]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #14713 from rgacogne/fix-coverity-secrets master
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 25 Sep 2024 14:19:18 +0000 (16:19 +0200)
committerGitHub <noreply@github.com>
Wed, 25 Sep 2024 14:19:18 +0000 (16:19 +0200)
coverity: Use the correct secret token

523 files changed:
.clang-format
.clang-tidy.bugs
.clang-tidy.full
.github/ISSUE_TEMPLATE/bug_report.md
.github/actions/spell-check/expect.txt
.github/actions/spell-check/only.txt
.github/actions/spell-check/patterns.txt
.github/workflows/build-and-test-all-releases-dispatch.yml
.github/workflows/build-and-test-all.yml
.github/workflows/build-docker-images.yml
.github/workflows/build-packages-daily-master.yml [new file with mode: 0644]
.github/workflows/build-packages.yml
.github/workflows/builder-releases-dispatch.yml
.github/workflows/builder.yml
.github/workflows/codeql-analysis.yml
.github/workflows/coverity-dispatch.yml [new file with mode: 0644]
.github/workflows/coverity.yml [new file with mode: 0644]
.github/workflows/documentation.yml
.github/workflows/misc-dailies.yml
.gitignore
.not-formatted
BUILDING-PACKAGES.md
CODE_COVERAGE.md
CONTRIBUTING.md
Dockerfile-recursor
SECURITY.md
build-scripts/docker/repo-test/README.md
build-scripts/docker/repo-test/generate-repo-files.py
build-scripts/docker/repo-test/templates/Dockerfile-centos.jinja2 [deleted file]
build-scripts/docker/repo-test/templates/Dockerfile-el.jinja2
build-scripts/docker/repo-test/templates/pdns-list.jinja2
builder
builder-support/debian/recursor/debian-buster/pdns-recursor.maintscript [new file with mode: 0644]
builder-support/debian/recursor/debian-buster/rules
builder-support/dockerfiles/Dockerfile.target.centos-7
builder-support/dockerfiles/Dockerfile.target.centos-7-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.centos-8 [deleted file]
builder-support/dockerfiles/Dockerfile.target.centos-8-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.centos-8-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.centos-8-stream [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-bookworm
builder-support/dockerfiles/Dockerfile.target.debian-bookworm-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-bookworm-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-bullseye
builder-support/dockerfiles/Dockerfile.target.debian-bullseye-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-bullseye-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-buster
builder-support/dockerfiles/Dockerfile.target.debian-buster-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-buster-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-trixie
builder-support/dockerfiles/Dockerfile.target.debian-trixie-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.debian-trixie-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.el-7
builder-support/dockerfiles/Dockerfile.target.el-7-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.el-8-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.el-8-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.el-9
builder-support/dockerfiles/Dockerfile.target.el-9-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.el-9-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.oraclelinux-7 [new file with mode: 0644]
builder-support/dockerfiles/Dockerfile.target.oraclelinux-8
builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-focal
builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-jammy
builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar
builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic
builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-arm64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-noble
builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-amd64 [deleted symlink]
builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-arm64 [deleted symlink]
builder-support/helpers/generate-sbom-dnf.py
builder-support/helpers/install_quiche.sh
builder-support/helpers/quiche.json
builder-support/helpers/rust.json
builder-support/post-build
builder-support/specs/dnsdist.spec
builder-support/specs/pdns-recursor.spec
configure.ac
contrib/ProtobufLogger.py
contrib/_pdnsutil.zsh_completion
contrib/pdnsutil.bash_completion.d
contrib/xdp.py
dockerdata/recursor.conf
docs/Makefile.am
docs/appendices/compiling.rst
docs/backends/generic-mysql.rst
docs/backends/index.rst
docs/backends/ldap.rst
docs/changelog/4.1.rst
docs/changelog/4.2.rst
docs/changelog/4.9.rst
docs/changelog/pre-4.0.rst
docs/generate-man-pages.py
docs/http-api/index.rst
docs/lua-records/index.rst
docs/manpages/pdnsutil.1.rst
docs/modes-of-operation.rst
docs/performance.rst
docs/requirements.in
docs/requirements.txt
docs/secpoll.zone
docs/settings.rst
docs/upgrading.rst
ext/json11/json11.cpp
ext/lmdb-safe/lmdb-typed.cc
ext/lmdb-safe/lmdb-typed.hh
ext/probds/meson.build [new file with mode: 0644]
ext/yahttp/yahttp/reqresp.hpp
ext/yahttp/yahttp/router.cpp
m4/systemd.m4
meson.build
meson/auto-var-init/meson.build
meson/boost-context/meson.build [new file with mode: 0644]
meson/boost-filesystem/meson.build [new file with mode: 0644]
meson/boost/meson.build
meson/cxx-fs/meson.build
meson/dnstap/meson.build [new file with mode: 0644]
meson/libcurl/meson.build [new file with mode: 0644]
meson/libresolv/meson.build [new file with mode: 0644]
meson/libsnmp/meson.build [new file with mode: 0644]
meson/nod/meson.build [new file with mode: 0644]
meson/pthread-np/meson.build [new file with mode: 0644]
modules/geoipbackend/Makefile.am
modules/geoipbackend/geoipbackend.cc
modules/geoipbackend/geoipinterface.cc
modules/geoipbackend/meson.build
modules/gmysqlbackend/gmysqlbackend.cc
modules/godbcbackend/OBJECTLIBS
modules/godbcbackend/godbcbackend.cc
modules/gpgsqlbackend/gpgsqlbackend.cc
modules/gsqlite3backend/gsqlite3backend.cc
modules/lmdbbackend/lmdbbackend.cc
modules/lmdbbackend/lmdbbackend.hh
modules/lmdbbackend/meson.build
modules/lua2backend/lua2api2.hh
modules/remotebackend/httpconnector.cc
pdns/Makefile.am
pdns/README-dnsdist.md [deleted file]
pdns/auth-main.cc
pdns/auth-secondarycommunicator.cc
pdns/axfr-retriever.cc
pdns/bpf-filter.cc [deleted file]
pdns/bpf-filter.ebpf.src [deleted file]
pdns/bpf-filter.hh [deleted file]
pdns/bpf-filter.main.ebpf [deleted file]
pdns/bpf-filter.qname.ebpf [deleted file]
pdns/cachecleaner.hh
pdns/communicator.cc
pdns/credentials.cc
pdns/credentials.hh
pdns/dbdnsseckeeper.cc
pdns/delaypipe.cc [deleted file]
pdns/delaypipe.hh [deleted file]
pdns/dns.cc
pdns/dns.hh
pdns/dnsbulktest.cc
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/README.md [changed from symlink to file mode: 0644]
pdns/dnsdistdist/bpf-filter.cc [changed from symlink to file mode: 0644]
pdns/dnsdistdist/bpf-filter.ebpf.src [changed from symlink to file mode: 0644]
pdns/dnsdistdist/bpf-filter.hh [changed from symlink to file mode: 0644]
pdns/dnsdistdist/bpf-filter.main.ebpf [changed from symlink to file mode: 0644]
pdns/dnsdistdist/bpf-filter.qname.ebpf [changed from symlink to file mode: 0644]
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/delaypipe.cc [changed from symlink to file mode: 0644]
pdns/dnsdistdist/delaypipe.hh [changed from symlink to file mode: 0644]
pdns/dnsdistdist/dnscrypt.cc
pdns/dnsdistdist/dnscrypt.hh
pdns/dnsdistdist/dnsdist-actions.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-async.cc
pdns/dnsdistdist/dnsdist-async.hh
pdns/dnsdistdist/dnsdist-backend.cc
pdns/dnsdistdist/dnsdist-backend.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-cache.cc
pdns/dnsdistdist/dnsdist-carbon.cc
pdns/dnsdistdist/dnsdist-carbon.hh
pdns/dnsdistdist/dnsdist-concurrent-connections.hh
pdns/dnsdistdist/dnsdist-configuration.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-configuration.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-console.cc
pdns/dnsdistdist/dnsdist-console.hh
pdns/dnsdistdist/dnsdist-discovery.cc
pdns/dnsdistdist/dnsdist-dnsparser.cc
pdns/dnsdistdist/dnsdist-dnsparser.hh
pdns/dnsdistdist/dnsdist-dnsquestion.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-dynblocks.cc
pdns/dnsdistdist/dnsdist-dynblocks.hh
pdns/dnsdistdist/dnsdist-dynbpf.cc
pdns/dnsdistdist/dnsdist-dynbpf.hh
pdns/dnsdistdist/dnsdist-ecs.cc
pdns/dnsdistdist/dnsdist-ecs.hh
pdns/dnsdistdist/dnsdist-frontend.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-frontend.hh [moved from pdns/doh.hh with 56% similarity]
pdns/dnsdistdist/dnsdist-healthchecks.cc
pdns/dnsdistdist/dnsdist-healthchecks.hh
pdns/dnsdistdist/dnsdist-lbpolicies.cc
pdns/dnsdistdist/dnsdist-lbpolicies.hh
pdns/dnsdistdist/dnsdist-lua-actions.cc
pdns/dnsdistdist/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc
pdns/dnsdistdist/dnsdist-lua-bindings.cc
pdns/dnsdistdist/dnsdist-lua-ffi-interface.h
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/dnsdist-lua-ffi.hh
pdns/dnsdistdist/dnsdist-lua-hooks.cc
pdns/dnsdistdist/dnsdist-lua-hooks.hh
pdns/dnsdistdist/dnsdist-lua-inspection.cc
pdns/dnsdistdist/dnsdist-lua-rules.cc
pdns/dnsdistdist/dnsdist-lua-web.cc
pdns/dnsdistdist/dnsdist-lua.cc
pdns/dnsdistdist/dnsdist-lua.hh
pdns/dnsdistdist/dnsdist-metrics.cc
pdns/dnsdistdist/dnsdist-metrics.hh
pdns/dnsdistdist/dnsdist-nghttp2-in.cc
pdns/dnsdistdist/dnsdist-nghttp2.cc
pdns/dnsdistdist/dnsdist-nghttp2.hh
pdns/dnsdistdist/dnsdist-proxy-protocol.cc
pdns/dnsdistdist/dnsdist-proxy-protocol.hh
pdns/dnsdistdist/dnsdist-query-count.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-query-count.hh [moved from pdns/pdns_hw.cc with 67% similarity]
pdns/dnsdistdist/dnsdist-rings.cc
pdns/dnsdistdist/dnsdist-rings.hh
pdns/dnsdistdist/dnsdist-rule-chains.cc
pdns/dnsdistdist/dnsdist-rule-chains.hh
pdns/dnsdistdist/dnsdist-rules.hh
pdns/dnsdistdist/dnsdist-secpoll.cc
pdns/dnsdistdist/dnsdist-secpoll.hh
pdns/dnsdistdist/dnsdist-session-cache.cc
pdns/dnsdistdist/dnsdist-session-cache.hh
pdns/dnsdistdist/dnsdist-snmp.cc
pdns/dnsdistdist/dnsdist-snmp.hh
pdns/dnsdistdist/dnsdist-svc.cc
pdns/dnsdistdist/dnsdist-svc.hh
pdns/dnsdistdist/dnsdist-tcp-downstream.cc
pdns/dnsdistdist/dnsdist-tcp-upstream.hh
pdns/dnsdistdist/dnsdist-tcp.cc
pdns/dnsdistdist/dnsdist-web.cc
pdns/dnsdistdist/dnsdist-web.hh
pdns/dnsdistdist/dnsdist-xsk.cc
pdns/dnsdistdist/dnsdist-xsk.hh
pdns/dnsdistdist/dnsdist.cc
pdns/dnsdistdist/dnsdist.hh
pdns/dnsdistdist/dnsdist.service.in
pdns/dnsdistdist/docs/advanced/ebpf.rst
pdns/dnsdistdist/docs/advanced/index.rst
pdns/dnsdistdist/docs/advanced/passing-source-address.rst
pdns/dnsdistdist/docs/advanced/tuning.rst
pdns/dnsdistdist/docs/advanced/xsk.rst
pdns/dnsdistdist/docs/advanced/zero-scope.rst [new file with mode: 0644]
pdns/dnsdistdist/docs/changelog.rst
pdns/dnsdistdist/docs/reference/actions.rst
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsdistdist/docs/reference/constants.rst
pdns/dnsdistdist/docs/reference/dnstap.rst
pdns/dnsdistdist/docs/reference/selectors.rst
pdns/dnsdistdist/docs/reference/tuning.rst
pdns/dnsdistdist/docs/requirements.txt
pdns/dnsdistdist/doh.cc
pdns/dnsdistdist/doh.hh [changed from symlink to file mode: 0644]
pdns/dnsdistdist/doh3.cc
pdns/dnsdistdist/doq.cc
pdns/dnsdistdist/m4/pdns_with_quiche.m4
pdns/dnsdistdist/test-dnscrypt_cc.cc
pdns/dnsdistdist/test-dnsdist-dnsparser.cc
pdns/dnsdistdist/test-dnsdist-lua-ffi.cc
pdns/dnsdistdist/test-dnsdist_cc.cc
pdns/dnsdistdist/test-dnsdistasync.cc
pdns/dnsdistdist/test-dnsdistdynblocks_hh.cc
pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc
pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc
pdns/dnsdistdist/test-dnsdistpacketcache_cc.cc
pdns/dnsdistdist/test-dnsdistrings_cc.cc
pdns/dnsdistdist/test-dnsdistrules_cc.cc
pdns/dnsdistdist/test-dnsdisttcp_cc.cc
pdns/dnsdistdist/test-sholder_hh.cc [new symlink]
pdns/dnsdistdist/testrunner.cc
pdns/dnsdistdist/xsk.cc [changed from symlink to file mode: 0644]
pdns/dnsdistdist/xsk.hh [changed from symlink to file mode: 0644]
pdns/dnsmessage.proto
pdns/dnsname.hh
pdns/dnspacket.cc
pdns/dnspacket.hh
pdns/dnsparser.cc
pdns/dnsparser.hh
pdns/dnsproxy.cc
pdns/dnsproxy.hh
pdns/dnsrecords.cc
pdns/dnsreplay.cc
pdns/dnsscope.cc
pdns/dnssecinfra.hh
pdns/dnsseckeeper.hh
pdns/dnssecsigner.cc
pdns/dnswriter.cc
pdns/dolog.hh
pdns/fstrm_logger.cc
pdns/fstrm_logger.hh
pdns/iputils.hh
pdns/ixfr.cc
pdns/ixfrdist.cc
pdns/ixfrutils.cc
pdns/keyroller/Pipfile.lock
pdns/keyroller/README.md
pdns/libssl.cc
pdns/libssl.hh
pdns/lock.hh
pdns/lua-auth4.cc
pdns/lua-auth4.hh
pdns/lua-base4.cc
pdns/lua-base4.hh
pdns/lua-record.cc
pdns/misc.cc
pdns/misc.hh
pdns/nsec3dig.cc
pdns/opensslsigners.cc
pdns/packethandler.cc
pdns/pdnsutil.cc
pdns/protozero.cc
pdns/protozero.hh
pdns/proxy-protocol.hh
pdns/recursordist/.gitignore
pdns/recursordist/Makefile.am
pdns/recursordist/RECURSOR-MIB.txt
pdns/recursordist/configure.ac
pdns/recursordist/docs/appendices/EOL.rst
pdns/recursordist/docs/appendices/FAQ.rst
pdns/recursordist/docs/appendices/compiling.rst
pdns/recursordist/docs/changelog/4.3.rst
pdns/recursordist/docs/changelog/4.9.rst
pdns/recursordist/docs/changelog/5.0.rst
pdns/recursordist/docs/changelog/5.1.rst
pdns/recursordist/docs/generate-man-pages.py [new symlink]
pdns/recursordist/docs/http-api/zone.rst
pdns/recursordist/docs/lua-config/protobuf.rst
pdns/recursordist/docs/lua-scripting/dq.rst
pdns/recursordist/docs/lua-scripting/hooks.rst
pdns/recursordist/docs/metrics.rst
pdns/recursordist/docs/nod_udr.rst
pdns/recursordist/docs/performance.rst
pdns/recursordist/docs/requirements.txt
pdns/recursordist/docs/running.rst
pdns/recursordist/docs/upgrade.rst
pdns/recursordist/ext/arc4random/meson.build [new symlink]
pdns/recursordist/ext/json11/meson.build [new symlink]
pdns/recursordist/ext/probds/meson.build [new symlink]
pdns/recursordist/ext/yahttp/meson.build [new symlink]
pdns/recursordist/ext/yahttp/yahttp/meson.build [new symlink]
pdns/recursordist/filterpo.cc
pdns/recursordist/lua-recursor4.cc
pdns/recursordist/lua-recursor4.hh
pdns/recursordist/lwres.cc
pdns/recursordist/lwres.hh
pdns/recursordist/meson [new symlink]
pdns/recursordist/meson.build [new file with mode: 0644]
pdns/recursordist/meson_options.txt [new file with mode: 0644]
pdns/recursordist/mtasker.hh
pdns/recursordist/mtasker_context.cc
pdns/recursordist/mtasker_fcontext.cc [deleted file]
pdns/recursordist/mtasker_ucontext.cc [deleted file]
pdns/recursordist/pdns_recursor.cc
pdns/recursordist/pubsuffix.cc [deleted symlink]
pdns/recursordist/rec-lua-conf.cc
pdns/recursordist/rec-main.cc
pdns/recursordist/rec-main.hh
pdns/recursordist/rec-protozero.cc
pdns/recursordist/rec-protozero.hh
pdns/recursordist/rec-snmp.cc
pdns/recursordist/rec-system-resolve.cc
pdns/recursordist/rec-tcounters.hh
pdns/recursordist/rec-tcp.cc
pdns/recursordist/rec_channel_rec.cc
pdns/recursordist/rec_control.cc
pdns/recursordist/reczones.cc
pdns/recursordist/rpzloader.cc
pdns/recursordist/settings/README.md
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/docs-new-preamble-in.rst
pdns/recursordist/settings/docs-old-preamble-in.rst
pdns/recursordist/settings/generate.py
pdns/recursordist/settings/meson.build [new file with mode: 0644]
pdns/recursordist/settings/rust/Cargo.lock
pdns/recursordist/settings/rust/Cargo.toml
pdns/recursordist/settings/rust/build_settings [new file with mode: 0755]
pdns/recursordist/settings/rust/meson.build [new file with mode: 0644]
pdns/recursordist/settings/rust/src/bridge.rs
pdns/recursordist/settings/table.py
pdns/recursordist/syncres.cc
pdns/recursordist/syncres.hh
pdns/recursordist/test-sholder_hh.cc [new symlink]
pdns/recursordist/test-syncres_cc.cc
pdns/recursordist/test-syncres_cc1.cc
pdns/recursordist/test-syncres_cc2.cc
pdns/recursordist/test-syncres_cc3.cc
pdns/recursordist/test-syncres_cc9.cc
pdns/recursordist/testrunner.cc
pdns/recursordist/ws-recursor.cc
pdns/resolver.cc
pdns/rfc2136handler.cc
pdns/saxfr.cc
pdns/sdig.cc
pdns/sholder.hh
pdns/shuffle.cc
pdns/signingpipe.cc
pdns/snmp-agent.cc
pdns/snmp-agent.hh
pdns/speedtest.cc
pdns/ssqlite3.cc
pdns/sstuff.hh
pdns/stat_t.hh
pdns/stubresolver.cc
pdns/tcpiohandler.cc
pdns/tcpiohandler.hh
pdns/tcpreceiver.cc
pdns/test-distributor_hh.cc
pdns/test-dnsrecords_cc.cc
pdns/test-sholder_hh.cc
pdns/test-tsig.cc
pdns/testrunner.cc
pdns/tsigverifier.cc
pdns/ueberbackend.cc
pdns/ueberbackend.hh
pdns/uuid-utils.cc
pdns/version.cc
pdns/version.hh
pdns/views.hh
pdns/webserver.cc
pdns/webserver.hh
pdns/ws-auth.cc
pdns/xsk.cc [deleted file]
pdns/xsk.hh [deleted file]
regression-tests.api/test_Zones.py
regression-tests.auth-py/authtests.py
regression-tests.auth-py/runtests
regression-tests.auth-py/test_ALIAS.py
regression-tests.auth-py/test_GSSTSIG.py
regression-tests.dnsdist/dnsdisttests.py
regression-tests.dnsdist/requirements.txt
regression-tests.dnsdist/runtests
regression-tests.dnsdist/test_DOH.py
regression-tests.dnsdist/test_EDE.py
regression-tests.dnsdist/test_EDNSSelfGenerated.py
regression-tests.dnsdist/test_LuaFFI.py
regression-tests.dnsdist/test_Prometheus.py
regression-tests.dnsdist/test_ProxyProtocol.py
regression-tests.dnsdist/test_SVCB.py
regression-tests.dnsdist/test_TLS.py
regression-tests.recursor-dnssec/printlogs.py
regression-tests.recursor-dnssec/recursortests.py
regression-tests.recursor-dnssec/requirements.txt
regression-tests.recursor-dnssec/runtests
regression-tests.recursor-dnssec/test_API.py
regression-tests.recursor-dnssec/test_Additionals.py
regression-tests.recursor-dnssec/test_AggressiveNSECCache.py
regression-tests.recursor-dnssec/test_AnyBind.py
regression-tests.recursor-dnssec/test_Carbon.py
regression-tests.recursor-dnssec/test_Chain.py [new file with mode: 0644]
regression-tests.recursor-dnssec/test_DNS64.py
regression-tests.recursor-dnssec/test_ECS.py
regression-tests.recursor-dnssec/test_EDNSBufferSize.py
regression-tests.recursor-dnssec/test_EDNSPadding.py
regression-tests.recursor-dnssec/test_Expired.py
regression-tests.recursor-dnssec/test_ExtendedErrors.py
regression-tests.recursor-dnssec/test_Flags.py
regression-tests.recursor-dnssec/test_Interop.py
regression-tests.recursor-dnssec/test_KeepOpenTCP.py
regression-tests.recursor-dnssec/test_LockedCache.py
regression-tests.recursor-dnssec/test_Lua.py
regression-tests.recursor-dnssec/test_NTA.py
regression-tests.recursor-dnssec/test_NamedForward.py
regression-tests.recursor-dnssec/test_NoDS.py
regression-tests.recursor-dnssec/test_NoDSYAML.py
regression-tests.recursor-dnssec/test_NotYetValid.py
regression-tests.recursor-dnssec/test_Notify.py
regression-tests.recursor-dnssec/test_OOOTCP.py
regression-tests.recursor-dnssec/test_PacketCache.py
regression-tests.recursor-dnssec/test_Prometheus.py
regression-tests.recursor-dnssec/test_Protobuf.py
regression-tests.recursor-dnssec/test_ProxyByTable.py
regression-tests.recursor-dnssec/test_ProxyProtocol.py
regression-tests.recursor-dnssec/test_RDFlag.py
regression-tests.recursor-dnssec/test_RPZ.py
regression-tests.recursor-dnssec/test_RPZIncomplete.py
regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py
regression-tests.recursor-dnssec/test_RecDnstap.py
regression-tests.recursor-dnssec/test_RootNXTrust.py
regression-tests.recursor-dnssec/test_RoutingTag.py
regression-tests.recursor-dnssec/test_SNMP.py
regression-tests.recursor-dnssec/test_ServerNames.py
regression-tests.recursor-dnssec/test_Simple.py
regression-tests.recursor-dnssec/test_SimpleDoT.py
regression-tests.recursor-dnssec/test_SimpleForwardOverDoT.py
regression-tests.recursor-dnssec/test_SimpleTCP.py
regression-tests.recursor-dnssec/test_SimpleYAML.py
regression-tests.recursor-dnssec/test_Sortlist.py
regression-tests.recursor-dnssec/test_TTL.py
regression-tests.recursor-dnssec/test_TraceFail.py
regression-tests.recursor-dnssec/test_TrustAnchors.py
regression-tests.recursor-dnssec/test_ZTC.py
regression-tests.recursor-dnssec/test_basicNSEC.py
regression-tests.recursor-dnssec/test_basicNSEC3.py
regression-tests.rootzone/tests/direct-ns/skip-unboundhost [new file with mode: 0644]
regression-tests/backends/bind-master
regression-tests/backends/common
regression-tests/backends/geoip-master
regression-tests/backends/gmysql-master
regression-tests/backends/godbc_mssql-master
regression-tests/backends/godbc_sqlite3-master
regression-tests/backends/gpgsql-master
regression-tests/backends/gsql-common
regression-tests/backends/gsqlite3-master
regression-tests/backends/ldap-master
regression-tests/backends/lmdb-master
regression-tests/backends/lua2-master
regression-tests/backends/remote-master
regression-tests/backends/tinydns-master
regression-tests/runtests
regression-tests/start-test-stop
tasks.py

index 1d681f062ec2a9155553b7e6675d82f680156fc9..e56bf7919702f28cc5cd3522642a9a99a92e87f5 100644 (file)
@@ -1,14 +1,14 @@
 ---
-Language:        Cpp
-BasedOnStyle:  WebKit
+Language: Cpp
+BasedOnStyle: WebKit
 AccessModifierOffset: -2
 ConstructorInitializerIndentWidth: 2
 ContinuationIndentWidth: 2
-IndentWidth:     2
+IndentWidth: 2
 ObjCBlockIndentWidth: 2
 AlignAfterOpenBracket: Align
 
-SortIncludes:    false
+SortIncludes: false
 
 SpaceBeforeCpp11BracedList: false
 Cpp11BracedListStyle: true
index d43aff95fca0a00070f5a1185d9f2629edff52f2..612bcf370c7804edde28a7e40e01bb6d3e30c3e5 100644 (file)
 ---
-Checks:          'clang-diagnostic-*,clang-analyzer-*,bugprone-*,concurrency-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-performance-avoid-endl'
+FormatStyle: none
+HeaderFileExtensions:
+  - h
+  - hh
+  - hpp
+ImplementationFileExtensions:
+  - c
+  - cc
+  - cpp
 WarningsAsErrors: ''
 HeaderFilterRegex: ''
-AnalyzeTemporaryDtors: false
-FormatStyle:     none
-User:            fred
+Checks: |
+  'clang-diagnostic-*,clang-analyzer-*,bugprone-*,concurrency-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-performance-avoid-endl'
+# yamllint disable rule:line-length
 CheckOptions:
-  - key:             bugprone-string-constructor.LargeLengthThreshold
-    value:           '8388608'
-  - key:             modernize-replace-auto-ptr.IncludeStyle
-    value:           llvm
-  - key:             bugprone-reserved-identifier.Invert
-    value:           'false'
-  - key:             bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
-    value:           'true'
-  - key:             cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
-    value:           'false'
-  - key:             bugprone-exception-escape.FunctionsThatShouldNotThrow
-    value:           ''
-  - key:             cert-dcl16-c.NewSuffixes
-    value:           'L;LL;LU;LLU'
-  - key:             bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
-    value:           'true'
-  - key:             modernize-loop-convert.MaxCopySize
-    value:           '16'
-  - key:             bugprone-narrowing-conversions.PedanticMode
-    value:           'false'
-  - key:             bugprone-unused-return-value.CheckedFunctions
-    value:           '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
-  - key:             bugprone-signed-char-misuse.CharTypdefsToIgnore
-    value:           ''
-  - key:             bugprone-argument-comment.CommentStringLiterals
-    value:           '0'
-  - key:             cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
-    value:           'true'
-  - key:             bugprone-easily-swappable-parameters.MinimumLength
-    value:           '2'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfConstant
-    value:           'true'
-  - key:             bugprone-argument-comment.CommentBoolLiterals
-    value:           '0'
-  - key:             bugprone-argument-comment.CommentUserDefinedLiterals
-    value:           '0'
-  - key:             cert-str34-c.DiagnoseSignedUnsignedCharComparisons
-    value:           'false'
-  - key:             bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
-    value:           'false'
-  - key:             concurrency-mt-unsafe.FunctionSet
-    value:           any
-  - key:             bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
-    value:           'false'
-  - key:             google-readability-braces-around-statements.ShortStatementLines
-    value:           '1'
-  - key:             bugprone-reserved-identifier.AllowedIdentifiers
-    value:           ''
-  - key:             bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
-    value:           'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
-  - key:             bugprone-easily-swappable-parameters.QualifiersMix
-    value:           'false'
-  - key:             bugprone-signal-handler.AsyncSafeFunctionSet
-    value:           POSIX
-  - key:             bugprone-easily-swappable-parameters.ModelImplicitConversions
-    value:           'true'
-  - key:             bugprone-suspicious-string-compare.WarnOnImplicitComparison
-    value:           'true'
-  - key:             bugprone-argument-comment.CommentNullPtrs
-    value:           '0'
-  - key:             bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
-    value:           'true'
-  - key:             bugprone-argument-comment.StrictMode
-    value:           '0'
-  - key:             bugprone-misplaced-widening-cast.CheckImplicitCasts
-    value:           'false'
-  - key:             bugprone-suspicious-missing-comma.RatioThreshold
-    value:           '0.200000'
-  - key:             modernize-loop-convert.MinConfidence
-    value:           reasonable
-  - key:             bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
-    value:           '1'
-  - key:             bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
-    value:           'true'
-  - key:             google-readability-namespace-comments.ShortNamespaceLines
-    value:           '10'
-  - key:             google-readability-namespace-comments.SpacesBeforeComments
-    value:           '2'
-  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
-    value:           'true'
-  - key:             bugprone-argument-comment.IgnoreSingleArgument
-    value:           '0'
-  - key:             bugprone-suspicious-string-compare.StringCompareLikeFunctions
-    value:           ''
-  - key:             bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
-    value:           'true'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
-    value:           'false'
-  - key:             bugprone-assert-side-effect.CheckFunctionCalls
-    value:           'false'
-  - key:             bugprone-easily-swappable-parameters.IgnoredParameterNames
-    value:           '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
-  - key:             bugprone-narrowing-conversions.IgnoreConversionFromTypes
-    value:           ''
-  - key:             bugprone-string-constructor.StringNames
-    value:           '::std::basic_string;::std::basic_string_view'
-  - key:             bugprone-assert-side-effect.AssertMacros
-    value:           assert,NSAssert,NSCAssert
-  - key:             bugprone-exception-escape.IgnoredExceptions
-    value:           ''
-  - key:             bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
-    value:           'true'
-  - key:             llvm-qualified-auto.AddConstToQualified
-    value:           'false'
-  - key:             bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
-    value:           'true'
-  - key:             modernize-loop-convert.NamingStyle
-    value:           CamelCase
-  - key:             bugprone-suspicious-include.ImplementationFileExtensions
-    value:           'c;cc;cpp;cxx'
-  - key:             bugprone-suspicious-missing-comma.SizeThreshold
-    value:           '5'
-  - key:             bugprone-suspicious-include.HeaderFileExtensions
-    value:           ';h;hh;hpp;hxx'
-  - key:             google-readability-function-size.StatementThreshold
-    value:           '800'
-  - key:             llvm-else-after-return.WarnOnConditionVariables
-    value:           'false'
-  - key:             bugprone-argument-comment.CommentCharacterLiterals
-    value:           '0'
-  - key:             bugprone-argument-comment.CommentIntegerLiterals
-    value:           '0'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
-    value:           'true'
-  - key:             modernize-pass-by-value.IncludeStyle
-    value:           llvm
-  - key:             bugprone-reserved-identifier.AggressiveDependentMemberLookup
-    value:           'false'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfThis
-    value:           'true'
-  - key:             bugprone-string-constructor.WarnOnLargeLength
-    value:           'true'
-  - key:             bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
-    value:           '16'
-  - key:             bugprone-argument-comment.CommentFloatLiterals
-    value:           '0'
-  - key:             modernize-use-nullptr.NullMacros
-    value:           'NULL'
-  - key:             bugprone-dangling-handle.HandleClasses
-    value:           'std::basic_string_view;std::experimental::basic_string_view'
-  - key:             bugprone-dynamic-static-initializers.HeaderFileExtensions
-    value:           ';h;hh;hpp;hxx'
-  - key:             bugprone-suspicious-enum-usage.StrictMode
-    value:           'false'
-  - key:             bugprone-implicit-widening-of-multiplication-result.IncludeStyle
-    value:           llvm
-  - key:             bugprone-suspicious-missing-comma.MaxConcatenatedTokens
-    value:           '5'
-  - key:             bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
-    value:           'true'
-  - key:             llvm-else-after-return.WarnOnUnfixable
-    value:           'false'
-  - key:             bugprone-not-null-terminated-result.WantToUseSafeFunctions
-    value:           'true'
+  - key: bugprone-string-constructor.LargeLengthThreshold
+    value: '8388608'
+  - key: modernize-replace-auto-ptr.IncludeStyle
+    value: llvm
+  - key: bugprone-reserved-identifier.Invert
+    value: 'false'
+  - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
+    value: 'true'
+  - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
+    value: 'false'
+  - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
+    value: ''
+  - key: cert-dcl16-c.NewSuffixes
+    value: 'L;LL;LU;LLU'
+  - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+    value: 'true'
+  - key: modernize-loop-convert.MaxCopySize
+    value: '16'
+  - key: bugprone-narrowing-conversions.PedanticMode
+    value: 'false'
+  - key: bugprone-unused-return-value.CheckedFunctions
+    value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
+  - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
+    value: ''
+  - key: bugprone-argument-comment.CommentStringLiterals
+    value: '0'
+  - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
+    value: 'true'
+  - key: bugprone-easily-swappable-parameters.MinimumLength
+    value: '2'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
+    value: 'true'
+  - key: bugprone-argument-comment.CommentBoolLiterals
+    value: '0'
+  - key: bugprone-argument-comment.CommentUserDefinedLiterals
+    value: '0'
+  - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
+    value: 'false'
+  - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
+    value: 'false'
+  - key: concurrency-mt-unsafe.FunctionSet
+    value: any
+  - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
+    value: 'false'
+  - key: google-readability-braces-around-statements.ShortStatementLines
+    value: '1'
+  - key: bugprone-reserved-identifier.AllowedIdentifiers
+    value: ''
+  - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
+    value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
+  - key: bugprone-easily-swappable-parameters.QualifiersMix
+    value: 'false'
+  - key: bugprone-signal-handler.AsyncSafeFunctionSet
+    value: POSIX
+  - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
+    value: 'true'
+  - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
+    value: 'true'
+  - key: bugprone-argument-comment.CommentNullPtrs
+    value: '0'
+  - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
+    value: 'true'
+  - key: bugprone-argument-comment.StrictMode
+    value: '0'
+  - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
+    value: 'false'
+  - key: bugprone-suspicious-missing-comma.RatioThreshold
+    value: '0.200000'
+  - key: modernize-loop-convert.MinConfidence
+    value: reasonable
+  - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
+    value: '1'
+  - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
+    value: 'true'
+  - key: google-readability-namespace-comments.ShortNamespaceLines
+    value: '10'
+  - key: google-readability-namespace-comments.SpacesBeforeComments
+    value: '2'
+  - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
+    value: 'true'
+  - key: bugprone-argument-comment.IgnoreSingleArgument
+    value: '0'
+  - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
+    value: ''
+  - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
+    value: 'true'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
+    value: 'false'
+  - key: bugprone-assert-side-effect.CheckFunctionCalls
+    value: 'false'
+  - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
+    value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
+  - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
+    value: ''
+  - key: bugprone-string-constructor.StringNames
+    value: '::std::basic_string;::std::basic_string_view'
+  - key: bugprone-assert-side-effect.AssertMacros
+    value: assert,NSAssert,NSCAssert
+  - key: bugprone-exception-escape.IgnoredExceptions
+    value: ''
+  - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
+    value: 'true'
+  - key: llvm-qualified-auto.AddConstToQualified
+    value: 'false'
+  - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
+    value: 'true'
+  - key: modernize-loop-convert.NamingStyle
+    value: CamelCase
+  - key: bugprone-suspicious-include.ImplementationFileExtensions
+    value: 'c;cc;cpp;cxx'
+  - key: bugprone-suspicious-missing-comma.SizeThreshold
+    value: '5'
+  - key: bugprone-suspicious-include.HeaderFileExtensions
+    value: ';h;hh;hpp;hxx'
+  - key: google-readability-function-size.StatementThreshold
+    value: '800'
+  - key: llvm-else-after-return.WarnOnConditionVariables
+    value: 'false'
+  - key: bugprone-argument-comment.CommentCharacterLiterals
+    value: '0'
+  - key: bugprone-argument-comment.CommentIntegerLiterals
+    value: '0'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
+    value: 'true'
+  - key: modernize-pass-by-value.IncludeStyle
+    value: llvm
+  - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
+    value: 'false'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfThis
+    value: 'true'
+  - key: bugprone-string-constructor.WarnOnLargeLength
+    value: 'true'
+  - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
+    value: '16'
+  - key: bugprone-argument-comment.CommentFloatLiterals
+    value: '0'
+  - key: modernize-use-nullptr.NullMacros
+    value: 'NULL'
+  - key: bugprone-dangling-handle.HandleClasses
+    value: 'std::basic_string_view;std::experimental::basic_string_view'
+  - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
+    value: ';h;hh;hpp;hxx'
+  - key: bugprone-suspicious-enum-usage.StrictMode
+    value: 'false'
+  - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
+    value: llvm
+  - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
+    value: '5'
+  - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
+    value: 'true'
+  - key: llvm-else-after-return.WarnOnUnfixable
+    value: 'false'
+  - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
+    value: 'true'
+# yamllint enable
 ...
index 0d82ca9e3e8b0cead8776f4e7e2b876675e134a3..3c73e19b47da9fbdbe558afb02b749ecd7f0a039 100644 (file)
 ---
-Checks:          'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,bugprone-*,concurrency-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-do-while,-cppcoreguidelines-avoid-const-or-ref-data-members,-performance-avoid-endl'
+FormatStyle: none
+HeaderFileExtensions:
+  - h
+  - hh
+  - hpp
+ImplementationFileExtensions:
+  - c
+  - cc
+  - cpp
 WarningsAsErrors: ''
 HeaderFilterRegex: ''
-AnalyzeTemporaryDtors: false
-FormatStyle:     none
-User:            fred
+Checks: |
+  'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,bugprone-*,concurrency-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-trailing-return-type,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-do-while,-cppcoreguidelines-avoid-const-or-ref-data-members,-performance-avoid-endl'
+# yamllint disable rule:line-length
 CheckOptions:
-  - key:             readability-suspicious-call-argument.PrefixSimilarAbove
-    value:           '30'
-  - key:             cppcoreguidelines-no-malloc.Reallocations
-    value:           '::realloc'
-  - key:             cppcoreguidelines-owning-memory.LegacyResourceConsumers
-    value:           '::free;::realloc;::freopen;::fclose'
-  - key:             bugprone-reserved-identifier.Invert
-    value:           'false'
-  - key:             bugprone-narrowing-conversions.PedanticMode
-    value:           'false'
-  - key:             bugprone-unused-return-value.CheckedFunctions
-    value:           '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
-  - key:             modernize-use-auto.MinTypeNameLength
-    value:           '5'
-  - key:             cppcoreguidelines-macro-usage.CheckCapsOnly
-    value:           'false'
-  - key:             readability-inconsistent-declaration-parameter-name.Strict
-    value:           'false'
-  - key:             readability-suspicious-call-argument.DiceDissimilarBelow
-    value:           '60'
-  - key:             readability-suspicious-call-argument.Equality
-    value:           'true'
-  - key:             bugprone-easily-swappable-parameters.QualifiersMix
-    value:           'false'
-  - key:             bugprone-suspicious-string-compare.WarnOnImplicitComparison
-    value:           'true'
-  - key:             bugprone-argument-comment.CommentNullPtrs
-    value:           '0'
-  - key:             cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
-    value:           'true'
-  - key:             cppcoreguidelines-init-variables.IncludeStyle
-    value:           llvm
-  - key:             modernize-use-nodiscard.ReplacementString
-    value:           '[[nodiscard]]'
-  - key:             modernize-loop-convert.MakeReverseRangeHeader
-    value:           ''
-  - key:             readability-suspicious-call-argument.SuffixSimilarAbove
-    value:           '30'
-  - key:             cppcoreguidelines-narrowing-conversions.WarnOnIntegerNarrowingConversion
-    value:           'true'
-  - key:             bugprone-easily-swappable-parameters.IgnoredParameterNames
-    value:           '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
-  - key:             modernize-loop-convert.UseCxx20ReverseRanges
-    value:           'true'
-  - key:             cppcoreguidelines-prefer-member-initializer.UseAssignment
-    value:           'false'
-  - key:             performance-type-promotion-in-math-fn.IncludeStyle
-    value:           llvm
-  - key:             readability-function-cognitive-complexity.DescribeBasicIncrements
-    value:           'true'
-  - key:             bugprone-suspicious-include.ImplementationFileExtensions
-    value:           'c;cc;cpp;cxx'
-  - key:             modernize-loop-convert.MakeReverseRangeFunction
-    value:           ''
-  - key:             readability-inconsistent-declaration-parameter-name.IgnoreMacros
-    value:           'true'
-  - key:             bugprone-suspicious-missing-comma.SizeThreshold
-    value:           '5'
-  - key:             readability-identifier-naming.IgnoreFailedSplit
-    value:           'false'
-  - key:             readability-qualified-auto.AddConstToQualified
-    value:           'true'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfThis
-    value:           'true'
-  - key:             bugprone-string-constructor.WarnOnLargeLength
-    value:           'true'
-  - key:             cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
-    value:           override
-  - key:             readability-uppercase-literal-suffix.IgnoreMacros
-    value:           'true'
-  - key:             modernize-make-shared.IgnoreMacros
-    value:           'true'
-  - key:             bugprone-dynamic-static-initializers.HeaderFileExtensions
-    value:           ';h;hh;hpp;hxx'
-  - key:             bugprone-suspicious-enum-usage.StrictMode
-    value:           'false'
-  - key:             performance-unnecessary-copy-initialization.AllowedTypes
-    value:           ''
-  - key:             bugprone-suspicious-missing-comma.MaxConcatenatedTokens
-    value:           '5'
-  - key:             modernize-use-transparent-functors.SafeMode
-    value:           'false'
-  - key:             readability-suspicious-call-argument.Levenshtein
-    value:           'true'
-  - key:             bugprone-not-null-terminated-result.WantToUseSafeFunctions
-    value:           'true'
-  - key:             bugprone-string-constructor.LargeLengthThreshold
-    value:           '8388608'
-  - key:             readability-simplify-boolean-expr.ChainedConditionalAssignment
-    value:           'false'
-  - key:             cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
-    value:           'false'
-  - key:             cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
-    value:           'false'
-  - key:             bugprone-exception-escape.FunctionsThatShouldNotThrow
-    value:           ''
-  - key:             performance-inefficient-vector-operation.EnableProto
-    value:           'false'
-  - key:             modernize-make-shared.MakeSmartPtrFunction
-    value:           'std::make_shared'
-  - key:             modernize-loop-convert.MaxCopySize
-    value:           '16'
-  - key:             readability-suspicious-call-argument.PrefixDissimilarBelow
-    value:           '25'
-  - key:             readability-function-size.LineThreshold
-    value:           '4294967295'
-  - key:             bugprone-easily-swappable-parameters.MinimumLength
-    value:           '4'
-  - key:             portability-simd-intrinsics.Suggest
-    value:           'false'
-  - key:             cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
-    value:           ''
-  - key:             modernize-use-override.IgnoreDestructors
-    value:           'false'
-  - key:             modernize-make-shared.MakeSmartPtrFunctionHeader
-    value:           '<memory>'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfConstant
-    value:           'true'
-  - key:             readability-redundant-string-init.StringNames
-    value:           '::std::basic_string_view;::std::basic_string'
-  - key:             modernize-make-unique.IgnoreDefaultInitialization
-    value:           'true'
-  - key:             modernize-use-emplace.ContainersWithPushBack
-    value:           '::std::vector;::std::list;::std::deque'
-  - key:             readability-magic-numbers.IgnoreBitFieldsWidths
-    value:           'true'
-  - key:             modernize-make-unique.IncludeStyle
-    value:           llvm
-  - key:             modernize-use-override.OverrideSpelling
-    value:           override
-  - key:             readability-suspicious-call-argument.LevenshteinDissimilarBelow
-    value:           '50'
-  - key:             bugprone-argument-comment.CommentStringLiterals
-    value:           '0'
-  - key:             concurrency-mt-unsafe.FunctionSet
-    value:           any
-  - key:             google-readability-braces-around-statements.ShortStatementLines
-    value:           '1'
-  - key:             bugprone-reserved-identifier.AllowedIdentifiers
-    value:           ''
-  - key:             cppcoreguidelines-pro-type-member-init.IgnoreArrays
-    value:           'false'
-  - key:             readability-else-after-return.WarnOnUnfixable
-    value:           'true'
-  - key:             cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
-    value:           '1.0;100.0;'
-  - key:             modernize-use-emplace.IgnoreImplicitConstructors
-    value:           'false'
-  - key:             cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
-    value:           'true'
-  - key:             readability-suspicious-call-argument.Substring
-    value:           'true'
-  - key:             modernize-use-equals-delete.IgnoreMacros
-    value:           'true'
-  - key:             cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
-    value:           llvm
-  - key:             readability-magic-numbers.IgnoreAllFloatingPointValues
-    value:           'false'
-  - key:             readability-suspicious-call-argument.Abbreviations
-    value:           'arr=array;cnt=count;idx=index;src=source;stmt=statement;cpy=copy;dest=destination;dist=distancedst=distance;ptr=pointer;wdth=width;str=string;ln=line;srv=server;attr=attribute;ref=reference;buf=buffer;col=column;nr=number;vec=vector;len=length;elem=element;val=value;i=index;var=variable;hght=height;cl=client;num=number;pos=position;lst=list;addr=address'
-  - key:             bugprone-misplaced-widening-cast.CheckImplicitCasts
-    value:           'false'
-  - key:             readability-uppercase-literal-suffix.NewSuffixes
-    value:           ''
-  - key:             modernize-loop-convert.MinConfidence
-    value:           reasonable
-  - key:             performance-unnecessary-value-param.AllowedTypes
-    value:           ''
-  - key:             readability-uniqueptr-delete-release.PreferResetCall
-    value:           'false'
-  - key:             cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
-    value:           'false'
-  - key:             google-readability-namespace-comments.SpacesBeforeComments
-    value:           '2'
-  - key:             cppcoreguidelines-avoid-magic-numbers.IgnoreBitFieldsWidths
-    value:           'true'
-  - key:             cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
-    value:           '1;2;3;4;'
-  - key:             cppcoreguidelines-no-malloc.Allocations
-    value:           '::malloc;::calloc'
-  - key:             bugprone-narrowing-conversions.IgnoreConversionFromTypes
-    value:           ''
-  - key:             readability-function-size.BranchThreshold
-    value:           '4294967295'
-  - key:             bugprone-suspicious-missing-comma.RatioThreshold
-    value:           '0.200000'
-  - key:             readability-implicit-bool-conversion.AllowIntegerConditions
-    value:           'false'
-  - key:             readability-function-size.StatementThreshold
-    value:           '800'
-  - key:             readability-identifier-naming.IgnoreMainLikeFunctions
-    value:           'false'
-  - key:             cppcoreguidelines-init-variables.MathHeader
-    value:           '<math.h>'
-  - key:             google-readability-function-size.StatementThreshold
-    value:           '800'
-  - key:             bugprone-reserved-identifier.AggressiveDependentMemberLookup
-    value:           'false'
-  - key:             readability-suspicious-call-argument.DiceSimilarAbove
-    value:           '70'
-  - key:             modernize-use-equals-default.IgnoreMacros
-    value:           'true'
-  - key:             readability-suspicious-call-argument.Abbreviation
-    value:           'true'
-  - key:             cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
-    value:           'false'
-  - key:             modernize-use-emplace.SmartPointers
-    value:           '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
-  - key:             cppcoreguidelines-no-malloc.Deallocations
-    value:           '::free'
-  - key:             bugprone-dangling-handle.HandleClasses
-    value:           'std::basic_string_view;std::experimental::basic_string_view'
-  - key:             readability-magic-numbers.IgnorePowersOf2IntegerValues
-    value:           'false'
-  - key:             readability-suspicious-call-argument.JaroWinklerSimilarAbove
-    value:           '85'
-  - key:             readability-simplify-subscript-expr.Types
-    value:           '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
-  - key:             performance-unnecessary-copy-initialization.ExcludedContainerTypes
-    value:           ''
-  - key:             modernize-replace-auto-ptr.IncludeStyle
-    value:           llvm
-  - key:             performance-move-const-arg.CheckTriviallyCopyableMove
-    value:           'true'
-  - key:             readability-static-accessed-through-instance.NameSpecifierNestingThreshold
-    value:           '3'
-  - key:             readability-function-size.VariableThreshold
-    value:           '4294967295'
-  - key:             cert-dcl16-c.NewSuffixes
-    value:           'L;LL;LU;LLU'
-  - key:             bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
-    value:           'true'
-  - key:             readability-identifier-naming.GetConfigPerFile
-    value:           'true'
-  - key:             modernize-use-default-member-init.UseAssignment
-    value:           'false'
-  - key:             readability-function-size.NestingThreshold
-    value:           '4294967295'
-  - key:             modernize-use-override.AllowOverrideAndFinal
-    value:           'false'
-  - key:             cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes
-    value:           ''
-  - key:             readability-function-size.ParameterThreshold
-    value:           '4294967295'
-  - key:             modernize-pass-by-value.ValuesOnly
-    value:           'false'
-  - key:             readability-function-cognitive-complexity.IgnoreMacros
-    value:           'true'
-  - key:             modernize-loop-convert.IncludeStyle
-    value:           llvm
-  - key:             cert-str34-c.DiagnoseSignedUnsignedCharComparisons
-    value:           'false'
-  - key:             bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
-    value:           'false'
-  - key:             bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
-    value:           'false'
-  - key:             cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
-    value:           'false'
-  - key:             readability-redundant-smartptr-get.IgnoreMacros
-    value:           'true'
-  - key:             readability-identifier-naming.AggressiveDependentMemberLookup
-    value:           'false'
-  - key:             modernize-use-emplace.TupleTypes
-    value:           '::std::pair;::std::tuple'
-  - key:             modernize-use-emplace.TupleMakeFunctions
-    value:           '::std::make_pair;::std::make_tuple'
-  - key:             cppcoreguidelines-owning-memory.LegacyResourceProducers
-    value:           '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
-  - key:             bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
-    value:           'true'
-  - key:             bugprone-argument-comment.StrictMode
-    value:           '0'
-  - key:             modernize-replace-random-shuffle.IncludeStyle
-    value:           llvm
-  - key:             modernize-use-bool-literals.IgnoreMacros
-    value:           'true'
-  - key:             bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
-    value:           'true'
-  - key:             google-readability-namespace-comments.ShortNamespaceLines
-    value:           '10'
-  - key:             bugprone-suspicious-string-compare.StringCompareLikeFunctions
-    value:           ''
-  - key:             modernize-avoid-bind.PermissiveParameterList
-    value:           'false'
-  - key:             bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
-    value:           '1'
-  - key:             readability-suspicious-call-argument.Suffix
-    value:           'true'
-  - key:             readability-suspicious-call-argument.JaroWinklerDissimilarBelow
-    value:           '75'
-  - key:             modernize-use-noexcept.ReplacementString
-    value:           ''
-  - key:             modernize-use-override.FinalSpelling
-    value:           final
-  - key:             modernize-use-using.IgnoreMacros
-    value:           'true'
-  - key:             cppcoreguidelines-explicit-virtual-functions.FinalSpelling
-    value:           final
-  - key:             readability-suspicious-call-argument.MinimumIdentifierNameLength
-    value:           '3'
-  - key:             bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
-    value:           'true'
-  - key:             modernize-loop-convert.NamingStyle
-    value:           CamelCase
-  - key:             cppcoreguidelines-pro-type-member-init.UseAssignment
-    value:           'false'
-  - key:             bugprone-suspicious-include.HeaderFileExtensions
-    value:           ';h;hh;hpp;hxx'
-  - key:             performance-no-automatic-move.AllowedTypes
-    value:           ''
-  - key:             readability-suspicious-call-argument.SubstringDissimilarBelow
-    value:           '40'
-  - key:             bugprone-argument-comment.CommentIntegerLiterals
-    value:           '0'
-  - key:             performance-for-range-copy.WarnOnAllAutoCopies
-    value:           'false'
-  - key:             modernize-pass-by-value.IncludeStyle
-    value:           llvm
-  - key:             bugprone-argument-comment.CommentFloatLiterals
-    value:           '0'
-  - key:             bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
-    value:           '16'
-  - key:             readability-simplify-boolean-expr.ChainedConditionalReturn
-    value:           'false'
-  - key:             readability-else-after-return.WarnOnConditionVariables
-    value:           'true'
-  - key:             modernize-use-nullptr.NullMacros
-    value:           'NULL'
-  - key:             readability-suspicious-call-argument.SuffixDissimilarBelow
-    value:           '25'
-  - key:             bugprone-argument-comment.CommentCharacterLiterals
-    value:           '0'
-  - key:             cppcoreguidelines-macro-usage.AllowedRegexp
-    value:           '^DEBUG_*'
-  - key:             readability-suspicious-call-argument.LevenshteinSimilarAbove
-    value:           '66'
-  - key:             cppcoreguidelines-narrowing-conversions.PedanticMode
-    value:           'false'
-  - key:             modernize-make-shared.IgnoreDefaultInitialization
-    value:           'true'
-  - key:             readability-suspicious-call-argument.JaroWinkler
-    value:           'true'
-  - key:             bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
-    value:           'true'
-  - key:             modernize-make-shared.IncludeStyle
-    value:           llvm
-  - key:             readability-suspicious-call-argument.Prefix
-    value:           'true'
-  - key:             cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
-    value:           'false'
-  - key:             bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
-    value:           'true'
-  - key:             bugprone-signed-char-misuse.CharTypdefsToIgnore
-    value:           ''
-  - key:             cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
-    value:           'true'
-  - key:             modernize-make-unique.IgnoreMacros
-    value:           'true'
-  - key:             performance-for-range-copy.AllowedTypes
-    value:           ''
-  - key:             bugprone-argument-comment.CommentBoolLiterals
-    value:           '0'
-  - key:             readability-braces-around-statements.ShortStatementLines
-    value:           '0'
-  - key:             bugprone-argument-comment.CommentUserDefinedLiterals
-    value:           '0'
-  - key:             readability-magic-numbers.IgnoredFloatingPointValues
-    value:           '1.0;100.0;'
-  - key:             readability-implicit-bool-conversion.AllowPointerConditions
-    value:           'false'
-  - key:             performance-inefficient-string-concatenation.StrictMode
-    value:           'false'
-  - key:             bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
-    value:           'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
-  - key:             modernize-make-unique.MakeSmartPtrFunction
-    value:           'std::make_unique'
-  - key:             readability-redundant-declaration.IgnoreMacros
-    value:           'true'
-  - key:             portability-restrict-system-includes.Includes
-    value:           '*'
-  - key:             modernize-make-unique.MakeSmartPtrFunctionHeader
-    value:           '<memory>'
-  - key:             bugprone-signal-handler.AsyncSafeFunctionSet
-    value:           POSIX
-  - key:             bugprone-easily-swappable-parameters.ModelImplicitConversions
-    value:           'true'
-  - key:             readability-suspicious-call-argument.SubstringSimilarAbove
-    value:           '50'
-  - key:             cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
-    value:           'false'
-  - key:             cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
-    value:           'true'
-  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
-    value:           'false'
-  - key:             cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
-    value:           'false'
-  - key:             modernize-use-noexcept.UseNoexceptFalse
-    value:           'true'
-  - key:             readability-function-cognitive-complexity.Threshold
-    value:           '75'
-  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
-    value:           'true'
-  - key:             bugprone-argument-comment.IgnoreSingleArgument
-    value:           '0'
-  - key:             bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
-    value:           'true'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
-    value:           'false'
-  - key:             performance-faster-string-find.StringLikeClasses
-    value:           '::std::basic_string;::std::basic_string_view'
-  - key:             bugprone-assert-side-effect.CheckFunctionCalls
-    value:           'false'
-  - key:             bugprone-string-constructor.StringNames
-    value:           '::std::basic_string;::std::basic_string_view'
-  - key:             bugprone-assert-side-effect.AssertMacros
-    value:           assert,NSAssert,NSCAssert
-  - key:             bugprone-exception-escape.IgnoredExceptions
-    value:           ''
-  - key:             bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
-    value:           'true'
-  - key:             modernize-use-default-member-init.IgnoreMacros
-    value:           'true'
-  - key:             llvm-qualified-auto.AddConstToQualified
-    value:           'false'
-  - key:             llvm-else-after-return.WarnOnConditionVariables
-    value:           'false'
-  - key:             bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
-    value:           'true'
-  - key:             modernize-raw-string-literal.DelimiterStem
-    value:           lit
-  - key:             readability-suspicious-call-argument.Dice
-    value:           'true'
-  - key:             modernize-raw-string-literal.ReplaceShorterLiterals
-    value:           'false'
-  - key:             readability-magic-numbers.IgnoredIntegerValues
-    value:           '1;2;3;4;'
-  - key:             performance-inefficient-vector-operation.VectorLikeClasses
-    value:           '::std::vector'
-  - key:             modernize-use-auto.RemoveStars
-    value:           'false'
-  - key:             bugprone-implicit-widening-of-multiplication-result.IncludeStyle
-    value:           llvm
-  - key:             portability-simd-intrinsics.Std
-    value:           ''
-  - key:             performance-unnecessary-value-param.IncludeStyle
-    value:           llvm
-  - key:             readability-redundant-member-init.IgnoreBaseInCopyConstructors
-    value:           'false'
-  - key:             modernize-replace-disallow-copy-and-assign-macro.MacroName
-    value:           DISALLOW_COPY_AND_ASSIGN
-  - key:             llvm-else-after-return.WarnOnUnfixable
-    value:           'false'
+  - key: readability-suspicious-call-argument.PrefixSimilarAbove
+    value: '30'
+  - key: cppcoreguidelines-no-malloc.Reallocations
+    value: '::realloc'
+  - key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
+    value: '::free;::realloc;::freopen;::fclose'
+  - key: bugprone-reserved-identifier.Invert
+    value: 'false'
+  - key: bugprone-narrowing-conversions.PedanticMode
+    value: 'false'
+  - key: bugprone-unused-return-value.CheckedFunctions
+    value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
+  - key: modernize-use-auto.MinTypeNameLength
+    value: '5'
+  - key: cppcoreguidelines-macro-usage.CheckCapsOnly
+    value: 'false'
+  - key: readability-inconsistent-declaration-parameter-name.Strict
+    value: 'false'
+  - key: readability-suspicious-call-argument.DiceDissimilarBelow
+    value: '60'
+  - key: readability-suspicious-call-argument.Equality
+    value: 'true'
+  - key: bugprone-easily-swappable-parameters.QualifiersMix
+    value: 'false'
+  - key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
+    value: 'true'
+  - key: bugprone-argument-comment.CommentNullPtrs
+    value: '0'
+  - key: cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+    value: 'true'
+  - key: cppcoreguidelines-init-variables.IncludeStyle
+    value: llvm
+  - key: modernize-use-nodiscard.ReplacementString
+    value: '[[nodiscard]]'
+  - key: modernize-loop-convert.MakeReverseRangeHeader
+    value: ''
+  - key: readability-suspicious-call-argument.SuffixSimilarAbove
+    value: '30'
+  - key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerNarrowingConversion
+    value: 'true'
+  - key: bugprone-easily-swappable-parameters.IgnoredParameterNames
+    value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
+  - key: modernize-loop-convert.UseCxx20ReverseRanges
+    value: 'true'
+  - key: cppcoreguidelines-prefer-member-initializer.UseAssignment
+    value: 'false'
+  - key: performance-type-promotion-in-math-fn.IncludeStyle
+    value: llvm
+  - key: readability-function-cognitive-complexity.DescribeBasicIncrements
+    value: 'true'
+  - key: bugprone-suspicious-include.ImplementationFileExtensions
+    value: 'c;cc;cpp;cxx'
+  - key: modernize-loop-convert.MakeReverseRangeFunction
+    value: ''
+  - key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
+    value: 'true'
+  - key: bugprone-suspicious-missing-comma.SizeThreshold
+    value: '5'
+  - key: readability-identifier-naming.IgnoreFailedSplit
+    value: 'false'
+  - key: readability-qualified-auto.AddConstToQualified
+    value: 'true'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfThis
+    value: 'true'
+  - key: bugprone-string-constructor.WarnOnLargeLength
+    value: 'true'
+  - key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
+    value: override
+  - key: readability-uppercase-literal-suffix.IgnoreMacros
+    value: 'true'
+  - key: modernize-make-shared.IgnoreMacros
+    value: 'true'
+  - key: bugprone-dynamic-static-initializers.HeaderFileExtensions
+    value: ';h;hh;hpp;hxx'
+  - key: bugprone-suspicious-enum-usage.StrictMode
+    value: 'false'
+  - key: performance-unnecessary-copy-initialization.AllowedTypes
+    value: ''
+  - key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
+    value: '5'
+  - key: modernize-use-transparent-functors.SafeMode
+    value: 'false'
+  - key: readability-suspicious-call-argument.Levenshtein
+    value: 'true'
+  - key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
+    value: 'true'
+  - key: bugprone-string-constructor.LargeLengthThreshold
+    value: '8388608'
+  - key: readability-simplify-boolean-expr.ChainedConditionalAssignment
+    value: 'false'
+  - key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
+    value: 'false'
+  - key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
+    value: 'false'
+  - key: bugprone-exception-escape.FunctionsThatShouldNotThrow
+    value: ''
+  - key: performance-inefficient-vector-operation.EnableProto
+    value: 'false'
+  - key: modernize-make-shared.MakeSmartPtrFunction
+    value: 'std::make_shared'
+  - key: modernize-loop-convert.MaxCopySize
+    value: '16'
+  - key: readability-suspicious-call-argument.PrefixDissimilarBelow
+    value: '25'
+  - key: readability-function-size.LineThreshold
+    value: '4294967295'
+  - key: bugprone-easily-swappable-parameters.MinimumLength
+    value: '4'
+  - key: portability-simd-intrinsics.Suggest
+    value: 'false'
+  - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
+    value: ''
+  - key: modernize-use-override.IgnoreDestructors
+    value: 'false'
+  - key: modernize-make-shared.MakeSmartPtrFunctionHeader
+    value: '<memory>'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfConstant
+    value: 'true'
+  - key: readability-redundant-string-init.StringNames
+    value: '::std::basic_string_view;::std::basic_string'
+  - key: modernize-make-unique.IgnoreDefaultInitialization
+    value: 'true'
+  - key: modernize-use-emplace.ContainersWithPushBack
+    value: '::std::vector;::std::list;::std::deque'
+  - key: readability-magic-numbers.IgnoreBitFieldsWidths
+    value: 'true'
+  - key: modernize-make-unique.IncludeStyle
+    value: llvm
+  - key: modernize-use-override.OverrideSpelling
+    value: override
+  - key: readability-suspicious-call-argument.LevenshteinDissimilarBelow
+    value: '50'
+  - key: bugprone-argument-comment.CommentStringLiterals
+    value: '0'
+  - key: concurrency-mt-unsafe.FunctionSet
+    value: any
+  - key: google-readability-braces-around-statements.ShortStatementLines
+    value: '1'
+  - key: bugprone-reserved-identifier.AllowedIdentifiers
+    value: ''
+  - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
+    value: 'false'
+  - key: readability-else-after-return.WarnOnUnfixable
+    value: 'true'
+  - key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
+    value: '1.0;100.0;'
+  - key: modernize-use-emplace.IgnoreImplicitConstructors
+    value: 'false'
+  - key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
+    value: 'true'
+  - key: readability-suspicious-call-argument.Substring
+    value: 'true'
+  - key: modernize-use-equals-delete.IgnoreMacros
+    value: 'true'
+  - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
+    value: llvm
+  - key: readability-magic-numbers.IgnoreAllFloatingPointValues
+    value: 'false'
+  - key: readability-suspicious-call-argument.Abbreviations
+    value: 'arr=array;cnt=count;idx=index;src=source;stmt=statement;cpy=copy;dest=destination;dist=distancedst=distance;ptr=pointer;wdth=width;str=string;ln=line;srv=server;attr=attribute;ref=reference;buf=buffer;col=column;nr=number;vec=vector;len=length;elem=element;val=value;i=index;var=variable;hght=height;cl=client;num=number;pos=position;lst=list;addr=address'
+  - key: bugprone-misplaced-widening-cast.CheckImplicitCasts
+    value: 'false'
+  - key: readability-uppercase-literal-suffix.NewSuffixes
+    value: ''
+  - key: modernize-loop-convert.MinConfidence
+    value: reasonable
+  - key: performance-unnecessary-value-param.AllowedTypes
+    value: ''
+  - key: readability-uniqueptr-delete-release.PreferResetCall
+    value: 'false'
+  - key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
+    value: 'false'
+  - key: google-readability-namespace-comments.SpacesBeforeComments
+    value: '2'
+  - key: cppcoreguidelines-avoid-magic-numbers.IgnoreBitFieldsWidths
+    value: 'true'
+  - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
+    value: '1;2;3;4;'
+  - key: cppcoreguidelines-no-malloc.Allocations
+    value: '::malloc;::calloc'
+  - key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
+    value: ''
+  - key: readability-function-size.BranchThreshold
+    value: '4294967295'
+  - key: bugprone-suspicious-missing-comma.RatioThreshold
+    value: '0.200000'
+  - key: readability-implicit-bool-conversion.AllowIntegerConditions
+    value: 'false'
+  - key: readability-function-size.StatementThreshold
+    value: '800'
+  - key: readability-identifier-naming.IgnoreMainLikeFunctions
+    value: 'false'
+  - key: cppcoreguidelines-init-variables.MathHeader
+    value: '<math.h>'
+  - key: google-readability-function-size.StatementThreshold
+    value: '800'
+  - key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
+    value: 'false'
+  - key: readability-suspicious-call-argument.DiceSimilarAbove
+    value: '70'
+  - key: modernize-use-equals-default.IgnoreMacros
+    value: 'true'
+  - key: readability-suspicious-call-argument.Abbreviation
+    value: 'true'
+  - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value: 'false'
+  - key: modernize-use-emplace.SmartPointers
+    value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
+  - key: cppcoreguidelines-no-malloc.Deallocations
+    value: '::free'
+  - key: bugprone-dangling-handle.HandleClasses
+    value: 'std::basic_string_view;std::experimental::basic_string_view'
+  - key: readability-magic-numbers.IgnorePowersOf2IntegerValues
+    value: 'false'
+  - key: readability-suspicious-call-argument.JaroWinklerSimilarAbove
+    value: '85'
+  - key: readability-simplify-subscript-expr.Types
+    value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
+  - key: performance-unnecessary-copy-initialization.ExcludedContainerTypes
+    value: ''
+  - key: modernize-replace-auto-ptr.IncludeStyle
+    value: llvm
+  - key: performance-move-const-arg.CheckTriviallyCopyableMove
+    value: 'true'
+  - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
+    value: '3'
+  - key: readability-function-size.VariableThreshold
+    value: '4294967295'
+  - key: cert-dcl16-c.NewSuffixes
+    value: 'L;LL;LU;LLU'
+  - key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
+    value: 'true'
+  - key: readability-identifier-naming.GetConfigPerFile
+    value: 'true'
+  - key: modernize-use-default-member-init.UseAssignment
+    value: 'false'
+  - key: readability-function-size.NestingThreshold
+    value: '4294967295'
+  - key: modernize-use-override.AllowOverrideAndFinal
+    value: 'false'
+  - key: cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes
+    value: ''
+  - key: readability-function-size.ParameterThreshold
+    value: '4294967295'
+  - key: modernize-pass-by-value.ValuesOnly
+    value: 'false'
+  - key: readability-function-cognitive-complexity.IgnoreMacros
+    value: 'true'
+  - key: modernize-loop-convert.IncludeStyle
+    value: llvm
+  - key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
+    value: 'false'
+  - key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
+    value: 'false'
+  - key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
+    value: 'false'
+  - key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
+    value: 'false'
+  - key: readability-redundant-smartptr-get.IgnoreMacros
+    value: 'true'
+  - key: readability-identifier-naming.AggressiveDependentMemberLookup
+    value: 'false'
+  - key: modernize-use-emplace.TupleTypes
+    value: '::std::pair;::std::tuple'
+  - key: modernize-use-emplace.TupleMakeFunctions
+    value: '::std::make_pair;::std::make_tuple'
+  - key: cppcoreguidelines-owning-memory.LegacyResourceProducers
+    value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
+  - key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
+    value: 'true'
+  - key: bugprone-argument-comment.StrictMode
+    value: '0'
+  - key: modernize-replace-random-shuffle.IncludeStyle
+    value: llvm
+  - key: modernize-use-bool-literals.IgnoreMacros
+    value: 'true'
+  - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
+    value: 'true'
+  - key: google-readability-namespace-comments.ShortNamespaceLines
+    value: '10'
+  - key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
+    value: ''
+  - key: modernize-avoid-bind.PermissiveParameterList
+    value: 'false'
+  - key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
+    value: '1'
+  - key: readability-suspicious-call-argument.Suffix
+    value: 'true'
+  - key: readability-suspicious-call-argument.JaroWinklerDissimilarBelow
+    value: '75'
+  - key: modernize-use-noexcept.ReplacementString
+    value: ''
+  - key: modernize-use-override.FinalSpelling
+    value: final
+  - key: modernize-use-using.IgnoreMacros
+    value: 'true'
+  - key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling
+    value: final
+  - key: readability-suspicious-call-argument.MinimumIdentifierNameLength
+    value: '3'
+  - key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
+    value: 'true'
+  - key: modernize-loop-convert.NamingStyle
+    value: CamelCase
+  - key: cppcoreguidelines-pro-type-member-init.UseAssignment
+    value: 'false'
+  - key: bugprone-suspicious-include.HeaderFileExtensions
+    value: ';h;hh;hpp;hxx'
+  - key: performance-no-automatic-move.AllowedTypes
+    value: ''
+  - key: readability-suspicious-call-argument.SubstringDissimilarBelow
+    value: '40'
+  - key: bugprone-argument-comment.CommentIntegerLiterals
+    value: '0'
+  - key: performance-for-range-copy.WarnOnAllAutoCopies
+    value: 'false'
+  - key: modernize-pass-by-value.IncludeStyle
+    value: llvm
+  - key: bugprone-argument-comment.CommentFloatLiterals
+    value: '0'
+  - key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
+    value: '16'
+  - key: readability-simplify-boolean-expr.ChainedConditionalReturn
+    value: 'false'
+  - key: readability-else-after-return.WarnOnConditionVariables
+    value: 'true'
+  - key: modernize-use-nullptr.NullMacros
+    value: 'NULL'
+  - key: readability-suspicious-call-argument.SuffixDissimilarBelow
+    value: '25'
+  - key: bugprone-argument-comment.CommentCharacterLiterals
+    value: '0'
+  - key: cppcoreguidelines-macro-usage.AllowedRegexp
+    value: '^DEBUG_*'
+  - key: readability-suspicious-call-argument.LevenshteinSimilarAbove
+    value: '66'
+  - key: cppcoreguidelines-narrowing-conversions.PedanticMode
+    value: 'false'
+  - key: modernize-make-shared.IgnoreDefaultInitialization
+    value: 'true'
+  - key: readability-suspicious-call-argument.JaroWinkler
+    value: 'true'
+  - key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
+    value: 'true'
+  - key: modernize-make-shared.IncludeStyle
+    value: llvm
+  - key: readability-suspicious-call-argument.Prefix
+    value: 'true'
+  - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
+    value: 'false'
+  - key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
+    value: 'true'
+  - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
+    value: ''
+  - key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
+    value: 'true'
+  - key: modernize-make-unique.IgnoreMacros
+    value: 'true'
+  - key: performance-for-range-copy.AllowedTypes
+    value: ''
+  - key: bugprone-argument-comment.CommentBoolLiterals
+    value: '0'
+  - key: readability-braces-around-statements.ShortStatementLines
+    value: '0'
+  - key: bugprone-argument-comment.CommentUserDefinedLiterals
+    value: '0'
+  - key: readability-magic-numbers.IgnoredFloatingPointValues
+    value: '1.0;100.0;'
+  - key: readability-implicit-bool-conversion.AllowPointerConditions
+    value: 'false'
+  - key: performance-inefficient-string-concatenation.StrictMode
+    value: 'false'
+  - key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
+    value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;FowardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
+  - key: modernize-make-unique.MakeSmartPtrFunction
+    value: 'std::make_unique'
+  - key: readability-redundant-declaration.IgnoreMacros
+    value: 'true'
+  - key: portability-restrict-system-includes.Includes
+    value: '*'
+  - key: modernize-make-unique.MakeSmartPtrFunctionHeader
+    value: '<memory>'
+  - key: bugprone-signal-handler.AsyncSafeFunctionSet
+    value: POSIX
+  - key: bugprone-easily-swappable-parameters.ModelImplicitConversions
+    value: 'true'
+  - key: readability-suspicious-call-argument.SubstringSimilarAbove
+    value: '50'
+  - key: cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
+    value: 'false'
+  - key: cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
+    value: 'true'
+  - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
+    value: 'false'
+  - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
+    value: 'false'
+  - key: modernize-use-noexcept.UseNoexceptFalse
+    value: 'true'
+  - key: readability-function-cognitive-complexity.Threshold
+    value: '75'
+  - key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
+    value: 'true'
+  - key: bugprone-argument-comment.IgnoreSingleArgument
+    value: '0'
+  - key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
+    value: 'true'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
+    value: 'false'
+  - key: performance-faster-string-find.StringLikeClasses
+    value: '::std::basic_string;::std::basic_string_view'
+  - key: bugprone-assert-side-effect.CheckFunctionCalls
+    value: 'false'
+  - key: bugprone-string-constructor.StringNames
+    value: '::std::basic_string;::std::basic_string_view'
+  - key: bugprone-assert-side-effect.AssertMacros
+    value: assert,NSAssert,NSCAssert
+  - key: bugprone-exception-escape.IgnoredExceptions
+    value: ''
+  - key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
+    value: 'true'
+  - key: modernize-use-default-member-init.IgnoreMacros
+    value: 'true'
+  - key: llvm-qualified-auto.AddConstToQualified
+    value: 'false'
+  - key: llvm-else-after-return.WarnOnConditionVariables
+    value: 'false'
+  - key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
+    value: 'true'
+  - key: modernize-raw-string-literal.DelimiterStem
+    value: lit
+  - key: readability-suspicious-call-argument.Dice
+    value: 'true'
+  - key: modernize-raw-string-literal.ReplaceShorterLiterals
+    value: 'false'
+  - key: readability-magic-numbers.IgnoredIntegerValues
+    value: '1;2;3;4;'
+  - key: performance-inefficient-vector-operation.VectorLikeClasses
+    value: '::std::vector'
+  - key: modernize-use-auto.RemoveStars
+    value: 'false'
+  - key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
+    value: llvm
+  - key: portability-simd-intrinsics.Std
+    value: ''
+  - key: performance-unnecessary-value-param.IncludeStyle
+    value: llvm
+  - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
+    value: 'false'
+  - key: modernize-replace-disallow-copy-and-assign-macro.MacroName
+    value: DISALLOW_COPY_AND_ASSIGN
+  - key: llvm-else-after-return.WarnOnUnfixable
+    value: 'false'
+# yamllint enable
 ...
index 13044f019de23b10117fdac42a99a129b7255a0c..13362b2a212a747f8cd9ea779db87cc8b1783b50 100644 (file)
@@ -9,7 +9,7 @@ assignees: ''
 
 <!-- Hi! Thanks for filing an issue. It will be read with care by human beings. Can we ask you to please fill out this template and not simply demand new features or send in complaints? Thanks! -->
 <!-- Also please search the existing issues (both open and closed) to see if your report might be duplicate -->
-- [ ] This is not a support question, I have read [about opensource](https://www.powerdns.com/opensource.html) and will send support questions to the IRC channel, [Github Discussions](https://github.com/PowerDNS/pdns/discussions/) or the mailing list.
+- [ ] This is not a support question, I have read [about opensource](https://www.powerdns.com/opensource.html) and will send support questions to the IRC channel, [GitHub Discussions](https://github.com/PowerDNS/pdns/discussions/) or the mailing list.
 - [ ] I have read and understood the ['out in the open' support policy](https://blog.powerdns.com/2016/01/18/open-source-support-out-in-the-open/)
 
 <!-- Tell us what is issue is about -->
index cd77ab8d2094ea254a966dfe7bcaa5828db68b53..bfd1ef6d5fbc12673eccddcd2785158b9d72db7f 100644 (file)
@@ -23,6 +23,7 @@ Aki
 Alenichev
 alexa
 algoroll
+alloca
 allocs
 Altpeter
 Anderton
@@ -162,9 +163,11 @@ cachekey
 Cairney
 calculatesoaserial
 calidns
+capf
 Cauquil
 ccache
 ccc
+ccls
 ccounts
 cdb
 CDBKV
@@ -183,6 +186,7 @@ chopoff
 Christof
 chrooted
 chrooting
+clangd
 clientanswers
 Cloos
 closesocket
@@ -208,8 +212,10 @@ colm
 comboaddress
 commandline
 committransaction
+compiledb
 conaxis
 configfile
+configmap
 configname
 configsetting
 confs
@@ -224,6 +230,7 @@ coredumps
 cornercases
 corpit
 costypetrisor
+coverallsapp
 coverity
 cppcheck
 createslavedomain
@@ -244,6 +251,8 @@ cvename
 cvs
 cvstrac
 CXXFLAGS
+cxxsettings
+cxxsupport
 daemonizing
 daemontools
 Daganoto
@@ -257,6 +266,7 @@ Daugaard
 Davids
 Dayneko
 dbfile
+dblacka
 dblfilename
 dblookup
 dbpf
@@ -270,6 +280,7 @@ deboynepollard
 Deduktiva
 dedup
 defcontent
+defmacro
 defpol
 defttl
 Dehaine
@@ -293,6 +304,7 @@ dilinger
 Dimitrios
 Directi
 Disqus
+distclean
 djbdns
 dlerror
 dlg
@@ -349,6 +361,7 @@ domainrelatedobject
 Donatas
 dontcare
 doq
+dotout
 downsides
 downstreams
 dport
@@ -361,6 +374,7 @@ DTS
 Dufberg
 dumpluaraw
 dumresp
+dwarfstd
 dynblock
 dynblocklist
 dynblocksref
@@ -375,7 +389,6 @@ ebpfblocklist
 ECCN
 ech
 econds
-ECSDA
 ecswho
 editline
 edns
@@ -385,12 +398,18 @@ ednsoptionview
 ednssubnet
 EDNSTo
 edu
+eglot
 ejones
 Ekkelenkamp
+eldoc
 elgoog
+elisp
+elpa
+emacs
 endbr
 Enden
 enp
+Ensar
 ent
 envoutput
 epel
@@ -426,6 +445,8 @@ firewalled
 firewalls
 fixednow
 Florus
+flycheck
+flyspell
 footerbgcolor
 footertextcolor
 forfun
@@ -445,6 +466,7 @@ fulltoc
 fullycapable
 Furnell
 Fusl
+fuzzers
 fwzones
 FYhvws
 FZq
@@ -453,6 +475,8 @@ gacogne
 gatech
 Gavarret
 Gbps
+gcna
+gcovr
 gdpr
 Geijn
 genindex
@@ -481,6 +505,7 @@ gettime
 gettsigkey
 Geuze
 GFm
+ggdb
 Ghz
 Gibheer
 Gieben
@@ -518,6 +543,7 @@ Hannu
 Harker
 Hausberger
 headbgcolor
+headerline
 headerlink
 headfont
 headlinkcolor
@@ -563,6 +589,7 @@ ifportup
 ifurlextup
 ifurlup
 ihsinme
+imenu
 Imhard
 incbin
 includeboilerplate
@@ -606,6 +633,7 @@ Jelte
 Jermar
 Jeroen
 jessie
+joaotavora
 jonathaneen
 Jong
 Jorn
@@ -625,6 +653,8 @@ Kerkhof
 KEYBITS
 keyblock
 keydir
+keyids
+keymap
 keyname
 keypair
 keypairgen
@@ -632,6 +662,7 @@ keyroll
 keyroller
 keysearch
 keysize
+keystyle
 keytab
 keytype
 keywordmatches
@@ -654,6 +685,7 @@ ktls
 KTNAME
 Kuehrer
 kvs
+KVTo
 kxdpgun
 Ladot
 Lafon
@@ -667,9 +699,9 @@ latexpdf
 latlon
 latlonloc
 latomic
-lauch
 Laurient
 Laursen
+lcov
 LCUP
 LDA
 ldapbackend
@@ -685,6 +717,7 @@ lethalgroup
 letsencrypt
 letterpaper
 libatomic
+libclang
 libcrypto
 libcryptopp
 libdecaf
@@ -704,8 +737,10 @@ libpqpp
 libresolv
 libressl
 librt
+libsettings
 libsodium
 libsofthsm
+libstdc
 libsystemd
 libtdsodbc
 libxdp
@@ -741,6 +776,7 @@ loweralpha
 lowerroman
 Lrhazi
 lsock
+lsp
 lto
 luaaction
 luabackend
@@ -781,6 +817,7 @@ MBOXFW
 mbytes
 Meerwald
 Mekking
+melpa
 memlock
 Memusage
 menuselection
@@ -806,6 +843,7 @@ mmdb
 mnordhoff
 MOADNS
 Modderman
+modeline
 modifyingpolicydecisions
 modindex
 monshouwer
@@ -864,10 +902,12 @@ netherlabs
 netinet
 netmaskgroup
 netmasks
+netms
 netsnmp
 NETWORKMASK
 Neue
 Neuf
+newcomment
 newcontent
 nftables
 nic
@@ -886,6 +926,7 @@ NODCACHEDIRNOD
 NODCACHEDIRUDR
 noedns
 noerrors
+NOLINTNEXTLINE
 NOLOCK
 nometasync
 Nominet
@@ -925,6 +966,7 @@ NULs
 NUMA
 numreceived
 nvd
+nwk
 nxd
 NXDATA
 nxdomain
@@ -975,7 +1017,6 @@ PACKAGEVERSION
 packetcache
 packethandler
 papersize
-paramater
 PARAMKEYWORDS
 PATC
 patchlevels
@@ -986,9 +1027,11 @@ Pbackend
 PCache
 pcap
 PCAPFILE
+pch
 pdns
 pdnsbackend
 pdnscontrol
+pdnskeyroller
 pdnsldap
 pdnslog
 pdnsodbx
@@ -1004,6 +1047,7 @@ Pertubation
 Pfetzing
 pgmysql
 pgmysqlbackend
+PGO
 pgp
 pgpsql
 phishing
@@ -1018,10 +1062,12 @@ pickwhashed
 pickwrandom
 piddir
 pidfile
+PIDs
 pilindex
 Pinski
 pipebackend
 pipermail
+pkghashes
 Plusnet
 plzz
 pmtmr
@@ -1048,6 +1094,7 @@ powerldap
 Predota
 preoutquery
 Preproc
+prepublishkeyroll
 prequery
 prerpz
 presignedness
@@ -1056,6 +1103,9 @@ primetime
 princ
 prioritization
 privs
+profdata
+profraw
+progn
 protobuf
 protozero
 providername
@@ -1089,6 +1139,7 @@ querycount
 querytime
 qytpe
 ragel
+raii
 Rak
 randombackend
 randombit
@@ -1112,6 +1163,7 @@ recursor
 recursord
 recursordist
 Recursordoc
+Recursorsettings
 Recuweb
 recvbuf
 recverr
@@ -1146,7 +1198,6 @@ respawning
 respout
 respsizes
 resynchronise
-retransfering
 reuseds
 reuseport
 RFCs
@@ -1155,11 +1206,13 @@ Rietz
 rightsidebar
 Rijsdijk
 ringbuffer
+rizsotto
 rkey
 rmem
 rname
 rocommunity
 Roel
+rolltype
 Rosmalen
 roundrobin
 rping
@@ -1209,7 +1262,7 @@ segfault
 selectmplexer
 senderrors
 Sendetzky
-sensistive
+serde
 Sergey
 serverpools
 serverselection
@@ -1221,6 +1274,7 @@ seting
 setkey
 setnotified
 SETPIPE
+setq
 settting
 setvariable
 Shabanov
@@ -1270,6 +1324,7 @@ socketdir
 softhsm
 Soldaat
 somedomain
+somestruct
 Sonix
 Soref
 Soroceanu
@@ -1288,6 +1343,7 @@ SPHINXOPTS
 SPHINXPROJ
 sphinxsidebar
 sphinxsidebarwrapper
+Spinlocks
 splitsetup
 Spruyt
 SQLs
@@ -1326,7 +1382,9 @@ Stussy
 stutiredboy
 subkey
 submitters
+subnamespace
 subnetmask
+substructs
 suffixmatchtree
 Sukhbir
 supermaster
@@ -1353,13 +1411,14 @@ Tarnell
 taskqueue
 tbhandler
 tcely
-TCounters
+tcounters
 tcpconnecttimeouts
 tcpdump
 TCPKEEPALIVE
 tcplatency
 tcpmaxconcurrentconnections
 tcpnewconnections
+tcpout
 tcpreusedconnections
 tcptoomanyconcurrentconnections
 tds
@@ -1389,6 +1448,7 @@ tisr
 tlsa
 tmpfs
 tobool
+TOCTOU
 toctree
 todos
 toint
@@ -1396,7 +1456,9 @@ tokenuser
 Tolstov
 Toosarani
 Toshifumi
+totms
 Travaille
+treemacs
 tribool
 trustanchor
 trustanchorfile
@@ -1438,10 +1500,9 @@ uninett
 uninitialised
 Uninstaller
 unistd
-unitialized
 unixodbc
 unixtime
-unparseable
+unparsable
 UNPRIV
 unpublishdomainkey
 unreachables
@@ -1474,6 +1535,7 @@ Viala
 viewcode
 visitedlinkcolor
 vixie
+vla
 Voegeli
 Volker
 voxel
@@ -1521,6 +1583,7 @@ wouter
 wpad
 wproduction
 wrandom
+wrapv
 wuh
 Wzs
 Xander
@@ -1530,7 +1593,6 @@ xdp
 Xek
 Xeon
 XForwarded
-XFR
 Xiang
 xorbooter
 xpf
@@ -1538,9 +1600,11 @@ XRecord
 xsk
 xskmap
 XXXXXX
+XXXXXXX
 yahttp
 yamlconversion
 yamlsettings
+yasnippet
 Yehuda
 yeswehack
 Yiu
index d4d5dca9fbd15b2f93f3ca3d4ca18ccf25ab55ab..ee4183ff66c823d158160ea43efee6d40c419370 100644 (file)
@@ -1,3 +1,4 @@
 /docs/
 ^docs/
+\.md$
 pdns/recursordist/settings/table.py
index 25f42486e73b2cac4d2b1242540fe52819ae3405..6b4d3610fe1fbe58acc815b3b4dbdcd8672efd05 100644 (file)
@@ -85,7 +85,7 @@ DoH
 # hit-count: 9 file-count: 7
 # Compiler flags
 (?:^|[\t ,"'`=(])-[DWL](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
-(?:^|[\t ,"'`=(])-f(?!ield|ile|ilter|orce|unction)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
+(?:^|[\t ,"'`=(])-f(?!ield|ile|ilter|orce|ormat|unction)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
 (?:^|[\t ,"'`=(])-l(?!imited)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
 
 # hit-count: 9 file-count: 2
@@ -147,3 +147,6 @@ DoH
 
 # ignore long runs of a single character:
 \b([A-Za-z])\g{-1}{3,}\b
+
+# scrypt / argon
+\$(?:scrypt|argon\d+[di]*)\$\S+
index b00829dfa305842814fa326179a8164a6f88c83b..32fad390f29e316fe09bde502747e835d8aa8986 100644 (file)
@@ -12,7 +12,6 @@ permissions: # least privileges, see https://docs.github.com/en/actions/using-wo
 
 jobs:
   call-build-and-test-all-master-debian-11:
-    name: Call build-and-test-all master using debian 11 as docker runner image
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@master
     with:
@@ -20,71 +19,49 @@ jobs:
       runner-docker-image-name: base-pdns-ci-image/debian-11-pdns-base
 
   call-build-and-test-all-auth-49:
-    name: Call build-and-test-all rel/auth-4.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.9.x
     with:
       branch-name: rel/auth-4.9.x
 
   call-build-and-test-all-auth-48:
-    name: Call build-and-test-all rel/auth-4.8.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.8.x
     with:
       branch-name: rel/auth-4.8.x
 
   call-build-and-test-all-auth-47:
-    name: Call build-and-test-all rel/auth-4.7.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.7.x
     with:
       branch-name: rel/auth-4.7.x
 
-  call-build-and-test-all-auth-46:
-    name: Call build-and-test-all rel/auth-4.6.x
+  call-build-and-test-all-rec-51:
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
-    uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/auth-4.6.x
+    uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-5.1.x
     with:
-      branch-name: rel/auth-4.6.x
+      branch-name: rel/rec-5.1.x
 
   call-build-and-test-all-rec-50:
-    name: Call build-and-test-all rel/rec-5.0.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-5.0.x
     with:
       branch-name: rel/rec-5.0.x
 
   call-build-and-test-all-rec-49:
-    name: Call build-and-test-all rel/rec-4.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-4.9.x
     with:
       branch-name: rel/rec-4.9.x
 
-  call-build-and-test-all-rec-48:
-    name: Call build-and-test-all rel/rec-4.8.x
-    if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
-    uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/rec-4.8.x
-    with:
-      branch-name: rel/rec-4.8.x
-
   call-build-and-test-all-dnsdist-19:
-    name: Call build-and-test-all rel/dnsdist-1.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.9.x
     with:
       branch-name: rel/dnsdist-1.9.x
 
   call-build-and-test-all-dnsdist-18:
-    name: Call build-and-test-all rel/dnsdist-1.8.x
     if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.8.x
     with:
       branch-name: rel/dnsdist-1.8.x
-
-  call-build-and-test-all-dnsdist-17:
-    name: Call build-and-test-all rel/dnsdist-1.7.x
-    if: ${{ vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
-    uses: PowerDNS/pdns/.github/workflows/build-and-test-all.yml@rel/dnsdist-1.7.x
-    with:
-      branch-name: rel/dnsdist-1.7.x
index 7d2e579ade48f193bf2e302f44c9d3cda4481128..4fa0b42bbad34cae23b0ba2d716484bf9c598061 100644 (file)
@@ -50,12 +50,12 @@ jobs:
           echo "tag=${{ env.DEFAULT_IMAGE_TAG }}" >> "$GITHUB_OUTPUT"
 
   build-auth:
-    name: build auth
+    name: build auth (${{ matrix.builder }})
     if: ${{ !github.event.schedule || vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
     runs-on: ubuntu-22.04
     needs: get-runner-container-image
     container:
-      image: "${{ needs.get-runner-container-image.outputs.id }}:${{ needs.get-runner-container-image.outputs.tag }}"
+      image: "${{ matrix.container_image }}"
       env:
         FUZZING_TARGETS: yes
         UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1:suppressions=${{ env.REPO_HOME }}/build-scripts/UBSan.supp"
@@ -63,12 +63,11 @@ jobs:
       options: --sysctl net.ipv6.conf.all.disable_ipv6=0
     strategy:
       matrix:
-        include:
-          - builder: autotools
-            sanitizers: asan+ubsan
-          - builder: meson
-            sanitizers: address,undefined
-            build_option: '--meson'
+        container_image: ["${{ needs.get-runner-container-image.outputs.id }}:${{ needs.get-runner-container-image.outputs.tag }}"]
+        builder: [autotools, meson]
+        exclude:
+          - container_image: "ghcr.io/powerdns/base-pdns-ci-image/debian-11-pdns-base:${{ needs.get-runner-container-image.outputs.tag }}"
+            builder: meson
       fail-fast: false
     defaults:
       run:
@@ -94,17 +93,21 @@ jobs:
           key: auth-ccache-${{ matrix.builder }}-${{ steps.get-stamp.outputs.stamp }}
           restore-keys: auth-ccache-${{ matrix.builder }}
       - name: set sanitizers
-        run: echo "SANITIZERS=${{ matrix.sanitizers }}" >> "$GITHUB_ENV"
+        run: echo "SANITIZERS=${{ matrix.builder == 'meson' && 'address,undefined' || 'asan+ubsan' }}" >> "$GITHUB_ENV"
         working-directory: .
       - run: inv install-auth-build-deps
         working-directory: .
-      - run: inv ci-autoconf ${{ matrix.build_option }}
+      - run: inv ci-autoconf ${{ matrix.builder == 'meson' && '--meson' || '' }}
         working-directory: .
-      - run: inv ci-auth-configure ${{ matrix.build_option }} -b pdns-${{ env.BUILDER_VERSION }}
+      - run: inv ci-auth-configure ${{ matrix.builder == 'meson' && '--meson' || '' }} -b pdns-${{ env.BUILDER_VERSION }}
         working-directory: .
-      - run: inv ci-auth-build ${{ matrix.build_option }} # This runs under pdns-$BUILDER_VERSION/pdns/ for make bear
+      - run: inv ci-auth-build ${{ matrix.builder == 'meson' && '--meson' || '' }} # This runs under pdns-$BUILDER_VERSION/pdns/ for make bear
       - run: inv ci-auth-install-remotebackend-test-deps
-      - run: inv ci-auth-run-unit-tests ${{ matrix.build_option }}
+      - if: ${{ matrix.builder == 'meson' }}
+        run: inv install-auth-test-deps-only -b geoip
+      - run: inv ci-auth-run-unit-tests ${{ matrix.builder == 'meson' && '--meson' || '' }}
+        env:
+          PDNS_BUILD_PATH: ../pdns-${{ env.BUILDER_VERSION }}
       - run: inv generate-coverage-info ./testrunner $GITHUB_WORKSPACE
         if: ${{ env.COVERAGE == 'yes' && matrix.builder != 'meson' }}
         working-directory: ./pdns-${{ env.BUILDER_VERSION }}/pdns
@@ -112,11 +115,12 @@ jobs:
         if: ${{ env.COVERAGE == 'yes' && matrix.builder != 'meson' }}
         uses: coverallsapp/github-action@v2
         with:
-          flag-name: auth-unit-${{ matrix.sanitizers }}
+          flag-name: auth-unit-${{ env.SANITIZERS }}
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
-      - run: inv ci-auth-install ${{ matrix.build_option }}
+          fail-on-error: false
+      - run: inv ci-auth-install ${{ matrix.builder == 'meson' && '--meson' || '' }}
       - run: ccache -s
       - if: ${{ matrix.builder != 'meson' }}
         run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
@@ -191,6 +195,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
       - run: inv ci-make-install
       - run: ccache -s
       - run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
@@ -267,6 +272,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
       - run: inv ci-make-install
       - run: ccache -s
       - run: echo "normalized-branch-name=${{ inputs.branch-name || github.ref_name }}" | tr "/" "-" >> "$GITHUB_ENV"
@@ -341,6 +347,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-auth-backend:
     needs:
@@ -415,7 +422,7 @@ jobs:
             env: {}
             ports: []
           - backend: godbc_mssql
-            image: mcr.microsoft.com/mssql/server:2017-GA-ubuntu
+            image: mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04
             env:
               ACCEPT_EULA: Y
               SA_PASSWORD: 'SAsa12%%-not-a-secret-password'
@@ -467,6 +474,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-ixfrdist:
     needs:
@@ -504,6 +512,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-recursor-api:
     needs:
@@ -549,6 +558,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-recursor-regression:
     needs:
@@ -596,6 +606,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-recursor-bulk:
     name: 'test rec *mini* bulk'
@@ -641,6 +652,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   test-dnsdist-regression:
     needs:
@@ -688,6 +700,7 @@ jobs:
           path-to-lcov: $GITHUB_WORKSPACE/coverage.lcov
           parallel: true
           allow-empty: true
+          fail-on-error: false
 
   swagger-syntax-check:
     if: ${{ !github.event.schedule || vars.SCHEDULED_JOBS_BUILD_AND_TEST_ALL }}
@@ -728,6 +741,7 @@ jobs:
         uses: coverallsapp/github-action@v2
         with:
           parallel-finished: true
+          fail-on-error: false
       - name: Install jq and jc
         run: "sudo apt-get update && sudo apt-get install jq jc"
       - name: Fail job if any of the previous jobs failed
index fd78616a101c3e97ede7cb1637d95283b1a94565..d760733b858594a8cfcbb4a0f8ae3da71dc678ea 100644 (file)
@@ -98,7 +98,7 @@ jobs:
           tags: ${{ inputs.image-tags }}
       - name: Build and load powerdns product images
         id: build-image
-        uses: docker/build-push-action@v5
+        uses: docker/build-push-action@v6
         with:
           context: .
           file: Dockerfile-${{ inputs.product }}
diff --git a/.github/workflows/build-packages-daily-master.yml b/.github/workflows/build-packages-daily-master.yml
new file mode 100644 (file)
index 0000000..d0f248d
--- /dev/null
@@ -0,0 +1,45 @@
+---
+name: 'daily: build packages for master '
+
+on:
+  schedule:
+    - cron: '0 5 * * *'
+
+permissions:
+  actions: read
+  id-token: write
+  contents: write
+
+jobs:
+  call-build-packages-auth:
+    uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+    with:
+      is_release: 'NO'
+      product: 'authoritative'
+      ref: master
+    secrets:
+      DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+      DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+      DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
+
+  call-build-packages-dnsdist:
+    uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+    with:
+      is_release: 'NO'
+      product: 'dnsdist'
+      ref: master
+    secrets:
+      DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+      DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+      DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
+
+  call-build-packages-rec:
+    uses: PowerDNS/pdns/.github/workflows/build-packages.yml@master
+    with:
+      is_release: 'NO'
+      product: 'recursor'
+      ref: master
+    secrets:
+      DOWNLOADS_AUTOBUILT_SECRET: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
+      DOWNLOADS_AUTOBUILT_RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
+      DOWNLOADS_AUTOBUILT_HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
index 127acc635ba417a4ec10e616d85966e1b04cc562..6ece22db86901a1793e2e668b278bc21a1eddbf4 100644 (file)
@@ -48,7 +48,7 @@ permissions: # least privileges, see https://docs.github.com/en/actions/using-wo
 jobs:
   prepare:
     name: generate OS list
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     outputs:
       oslist: ${{ steps.get-oslist.outputs.oslist }}
     steps:
@@ -60,24 +60,38 @@ jobs:
         run: echo "oslist=$(jo -a ${{ inputs.os }})" >> "$GITHUB_OUTPUT"
   build:
     needs: prepare
-    name: build ${{ inputs.product }} (${{ inputs.ref }}) for ${{ matrix.os }}
-    # on a ubuntu-20.04 VM
-    runs-on: ubuntu-20.04
+    name: ${{ inputs.product }} (${{ inputs.ref }}) on ${{ matrix.runner-os }} for ${{ matrix.os }}
+    runs-on: ${{ matrix.runner-os }}
     strategy:
       matrix:
         os: ${{fromJson(needs.prepare.outputs.oslist)}}
+        runner-os:
+          - ubuntu-22.04
+          - ubicloud-standard-2-arm
+        exclude:
+          - os: el-7
+            runner-os: ubicloud-standard-2-arm
       fail-fast: false
     outputs:
+      product-name: ${{ steps.normalize-name.outputs.normalized-package-name }}
       version: ${{ steps.getversion.outputs.version }}
-      pkghashes-el-7: ${{ steps.pkghashes.outputs.pkghashes-el-7 }}
-      pkghashes-el-8: ${{ steps.pkghashes.outputs.pkghashes-el-8 }}
-      pkghashes-el-9: ${{ steps.pkghashes.outputs.pkghashes-el-9 }}
-      pkghashes-debian-buster: ${{ steps.pkghashes.outputs.pkghashes-debian-buster }}
-      pkghashes-debian-bullseye: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye }}
-      pkghashes-debian-bookworm: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm }}
-      pkghashes-ubuntu-focal: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal }}
-      pkghashes-ubuntu-jammy: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy }}
-      pkghashes-ubuntu-noble: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble }}
+      pkghashes-el-7-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-7-x86_64 }}
+      pkghashes-el-8-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-8-x86_64 }}
+      pkghashes-el-8-aarch64: ${{ steps.pkghashes.outputs.pkghashes-el-8-aarch64 }}
+      pkghashes-el-9-x86_64: ${{ steps.pkghashes.outputs.pkghashes-el-9-x86_64 }}
+      pkghashes-el-9-aarch64: ${{ steps.pkghashes.outputs.pkghashes-el-9-aarch64 }}
+      pkghashes-debian-buster-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-buster-x86_64 }}
+      pkghashes-debian-buster-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-buster-aarch64 }}
+      pkghashes-debian-bullseye-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye-x86_64 }}
+      pkghashes-debian-bullseye-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-bullseye-aarch64 }}
+      pkghashes-debian-bookworm-x86_64: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm-x86_64 }}
+      pkghashes-debian-bookworm-aarch64: ${{ steps.pkghashes.outputs.pkghashes-debian-bookworm-aarch64 }}
+      pkghashes-ubuntu-focal-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal-x86_64 }}
+      pkghashes-ubuntu-focal-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-focal-aarch64 }}
+      pkghashes-ubuntu-jammy-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy-x86_64 }}
+      pkghashes-ubuntu-jammy-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-jammy-aarch64 }}
+      pkghashes-ubuntu-noble-x86_64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble-x86_64 }}
+      pkghashes-ubuntu-noble-aarch64: ${{ steps.pkghashes.outputs.pkghashes-ubuntu-noble-aarch64 }}
       srchashes: ${{ steps.srchashes.outputs.srchashes }}
     steps:
       - uses: actions/checkout@v4
@@ -91,12 +105,10 @@ jobs:
         run: |
           echo "version=$(readlink builder/tmp/latest)" >> $GITHUB_OUTPUT
         id: getversion
-      - name: Upload packages as GH artifacts
-        uses: actions/upload-artifact@v4
-        with:
-          name: ${{ inputs.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}
-          path: built_pkgs/
-          retention-days: 7
+      - name: Get target architecture
+        run: |
+          echo "target-arch=$(uname -m)" >> $GITHUB_OUTPUT
+        id: getarch
       - name: Normalize package name
         id: normalize-name
         run: |
@@ -107,23 +119,30 @@ jobs:
           else
             echo "normalized-package-name=${{ inputs.product }}" >> $GITHUB_OUTPUT
           fi
-
+      - name: Include architecture in the packages compressed file name
+        run: for f in $(ls ./built_pkgs/*/*/*-${{ matrix.os }}.tar.bz2 | sed 's/\.tar.bz2$//'); do mv $f.tar.bz2 $f-${{ steps.getarch.outputs.target-arch }}.tar.bz2; done
+      - name: Upload packages as GH artifacts
+        uses: actions/upload-artifact@v4
+        with:
+          name: ${{ inputs.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}-${{ steps.getarch.outputs.target-arch }}
+          path: built_pkgs/
+          retention-days: 7
       - name: Extract packages from the tarball
         # so we get provenance for individual packages (and the JSON package manifests from the builder)
         id: extract
         run: |
           mkdir -m 700 -p ./packages/
-          tar xvf ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}-${{ matrix.os }}.tar.bz2 -C ./packages/ --transform='s/.*\///'
+          tar xvf ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}-${{ matrix.os }}-${{ steps.getarch.outputs.target-arch }}.tar.bz2 -C ./packages/ --transform='s/.*\///'
       - name: Generate package hashes for provenance
         shell: bash
         id: pkghashes
         run: |
-          echo "pkghashes-${{ matrix.os }}=$(sha256sum ./packages/*.rpm ./packages/*.deb ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
+          echo "pkghashes-${{ matrix.os }}-${{ steps.getarch.outputs.target-arch }}=$(sha256sum ./packages/*.rpm ./packages/*.deb ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
       - name: Generate source hash for provenance
         shell: bash
         id: srchashes
         run: |
-          echo "srchashes=$(sha256sum ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}.tar.bz2 ./packages/*.json | base64 -w0)" >> $GITHUB_OUTPUT
+          echo "srchashes=$(sha256sum ./built_pkgs/*/*/${{ steps.normalize-name.outputs.normalized-package-name }}-${{ steps.getversion.outputs.version }}.tar.bz2 | base64 -w0)" >> $GITHUB_OUTPUT
       - name: Upload packages to downloads.powerdns.com
         env:
           SSHKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
@@ -141,12 +160,19 @@ jobs:
   check-hashes:
     needs: build
     name: Check if hashes were created for all requested targets
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - name: Get list of outputs from build jobs
-        run: echo '${{ toJSON(needs.build.outputs) }}' | jq 'keys[]' | grep -v version | tee /tmp/build-outputs.txt
+        run: echo '${{ toJSON(needs.build.outputs) }}' | jq 'keys[]' | grep -vE 'version|product-name' | tee /tmp/build-outputs.txt
       - name: Get list of OS inputs
-        run: for i in ${{ inputs.os }}; do echo "\"pkghashes-$i\""; done | sort | tee /tmp/os-inputs.txt; echo "\"srchashes\"" | tee -a /tmp/os-inputs.txt
+        run: |
+          for os in ${{ inputs.os }}; do
+            for architecture in x86_64 aarch64; do
+              [[ "$os" != "el-7" || "$architecture" != "aarch64"  ]] && echo "\"pkghashes-$os-$architecture\"" | tee -a /tmp/os-inputs.txt
+            done
+          done
+          sort -o /tmp/os-inputs.txt /tmp/os-inputs.txt
+          echo "\"srchashes\"" | tee -a /tmp/os-inputs.txt
       - name: Fail if there is a hash missing
         run: if ! diff -q /tmp/build-outputs.txt /tmp/os-inputs.txt; then exit 1; fi
 
@@ -156,15 +182,20 @@ jobs:
     strategy:
       matrix:
         os: ${{fromJson(needs.prepare.outputs.oslist)}}
+        architecture: ['x86_64', 'aarch64']
+        exclude:
+          - os: el-7
+            architecture: aarch64
     permissions:
       actions: read   # To read the workflow path.
       id-token: write # To sign the provenance.
       contents: write # To be able to upload assets as release artifacts
     uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
     with:
-      base64-subjects: "${{ needs.build.outputs[format('pkghashes-{0}', matrix.os)] }}"
+      base64-subjects: "${{ needs.build.outputs[format('pkghashes-{0}-{1}', matrix.os, matrix.architecture)] }}"
       upload-assets: false
-      provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os}}.intoto.jsonl"
+      provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os }}-${{ matrix.architecture }}.intoto.jsonl"
+      private-repository: true
 
   provenance-src:
     needs: build
@@ -178,14 +209,19 @@ jobs:
       base64-subjects: "${{ needs.build.outputs.srchashes }}"
       upload-assets: false
       provenance-name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-src.intoto.jsonl"
+      private-repository: true
 
   upload-provenance:
     needs: [prepare, build, provenance-src, provenance-pkgs]
     name: Upload the provenance artifacts to downloads.powerdns.com
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     strategy:
       matrix:
         os: ${{fromJson(needs.prepare.outputs.oslist)}}
+        architecture: ['x86_64', 'aarch64']
+        exclude:
+          - os: el-7
+            architecture: aarch64
     steps:
       - name: Download source tarball provenance for ${{ inputs.product }} (${{ inputs.ref }})
         id: download-src-provenance
@@ -196,14 +232,14 @@ jobs:
         id: download-provenance
         uses: actions/download-artifact@v4 # be careful, this needs to match what https://github.com/slsa-framework/slsa-github-generator is using
         with:
-          name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os}}.intoto.jsonl"
+          name: "${{ inputs.product }}-${{ needs.build.outputs.version }}-${{ matrix.os }}-${{ matrix.architecture }}.intoto.jsonl"
       - name: Upload provenance artifacts to downloads.powerdns.com
         id: upload-provenance
         env:
           SSHKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_SECRET }}
           RSYNCTARGET: ${{ secrets.DOWNLOADS_AUTOBUILT_RSYNCTARGET }}
           HOSTKEY: ${{ secrets.DOWNLOADS_AUTOBUILT_HOSTKEY }}
-          PRODUCT: ${{ inputs.product }}
+          PRODUCT: ${{ needs.build.outputs.product-name }}
           VERSION: ${{ needs.build.outputs.version }}
         if:
           "${{ env.SSHKEY != '' }}"
@@ -213,4 +249,6 @@ jobs:
           echo "$SSHKEY" > ~/.ssh/id_ed25519
           chmod 600 ~/.ssh/id_ed25519
           echo "$HOSTKEY" > ~/.ssh/known_hosts
-          rsync -4rlptD ${{steps.download-src-provenance.outputs.download-path}}/*.jsonl ${{steps.download-provenance.outputs.download-path}}/*.jsonl "${RSYNCTARGET}/${PRODUCT}/${VERSION}/"
+          mkdir -m 755 -p "slsa/${PRODUCT}/${VERSION}/"
+          mv ${{steps.download-provenance.outputs.download-path}}/*.jsonl "slsa/${PRODUCT}/${VERSION}"
+          rsync -4rlptD slsa/* "$RSYNCTARGET"
index dbaa72fd7239c1c92ac223bfdd4ea53f231c8526..e18e69db5e3bb1b5dffab4f3ba0635f961d9e46a 100644 (file)
@@ -12,71 +12,49 @@ permissions: # least privileges, see https://docs.github.com/en/actions/using-wo
 
 jobs:
   call-builder-auth-49:
-    name: Call builder rel/auth-4.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.9.x
     with:
       branch-name: rel/auth-4.9.x
 
   call-builder-auth-48:
-    name: Call builder rel/auth-4.8.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.8.x
     with:
       branch-name: rel/auth-4.8.x
 
   call-builder-auth-47:
-    name: Call builder rel/auth-4.7.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.7.x
     with:
       branch-name: rel/auth-4.7.x
 
-  call-builder-auth-46:
-    name: Call builder rel/auth-4.6.x
+  call-builder-rec-51:
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
-    uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/auth-4.6.x
+    uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-5.1.x
     with:
-      branch-name: rel/auth-4.6.x
+      branch-name: rel/rec-5.1.x
 
   call-builder-rec-50:
-    name: Call builder rel/rec-5.0.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-5.0.x
     with:
       branch-name: rel/rec-5.0.x
 
   call-builder-rec-49:
-    name: Call builder rel/rec-4.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-4.9.x
     with:
       branch-name: rel/rec-4.9.x
 
-  call-builder-rec-48:
-    name: Call builder rel/rec-4.8.x
-    if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
-    uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/rec-4.8.x
-    with:
-      branch-name: rel/rec-4.8.x
-
   call-builder-dnsdist-19:
-    name: Call builder rel/dnsdist-1.9.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.9.x
     with:
       branch-name: rel/dnsdist-1.9.x
 
   call-builder-dnsdist-18:
-    name: Call builder rel/dnsdist-1.8.x
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
     uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.8.x
     with:
       branch-name: rel/dnsdist-1.8.x
-
-  call-builder-dnsdist-17:
-    name: Call builder rel/dnsdist-1.7.x
-    if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
-    uses: PowerDNS/pdns/.github/workflows/builder.yml@rel/dnsdist-1.7.x
-    with:
-      branch-name: rel/dnsdist-1.7.x
index 759229824548012c24b4cf11f9e95e8be745b513..99196f0eefb27bd51fdfa66779c48ca823717eb7 100644 (file)
@@ -19,15 +19,13 @@ jobs:
   build:
     name: build.sh
     if: ${{ vars.SCHEDULED_JOBS_BUILDER }}
-    # on a ubuntu-20.04 VM
-    runs-on: ubuntu-20.04
+    runs-on: ${{ matrix.runner-os }}
     strategy:
       matrix:
         product: ['authoritative', 'recursor', 'dnsdist']
         os:
-          - centos-7
+          - el-7
           - el-8
-          - centos-8-stream
           - centos-9-stream
           - ubuntu-lunar
           - ubuntu-mantic
@@ -35,6 +33,12 @@ jobs:
           - debian-bookworm
           - debian-trixie
           - amazon-2023
+        runner-os:
+          - ubuntu-22.04
+          - ubicloud-standard-2-arm
+        exclude:
+          - os: el-7
+            runner-os: ubicloud-standard-2-arm
       fail-fast: false
     steps:
       - uses: actions/checkout@v4
@@ -48,9 +52,13 @@ jobs:
         run: |
           echo "version=$(readlink builder/tmp/latest)" >> $GITHUB_OUTPUT
         id: getversion
+      - name: Get target architecture
+        run: |
+          echo "target-arch=$(uname -m)" >> $GITHUB_OUTPUT
+        id: getarch
       - name: Upload packages
         uses: actions/upload-artifact@v4
         with:
-          name: ${{ matrix.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}
+          name: ${{ matrix.product }}-${{ matrix.os }}-${{ steps.getversion.outputs.version }}-${{ steps.getarch.outputs.target-arch }}
           path: built_pkgs/
           retention-days: 7
index 17391461f7c7c90506954f2fe804f171ce490eb8..35e2b0af24d0a2d2bee13a3eb4d9e6494f67ef9e 100644 (file)
@@ -67,6 +67,9 @@ jobs:
         # We must fetch at least the immediate parents so that if this is
         # a pull request then we can checkout the head.
         fetch-depth: 2
+    - uses: actions/setup-python@v5
+      with:
+        python-version: '3.11'
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
@@ -125,7 +128,7 @@ jobs:
       if: matrix.product == 'auth'
     - name: Run clang-tidy for auth
       if: matrix.product == 'auth'
-      run: git diff --no-prefix -U0 HEAD^..HEAD | python3 .github/scripts/git-filter.py --product auth | python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-auth.yml
+      run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 .github/scripts/git-filter.py --product auth | /usr/bin/python3 .github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-auth.yml
     - name: Print clang-tidy fixes YAML for auth
       if: matrix.product == 'auth'
       shell: bash
@@ -140,7 +143,7 @@ jobs:
       run: |
         if [ -f clang-tidy-auth.yml ]; then
           set +e
-          python3 .github/scripts/clang-tidy.py --fixes-file clang-tidy-auth.yml
+          /usr/bin/python3 .github/scripts/clang-tidy.py --fixes-file clang-tidy-auth.yml
           echo "failed=$?" >> $GITHUB_OUTPUT
         fi
 
@@ -175,7 +178,7 @@ jobs:
     - name: Run clang-tidy for dnsdist
       if: matrix.product == 'dnsdist'
       working-directory: ./pdns/dnsdistdist/
-      run: git diff --no-prefix -U0 HEAD^..HEAD | python3 ../../.github/scripts/git-filter.py --product dnsdist | python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-dnsdist.yml
+      run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 ../../.github/scripts/git-filter.py --product dnsdist | /usr/bin/python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-dnsdist.yml
     - name: Print clang-tidy fixes YAML for dnsdist
       if: matrix.product == 'dnsdist'
       working-directory: ./pdns/dnsdistdist/
@@ -192,7 +195,7 @@ jobs:
       run: |
         if [ -f clang-tidy-dnsdist.yml ]; then
           set +e
-          python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
+          /usr/bin/python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-dnsdist.yml
           echo "failed=$?" >> $GITHUB_OUTPUT
         fi
 
@@ -224,7 +227,7 @@ jobs:
     - name: Run clang-tidy for rec
       if: matrix.product == 'rec'
       working-directory: ./pdns/recursordist/
-      run: git diff --no-prefix -U0 HEAD^..HEAD | python3 ../../.github/scripts/git-filter.py --product rec | python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-rec.yml
+      run: git diff --no-prefix -U0 HEAD^..HEAD | /usr/bin/python3 ../../.github/scripts/git-filter.py --product rec | /usr/bin/python3 ../../.github/scripts/clang-tidy-diff.py -clang-tidy-binary /usr/bin/clang-tidy-${CLANG_VERSION} -extra-arg=-ferror-limit=0 -p0 -export-fixes clang-tidy-rec.yml
     - name: Print clang-tidy fixes YAML for rec
       if: matrix.product == 'rec'
       working-directory: ./pdns/recursordist/
@@ -241,7 +244,7 @@ jobs:
       run: |
         if [ -f clang-tidy-rec.yml ]; then
           set +e
-          python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
+          /usr/bin/python3 ../../.github/scripts/clang-tidy.py --fixes-file clang-tidy-rec.yml
           echo "failed=$?" >> $GITHUB_OUTPUT
         fi
 
diff --git a/.github/workflows/coverity-dispatch.yml b/.github/workflows/coverity-dispatch.yml
new file mode 100644 (file)
index 0000000..2b4f116
--- /dev/null
@@ -0,0 +1,47 @@
+---
+name: Trigger specific coverity scan
+
+on:
+  workflow_dispatch:
+    inputs:
+      product:
+        description: Product to build
+        type: choice
+        options:
+        - authoritative
+        - recursor
+        - dnsdist
+
+permissions: # least privileges, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+  contents: read
+
+jobs:
+  coverity-auth:
+    name: coverity scan of the auth
+    if: ${{ github.event.inputs.product == 'authoritative' }}
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: ${{ github.event.inputs.product }}
+    secrets:
+      COVERITY_TOKEN: ${{ secrets.coverity_auth_token }}
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
+
+  coverity-dnsdist:
+    name: coverity scan of dnsdist
+    if: ${{ github.event.inputs.product == 'dnsdist' }}
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: ${{ github.event.inputs.product }}
+    secrets:
+      COVERITY_TOKEN: ${{ secrets.coverity_dnsdist_token }}
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
+
+  coverity-rec:
+    name: coverity scan of the rec
+    if: ${{ github.event.inputs.product == 'recursor' }}
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: ${{ github.event.inputs.product }}
+    secrets:
+      COVERITY_TOKEN: ${{ secrets.coverity_rec_token }}
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
new file mode 100644 (file)
index 0000000..3c66162
--- /dev/null
@@ -0,0 +1,122 @@
+---
+name: Coverity scan
+
+on:
+  workflow_call:
+    inputs:
+      product:
+        required: true
+        description: Product to build
+        type: string
+    secrets:
+      COVERITY_TOKEN:
+        required: true
+      COVERITY_EMAIL:
+        required: true
+
+permissions: # least privileges, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+  contents: read
+
+env:
+  CLANG_VERSION: '12'
+
+jobs:
+  coverity-auth:
+    name: coverity scan of the auth
+    if: ${{ inputs.product == 'authoritative' }}
+    runs-on: ubuntu-22.04
+    env:
+      COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+      FUZZING_TARGETS: no
+      SANITIZERS:
+      UNIT_TESTS: no
+    steps:
+      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 5
+          submodules: recursive
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+      - run: inv install-clang
+      - run: inv install-auth-build-deps
+      - run: inv install-coverity-tools PowerDNS
+      - run: inv coverity-clang-configure
+      - run: inv ci-autoconf
+      - run: inv ci-auth-configure
+      - run: inv coverity-make
+      - run: inv coverity-tarball auth.tar.bz2
+      - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} PowerDNS auth.tar.bz2
+
+  coverity-dnsdist:
+    name: coverity scan of dnsdist
+    if: ${{ inputs.product == 'dnsdist' }}
+    runs-on: ubuntu-22.04
+    env:
+      COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+      SANITIZERS:
+      UNIT_TESTS: no
+      REPO_HOME: ${{ github.workspace }}
+    steps:
+      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 5
+          submodules: recursive
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+      - run: inv install-clang
+      - run: inv install-dnsdist-build-deps --skipXDP
+      - run: inv install-coverity-tools dnsdist
+      - run: inv coverity-clang-configure
+      - run: inv ci-autoconf
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv ci-install-rust ${{ env.REPO_HOME }}
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv ci-build-and-install-quiche ${{ env.REPO_HOME }}
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv ci-dnsdist-configure full
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv coverity-make
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv coverity-tarball dnsdist.tar.bz2
+        working-directory: ./pdns/dnsdistdist/
+      - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} dnsdist dnsdist.tar.bz2
+        working-directory: ./pdns/dnsdistdist/
+
+  coverity-rec:
+    name: coverity scan of the rec
+    if: ${{ inputs.product == 'recursor' }}
+    runs-on: ubuntu-22.04
+    env:
+      COVERITY_TOKEN: ${{ secrets.COVERITY_TOKEN }}
+      SANITIZERS:
+      UNIT_TESTS: no
+    steps:
+      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 5
+          submodules: recursive
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
+      - run: inv install-clang
+      - run: inv install-rec-build-deps
+      - run: inv install-coverity-tools 'PowerDNS+Recursor'
+      - run: inv coverity-clang-configure
+      - run: inv ci-autoconf
+        working-directory: ./pdns/recursordist/
+      - run: inv ci-rec-configure full
+        working-directory: ./pdns/recursordist/
+      - run: inv coverity-make
+        working-directory: ./pdns/recursordist/
+      - run: inv coverity-tarball recursor.tar.bz2
+        working-directory: ./pdns/recursordist/
+      - run: inv coverity-upload ${{ secrets.COVERITY_EMAIL }} 'PowerDNS+Recursor' recursor.tar.bz2
+        working-directory: ./pdns/recursordist/
index 54c474c440d10a65664d5d08f9924c773ff82761..f380b68efd5a8aff08d101554a782539762519ff 100644 (file)
@@ -30,6 +30,9 @@ jobs:
     steps:
       - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
       - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
       # Configure pip index-url set to proxpi
       - run: pip config set global.index-url http://${{ env.SERVICE_IP_ADDR }}:5000/index/
       - run: pip config set global.trusted-host ${{ env.SERVICE_IP_ADDR }}
index b452528fd75e969459436abb8ff41b893cb401d6..c11ebc27f70efcb2215be95251cb54e823cf0d93 100644 (file)
@@ -42,88 +42,29 @@ jobs:
   coverity-auth:
     name: coverity scan of the auth
     if: ${{ vars.SCHEDULED_MISC_DAILIES }}
-    runs-on: ubuntu-22.04
-    env:
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: 'authoritative'
+    secrets:
       COVERITY_TOKEN: ${{ secrets.coverity_auth_token }}
-      FUZZING_TARGETS: no
-      SANITIZERS:
-      UNIT_TESTS: no
-    steps:
-      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 5
-          submodules: recursive
-      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
-      - run: inv install-clang
-      - run: inv install-auth-build-deps
-      - run: inv install-coverity-tools PowerDNS
-      - run: inv coverity-clang-configure
-      - run: inv ci-autoconf
-      - run: inv ci-auth-configure
-      - run: inv coverity-make
-      - run: inv coverity-tarball auth.tar.bz2
-      - run: inv coverity-upload ${{ secrets.coverity_email }} PowerDNS auth.tar.bz2
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
 
   coverity-dnsdist:
     name: coverity scan of dnsdist
     if: ${{ vars.SCHEDULED_MISC_DAILIES }}
-    runs-on: ubuntu-22.04
-    env:
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: 'dnsdist'
+    secrets:
       COVERITY_TOKEN: ${{ secrets.coverity_dnsdist_token }}
-      SANITIZERS:
-      UNIT_TESTS: no
-      REPO_HOME: ${{ github.workspace }}
-    steps:
-      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 5
-          submodules: recursive
-      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
-      - run: inv install-clang
-      - run: inv install-dnsdist-build-deps --skipXDP
-      - run: inv install-coverity-tools dnsdist
-      - run: inv coverity-clang-configure
-      - run: inv ci-autoconf
-        working-directory: ./pdns/dnsdistdist/
-      - run: inv ci-build-and-install-quiche ${{ env.REPO_HOME }}
-        working-directory: ./pdns/dnsdistdist/
-      - run: inv ci-dnsdist-configure full
-        working-directory: ./pdns/dnsdistdist/
-      - run: inv coverity-make
-        working-directory: ./pdns/dnsdistdist/
-      - run: inv coverity-tarball dnsdist.tar.bz2
-        working-directory: ./pdns/dnsdistdist/
-      - run: inv coverity-upload ${{ secrets.coverity_email }} dnsdist dnsdist.tar.bz2
-        working-directory: ./pdns/dnsdistdist/
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
 
   coverity-rec:
     name: coverity scan of the rec
     if: ${{ vars.SCHEDULED_MISC_DAILIES }}
-    runs-on: ubuntu-22.04
-    env:
+    uses: PowerDNS/pdns/.github/workflows/coverity.yml@master
+    with:
+      product: 'recursor'
+    secrets:
       COVERITY_TOKEN: ${{ secrets.coverity_rec_token }}
-      SANITIZERS:
-      UNIT_TESTS: no
-    steps:
-      - uses: PowerDNS/pdns/set-ubuntu-mirror@meta
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 5
-          submodules: recursive
-      - run: build-scripts/gh-actions-setup-inv-no-dist-upgrade
-      - run: inv install-clang
-      - run: inv install-rec-build-deps
-      - run: inv install-coverity-tools 'PowerDNS+Recursor'
-      - run: inv coverity-clang-configure
-      - run: inv ci-autoconf
-        working-directory: ./pdns/recursordist/
-      - run: inv ci-rec-configure full
-        working-directory: ./pdns/recursordist/
-      - run: inv coverity-make
-        working-directory: ./pdns/recursordist/
-      - run: inv coverity-tarball recursor.tar.bz2
-        working-directory: ./pdns/recursordist/
-      - run: inv coverity-upload ${{ secrets.coverity_email }} 'PowerDNS+Recursor' recursor.tar.bz2
-        working-directory: ./pdns/recursordist/
+      COVERITY_EMAIL: ${{ secrets.coverity_email }}
index 07dd058c9e930d5bbea4cf4e2cff7043f43f0a37..5d764b3340175d82c321c53d47222daf9f1cb779 100644 (file)
@@ -58,5 +58,6 @@ __pycache__
 compile_commands.*
 .cache
 /.clang-tidy
+.ccls-cache
 .gdb_history
 .venv
index 696f65ed70d7fc0ffb892f52a0ad772c00153aaf..904e4c65f39525b54abbccb59ff044ed653c780d 100644 (file)
@@ -1,6 +1,5 @@
 ./ext/lmdb-safe/lmdb-safe.cc
 ./ext/lmdb-safe/lmdb-safe.hh
-./ext/lmdb-safe/lmdb-typed.cc
 ./ext/lmdb-safe/lmdb-typed.hh
 ./ext/probds/murmur3.cc
 ./pdns/anadns.hh
@@ -8,6 +7,7 @@
 ./pdns/auth-carbon.cc
 ./pdns/auth-packetcache.cc
 ./pdns/auth-packetcache.hh
+./pdns/auth-primarycommunicator.cc
 ./pdns/auth-querycache.cc
 ./pdns/auth-querycache.hh
 ./pdns/axfr-retriever.cc
@@ -18,8 +18,6 @@
 ./pdns/base64.cc
 ./pdns/base64.hh
 ./pdns/bindparserclasses.hh
-./pdns/bpf-filter.cc
-./pdns/bpf-filter.hh
 ./pdns/calidns.cc
 ./pdns/capabilities.cc
 ./pdns/cdb.cc
@@ -27,8 +25,6 @@
 ./pdns/comfun.cc
 ./pdns/comment.hh
 ./pdns/dbdnsseckeeper.cc
-./pdns/delaypipe.cc
-./pdns/delaypipe.hh
 ./pdns/distributor.hh
 ./pdns/dns.cc
 ./pdns/dns.hh
@@ -87,7 +83,6 @@
 ./pdns/dnswasher.cc
 ./pdns/dnswriter.cc
 ./pdns/dnswriter.hh
-./pdns/doh.hh
 ./pdns/dumresp.cc
 ./pdns/dynhandler.cc
 ./pdns/dynhandler.hh
@@ -99,8 +94,6 @@
 ./pdns/ednsoptions.cc
 ./pdns/ednsoptions.hh
 ./pdns/ednspadding.cc
-./pdns/fstrm_logger.cc
-./pdns/fstrm_logger.hh
 ./pdns/gettime.cc
 ./pdns/gettime.hh
 ./pdns/histog.hh
 ./pdns/kvresp.cc
 ./pdns/libssl.cc
 ./pdns/libssl.hh
-./pdns/lock.hh
 ./pdns/lua-auth4.cc
 ./pdns/lua-auth4.hh
 ./pdns/lua-base4.cc
 ./pdns/lua-record.cc
 ./pdns/malloctrace.cc
 ./pdns/malloctrace.hh
-./pdns/auth-primarycommunicator.cc
 ./pdns/minicurl.cc
 ./pdns/minicurl.hh
 ./pdns/misc.cc
 ./pdns/pdnsutil.cc
 ./pdns/pkcs11signers.cc
 ./pdns/pkcs11signers.hh
-./pdns/protozero.cc
-./pdns/protozero.hh
 ./pdns/proxy-protocol.cc
 ./pdns/proxy-protocol.hh
 ./pdns/qtype.cc
 ./pdns/secpoll.cc
 ./pdns/secpoll.hh
 ./pdns/serialtweaker.cc
-./pdns/sholder.hh
 ./pdns/signingpipe.cc
 ./pdns/signingpipe.hh
 ./pdns/sillyrecords.cc
 ./pdns/snmp-agent.cc
 ./pdns/snmp-agent.hh
 ./pdns/speedtest.cc
-./pdns/sstuff.hh
 ./pdns/standalone_fuzz_target_runner.cc
 ./pdns/stat_t.hh
 ./pdns/statbag.cc
 ./pdns/test-packetcache_hh.cc
 ./pdns/test-proxy_protocol_cc.cc
 ./pdns/test-rcpgenerator_cc.cc
-./pdns/test-sholder_hh.cc
 ./pdns/test-statbag_cc.cc
 ./pdns/test-svc_records_cc.cc
 ./pdns/test-trusted-notification-proxy_cc.cc
 ./pdns/uuid-utils.cc
 ./pdns/validate.cc
 ./pdns/validate.hh
-./pdns/version.cc
-./pdns/version.hh
 ./pdns/webserver.cc
 ./pdns/webserver.hh
-./pdns/xpf.cc
-./pdns/xpf.hh
 ./pdns/zone2json.cc
 ./pdns/zone2ldap.cc
 ./pdns/zone2sql.cc
index 0df59bdd90c3405d3dfe54dccd824d6e093c6ad1..9ca9c691712b4f41ef219fb64fbe7d95fe09e40e 100644 (file)
@@ -49,13 +49,7 @@ Copy the existing instructions for Debian Buster:
 cp builder-support/dockerfiles/Dockerfile.target.debian-buster builder-support/dockerfiles/Dockerfile.target.debian-bookworm
 ```
 
-In the new `builder-support/dockerfiles/Dockerfile.target.debian-bookworm` file, replace every occurence of `debian-buster` by `debian-bookworm`, and of `debian:buster` by `debian:bookworm`
-
-Create symbolic links for the amd64 and arm64 versions:
-```
-ln -s builder-support/dockerfiles/Dockerfile.target.debian-bookworm builder-support/dockerfiles/Dockerfile.target.debian-bookworm-amd64
-ln -s builder-support/dockerfiles/Dockerfile.target.debian-bookworm builder-support/dockerfiles/Dockerfile.target.debian-bookworm-arm64
-```
+In the new `builder-support/dockerfiles/Dockerfile.target.debian-bookworm` file, replace every occurrence of `debian-buster` by `debian-bookworm`, and of `debian:buster` by `debian:bookworm`
 
 Then add the new target to the list of OSes in the `.github/workflows/builder-dispatch.yml` workflow file:
 ```
index 778928b7bca2b62ec8a38202158cec67df2f6d8f..3eec37d953d33adc0589f8cd38b347e7effbd47d 100644 (file)
@@ -20,7 +20,7 @@ This approach generates `.gcno` files during the compilation, which are stored a
 * Every invocation of a program updates the `.gcda` files corresponding to the code that has been executed. It will append to existing `.gcda` files, but only process can update a given file so parallel execution will result in corrupted data.
 * Writing to each `.gcda` might take a while for large programs, and has been known to slow down execution quite a lot.
 * Accurate reporting of lines and branches may be problematic when optimizations are enabled, so it is advised to disable optimizations to get useful analysis.
-* Note that the `.gcda` files produced by `clang++` are not fully compatible with the `g++` ones, and with the existing tools, but [`llvm-cov gcov`](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) can produce `.gcov` files that should be compatible. A symptom of this incompatiblity looks like this:
+* Note that the `.gcda` files produced by `clang++` are not fully compatible with the `g++` ones, and with the existing tools, but [`llvm-cov gcov`](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) can produce `.gcov` files that should be compatible. A symptom of this incompatibility looks like this:
 
 ```
 Processing pdns/ednssubnet.gcda
index 20a812fcc5d1880a4ec1ba1b2f33331ff617bc69..641dfd2934070e809518279afb93eb38c2ba9128 100644 (file)
@@ -24,7 +24,7 @@ at least the following information (if they are relevant):
 
 ## Filing an Issue or Bug
 **Note:** if you're planning to file a security bug, look at our
-[Security Policy](https://doc.powerdns.com/md/security/) first.
+[Security Policy](https://github.com/PowerDNS/pdns/security/policy) first.
 
 When filing an issue or bug report, make the title of the issue a very short
 summary (e.g. "Recursor crash when some-setting is set to 'crash'"). In the
@@ -58,7 +58,7 @@ A pull request, at the least, should have:
 
 And must:
 * Be filed against the master branch before any release branch
-* Pass all tests in our CI (currently Github Actions and CircleCI)
+* Pass all tests in our CI (currently GitHub Actions and CircleCI)
 
 Information on the tests can be found in the repository at
 [/regression-tests/README.md](https://github.com/PowerDNS/pdns/blob/master/regression-tests/README.md)
@@ -120,7 +120,7 @@ However, it may happen that existing code could produce warnings and can show up
 1. Fix the warnings in a separate commit.
 2. If fixing the warning would be too much trouble at this point in time, disabling the specific warning using the `// NOLINTNEXTLINE` or `// NOLINT` directives can be acceptable given the following is adhered to:
 
-Any added `// NOLINTNEXTLINE` or `// NOLINT` directive or others need to have a Github issue title, issue number and link next to them in the description along with the name or Github nickname of the person that wrote it. The Github issue must have an assignee and an accurate description of what needs to be done. As an example:
+Any added `// NOLINTNEXTLINE` or `// NOLINT` directive or others need to have a GitHub issue title, issue number and link next to them in the description along with the name or GitHub nickname of the person that wrote it. The GitHub issue must have an assignee and an accurate description of what needs to be done. As an example:
 
 `// NOLINTNEXTLINE(<warning-name>) <issue-number> <issue-link> <person-name>: <issue-title> + a short comment if needed.`
 
index 40c2847118bc4fe211e3ef253234bf8fa3d9a5dc..0f700781ee224aac33602010af45cabbc1ce1b19 100644 (file)
@@ -1,6 +1,6 @@
 # USAGE
 
-#   docker build --build-arg MAKEFLAGS=-j8 -t recursor -f docker/Dockerfile-recursor .
+#   docker build --build-arg MAKEFLAGS=-j8 -t recursor -f Dockerfile-recursor .
 #   docker run -p 1053:53 -p 1053:53/udp -ti --rm recursor
 #   dig a www.example.com @0 -p 1053
 
index 8b74cc1d5f739bba3cf81b9d2c7fbd50cb906568..f77cd869cfefa8ea418e75c79e4069119edb9a94 100644 (file)
@@ -1,4 +1,4 @@
-PowerDNS and dnsdist Security Policy
+PowerDNS and DNSdist Security Policy
 ====================================
 
 If you have a security problem to report, please email us at both peter.van.dijk@powerdns.com and remi.gacogne@powerdns.com.
@@ -7,13 +7,13 @@ In case you want to encrypt your report using PGP, please use: https://doc.power
 Please do not mail security issues to public lists, nor file a ticket, unless we do not get back to you in a timely manner.
 We fully credit reporters of security issues, and respond quickly, but please allow us a reasonable timeframe to coordinate a response.
 
-We remind PowerDNS and dnsdist users that under the terms of the GNU General Public License, PowerDNS and dnsdist come with ABSOLUTELY NO WARRANTY.
+We remind PowerDNS and DNSdist users that under the terms of the GNU General Public License, PowerDNS and DNSdist come with ABSOLUTELY NO WARRANTY.
 This license is included in this documentation.
 
 Yes We Hack
 -----------
 Security issues can also be reported on [our YesWeHack page](https://yeswehack.com/programs/powerdns) and might fetch a bounty.
-Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and dnsdist) is in scope for the YesWeHack program, not our websites or other infrastructure.
+Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and DNSdist) is in scope for the YesWeHack program, not our websites or other infrastructure.
 
 Disclosure Policy
 -----------------
index 36038b437b2e6f2175cee8dda8a564c34f60b80b..94af3ad403576a76a88fd74daa7205c2522a15c4 100644 (file)
@@ -10,6 +10,11 @@ To see the supported releases do `./generate-repo-files.py --help`.
 This tool is mainly used internally to test releases but might be useful
 for others.
 
+## Known Issues
+
+- `--test-aarch64` really only makes sense if the test script is running on
+  another platform (and so far we've assumed `x86_64` to be the default)
+
 ## Dependencies
 
 - Python 3
index 7ebe25bd3f4d739f4ae537918b610edac850598f..63af7fbd5f822d906cb8b8c9b95cd12763a3cf05 100755 (executable)
@@ -8,7 +8,7 @@
 # - `source venv/bin/activate`
 # - `pip install --upgrade pip`
 # - `pip install -r requirements.txt`
-# - `./generate-repo-files.py auth-41`
+# - `./generate-repo-files.py --test rec-51`
 
 # Modules
 
@@ -25,7 +25,7 @@ from jinja2 import Environment, FileSystemLoader
 
 # Globals
 
-g_version = '1.0.3'
+g_version = '1.0.4'
 
 g_verbose = False
 
@@ -44,21 +44,22 @@ def init_argparser():
                                                  'test PowerDNS repositories.')
     parser.add_argument('release', metavar='RELEASE',
                         choices=[# Authoritative Server
-                                 'auth-44', 'auth-45', 'auth-46', 'auth-47',
-                                 'auth-48', 'auth-master',
+                                 'auth-47', 'auth-48', 'auth-49',
+                                 'auth-master',
                                  # Recursor
-                                 'rec-46', 'rec-47', 'rec-48', 'rec-49',
+                                 'rec-48', 'rec-49', 'rec-50', 'rec-51',
                                  'rec-master',
                                  # DNSDist
-                                 'dnsdist-15', 'dnsdist-16', 'dnsdist-17',
-                                 'dnsdist-18', 'dnsdist-master'
-                                 ],
+                                 'dnsdist-17', 'dnsdist-18', 'dnsdist-19',
+                                 'dnsdist-master'],
                         help='the release to generate Docker files for: ' +
                              '%(choices)s')
     parser.add_argument('--run-output', action='store_true',
                         help='always show output from running a container')
     parser.add_argument('--test', action='store_true',
                         help='test the release')
+    parser.add_argument('--test-aarch64', action='store_true',
+                        help='test the release for ARM64')
     parser.add_argument('--verbose', action='store_true',
                         help='verbose output')
     parser.add_argument('--version', action='store_true',
@@ -79,7 +80,7 @@ def write_dockerfile (os, os_version, release):
         os_image = os
 
     if release.startswith('auth-'):
-        if os in ('centos', 'el'):
+        if os in ('el'):
             pkg = 'pdns'
         else:
             pkg = 'pdns-server'
@@ -111,16 +112,10 @@ def write_dockerfile (os, os_version, release):
 def write_list_file (os, os_version, release):
     tpl = g_env.get_template('pdns-list.jinja2')
 
-    if os in ['debian', 'ubuntu']:
-        arch = ' [arch=amd64] '
-    else:
-        arch = ' '
-
     f = open('pdns.list.{}.{}-{}'.format(release, os, os_version), 'w')
     f.write(tpl.render({ "os": os,
                          "os_version": os_version,
-                         "release": release,
-                         "arch": arch }))
+                         "release": release }))
     f.close()
 
 
@@ -141,54 +136,37 @@ def write_release_files (release):
     if g_verbose:
         print("Writing release files...")
 
-    if release in ['auth-44', 'auth-45', 'auth-46', 'auth-47', 'auth-48',
-                   'auth-master',
-                   'rec-46', 'rec-47', 'rec-48', 'rec-49',
-                   'rec-master',
-                   'dnsdist-15', 'dnsdist-16', 'dnsdist-17', 'dnsdist-18',
-                   'dnsdist-master']:
+    if release in ['auth-47', 'auth-48', 'auth-49', 'auth-master',
+                   'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-master',
+                   'dnsdist-17', 'dnsdist-18', 'dnsdist-19', 'dnsdist-master']:
         write_pkg_pin_file(release)
-        write_dockerfile('centos', '7', release)
+        write_dockerfile('el', '7', release)
         write_dockerfile('el', '8', release)
+        write_dockerfile('el', '9', release)
         write_dockerfile('debian', 'buster', release)
         write_list_file('debian', 'buster', release)
-        write_dockerfile('ubuntu', 'focal', release)
-        write_list_file('ubuntu', 'focal', release)
-
-    if release in ['dnsdist-15']:
-        write_dockerfile('raspbian', 'buster', release)
-        write_list_file('raspbian', 'buster', release)
-
-    if release in ['auth-46', 'auth-47', 'auth-48', 'auth-master',
-                   'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
-                   'dnsdist-16', 'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
         write_dockerfile('debian', 'bullseye', release)
         write_list_file('debian', 'bullseye', release)
-
-    if release in ['auth-46', 'auth-47', 'auth-master',
-                   'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
-                   'dnsdist-15', 'dnsdist-16', 'dnsdist-17', 'dnsdist-master']:
-        write_dockerfile('ubuntu', 'bionic', release)
-        write_list_file('ubuntu', 'bionic', release)
-
-    if release in ['auth-46', 'auth-47', 'auth-48', 'auth-master',
-                   'rec-46', 'rec-47', 'rec-48', 'rec-49', 'rec-master',
-                   'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
+        write_dockerfile('ubuntu', 'focal', release)
+        write_list_file('ubuntu', 'focal', release)
         write_dockerfile('ubuntu', 'jammy', release)
         write_list_file('ubuntu', 'jammy', release)
 
-    if release in ['auth-47', 'auth-48', 'auth-master',
-                   'rec-47', 'rec-48', 'rec-49', 'rec-master',
-                   'dnsdist-17', 'dnsdist-18', 'dnsdist-master']:
-        write_dockerfile('el', '9', release)
-
-    if release in ['auth-48', 'auth-master']:
+    if release in ['auth-48', 'auth-49', 'auth-master',
+                   'rec-48', 'rec-49', 'rec-50', 'rec-51', 'rec-master',
+                   'dnsdist-19', 'dnsdist-master']:
         write_dockerfile('debian', 'bookworm', release)
         write_list_file('debian', 'bookworm', release)
 
+    if release in ['auth-49', 'auth-master',
+                   'rec-50', 'rec-51', 'rec-master',
+                   'dnsdist-19', 'dnsdist-master']:
+        write_dockerfile('ubuntu', 'noble', release)
+        write_list_file('ubuntu', 'noble', release)
+
 # Test Release Functions
 
-def build (dockerfile):
+def build (dockerfile, arch='x86_64'):
     # Maybe create `determine_tag` function.
     if len(str(dockerfile)) <= len(g_dockerfile):
         print('Unable to determine tag for {}'.format(dockerfile))
@@ -197,9 +175,16 @@ def build (dockerfile):
     print('Building Docker image using {}...'.format(dockerfile))
     if g_verbose:
         print('  - tag = {}'.format(tag))
-    cp = subprocess.run(['docker', 'build', '--no-cache', '--pull', '--file',
-                         dockerfile, '--tag', tag, '.'],
-                        capture_output=not(g_verbose))
+    if arch == 'x86_64':
+        cp = subprocess.run(['docker', 'build', '--no-cache', '--pull',
+                             '--file', dockerfile, '--tag', tag, '.'],
+                            capture_output=not(g_verbose))
+    # not very subtle
+    elif arch == 'aarch64':
+        cp = subprocess.run(['docker', 'build', '--platform', 'linux/arm64/v8',
+                             '--no-cache', '--pull', '--file', dockerfile,
+                             '--tag', tag, '.'],
+                            capture_output=not(g_verbose))
     # FIXME write failed output to log
     if cp.returncode != 0:
         print('Error building {}: {}'.format(tag, repr(cp.returncode)))
@@ -207,16 +192,22 @@ def build (dockerfile):
     return ( tag, cp.returncode )
 
 
-def run (tag):
+def run (tag, arch='x86_64'):
     if g_run_output:
         capture_run_output = False
     else:
         capture_run_output = not(g_verbose)
     print('Running Docker container tagged {}...'.format(tag))
-    cp = subprocess.run(['docker', 'run', tag],
-                        stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    version = re.search('(PowerDNS Authoritative Server|PowerDNS Recursor|' +
-                         'dnsdist) (\d+\.\d+\.\d+(-\w+)?)',
+    if arch == 'x86_64':
+        cp = subprocess.run(['docker', 'run', tag],
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    # not very subtle
+    elif arch == 'aarch64':
+        cp = subprocess.run(['docker', 'run', '--platform', 'linux/arm64/v8',
+                             tag],
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    version = re.search(r'(PowerDNS Authoritative Server|PowerDNS Recursor|' +
+                        r'dnsdist) (\d+\.\d+\.\d+(-\w+)?)',
                         cp.stdout.decode())
     if g_verbose:
         print(cp.stdout.decode())
@@ -242,17 +233,22 @@ def collect_dockerfiles (release):
     return files
 
 
-def test_release (release):
+def test_release (release, arch='x86_64'):
     # sorted because we want determinism
     dockerfiles = sorted(collect_dockerfiles(release))
     failed_builds = []
     failed_runs = []
     returned_versions = []
-    print('=== testing {} ==='.format(release))
+    print('=== testing {} ({}) ==='.format(release, arch))
     for df in dockerfiles:
+        if arch == 'aarch64' and str(df).endswith('el-7'):
+            continue
+        if arch == 'aarch64' and not release in ['rec-49', 'rec-50', 'rec-51', 'rec-master',
+                                                 'dnsdist-19', 'dnsdist-master']:
+            continue
         if g_verbose:
             print('--- {} ---'.format(df))
-        (tag, returncode) = build(df)
+        (tag, returncode) = build(df, arch)
         if returncode != 0:
             print('Skipping running {} due to build error: {}'
                   .format(df, returncode))
@@ -261,7 +257,7 @@ def test_release (release):
             print('Skipping running {} due to undetermined tag.'.format(df))
             failed_builds.append((str(df), returncode))
         else:
-            (returncode, return_version) = run(tag)
+            (returncode, return_version) = run(tag, arch)
             # for some reason 99 is returned on `cmd --version` :shrug:
             # (not sure if this is true since using `stdout=PIPE...`)
             if returncode != 0 and returncode != 99:
@@ -304,3 +300,6 @@ write_release_files(args.release)
 
 if args.test:
     test_release(args.release)
+
+if args.test_aarch64:
+    test_release(args.release, 'aarch64')
diff --git a/build-scripts/docker/repo-test/templates/Dockerfile-centos.jinja2 b/build-scripts/docker/repo-test/templates/Dockerfile-centos.jinja2
deleted file mode 100644 (file)
index 69ea057..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-FROM {{ os_image }}:{{ os_version }}
-
-RUN yum install -y epel-release bind-utils
-
-{% if os_version == '7' %}
-RUN yum install -y yum-plugin-priorities
-{% endif %}
-
-{% if release == 'dnsdist-15' and os_version == '8' %}
-RUN dnf install -y 'dnf-command(config-manager)'
-RUN dnf config-manager --set-enabled powertools
-{% endif %}
-
-RUN curl -o /etc/yum.repos.d/powerdns-{{ release }}.repo https://repo.powerdns.com/repo-files/{{ os }}-{{ release }}.repo
-RUN yum install --assumeyes {%- if os_version == '8' %} --nobest{% endif %} {{ pkg }}
-
-{% if release.startswith('rec-') %}
-RUN mkdir /var/run/pdns-recursor
-{% endif %}
-
-CMD {{ cmd }} --version
-
index 5e78b7b59b7103331b19c9d93c610967c53775b7..9dbabb84d9ac754957f309d8ad6b27143e477639 100644 (file)
@@ -1,12 +1,6 @@
 FROM {{ os_image }}:{{ os_version }}
 
-{% if os_version == '8' or os_version == '9' %}
-RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ os_version }}.noarch.rpm bind-utils
-{% endif %}
-
-{% if os_version == '7' %}
-RUN yum install -y yum-plugin-priorities
-{% endif %}
+RUN yum install -y oracle-epel-release-el{{ os_version }} bind-utils
 
 {% if release == 'dnsdist-15' and os_version == '8' %}
 RUN dnf install -y 'dnf-command(config-manager)'
index 212150189ef803b1f2585f13c56ed8bbd4b794e4..4572866a0b28501aa4befddc21317c7e4fb455d3 100644 (file)
@@ -1,2 +1 @@
-deb {{- arch -}} http://repo.powerdns.com/{{ os }} {{ os_version }}-{{ release }} main
-
+deb http://repo.powerdns.com/{{ os }} {{ os_version }}-{{ release }} main
diff --git a/builder b/builder
index 16bc1604c48821c12b708d7afa88d9612ebdd0da..f2c8c68dccb142152d8e2120b29e597e24222ddc 160000 (submodule)
--- a/builder
+++ b/builder
@@ -1 +1 @@
-Subproject commit 16bc1604c48821c12b708d7afa88d9612ebdd0da
+Subproject commit f2c8c68dccb142152d8e2120b29e597e24222ddc
diff --git a/builder-support/debian/recursor/debian-buster/pdns-recursor.maintscript b/builder-support/debian/recursor/debian-buster/pdns-recursor.maintscript
new file mode 100644 (file)
index 0000000..ce9c72d
--- /dev/null
@@ -0,0 +1,4 @@
+# must support Ubuntu focal, with dpkg 1.19.7
+# Enable the line below once we fully moved to YAML configuration
+#rm_conffile /etc/powerdns/recursor.lua 5.1~
+
index 9e122d632667bf1dcb901b70ec3a1906757282c4..eee8834436c09cef4801d30331d6bb747b71c251 100755 (executable)
@@ -32,6 +32,7 @@ override_dh_auto_configure:
                --enable-dnstap \
                --enable-nod
 
+# Stop installing the Lua config files once we fully moved to YAML configuration
 override_dh_auto_install:
        dh_auto_install
        install -d debian/pdns-recursor/usr/share/pdns-recursor/lua-config
@@ -41,15 +42,20 @@ override_dh_auto_install:
        install -m 644 -t debian/pdns-recursor/usr/share/pdns-recursor/snmp RECURSOR-MIB.txt
        rm -f debian/pdns-recursor/etc/powerdns/recursor.conf-dist
        rm -f debian/pdns-recursor/etc/powerdns/recursor.yml-dist
-       ./pdns_recursor --no-config --config=default | sed \
-               -e 's!^# config-dir=.*!config-dir=/etc/powerdns!' \
-               -e 's!^# hint-file=.*!&\nhint-file=/usr/share/dns/root.hints!' \
-               -e 's!^# include-dir=.*!&\ninclude-dir=/etc/powerdns/recursor.d!' \
-               -e 's!^# local-address=.*!local-address=127.0.0.1!' \
-               -e 's!^# lua-config-file=.*!lua-config-file=/etc/powerdns/recursor.lua!' \
-               -e 's!^# quiet=.*!quiet=yes!' \
-               -e '/^# version-string=.*/d' \
-               > debian/pdns-recursor/etc/powerdns/recursor.conf
+       @echo "\
+       dnssec:\n\
+         # validation: process # default\n\
+         trustanchorfile: /usr/share/dns/root.key\n\
+       recursor:\n\
+         hint_file: /usr/share/dns/root.hints\n\
+         include_dir: /etc/powerdns/recursor.d\n\
+       incoming:\n\
+        # listen:\n\
+        # - 127.0.0.1 # default\n\
+       outgoing:\n\
+        # source_address:\n\
+        # - 0.0.0.0 # default\n\
+       " > debian/pdns-recursor/etc/powerdns/recursor.conf
 
 override_dh_auto_test:
 ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
index 24a5dff8062e9905eb4aa10e77e46979212e455f..acf1e45b50e56c611a0d1754d69d082fba79327b 100644 (file)
@@ -3,12 +3,7 @@
 
 # This defines the distribution base layer
 # Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = centos-7 -o ${BUILDER_TARGET} = el-7 ]
 FROM centos:7 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-7-amd64 -o ${BUILDER_TARGET} = el-7-amd64]
-FROM amd64/centos:7 as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 RUN touch /var/lib/rpm/* && yum install -y epel-release centos-release-scl-rh
diff --git a/builder-support/dockerfiles/Dockerfile.target.centos-7-amd64 b/builder-support/dockerfiles/Dockerfile.target.centos-7-amd64
deleted file mode 120000 (symlink)
index c6fc1ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.centos-7
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.centos-8 b/builder-support/dockerfiles/Dockerfile.target.centos-8
deleted file mode 100644 (file)
index 237ff5a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# First do the source builds
-@INCLUDE Dockerfile.target.sdist
-
-# This defines the distribution base layer
-# Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = centos-8 ]
-FROM centos:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-stream ]
-FROM quay.io/centos/centos:stream8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-amd64 ]
-FROM amd64/centos:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = centos-8-arm64 ]
-FROM arm64v8/centos:8 as dist-base
-@ENDIF
-
-ARG BUILDER_CACHE_BUSTER=
-
-@IF [[ $BUILDER_TARGET = centos-*-stream ]]
-RUN touch /var/lib/rpm/* && dnf swap -y centos-linux-repos centos-stream-repos && dnf -y distro-sync
-@ENDIF
-
-RUN touch /var/lib/rpm/* && dnf install -y epel-release && \
-    dnf install -y 'dnf-command(config-manager)' && \
-    dnf config-manager --set-enabled powertools
-
-# Do the actual rpm build
-@INCLUDE Dockerfile.rpmbuild
-
-# Do a test install and verify
-# Can be skipped with skippackagetest=1 in the environment
-@EXEC [ "$skippackagetest" = "" ] && include Dockerfile.rpmtest
diff --git a/builder-support/dockerfiles/Dockerfile.target.centos-8-amd64 b/builder-support/dockerfiles/Dockerfile.target.centos-8-amd64
deleted file mode 120000 (symlink)
index cfe8905..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.centos-8
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.centos-8-arm64 b/builder-support/dockerfiles/Dockerfile.target.centos-8-arm64
deleted file mode 120000 (symlink)
index cfe8905..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.centos-8
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.centos-8-stream b/builder-support/dockerfiles/Dockerfile.target.centos-8-stream
deleted file mode 120000 (symlink)
index cfe8905..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.centos-8
\ No newline at end of file
index 073bb7645f7281911a6a4fd5c10d331c109d8b9f..d134ec07398a59ff28d4d525f102ccd271ccb263 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = debian-bookworm ]
 FROM debian:bookworm as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bookworm-amd64 ]
-FROM amd64/debian:bookworm as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bookworm-arm64 ]
-FROM arm64v8/debian:bookworm as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-bookworm-amd64 b/builder-support/dockerfiles/Dockerfile.target.debian-bookworm-amd64
deleted file mode 120000 (symlink)
index 3e463e2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-bookworm
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-bookworm-arm64 b/builder-support/dockerfiles/Dockerfile.target.debian-bookworm-arm64
deleted file mode 120000 (symlink)
index 3e463e2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-bookworm
\ No newline at end of file
index fb77dba9e044292aa1428e84bb92901d1d14c2cc..df239cfdd1b7c5589716caafb540cfdd2b687cbd 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = debian-bullseye ]
 FROM debian:bullseye as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bullseye-amd64 ]
-FROM amd64/debian:bullseye as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-bullseye-arm64 ]
-FROM arm64v8/debian:bullseye as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-bullseye-amd64 b/builder-support/dockerfiles/Dockerfile.target.debian-bullseye-amd64
deleted file mode 120000 (symlink)
index f7f2fce..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-bullseye
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-bullseye-arm64 b/builder-support/dockerfiles/Dockerfile.target.debian-bullseye-arm64
deleted file mode 120000 (symlink)
index f7f2fce..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-bullseye
\ No newline at end of file
index 6d0bba14e278cb365496417384f4fec505b96d78..bff27c137d587ca9f65edb1dce809dd29c187171 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = debian-buster ]
 FROM debian:buster as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-buster-amd64 ]
-FROM amd64/debian:buster as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-buster-arm64 ]
-FROM arm64v8/debian:buster as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-buster-amd64 b/builder-support/dockerfiles/Dockerfile.target.debian-buster-amd64
deleted file mode 120000 (symlink)
index 47231fd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-buster
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-buster-arm64 b/builder-support/dockerfiles/Dockerfile.target.debian-buster-arm64
deleted file mode 120000 (symlink)
index 47231fd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-buster
\ No newline at end of file
index 8642f323b08ddce6e3b46422e748942170c16757..21759e0b618b7fd4e4575661123df9d24cfd208e 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = debian-trixie ]
 FROM debian:trixie as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-trixie-amd64 ]
-FROM amd64/debian:trixie as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = debian-trixie-arm64 ]
-FROM arm64v8/debian:trixie as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-trixie-amd64 b/builder-support/dockerfiles/Dockerfile.target.debian-trixie-amd64
deleted file mode 120000 (symlink)
index fed04d5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-trixie
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.debian-trixie-arm64 b/builder-support/dockerfiles/Dockerfile.target.debian-trixie-arm64
deleted file mode 120000 (symlink)
index fed04d5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.debian-trixie
\ No newline at end of file
index c6fc1ef94f7ca85813942b3ee4077b0266f341f3..a67155b251c27e9bdbd5a486f8326c496ef851be 120000 (symlink)
@@ -1 +1 @@
-Dockerfile.target.centos-7
\ No newline at end of file
+Dockerfile.target.oraclelinux-7
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.el-7-amd64 b/builder-support/dockerfiles/Dockerfile.target.el-7-amd64
deleted file mode 120000 (symlink)
index 3369705..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.centos-7-amd64
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.el-8-amd64 b/builder-support/dockerfiles/Dockerfile.target.el-8-amd64
deleted file mode 120000 (symlink)
index f5f60ee..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.oraclelinux-8-amd64
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.el-8-arm64 b/builder-support/dockerfiles/Dockerfile.target.el-8-arm64
deleted file mode 120000 (symlink)
index 55a25a3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.oraclelinux-8-arm64
\ No newline at end of file
index 5e35f9193c5decce4f6c06e7ece15ae019e25ebe..5aca4059a21b480aa30924de80a0a1fc8a4a0726 100644 (file)
@@ -3,15 +3,7 @@
 
 # This defines the distribution base layer
 # Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = oraclelinux-9 -o ${BUILDER_TARGET} = el-9 ]
 FROM oraclelinux:9 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-9-amd64 -o ${BUILDER_TARGET} = el-9-amd64 ]
-FROM amd64/oraclelinux:9 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-9-arm64 -o ${BUILDER_TARGET} = el-9-arm64 ]
-FROM arm64v8/oraclelinux:9 as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 RUN touch /var/lib/rpm/* && dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm && \
diff --git a/builder-support/dockerfiles/Dockerfile.target.el-9-amd64 b/builder-support/dockerfiles/Dockerfile.target.el-9-amd64
deleted file mode 120000 (symlink)
index 46968c4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.el-9
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.el-9-arm64 b/builder-support/dockerfiles/Dockerfile.target.el-9-arm64
deleted file mode 120000 (symlink)
index 46968c4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.el-9
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.oraclelinux-7 b/builder-support/dockerfiles/Dockerfile.target.oraclelinux-7
new file mode 100644 (file)
index 0000000..7b47e23
--- /dev/null
@@ -0,0 +1,18 @@
+# First do the source builds
+@INCLUDE Dockerfile.target.sdist
+
+# This defines the distribution base layer
+# Put only the bare minimum of common commands here, without dev tools
+FROM oraclelinux:7 as dist-base
+
+ARG BUILDER_CACHE_BUSTER=
+RUN touch /var/lib/rpm/* && yum install -y oracle-epel-release-el7 oracle-softwarecollection-release-el7 && \
+       yum-config-manager  --add-repo=http://yum.oracle.com/repo/OracleLinux/OL7/optional/developer/$(uname -m)/ && \
+    yum install -y --nogpgcheck devtoolset-11-gcc-c++ scl-utils
+
+# Do the actual rpm build
+@INCLUDE Dockerfile.rpmbuild
+
+# Do a test install and verify
+# Can be skipped with skippackagetest=1 in the environment
+@EXEC [ "$skippackagetest" = "" ] && include Dockerfile.rpmtest
index 923759aa8a879e1091f2eaeb7e0ea3ca8b97d7df..f8e6e99b9e8243588e51d7ad26c3f9aa97f60156 100644 (file)
@@ -3,15 +3,7 @@
 
 # This defines the distribution base layer
 # Put only the bare minimum of common commands here, without dev tools
-@IF [ ${BUILDER_TARGET} = oraclelinux-8 -o ${BUILDER_TARGET} = el-8 ]
 FROM oraclelinux:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-8-amd64 -o ${BUILDER_TARGET} = el-8-amd64 ]
-FROM amd64/oraclelinux:8 as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = oraclelinux-8-arm64 -o ${BUILDER_TARGET} = el-8-arm64 ]
-FROM arm64v8/oraclelinux:8 as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 RUN touch /var/lib/rpm/* && dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
diff --git a/builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-amd64 b/builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-amd64
deleted file mode 120000 (symlink)
index 608942e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.oraclelinux-8
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-arm64 b/builder-support/dockerfiles/Dockerfile.target.oraclelinux-8-arm64
deleted file mode 120000 (symlink)
index 608942e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.oraclelinux-8
\ No newline at end of file
index 956c4494971a525dfc7cde3d3f8dd608b893ce77..0431c3d1acf431847ec6135cedf88b4ba9acadd6 100644 (file)
@@ -1,15 +1,8 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = ubuntu-focal ]
 FROM ubuntu:focal as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-focal-amd64 ]
-FROM amd64/ubuntu:focal as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-focal-arm64 ]
-FROM arm64v8/ubuntu:focal as dist-base
-@ENDIF
+
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
 RUN apt-get update && apt-get -y dist-upgrade
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-amd64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-amd64
deleted file mode 120000 (symlink)
index d2a0521..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-focal
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-arm64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-focal-arm64
deleted file mode 120000 (symlink)
index d2a0521..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-focal
\ No newline at end of file
index d623a956e2f66994439097bd7a841e6627358cd4..b9a9047d1d9d1b415198d4698f82b8b7e5685321 100644 (file)
@@ -1,15 +1,8 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy ]
 FROM ubuntu:jammy as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy-amd64 ]
-FROM amd64/ubuntu:jammy as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-jammy-arm64 ]
-FROM arm64v8/ubuntu:jammy as dist-base
-@ENDIF
+
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
 RUN apt-get update && apt-get -y dist-upgrade
index ce71c39c03afa09a7fb870da0c866e5cf18b6e3c..c3c3c4d8ec2e61591730a68523dc0dead4e46f66 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar ]
 FROM ubuntu:lunar as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar-amd64 ]
-FROM amd64/ubuntu:lunar as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-lunar-arm64 ]
-FROM arm64v8/ubuntu:lunar as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-amd64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-amd64
deleted file mode 120000 (symlink)
index 5ab4dd2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-lunar
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-arm64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-lunar-arm64
deleted file mode 120000 (symlink)
index 5ab4dd2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-lunar
\ No newline at end of file
index a55089dfe9873748b3f74869f0fa846e2dd9d4ec..21639a4afddf1918e02ad0bafdb6e5e2b5aa4309 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic ]
 FROM ubuntu:mantic as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic-amd64 ]
-FROM amd64/ubuntu:mantic as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-mantic-arm64 ]
-FROM arm64v8/ubuntu:mantic as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-amd64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-amd64
deleted file mode 120000 (symlink)
index 17efdef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-mantic
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-arm64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-mantic-arm64
deleted file mode 120000 (symlink)
index 17efdef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-mantic
\ No newline at end of file
index e25bddfb8551d904d1fe83e775020f3f1a8926df..5df880b950bebdb638b78fefb7ef551bbe179ffa 100644 (file)
@@ -1,15 +1,7 @@
 # First do the source builds
 @INCLUDE Dockerfile.target.sdist
 
-@IF [ ${BUILDER_TARGET} = ubuntu-noble ]
 FROM ubuntu:noble as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-noble-amd64 ]
-FROM amd64/ubuntu:noble as dist-base
-@ENDIF
-@IF [ ${BUILDER_TARGET} = ubuntu-noble-arm64 ]
-FROM arm64v8/ubuntu:noble as dist-base
-@ENDIF
 
 ARG BUILDER_CACHE_BUSTER=
 ARG APT_URL
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-amd64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-amd64
deleted file mode 120000 (symlink)
index c0c8713..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-noble
\ No newline at end of file
diff --git a/builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-arm64 b/builder-support/dockerfiles/Dockerfile.target.ubuntu-noble-arm64
deleted file mode 120000 (symlink)
index c0c8713..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Dockerfile.target.ubuntu-noble
\ No newline at end of file
index ff6f53809c9b8f74389846082e35cc47e0f3219a..621990c646643ad3aa8d9b2dc15bc267592102fb 100755 (executable)
@@ -48,6 +48,8 @@ def addDependencyToSBOM(sbom, appInfos, pkg):
         component['version'] = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version) + '-' + pkg.release
     else:
         component['version'] = (pkg.version if pkg.epoch == 0 else str(pkg.epoch) + ':' + pkg.version)
+    if hasattr(pkg, 'arch'):
+        component['version'] += '.' + pkg.arch
     if hasattr(pkg, 'vendor') and pkg.vendor is not None:
         component['supplier'] = {'name': pkg.vendor}
     if hasattr(pkg, 'publisher') and pkg.publisher is not None:
@@ -132,7 +134,15 @@ def generateSBOM(packageName, additionalDeps):
     appName = packageName
     appInfos = getPackageInformations(pkgDB, packageName)
     component = { 'name': appName, 'bom-ref': 'pkg:' + appName, 'type': 'application'}
-    component['version'] = appInfos.version
+
+    if appInfos.release:
+        component['version'] = (appInfos.version if appInfos.epoch == 0 else str(appInfos.epoch) + ':' + appInfos.version) + '-' + appInfos.release
+    else:
+        component['version'] = (appInfos.version if appInfos.epoch == 0 else str(appInfos.epoch) + ':' + appInfos.version)
+
+    if hasattr(appInfos, 'arch'):
+        component['version'] += '.' + appInfos.arch
+
     component['supplier'] = {'name': appInfos.vendor if appInfos.vendor != '<NULL>' else 'PowerDNS.COM BV', 'url': ['https://www.powerdns.com']}
     component['licenses'] = [{'license': {'id': licenseToSPDXIdentifier(appInfos.license)}}]
     depRelations['pkg:' + appName] = []
index b09793fcd00d9c331425a175ed4596049daa6905..57656bf2c65336b321cc8abb252ff59558527865 100755 (executable)
@@ -26,6 +26,9 @@ echo $0: Checking that the hash of ${QUICHE_TARBALL} is ${QUICHE_TARBALL_HASH}
 echo "${QUICHE_TARBALL_HASH}"  "${QUICHE_TARBALL}" | sha256sum -c -
 tar xf "${QUICHE_TARBALL}"
 cd "quiche-${QUICHE_VERSION}"
+# Disable SONAME in the quiche shared library, we do not intend this library to be used by anyone else and it makes things more complicated since we rename it to libdnsdist-quiche
+sed -i 's/ffi = \["dep:cdylib-link-lines"\]/ffi = \[\]/' quiche/Cargo.toml
+sed -i 's,cdylib_link_lines::metabuild();,//cdylib_link_lines::metabuild();,' quiche/src/build.rs
 RUST_BACKTRACE=1 cargo build --release --no-default-features --features ffi,boringssl-boring-crate --package quiche
 
 install -m644 quiche/include/quiche.h "${INSTALL_PREFIX}"/include
index 1770290d84a9cf446f835724a3e5d724a9c68eb6..c0e96aa404a9738dad73ce192845afad9f3f8924 100644 (file)
@@ -1,6 +1,6 @@
 {
-  "version": "0.21.0",
+  "version": "0.22.0",
   "license": "BSD-2-Clause",
   "publisher": "https://github.com/cloudflare/quiche",
-  "SHA256SUM": "ca0f953c34e1549930cfd44deac5e8a6d9e6c3c3df01e5a2d9bcf6d07246b6a4"
+  "SHA256SUM": "0af8744b07038ee4af8cdb94dd4c11f1a730001944a0ef2f3f03e63715b15268"
 }
index 0e93f217bb1fd09795ff2da716c561cbcdd7205b..b98cbdde6bf05f6a3b40dcaa3c97675da42fda69 100644 (file)
@@ -1,7 +1,7 @@
 {
-  "version": "1.75.0",
+  "version": "1.78.0",
   "license": "MIT",
   "publisher": "https://www.rust-lang.org/",
-  "SHA256SUM_x86_64": "473978b6f8ff216389f9e89315211c6b683cf95a966196e7914b46e8cf0d74f6",
-  "SHA256SUM_aarch64": "30828cd904fcfb47f1ac43627c7033c903889ea4aca538f53dcafbb3744a9a73"
+  "SHA256SUM_x86_64": "1377999f189d328ec183676c0e69f21af16e450f8d67f10d1f6cf746951a1d64",
+  "SHA256SUM_aarch64": "a76e6b659e9948f2bbd9d1c99b45348c3729bac7003d5f5b7fb5cacddb2bfcc1"
 }
index 9e7a9c64b250744a8e502f6219d45ae8384fb71b..b97d254ab100fd9d450b676e8322b2b637e27dd6 100755 (executable)
@@ -17,15 +17,23 @@ if ! $tar --version | grep -q GNU; then
     exit 1
 fi
 
-for prog in pdns-recursor dnsdist pdns; do
+# pdns (auth) is handled seperately, it needs a special find condition which is hard to do with
+# vars, as we don't want the asterisks to expand prematurely. So repeat the body of the loop below
+# with a find condition for pdns to exclude accidentally matching pdns-recursor*.
+for prog in pdns-recursor dnsdist; do
   if [ $(find ${SRCDIR}/dist -name "${prog}*" 2>/dev/null | wc -l) -ne 0 ]; then
     dst=${DESTDIR}/${prog}/${BUILDER_VERSION}
     mkdir -p ${dst}
     cp ${BUILDER_TMP}/${BUILDER_VERSION}/sdist/${prog}*.tar.bz2 ${dst}
-    if [ "${prog}" = "pdns" ]; then
-      rm -f ${dst}/pdns-recursor*
-    fi
     tardirname=${prog}-${BUILDER_VERSION}-${BUILDER_TARGET}
     "$tar" -cjf ${dst}/${tardirname}.tar.bz2 --transform="s,.*/,${tardirname}/,g"  $(find ${SRCDIR} -type f)
   fi
 done
+prog=pdns
+if [ $(find ${SRCDIR}/dist -name 'pdns*' -a ! -name 'pdns-recursor*' 2>/dev/null | wc -l) -ne 0 ]; then
+  dst=${DESTDIR}/${prog}/${BUILDER_VERSION}
+  mkdir -p ${dst}
+  cp ${BUILDER_TMP}/${BUILDER_VERSION}/sdist/${prog}*.tar.bz2 ${dst}
+  tardirname=${prog}-${BUILDER_VERSION}-${BUILDER_TARGET}
+  "$tar" -cjf ${dst}/${tardirname}.tar.bz2 --transform="s,.*/,${tardirname}/,g"  $(find ${SRCDIR} -type f)
+fi
index 7f8747a1898d2b9f4d05ce79483f2eb5bedf9161..182b7887a2835917099a28cd665b58a2c55cac10 100644 (file)
@@ -55,7 +55,7 @@ Requires(pre): shadow-utils
 BuildRequires: fstrm-devel
 %systemd_requires
 %endif
-%if 0%{?rhel} >= 8
+%if ( "%{_arch}" != "aarch64" && 0%{?rhel} >= 8 ) || ( "%{_arch}" == "aarch64" && 0%{?rhel} >= 9 )
 BuildRequires: libbpf-devel
 BuildRequires: libxdp-devel
 %endif
index cbb5c1942661d3f825901c09831166be7914e294..bc478d433e558092b0435ed292f44d98d1b5728a 100644 (file)
@@ -81,15 +81,23 @@ make %{?_smp_mflags} check || (cat test-suite.log && false)
 %install
 make install DESTDIR=%{buildroot}
 
-%{__mv} %{buildroot}%{_sysconfdir}/%{name}/recursor.conf{-dist,}
 %{__mkdir} %{buildroot}%{_sysconfdir}/%{name}/recursor.d
 
 # change user and group to pdns-recursor and add default include-dir
-sed -i \
-    -e 's/# setuid=/setuid=pdns-recursor/' \
-    -e 's/# setgid=/setgid=pdns-recursor/' \
-    -e 's!# include-dir=.*!&\ninclude-dir=%{_sysconfdir}/%{name}/recursor.d!' \
-    %{buildroot}%{_sysconfdir}/%{name}/recursor.conf
+cat << EOF > %{buildroot}%{_sysconfdir}/%{name}/recursor.conf
+dnssec:
+  # validation: process
+recursor:
+  include_dir: %{_sysconfdir}/%{name}/recursor.d
+  setuid: pdns-recursor
+  setgid: pdns-recursor
+incoming:
+  # listen:
+  # - 127.0.0.1
+outgoing:
+  # source_address:
+  # - 0.0.0.0
+EOF
 
 %{__install } -d %{buildroot}/%{_sharedstatedir}/%{name}
 
index 348127854d4e8611e7c77aecdc7167c1a3a34b6a..011b5a7ec61e7a2def8629ee7f228d7d12b85718 100644 (file)
@@ -114,13 +114,7 @@ PDNS_ENABLE_IPCIPHER
 PDNS_CHECK_RAGEL([pdns/dnslabeltext.cc], [www.powerdns.com])
 PDNS_CHECK_CLOCK_GETTIME
 
-BOOST_REQUIRE([1.42])
-# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+
-# to be compatible with C++11
-AM_CONDITIONAL([HAVE_BOOST_GE_148], [test "$boost_major_version" -ge 148])
-AS_IF([test "$boost_major_version" -ge 148], [
-  AC_DEFINE(HAVE_BOOST_GE_148, [1], [Define to 1 if you have boost >= 1.48])
-])
+BOOST_REQUIRE([1.54])
 
 BOOST_PROGRAM_OPTIONS([mt])
 AS_IF([test "$boost_cv_lib_program_options" = "no"], [
@@ -309,11 +303,12 @@ LDFLAGS="$RELRO_LDFLAGS $LDFLAGS"
 
 CFLAGS="$PIE_CFLAGS $CFLAGS"
 CXXFLAGS="$PIE_CFLAGS $CXXFLAGS"
-PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS"
 AS_IF([test "$ax_cxx_cv_filesystem_lib" != "none"],
- [PROGRAM_LDFLAGS="$PROGRAM_LDFLAGS -l$ax_cxx_cv_filesystem_lib"],
+ [CXXFS_LIBS="-l$ax_cxx_cv_filesystem_lib"],
  []
 )
+AC_SUBST([CXXFS_LIBS])
+PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS $CXXFS_LIBS"
 AC_SUBST([PROGRAM_LDFLAGS])
 
 PDNS_ENABLE_COVERAGE
index b4dc9f3d8d76875933183409b83147c31a494c97..9cd614342266aaf71724ba4b613722fe0e220d1d 100644 (file)
@@ -139,7 +139,7 @@ class PDNSPBConnHandler(object):
             if response.HasField('queryTimeSec'):
                 datestr = datetime.datetime.fromtimestamp(response.queryTimeSec).strftime('%Y-%m-%d %H:%M:%S')
                 if response.HasField('queryTimeUsec'):
-                    datestr = datestr + '.' + str(response.queryTimeUsec)
+                    datestr = datestr + '.' + ("%06d" % response.queryTimeUsec)
                 print("- Query time: %s" % (datestr))
 
             policystr = ''
@@ -166,12 +166,12 @@ class PDNSPBConnHandler(object):
             for rr in response.rrs:
                 rrclass = 1
                 rdatastr = ''
-                rrudr = 0
+                rrudr = 'N/A'
                 if rr.HasField('class'):
                     rrclass = getattr(rr, 'class')
                 rrtype = rr.type
                 if rr.HasField('udr'):
-                    rrudr = rr.udr
+                    rrudr = str(rr.udr)
                 if (rrclass == 1 or rrclass == 255) and rr.HasField('rdata'):
                     if rrtype == 1:
                         rdatastr = socket.inet_ntop(socket.AF_INET, rr.rdata)
@@ -180,7 +180,7 @@ class PDNSPBConnHandler(object):
                     elif rrtype == 28:
                         rdatastr = socket.inet_ntop(socket.AF_INET6, rr.rdata)
 
-                print("\t - %d, %d, %s, %d, %s, %d" % (rrclass,
+                print("\t - %d, %d, %s, %d, %s, %s" % (rrclass,
                                                    rrtype,
                                                    rr.name,
                                                    rr.ttl,
@@ -190,7 +190,7 @@ class PDNSPBConnHandler(object):
     def printSummary(self, msg, typestr):
         datestr = datetime.datetime.fromtimestamp(msg.timeSec).strftime('%Y-%m-%d %H:%M:%S')
         if msg.HasField('timeUsec'):
-            datestr = datestr + '.' + str(msg.timeUsec)
+            datestr = datestr + '.' + ("%06d" % msg.timeUsec)
         ipfromstr = 'N/A'
         iptostr = 'N/A'
         toportstr = ''
@@ -241,12 +241,24 @@ class PDNSPBConnHandler(object):
         if msg.HasField('requestorId'):
             requestorId = msg.requestorId
 
-        nod = 0
+        nod = 'N/A';
         if msg.HasField('newlyObservedDomain'):
-            nod = msg.newlyObservedDomain
+            nod = str(msg.newlyObservedDomain)
+
+        workerId = 'N/A'
+        if msg.HasField('workerId'):
+           workerId = str(msg.workerId)
+
+        pcCacheHit = 'N/A'
+        if msg.HasField('packetCacheHit'):
+           pcCacheHit = str(msg.packetCacheHit)
+
+        outgoingQs = 'N/A'
+        if msg.HasField('outgoingQueries'):
+           outgoingQs = str(msg.outgoingQueries)
 
         print('[%s] %s of size %d: %s%s%s -> %s%s(%s) id: %d uuid: %s%s '
-                  'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %d' % (datestr,
+                  'requestorid: %s deviceid: %s devicename: %s serverid: %s nod: %s workerId: %s pcCacheHit: %s outgoingQueries: %s' % (datestr,
                                                     typestr,
                                                     msg.inBytes,
                                                     ipfromstr,
@@ -262,7 +274,10 @@ class PDNSPBConnHandler(object):
                                                     deviceId,
                                                     deviceName,
                                                     serveridstr,
-                                                    nod))
+                                                    nod,
+                                                    workerId,
+                                                    pcCacheHit,
+                                                    outgoingQs))
 
         for mt in msg.meta:
             values = ''
@@ -271,7 +286,7 @@ class PDNSPBConnHandler(object):
             for entry in mt.value.intVal:
                 values = ', '.join([values, str(entry)]) if values != '' else str(entry)
 
-            print('- %s -> %s' % (mt.key, values))
+            print('- (meta) %s -> %s' % (mt.key, values))
 
     def getRequestorSubnet(self, msg):
         requestorstr = None
index f4d406075cb9014bec92b855ad1dc943f0dda522..575cf913d41d428c0cf6f1da50d8edb9ed79bcf4 100644 (file)
@@ -19,6 +19,7 @@
             'list-autoprimaries:List all autoprimaries'
             'add-zone-key:Add a ZSK or KSK to zone and specify algo&bits'
             'backend-cmd:Perform one or more backend commands'
+            'backend-lookup:Perform a backend record lookup'
             'b2b-migrate:Move all data from one backend to another'
             'bench-db:Bench database backend with queries, one zone per line'
             'check-zone:Check a zone for correctness'
index ad2a8afd56291d0abbfd626c705a56ba055c4015..7395e78879c1fbcafef7e507251e6161808f242d 100644 (file)
@@ -15,7 +15,7 @@ have pdnsutil && {
   _pdnsutil_helper_local_() {
     local cur prev cmd
 
-    local _PDNSUTIL_ALL_CMDS="activate-tsig-key activate-zone-key add-record add-supermaster add-zone-key backend-cmd b2b-migrate bench-db change-slave-zone-master
+    local _PDNSUTIL_ALL_CMDS="activate-tsig-key activate-zone-key add-record add-supermaster add-zone-key backend-cmd backend-lookup b2b-migrate bench-db change-slave-zone-master
                               check-zone check-all-zones clear-zone create-bind-db create-slave-zone create-zone deactivate-tsig-key deactivate-zone-key delete-rrset
                               delete-tsig-key delete-zone disable-dnssec edit-zone export-zone-dnskey export-zone-key generate-tsig-key generate-zone-key get-meta
                               hash-zone-record increase-serial import-tsig-key import-zone-key load-zone list-algorithms list-keys list-zone list-all-zones
index 089e68d9b1b1a3584f55fcf14241c14b3822319d..46725e8fd637ab042e8ea2da04b12b0b847630d3 100644 (file)
@@ -120,16 +120,26 @@ try:
 except KeyboardInterrupt:
   pass
 
-for item in v4filter.items():
-  print(f"{str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in v6filter.items():
-  print(f"{str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in cidr4filter.items():
-  addr = netaddr.IPAddress(socket.ntohl(item[0].addr))
-  print(f"{str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in cidr6filter.items():
-  print(f"{str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
-for item in qnamefilter.items():
-  print(f"{''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}")
+if v4filter or v6filter or cidr4filter or cidr6filter:
+  print("Blocked networks:")
+  for item in v4filter.items():
+    print(f"- {str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}")
+  for item in v6filter.items():
+    print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}")
+  for item in cidr4filter.items():
+    addr = netaddr.IPAddress(socket.ntohl(item[0].addr))
+    print(f"- {str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
+  for item in cidr6filter.items():
+    print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}")
+
+if qnamefilter:
+  print("Blocked query names:")
+  for item in qnamefilter.items():
+    print(f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}")
+
+if parameters.xsk and xskDestinations:
+  print("Content of the AF_XDP (XSK) routing map:")
+  for item in xskDestinations.items():
+    print(f"- {str(netaddr.IPAddress(socket.ntohl(item[0].addr)))}:{str(socket.ntohs(item[0].port))}")
 
 xdp.remove_xdp(parameters.interface, 0)
index efc61ad181a6989b2c52943982569fc2c8199cb2..eeba25fed56620a9f3173ea661146a2ca796870a 100644 (file)
@@ -1,2 +1,8 @@
-local-address=0.0.0.0,::
-include-dir=/etc/powerdns/recursor.d
+recursor:
+  include_dir: /etc/powerdns/recursor.d
+
+incoming:
+  listen:
+  - 0.0.0.0
+  - '::'
+
index f9dab778a603a61f8ae7c540adcced6be5813ecf..f66969b91aedb18b6997b06cfc3d3a34204a5792 100644 (file)
@@ -36,10 +36,8 @@ MANPAGES_DIST += $(MANPAGES_TARGET_TOOLS) \
        dnsbulktest.1 \
        dnstcpbench.1
 
-if HAVE_BOOST_GE_148
 MANPAGES_INSTALL += dnsbulktest.1 \
        dnstcpbench.1
-endif
 
 if TOOLS
 MANPAGES_INSTALL += $(MANPAGES_TARGET_TOOLS)
index 6d165b4a1f52293deb4ea1dea2016f6a7873a80f..97fda12ff0c74bf8da87861f890a189bff8dda75 100644 (file)
@@ -42,7 +42,7 @@ Furthermore, the Makefiles require GNU make, not BSD make.
 
 By default, the PowerDNS Authoritative Server requires the following libraries and headers:
 
-* `Boost <http://boost.org/>`_ 1.35 or newer
+* `Boost <http://boost.org/>`_ 1.54 or newer
 * `OpenSSL <https://openssl.org>`_
 
 To build from a Git repository clone, the following dependencies are also required:
index 5695e9b618e663aa29cfbdc4cdf606dff9887632..d997f9633adbaffc247e539c4bbb3d54041f3e3b 100644 (file)
@@ -1,5 +1,5 @@
-Generic MySQL backend
-=====================
+Generic MySQL/MariaDB  backend
+==============================
 
 * Native: Yes
 * Master: Yes
@@ -22,7 +22,7 @@ Generic MySQL backend
   zone transfer fails.
 
 .. warning::
-  While it is possible to run the Generic MySQL backend on top of MySQL
+  While it is possible to run the Generic MySQL/MariaDB backend on top of MySQL/MariaDB 
   views, we have received several reports of this causing performance
   problems and memory leaks.  Please know that when reporting problems when
   running PowerDNS on top of a modified schema, our open source support
@@ -43,14 +43,15 @@ domains table. The following SQL does the job:
 .. literalinclude:: ../../modules/gmysqlbackend/enable-foreign-keys.mysql.sql
    :language: SQL
 
-Using MySQL replication
------------------------
+Using MySQL/MariaDB replication
+-------------------------------
 
-To support ``NATIVE`` domains, the ``binlog_format`` for the MySQL
+To support ``NATIVE`` domains, the ``binlog_format`` for the MySQL/MariaDB
 replication **must** be set to ``MIXED`` or ``ROW`` to prevent
 differences in data between replicated servers. See `"Setting
 The Binary Log
 Format" <http://dev.mysql.com/doc/refman/5.7/en/binary-log-setting.html>`__
+and `"Binary Log Formats" <https://mariadb.com/kb/en/binary-log-formats/>`__
 for more information.
 
 Otherwise, you will probably see:
index 0bf1df1fdcc1a39f504e16f3cc87fea0efcad318..266f45befa2d3a068a80f3351034741d9350f233 100644 (file)
@@ -8,7 +8,7 @@ The following table describes the supported backends and some of their capabilit
 +================================================+========+=========+===========+==========+==========+==============+==================================+=================================+==============+
 | :doc:`BIND <bind>`                             | Yes    | Yes     | Yes       | No       | No       | Yes          | No                               | Yes                             | ``bind``     |
 +------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
-| :doc:`Generic Mysql <generic-mysql>`           | Yes    | Yes     | Yes       | Yes      | Yes      | Yes          | Yes                              | Yes                             | ``gmysql``   |
+| :doc:`Generic Mysql/Mariadb <generic-mysql>`   | Yes    | Yes     | Yes       | Yes      | Yes      | Yes          | Yes                              | Yes                             | ``gmysql``   |
 +------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
 | :doc:`Generic ODBC <generic-odbc>`             | Yes    | Yes     | Yes       | Yes      | Yes      | Yes          | Yes                              | Yes                             | ``godbc``    |
 +------------------------------------------------+--------+---------+-----------+----------+----------+--------------+----------------------------------+---------------------------------+--------------+
index 9779f32491a35b3efe39623e31aa18aa15db0a3f..a1e2045650bca774357f0cd5e9b2d8949b918a40 100644 (file)
@@ -175,7 +175,7 @@ information.
 
 -  ``simple``: Search the requested domain by comparing the
    associatedDomain attributes with the domain string in the question.
--  ``tree``: Search entires by translating the domain string into a LDAP
+-  ``tree``: Search entries by translating the domain string into a LDAP
    dn. Your LDAP tree must be designed in the same way as the DNS LDAP
    tree. The question for "myhost.linuxnetworks.de" would translate into
    "dc=myhost,dc=linuxnetworks,dc=de,ou=hosts=..." and the entry where
index 225a2cb7e0ab3fbc5d981b9cfc6989c329908070..2ca9b77138507b6f376a2f6f8a28882c1f7382b3 100644 (file)
@@ -488,7 +488,7 @@ Changelogs for 4.1.x
     :pullreq: 6555
     :tickets: 6396
 
-    Report unparseable data in stoul invalid_argument exception
+    Report unparsable data in stoul invalid_argument exception
 
   .. change::
     :tags: Improvements
index f15ebf31bb13b35f59ee1e0d75463951a5c8b559..aaf47393fc1598f607a878aa8a626151e52eb41e 100644 (file)
@@ -1455,7 +1455,7 @@ Changelogs for 4.2.x
     :tags: Bug Fixes
     :pullreq: 6396
 
-    Report unparseable data in stoul ``invalid_argument`` exception.
+    Report unparsable data in stoul ``invalid_argument`` exception.
 
   .. change::
     :tags: New Features, Tools
index 6892a17a9ef93efb2b72212d3450065f73e626f6..44ed62d090efa6fb7c863812eca2db5981661496 100644 (file)
@@ -1,6 +1,92 @@
 Changelogs for 4.9.x
 ====================
 
+.. changelog::
+  :version: 4.9.1
+  :released: 28th of May 2024
+
+  This is release 4.9.1 of the Authoritative Server.
+
+  Please review the :doc:`Upgrade Notes <../upgrading>` before upgrading from versions < 4.9.x.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14253
+
+    autoconf: allow prerelease systemd versions (Chris Hofstaedtler)
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14251
+
+    ixfrdist: Fix broken 'uid' and 'gid' parsing for non-numerical values
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14229
+
+    YaHTTP: Enforce max # of request fields and max request line size
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14188
+
+    rpm: Change home directory to /var/lib/pdns
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14199
+
+    Fix memory leaks in the bind file format parser
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14186
+
+    dnsproxy: fix build on s390x (Chris Hofstaedtler)
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14191
+
+    m4: Add option for 64-bit time_t on 32-bit systems with glibc-2.34 (Sven Wegener)
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14189
+
+    pdnsutil check-zone: accept LUA A/AAAA as SVCB address targets
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14190
+
+    Properly finalize PKCS11 modules before releasing them (Aki Tuomi)
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14187
+
+    Wrap backend factories in smart pointers
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14058
+
+    don't crash when a catalog SOA is invalid 
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14126
+
+    (optionally) drop whitespace on join
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 13929
+
+    debian: adjust option name in shipped postinst
+
 .. changelog::
   :version: 4.9.0
   :released: 15th of March 2024
index 8282b79e42c7723b0aa67941e8d9001cf01e5cc4..6c24e472f5dcfead56f4905c69d16133d3a6f199 100644 (file)
@@ -1443,7 +1443,7 @@ Other changes
    parameters for pdnssec.
 -  `commit 2f2b014 <https://github.com/PowerDNS/pdns/commit/2f2b014>`__:
    apply variant of code in `ticket
-   714 <https://github.com/PowerDNS/pdns/issues/714>`__ so we can lauch
+   714 <https://github.com/PowerDNS/pdns/issues/714>`__ so we can launch
    pipe backend scripts with parameters, plus add experimental code that
    if pipe-command is a unix domain socket, we use that.
 -  `commit 9566683 <https://github.com/PowerDNS/pdns/commit/9566683>`__:
@@ -4749,7 +4749,7 @@ Improvements
    fact only made things worse.
 -  LDAP backend updates from its author Norbert Sendetzky. Reverse
    lookups should work now too.
--  An error message about unparseable packets did not include the
+-  An error message about unparsable packets did not include the
    originating IP address (fixed by Mark Bergsma)
 -  PowerDNS can now be started via path resolution while running with a
    guardian. Suggested by Maurice Nonnekes.
index 56a85374175b29da834bb8dd52469de0abb1d1a3..ddf7e0d73bd1c77422c773b442fb25067c08eb43 100755 (executable)
@@ -30,7 +30,7 @@ def main():
     # Install some stuff into the venv.
     requirements_file = source_root.joinpath(args.requirements_file)
     pip = venv_directory.joinpath("bin").joinpath("pip")
-    subprocess.run([pip, "install", "-U", "pip", "setuptools-git", "wheel"])
+    subprocess.run([pip, "install", "-U", "pip", "setuptools", "wheel"])
     subprocess.run([pip, "install", "-r", requirements_file])
 
     # Run sphinx to generate the man-pages.
index 256033f9f42cbb5acba4c8c7ecd7d3d43c69b67c..d2e56e7538d9f36e308ffb1709facdea893392d2 100644 (file)
@@ -20,6 +20,7 @@ The following webserver related configuration items are available:
 * :ref:`setting-webserver-port`: Port to bind the webserver to.
 * :ref:`setting-webserver-allow-from`: Netmasks that are allowed to connect to the webserver
 * :ref:`setting-webserver-max-bodysize`: Maximum request/response body size in megabytes
+* :ref:`setting-webserver-connection-timeout`: Request/response timeout in seconds
 
 
 Metrics Endpoint
index 486c439f77e187b835bf6f61a6541fb7b161ae53..3da00b29ea07702e1e935fbfa40fb33656a69285 100644 (file)
@@ -6,7 +6,7 @@ PowerDNS Authoritative Server version 4.2 and later support dynamic DNS
 records.
 
 These records contain small snippets of configuration that enable dynamic
-behaviour based on requester IP address, requester's EDNS Client Subnet,
+behaviour based on requestor IP address, requestor's EDNS Client Subnet,
 server availability or other factors.
 
 Capabilities range from very simple to highly advanced multi-pool
@@ -21,7 +21,7 @@ tiny (or larger) `Lua <https://www.lua.org>`_ statements.
   interoperability, and strive to turn this functionality into a broadly
   supported standard.
 
-To enable this feature, either set `:ref:`setting-enable-lua-records` in the configuration,
+To enable this feature, either set :ref:`setting-enable-lua-records` in the configuration,
 or set the ``ENABLE-LUA-RECORDS`` per-zone metadata item to ``1``.
 
 In addition, to benefit from the geographical features, make sure the PowerDNS
@@ -66,7 +66,7 @@ Another example using :func:`pickclosest`::
     www    IN    LUA    A    "pickclosest({'192.0.2.1','192.0.2.2','198.51.100.1'})"
 
 This uses the GeoIP backend to find indications of the geographical location of
-the requester and the listed IP addresses. It will return with one of the closest
+the requestor and the listed IP addresses. It will return with one of the closest
 addresses.
 
 :func:`pickclosest` and :func:`ifportup` can be combined as follows::
@@ -177,9 +177,10 @@ outside of Europe will hit 198.51.100.1 as long as it is available, and the
 
 Advanced topics
 ---------------
-By default, LUA records are executed with ``return `` prefixed to them. This saves
-a lot of typing for common cases. To run actual Lua scripts, start a record with a ``;``
-which indicates no ``return `` should be prepended.
+
+By default, LUA records are executed as if they were the argument to Lua's ``return`` statement.
+This saves a lot of typing for common cases.
+To run actual Lua scripts, start a record with a semicolon (``;``). You need to add your own ``return`` statement.
 
 To keep records more concise and readable, configuration can be stored in
 separate records. The full example from above can also be written as::
index 4dcdfef79d756dd882a8441ec9d722a7998de2b1..dfc8e01c6030029c2db6cc7ae9a2d4cd2384c27a 100644 (file)
@@ -283,6 +283,8 @@ backend-cmd *BACKEND* *CMD* [*CMD...*]
     Send a text command to a backend for execution. GSQL backends will
     take SQL commands, other backends may take different things. Be
     careful!
+backend-lookup *BACKEND* *NAME* [*TYPE* [*CLIENT-IP-SUBNET*]]
+    Perform a backend record lookup.
 bench-db [*FILE*]
     Perform a benchmark of the backend-database.
     *FILE* can be a file with a list, one per line, of zone names to use for this.
index 89f25b32af2094caa233fb7d272af7ed4769c058..6f563a43a82b30f96f24a7f2f6a97ea812153045 100644 (file)
@@ -148,7 +148,7 @@ respective domain to allow immediate freshness checks for this domain.
   ``/etc`` and ``/home``, possibly being unable to write AXFR'd zones.
 
 PowerDNS also reacts to notifies by immediately checking if the zone has
-updated and if so, retransfering it.
+updated and if so, retransferring it.
 
 All backends which implement this feature must make sure that they can
 handle transactions so as to not leave the zone in a half updated state.
index 82417d635873e40b86b90e31ab779c31f632d928..cc2a473621d80f1b0dc60a08bea20f4fe65f4f5f 100644 (file)
@@ -62,6 +62,11 @@ To determine if PowerDNS is unable to keep up with packets, determine
 the value of the :ref:`stat-qsize-q` variable. This represents the number of
 packets waiting for database attention. During normal operations the
 queue should be small.
+This number is a total over all receiver threads.
+
+The :ref:`setting-max-queue-length` and :ref:`setting-overload-queue-length` settings determine how PowerDNS deals with growing queues.
+If the queue for a single receiver thread (and its associated distributor threads) grows beyond the ``overload`` number, queries are answered only from the packet cache so the database can hopefully recover.
+If we reach the ``max`` number, we consider the situation hopeless and respawn the server process.
 
 The value of :ref:`setting-queue-limit` should be set to only keep queries in
 queue for as long as someone would be interested in knowing the answer. Many
@@ -260,7 +265,7 @@ Amount of packets in the packetcache
 
 qsize-q
 ^^^^^^^
-Number of packets waiting for database attention, only available if :ref:`setting-receiver-threads` > 1
+Number of packets waiting for database attention, only available if :ref:`setting-distributor-threads` > 1
 
 .. _stat-query-cache-hit:
 
index c8f9f1d696d9bef05141b106853e3acb5a2e4897..e85e84d46017815dcc4484e1ee8ab7465d02a641 100644 (file)
@@ -10,6 +10,6 @@ guzzle_sphinx_theme
 docutils!=0.15,<0.18
 jinja2<3.1.0
 pyyaml==6.0.1
-packaging==24.0
+packaging==24.1
 setuptools-scm==8.0.3 # setup-requires for sphinxcontrib-openapi
-pbr # setup-requires for sphinxcontrib-fulltoc
+pbr==6.1.0 # setup-requires for sphinxcontrib-fulltoc
index 772ec9048bb8aa8a6da45303364ceafe09363346..c2e73af45ea65164e2d5beb06a4e658e345c7b45 100644 (file)
@@ -1,5 +1,5 @@
 #
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
 # by the following command:
 #
 #    pip-compile --generate-hashes requirements.in
@@ -16,9 +16,9 @@ babel==2.12.1 \
     --hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \
     --hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455
     # via sphinx
-certifi==2023.7.22 \
-    --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
-    --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+certifi==2024.7.4 \
+    --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+    --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
     # via requests
 changelog==0.5.8 \
     --hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
@@ -184,16 +184,16 @@ markupsafe==2.1.3 \
     --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
     --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2
     # via jinja2
-packaging==24.0 \
-    --hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
-    --hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
+packaging==24.1 \
+    --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+    --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
     # via
     #   -r requirements.in
     #   setuptools-scm
     #   sphinx
-pbr==6.0.0 \
-    --hash=sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda \
-    --hash=sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9
+pbr==6.1.0 \
+    --hash=sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24 \
+    --hash=sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a
     # via -r requirements.in
 pygments==2.15.1 \
     --hash=sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c \
@@ -327,17 +327,9 @@ sphinxcontrib-websupport==1.2.4 \
     --hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
     --hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
     # via sphinx
-tomli==2.0.1 \
-    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
-    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
-    # via setuptools-scm
-typing-extensions==4.11.0 \
-    --hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
-    --hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
-    # via setuptools-scm
-urllib3==2.0.7 \
-    --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \
-    --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e
+urllib3==2.2.2 \
+    --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+    --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
     # via requests
 
 # WARNING: The following packages were not pinned, but pip requires them to be
index da1d61f03423830d8ba8c9110dbca60368249da3..2f36a583b29a6d02db75f126b36dd1a7e5a503f4 100644 (file)
@@ -1,4 +1,4 @@
-@       86400   IN  SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2024051501 10800 3600 604800 10800
+@       86400   IN  SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2024092001 10800 3600 604800 10800
 @       3600    IN  NS  pdns-public-ns1.powerdns.com.
 @       3600    IN  NS  pdns-public-ns2.powerdns.com.
 
@@ -128,6 +128,7 @@ auth-4.8.4.security-status                              60 IN TXT "1 OK"
 auth-4.9.0-alpha1.security-status                       60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
 auth-4.9.0-beta2.security-status                        60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
 auth-4.9.0.security-status                              60 IN TXT "1 OK"
+auth-4.9.1.security-status                              60 IN TXT "1 OK"
 
 ; Auth Debian
 auth-3.4.1-2.debian.security-status                     60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2015-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-03/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-04/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-05/"
@@ -372,6 +373,8 @@ recursor-4.9.3.security-status                          60 IN TXT "1 OK"
 recursor-4.9.4.security-status                          60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-02.html"
 recursor-4.9.5.security-status                          60 IN TXT "1 OK"
 recursor-4.9.6.security-status                          60 IN TXT "1 OK"
+recursor-4.9.7.security-status                          60 IN TXT "1 OK"
+recursor-4.9.8.security-status                          60 IN TXT "1 OK"
 recursor-5.0.0-alpha1.security-status                   60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
 recursor-5.0.0-alpha2.security-status                   60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
 recursor-5.0.0-beta1.security-status                    60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
@@ -383,7 +386,14 @@ recursor-5.0.2.security-status                          60 IN TXT "1 OK"
 recursor-5.0.3.security-status                          60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-02.html"
 recursor-5.0.4.security-status                          60 IN TXT "1 OK"
 recursor-5.0.5.security-status                          60 IN TXT "1 OK"
-recursor-5.1.0-alpha1.security-status                   60 IN TXT "1 OK"
+recursor-5.0.6.security-status                          60 IN TXT "1 OK"
+recursor-5.0.7.security-status                          60 IN TXT "1 OK"
+recursor-5.0.8.security-status                          60 IN TXT "1 OK"
+recursor-5.1.0-alpha1.security-status                   60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0-beta1.security-status                    60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0-rc1.security-status                      60 IN TXT "2 Superseded pre-release"
+recursor-5.1.0.security-status                          60 IN TXT "1 OK"
+recursor-5.1.1.security-status                          60 IN TXT "1 OK"
 
 ; Recursor Debian
 recursor-3.6.2-2.debian.security-status                 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/"
@@ -544,6 +554,7 @@ dnsdist-1.8.0.security-status                              60 IN TXT "3 Upgrade
 dnsdist-1.8.1.security-status                              60 IN TXT "3 Upgrade now, see https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"
 dnsdist-1.8.2.security-status                              60 IN TXT "1 OK"
 dnsdist-1.8.3.security-status                              60 IN TXT "1 OK"
+dnsdist-1.8.4.security-status                              60 IN TXT "1 OK"
 dnsdist-1.9.0-alpha1.security-status                       60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
 dnsdist-1.9.0-alpha2.security-status                       60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
 dnsdist-1.9.0-alpha3.security-status                       60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
@@ -554,3 +565,5 @@ dnsdist-1.9.1.security-status                              60 IN TXT "3 Upgrade
 dnsdist-1.9.2.security-status                              60 IN TXT "3 Upgrade now, see https://dnsdist.org/security-advisories/powerdns-advisory-for-dnsdist-2024-03.html"
 dnsdist-1.9.3.security-status                              60 IN TXT "3 Upgrade now, see https://dnsdist.org/security-advisories/powerdns-advisory-for-dnsdist-2024-03.html"
 dnsdist-1.9.4.security-status                              60 IN TXT "1 OK"
+dnsdist-1.9.5.security-status                              60 IN TXT "1 OK"
+dnsdist-1.9.6.security-status                              60 IN TXT "1 OK"
index 2684ec40d5dc519bcc9a77a9ee4368dcc43cd169..35a65cfd9fcc3c84e1051a498c707917254f80f6 100644 (file)
@@ -97,6 +97,7 @@ signed by valid TSIG signature for the zone.
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-allow-unsigned-autoprimary`.
+  Removed in 4.9.0
 
 .. _setting-also-notify:
 
@@ -633,6 +634,20 @@ approximately doubles query load.
 If this is turned off, DNAME records are treated as any other and served
 only when queried explicitly.
 
+.. _setting-dnsproxy-udp-port-range:
+
+``dnsproxy-udp-port-range``
+---------------------------
+
+-  String
+-  Default: `10000 60000`
+
+If :ref:`setting-resolver` enables the DNS Proxy, this setting limits the
+port range the DNS Proxy's UDP port is chosen from.
+
+Default should be fine on most installs, but if you have conflicting local
+services, you may choose to limit the range.
+
 .. _setting-dnssec-key-cache-ttl:
 
 ``dnssec-key-cache-ttl``
@@ -1046,6 +1061,18 @@ Amount of time (in seconds) between subsequent cleanup routines for pre-computed
 
 Amount of time (in seconds) a pre-computed hash entry will be considered as expired when unused. See :func:`pickchashed()`.
 
+.. _setting-lua-global-include-dir:
+
+``lua-global-include-dir``
+---------------------------
+
+-  String
+-  Default: empty
+-  Example: ``/etc/pdns/lua-global/``
+
+When creating a Lua context, scan this directory for additional lua files. All files that end with
+.lua are loaded in order using ``POSIX`` as locale with Lua scripts.
+
 .. _setting-lua-health-checks-expire-delay:
 
 ``lua-health-checks-expire-delay``
@@ -1113,6 +1140,7 @@ When combining the ``"`` delimited chunks of a LUA record, whether to insert whi
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-primary`.
+  Removed in 4.9.0.
 
 -  Boolean
 -  Default: no
@@ -1199,7 +1227,8 @@ will generally suffice for most installations.
 -  Default: 5000
 
 If this many packets are waiting for database attention, consider the
-situation hopeless and respawn.
+situation hopeless and respawn the server process.
+This limit is per receiver thread.
 
 .. _setting-max-signature-cache-entries:
 
@@ -1394,7 +1423,7 @@ Secondary name servers.
 
 If this many packets are waiting for database attention, answer any new
 questions strictly from the packet cache. Packets not in the cache will
-be dropped, and :ref:`_stat-overload-drops` will be incremented.
+be dropped, and :ref:`stat-overload-drops` will be incremented.
 
 .. _setting-prevent-self-notification:
 
@@ -1529,6 +1558,8 @@ Number of receiver (listening) threads to start. See :doc:`performance`.
 
 Recursive DNS server to use for ALIAS lookups and the internal stub resolver. Only one address can be given.
 
+It is assumed that the specified recursive DNS server, and the network path to it, are trusted.
+
 Examples::
 
   resolver=127.0.0.1
@@ -1684,6 +1715,7 @@ signing speed by changing this number.
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-secondary`.
+  Removed in 4.9.0.
 
 .. _setting-slave-cycle-interval:
 
@@ -1692,6 +1724,7 @@ signing speed by changing this number.
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-xfr-cycle-interval`.
+  Removed in 4.9.0.
 
 .. _setting-slave-renotify:
 
@@ -1700,6 +1733,7 @@ signing speed by changing this number.
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-secondary-do-renotify`.
+  Removed in 4.9.0.
 
 -  Boolean
 -  Default: no
@@ -1784,6 +1818,7 @@ and :doc:`Virtual Hosting <guides/virtual-instances>` how this can differ.
 
 .. deprecated:: 4.5.0
   Renamed to :ref:`setting-autosecondary`.
+  Removed in 4.9.0.
 
 -  Boolean
 -  Default: no
@@ -2026,7 +2061,7 @@ When set to "detailed", all information about the request and response are logge
 The value between the hooks is a UUID that is generated for each request. This can be used to find all lines related to a single request.
 
 .. note::
-  The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` seting must be 5 or higher for these lines to end up in the log.
+  The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` setting must be 5 or higher for these lines to end up in the log.
 
 .. _setting-webserver-max-bodysize:
 
@@ -2038,6 +2073,17 @@ The value between the hooks is a UUID that is generated for each request. This c
 
 Maximum request/response body size in megabytes.
 
+.. _setting-webserver-connection-timeout:
+
+``webserver-connection-timeout``
+--------------------------------
+.. versionadded:: 4.8.5
+
+-  Integer
+-  Default: 5
+
+Request/response timeout in seconds.
+
 .. _setting-webserver-password:
 
 ``webserver-password``
@@ -2091,7 +2137,7 @@ Workaround for `issue #11804 (outgoing AXFR may try to overfill a chunk and fail
 
 Default of no implies the pre-4.8 behaviour of up to 100 RRs per AXFR chunk.
 
-If enabled, only a single RR will be put into each AXFR chunk, making some zones transferable when they were not.
+If enabled, only a single RR will be put into each AXFR chunk, making some zones transferable when they were not otherwise.
 
 .. _setting-xfr-cycle-interval:
 
index 683ac23c9bbf72ed646d4161c9a6287ad54ed94f..56d22dbe2435aacd43ee4caf17a5393459fbe00a 100644 (file)
@@ -9,7 +9,7 @@ See the `3.X <https://doc.powerdns.com/3/authoritative/upgrading/>`__
 upgrade notes if your version is older than 3.4.2.
 
 4.9.0 to 5.0.0/master
---------------
+---------------------
 
 LUA records whitespace insertion
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index a0ed9645da16e4b7fc3fe3c354f43c87951b5715..2a7890a6cce249f46646b0655b1348532b9159a3 100644 (file)
@@ -22,6 +22,7 @@
 #include "json11.hpp"
 #include <cassert>
 #include <cmath>
+#include <cstdint>
 #include <cstdlib>
 #include <cstdio>
 #include <limits>
index 720285352db5632c1400168c5943ad1851dfe6ac..e9a2d1e2c089e9b47b60dec425d8edfdb6822c9d 100644 (file)
@@ -4,9 +4,10 @@
 unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
 {
   auto cursor = txn->getRWCursor(dbi);
-  MDBOutVal maxidval, maxcontent;
+  MDBOutVal maxidval{};
+  MDBOutVal maxcontent{};
   unsigned int maxid{0};
-  if(!cursor.get(maxidval, maxcontent, MDB_LAST)) {
+  if (cursor.get(maxidval, maxcontent, MDB_LAST) == 0) {
     maxid = maxidval.getNoStripHeader<unsigned int>();
   }
   return maxid;
@@ -15,15 +16,16 @@ unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi)
 unsigned int MDBGetRandomID(MDBRWTransaction& txn, MDBDbi& dbi)
 {
   auto cursor = txn->getRWCursor(dbi);
-  unsigned int id;
-  for(int attempts=0; attempts<20; attempts++) {
-    MDBOutVal key, content;
+  unsigned int newID = 0;
+  for (int attempts = 0; attempts < 20; attempts++) {
+    MDBOutVal key{};
+    MDBOutVal content{};
 
     // dns_random generates a random number in [0..signed_int_max-1]. We add 1 to avoid 0 and allow type_max.
     // 0 is avoided because the put() interface uses it to mean "please allocate a number for me"
-    id = dns_random(std::numeric_limits<signed int>::max()) + 1;
-    if(cursor.find(MDBInVal(id), key, content)) {
-      return id;
+    newID = dns_random(std::numeric_limits<signed int>::max()) + 1;
+    if (cursor.find(MDBInVal(newID), key, content) != 0) {
+      return newID;
     }
   }
   throw std::runtime_error("MDBGetRandomID() could not assign an unused random ID");
index ae32d78fd67b26a37bdcd969a6c2f4b2253d74d5..14e775e1bcc64b92ee18eb4fbfc2b87e34214b13 100644 (file)
@@ -1,8 +1,10 @@
 #pragma once
+
 #include <stdexcept>
 #include <string_view>
+#include <sstream>
 #include <iostream>
-#include "lmdb-safe.hh"
+
 #include <boost/archive/binary_oarchive.hpp>
 #include <boost/archive/binary_iarchive.hpp>
 #include <boost/serialization/vector.hpp>
 #include <boost/iostreams/stream.hpp>
 #include <boost/iostreams/stream_buffer.hpp>
 #include <boost/iostreams/device/back_inserter.hpp>
-#include <sstream>
-// using std::cout;
-// using std::endl;
 
+#include "lmdb-safe.hh"
 
 /*
-   Open issues:
-
-   Everything should go into a namespace
-   What is an error? What is an exception?
-   could id=0 be magic? ('no such id')
-     yes
-   Is boost the best serializer?
-     good default
-   Perhaps use the separate index concept from multi_index
-   perhaps get eiter to be of same type so for(auto& a : x) works
-     make it more value "like" with unique_ptr
-*/
-
-
-/** Return the highest ID used in a database. Returns 0 for an empty DB.
-    This makes us start everything at ID=1, which might make it possible to
-    treat id 0 as special
-*/
+ * OPEN ISSUES:
+ *
+ * - Everything should go into a namespace.
+ * - Decide on what is an error and what is an exception.
+ * - Could id=0 be magic? (e.g. 'no such id') - yes.
+ * - Is boost the best serializer? It's a good default.
+ * - Perhaps use the separate index concept from multi_index.
+ * - Perhaps get eiter to be of same type so that for(auto& a : x) works.
+ *   - Make it more value-like with unique_ptr.
+ */
+
+/**
+ * LMDB ID Vector Type.
+ */
+typedef std::vector<uint32_t> LmdbIdVec;
+
+/**
+ * Return the highest ID used in a database. Returns 0 for an empty DB. This makes us
+ * start everything at ID=1, which might make it possible to treat id 0 as special.
+ */
 unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
 
-/** Return a randomly generated ID that is unique and not zero.
-    May throw if the database is very full.
-*/
+/**
+ * Return a randomly generated ID that is unique and not zero. May throw if the database
+ * is very full.
+ */
 unsigned int MDBGetRandomID(MDBRWTransaction& txn, MDBDbi& dbi);
 
-typedef std::vector<uint32_t> LMDBIDvec;
-
-/** This is our serialization interface.
-    You can define your own serToString for your type if you know better
-*/
-template<typename T>
-std::string serToString(const T& t)
+/**
+ * This is our serialization interface. It can be specialized for other types.
+ */
+template <typename T>
+std::string serializeToBuffer(const T& value)
 {
-  std::string serial_str;
-  boost::iostreams::back_insert_device<std::string> inserter(serial_str);
-  boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
-  boost::archive::binary_oarchive oa(s, boost::archive::no_header | boost::archive::no_codecvt);
-
-  oa << t;
-  return serial_str;
+  std::string buffer;
+  boost::iostreams::back_insert_device<std::string> inserter(buffer);
+  boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>> inserterStream(inserter);
+  boost::archive::binary_oarchive outputArchive(inserterStream, boost::archive::no_header | boost::archive::no_codecvt);
+  outputArchive << value;
+  return buffer;
 }
 
-template<typename T>
-void serFromString(const string_view& str, T& ret)
+template <typename T>
+void deserializeFromBuffer(const string_view& buffer, T& value)
 {
-  ret = T();
-
-  boost::iostreams::array_source source(&str[0], str.size());
+  value = T();
+  boost::iostreams::array_source source(&buffer[0], buffer.size());
   boost::iostreams::stream<boost::iostreams::array_source> stream(source);
-  boost::archive::binary_iarchive in_archive(stream, boost::archive::no_header|boost::archive::no_codecvt);
-  in_archive >> ret;
-
-  /*
-  std::istringstream istr{str};
-  boost::archive::binary_iarchive oi(istr,boost::archive::no_header|boost::archive::no_codecvt );
-  oi >> ret;
-  */
+  boost::archive::binary_iarchive inputArchive(stream, boost::archive::no_header | boost::archive::no_codecvt);
+  inputArchive >> value;
 }
 
-
 template <class T, class Enable>
-inline std::string keyConv(const T& t);
+inline std::string keyConv(const T& value);
 
-template <class T, typename std::enable_if<std::is_arithmetic<T>::value,T>::type* = nullptr>
-inline std::string keyConv(const T& t)
+template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type* = nullptr>
+inline std::string keyConv(const T& value)
 {
-  return std::string((char*)&t, sizeof(t));
+  return std::string((char*)&value, sizeof(value));
 }
 
-// this is how to override specific types.. it is ugly
-template<class T, typename std::enable_if<std::is_same<T, std::string>::value,T>::type* = nullptr>
-inline std::string keyConv(const T& t)
+/**
+ * keyConv specialization for std::string.
+ */
+template <class T, typename std::enable_if<std::is_same<T, std::string>::value, T>::type* = nullptr>
+inline std::string keyConv(const T& value)
 {
-  return t;
+  return value;
 }
 
-
 namespace {
   inline MDBOutVal getKeyFromCombinedKey(MDBInVal combined) {
     if (combined.d_mdbval.mv_size < sizeof(uint32_t)) {
@@ -290,7 +283,7 @@ public:
       if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
         return false;
 
-      serFromString(data.get<std::string>(), t);
+      deserializeFromBuffer(data.get<std::string>(), t);
       return true;
     }
 
@@ -304,7 +297,7 @@ public:
       // auto range = (*d_parent.d_txn)->prefix_range<N>(domain);
 
       // auto range = prefix_range<N>(key);
-      LMDBIDvec ids;
+      LmdbIdVec ids;
 
       // because we know we only want one item, pass onlyOldest=true to consistently get the same one out of a set of duplicates
       get_multi<N>(key, ids, true);
@@ -378,10 +371,10 @@ public:
         if(d_on_index) {
           if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
             throw std::runtime_error("Missing id in constructor");
-          serFromString(d_data.get<std::string>(), d_t);
+          deserializeFromBuffer(d_data.get<std::string>(), d_t);
         }
         else
-          serFromString(d_id.get<std::string>(), d_t);
+          deserializeFromBuffer(d_id.get<std::string>(), d_t);
       }
 
       explicit iter_t(Parent* parent, typename Parent::cursor_t&& cursor, const std::string& prefix) :
@@ -405,10 +398,10 @@ public:
         if(d_on_index) {
           if((*d_parent->d_txn)->get(d_parent->d_parent->d_main, d_id, d_data))
             throw std::runtime_error("Missing id in constructor");
-          serFromString(d_data.get<std::string>(), d_t);
+          deserializeFromBuffer(d_data.get<std::string>(), d_t);
         }
         else
-          serFromString(d_id.get<std::string>(), d_t);
+          deserializeFromBuffer(d_id.get<std::string>(), d_t);
       }
 
 
@@ -473,13 +466,13 @@ public:
             // if(filter && !filter(data))
             //   goto next;
 
-            serFromString(data.get<std::string>(), d_t);
+            deserializeFromBuffer(data.get<std::string>(), d_t);
           }
           else {
             // if(filter && !filter(data))
             //   goto next;
 
-            serFromString(d_id.get<std::string>(), d_t);
+            deserializeFromBuffer(d_id.get<std::string>(), d_t);
           }
         }
         return *this;
@@ -643,7 +636,7 @@ public:
     };
 
     template<int N>
-    void get_multi(const typename std::tuple_element<N, tuple_t>::type::type& key, LMDBIDvec& ids, bool onlyOldest=false)
+    void get_multi(const typename std::tuple_element<N, tuple_t>::type::type& key, LmdbIdVec& ids, bool onlyOldest=false)
     {
       // std::cerr<<"in get_multi"<<std::endl;
       typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
@@ -763,7 +756,7 @@ public:
           // flags = MDB_APPEND;
         }
       }
-      (*d_txn)->put(d_parent->d_main, id, serToString(t), flags);
+      (*d_txn)->put(d_parent->d_main, id, serializeToBuffer(t), flags);
 
 #define insertMacro(N) std::get<N>(d_parent->d_tuple).put(*d_txn, t, id);
       insertMacro(0);
@@ -807,7 +800,7 @@ public:
       while(!cursor.get(key, data, first ? MDB_FIRST : MDB_NEXT)) {
         first = false;
         T t;
-        serFromString(data.get<std::string>(), t);
+        deserializeFromBuffer(data.get<std::string>(), t);
         clearIndex(key.get<uint32_t>(), t);
         cursor.del();
       }
diff --git a/ext/probds/meson.build b/ext/probds/meson.build
new file mode 100644 (file)
index 0000000..00ff3d8
--- /dev/null
@@ -0,0 +1,12 @@
+lib_probds = static_library(
+  'probds',
+  'murmur3.cc',
+  extra_files: [
+    'murmur3.h',
+  ],
+)
+
+dep_probds = declare_dependency(
+  link_with: lib_probds,
+  include_directories: include_directories('.'),
+)
index 4db53bec85a1478f5ebdee563f415506388885fa..e420c24a153ba20487db5b6bf674d6a6438a85fd 100644 (file)
@@ -98,6 +98,7 @@ namespace YaHTTP {
     HTTPBase() {
       HTTPBase::initialize();
     };
+    virtual ~HTTPBase() = default;
 
     virtual void initialize() {
       kind = 0;
index e123b38479637a442ab90eb08b85352e6bb1e0a0..5f6885a887b444dc0b3ad720a292350966663719 100644 (file)
@@ -49,21 +49,28 @@ namespace YaHTTP {
             rpos = route.size();
             upos = requrl.path.size();
             break;
-          } else { 
-            // match until url[upos] or next / if pattern is at end
-            while (upos < requrl.path.size()) {
-               if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
-                  break;
-               }
-               if (requrl.path[upos] == route[rpos+1]) {
-                  break;
-               }
-               upos++;
+          }
+          // match until url[upos] or next / if pattern is at end
+          while (upos < requrl.path.size()) {
+            if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
+              break;
+            }
+            if (requrl.path[upos] == route[rpos+1]) {
+              break;
             }
-            nend = upos;
-            params[pname] = funcptr::tie(nstart, nend);
+            upos++;
+          }
+          nend = upos;
+          params[pname] = funcptr::tie(nstart, nend);
+          if (upos > 0) {
+            upos--;
+          }
+          else {
+            // If upos is zero, do not decrement it and then increment at bottom of loop, this disturbs Coverity.
+            // Only increment rpos and continue loop
+            rpos++;
+            continue;
           }
-          upos--;
         }
         else if (route[rpos] != requrl.path[upos]) {
           break;
index faa53589ca9d931f15609c3f9f20a65be1bb2f79..6c1ef9f75a9112fba6f93925621e6d073e5b5468 100644 (file)
@@ -134,7 +134,7 @@ AC_DEFUN([AX_CHECK_SYSTEMD_FEATURES], [
           AC_PATH_PROG([SYSTEMCTL], [systemctl], [no])
           AS_IF([test "$SYSTEMCTL" = "no"],
             [AC_MSG_ERROR([systemctl not found])], [
-              _systemd_version=`${SYSTEMCTL} --version|head -1 |cut -d" " -f 2`
+              _systemd_version=`${SYSTEMCTL} --version|head -1 | tr ".~" "  " | cut -d" " -f 2`
               if test $_systemd_version -ge 183; then
                  systemd_private_tmp=y
               fi
index 9a5617ffb9b17339bb50b972f5e3bc23b64ae1a6..c201c5cc0883b750d96d5b37600bd8d81046fd4b 100644 (file)
@@ -106,6 +106,15 @@ libpdns_gettime = declare_dependency(
   )
 )
 
+libpdns_uuidutils = declare_dependency(
+  link_whole: static_library(
+    'pdns-uuidutils',
+    src_dir / 'uuid-utils.cc',
+    src_dir / 'uuid-utils.hh',
+    dependencies: [dep_rt, dep_boost],
+  )
+)
+
 if get_option('module-lmdb') != 'disabled'
   subdir('ext' / 'lmdb-safe')
 endif
@@ -152,8 +161,8 @@ deps = [
 
 if dep_systemd.found()
   systemd_service_conf = configuration_data()
-  systemd_service_conf.set('BinDir', get_option('bindir'))
-  systemd_service_conf.set('StaticBinDir', get_option('sbindir'))
+  systemd_service_conf.set('BinDir', get_option('prefix') / get_option('bindir'))
+  systemd_service_conf.set('StaticBinDir', get_option('prefix') / get_option('sbindir'))
   systemd_service_user = get_option('systemd-service-user')
   systemd_service_group = get_option('systemd-service-group')
   systemd_service_conf.set('ServiceUser', systemd_service_user)
@@ -220,6 +229,7 @@ if dep_systemd.found()
   auth_service_conf_general = configuration_data()
   auth_service_conf_general.merge_from(auth_service_conf)
   auth_service_conf_general.set('Description', 'PowerDNS Authoritative Server')
+  auth_service_conf_general.set('ConfigName', '')
   auth_service_conf_general.set('SocketDir', enable_socket_dir ? '--socket-dir=%t/pdns-auth' : '')
   auth_service_conf_general.set('SyslogIdentifier', 'pdns-auth')
   auth_service_conf_general.set('RuntimeDirectory', 'pdns-auth')
@@ -259,6 +269,7 @@ if dep_systemd.found()
     ixfrdist_service_conf_general = configuration_data()
     ixfrdist_service_conf_general.merge_from(ixfrdist_service_conf)
     ixfrdist_service_conf_general.set('Description', 'PowerDNS IXFR Distributor')
+    ixfrdist_service_conf_general.set('Config', '')
 
     configure_file(
       input: 'auth' / 'systemd' / 'ixfrdist.service.in',
@@ -269,7 +280,7 @@ if dep_systemd.found()
     ixfrdist_service_conf_instance = configuration_data()
     ixfrdist_service_conf_instance.merge_from(ixfrdist_service_conf)
     ixfrdist_service_conf_instance.set('Description', 'PowerDNS IXFR Distributor %i')
-    ixfrdist_service_conf_instance.set('Config', '--config=' + get_option('sysconfdir') + '/ixfrdist-%.ymli')
+    ixfrdist_service_conf_instance.set('Config', '--config=' + get_option('sysconfdir') + '/ixfrdist-%i.yml')
 
     configure_file(
       input: 'auth' / 'systemd' / 'ixfrdist.service.in',
@@ -623,8 +634,6 @@ common_sources += files(
   src_dir / 'unix_semaphore.cc',
   src_dir / 'unix_utility.cc',
   src_dir / 'utility.hh',
-  src_dir / 'uuid-utils.cc',
-  src_dir / 'uuid-utils.hh',
   src_dir / 'validate.hh',
   src_dir / 'version.cc',
   src_dir / 'version.hh',
@@ -690,6 +699,7 @@ tools = {
   },
   'pdns-auth-util': {
     'main': src_dir / 'pdnsutil.cc',
+    'export-dynamic': true,
     'files-extra': libpdns_bind_dnssec_schema_gen,
     'deps-extra': [
       dep_modules,
@@ -795,6 +805,14 @@ if get_option('tools')
       'main': src_dir / 'ixplore.cc',
       'manpages': ['ixplore.1'],
     },
+    'dnstcpbench': {
+      'main': src_dir / 'dnstcpbench.cc',
+      'manpages': ['dnstcpbench.1'],
+    },
+    'dnsbulktest': {
+      'main': src_dir / 'dnsbulktest.cc',
+      'manpages': ['dnsbulktest.1'],
+    },
     # Broken
     # 'comfun' : {
     #   'main': src_dir / 'comfun.cc',
@@ -823,18 +841,6 @@ if get_option('tools')
     src_dir / 'tcpiohandler.hh',
   )
 
-  if have_boost_1_48_0
-    tools += {
-      'dnstcpbench': {
-        'main': src_dir / 'dnstcpbench.cc',
-        'manpages': ['dnstcpbench.1'],
-      },
-      'dnsbulktest': {
-        'main': src_dir / 'dnsbulktest.cc',
-        'manpages': ['dnsbulktest.1'],
-      },
-    }
-  endif
 endif
 
 if get_option('tools-ixfrdist')
@@ -938,14 +944,21 @@ if get_option('unit-tests')
 endif
 
 if get_option('fuzz-targets')
-  tools += {
-    'fuzz-target-moadnsparser'                        : { 'main': src_dir / 'fuzz_moadnsparser.cc'                        },
-    'fuzz-target-packetcache'                         : { 'main': src_dir / 'fuzz_packetcache.cc'                         },
-    'fuzz-target-proxyprotocol'                       : { 'main': src_dir / 'fuzz_proxyprotocol.cc'                       },
-    'fuzz-target-dnslabeltext-parseRFC1035CharString' : { 'main': src_dir / 'fuzz_dnslabeltext_parseRFC1035CharString.cc' },
-    'fuzz-target-yahttp'                              : { 'main': src_dir / 'fuzz_yahttp.cc'                              },
-    'fuzz-target-zoneparsertng'                       : { 'main': src_dir / 'fuzz_zoneparsertng.cc'                       },
-  }
+  fuzz_targets = [
+    'moadnsparser',
+    'packetcache',
+    'proxyprotocol',
+    'dnslabeltext-parseRFC1035CharString',
+    'yahttp',
+    'zoneparsertng',
+  ]
+
+  foreach target: fuzz_targets
+    source_file = src_dir / 'fuzz_' + target.underscorify() + '.cc'
+    tools += {
+      'fuzz-target-' + target: { 'main': source_file }
+    }
+  endforeach
 endif
 
 libpdns_common = declare_dependency(
@@ -983,6 +996,7 @@ foreach tool, info: tools
       dependencies: [
         deps,
         libpdns_common,
+        libpdns_uuidutils,
         deps_extra,
       ],
     )
@@ -1008,7 +1022,7 @@ if python.found()
     'man-pages',
     command: [
       python,
-      docs_dir / 'generate-man-pages.py',
+      product_source_dir / docs_dir / 'generate-man-pages.py',
       '--venv-name', 'venv-auth-man-pages',
       '--requirements-file', docs_dir / 'requirements.txt',
       '--source-directory', docs_dir,
@@ -1076,3 +1090,17 @@ if get_option('module-remote') != 'disabled' and get_option('unit-tests-backends
     )
   endforeach
 endif
+
+if get_option('unit-tests-backends')
+  start_test_stop = files('regression-tests' / 'start-test-stop')[0]
+endif
+
+if get_option('module-geoip') != 'disabled' and get_option('unit-tests-backends')
+  test(
+    'pdns-auth-backend-geoip',
+    start_test_stop,
+    args: ['5300', 'geoip'],
+    workdir: product_source_dir / 'regression-tests',
+    depends: [pdns_auth],
+  )
+endif
index 1d528437eafc8b2448d245536d1b740b72c3bdaf..56c3ade41fccc3f4e5b28b1e49839743c36a7b43 100644 (file)
@@ -2,12 +2,12 @@ auto_var_init = get_option('auto-var-init')
 
 if auto_var_init != 'disabled'
   arg = '-ftrivial-auto-var-init=' + auto_var_init
-  if not cxx.has_argument(arg)
-    error('Compiler does not support ' + arg + ', which is needed for automatic variable initialization')
-    subdir_done()
+  if cxx.has_argument(arg)
+    add_project_arguments(arg, language: ['c', 'cpp'])
+  else
+    warning('Compiler does not support ' + arg + ', which is needed for automatic variable initialization')
+    auto_var_init = 'unsupported by compiler'
   endif
-
-  add_project_arguments(arg, language: ['c', 'cpp'])
 endif
 
 summary('Auto Var Init', auto_var_init, section: 'Configuration')
diff --git a/meson/boost-context/meson.build b/meson/boost-context/meson.build
new file mode 100644 (file)
index 0000000..0a0b487
--- /dev/null
@@ -0,0 +1,2 @@
+dep_boost_context = dependency('boost', modules: ['context'], required: true)
+
diff --git a/meson/boost-filesystem/meson.build b/meson/boost-filesystem/meson.build
new file mode 100644 (file)
index 0000000..8f0c5d7
--- /dev/null
@@ -0,0 +1,2 @@
+dep_boost_filesystem = dependency('boost', modules: ['filesystem'], required: false)
+summary('Filesystem', dep_boost_filesystem.found(), bool_yn: true, section: 'Boost')
index 943f0c4d803686822215c8641f520e4a609898fa..76e97576bb32e5d1f7216d6c16e70575a076f283 100644 (file)
@@ -1,8 +1,4 @@
-dep_boost = dependency('boost', version: '>= 1.42', required: true)
-# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+ to be compatible
-# with C++11.
-have_boost_1_48_0 = dep_boost.version().version_compare('>= 1.48.0')
-conf.set('HAVE_BOOST_GE_148', have_boost_1_48_0, description: 'Boost version >= 1.48.0')
+dep_boost = dependency('boost', version: '>= 1.54', required: true)
 # conf.set('BOOST_CONTAINER_USE_STD_EXCEPTIONS', true, description: 'Boost use std exceptions')
 add_project_arguments('-DBOOST_CONTAINER_USE_STD_EXCEPTIONS', language: ['c', 'cpp'])
 summary('Boost', dep_boost.found(), bool_yn: true, section: 'Boost')
index 38fdf963b565167dc5e4cfebb9fb3fd5258c3031..6fdd3880f1a555d4e7e32261591db0bac400e546 100644 (file)
@@ -8,7 +8,7 @@ if get_option('module-geoip') != 'disabled'
     lib_cxx_fs = cxx.find_library('stdc++fs', disabler: true, required: false)
     if lib_cxx_fs.found()
       if cxx.links(prog, name: '-lstdc++fs is needed', dependencies: lib_cxx_fs)
-        need_cxx_fs = '-lstdc++fs'
+        need_cxx_fs = true
         dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs)
         summary('Filesystem library', lib_cxx_fs, section: 'System')
       endif
@@ -18,7 +18,7 @@ if get_option('module-geoip') != 'disabled'
       lib_cxx_fs = cxx.find_library('c++fs', disabler: true, required: false)
       if lib_cxx_fs.found()
         if cxx.links(prog, name: '-lc++fs is needed', dependencies: lib_cxx_fs)
-          need_cxx_fs = '-lc++fs'
+          need_cxx_fs = true
           dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs)
           summary('Filesystem library', lib_cxx_fs, section: 'System')
         else
diff --git a/meson/dnstap/meson.build b/meson/dnstap/meson.build
new file mode 100644 (file)
index 0000000..e7a487e
--- /dev/null
@@ -0,0 +1,17 @@
+opt_dnstap = get_option('dnstap')
+dep_dnstap = dependency('libfstrm', required: opt_dnstap)
+
+if dep_dnstap.found()
+  funcs = [
+    'fstrm_tcp_writer_init',
+  ]
+
+  foreach func: funcs
+    has = cxx.has_function(func, dependencies: dep_dnstap)
+    conf.set('HAVE_' + func.to_upper(), has, description: 'Have libfstram ' + func)
+  endforeach
+endif
+
+conf.set('HAVE_FSTRM', dep_dnstap.found(), description: 'libfstrm')
+summary('DNSTAP', dep_dnstap.found(), bool_yn: true, section: 'Configuration')
+
diff --git a/meson/libcurl/meson.build b/meson/libcurl/meson.build
new file mode 100644 (file)
index 0000000..1f434ba
--- /dev/null
@@ -0,0 +1,4 @@
+opt_libcurl = get_option('libcurl')
+dep_libcurl = dependency('libcurl', version: '>= 7.21.3', required: opt_libcurl)
+conf.set('HAVE_LIBCURL', dep_libcurl.found(), description: 'Whether we have libcurl')
+summary('CURL', dep_libcurl.found(), bool_yn: true, section: 'Configuration')
diff --git a/meson/libresolv/meson.build b/meson/libresolv/meson.build
new file mode 100644 (file)
index 0000000..ca1bfc3
--- /dev/null
@@ -0,0 +1,14 @@
+dep_libresolv = dependency('resolv', required: false)
+
+need = false
+if not dep_libresolv.found()
+  # Dependency resolving does not work for macOS
+  if build_machine.system() == 'darwin'
+    add_project_link_arguments('-lresolv', language: 'cpp')
+    need = true
+  endif
+else
+  need = true
+endif
+
+summary('Need -lresolv', need, bool_yn: true, section: 'System')
diff --git a/meson/libsnmp/meson.build b/meson/libsnmp/meson.build
new file mode 100644 (file)
index 0000000..a39100a
--- /dev/null
@@ -0,0 +1,30 @@
+opt_libsnmp = get_option('snmp')
+
+dep_libsnmp = declare_dependency()
+
+if get_option('snmp')
+    snmp_config = find_program('net-snmp-config', required: true)
+    snmp_ldflags_res = run_command(snmp_config, '--libs', check: true)
+    snmp_ldflags = snmp_ldflags_res.stdout().strip().split()
+    snmp_ldflags_res = run_command(snmp_config, '--agent-libs', check: true)
+    snmp_ldflags += snmp_ldflags_res.stdout().strip().split()
+
+    dep_libsnmp = declare_dependency(
+      link_args: snmp_ldflags,
+    )
+endif
+
+if dep_libsnmp.found()
+  funcs = [
+    'snmp_select_info2',
+  ]
+
+  foreach func: funcs
+    define = 'HAVE_' + func.to_upper()
+    have_func = cxx.has_function(func, dependencies: dep_libsnmp)
+    conf.set(define, have_func, description: 'Have libsnmp ' + func)
+  endforeach
+endif
+
+conf.set('HAVE_LIBSSNMP', dep_libsnmp.found(), description: 'libsnmp')
+summary('SNMP', dep_libsnmp.found(), bool_yn: true, section: 'Configuration')
diff --git a/meson/nod/meson.build b/meson/nod/meson.build
new file mode 100644 (file)
index 0000000..ad0c2f4
--- /dev/null
@@ -0,0 +1,13 @@
+opt_nod = get_option('nod')
+
+if not dep_boost_filesystem.found() and opt_nod
+  error('NOD support was requested but boost filesystem module not found')
+endif
+
+enable_nod = dep_boost_filesystem.found() and opt_nod
+dep_nod = declare_dependency(
+      dependencies: [dep_boost_filesystem, dep_probds],
+) 
+
+conf.set('NOD_ENABLED', enable_nod, description: 'NOD')
+summary('NOD', enable_nod, bool_yn: true, section: 'Configuration')
diff --git a/meson/pthread-np/meson.build b/meson/pthread-np/meson.build
new file mode 100644 (file)
index 0000000..7dc7892
--- /dev/null
@@ -0,0 +1,13 @@
+funcs = [
+  'pthread_setaffinity_np',
+  'pthread_getattr_np',
+  'pthread_get_stackaddr_np',
+  'pthread_get_stacksize_np',
+]
+
+foreach func: funcs
+  found = cxx.has_function(func, dependencies: dep_threads)
+  define = 'HAVE_' + func.to_upper()
+  conf.set(define, found, description: 'Have ' + func)
+  summary(func, found, bool_yn: true, section: 'POSIX Threads')
+endforeach
index f9622206ff86bf137e2ab0b07d9df1893e75d47d..f7ea40739f69f4d2ace76f8fff9401869e34e2d4 100644 (file)
@@ -11,4 +11,4 @@ libgeoipbackend_la_SOURCES = \
        geoipinterface.cc geoipinterface.hh
 
 libgeoipbackend_la_LDFLAGS = -module -avoid-version
-libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS)
+libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS) $(MMDB_LIBS) $(CXXFS_LIBS)
index 5d06d2f6cc4401b2fc319f3203f683b9aba50d4d..c6441bbd777838be00049a4c98fbaab24f517078 100644 (file)
@@ -512,8 +512,9 @@ void GeoIPBackend::lookup(const QType& qtype, const DNSName& qdomain, int zoneId
   }
 
   Netmask addr{"0.0.0.0/0"};
-  if (pkt_p != nullptr)
+  if (pkt_p != nullptr) {
     addr = Netmask(pkt_p->getRealRemote());
+  }
 
   gl.netmask = 0;
 
@@ -582,8 +583,9 @@ void GeoIPBackend::lookup(const QType& qtype, const DNSName& qdomain, int zoneId
 
 bool GeoIPBackend::get(DNSResourceRecord& r)
 {
-  if (d_result.empty())
+  if (d_result.empty()) {
     return false;
+  }
 
   r = d_result.back();
   d_result.pop_back();
@@ -895,7 +897,7 @@ bool GeoIPBackend::getDomainInfo(const DNSName& domain, DomainInfo& di, bool /*
 {
   ReadLock rl(&s_state_lock);
 
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == domain) {
       SOAData sd;
       this->getSOA(domain, sd);
@@ -933,7 +935,7 @@ bool GeoIPBackend::getAllDomainMetadata(const DNSName& name, std::map<std::strin
     return false;
 
   ReadLock rl(&s_state_lock);
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       if (hasDNSSECkey(dom.domain)) {
         meta[string("NSEC3NARROW")].push_back("1");
@@ -951,7 +953,7 @@ bool GeoIPBackend::getDomainMetadata(const DNSName& name, const std::string& kin
     return false;
 
   ReadLock rl(&s_state_lock);
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       if (hasDNSSECkey(dom.domain)) {
         if (kind == "NSEC3NARROW")
@@ -970,7 +972,7 @@ bool GeoIPBackend::getDomainKeys(const DNSName& name, std::vector<DNSBackend::Ke
   if (!d_dnssec)
     return false;
   ReadLock rl(&s_state_lock);
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       regex_t reg;
       regmatch_t regm[5];
@@ -1016,7 +1018,7 @@ bool GeoIPBackend::removeDomainKey(const DNSName& name, unsigned int id)
   WriteLock rl(&s_state_lock);
   ostringstream path;
 
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       regex_t reg;
       regmatch_t regm[5];
@@ -1052,7 +1054,7 @@ bool GeoIPBackend::addDomainKey(const DNSName& name, const KeyData& key, int64_t
   WriteLock rl(&s_state_lock);
   unsigned int nextid = 1;
 
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       regex_t reg;
       regmatch_t regm[5];
@@ -1088,7 +1090,7 @@ bool GeoIPBackend::activateDomainKey(const DNSName& name, unsigned int id)
   if (!d_dnssec)
     return false;
   WriteLock rl(&s_state_lock);
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       regex_t reg;
       regmatch_t regm[5];
@@ -1123,7 +1125,7 @@ bool GeoIPBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
   if (!d_dnssec)
     return false;
   WriteLock rl(&s_state_lock);
-  for (GeoIPDomain dom : s_domains) {
+  for (const GeoIPDomain& dom : s_domains) {
     if (dom.domain == name) {
       regex_t reg;
       regmatch_t regm[5];
index aac49eca75cb32745002ce03f3db5193c14f03e0..7fc6cce353744d9952b32860749b6ff0908eb41d 100644 (file)
@@ -38,7 +38,7 @@ unique_ptr<GeoIPInterface> GeoIPInterface::makeInterface(const string& dbStr)
     stringtok(parts2, parts1[0], ";");
     /* try extension */
     filename = parts2[0];
-    size_t pos = filename.find_last_of(".");
+    size_t pos = filename.find_last_of('.');
     if (pos != string::npos)
       driver = filename.substr(pos + 1);
     else
index 673d923d3955ff5b20fd2db1cf00b8e3fec5a522..769730de83ffb60476a0b030bbee253c8ac2bae3 100644 (file)
@@ -10,4 +10,4 @@ module_extras = files(
   'geoipinterface.hh',
 )
 
-module_deps = [deps, dep_geoip, dep_mmdb, dep_yaml_cpp]
+module_deps = [deps, dep_geoip, dep_mmdb, dep_yaml_cpp, dep_cxx_fs]
index 6ab5d9086ceb6cadd87a68ad26ec027052e42bd2..77c2fcd1b80a16ce74e3560c78455d0e5740f171 100644 (file)
@@ -131,7 +131,7 @@ public:
     declare(suffix, "update-account-query", "", "update domains set account=? where name=?");
     declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
     declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
-    declare(suffix, "info-all-primary-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER')");
+    declare(suffix, "info-all-primary-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER') order by d.id");
     declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
     declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
     declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
index 3660bcf3fee87a748cd4c02fceab0a68bb8bd769..ef3e20487fb0c260250b2cf957b66a4cdb54a323 100644 (file)
@@ -1 +1 @@
--lodbc
\ No newline at end of file
+$(UNIXODBC_LIBS)
index d781a51404a84157d0e2450a11b45ac5eca0fc72..00d30bc4bbf072107b9e6d2e42012570507b159d 100644 (file)
@@ -112,7 +112,7 @@ public:
     declare(suffix, "update-account-query", "", "update domains set account=? where name=?");
     declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
     declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
-    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
     declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0");
     declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=?");
     declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
index ea51b68c638afb5ec79d37116335233a2b966b56..10f4b9ad9f3f9389953d8a6d608e60b99f1f80c8 100644 (file)
@@ -139,7 +139,7 @@ public:
     declare(suffix, "update-account-query", "", "update domains set account=$1 where name=$2");
     declare(suffix, "update-serial-query", "", "update domains set notified_serial=$1 where id=$2");
     declare(suffix, "update-lastcheck-query", "", "update domains set last_check=$1 where id=$2");
-    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER')");
+    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
     declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=$1 and records.type='SOA' and records.disabled=false");
     declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=$1");
     declare(suffix, "delete-domain-query", "", "delete from domains where name=$1");
index 09ef25fb6b2175688134ad213c785d051d3b66aa..4b45c5c6ee4b81e26440088205a2467488f82796 100644 (file)
@@ -125,7 +125,7 @@ public:
     declare(suffix, "update-account-query", "", "update domains set account=:account where name=:domain");
     declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
     declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
-    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+    declare(suffix, "info-all-primary-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id");
     declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=:catalog and records.type='SOA' and records.disabled=0");
     declare(suffix, "info-consumer-members-query", "", "select id, name, options, master from domains where type='SLAVE' and catalog=:catalog");
     declare(suffix, "delete-domain-query", "", "delete from domains where name=:domain");
index 2997e9911202223fb6559ccb8949de29156e434c..e632c88ed6504cd7db6730e0c824feaf7f20d8a1 100644 (file)
@@ -21,7 +21,9 @@
  */
 
 #include "ext/lmdb-safe/lmdb-safe.hh"
+#include <cstring>
 #include <lmdb.h>
+#include <memory>
 #include <stdexcept>
 #include <utility>
 #ifdef HAVE_CONFIG_H
@@ -73,51 +75,53 @@ std::pair<uint32_t, uint32_t> LMDBBackend::getSchemaVersionAndShards(std::string
 
   uint32_t schemaversion;
 
-  int rc;
-  MDB_env* env = nullptr;
+  MDB_env* tmpEnv = nullptr;
 
-  if ((rc = mdb_env_create(&env)) != 0) {
+  if (mdb_env_create(&tmpEnv) != 0) {
     throw std::runtime_error("mdb_env_create failed");
   }
 
-  if ((rc = mdb_env_set_mapsize(env, 0)) != 0) {
+  std::unique_ptr<MDB_env, decltype(&mdb_env_close)> env{tmpEnv, mdb_env_close};
+
+  if (mdb_env_set_mapsize(tmpEnv, 0) != 0) {
     throw std::runtime_error("mdb_env_set_mapsize failed");
   }
 
-  if ((rc = mdb_env_set_maxdbs(env, 20)) != 0) { // we need 17: 1 {"pdns"} + 4 {"domains", "keydata", "tsig", "metadata"} * 2 {v4, v5} * 2 {main, index in _0}
-    mdb_env_close(env);
+  if (mdb_env_set_maxdbs(tmpEnv, 20) != 0) { // we need 17: 1 {"pdns"} + 4 {"domains", "keydata", "tsig", "metadata"} * 2 {v4, v5} * 2 {main, index in _0}
     throw std::runtime_error("mdb_env_set_maxdbs failed");
   }
 
-  if ((rc = mdb_env_open(env, filename.c_str(), MDB_NOSUBDIR | MDB_RDONLY, 0600)) != 0) {
-    if (rc == ENOENT) {
-      // we don't have a database yet! report schema 0, with 0 shards
-      return {0u, 0u};
+  {
+    int retCode = mdb_env_open(tmpEnv, filename.c_str(), MDB_NOSUBDIR | MDB_RDONLY, 0600);
+    if (retCode != 0) {
+      if (retCode == ENOENT) {
+        // we don't have a database yet! report schema 0, with 0 shards
+        return {0U, 0U};
+      }
+      throw std::runtime_error("mdb_env_open failed");
     }
-    mdb_env_close(env);
-    throw std::runtime_error("mdb_env_open failed");
   }
 
   MDB_txn* txn = nullptr;
 
-  if ((rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)) != 0) {
-    mdb_env_close(env);
+  if (mdb_txn_begin(tmpEnv, nullptr, MDB_RDONLY, &txn) != 0) {
     throw std::runtime_error("mdb_txn_begin failed");
   }
 
   MDB_dbi dbi;
 
-  if ((rc = mdb_dbi_open(txn, "pdns", 0, &dbi)) != 0) {
-    if (rc == MDB_NOTFOUND) {
-      // this means nothing has been inited yet
-      // we pretend this means 5
+  {
+    int retCode = mdb_dbi_open(txn, "pdns", 0, &dbi);
+    if (retCode != 0) {
+      if (retCode == MDB_NOTFOUND) {
+        // this means nothing has been inited yet
+        // we pretend this means 5
+        mdb_txn_abort(txn);
+        return {5U, 0U};
+      }
       mdb_txn_abort(txn);
-      mdb_env_close(env);
-      return {5u, 0u};
+      throw std::runtime_error("mdb_dbi_open failed");
     }
-    mdb_txn_abort(txn);
-    mdb_env_close(env);
-    throw std::runtime_error("mdb_dbi_open failed");
   }
 
   MDB_val key, data;
@@ -125,16 +129,18 @@ std::pair<uint32_t, uint32_t> LMDBBackend::getSchemaVersionAndShards(std::string
   key.mv_data = (char*)"schemaversion";
   key.mv_size = strlen((char*)key.mv_data);
 
-  if ((rc = mdb_get(txn, dbi, &key, &data)) != 0) {
-    if (rc == MDB_NOTFOUND) {
-      // this means nothing has been inited yet
-      // we pretend this means 5
-      mdb_txn_abort(txn);
-      mdb_env_close(env);
-      return {5u, 0u};
-    }
+  {
+    int retCode = mdb_get(txn, dbi, &key, &data);
+    if (retCode != 0) {
+      if (retCode == MDB_NOTFOUND) {
+        // this means nothing has been inited yet
+        // we pretend this means 5
+        mdb_txn_abort(txn);
+        return {5U, 0U};
+      }
 
-    throw std::runtime_error("mdb_get pdns.schemaversion failed");
+      throw std::runtime_error("mdb_get pdns.schemaversion failed");
+    }
   }
 
   if (data.mv_size == 4) {
@@ -159,15 +165,18 @@ std::pair<uint32_t, uint32_t> LMDBBackend::getSchemaVersionAndShards(std::string
   key.mv_data = (char*)"shards";
   key.mv_size = strlen((char*)key.mv_data);
 
-  if ((rc = mdb_get(txn, dbi, &key, &data)) != 0) {
-    if (rc == MDB_NOTFOUND) {
-      cerr << "schemaversion was set, but shards was not. Dazed and confused, trying to exit." << endl;
-      mdb_txn_abort(txn);
-      mdb_env_close(env);
-      exit(1);
-    }
+  {
+    int retCode = mdb_get(txn, dbi, &key, &data);
+    if (retCode != 0) {
+      if (retCode == MDB_NOTFOUND) {
+        cerr << "schemaversion was set, but shards was not. Dazed and confused, trying to exit." << endl;
+        mdb_txn_abort(txn);
+        // NOLINTNEXTLINE(concurrency-mt-unsafe)
+        exit(1);
+      }
 
-    throw std::runtime_error("mdb_get pdns.shards failed");
+      throw std::runtime_error("mdb_get pdns.shards failed");
+    }
   }
 
   if (data.mv_size == 4) {
@@ -185,7 +194,6 @@ std::pair<uint32_t, uint32_t> LMDBBackend::getSchemaVersionAndShards(std::string
   }
 
   mdb_txn_abort(txn);
-  mdb_env_close(env);
 
   return {schemaversion, shards};
 }
@@ -898,32 +906,45 @@ BOOST_SERIALIZATION_SPLIT_FREE(DomainInfo);
 BOOST_IS_BITWISE_SERIALIZABLE(ComboAddress);
 
 template <>
-std::string serToString(const LMDBBackend::LMDBResourceRecord& lrr)
+std::string serializeToBuffer(const LMDBBackend::LMDBResourceRecord& value)
 {
-  std::string ret;
-  uint16_t len = lrr.content.length();
-  ret.reserve(2 + len + 7);
-
-  ret.assign((const char*)&len, 2);
-  ret += lrr.content;
-  ret.append((const char*)&lrr.ttl, 4);
-  ret.append(1, (char)lrr.auth);
-  ret.append(1, (char)lrr.disabled);
-  ret.append(1, (char)lrr.ordername);
-  return ret;
+  std::string buffer;
+
+  // Data size of the resource record.
+  uint16_t len = value.content.length();
+
+  // Reserve space to store the size of the resource record + the content of the resource
+  // record + a few other things.
+  buffer.reserve(sizeof(len) + len + sizeof(value.ttl) + sizeof(value.auth) + sizeof(value.disabled) + sizeof(value.ordername));
+
+  // Store the size of the resource record.
+  // NOLINTNEXTLINE.
+  buffer.assign((const char*)&len, sizeof(len));
+
+  // Store the contents of the resource record.
+  buffer += value.content;
+
+  // The few other things.
+  // NOLINTNEXTLINE.
+  buffer.append((const char*)&value.ttl, sizeof(value.ttl));
+  buffer.append(1, (char)value.auth);
+  buffer.append(1, (char)value.disabled);
+  buffer.append(1, (char)value.ordername);
+
+  return buffer;
 }
 
 template <>
-std::string serToString(const vector<LMDBBackend::LMDBResourceRecord>& lrrs)
+std::string serializeToBuffer(const vector<LMDBBackend::LMDBResourceRecord>& value)
 {
   std::string ret;
-  for (const auto& lrr : lrrs) {
-    ret += serToString(lrr);
+  for (const auto& lrr : value) {
+    ret += serializeToBuffer(lrr);
   }
   return ret;
 }
 
-static inline size_t serOneRRFromString(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
+static inline size_t deserializeRRFromBuffer(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
 {
   uint16_t len;
   memcpy(&len, &str[0], 2);
@@ -938,19 +959,19 @@ static inline size_t serOneRRFromString(const string_view& str, LMDBBackend::LMD
 }
 
 template <>
-void serFromString(const string_view& str, LMDBBackend::LMDBResourceRecord& lrr)
+void deserializeFromBuffer(const string_view& buffer, LMDBBackend::LMDBResourceRecord& value)
 {
-  serOneRRFromString(str, lrr);
+  deserializeRRFromBuffer(buffer, value);
 }
 
 template <>
-void serFromString(const string_view& str, vector<LMDBBackend::LMDBResourceRecord>& lrrs)
+void deserializeFromBuffer(const string_view& buffer, vector<LMDBBackend::LMDBResourceRecord>& value)
 {
-  auto str_copy = str;
+  auto str_copy = buffer;
   while (str_copy.size() >= 9) { // minimum length for a record is 10
     LMDBBackend::LMDBResourceRecord lrr;
-    auto rrLength = serOneRRFromString(str_copy, lrr);
-    lrrs.emplace_back(lrr);
+    auto rrLength = deserializeRRFromBuffer(str_copy, lrr);
+    value.emplace_back(lrr);
     str_copy.remove_prefix(rrLength);
   }
 }
@@ -1081,7 +1102,7 @@ bool LMDBBackend::feedRecord(const DNSResourceRecord& r, const DNSName& ordernam
     rrs = _rrs.get<string>();
   }
 
-  rrs += serToString(lrr);
+  rrs += serializeToBuffer(lrr);
 
   d_rwtxn->txn->put(d_rwtxn->db->dbi, matchName, rrs);
 
@@ -1091,12 +1112,12 @@ bool LMDBBackend::feedRecord(const DNSResourceRecord& r, const DNSName& ordernam
       lrr.ttl = 0;
       lrr.content = lrr.qname.toDNSStringLC();
       lrr.auth = 0;
-      string ser = serToString(lrr);
+      string ser = serializeToBuffer(lrr);
       d_rwtxn->txn->put(d_rwtxn->db->dbi, co(lrr.domain_id, ordername, QType::NSEC3), ser);
 
       lrr.ttl = 1;
       lrr.content = ordername.toDNSString();
-      ser = serToString(lrr);
+      ser = serializeToBuffer(lrr);
       d_rwtxn->txn->put(d_rwtxn->db->dbi, co(lrr.domain_id, lrr.qname, QType::NSEC3), ser);
     }
   }
@@ -1113,7 +1134,7 @@ bool LMDBBackend::feedEnts(int domain_id, map<DNSName, bool>& nonterm)
     lrr.auth = nt.second;
     lrr.ordername = true;
 
-    std::string ser = serToString(lrr);
+    std::string ser = serializeToBuffer(lrr);
     d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::ENT), ser);
   }
   return true;
@@ -1130,21 +1151,21 @@ bool LMDBBackend::feedEnts3(int domain_id, const DNSName& domain, map<DNSName, b
     lrr.ttl = 0;
     lrr.auth = nt.second;
     lrr.ordername = nt.second;
-    ser = serToString(lrr);
+    ser = serializeToBuffer(lrr);
     d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::ENT), ser);
 
     if (!narrow && lrr.auth) {
       lrr.content = lrr.qname.toDNSString();
       lrr.auth = false;
       lrr.ordername = false;
-      ser = serToString(lrr);
+      ser = serializeToBuffer(lrr);
 
       ordername = DNSName(toBase32Hex(hashQNameWithSalt(ns3prc, nt.first)));
       d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, ordername, QType::NSEC3), ser);
 
       lrr.ttl = 1;
       lrr.content = ordername.toDNSString();
-      ser = serToString(lrr);
+      ser = serializeToBuffer(lrr);
       d_rwtxn->txn->put(d_rwtxn->db->dbi, co(domain_id, lrr.qname, QType::NSEC3), ser);
     }
   }
@@ -1189,7 +1210,7 @@ bool LMDBBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const Q
 
       adjustedRRSet.emplace_back(lrr);
     }
-    txn->txn->put(txn->db->dbi, match, serToString(adjustedRRSet));
+    txn->txn->put(txn->db->dbi, match, serializeToBuffer(adjustedRRSet));
   }
 
   if (needCommit)
@@ -1320,7 +1341,7 @@ bool LMDBBackend::deleteDomain(const DNSName& domain)
 
   abortTransaction();
 
-  LMDBIDvec idvec;
+  LmdbIdVec idvec;
 
   if (!d_handle_dups) {
     // get domain id
@@ -1345,7 +1366,7 @@ bool LMDBBackend::deleteDomain(const DNSName& domain)
 
     { // Remove metadata
       auto txn = d_tmeta->getRWTransaction();
-      LMDBIDvec ids;
+      LmdbIdVec ids;
 
       txn.get_multi<0>(domain, ids);
 
@@ -1358,7 +1379,7 @@ bool LMDBBackend::deleteDomain(const DNSName& domain)
 
     { // Remove cryptokeys
       auto txn = d_tkdb->getRWTransaction();
-      LMDBIDvec ids;
+      LmdbIdVec ids;
       txn.get_multi<0>(domain, ids);
 
       for (auto _id : ids) {
@@ -1515,7 +1536,7 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
         continue;
       }
 
-      serFromString(d_currentVal.get<string_view>(), d_currentrrset);
+      deserializeFromBuffer(d_currentVal.get<string_view>(), d_currentrrset);
       d_currentrrsetpos = 0;
     }
     else {
@@ -1581,7 +1602,7 @@ bool LMDBBackend::getSerial(DomainInfo& di)
   MDBOutVal val;
   if (!txn->txn->get(txn->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
     LMDBResourceRecord lrr;
-    serFromString(val.get<string_view>(), lrr);
+    deserializeFromBuffer(val.get<string_view>(), lrr);
     if (lrr.content.size() >= 5 * sizeof(uint32_t)) {
       uint32_t serial;
       // a SOA has five 32 bit fields, the first of which is the serial
@@ -1779,7 +1800,7 @@ void LMDBBackend::getUnfreshSecondaryInfos(vector<DomainInfo>* domains)
     compoundOrdername co;
     MDBOutVal val;
     if (!txn2->txn->get(txn2->db->dbi, co(di.id, g_rootdnsname, QType::SOA), val)) {
-      serFromString(val.get<string_view>(), lrr);
+      deserializeFromBuffer(val.get<string_view>(), lrr);
       memcpy(&st, &lrr.content[lrr.content.size() - sizeof(soatimes)], sizeof(soatimes));
       if ((time_t)(di.last_check + ntohl(st.refresh)) > now) { // still fresh
         return false;
@@ -1902,7 +1923,7 @@ bool LMDBBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string
 {
   meta.clear();
   auto txn = d_tmeta->getROTransaction();
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   DomainMeta dm;
@@ -1919,7 +1940,7 @@ bool LMDBBackend::setDomainMetadata(const DNSName& name, const std::string& kind
 {
   auto txn = d_tmeta->getRWTransaction();
 
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   DomainMeta dmeta;
@@ -1943,7 +1964,7 @@ bool LMDBBackend::setDomainMetadata(const DNSName& name, const std::string& kind
 bool LMDBBackend::getDomainKeys(const DNSName& name, std::vector<KeyData>& keys)
 {
   auto txn = d_tkdb->getROTransaction();
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   KeyDataDB key;
@@ -2080,13 +2101,13 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
 
     for (;;) {
       if (co.getDomainID(key.getNoStripHeader<StringView>()) != id) {
-        //cout<<"Last record also not part of this zone!"<<endl;
-        // this implies something is wrong in the database, nothing we can do
+        // cout<<"Last record also not part of this zone!"<<endl;
+        //  this implies something is wrong in the database, nothing we can do
         return false;
       }
 
       if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-        serFromString(val.get<StringView>(), lrr);
+        deserializeFromBuffer(val.get<StringView>(), lrr);
         if (!lrr.ttl) // the kind of NSEC3 we need
           break;
       }
@@ -2105,7 +2126,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
     }
     for (;;) {
       if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-        serFromString(val.get<StringView>(), lrr);
+        deserializeFromBuffer(val.get<StringView>(), lrr);
         if (!lrr.ttl)
           break;
       }
@@ -2136,7 +2157,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
       }
       for (;;) {
         if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-          serFromString(val.get<StringView>(), lrr);
+          deserializeFromBuffer(val.get<StringView>(), lrr);
           if (!lrr.ttl)
             break;
         }
@@ -2159,7 +2180,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
         // cout<<"Potentially stopping traverse at "<< co.getQName(key.get<StringView>()) <<", " << (co.getQName(key.get<StringView>()).canonCompare(qname))<<endl;
         // cout<<"qname = "<<qname<<endl;
         // cout<<"here  = "<<co.getQName(key.get<StringView>())<<endl;
-        serFromString(val.get<StringView>(), lrr);
+        deserializeFromBuffer(val.get<StringView>(), lrr);
         if (!lrr.ttl)
           break;
       }
@@ -2178,13 +2199,13 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
 
         for (;;) {
           if (co.getDomainID(key.getNoStripHeader<StringView>()) != id) {
-            //cout<<"Last record also not part of this zone!"<<endl;
-            // this implies something is wrong in the database, nothing we can do
+            // cout<<"Last record also not part of this zone!"<<endl;
+            //  this implies something is wrong in the database, nothing we can do
             return false;
           }
 
           if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-            serFromString(val.get<StringView>(), lrr);
+            deserializeFromBuffer(val.get<StringView>(), lrr);
             if (!lrr.ttl) // the kind of NSEC3 we need
               break;
           }
@@ -2205,7 +2226,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
         }
         for (;;) {
           if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-            serFromString(val.get<StringView>(), lrr);
+            deserializeFromBuffer(val.get<StringView>(), lrr);
             if (!lrr.ttl)
               break;
           }
@@ -2241,7 +2262,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
       }
       for (;;) {
         if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-          serFromString(val.get<StringView>(), lrr);
+          deserializeFromBuffer(val.get<StringView>(), lrr);
           if (!lrr.ttl)
             break;
         }
@@ -2261,7 +2282,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qna
 
     // cout<<"After "<<co.getQName(key.get<StringView>()) <<endl;
     if (co.getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-      serFromString(val.get<StringView>(), lrr);
+      deserializeFromBuffer(val.get<StringView>(), lrr);
       if (!lrr.ttl) {
         break;
       }
@@ -2309,7 +2330,7 @@ bool LMDBBackend::getBeforeAndAfterNames(uint32_t id, const DNSName& zonenameU,
       if (co.getDomainID(key.getNoStripHeader<string_view>()) == id && key.getNoStripHeader<StringView>().rfind(matchkey, 0) == 0)
         continue;
       LMDBResourceRecord lrr;
-      serFromString(val.get<StringView>(), lrr);
+      deserializeFromBuffer(val.get<StringView>(), lrr);
       if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS))
         break;
     }
@@ -2340,7 +2361,7 @@ bool LMDBBackend::getBeforeAndAfterNames(uint32_t id, const DNSName& zonenameU,
         return false;
       }
       LMDBResourceRecord lrr;
-      serFromString(val.get<StringView>(), lrr);
+      deserializeFromBuffer(val.get<StringView>(), lrr);
       if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS))
         break;
     }
@@ -2355,7 +2376,7 @@ bool LMDBBackend::getBeforeAndAfterNames(uint32_t id, const DNSName& zonenameU,
   int skips = 0;
   for (;;) {
     LMDBResourceRecord lrr;
-    serFromString(val.get<StringView>(), lrr);
+    deserializeFromBuffer(val.get<StringView>(), lrr);
     if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()).getCode() == QType::NS)) {
       after = co.getQName(key.getNoStripHeader<string_view>()) + zonename;
       // cout <<"Found auth ("<<lrr.auth<<") or an NS record "<<after<<", type: "<<co.getQType(key.getNoStripHeader<string_view>()).toString()<<", ttl = "<<lrr.ttl<<endl;
@@ -2385,7 +2406,7 @@ bool LMDBBackend::getBeforeAndAfterNames(uint32_t id, const DNSName& zonenameU,
     }
     before = co.getQName(key.getNoStripHeader<string_view>()) + zonename;
     LMDBResourceRecord lrr;
-    serFromString(val.get<string_view>(), lrr);
+    deserializeFromBuffer(val.get<string_view>(), lrr);
     // cout<<"And before to "<<before<<", auth = "<<rr.auth<<endl;
     if (co.getQType(key.getNoStripHeader<string_view>()).getCode() && (lrr.auth || co.getQType(key.getNoStripHeader<string_view>()) == QType::NS))
       break;
@@ -2435,7 +2456,7 @@ bool LMDBBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName
     vector<LMDBResourceRecord> lrrs;
 
     if (co.getQType(key.getNoStripHeader<StringView>()) != QType::NSEC3) {
-      serFromString(val.get<StringView>(), lrrs);
+      deserializeFromBuffer(val.get<StringView>(), lrrs);
       bool changed = false;
       vector<LMDBResourceRecord> newRRs;
       for (auto& lrr : lrrs) {
@@ -2452,7 +2473,7 @@ bool LMDBBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName
         newRRs.push_back(std::move(lrr));
       }
       if (changed) {
-        cursor.put(key, serToString(newRRs));
+        cursor.put(key, serializeToBuffer(newRRs));
       }
     }
 
@@ -2466,7 +2487,7 @@ bool LMDBBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName
   // cerr<<"here qname="<<qname<<" ordername="<<ordername<<" qtype="<<qtype<<" matchkey="<<makeHexDump(matchkey)<<endl;
   int txngetrc;
   if (!(txngetrc = txn->txn->get(txn->db->dbi, matchkey, val))) {
-    serFromString(val.get<string_view>(), lrr);
+    deserializeFromBuffer(val.get<string_view>(), lrr);
 
     if (needNSEC3) {
       if (hasOrderName && lrr.content != ordername.toDNSStringLC()) {
@@ -2492,11 +2513,11 @@ bool LMDBBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName
     lrr.auth = 0;
     lrr.content = rel.toDNSStringLC();
 
-    string str = serToString(lrr);
+    string str = serializeToBuffer(lrr);
     txn->txn->put(txn->db->dbi, co(domain_id, ordername, QType::NSEC3), str);
     lrr.ttl = 1;
     lrr.content = ordername.toDNSStringLC();
-    str = serToString(lrr);
+    str = serializeToBuffer(lrr);
     txn->txn->put(txn->db->dbi, matchkey, str); // 2
   }
 
@@ -2539,7 +2560,7 @@ bool LMDBBackend::updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& inse
       lrr.ttl = 0;
       lrr.auth = true;
 
-      std::string ser = serToString(lrr);
+      std::string ser = serializeToBuffer(lrr);
 
       txn->txn->put(txn->db->dbi, co(domain_id, lrr.qname, 0), ser);
 
@@ -2560,7 +2581,7 @@ bool LMDBBackend::updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& inse
 bool LMDBBackend::getTSIGKey(const DNSName& name, DNSName& algorithm, string& content)
 {
   auto txn = d_ttsig->getROTransaction();
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   TSIGKey key;
@@ -2581,7 +2602,7 @@ bool LMDBBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, cons
 {
   auto txn = d_ttsig->getRWTransaction();
 
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   TSIGKey key;
@@ -2607,7 +2628,7 @@ bool LMDBBackend::deleteTSIGKey(const DNSName& name)
 {
   auto txn = d_ttsig->getRWTransaction();
 
-  LMDBIDvec ids;
+  LmdbIdVec ids;
   txn.get_multi<0>(name, ids);
 
   TSIGKey key;
@@ -2691,7 +2712,7 @@ string LMDBBackend::directBackendCmd(const string& query)
 
           auto id = iter.getID();
 
-          LMDBIDvec ids;
+          LmdbIdVec ids;
           txn.get_multi<0>(di.zone, ids);
 
           if (ids.size() != 1) {
index 40f18f8fb3bd9df2e26edbeac894665000b6c4b3..70a712bf7864175b6ad1f60b147497916249521f 100644 (file)
@@ -30,7 +30,6 @@ std::string keyConv(const T& t)
   /* www.ds9a.nl -> nl0ds9a0www0
      root -> 0   <- we need this to keep lmdb happy
      nl -> nl0
-     
   */
   if (t.empty()) {
     throw std::out_of_range(std::string(__PRETTY_FUNCTION__) + " Attempt to serialize an unset dnsname");
index 45227416a9c3d508d2069abbe34ea3c0cac1c671..a53ef2948894a906a149ec340d220839ce47fe3d 100644 (file)
@@ -6,4 +6,4 @@ module_extras = files(
   'lmdbbackend.hh',
 )
 
-module_deps = [deps, dep_lmdb_safe, dep_lmdb, dep_boost_serialization]
+module_deps = [deps, dep_lmdb_safe, dep_lmdb, dep_boost_serialization, dep_systemd]
index 8f5683e3b20fc3346dcf7b79d3ec5294477a00ab..857fb1782c4a6073996a2d44109849e951999c3e 100644 (file)
@@ -24,6 +24,9 @@
 #include "boost/algorithm/string/join.hpp"
 #include "pdns/arguments.hh"
 
+#include "pdns/dnsbackend.hh"
+#include "pdns/lua-auth4.hh"
+
 class Lua2BackendAPIv2 : public DNSBackend, AuthLua4
 {
 private:
@@ -65,6 +68,7 @@ private:
 public:
   Lua2BackendAPIv2(const string& suffix)
   {
+    d_include_path = ::arg()["lua-global-include-dir"];
     setArgPrefix("lua2" + suffix);
     d_debug_log = mustDo("query-logging");
     prepareContext();
index bc22195e09d3d5e7756f301e622f40912028c2af..acff9dfb7c0dcb7b52dc9887c93cc4639eab7b9e 100644 (file)
@@ -95,14 +95,12 @@ std::string HTTPConnector::buildMemberListArgs(const std::string& prefix, const
   std::stringstream stream;
 
   for (const auto& pair : args.object_items()) {
+    stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=";
     if (pair.second.is_bool()) {
       stream << (pair.second.bool_value() ? "1" : "0");
     }
-    else if (pair.second.is_null()) {
-      stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=";
-    }
-    else {
-      stream << prefix << "[" << YaHTTP::Utility::encodeURL(pair.first, false) << "]=" << YaHTTP::Utility::encodeURL(HTTPConnector::asString(pair.second), false);
+    else if (!pair.second.is_null()) {
+      stream << YaHTTP::Utility::encodeURL(HTTPConnector::asString(pair.second), false);
     }
     stream << "&";
   }
@@ -183,9 +181,9 @@ void HTTPConnector::restful_requestbuilder(const std::string& method, const Json
   else if (method == "replaceRRSet") {
     std::stringstream ss2;
     for (size_t index = 0; index < parameters["rrset"].array_items().size(); index++) {
-      ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]);
+      ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]) << "&";
     }
-    req.body = ss2.str();
+    req.body = ss2.str().substr(0, ss2.str().size() - 1); // remove trailing &
     req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
     req.headers["content-length"] = std::to_string(req.body.size());
     verb = "PATCH";
@@ -433,23 +431,19 @@ int HTTPConnector::recv_message(Json& output)
   if (d_socket == nullptr) {
     return -1; // cannot receive :(
   }
-  char buffer[4096];
-  int rd = -1;
-  time_t t0 = 0;
+  std::array<char, 4096> buffer{};
+  time_t time0 = 0;
 
   arl.initialize(&resp);
 
   try {
-    t0 = time((time_t*)nullptr);
-    while (!arl.ready() && (labs(time((time_t*)nullptr) - t0) <= timeout)) {
-      rd = d_socket->readWithTimeout(buffer, sizeof(buffer), timeout);
-      if (rd == 0) {
+    time0 = time(nullptr);
+    while (!arl.ready() && (labs(time(nullptr) - time0) <= timeout)) {
+      auto readBytes = d_socket->readWithTimeout(buffer.data(), buffer.size(), timeout);
+      if (readBytes == 0) {
         throw NetworkError("EOF while reading");
       }
-      if (rd < 0) {
-        throw NetworkError(std::string(strerror(rd)));
-      }
-      arl.feed(std::string(buffer, rd));
+      arl.feed(std::string(buffer.data(), readBytes));
     }
     // timeout occurred.
     if (!arl.ready()) {
@@ -472,13 +466,12 @@ int HTTPConnector::recv_message(Json& output)
     throw PDNSException("Received unacceptable HTTP status code " + std::to_string(resp.status) + " from HTTP endpoint " + d_addr.toStringWithPort());
   }
 
-  int rv = -1;
   std::string err;
   output = Json::parse(resp.body, err);
   if (output != nullptr) {
-    return resp.body.size();
+    return static_cast<int>(resp.body.size());
   }
   g_log << Logger::Error << "Cannot parse JSON reply: " << err << endl;
 
-  return rv;
+  return -1;
 }
index bee1d58ef06d9ef2bf07f4dd03bf6c1ab84a515a..2522839a0f3cbbb4a8d016828e1b6c2931bba5d2 100644 (file)
@@ -145,11 +145,9 @@ bin_PROGRAMS += \
 
 bin_PROGRAMS += calidns
 
-if HAVE_BOOST_GE_148
 bin_PROGRAMS += \
        dnsbulktest \
        dnstcpbench
-endif
 
 endif # TOOLS
 
@@ -1533,13 +1531,8 @@ noinst_PROGRAMS = speedtest
 
 if UNIT_TESTS
 noinst_PROGRAMS += testrunner
-if HAVE_BOOST_GE_148
 TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message BOOST_TEST_RANDOM=1 SRCDIR='$(srcdir)'
 TESTS=testrunner
-else
-check-local:
-       @echo "Unit tests disabled, boost is too old"
-endif
 
 else
 check-local:
diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md
deleted file mode 100644 (file)
index f8e67cb..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# dnsdist
-`dnsdist` is a highly DNS-, DoS- and abuse-aware loadbalancer. Its goal in
-life is to route traffic to the best server, delivering top performance
-to legitimate users while shunting or blocking abusive traffic.
-
-`dnsdist` is dynamic, in the sense that its configuration can be changed at
-runtime, and that its statistics can be queried from a console-like
-interface.
-
-All `dnsdist` features are documented at [dnsdist.org](https://dnsdist.org).
-
-## Compiling from git
-
-Make sure to `autoreconf -vi` before running `configure`.
-
-## macOS Notes
-
-Install dependencies from Homebrew:
-
-```sh
-brew install autoconf automake boost libedit libsodium libtool lua pkg-config protobuf
-```
-
-Let configure know where to find libedit, and openssl or libressl:
-
-```sh
-./configure 'PKG_CONFIG_PATH=/usr/local/opt/libedit/lib/pkgconfig:/usr/local/opt/libressl/lib/pkgconfig'
-make
-```
index fc42d07db8f951fe8f57afe02debadb2b5bcafbd..72e05c9e6e7fd0b92b10172d6f8fad79468c4512 100644 (file)
@@ -205,6 +205,7 @@ static void declareArguments()
   ::arg().set("receiver-threads", "Default number of receiver threads to start") = "1";
   ::arg().set("queue-limit", "Maximum number of milliseconds to queue a query") = "1500";
   ::arg().set("resolver", "Use this resolver for ALIAS and the internal stub resolver") = "no";
+  ::arg().set("dnsproxy-udp-port-range", "Select DNS Proxy outgoing UDP port from given range (lower upper)") = "10000 60000";
   ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232";
 
   ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = "";
@@ -244,6 +245,7 @@ static void declareArguments()
   ::arg().set("webserver-allow-from", "Webserver/API access is only allowed from these subnets") = "127.0.0.1,::1";
   ::arg().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal";
   ::arg().set("webserver-max-bodysize", "Webserver/API maximum request/response body size in megabytes") = "2";
+  ::arg().set("webserver-connection-timeout", "Webserver/API request/response timeout in seconds") = "5";
   ::arg().setSwitch("webserver-hash-plaintext-credentials", "Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime") = "no";
 
   ::arg().setSwitch("query-logging", "Hint backends that queries should be logged") = "no";
@@ -290,6 +292,7 @@ static void declareArguments()
 
   ::arg().set("lua-prequery-script", "Lua script with prequery handler (DO NOT USE)") = "";
   ::arg().set("lua-dnsupdate-policy-script", "Lua script with DNS update policy handler") = "";
+  ::arg().set("lua-global-include-dir", "Include *.lua files from this directory into Lua contexts") = "";
 
   ::arg().setSwitch("traceback-handler", "Enable the traceback handler (Linux only)") = "yes";
   ::arg().setSwitch("direct-dnskey", "Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis") = "no";
@@ -784,7 +787,7 @@ static void mainthread()
   Utility::dropUserPrivs(newuid);
 
   if (::arg().mustDo("resolver")) {
-    DP = std::make_unique<DNSProxy>(::arg()["resolver"]);
+    DP = std::make_unique<DNSProxy>(::arg()["resolver"], ::arg()["dnsproxy-udp-port-range"]);
     DP->go();
   }
 
@@ -1201,6 +1204,7 @@ static void sigTermHandler([[maybe_unused]] int signal)
 #endif /* COVERAGE */
 
 //! The main function of pdns, the pdns process
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
 int main(int argc, char** argv)
 {
   versionSetProduct(ProductAuthoritative);
@@ -1225,8 +1229,8 @@ int main(int argc, char** argv)
     ::arg().laxParse(argc, argv); // do a lax parse
 
     if (::arg().mustDo("version")) {
-      showProductVersion();
-      showBuildConfiguration();
+      cout << getProductVersion();
+      cout << getBuildConfiguration();
       return 0;
     }
 
@@ -1500,7 +1504,9 @@ int main(int argc, char** argv)
 
   DLOG(g_log << Logger::Warning << "Verbose logging in effect" << endl);
 
-  showProductVersion();
+  for (const string& line : getProductVersionLines()) {
+    g_log << Logger::Info << line << endl;
+  }
 
   try {
     mainthread();
index 9f21e81256b6cbe17f20eccd59fe8f710db40e6a..ae9a54243712f824a5243af3850d331cce5a6eec 100644 (file)
@@ -639,7 +639,7 @@ static vector<DNSResourceRecord> doAxfr(const ComboAddress& raddr, const DNSName
   return rrs;
 }
 
-void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote, bool force)
+void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote, bool force) // NOLINT(readability-function-cognitive-complexity)
 {
   {
     auto data = d_data.lock();
@@ -700,7 +700,7 @@ void CommunicatorClass::suck(const DNSName& domain, const ComboAddress& remote,
     }
     if (!script.empty()) {
       try {
-        pdl = make_unique<AuthLua4>();
+        pdl = make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
         pdl->loadFile(script);
         g_log << Logger::Info << logPrefix << "loaded Lua script '" << script << "'" << endl;
       }
index f2630c9aebf47139e20e92ef42c533c21c84229b..6b87f5bd968f1437e618aeccd619f176d98b3b33 100644 (file)
@@ -148,9 +148,11 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records, ui
     err = parseResult(mdp, DNSName(), 0, 0, &res);
 
     if (!err) {
-      for(const auto& answer :  mdp.d_answers)
-        if (answer.first.d_type == QType::SOA)
+      for(const auto& answer :  mdp.d_answers) {
+        if (answer.d_type == QType::SOA) {
           d_soacount++;
+        }
+      }
     }
   }
   else {
@@ -158,11 +160,11 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records, ui
     records->reserve(mdp.d_answers.size());
 
     for(auto& r: mdp.d_answers) {
-      if (r.first.d_type == QType::SOA) {
+      if (r.d_type == QType::SOA) {
         d_soacount++;
       }
 
-      records->push_back(std::move(r.first));
+      records->push_back(std::move(r));
     }
   }
 
@@ -171,23 +173,31 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records, ui
 
 void AXFRRetriever::timeoutReadn(uint16_t bytes, uint16_t timeoutsec)
 {
-  time_t start=time(nullptr);
-  int n=0;
-  int numread;
-  while(n<bytes) {
+  const time_t start = time(nullptr);
+  uint16_t bytesRead = 0;
+
+  while (bytesRead < bytes) {
     // coverity[store_truncates_time_t]
-    int res=waitForData(d_sock, static_cast<int>(timeoutsec - (time(nullptr) - start)));
-    if(res<0)
-      throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
-    if(!res)
+    auto elapsed = time(nullptr) - start;
+    if (elapsed > timeoutsec) {
+      throw ResolverException("Timeout while reading data from remote nameserver over TCP");
+    }
+    auto res = waitForData(d_sock, static_cast<int>(timeoutsec - elapsed));
+    if (res < 0) {
+      throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
+    }
+    if (res == 0) {
       throw ResolverException("Timeout while reading data from remote nameserver over TCP");
+    }
 
-    numread=recv(d_sock, &d_buf.at(n), bytes-n, 0);
-    if(numread<0)
-      throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
-    if(numread==0)
+    auto received = recv(d_sock, &d_buf.at(bytesRead), bytes - bytesRead, 0);
+    if (received < 0) {
+      throw ResolverException("Reading data from remote nameserver over TCP: " + stringerror());
+    }
+    if (received == 0) {
       throw ResolverException("Remote nameserver closed TCP connection");
-    n+=numread;
+    }
+    bytesRead += static_cast<uint16_t>(received);
   }
 }
 
diff --git a/pdns/bpf-filter.cc b/pdns/bpf-filter.cc
deleted file mode 100644 (file)
index 4a12d9d..0000000
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "bpf-filter.hh"
-#include "iputils.hh"
-#include "dolog.hh"
-
-#ifdef HAVE_EBPF
-
-#include <sys/syscall.h>
-#include <sys/resource.h>
-#include <linux/bpf.h>
-
-#include "ext/libbpf/libbpf.h"
-
-#include "misc.hh"
-
-static __u64 ptr_to_u64(const void *ptr)
-{
-  return (__u64) (unsigned long) ptr;
-}
-
-/* these can be static as they are not declared in libbpf.h: */
-static int bpf_pin_map(int descriptor, const std::string& path)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.bpf_fd = descriptor;
-  attr.pathname = ptr_to_u64(path.c_str());
-  return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
-}
-
-static int bpf_load_pinned_map(const std::string& path)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.pathname = ptr_to_u64(path.c_str());
-  return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
-}
-
-static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize)
-{
-  struct bpf_map_info info;
-  uint32_t info_len = sizeof(info);
-  memset(&info, 0, sizeof(info));
-
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.info.bpf_fd = descriptor;
-  attr.info.info_len = info_len;
-  attr.info.info = ptr_to_u64(&info);
-
-  int err = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
-  if (err != 0) {
-    throw std::runtime_error("Error checking the size of eBPF map: " + stringerror());
-  }
-  if (info_len != sizeof(info)) {
-    throw std::runtime_error("Error checking the size of eBPF map: invalid info size returned");
-  }
-  if (info.key_size != expectedKeySize) {
-    throw std::runtime_error("Error checking the size of eBPF map: key size mismatch (" + std::to_string(info.key_size) + " VS " + std::to_string(expectedKeySize) + ")");
-  }
-  if (info.value_size != expectedValueSize) {
-    throw std::runtime_error("Error checking the size of eBPF map: value size mismatch (" + std::to_string(info.value_size) + " VS " + std::to_string(expectedValueSize) + ")");
-  }
-}
-
-// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
-static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
-                          int max_entries, int map_flags)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.map_type = map_type;
-  attr.key_size = key_size;
-  attr.value_size = value_size;
-  attr.max_entries = max_entries;
-  attr.map_flags = map_flags;
-  return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
-}
-
-static int bpf_update_elem(int descriptor, void *key, void *value, unsigned long long flags)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.map_fd = descriptor;
-  attr.key = ptr_to_u64(key);
-  attr.value = ptr_to_u64(value);
-  attr.flags = flags;
-  return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_lookup_elem(int descriptor, void *key, void *value)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.map_fd = descriptor;
-  attr.key = ptr_to_u64(key);
-  attr.value = ptr_to_u64(value);
-  return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_delete_elem(int descriptor, void *key)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.map_fd = descriptor;
-  attr.key = ptr_to_u64(key);
-  return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
-}
-
-static int bpf_get_next_key(int descriptor, void *key, void *next_key)
-{
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.map_fd = descriptor;
-  attr.key = ptr_to_u64(key);
-  attr.next_key = ptr_to_u64(next_key);
-  return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
-}
-
-static int bpf_prog_load(enum bpf_prog_type prog_type,
-                         const struct bpf_insn *insns, size_t prog_len,
-                         const char *license, int kern_version)
-{
-  char log_buf[65535];
-  union bpf_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.prog_type = prog_type;
-  attr.insns = ptr_to_u64((void *) insns);
-  attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn));
-  attr.license = ptr_to_u64((void *) license);
-  attr.log_buf = ptr_to_u64(log_buf);
-  attr.log_size = sizeof(log_buf);
-  attr.log_level = 1;
-  /* assign one field outside of struct init to make sure any
-   * padding is zero initialized
-   */
-  attr.kern_version = kern_version;
-
-  long res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
-  if (res == -1) {
-    if (errno == ENOSPC) {
-      /* not enough space in the log buffer */
-      attr.log_level = 0;
-      attr.log_size = 0;
-      attr.log_buf = ptr_to_u64(nullptr);
-      res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
-      if (res != -1) {
-        return res;
-      }
-    }
-    throw std::runtime_error("Error loading BPF program: (" + stringerror() + "):\n" + std::string(log_buf));
-  }
-  return res;
-}
-
-struct KeyV6
-{
-  uint8_t src[16];
-};
-
-struct QNameKey
-{
-  uint8_t qname[255];
-};
-
-struct QNameAndQTypeKey
-{
-  uint8_t qname[255];
-  uint16_t qtype;
-};
-
-struct QNameValue
-{
-  uint64_t counter{0};
-  uint16_t qtype{0};
-};
-
-
-BPFFilter::Map::Map(const BPFFilter::MapConfiguration& config, BPFFilter::MapFormat format): d_config(config)
-{
-  if (d_config.d_type == BPFFilter::MapType::Filters) {
-    /* special case, this is a map of eBPF programs */
-    d_fd = FDWrapper(bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), d_config.d_maxItems, 0));
-    if (d_fd.getHandle() == -1) {
-      throw std::runtime_error("Error creating a BPF program map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
-    }
-  }
-  else {
-    int keySize = 0;
-    int valueSize = 0;
-    int flags = 0;
-    bpf_map_type type = BPF_MAP_TYPE_HASH;
-    if (format == MapFormat::Legacy) {
-      switch (d_config.d_type) {
-      case MapType::IPv4:
-        keySize = sizeof(uint32_t);
-        valueSize = sizeof(uint64_t);
-        break;
-      case MapType::IPv6:
-        keySize = sizeof(KeyV6);
-        valueSize = sizeof(uint64_t);
-        break;
-      case MapType::QNames:
-        keySize = sizeof(QNameKey);
-        valueSize = sizeof(QNameValue);
-        break;
-      default:
-        throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)) + " for legacy eBPF, perhaps you are trying to use an external program instead?");
-      }
-    }
-    else {
-      switch (d_config.d_type) {
-      case MapType::IPv4:
-        keySize = sizeof(uint32_t);
-        valueSize = sizeof(CounterAndActionValue);
-        break;
-      case MapType::IPv6:
-        keySize = sizeof(KeyV6);
-        valueSize = sizeof(CounterAndActionValue);
-        break;
-      case MapType::CIDR4:
-        keySize = sizeof(CIDR4);
-        valueSize = sizeof(CounterAndActionValue);
-        flags = BPF_F_NO_PREALLOC;
-        type = BPF_MAP_TYPE_LPM_TRIE;
-        break;
-      case MapType::CIDR6:
-        keySize = sizeof(CIDR6);
-        valueSize = sizeof(CounterAndActionValue);
-        flags = BPF_F_NO_PREALLOC;
-        type = BPF_MAP_TYPE_LPM_TRIE;
-        break;
-      case MapType::QNames:
-        keySize = sizeof(QNameAndQTypeKey);
-        valueSize = sizeof(CounterAndActionValue);
-        break;
-      default:
-        throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
-      }
-    }
-
-    if (!d_config.d_pinnedPath.empty()) {
-      /* try to load */
-      d_fd = FDWrapper(bpf_load_pinned_map(d_config.d_pinnedPath));
-      if (d_fd.getHandle() != -1) {
-        /* sanity checks: key and value size */
-        bpf_check_map_sizes(d_fd.getHandle(), keySize, valueSize);
-        switch (d_config.d_type) {
-        case MapType::IPv4: {
-          uint32_t key = 0;
-          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-            ++d_count;
-          }
-          break;
-        }
-        case MapType::IPv6: {
-          KeyV6 key;
-          memset(&key, 0, sizeof(key));
-          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-            ++d_count;
-          }
-          break;
-        }
-        case MapType::CIDR4: {
-          CIDR4 key;
-          memset(&key, 0, sizeof(key));
-          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-            ++d_count;
-          }
-          break;
-        }
-        case MapType::CIDR6: {
-          CIDR6 key;
-          memset(&key, 0, sizeof(key));
-          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-            ++d_count;
-          }
-          break;
-        }
-        case MapType::QNames: {
-          if (format == MapFormat::Legacy) {
-            QNameKey key;
-            memset(&key, 0, sizeof(key));
-            while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-              ++d_count;
-            }
-          }
-          else {
-            QNameAndQTypeKey key;
-            memset(&key, 0, sizeof(key));
-            while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
-              ++d_count;
-            }
-          }
-          break;
-        }
-
-        default:
-          throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
-        }
-      }
-    }
-
-    if (d_fd.getHandle() == -1) {
-      d_fd = FDWrapper(bpf_create_map(type, keySize, valueSize, static_cast<int>(d_config.d_maxItems), flags));
-      if (d_fd.getHandle() == -1) {
-        throw std::runtime_error("Error creating a BPF map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
-      }
-
-      if (!d_config.d_pinnedPath.empty()) {
-        if (bpf_pin_map(d_fd.getHandle(), d_config.d_pinnedPath) != 0) {
-          throw std::runtime_error("Unable to pin map to path '" + d_config.d_pinnedPath + "': " + stringerror());
-        }
-      }
-    }
-  }
-}
-
-static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize)
-{
-  auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
-                                            filter,
-                                            filterSize,
-                                            "GPL",
-                                            0));
-  if (descriptor.getHandle() == -1) {
-    throw std::runtime_error("error loading BPF filter: " + stringerror());
-  }
-  return descriptor;
-}
-
-
-BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) :
-  d_mapFormat(format), d_external(external)
-{
-  if (d_mapFormat != BPFFilter::MapFormat::Legacy && !d_external) {
-    throw std::runtime_error("Unsupported eBPF map format, the current internal implemenation only supports the legacy format");
-  }
-
-  struct rlimit old_limit;
-  if (getrlimit(RLIMIT_MEMLOCK, &old_limit) != 0) {
-    throw std::runtime_error("Unable to get memory lock limit: " + stringerror());
-  }
-
-  const rlim_t new_limit_size = 1024 * 1024;
-
-  /* Check if the current soft memlock limit is at least the limit */
-  if (old_limit.rlim_cur < new_limit_size) {
-    infolog("The current limit of locked memory (soft: %d, hard: %d) is too low for eBPF, trying to raise it to %d", old_limit.rlim_cur, old_limit.rlim_max, new_limit_size);
-
-    struct rlimit new_limit;
-    new_limit.rlim_cur = new_limit_size;
-    new_limit.rlim_max = new_limit_size;
-
-    if (setrlimit(RLIMIT_MEMLOCK, &new_limit) != 0) {
-      warnlog("Unable to raise the maximum amount of locked memory for eBPF from %d to %d, consider raising RLIMIT_MEMLOCK or setting LimitMEMLOCK in the systemd unit: %d", old_limit.rlim_cur, new_limit.rlim_cur, stringerror());
-    }
-  }
-
-  auto maps = d_maps.lock();
-
-  maps->d_v4 = BPFFilter::Map(configs["ipv4"], d_mapFormat);
-  maps->d_v6 = BPFFilter::Map(configs["ipv6"], d_mapFormat);
-  maps->d_qnames = BPFFilter::Map(configs["qnames"], d_mapFormat);
-
-  if (d_mapFormat != BPFFilter::MapFormat::Legacy) {
-    maps->d_cidr4 = BPFFilter::Map(configs["cidr4"], d_mapFormat);
-    maps->d_cidr6 = BPFFilter::Map(configs["cidr6"], d_mapFormat);
-  }
-
-  if (!external) {
-    BPFFilter::MapConfiguration filters;
-    filters.d_maxItems = 1;
-    filters.d_type = BPFFilter::MapType::Filters;
-    maps->d_filters = BPFFilter::Map(filters, d_mapFormat);
-
-    const struct bpf_insn main_filter[] = {
-#include "bpf-filter.main.ebpf"
-    };
-
-    const struct bpf_insn qname_filter[] = {
-#include "bpf-filter.qname.ebpf"
-    };
-
-    try {
-      d_mainfilter = loadProgram(main_filter,
-                                 sizeof(main_filter));
-    }
-    catch (const std::exception& e) {
-      throw std::runtime_error("Error load the main eBPF filter: " + std::string(e.what()));
-    }
-
-    try {
-      d_qnamefilter = loadProgram(qname_filter,
-                                  sizeof(qname_filter));
-    }
-    catch (const std::exception& e) {
-      throw std::runtime_error("Error load the qname eBPF filter: " + std::string(e.what()));
-    }
-
-    uint32_t key = 0;
-    int qnamefd = d_qnamefilter.getHandle();
-    int res = bpf_update_elem(maps->d_filters.d_fd.getHandle(), &key, &qnamefd, BPF_ANY);
-    if (res != 0) {
-      throw std::runtime_error("Error updating BPF filters map: " + stringerror());
-    }
-  }
-}
-
-void BPFFilter::addSocket(int sock)
-{
-  int descriptor = d_mainfilter.getHandle();
-  int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor));
-
-  if (res != 0) {
-    throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror());
-  }
-}
-
-void BPFFilter::removeSocket(int sock)
-{
-  int descriptor = d_mainfilter.getHandle();
-  int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor));
-
-  if (res != 0) {
-    throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror());
-  }
-}
-
-void BPFFilter::block(const ComboAddress& addr, BPFFilter::MatchAction action)
-{
-  CounterAndActionValue value;
-  value.counter = 0;
-  value.action = action;
-
-  int res = 0;
-  if (addr.isIPv4()) {
-    uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v4;
-    if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to block " + addr.toString());
-    }
-
-    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (res != -1) {
-      throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
-    }
-
-    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
-    if (res == 0) {
-      ++map.d_count;
-    }
-  }
-  else if (addr.isIPv6()) {
-    uint8_t key[16];
-    static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
-    for (size_t idx = 0; idx < sizeof(key); idx++) {
-      key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
-    }
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v6;
-    if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to block " + addr.toString());
-    }
-
-    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (res != -1) {
-      throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
-    }
-
-    res = bpf_update_elem(map.d_fd.getHandle(), key, &value, BPF_NOEXIST);
-    if (res == 0) {
-      map.d_count++;
-    }
-  }
-
-  if (res != 0) {
-    throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror());
-  }
-}
-
-void BPFFilter::unblock(const ComboAddress& addr)
-{
-  int res = 0;
-  if (addr.isIPv4()) {
-    uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v4;
-    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
-    if (res == 0) {
-      --map.d_count;
-    }
-  }
-  else if (addr.isIPv6()) {
-    uint8_t key[16];
-    static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
-    for (size_t idx = 0; idx < sizeof(key); idx++) {
-      key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
-    }
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v6;
-    res = bpf_delete_elem(map.d_fd.getHandle(), key);
-    if (res == 0) {
-      --map.d_count;
-    }
-  }
-
-  if (res != 0) {
-    throw std::runtime_error("Error removing blocked address " + addr.toString() + ": " + stringerror());
-  }
-}
-
-void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
-{
-  CounterAndActionValue value;
-
-  int res = 0;
-  if (addr.isIPv4()) {
-    CIDR4 key(addr);
-    auto maps = d_maps.lock();
-    auto& map = maps->d_cidr4;
-    if (map.d_fd.getHandle() == -1) {
-      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
-    }
-    if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
-    }
-
-    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
-      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
-    }
-
-    value.counter = 0;
-    value.action = action;
-
-    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, force ? BPF_ANY : BPF_NOEXIST);
-    if (res == 0) {
-      ++map.d_count;
-    }
-  }
-  else if (addr.isIPv6()) {
-    CIDR6 key(addr);
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_cidr6;
-    if (map.d_fd.getHandle() == -1) {
-      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
-    }
-    if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
-    }
-
-    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
-    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
-      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
-    }
-
-    value.counter = 0;
-    value.action = action;
-
-    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
-    if (res == 0) {
-      map.d_count++;
-    }
-  }
-
-  if (res != 0) {
-    throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror());
-  }
-}
-
-void BPFFilter::rmRangeRule(const Netmask& addr)
-{
-  int res = 0;
-  CounterAndActionValue value;
-  value.counter = 0;
-  value.action = MatchAction::Pass;
-  if (addr.isIPv4()) {
-    CIDR4 key(addr);
-    auto maps = d_maps.lock();
-    auto& map = maps->d_cidr4;
-    if (map.d_fd.getHandle() == -1) {
-      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
-    }
-    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
-    if (res == 0) {
-      --map.d_count;
-    }
-    else {
-      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
-    }
-  }
-  else if (addr.isIPv6()) {
-    CIDR6 key(addr);
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_cidr6;
-    if (map.d_fd.getHandle() == -1) {
-      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
-    }
-    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
-    if (res == 0) {
-      --map.d_count;
-    }
-    else {
-      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
-    }
-  }
-
-  if (res != 0) {
-    throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror());
-  }
-}
-
-void BPFFilter::block(const DNSName& qname, BPFFilter::MatchAction action, uint16_t qtype)
-{
-  CounterAndActionValue cadvalue;
-  QNameValue qvalue;
-  void* value = nullptr;
-
-  if (d_external) {
-    cadvalue.counter = 0;
-    cadvalue.action = action;
-    value = &cadvalue;
-  }
-  else {
-    qvalue.counter = 0;
-    qvalue.qtype = qtype;
-    value = &qvalue;
-  }
-
-  QNameAndQTypeKey key;
-  memset(&key, 0, sizeof(key));
-
-  std::string keyStr = qname.toDNSStringLC();
-  if (keyStr.size() > sizeof(key.qname)) {
-    throw std::runtime_error("Invalid QName to block " + qname.toLogString());
-  }
-  memcpy(key.qname, keyStr.c_str(), keyStr.size());
-  key.qtype = qtype;
-
-  {
-    auto maps = d_maps.lock();
-    auto& map = maps->d_qnames;
-    if (map.d_count >= map.d_config.d_maxItems) {
-      throw std::runtime_error("Table full when trying to block " + qname.toLogString());
-    }
-
-    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, value);
-    if (res != -1) {
-      throw std::runtime_error("Trying to block an already blocked qname: " + qname.toLogString());
-    }
-    res = bpf_update_elem(map.d_fd.getHandle(), &key, value, BPF_NOEXIST);
-    if (res == 0) {
-      ++map.d_count;
-    }
-
-    if (res != 0) {
-      throw std::runtime_error("Error adding blocked qname " + qname.toLogString() + ": " + stringerror());
-    }
-  }
-}
-
-void BPFFilter::unblock(const DNSName& qname, uint16_t qtype)
-{
-  QNameAndQTypeKey key;
-  memset(&key, 0, sizeof(key));
-  std::string keyStr = qname.toDNSStringLC();
-
-  if (keyStr.size() > sizeof(key.qname)) {
-    throw std::runtime_error("Invalid QName to block " + qname.toLogString());
-  }
-  memcpy(key.qname, keyStr.c_str(), keyStr.size());
-  key.qtype = qtype;
-
-  {
-    auto maps = d_maps.lock();
-    auto& map = maps->d_qnames;
-    int res = bpf_delete_elem(map.d_fd.getHandle(), &key);
-    if (res == 0) {
-      --map.d_count;
-    }
-    else {
-      throw std::runtime_error("Error removing qname address " + qname.toLogString() + ": " + stringerror());
-    }
-  }
-}
-
-std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
-{
-  std::vector<std::pair<ComboAddress, uint64_t> > result;
-  {
-    auto maps = d_maps.lock();
-    result.reserve(maps->d_v4.d_count + maps->d_v6.d_count);
-  }
-
-  sockaddr_in v4Addr{};
-  memset(&v4Addr, 0, sizeof(v4Addr));
-  v4Addr.sin_family = AF_INET;
-
-  uint32_t v4Key = 0;
-  uint32_t nextV4Key{};
-  CounterAndActionValue value{};
-
-  std::array<uint8_t, 16> v6Key{};
-  std::array<uint8_t, 16> nextV6Key{};
-  sockaddr_in6 v6Addr{};
-  memset(&v6Addr, 0, sizeof(v6Addr));
-  v6Addr.sin6_family = AF_INET6;
-
-  static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t");
-  memset(&v6Key, 0, sizeof(v6Key));
-
-  auto maps = d_maps.lock();
-
-  {
-    auto& map = maps->d_v4;
-    int res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
-
-    while (res == 0) {
-      v4Key = nextV4Key;
-      if (bpf_lookup_elem(map.d_fd.getHandle(), &v4Key, &value) == 0) {
-      v4Addr.sin_addr.s_addr = ntohl(v4Key);
-      result.emplace_back(ComboAddress(&v4Addr), value.counter);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
-    }
-  }
-
-  {
-    auto& map = maps->d_v6;
-    int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data());
-
-    while (res == 0) {
-      if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) {
-        memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size());
-
-        result.emplace_back(ComboAddress(&v6Addr), value.counter);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data());
-    }
-  }
-
-  return result;
-}
-
-std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
-{
-  CIDR4 cidr4[2];
-  CIDR6 cidr6[2];
-  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
-
-  sockaddr_in v4Addr;
-  sockaddr_in6 v6Addr;
-  CounterAndActionValue value;
-
-  memset(cidr4, 0, sizeof(cidr4));
-  memset(cidr6, 0, sizeof(cidr6));
-  memset(&v4Addr, 0, sizeof(v4Addr));
-  memset(&v6Addr, 0, sizeof(v6Addr));
-  v4Addr.sin_family = AF_INET;
-  v6Addr.sin6_family = AF_INET6;
-  auto maps = d_maps.lock();
-  result.reserve(maps->d_cidr4.d_count + maps->d_cidr6.d_count);
-  {
-    auto& map = maps->d_cidr4;
-    int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[0], &cidr4[1]);
-    while (res == 0) {
-      if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) {
-        v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr;
-        result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]);
-    }
-  }
-
-  {
-    auto& map = maps->d_cidr6;
-    int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[0], &cidr6[1]);
-    while (res == 0) {
-      if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) {
-        v6Addr.sin6_addr = cidr6[1].addr;
-        result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]);
-    }
-  }
-  return result;
-}
-
-std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
-{
-  std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result;
-
-  if (d_mapFormat == MapFormat::Legacy) {
-    QNameKey key = { { 0 } };
-    QNameKey nextKey = { { 0 } };
-    QNameValue value;
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_qnames;
-    result.reserve(map.d_count);
-    int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
-
-    while (res == 0) {
-      if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
-        nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
-        result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
-    }
-  }
-  else {
-    QNameAndQTypeKey key;
-    QNameAndQTypeKey nextKey;
-    memset(&key, 0, sizeof(key));
-    memset(&nextKey, 0, sizeof(nextKey));
-    CounterAndActionValue value;
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_qnames;
-    result.reserve(map.d_count);
-    int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
-
-    while (res == 0) {
-      if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
-        nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
-        result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter);
-      }
-
-      res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
-    }
-  }
-
-  return result;
-}
-
-uint64_t BPFFilter::getHits(const ComboAddress& requestor)
-{
-  CounterAndActionValue counter;
-
-  if (requestor.isIPv4()) {
-    uint32_t key = htonl(requestor.sin4.sin_addr.s_addr);
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v4;
-    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
-    if (res == 0) {
-      return counter.counter;
-    }
-  }
-  else if (requestor.isIPv6()) {
-    uint8_t key[16];
-    static_assert(sizeof(requestor.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
-    for (size_t idx = 0; idx < sizeof(key); idx++) {
-      key[idx] = requestor.sin6.sin6_addr.s6_addr[idx];
-    }
-
-    auto maps = d_maps.lock();
-    auto& map = maps->d_v6;
-    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
-    if (res == 0) {
-      return counter.counter;
-    }
-  }
-
-  return 0;
-}
-
-#else
-
-BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external)
-{
-}
-
-void BPFFilter::addSocket(int)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::removeSocket(int)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::block(const ComboAddress&, BPFFilter::MatchAction)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::unblock(const ComboAddress&)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::block(const DNSName&, BPFFilter::MatchAction, uint16_t)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::unblock(const DNSName&, uint16_t)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-void BPFFilter::rmRangeRule(const Netmask&)
-{
-  throw std::runtime_error("eBPF support not enabled");
-}
-
-std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule(){
-  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
-  return result;
-}
-std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
-{
-  std::vector<std::pair<ComboAddress, uint64_t> > result;
-  return result;
-}
-
-std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
-{
-  std::vector<std::tuple<DNSName, uint16_t, uint64_t> > result;
-  return result;
-}
-
-uint64_t BPFFilter::getHits(const ComboAddress&)
-{
-  return 0;
-}
-#endif /* HAVE_EBPF */
-
-bool BPFFilter::supportsMatchAction(MatchAction action) const
-{
-#ifdef HAVE_EBPF
-  if (action == BPFFilter::MatchAction::Drop) {
-    return true;
-  }
-  return d_mapFormat == BPFFilter::MapFormat::WithActions;
-#endif /* HAVE_EBPF */
-  return false;
-}
-
-bool BPFFilter::isExternal() const
-{
-#ifdef HAVE_EBPF
-  return d_external;
-#endif /* HAVE_EBPF */
-  return false;
-}
diff --git a/pdns/bpf-filter.ebpf.src b/pdns/bpf-filter.ebpf.src
deleted file mode 100644 (file)
index 9f58669..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-
-#include <net/sock.h>
-#include <linux/types.h>
-#include <uapi/linux/tcp.h>
-#include <uapi/linux/udp.h>
-#include <uapi/linux/ip.h>
-#include <uapi/linux/ipv6.h>
-#include <bcc/proto.h>
-
-struct dnsheader {
-        unsigned        id :16;         /* query identification number */
-#if BYTE_ORDER == BIG_ENDIAN
-                        /* fields in third byte */
-        unsigned        qr: 1;          /* response flag */
-        unsigned        opcode: 4;      /* purpose of message */
-        unsigned        aa: 1;          /* authoritative answer */
-        unsigned        tc: 1;          /* truncated message */
-        unsigned        rd: 1;          /* recursion desired */
-                        /* fields in fourth byte */
-        unsigned        ra: 1;          /* recursion available */
-        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
-        unsigned        ad: 1;          /* authentic data from named */
-        unsigned        cd: 1;          /* checking disabled by resolver */
-        unsigned        rcode :4;       /* response code */
-#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
-                        /* fields in third byte */
-        unsigned        rd :1;          /* recursion desired */
-        unsigned        tc :1;          /* truncated message */
-        unsigned        aa :1;          /* authoritative answer */
-        unsigned        opcode :4;      /* purpose of message */
-        unsigned        qr :1;          /* response flag */
-                        /* fields in fourth byte */
-        unsigned        rcode :4;       /* response code */
-        unsigned        cd: 1;          /* checking disabled by resolver */
-        unsigned        ad: 1;          /* authentic data from named */
-        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
-        unsigned        ra :1;          /* recursion available */
-#endif
-                        /* remaining bytes */
-        unsigned        qdcount :16;    /* number of question entries */
-        unsigned        ancount :16;    /* number of answer entries */
-        unsigned        nscount :16;    /* number of authority entries */
-        unsigned        arcount :16;    /* number of resource entries */
-};
-
-struct QNameKey
-{
-  uint8_t qname[255];
-};
-
-struct KeyV6
-{
-  uint8_t src[16];
-};
-
-struct QNameValue
-{
-  u64 counter;
-  u16 qtype;
-};
-
-BPF_TABLE("hash", u32, u64, v4filter, 1024);
-BPF_TABLE("hash", struct KeyV6, u64, v6filter, 1024);
-BPF_TABLE("hash", struct QNameKey, struct QNameValue, qnamefilter, 1024);
-BPF_TABLE("prog", int, int, progsarray, 1);
-
-int bpf_qname_filter(struct __sk_buff *skb)
-{
-  uint32_t qname_off = skb->cb[0];
-  ssize_t labellen = skb->cb[3];
-  size_t idx = 2;
-  struct QNameKey qkey = { 0 };
-  u32 val = skb->cb[1];
-  if (val) {
-    qkey.qname[0] = val;
-  }
-  val = skb->cb[2];
-  if (val) {
-    qkey.qname[1] = val;
-  }
-  uint8_t temp;
-
-#define FILL_ONE_KEY                                    \
-  temp = load_byte(skb, qname_off + idx);               \
-  labellen--;                                           \
-  if (labellen < 0) {                                   \
-    labellen = temp;                                    \
-    if (labellen == 0) {                                \
-      goto end;                                         \
-    }                                                   \
-  } else if (temp >= 'A' && temp <= 'Z') {              \
-    temp += ('a' - 'A');                                \
-  }                                                     \
-  qkey.qname[idx] = temp;                               \
-  idx++;
-
-  /* 2 - 52 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* 52 - 102 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* 102 - 152 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* 152 - 202 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* 202 - 252 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* 252 - 254 */
-  FILL_ONE_KEY
-  FILL_ONE_KEY
-
-  /* the only value that makes sense for
-     qkey.qname[255] is 0, and it's already
-     there */
-  end:
-
-  {
-    idx++;
-    u16 qtype = load_half(skb, (qname_off + idx));
-
-    struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
-    if (qvalue &&
-      (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
-      __sync_fetch_and_add(&qvalue->counter, 1);
-      return 0;
-    }
-  }
-
-  return 2147483647;
-}
-
-int bpf_dns_filter(struct __sk_buff *skb) {
-  u8 ip_proto;
-  int proto_off;
-  /* nh_off will contain a negative offset, used in BPF to get access to
-     the MAC/network layers, as positive values are used to get access to
-     the transport layer */
-  int nh_off = BPF_LL_OFF + ETH_HLEN;
-
-  if (skb->protocol == ntohs(0x0800)) {
-    u32 key;
-    int off = nh_off + offsetof(struct iphdr, saddr);
-    key = load_word(skb, off);
-
-    u64* counter = v4filter.lookup(&key);
-    if (counter) {
-      __sync_fetch_and_add(counter, 1);
-      return 0;
-    }
-
-    ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
-    proto_off = nh_off + sizeof(struct iphdr);
-  }
-  else if (skb->protocol == ntohs(0x86DD)) {
-    struct KeyV6 key;
-    int off = nh_off + offsetof(struct ipv6hdr, saddr);
-    key.src[0] = load_byte(skb, off++);
-    key.src[1] = load_byte(skb, off++);
-    key.src[2] = load_byte(skb, off++);
-    key.src[3] = load_byte(skb, off++);
-    key.src[4] = load_byte(skb, off++);
-    key.src[5] = load_byte(skb, off++);
-    key.src[6] = load_byte(skb, off++);
-    key.src[7] = load_byte(skb, off++);
-    key.src[8] = load_byte(skb, off++);
-    key.src[9] = load_byte(skb, off++);
-    key.src[10] = load_byte(skb, off++);
-    key.src[11] = load_byte(skb, off++);
-    key.src[12] = load_byte(skb, off++);
-    key.src[13] = load_byte(skb, off++);
-    key.src[14] = load_byte(skb, off++);
-    key.src[15] = load_byte(skb, off++);
-
-    u64* counter = v6filter.lookup(&key);
-    if (counter) {
-      __sync_fetch_and_add(counter, 1);
-      return 0;
-    }
-
-    ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
-    proto_off = nh_off + sizeof(struct ipv6hdr);
-  }
-  else {
-    /* neither IPv4 not IPv6, well */
-    return 2147483647;
-  }
-
-  /* allow TCP */
-  if (ip_proto == IPPROTO_TCP) {
-    return 2147483647;
-  }
-
-  struct QNameKey qkey = { 0 };
-  /* switch to positive offsets here, as we have seen some issues
-     when accessing the content of the transport layer with negative offsets
-     https://github.com/PowerDNS/pdns/issues/9626 */
-  int dns_off = sizeof(struct udphdr);
-  int qname_off = dns_off + sizeof(struct dnsheader);
-  skb->cb[0] = (uint32_t) qname_off;
-  u16 qtype;
-
-  uint8_t temp = load_byte(skb, qname_off);
-  if (temp > 63) {
-    return 0;
-  }
-
-  if (temp == 0) {
-    /* root, nothing else to see */
-    qtype = load_half(skb, (qname_off + 1));
-
-    struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
-    if (qvalue &&
-      (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
-      __sync_fetch_and_add(&qvalue->counter, 1);
-      return 0;
-    }
-    return 2147483647;
-  }
-
-  ssize_t labellen = temp;
-  skb->cb[1] = temp;
-  qkey.qname[0] = temp;
-
-  temp = load_byte(skb, qname_off + 1);
-  labellen--;
-  if (temp >= 'A' && temp <= 'Z') {
-    temp += ('a' - 'A');
-  }
-  skb->cb[2] = temp;
-  skb->cb[3] = labellen;
-  progsarray.call(skb, 0);
-
-  return 2147483647;
-}
diff --git a/pdns/bpf-filter.hh b/pdns/bpf-filter.hh
deleted file mode 100644 (file)
index 2ab3aa5..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-#include "config.h"
-
-#include <unordered_map>
-
-#include "iputils.hh"
-#include "lock.hh"
-#include <netinet/in.h>
-#include <stdexcept>
-
-class BPFFilter
-{
-public:
-  enum class MapType : uint8_t {
-    IPv4,
-    IPv6,
-    QNames,
-    Filters,
-    CIDR4,
-    CIDR6
-  };
-
-  enum class MapFormat : uint8_t {
-    Legacy = 0,
-    WithActions = 1
-  };
-
-  enum class MatchAction : uint8_t {
-    Pass = 0,
-    Drop = 1,
-    Truncate = 2
-  };
-  static std::string toString(MatchAction s) noexcept
-  {
-    switch (s) {
-    case MatchAction::Pass:
-      return "Pass";
-    case MatchAction::Drop:
-      return "Drop";
-    case MatchAction::Truncate:
-      return "Truncate";
-    }
-    return "Unknown";
-  }
-
-  struct MapConfiguration
-  {
-    std::string d_pinnedPath;
-    uint32_t d_maxItems{0};
-    MapType d_type;
-  };
-
-  struct CounterAndActionValue
-  {
-    uint64_t counter{0};
-    BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
-  };
-  
-
-  BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
-  BPFFilter(const BPFFilter&) = delete;
-  BPFFilter(BPFFilter&&) = delete;
-  BPFFilter& operator=(const BPFFilter&) = delete;
-  BPFFilter& operator=(BPFFilter&&) = delete;
-
-  void addSocket(int sock);
-  void removeSocket(int sock);
-  void block(const ComboAddress& addr, MatchAction action);
-  void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
-  void block(const DNSName& qname, MatchAction action, uint16_t qtype=255);
-  void unblock(const ComboAddress& addr);
-  void rmRangeRule(const Netmask& address);
-  void unblock(const DNSName& qname, uint16_t qtype=255);
-
-  std::vector<std::pair<ComboAddress, uint64_t> > getAddrStats();
-  std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
-  std::vector<std::tuple<DNSName, uint16_t, uint64_t> > getQNameStats();
-
-  uint64_t getHits(const ComboAddress& requestor);
-
-  bool supportsMatchAction(MatchAction action) const;
-  bool isExternal() const;
-
-private:
-#ifdef HAVE_EBPF
-  struct Map
-  {
-    Map()
-    {
-    }
-    Map(const MapConfiguration&, MapFormat);
-    MapConfiguration d_config;
-    uint32_t d_count{0};
-    FDWrapper d_fd;
-  };
-
-  struct Maps
-  {
-    Map d_v4;
-    Map d_v6;
-    Map d_cidr4;
-    Map d_cidr6;
-    Map d_qnames;
-    /* The qname filter program held in d_qnamefilter is
-       stored in an eBPF map, so we can call it from the
-       main filter. This is the only entry in that map. */
-    Map d_filters;
-  };
-
-  LockGuarded<Maps> d_maps;
-
-  /* main eBPF program */
-  FDWrapper d_mainfilter;
-  /* qname filtering program */
-  FDWrapper d_qnamefilter;
-  struct CIDR4
-  {
-    uint32_t cidr;
-    struct in_addr addr;
-    explicit CIDR4(Netmask address)
-    {
-      if (!address.isIPv4()) {
-        throw std::runtime_error("ComboAddress is invalid");
-      }
-      addr = address.getNetwork().sin4.sin_addr;
-      cidr = address.getBits();
-    }
-    CIDR4() = default;
-  };
-  struct CIDR6
-  {
-    uint32_t cidr;
-    struct in6_addr addr;
-    CIDR6(Netmask address)
-    {
-      if (!address.isIPv6()) {
-        throw std::runtime_error("ComboAddress is invalid");
-      }
-      addr = address.getNetwork().sin6.sin6_addr;
-      cidr = address.getBits();
-    }
-    CIDR6() = default;
-  };
-  /* whether the maps are in the 'old' format, which we need
-     to keep to prevent going over the 4k instructions per eBPF
-     program limit in kernels < 5.2, as well as the complexity limit:
-     - 32k in Linux 3.18
-     - 64k in Linux 4.7
-     - 96k in Linux 4.12
-     - 128k in Linux 4.14,
-     - 1M in Linux 5.2 */
-  MapFormat d_mapFormat;
-
-  /* whether the filter is internal, using our own eBPF programs,
-     or external where we only update the maps but the filtering is
-     done by an external program. */
-  bool d_external;
-#endif /* HAVE_EBPF */
-};
-using CounterAndActionValue = BPFFilter::CounterAndActionValue;
diff --git a/pdns/bpf-filter.main.ebpf b/pdns/bpf-filter.main.ebpf
deleted file mode 100644 (file)
index 4b42a2e..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* generated from the bpf_dns_filter() function in bpf-filter.ebpf.src */
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,16),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,ntohs(0x86dd),11),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_1,ntohs(0x0800),109),
-BPF_LD_ABS(BPF_W,-2097126),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_0,-256),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_v4.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,98),
-BPF_LD_ABS(BPF_B,-2097129),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,39),
-BPF_LD_ABS(BPF_B,-2097130),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-256),
-BPF_LD_ABS(BPF_B,-2097129),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-255),
-BPF_LD_ABS(BPF_B,-2097128),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
-BPF_LD_ABS(BPF_B,-2097127),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
-BPF_LD_ABS(BPF_B,-2097126),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
-BPF_LD_ABS(BPF_B,-2097125),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
-BPF_LD_ABS(BPF_B,-2097124),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
-BPF_LD_ABS(BPF_B,-2097123),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
-BPF_LD_ABS(BPF_B,-2097122),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
-BPF_LD_ABS(BPF_B,-2097121),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
-BPF_LD_ABS(BPF_B,-2097120),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
-BPF_LD_ABS(BPF_B,-2097119),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
-BPF_LD_ABS(BPF_B,-2097118),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
-BPF_LD_ABS(BPF_B,-2097117),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
-BPF_LD_ABS(BPF_B,-2097116),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
-BPF_LD_ABS(BPF_B,-2097115),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_v6.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,58),
-BPF_LD_ABS(BPF_B,-2097132),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_0,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,6,58),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
-BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
-BPF_MOV64_IMM(BPF_REG_1,20),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,48),
-BPF_LD_ABS(BPF_B,20),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_MOV64_IMM(BPF_REG_7,0),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_8,63,17),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,18),
-BPF_LD_ABS(BPF_H,21),
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
-BPF_LDX_MEM(BPF_H,BPF_REG_1,BPF_REG_0,8),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,255,2),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
-BPF_JMP_REG(BPF_JNE,BPF_REG_1,BPF_REG_6,3),
-BPF_MOV64_IMM(BPF_REG_1,1),
-BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
-BPF_MOV64_IMM(BPF_REG_7,0),
-BPF_MOV64_REG(BPF_REG_0,BPF_REG_7),
-BPF_EXIT_INSN(),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,52),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_8,-256),
-BPF_LD_ABS(BPF_B,21),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-65),
-BPF_ALU64_IMM(BPF_LSH,BPF_REG_2,32),
-BPF_ALU64_IMM(BPF_RSH,BPF_REG_2,32),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,32),
-BPF_MOV64_IMM(BPF_REG_3,26),
-BPF_JMP_REG(BPF_JGT,BPF_REG_3,BPF_REG_2,1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,60),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,56),
-BPF_LD_MAP_FD(BPF_REG_2,maps->d_filters.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_6),
-BPF_MOV64_IMM(BPF_REG_3,0),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_tail_call),
-BPF_MOV64_IMM(BPF_REG_7,2147483647),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,-25),
diff --git a/pdns/bpf-filter.qname.ebpf b/pdns/bpf-filter.qname.ebpf
deleted file mode 100644 (file)
index c7d6094..0000000
+++ /dev/null
@@ -1,4095 +0,0 @@
-/* generated from the bpf_qname_filter() function in bpf-filter.ebpf.src */
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
-BPF_LDX_MEM(BPF_W,BPF_REG_8,BPF_REG_6,60),
-BPF_LDX_MEM(BPF_W,BPF_REG_7,BPF_REG_6,48),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
-BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
-BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
-BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,52),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-256),
-BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,56),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-255),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,2),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_2,0,0),
-BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,3),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4024),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,3),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,4),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4008),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,4),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,5),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3992),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,5),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,6),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3976),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,6),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,7),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3960),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,7),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,8),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3944),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,8),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,9),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3928),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,9),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,10),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3912),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,10),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,11),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3896),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,11),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,12),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3880),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,12),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,13),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3864),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,13),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,14),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3848),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,14),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,15),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3832),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,15),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,16),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3816),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,16),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,17),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3800),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-240),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,17),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,18),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3784),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-239),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,18),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,19),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3768),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-238),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,19),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,20),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3752),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-237),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,20),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,21),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3736),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-236),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,21),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,22),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3720),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-235),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,22),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,23),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3704),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-234),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,23),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,24),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3688),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-233),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,24),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,25),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3672),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-232),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,25),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,26),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3656),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-231),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,26),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,27),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3640),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-230),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,27),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,28),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3624),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-229),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,28),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,29),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3608),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-228),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,29),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,30),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3592),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-227),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,30),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,31),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3576),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-226),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,31),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,32),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3560),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-225),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,32),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,33),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3544),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-224),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,33),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,34),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3528),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-223),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,34),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,35),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3512),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-222),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,35),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,36),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3496),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-221),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,36),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,37),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3480),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-220),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,37),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,38),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3464),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-219),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,38),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,39),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3448),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-218),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,39),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,40),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3432),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-217),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,40),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,41),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3416),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-216),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,41),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,42),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3400),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-215),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,42),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,43),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3384),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-214),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,43),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,44),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3368),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-213),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,44),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,45),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3352),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-212),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,45),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,46),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3336),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-211),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,46),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,47),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3320),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-210),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,47),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,48),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3304),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-209),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,48),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,49),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3288),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-208),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,49),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,50),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3272),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-207),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,50),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,51),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3256),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-206),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,51),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,52),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3240),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-205),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,52),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,53),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3224),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-204),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,53),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,54),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3208),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-203),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,54),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,55),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3192),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-202),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,55),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,56),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3176),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-201),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,56),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,57),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3160),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-200),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,57),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,58),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3144),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-199),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,58),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,59),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3128),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-198),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,59),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,60),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3112),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-197),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,60),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,61),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3096),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-196),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,61),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,62),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3080),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-195),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,62),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,63),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3064),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-194),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,63),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,64),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3048),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-193),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,64),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,65),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3032),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-192),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,65),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,66),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3016),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-191),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,66),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,67),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3000),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-190),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,67),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,68),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2984),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-189),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,68),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,69),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2968),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-188),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,69),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,70),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2952),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-187),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,70),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,71),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2936),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-186),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,71),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,72),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2920),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-185),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,72),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,73),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2904),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-184),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,73),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,74),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2888),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-183),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,74),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,75),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2872),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-182),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,75),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,76),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2856),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-181),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,76),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,77),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2840),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-180),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,77),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,78),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2824),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-179),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,78),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,79),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2808),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-178),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,79),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,80),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2792),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-177),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,80),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,81),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2776),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-176),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,81),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,82),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2760),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-175),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,82),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,83),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2744),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-174),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,83),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,84),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2728),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-173),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,84),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,85),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2712),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-172),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,85),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,86),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2696),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-171),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,86),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,87),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2680),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-170),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,87),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,88),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2664),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-169),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,88),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,89),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2648),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-168),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,89),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,90),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2632),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-167),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,90),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,91),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2616),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-166),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,91),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,92),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2600),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-165),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,92),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,93),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2584),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-164),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,93),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,94),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2568),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-163),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,94),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,95),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2552),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-162),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,95),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,96),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2536),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-161),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,96),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,97),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2520),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-160),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,97),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,98),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2504),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-159),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,98),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,99),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2488),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-158),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,99),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,100),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2472),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-157),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,100),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,101),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2456),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-156),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,101),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,102),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2440),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-155),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,102),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,103),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2424),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-154),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,103),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,104),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2408),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-153),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,104),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,105),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2392),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-152),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,105),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,106),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2376),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-151),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,106),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,107),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2360),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-150),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,107),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,108),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2344),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-149),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,108),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,109),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2328),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-148),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,109),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,110),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2312),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-147),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,110),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,111),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2296),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-146),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,111),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,112),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2280),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-145),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,112),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,113),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2264),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-144),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,113),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,114),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2248),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-143),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,114),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,115),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2232),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-142),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,115),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,116),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2216),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-141),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,116),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,117),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2200),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-140),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,117),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,118),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2184),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-139),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,118),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,119),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2168),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-138),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,119),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,120),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2152),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-137),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,120),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,121),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2136),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-136),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,121),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,122),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2120),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-135),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,122),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,123),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2104),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-134),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,123),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,124),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2088),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-133),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,124),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,125),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2072),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-132),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,125),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,126),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2056),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-131),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,126),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,127),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2040),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-130),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,127),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,128),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2024),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-129),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,128),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,129),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2008),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-128),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,129),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,130),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1992),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-127),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,130),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,131),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1976),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-126),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,131),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,132),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1960),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-125),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,132),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,133),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1944),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-124),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,133),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,134),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1928),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-123),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,134),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,135),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1912),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-122),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,135),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,136),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1896),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-121),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,136),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,137),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1880),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-120),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,137),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,138),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1864),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-119),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,138),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,139),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1848),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-118),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,139),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,140),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1832),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-117),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,140),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,141),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1816),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-116),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,141),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,142),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1800),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-115),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,142),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,143),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1784),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-114),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,143),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,144),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1768),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-113),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,144),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,145),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1752),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-112),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,145),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,146),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1736),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-111),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,146),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,147),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1720),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-110),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,147),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,148),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1704),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-109),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,148),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,149),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1688),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-108),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,149),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,150),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1672),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-107),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,150),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,151),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1656),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-106),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,151),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,152),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1640),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-105),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,152),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,153),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1624),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-104),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,153),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,154),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1608),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-103),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,154),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,155),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1592),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-102),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,155),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,156),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1576),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-101),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,156),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,157),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1560),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-100),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,157),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,158),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1544),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-99),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,158),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,159),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1528),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-98),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,159),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,160),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1512),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-97),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,160),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,161),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1496),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-96),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,161),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,162),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1480),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-95),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,162),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,163),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1464),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-94),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,163),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,164),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1448),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-93),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,164),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,165),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1432),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-92),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,165),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,166),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1416),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-91),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,166),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,167),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1400),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-90),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,167),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,168),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1384),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-89),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,168),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,169),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1368),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-88),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,169),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,170),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1352),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-87),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,170),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,171),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1336),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-86),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,171),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,172),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1320),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-85),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,172),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,173),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1304),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-84),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,173),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,174),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1288),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-83),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,174),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,175),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1272),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-82),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,175),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,176),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1256),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-81),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,176),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,177),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1240),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-80),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,177),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,178),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1224),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-79),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,178),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,179),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1208),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-78),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,179),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,180),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1192),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-77),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,180),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,181),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1176),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-76),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,181),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,182),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1160),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-75),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,182),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,183),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1144),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-74),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,183),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,184),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1128),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-73),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,184),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,185),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1112),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-72),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,185),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,186),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1096),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-71),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,186),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,187),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1080),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-70),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,187),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,188),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1064),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-69),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,188),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,189),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1048),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-68),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,189),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,190),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1032),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-67),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,190),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,191),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1016),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-66),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,191),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,192),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1000),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-65),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,192),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,193),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,984),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-64),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,193),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,194),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,968),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-63),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,194),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,195),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,952),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-62),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,195),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,196),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,936),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-61),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,196),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,197),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,920),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-60),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,197),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,198),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,904),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-59),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,198),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,199),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,888),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-58),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,199),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,200),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,872),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-57),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,200),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,201),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,856),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-56),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,201),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,202),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,840),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-55),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,202),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,203),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,824),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-54),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,203),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,204),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,808),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-53),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,204),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,205),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,792),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-52),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,205),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,206),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,776),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-51),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,206),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,207),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,760),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-50),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,207),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,208),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,744),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-49),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,208),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,209),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,728),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-48),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,209),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,210),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,712),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-47),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,210),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,211),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,696),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-46),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,211),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,212),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,680),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-45),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,212),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,213),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,664),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-44),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,213),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,214),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,648),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-43),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,214),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,215),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,632),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-42),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,215),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,216),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,616),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-41),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,216),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,217),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,600),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-40),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,217),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,218),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,584),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-39),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,218),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,219),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,568),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-38),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,219),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,220),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,552),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-37),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,220),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,221),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,536),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-36),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,221),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,222),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,520),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-35),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,222),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,223),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,504),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-34),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,223),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,224),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,488),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-33),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,224),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,225),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,472),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-32),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,225),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,226),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,456),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-31),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,226),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,227),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,440),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-30),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,227),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,228),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,424),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-29),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,228),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,229),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,408),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-28),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,229),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,230),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,392),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-27),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,230),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,231),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,376),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-26),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,231),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,232),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,360),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-25),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,232),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,233),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,344),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-24),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,233),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,234),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,328),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-23),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,234),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,235),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,312),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-22),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,235),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,236),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,296),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-21),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,236),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,237),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,280),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-20),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,237),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,238),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,264),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-19),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,238),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,239),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,248),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-18),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,239),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,240),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,232),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-17),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,240),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,241),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,216),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-16),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,241),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,242),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,200),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-15),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,242),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,243),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,184),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-14),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,243),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,244),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,168),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-13),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,244),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,245),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,152),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-12),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,245),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,246),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,136),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-11),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,246),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,247),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,120),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-10),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,247),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,248),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,104),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-9),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,248),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,249),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,88),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-8),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,249),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,250),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,72),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-7),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,250),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,251),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,56),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-6),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,251),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,252),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,40),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-5),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,252),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,253),
-BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,24),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-4),
-BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,253),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
-BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
-BPF_MOV64_IMM(BPF_REG_9,254),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,8),
-BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,5),
-BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
-BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
-BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-3),
-BPF_MOV64_IMM(BPF_REG_9,255),
-BPF_ALU64_REG(BPF_ADD,BPF_REG_9,BPF_REG_7),
-BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_H,BPF_REG_0,BPF_REG_9,0,0),
-BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
-BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
-BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
-BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
-BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
-BPF_MOV64_IMM(BPF_REG_1,2147483647),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
-BPF_LDX_MEM(BPF_H,BPF_REG_2,BPF_REG_0,8),
-BPF_JMP_IMM(BPF_JEQ,BPF_REG_2,255,2),
-BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
-BPF_JMP_REG(BPF_JNE,BPF_REG_6,BPF_REG_2,3),
-BPF_MOV64_IMM(BPF_REG_1,1),
-BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
-BPF_MOV64_IMM(BPF_REG_1,0),
-BPF_MOV64_REG(BPF_REG_0,BPF_REG_1),
-BPF_EXIT_INSN(),
index aaf798152aa335392d273265b0ce80f89663493f..13160036366bb34f25ecf195199f5b7cfd417f13 100644 (file)
@@ -81,13 +81,14 @@ void pruneCollection(T& collection, size_t maxCached, size_t scanFraction = 1000
 template <typename S, typename T>
 void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front)
 {
-  typedef typename T::template index<S>::type sequence_t;
-  sequence_t& sidx = collection.template get<S>();
-  typename sequence_t::iterator si = collection.template project<S>(iter);
-  if (front)
-    sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
-  else
-    sidx.relocate(sidx.end(), si); // back
+  auto& sidx = collection.template get<S>();
+  auto siter = collection.template project<S>(iter);
+  if (front) {
+    sidx.relocate(sidx.begin(), siter); // at the beginning of the delete queue
+  }
+  else {
+    sidx.relocate(sidx.end(), siter); // back
+  }
 }
 
 template <typename S, typename T>
@@ -108,8 +109,8 @@ uint64_t pruneLockedCollectionsVector(std::vector<T>& maps)
   uint64_t totErased = 0;
   time_t now = time(nullptr);
 
-  for (auto& mc : maps) {
-    auto map = mc.d_map.write_lock();
+  for (auto& shard : maps) {
+    auto map = shard.d_map.write_lock();
 
     uint64_t lookAt = (map->size() + 9) / 10; // Look at 10% of this shard
     uint64_t erased = 0;
@@ -240,8 +241,8 @@ uint64_t purgeLockedCollectionsVector(std::vector<T>& maps)
 {
   uint64_t delcount = 0;
 
-  for (auto& mc : maps) {
-    auto map = mc.d_map.write_lock();
+  for (auto& shard : maps) {
+    auto map = shard.d_map.write_lock();
     delcount += map->size();
     map->clear();
   }
@@ -256,8 +257,8 @@ uint64_t purgeLockedCollectionsVector(std::vector<T>& maps, const std::string& m
   std::string prefix(match);
   prefix.resize(prefix.size() - 1);
   DNSName dprefix(prefix);
-  for (auto& mc : maps) {
-    auto map = mc.d_map.write_lock();
+  for (auto& shard : maps) {
+    auto map = shard.d_map.write_lock();
     auto& idx = boost::multi_index::get<N>(*map);
     auto iter = idx.lower_bound(dprefix);
     auto start = iter;
@@ -275,10 +276,10 @@ uint64_t purgeLockedCollectionsVector(std::vector<T>& maps, const std::string& m
 }
 
 template <typename N, typename T>
-uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname)
+uint64_t purgeExactLockedCollection(T& shard, const DNSName& qname)
 {
   uint64_t delcount = 0;
-  auto map = mc.d_map.write_lock();
+  auto map = shard.d_map.write_lock();
   auto& idx = boost::multi_index::get<N>(*map);
   auto range = idx.equal_range(qname);
   if (range.first != range.second) {
@@ -290,12 +291,12 @@ uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname)
 }
 
 template <typename S, typename Index>
-bool lruReplacingInsert(Index& i, const typename Index::value_type& x)
+bool lruReplacingInsert(Index& index, const typename Index::value_type& value)
 {
-  auto inserted = i.insert(x);
+  auto inserted = index.insert(value);
   if (!inserted.second) {
-    moveCacheItemToBack<S>(i, inserted.first);
-    i.replace(inserted.first, x);
+    moveCacheItemToBack<S>(index, inserted.first);
+    index.replace(inserted.first, value);
     return false;
   }
   return true;
index 1de71defdb564cb8fdff25676aafd3920f14d1bd..a18012ff30f210ae565bffd1426419fb7ac4b3c7 100644 (file)
@@ -42,7 +42,7 @@
 // there can be MANY OF THESE
 void CommunicatorClass::retrievalLoopThread()
 {
-  setThreadName("pdns/comm-retre");
+  setThreadName("pdns/comm-retri");
   for (;;) {
     d_suck_sem.wait();
     SuckRequest sr;
index ec11732f246c04a5998da426becf9ab2b2e4ef3e..a1131035d128612ad2928d01babde47c07d4b1a7 100644 (file)
@@ -56,10 +56,6 @@ static std::string const pwhash_prefix = "$scrypt$";
 static size_t const pwhash_prefix_size = pwhash_prefix.size();
 #endif
 
-uint64_t const CredentialsHolder::s_defaultWorkFactor{1024U}; /* N */
-uint64_t const CredentialsHolder::s_defaultParallelFactor{1U}; /* p */
-uint64_t const CredentialsHolder::s_defaultBlockSize{8U}; /* r */
-
 SensitiveData::SensitiveData(std::string&& data) :
   d_data(std::move(data))
 {
index 6762b1a845116d6247bfb9daa835b1083f0c8bda..08010a74fd56cf56a2083588232b669eda2eb7e1 100644 (file)
@@ -81,9 +81,9 @@ public:
   static bool isHashingAvailable();
   static SensitiveData readFromTerminal();
 
-  static uint64_t const s_defaultWorkFactor;
-  static uint64_t const s_defaultParallelFactor;
-  static uint64_t const s_defaultBlockSize;
+  static uint64_t constexpr s_defaultWorkFactor{1024U}; /* N */
+  static uint64_t constexpr s_defaultParallelFactor{1U}; /* p */
+  static uint64_t constexpr s_defaultBlockSize{8U}; /* r */
 
 private:
   SensitiveData d_credentials;
index 717b00bda2f6fc5ce3b723ad141582a43f36ac30..8685920dc7a2151294ff5da850c20293b5c44ac5 100644 (file)
@@ -630,7 +630,7 @@ bool DNSSECKeeper::checkKeys(const DNSName& zone, std::optional<std::reference_w
   return retval;
 }
 
-void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL)
+void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL, DNSPacket* packet)
 {
   if(rrs.empty()) {
     return;
@@ -640,7 +640,7 @@ void DNSSECKeeper::getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, ui
 
   DNSZoneRecord dzr;
 
-  db.lookup(QType(QType::RRSIG), !rr.wildcardname.empty() ? rr.wildcardname : rr.dr.d_name, rr.domain_id);
+  db.lookup(QType(QType::RRSIG), !rr.wildcardname.empty() ? rr.wildcardname : rr.dr.d_name, rr.domain_id, packet);
   while(db.get(dzr)) {
     auto rrsig = getRR<RRSIGRecordContent>(dzr.dr);
     if (rrsig->d_type == rr.dr.d_type) {
diff --git a/pdns/delaypipe.cc b/pdns/delaypipe.cc
deleted file mode 100644 (file)
index ada096c..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "delaypipe.hh"
-#include "misc.hh"
-#include "gettime.hh"
-#include <thread>
-#include "threadname.hh"
-
-template<class T>
-ObjectPipe<T>::ObjectPipe()
-{
-  auto [sender, receiver] = pdns::channel::createObjectQueue<T>(pdns::channel::SenderBlockingMode::SenderBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0, false);
-  d_sender = std::move(sender);
-  d_receiver = std::move(receiver);
-}
-
-template<class T>
-void ObjectPipe<T>::close()
-{
-  d_sender.close();
-}
-
-template<class T>
-void ObjectPipe<T>::write(T& t)
-{
-  auto ptr = std::make_unique<T>(t);
-  if (!d_sender.send(std::move(ptr))) {
-    unixDie("writing to the DelayPipe");
-  }
-}
-
-template<class T>
-int ObjectPipe<T>::readTimeout(T* t, double msec)
-{
-  while (true) {
-    int ret = waitForData(d_receiver.getDescriptor(), 0, 1000*msec);
-    if (ret < 0) {
-      if (errno == EINTR) {
-        continue;
-      }
-      unixDie("waiting for data in object pipe");
-    }
-    else if (ret == 0) {
-      return -1;
-    }
-
-    try {
-      auto tmp = d_receiver.receive();
-      if (!tmp) {
-        if (d_receiver.isClosed()) {
-          return 0;
-        }
-        continue;
-      }
-
-      *t = **tmp;
-      return 1;
-    }
-    catch (const std::exception& e) {
-      throw std::runtime_error("reading from the delay pipe: " + std::string(e.what()));
-    }
-  }
-}
-
-
-template<class T>
-DelayPipe<T>::DelayPipe() : d_thread(&DelayPipe<T>::worker, this)
-{
-}
-
-template<class T>
-void DelayPipe<T>::gettime(struct timespec* ts)
-{
-  ::gettime(ts);
-}
-
-
-template<class T>
-void DelayPipe<T>::submit(T& t, int msec)
-{
-  struct timespec now;
-  gettime(&now);
-  now.tv_nsec += msec*1e6;
-  while(now.tv_nsec > 1e9) {
-    now.tv_sec++;
-    now.tv_nsec-=1e9;
-  }
-  Combo c{t, now};
-  d_pipe.write(c);
-}
-
-template<class T>
-DelayPipe<T>::~DelayPipe()
-{
-  d_pipe.close();
-  d_thread.join();
-}
-
-
-
-template<class T>
-void DelayPipe<T>::worker()
-{
-  setThreadName("dnsdist/delayPi");
-  Combo c;
-  for(;;) {
-    /* this code is slightly too subtle, but I don't see how it could be any simpler.
-       So we have a set of work to do, and we need to wait until the time arrives to do it.
-       Simultaneously new work might come in. So we try to combine both of these things by
-       setting a timeout on listening to the pipe over which new work comes in. This timeout
-       is equal to the wait until the first thing that needs to be done.
-
-       Two additional cases exist: we have no work to wait for, so we can wait infinitely long.
-       The other special case is that the first we have to do.. is in the past, so we need to do it
-       immediately. */
-
-
-    double delay=-1;  // infinite
-    struct timespec now;
-    if(!d_work.empty()) {
-      gettime(&now);
-      delay=1000*tsdelta(d_work.begin()->first, now);
-      if(delay < 0) {
-       delay=0;   // don't wait - we have work that is late already!
-      }
-    }
-    if(delay != 0 ) {
-      int ret = d_pipe.readTimeout(&c, delay);
-      if(ret > 0) {  // we got an object
-        d_work.emplace(c.when, c.what);
-      }
-      else if(ret==0) { // EOF
-       break;
-      }
-      else {
-       ;
-      }
-      gettime(&now);
-    }
-
-    tscomp cmp;
-
-    for(auto iter = d_work.begin() ; iter != d_work.end(); ) { // do the needful
-      if(cmp(iter->first, now)) {
-       iter->second();
-       d_work.erase(iter++);
-      }
-      else {
-       break;
-      }
-    }
-  }
-}
diff --git a/pdns/delaypipe.hh b/pdns/delaypipe.hh
deleted file mode 100644 (file)
index b12fd50..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-#include <time.h>
-#include <thread>
-
-#include "channel.hh"
-
-/**
-   General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
-   The implementation is that submitter threads create an object that represents the work, and it gets sent over a pipe 
-   to the worker thread.
-
-   The worker thread meanwhile listens on this pipe (non-blocking), with a delay set to the next object that needs to be executed.
-   If meanwhile new work comes in, all objects who's time has come are executed, a new sleep time is calculated.
-*/
-
-
-/* ObjectPipe facilitates the type-safe passing of types over a pipe */
-
-template<class T>
-class ObjectPipe
-{
-public:
-  ObjectPipe();
-  void write(T& t);
-  int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely long. msec==0 = undefined
-  void close(); 
-private:
-  pdns::channel::Sender<T> d_sender;
-  pdns::channel::Receiver<T> d_receiver;
-};
-
-template<class T>
-class DelayPipe
-{
-public:
-  DelayPipe();
-  ~DelayPipe();
-  void submit(T& t, int msec); //!< don't try for more than 4294 msec
-
-private:
-  void worker();
-  struct Combo
-  {
-    T what;
-    struct timespec when;
-  };
-
-  double tsdelta(const struct timespec& a, const struct timespec& b) // read as a-b
-  {
-    return 1.0*(a.tv_sec-b.tv_sec)+1.0*(a.tv_nsec-b.tv_nsec)/1000000000.0;
-  }
-
-  ObjectPipe<Combo> d_pipe;
-  struct tscomp {
-    bool operator()(const struct timespec& a, const struct timespec& b) const
-    {
-      return std::tie(a.tv_sec, a.tv_nsec) < std::tie(b.tv_sec, b.tv_nsec);
-    }
-  };
-  std::multimap<struct timespec, T, tscomp> d_work;
-  void gettime(struct timespec* ts);
-  std::thread d_thread;
-};
-
-#include "delaypipe.cc"
index 99bbd72aa65e8749e66ee8237914427ab80ba681..12f97eaee9e4ea567433815f47db1a144c98f1aa 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 #include "dns.hh"
 #include "misc.hh"
+#include "views.hh"
 #include <stdexcept>
 #include <iostream>
 #include <boost/algorithm/string.hpp>
@@ -102,27 +103,41 @@ std::string Opcode::to_s(uint8_t opcode) {
 }
 
 // goal is to hash based purely on the question name, and turn error into 'default'
-uint32_t hashQuestion(const uint8_t* packet, uint16_t packet_len, uint32_t init, bool& ok)
+uint32_t hashQuestion(const uint8_t* packet, uint16_t packet_len, uint32_t init, bool& wasOK)
 {
   if (packet_len < sizeof(dnsheader)) {
-    ok = false;
+    wasOK = false;
     return init;
   }
-  // C++ 17 does not have std::u8string_view
-  std::basic_string_view<uint8_t> name(packet + sizeof(dnsheader), packet_len - sizeof(dnsheader));
-  std::basic_string_view<uint8_t>::size_type len = 0;
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  pdns::views::UnsignedCharView name(packet + sizeof(dnsheader), packet_len - sizeof(dnsheader));
+  pdns::views::UnsignedCharView::size_type len = 0;
 
   while (len < name.length()) {
     uint8_t labellen = name[len++];
     if (labellen == 0) {
-      ok = true;
+      wasOK = true;
       // len is name.length() at max as it was < before the increment
       return burtleCI(name.data(), len, init);
     }
     len += labellen;
   }
   // We've encountered a label that is too long
-  ok = false;
+  wasOK = false;
   return init;
 }
 
+static const std::array<std::string, 4> placeNames = {
+  "QUESTION",
+  "ANSWER",
+  "AUTHORITY",
+  "ADDITIONAL"
+};
+
+std::string DNSResourceRecord::placeString(uint8_t place)
+{
+  if (place >= placeNames.size()) {
+    return "?";
+  }
+  return placeNames.at(place);
+}
index c95a62f1c52fdd49e9fc1c7b8b79e7f1bb7870f3..b8dd761673c2311932af6a56f9f05c69a1df2dca 100644 (file)
@@ -66,6 +66,7 @@ public:
     ADDITIONAL = 3
   }; //!< Type describing the positioning within, say, a DNSPacket
 
+  [[nodiscard]] static std::string placeString(uint8_t place);
   void setContent(const string& content);
   [[nodiscard]] string getZoneRepresentation(bool noDot = false) const;
 
index fd1f6173f259d4f7f598bcdbbc807d3ee312cd59..49ad38ab49e464025df27190dc81505d6395d624 100644 (file)
@@ -161,15 +161,15 @@ struct SendReceive
       }
       dnsResult.rcode = mdp.d_header.rcode;
       for (auto i = mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
-        if (i->first.d_place == 1 && i->first.d_type == mdp.d_qtype) {
-          dnsResult.ips.emplace_back(i->first.getContent()->getZoneRepresentation());
+        if (i->d_place == 1 && i->d_type == mdp.d_qtype) {
+          dnsResult.ips.emplace_back(i->getContent()->getZoneRepresentation());
         }
-        if (i->first.d_place == 2 && i->first.d_type == QType::SOA) {
+        if (i->d_place == 2 && i->d_type == QType::SOA) {
           dnsResult.seenauthsoa = true;
         }
         if (!g_quiet) {
-          cout << i->first.d_place - 1 << "\t" << i->first.d_name << "\tIN\t" << DNSRecordContent::NumberToType(i->first.d_type);
-          cout << "\t" << i->first.d_ttl << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+          cout << i->d_place - 1 << "\t" << i->d_name << "\tIN\t" << DNSRecordContent::NumberToType(i->d_type);
+          cout << "\t" << i->d_ttl << "\t" << i->getContent()->getZoneRepresentation() << "\n";
         }
       }
 
index 5fb7fa5a8ad7382dc9e749ec36137e55861b6666..116e29c6508b707ac6bfb30974e1909b780945b4 100644 (file)
@@ -144,23 +144,27 @@ dnsdist_SOURCES = \
        dns.cc dns.hh \
        dns_random.hh \
        dnscrypt.cc dnscrypt.hh \
+       dnsdist-actions.hh \
        dnsdist-async.cc dnsdist-async.hh \
-       dnsdist-backend.cc \
+       dnsdist-backend.cc dnsdist-backend.hh \
        dnsdist-backoff.hh \
        dnsdist-cache.cc dnsdist-cache.hh \
        dnsdist-carbon.cc dnsdist-carbon.hh \
        dnsdist-concurrent-connections.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-console.cc dnsdist-console.hh \
        dnsdist-crypto.cc dnsdist-crypto.hh \
        dnsdist-discovery.cc dnsdist-discovery.hh \
        dnsdist-dnscrypt.cc \
        dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+       dnsdist-dnsquestion.cc \
        dnsdist-doh-common.cc dnsdist-doh-common.hh \
        dnsdist-downstream-connection.hh \
        dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
        dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-edns.cc dnsdist-edns.hh \
+       dnsdist-frontend.cc dnsdist-frontend.hh \
        dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
        dnsdist-idstate.cc dnsdist-idstate.hh \
        dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
@@ -194,6 +198,7 @@ dnsdist_SOURCES = \
        dnsdist-protobuf.cc dnsdist-protobuf.hh \
        dnsdist-protocols.cc dnsdist-protocols.hh \
        dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
+       dnsdist-query-count.hh dnsdist-query-count.cc \
        dnsdist-random.cc dnsdist-random.hh \
        dnsdist-resolver.cc dnsdist-resolver.hh \
        dnsdist-rings.cc dnsdist-rings.hh \
@@ -270,18 +275,21 @@ testrunner_SOURCES = \
        dns.cc dns.hh \
        dnscrypt.cc dnscrypt.hh \
        dnsdist-async.cc dnsdist-async.hh \
-       dnsdist-backend.cc \
+       dnsdist-backend.cc dnsdist-backend.hh \
        dnsdist-backoff.hh \
        dnsdist-cache.cc dnsdist-cache.hh \
        dnsdist-concurrent-connections.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-crypto.cc dnsdist-crypto.hh \
        dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+       dnsdist-dnsquestion.cc \
        dnsdist-doh-common.cc dnsdist-doh-common.hh \
        dnsdist-downstream-connection.hh \
        dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
        dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-edns.cc dnsdist-edns.hh \
+       dnsdist-frontend.cc dnsdist-frontend.hh \
        dnsdist-idstate.cc dnsdist-idstate.hh \
        dnsdist-kvs.cc dnsdist-kvs.hh \
        dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
@@ -362,6 +370,7 @@ testrunner_SOURCES = \
        test-luawrapper.cc \
        test-mplexer.cc \
        test-proxy_protocol_cc.cc \
+       test-sholder_hh.cc \
        testrunner.cc \
        threadname.hh threadname.cc \
        uuid-utils.hh uuid-utils.cc \
@@ -437,14 +446,14 @@ endif
 
 if HAVE_DNS_OVER_TLS
 if HAVE_GNUTLS
-dnsdist_LDADD += -lgnutls
+dnsdist_LDADD += $(GNUTLS_LIBS)
 endif
 endif
 
 if HAVE_DNS_OVER_HTTPS
 
 if HAVE_GNUTLS
-dnsdist_LDADD += -lgnutls
+dnsdist_LDADD += $(GNUTLS_LIBS)
 endif
 
 if HAVE_LIBH2OEVLOOP
@@ -547,7 +556,9 @@ fuzz_target_dnsdistcache_SOURCES = \
        channel.hh channel.cc \
        dns.cc dns.hh \
        dnsdist-cache.cc dnsdist-cache.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+       dnsdist-dnsquestion.cc \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-idstate.hh \
        dnsdist-protocols.cc dnsdist-protocols.hh \
deleted file mode 120000 (symlink)
index 35d8b2d6dc392ece8590d4bb9ebe24084a4cd93b..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../README-dnsdist.md
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..f8e67cb0772b0054693347ed7def0679c53630f3
--- /dev/null
@@ -0,0 +1,29 @@
+# dnsdist
+`dnsdist` is a highly DNS-, DoS- and abuse-aware loadbalancer. Its goal in
+life is to route traffic to the best server, delivering top performance
+to legitimate users while shunting or blocking abusive traffic.
+
+`dnsdist` is dynamic, in the sense that its configuration can be changed at
+runtime, and that its statistics can be queried from a console-like
+interface.
+
+All `dnsdist` features are documented at [dnsdist.org](https://dnsdist.org).
+
+## Compiling from git
+
+Make sure to `autoreconf -vi` before running `configure`.
+
+## macOS Notes
+
+Install dependencies from Homebrew:
+
+```sh
+brew install autoconf automake boost libedit libsodium libtool lua pkg-config protobuf
+```
+
+Let configure know where to find libedit, and openssl or libressl:
+
+```sh
+./configure 'PKG_CONFIG_PATH=/usr/local/opt/libedit/lib/pkgconfig:/usr/local/opt/libressl/lib/pkgconfig'
+make
+```
deleted file mode 120000 (symlink)
index c221c9206f31efc834a7f85fa08618afb7404b0e..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../bpf-filter.cc
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..700f32467dfbf82dd6ad8a8a5afeae01db6f4097
--- /dev/null
@@ -0,0 +1,984 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "bpf-filter.hh"
+#include "iputils.hh"
+#include "dolog.hh"
+
+#ifdef HAVE_EBPF
+
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <linux/bpf.h>
+
+#include "ext/libbpf/libbpf.h"
+
+#include "misc.hh"
+
+static __u64 ptr_to_u64(const void* ptr)
+{
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
+  return (__u64)(unsigned long)ptr;
+}
+
+/* these can be static as they are not declared in libbpf.h: */
+static int bpf_pin_map(int descriptor, const std::string& path)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.bpf_fd = descriptor;
+  attr.pathname = ptr_to_u64(path.c_str());
+  return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
+}
+
+static int bpf_load_pinned_map(const std::string& path)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.pathname = ptr_to_u64(path.c_str());
+  return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
+static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize)
+{
+  struct bpf_map_info info;
+  uint32_t info_len = sizeof(info);
+  memset(&info, 0, sizeof(info));
+
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.info.bpf_fd = descriptor;
+  attr.info.info_len = info_len;
+  attr.info.info = ptr_to_u64(&info);
+
+  int err = syscall(SYS_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
+  if (err != 0) {
+    throw std::runtime_error("Error checking the size of eBPF map: " + stringerror());
+  }
+  if (info_len != sizeof(info)) {
+    throw std::runtime_error("Error checking the size of eBPF map: invalid info size returned");
+  }
+  if (info.key_size != expectedKeySize) {
+    throw std::runtime_error("Error checking the size of eBPF map: key size mismatch (" + std::to_string(info.key_size) + " VS " + std::to_string(expectedKeySize) + ")");
+  }
+  if (info.value_size != expectedValueSize) {
+    throw std::runtime_error("Error checking the size of eBPF map: value size mismatch (" + std::to_string(info.value_size) + " VS " + std::to_string(expectedValueSize) + ")");
+  }
+}
+
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
+                          int max_entries, int map_flags)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.map_type = map_type;
+  attr.key_size = key_size;
+  attr.value_size = value_size;
+  attr.max_entries = max_entries;
+  attr.map_flags = map_flags;
+  return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
+}
+
+static int bpf_update_elem(int descriptor, void* key, void* value, unsigned long long flags)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.map_fd = descriptor;
+  attr.key = ptr_to_u64(key);
+  attr.value = ptr_to_u64(value);
+  attr.flags = flags;
+  return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_lookup_elem(int descriptor, void* key, void* value)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.map_fd = descriptor;
+  attr.key = ptr_to_u64(key);
+  attr.value = ptr_to_u64(value);
+  return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_delete_elem(int descriptor, void* key)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.map_fd = descriptor;
+  attr.key = ptr_to_u64(key);
+  return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
+}
+
+static int bpf_get_next_key(int descriptor, void* key, void* next_key)
+{
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.map_fd = descriptor;
+  attr.key = ptr_to_u64(key);
+  attr.next_key = ptr_to_u64(next_key);
+  return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
+}
+
+static int bpf_prog_load(enum bpf_prog_type prog_type,
+                         const struct bpf_insn* insns, size_t prog_len,
+                         const char* license, int kern_version)
+{
+  char log_buf[65535];
+  union bpf_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.prog_type = prog_type;
+  attr.insns = ptr_to_u64((void*)insns);
+  attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn));
+  attr.license = ptr_to_u64((void*)license);
+  attr.log_buf = ptr_to_u64(log_buf);
+  attr.log_size = sizeof(log_buf);
+  attr.log_level = 1;
+  /* assign one field outside of struct init to make sure any
+   * padding is zero initialized
+   */
+  attr.kern_version = kern_version;
+
+  long res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+  if (res == -1) {
+    if (errno == ENOSPC) {
+      /* not enough space in the log buffer */
+      attr.log_level = 0;
+      attr.log_size = 0;
+      attr.log_buf = ptr_to_u64(nullptr);
+      res = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
+      if (res != -1) {
+        return res;
+      }
+    }
+    throw std::runtime_error("Error loading BPF program: (" + stringerror() + "):\n" + std::string(log_buf));
+  }
+  return res;
+}
+
+struct KeyV6
+{
+  uint8_t src[16];
+};
+
+struct QNameKey
+{
+  uint8_t qname[255];
+};
+
+struct QNameAndQTypeKey
+{
+  uint8_t qname[255];
+  uint16_t qtype;
+};
+
+struct QNameValue
+{
+  uint64_t counter{0};
+  uint16_t qtype{0};
+};
+
+BPFFilter::Map::Map(BPFFilter::MapConfiguration config, BPFFilter::MapFormat format) :
+  d_config(std::move(config))
+{
+  if (d_config.d_type == BPFFilter::MapType::Filters) {
+    /* special case, this is a map of eBPF programs */
+    d_fd = FDWrapper(bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), d_config.d_maxItems, 0));
+    if (d_fd.getHandle() == -1) {
+      throw std::runtime_error("Error creating a BPF program map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
+    }
+  }
+  else {
+    int keySize = 0;
+    int valueSize = 0;
+    int flags = 0;
+    bpf_map_type type = BPF_MAP_TYPE_HASH;
+    if (format == MapFormat::Legacy) {
+      switch (d_config.d_type) {
+      case MapType::IPv4:
+        keySize = sizeof(uint32_t);
+        valueSize = sizeof(uint64_t);
+        break;
+      case MapType::IPv6:
+        keySize = sizeof(KeyV6);
+        valueSize = sizeof(uint64_t);
+        break;
+      case MapType::QNames:
+        keySize = sizeof(QNameKey);
+        valueSize = sizeof(QNameValue);
+        break;
+      default:
+        throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)) + " for legacy eBPF, perhaps you are trying to use an external program instead?");
+      }
+    }
+    else {
+      switch (d_config.d_type) {
+      case MapType::IPv4:
+        keySize = sizeof(uint32_t);
+        valueSize = sizeof(CounterAndActionValue);
+        break;
+      case MapType::IPv6:
+        keySize = sizeof(KeyV6);
+        valueSize = sizeof(CounterAndActionValue);
+        break;
+      case MapType::CIDR4:
+        keySize = sizeof(CIDR4);
+        valueSize = sizeof(CounterAndActionValue);
+        flags = BPF_F_NO_PREALLOC;
+        type = BPF_MAP_TYPE_LPM_TRIE;
+        break;
+      case MapType::CIDR6:
+        keySize = sizeof(CIDR6);
+        valueSize = sizeof(CounterAndActionValue);
+        flags = BPF_F_NO_PREALLOC;
+        type = BPF_MAP_TYPE_LPM_TRIE;
+        break;
+      case MapType::QNames:
+        keySize = sizeof(QNameAndQTypeKey);
+        valueSize = sizeof(CounterAndActionValue);
+        break;
+      default:
+        throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
+      }
+    }
+
+    if (!d_config.d_pinnedPath.empty()) {
+      /* try to load */
+      d_fd = FDWrapper(bpf_load_pinned_map(d_config.d_pinnedPath));
+      if (d_fd.getHandle() != -1) {
+        /* sanity checks: key and value size */
+        bpf_check_map_sizes(d_fd.getHandle(), keySize, valueSize);
+        switch (d_config.d_type) {
+        case MapType::IPv4: {
+          uint32_t key = 0;
+          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+            ++d_count;
+          }
+          break;
+        }
+        case MapType::IPv6: {
+          KeyV6 key;
+          memset(&key, 0, sizeof(key));
+          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+            ++d_count;
+          }
+          break;
+        }
+        case MapType::CIDR4: {
+          CIDR4 key;
+          memset(&key, 0, sizeof(key));
+          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+            ++d_count;
+          }
+          break;
+        }
+        case MapType::CIDR6: {
+          CIDR6 key;
+          memset(&key, 0, sizeof(key));
+          while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+            ++d_count;
+          }
+          break;
+        }
+        case MapType::QNames: {
+          if (format == MapFormat::Legacy) {
+            QNameKey key;
+            memset(&key, 0, sizeof(key));
+            while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+              ++d_count;
+            }
+          }
+          else {
+            QNameAndQTypeKey key;
+            memset(&key, 0, sizeof(key));
+            while (bpf_get_next_key(d_fd.getHandle(), &key, &key) == 0) {
+              ++d_count;
+            }
+          }
+          break;
+        }
+
+        default:
+          throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
+        }
+      }
+    }
+
+    if (d_fd.getHandle() == -1) {
+      d_fd = FDWrapper(bpf_create_map(type, keySize, valueSize, static_cast<int>(d_config.d_maxItems), flags));
+      if (d_fd.getHandle() == -1) {
+        throw std::runtime_error("Error creating a BPF map of size " + std::to_string(d_config.d_maxItems) + ": " + stringerror());
+      }
+
+      if (!d_config.d_pinnedPath.empty()) {
+        if (bpf_pin_map(d_fd.getHandle(), d_config.d_pinnedPath) != 0) {
+          throw std::runtime_error("Unable to pin map to path '" + d_config.d_pinnedPath + "': " + stringerror());
+        }
+      }
+    }
+  }
+}
+
+static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize)
+{
+  auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
+                                            filter,
+                                            filterSize,
+                                            "GPL",
+                                            0));
+  if (descriptor.getHandle() == -1) {
+    throw std::runtime_error("error loading BPF filter: " + stringerror());
+  }
+  return descriptor;
+}
+
+BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external) :
+  d_mapFormat(format), d_external(external)
+{
+  if (d_mapFormat != BPFFilter::MapFormat::Legacy && !d_external) {
+    throw std::runtime_error("Unsupported eBPF map format, the current internal implemenation only supports the legacy format");
+  }
+
+  struct rlimit old_limit;
+  if (getrlimit(RLIMIT_MEMLOCK, &old_limit) != 0) {
+    throw std::runtime_error("Unable to get memory lock limit: " + stringerror());
+  }
+
+  const rlim_t new_limit_size = 1024 * 1024;
+
+  /* Check if the current soft memlock limit is at least the limit */
+  if (old_limit.rlim_cur < new_limit_size) {
+    infolog("The current limit of locked memory (soft: %d, hard: %d) is too low for eBPF, trying to raise it to %d", old_limit.rlim_cur, old_limit.rlim_max, new_limit_size);
+
+    struct rlimit new_limit;
+    new_limit.rlim_cur = new_limit_size;
+    new_limit.rlim_max = new_limit_size;
+
+    if (setrlimit(RLIMIT_MEMLOCK, &new_limit) != 0) {
+      warnlog("Unable to raise the maximum amount of locked memory for eBPF from %d to %d, consider raising RLIMIT_MEMLOCK or setting LimitMEMLOCK in the systemd unit: %d", old_limit.rlim_cur, new_limit.rlim_cur, stringerror());
+    }
+  }
+
+  auto maps = d_maps.lock();
+
+  maps->d_v4 = BPFFilter::Map(configs["ipv4"], d_mapFormat);
+  maps->d_v6 = BPFFilter::Map(configs["ipv6"], d_mapFormat);
+  maps->d_qnames = BPFFilter::Map(configs["qnames"], d_mapFormat);
+
+  if (d_mapFormat != BPFFilter::MapFormat::Legacy) {
+    maps->d_cidr4 = BPFFilter::Map(configs["cidr4"], d_mapFormat);
+    maps->d_cidr6 = BPFFilter::Map(configs["cidr6"], d_mapFormat);
+  }
+
+  if (!external) {
+    BPFFilter::MapConfiguration filters;
+    filters.d_maxItems = 1;
+    filters.d_type = BPFFilter::MapType::Filters;
+    maps->d_filters = BPFFilter::Map(std::move(filters), d_mapFormat);
+
+    const struct bpf_insn main_filter[] = {
+#include "bpf-filter.main.ebpf"
+    };
+
+    const struct bpf_insn qname_filter[] = {
+#include "bpf-filter.qname.ebpf"
+    };
+
+    try {
+      d_mainfilter = loadProgram(main_filter,
+                                 sizeof(main_filter));
+    }
+    catch (const std::exception& e) {
+      throw std::runtime_error("Error load the main eBPF filter: " + std::string(e.what()));
+    }
+
+    try {
+      d_qnamefilter = loadProgram(qname_filter,
+                                  sizeof(qname_filter));
+    }
+    catch (const std::exception& e) {
+      throw std::runtime_error("Error load the qname eBPF filter: " + std::string(e.what()));
+    }
+
+    uint32_t key = 0;
+    int qnamefd = d_qnamefilter.getHandle();
+    int res = bpf_update_elem(maps->d_filters.d_fd.getHandle(), &key, &qnamefd, BPF_ANY);
+    if (res != 0) {
+      throw std::runtime_error("Error updating BPF filters map: " + stringerror());
+    }
+  }
+}
+
+void BPFFilter::addSocket(int sock)
+{
+  int descriptor = d_mainfilter.getHandle();
+  int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor));
+
+  if (res != 0) {
+    throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror());
+  }
+}
+
+void BPFFilter::removeSocket(int sock)
+{
+  int descriptor = d_mainfilter.getHandle();
+  int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor));
+
+  if (res != 0) {
+    throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror());
+  }
+}
+
+void BPFFilter::block(const ComboAddress& addr, BPFFilter::MatchAction action)
+{
+  CounterAndActionValue value;
+  value.counter = 0;
+  value.action = action;
+
+  int res = 0;
+  if (addr.isIPv4()) {
+    uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v4;
+    if (map.d_count >= map.d_config.d_maxItems) {
+      throw std::runtime_error("Table full when trying to block " + addr.toString());
+    }
+
+    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+    if (res != -1) {
+      throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
+    }
+
+    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
+    if (res == 0) {
+      ++map.d_count;
+    }
+  }
+  else if (addr.isIPv6()) {
+    uint8_t key[16];
+    static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+    for (size_t idx = 0; idx < sizeof(key); idx++) {
+      key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
+    }
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v6;
+    if (map.d_count >= map.d_config.d_maxItems) {
+      throw std::runtime_error("Table full when trying to block " + addr.toString());
+    }
+
+    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+    if (res != -1) {
+      throw std::runtime_error("Trying to block an already blocked address: " + addr.toString());
+    }
+
+    res = bpf_update_elem(map.d_fd.getHandle(), key, &value, BPF_NOEXIST);
+    if (res == 0) {
+      map.d_count++;
+    }
+  }
+
+  if (res != 0) {
+    throw std::runtime_error("Error adding blocked address " + addr.toString() + ": " + stringerror());
+  }
+}
+
+void BPFFilter::unblock(const ComboAddress& addr)
+{
+  int res = 0;
+  if (addr.isIPv4()) {
+    uint32_t key = htonl(addr.sin4.sin_addr.s_addr);
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v4;
+    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+    if (res == 0) {
+      --map.d_count;
+    }
+  }
+  else if (addr.isIPv6()) {
+    uint8_t key[16];
+    static_assert(sizeof(addr.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+    for (size_t idx = 0; idx < sizeof(key); idx++) {
+      key[idx] = addr.sin6.sin6_addr.s6_addr[idx];
+    }
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v6;
+    res = bpf_delete_elem(map.d_fd.getHandle(), key);
+    if (res == 0) {
+      --map.d_count;
+    }
+  }
+
+  if (res != 0) {
+    throw std::runtime_error("Error removing blocked address " + addr.toString() + ": " + stringerror());
+  }
+}
+
+void BPFFilter::addRangeRule(const Netmask& addr, bool force, BPFFilter::MatchAction action)
+{
+  CounterAndActionValue value;
+
+  int res = 0;
+  if (addr.isIPv4()) {
+    CIDR4 key(addr);
+    auto maps = d_maps.lock();
+    auto& map = maps->d_cidr4;
+    if (map.d_fd.getHandle() == -1) {
+      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+    }
+    if (map.d_count >= map.d_config.d_maxItems) {
+      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
+    }
+
+    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
+    }
+
+    value.counter = 0;
+    value.action = action;
+
+    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, force ? BPF_ANY : BPF_NOEXIST);
+    if (res == 0) {
+      ++map.d_count;
+    }
+  }
+  else if (addr.isIPv6()) {
+    CIDR6 key(addr);
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_cidr6;
+    if (map.d_fd.getHandle() == -1) {
+      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+    }
+    if (map.d_count >= map.d_config.d_maxItems) {
+      throw std::runtime_error("Table full when trying to add this rule: " + addr.toString());
+    }
+
+    res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &value);
+    if (((res != -1 && value.action == action) || (res == -1 && value.action == BPFFilter::MatchAction::Pass)) && !force) {
+      throw std::runtime_error("Trying to add a useless rule: " + addr.toString());
+    }
+
+    value.counter = 0;
+    value.action = action;
+
+    res = bpf_update_elem(map.d_fd.getHandle(), &key, &value, BPF_NOEXIST);
+    if (res == 0) {
+      map.d_count++;
+    }
+  }
+
+  if (res != 0) {
+    throw std::runtime_error("Error adding this rule: " + addr.toString() + ": " + stringerror());
+  }
+}
+
+void BPFFilter::rmRangeRule(const Netmask& addr)
+{
+  int res = 0;
+  CounterAndActionValue value;
+  value.counter = 0;
+  value.action = MatchAction::Pass;
+  if (addr.isIPv4()) {
+    CIDR4 key(addr);
+    auto maps = d_maps.lock();
+    auto& map = maps->d_cidr4;
+    if (map.d_fd.getHandle() == -1) {
+      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+    }
+    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+    if (res == 0) {
+      --map.d_count;
+    }
+    else {
+      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
+    }
+  }
+  else if (addr.isIPv6()) {
+    CIDR6 key(addr);
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_cidr6;
+    if (map.d_fd.getHandle() == -1) {
+      throw std::runtime_error("Trying to use an unsupported map type, likely adding a range to a legacy eBPF program");
+    }
+    res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+    if (res == 0) {
+      --map.d_count;
+    }
+    else {
+      throw std::runtime_error("Cannot remove '" + addr.toString() + "': No such rule");
+    }
+  }
+
+  if (res != 0) {
+    throw std::runtime_error("Error removing this rule: " + addr.toString() + ": " + stringerror());
+  }
+}
+
+void BPFFilter::block(const DNSName& qname, BPFFilter::MatchAction action, uint16_t qtype)
+{
+  CounterAndActionValue cadvalue;
+  QNameValue qvalue;
+  void* value = nullptr;
+
+  if (d_external) {
+    cadvalue.counter = 0;
+    cadvalue.action = action;
+    value = &cadvalue;
+  }
+  else {
+    qvalue.counter = 0;
+    qvalue.qtype = qtype;
+    value = &qvalue;
+  }
+
+  QNameAndQTypeKey key;
+  memset(&key, 0, sizeof(key));
+
+  std::string keyStr = qname.toDNSStringLC();
+  if (keyStr.size() > sizeof(key.qname)) {
+    throw std::runtime_error("Invalid QName to block " + qname.toLogString());
+  }
+  memcpy(key.qname, keyStr.c_str(), keyStr.size());
+  key.qtype = qtype;
+
+  {
+    auto maps = d_maps.lock();
+    auto& map = maps->d_qnames;
+    if (map.d_count >= map.d_config.d_maxItems) {
+      throw std::runtime_error("Table full when trying to block " + qname.toLogString());
+    }
+
+    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, value);
+    if (res != -1) {
+      throw std::runtime_error("Trying to block an already blocked qname: " + qname.toLogString());
+    }
+    res = bpf_update_elem(map.d_fd.getHandle(), &key, value, BPF_NOEXIST);
+    if (res == 0) {
+      ++map.d_count;
+    }
+
+    if (res != 0) {
+      throw std::runtime_error("Error adding blocked qname " + qname.toLogString() + ": " + stringerror());
+    }
+  }
+}
+
+void BPFFilter::unblock(const DNSName& qname, uint16_t qtype)
+{
+  QNameAndQTypeKey key;
+  memset(&key, 0, sizeof(key));
+  std::string keyStr = qname.toDNSStringLC();
+
+  if (keyStr.size() > sizeof(key.qname)) {
+    throw std::runtime_error("Invalid QName to block " + qname.toLogString());
+  }
+  memcpy(key.qname, keyStr.c_str(), keyStr.size());
+  key.qtype = qtype;
+
+  {
+    auto maps = d_maps.lock();
+    auto& map = maps->d_qnames;
+    int res = bpf_delete_elem(map.d_fd.getHandle(), &key);
+    if (res == 0) {
+      --map.d_count;
+    }
+    else {
+      throw std::runtime_error("Error removing qname address " + qname.toLogString() + ": " + stringerror());
+    }
+  }
+}
+
+std::vector<std::pair<ComboAddress, uint64_t>> BPFFilter::getAddrStats()
+{
+  std::vector<std::pair<ComboAddress, uint64_t>> result;
+  {
+    auto maps = d_maps.lock();
+    result.reserve(maps->d_v4.d_count + maps->d_v6.d_count);
+  }
+
+  sockaddr_in v4Addr{};
+  memset(&v4Addr, 0, sizeof(v4Addr));
+  v4Addr.sin_family = AF_INET;
+
+  uint32_t v4Key = 0;
+  uint32_t nextV4Key{};
+  CounterAndActionValue value{};
+
+  std::array<uint8_t, 16> v6Key{};
+  std::array<uint8_t, 16> nextV6Key{};
+  sockaddr_in6 v6Addr{};
+  memset(&v6Addr, 0, sizeof(v6Addr));
+  v6Addr.sin6_family = AF_INET6;
+
+  static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+  memset(&v6Key, 0, sizeof(v6Key));
+
+  auto maps = d_maps.lock();
+
+  {
+    auto& map = maps->d_v4;
+    int res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
+
+    while (res == 0) {
+      v4Key = nextV4Key;
+      if (bpf_lookup_elem(map.d_fd.getHandle(), &v4Key, &value) == 0) {
+        v4Addr.sin_addr.s_addr = ntohl(v4Key);
+        result.emplace_back(ComboAddress(&v4Addr), value.counter);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), &v4Key, &nextV4Key);
+    }
+  }
+
+  {
+    auto& map = maps->d_v6;
+    int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data());
+
+    while (res == 0) {
+      if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) {
+        memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size());
+
+        result.emplace_back(ComboAddress(&v6Addr), value.counter);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data());
+    }
+  }
+
+  return result;
+}
+
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
+{
+  CIDR4 cidr4[2];
+  CIDR6 cidr6[2];
+  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
+
+  sockaddr_in v4Addr;
+  sockaddr_in6 v6Addr;
+  CounterAndActionValue value;
+
+  memset(cidr4, 0, sizeof(cidr4));
+  memset(cidr6, 0, sizeof(cidr6));
+  memset(&v4Addr, 0, sizeof(v4Addr));
+  memset(&v6Addr, 0, sizeof(v6Addr));
+  v4Addr.sin_family = AF_INET;
+  v6Addr.sin6_family = AF_INET6;
+  auto maps = d_maps.lock();
+  result.reserve(maps->d_cidr4.d_count + maps->d_cidr6.d_count);
+  {
+    auto& map = maps->d_cidr4;
+    int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[0], &cidr4[1]);
+    while (res == 0) {
+      if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr4[1], &value) == 0) {
+        v4Addr.sin_addr.s_addr = cidr4[1].addr.s_addr;
+        result.emplace_back(Netmask(&v4Addr, cidr4[1].cidr), value);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), &cidr4[1], &cidr4[1]);
+    }
+  }
+
+  {
+    auto& map = maps->d_cidr6;
+    int res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[0], &cidr6[1]);
+    while (res == 0) {
+      if (bpf_lookup_elem(map.d_fd.getHandle(), &cidr6[1], &value) == 0) {
+        v6Addr.sin6_addr = cidr6[1].addr;
+        result.emplace_back(Netmask(&v6Addr, cidr6[1].cidr), value);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), &cidr6[1], &cidr6[1]);
+    }
+  }
+  return result;
+}
+
+std::vector<std::tuple<DNSName, uint16_t, uint64_t>> BPFFilter::getQNameStats()
+{
+  std::vector<std::tuple<DNSName, uint16_t, uint64_t>> result;
+
+  if (d_mapFormat == MapFormat::Legacy) {
+    QNameKey key = {{0}};
+    QNameKey nextKey = {{0}};
+    QNameValue value;
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_qnames;
+    result.reserve(map.d_count);
+    int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
+
+    while (res == 0) {
+      if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
+        nextKey.qname[sizeof(nextKey.qname) - 1] = '\0';
+        result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
+    }
+  }
+  else {
+    QNameAndQTypeKey key;
+    QNameAndQTypeKey nextKey;
+    memset(&key, 0, sizeof(key));
+    memset(&nextKey, 0, sizeof(nextKey));
+    CounterAndActionValue value;
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_qnames;
+    result.reserve(map.d_count);
+    int res = bpf_get_next_key(map.d_fd.getHandle(), &key, &nextKey);
+
+    while (res == 0) {
+      if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
+        nextKey.qname[sizeof(nextKey.qname) - 1] = '\0';
+        result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter);
+      }
+
+      res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
+    }
+  }
+
+  return result;
+}
+
+uint64_t BPFFilter::getHits(const ComboAddress& requestor)
+{
+  CounterAndActionValue counter;
+
+  if (requestor.isIPv4()) {
+    uint32_t key = htonl(requestor.sin4.sin_addr.s_addr);
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v4;
+    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
+    if (res == 0) {
+      return counter.counter;
+    }
+  }
+  else if (requestor.isIPv6()) {
+    uint8_t key[16];
+    static_assert(sizeof(requestor.sin6.sin6_addr.s6_addr) == sizeof(key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+    for (size_t idx = 0; idx < sizeof(key); idx++) {
+      key[idx] = requestor.sin6.sin6_addr.s6_addr[idx];
+    }
+
+    auto maps = d_maps.lock();
+    auto& map = maps->d_v6;
+    int res = bpf_lookup_elem(map.d_fd.getHandle(), &key, &counter);
+    if (res == 0) {
+      return counter.counter;
+    }
+  }
+
+  return 0;
+}
+
+#else
+
+BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external)
+{
+}
+
+void BPFFilter::addSocket(int)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::removeSocket(int)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::block(const ComboAddress&, BPFFilter::MatchAction)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::unblock(const ComboAddress&)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::block(const DNSName&, BPFFilter::MatchAction, uint16_t)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::unblock(const DNSName&, uint16_t)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+void BPFFilter::addRangeRule(const Netmask&, bool, BPFFilter::MatchAction)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+void BPFFilter::rmRangeRule(const Netmask&)
+{
+  throw std::runtime_error("eBPF support not enabled");
+}
+
+std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule()
+{
+  std::vector<std::pair<Netmask, CounterAndActionValue>> result;
+  return result;
+}
+std::vector<std::pair<ComboAddress, uint64_t>> BPFFilter::getAddrStats()
+{
+  std::vector<std::pair<ComboAddress, uint64_t>> result;
+  return result;
+}
+
+std::vector<std::tuple<DNSName, uint16_t, uint64_t>> BPFFilter::getQNameStats()
+{
+  std::vector<std::tuple<DNSName, uint16_t, uint64_t>> result;
+  return result;
+}
+
+uint64_t BPFFilter::getHits(const ComboAddress&)
+{
+  return 0;
+}
+#endif /* HAVE_EBPF */
+
+bool BPFFilter::supportsMatchAction(MatchAction action) const
+{
+#ifdef HAVE_EBPF
+  if (action == BPFFilter::MatchAction::Drop) {
+    return true;
+  }
+  return d_mapFormat == BPFFilter::MapFormat::WithActions;
+#endif /* HAVE_EBPF */
+  return false;
+}
+
+bool BPFFilter::isExternal() const
+{
+#ifdef HAVE_EBPF
+  return d_external;
+#endif /* HAVE_EBPF */
+  return false;
+}
deleted file mode 120000 (symlink)
index e3c87ff0e9242c570a4036b99083ee138b6d5c25..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../bpf-filter.ebpf.src
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..9f58669068761bf0b271eddd4e01653cdf1806d0
--- /dev/null
@@ -0,0 +1,503 @@
+
+#include <net/sock.h>
+#include <linux/types.h>
+#include <uapi/linux/tcp.h>
+#include <uapi/linux/udp.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/ipv6.h>
+#include <bcc/proto.h>
+
+struct dnsheader {
+        unsigned        id :16;         /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+                        /* fields in third byte */
+        unsigned        qr: 1;          /* response flag */
+        unsigned        opcode: 4;      /* purpose of message */
+        unsigned        aa: 1;          /* authoritative answer */
+        unsigned        tc: 1;          /* truncated message */
+        unsigned        rd: 1;          /* recursion desired */
+                        /* fields in fourth byte */
+        unsigned        ra: 1;          /* recursion available */
+        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
+        unsigned        ad: 1;          /* authentic data from named */
+        unsigned        cd: 1;          /* checking disabled by resolver */
+        unsigned        rcode :4;       /* response code */
+#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+                        /* fields in third byte */
+        unsigned        rd :1;          /* recursion desired */
+        unsigned        tc :1;          /* truncated message */
+        unsigned        aa :1;          /* authoritative answer */
+        unsigned        opcode :4;      /* purpose of message */
+        unsigned        qr :1;          /* response flag */
+                        /* fields in fourth byte */
+        unsigned        rcode :4;       /* response code */
+        unsigned        cd: 1;          /* checking disabled by resolver */
+        unsigned        ad: 1;          /* authentic data from named */
+        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
+        unsigned        ra :1;          /* recursion available */
+#endif
+                        /* remaining bytes */
+        unsigned        qdcount :16;    /* number of question entries */
+        unsigned        ancount :16;    /* number of answer entries */
+        unsigned        nscount :16;    /* number of authority entries */
+        unsigned        arcount :16;    /* number of resource entries */
+};
+
+struct QNameKey
+{
+  uint8_t qname[255];
+};
+
+struct KeyV6
+{
+  uint8_t src[16];
+};
+
+struct QNameValue
+{
+  u64 counter;
+  u16 qtype;
+};
+
+BPF_TABLE("hash", u32, u64, v4filter, 1024);
+BPF_TABLE("hash", struct KeyV6, u64, v6filter, 1024);
+BPF_TABLE("hash", struct QNameKey, struct QNameValue, qnamefilter, 1024);
+BPF_TABLE("prog", int, int, progsarray, 1);
+
+int bpf_qname_filter(struct __sk_buff *skb)
+{
+  uint32_t qname_off = skb->cb[0];
+  ssize_t labellen = skb->cb[3];
+  size_t idx = 2;
+  struct QNameKey qkey = { 0 };
+  u32 val = skb->cb[1];
+  if (val) {
+    qkey.qname[0] = val;
+  }
+  val = skb->cb[2];
+  if (val) {
+    qkey.qname[1] = val;
+  }
+  uint8_t temp;
+
+#define FILL_ONE_KEY                                    \
+  temp = load_byte(skb, qname_off + idx);               \
+  labellen--;                                           \
+  if (labellen < 0) {                                   \
+    labellen = temp;                                    \
+    if (labellen == 0) {                                \
+      goto end;                                         \
+    }                                                   \
+  } else if (temp >= 'A' && temp <= 'Z') {              \
+    temp += ('a' - 'A');                                \
+  }                                                     \
+  qkey.qname[idx] = temp;                               \
+  idx++;
+
+  /* 2 - 52 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* 52 - 102 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* 102 - 152 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* 152 - 202 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* 202 - 252 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* 252 - 254 */
+  FILL_ONE_KEY
+  FILL_ONE_KEY
+
+  /* the only value that makes sense for
+     qkey.qname[255] is 0, and it's already
+     there */
+  end:
+
+  {
+    idx++;
+    u16 qtype = load_half(skb, (qname_off + idx));
+
+    struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
+    if (qvalue &&
+      (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
+      __sync_fetch_and_add(&qvalue->counter, 1);
+      return 0;
+    }
+  }
+
+  return 2147483647;
+}
+
+int bpf_dns_filter(struct __sk_buff *skb) {
+  u8 ip_proto;
+  int proto_off;
+  /* nh_off will contain a negative offset, used in BPF to get access to
+     the MAC/network layers, as positive values are used to get access to
+     the transport layer */
+  int nh_off = BPF_LL_OFF + ETH_HLEN;
+
+  if (skb->protocol == ntohs(0x0800)) {
+    u32 key;
+    int off = nh_off + offsetof(struct iphdr, saddr);
+    key = load_word(skb, off);
+
+    u64* counter = v4filter.lookup(&key);
+    if (counter) {
+      __sync_fetch_and_add(counter, 1);
+      return 0;
+    }
+
+    ip_proto = load_byte(skb, nh_off + offsetof(struct iphdr, protocol));
+    proto_off = nh_off + sizeof(struct iphdr);
+  }
+  else if (skb->protocol == ntohs(0x86DD)) {
+    struct KeyV6 key;
+    int off = nh_off + offsetof(struct ipv6hdr, saddr);
+    key.src[0] = load_byte(skb, off++);
+    key.src[1] = load_byte(skb, off++);
+    key.src[2] = load_byte(skb, off++);
+    key.src[3] = load_byte(skb, off++);
+    key.src[4] = load_byte(skb, off++);
+    key.src[5] = load_byte(skb, off++);
+    key.src[6] = load_byte(skb, off++);
+    key.src[7] = load_byte(skb, off++);
+    key.src[8] = load_byte(skb, off++);
+    key.src[9] = load_byte(skb, off++);
+    key.src[10] = load_byte(skb, off++);
+    key.src[11] = load_byte(skb, off++);
+    key.src[12] = load_byte(skb, off++);
+    key.src[13] = load_byte(skb, off++);
+    key.src[14] = load_byte(skb, off++);
+    key.src[15] = load_byte(skb, off++);
+
+    u64* counter = v6filter.lookup(&key);
+    if (counter) {
+      __sync_fetch_and_add(counter, 1);
+      return 0;
+    }
+
+    ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
+    proto_off = nh_off + sizeof(struct ipv6hdr);
+  }
+  else {
+    /* neither IPv4 not IPv6, well */
+    return 2147483647;
+  }
+
+  /* allow TCP */
+  if (ip_proto == IPPROTO_TCP) {
+    return 2147483647;
+  }
+
+  struct QNameKey qkey = { 0 };
+  /* switch to positive offsets here, as we have seen some issues
+     when accessing the content of the transport layer with negative offsets
+     https://github.com/PowerDNS/pdns/issues/9626 */
+  int dns_off = sizeof(struct udphdr);
+  int qname_off = dns_off + sizeof(struct dnsheader);
+  skb->cb[0] = (uint32_t) qname_off;
+  u16 qtype;
+
+  uint8_t temp = load_byte(skb, qname_off);
+  if (temp > 63) {
+    return 0;
+  }
+
+  if (temp == 0) {
+    /* root, nothing else to see */
+    qtype = load_half(skb, (qname_off + 1));
+
+    struct QNameValue* qvalue = qnamefilter.lookup(&qkey);
+    if (qvalue &&
+      (qvalue->qtype == 255 || qtype == qvalue->qtype)) {
+      __sync_fetch_and_add(&qvalue->counter, 1);
+      return 0;
+    }
+    return 2147483647;
+  }
+
+  ssize_t labellen = temp;
+  skb->cb[1] = temp;
+  qkey.qname[0] = temp;
+
+  temp = load_byte(skb, qname_off + 1);
+  labellen--;
+  if (temp >= 'A' && temp <= 'Z') {
+    temp += ('a' - 'A');
+  }
+  skb->cb[2] = temp;
+  skb->cb[3] = labellen;
+  progsarray.call(skb, 0);
+
+  return 2147483647;
+}
deleted file mode 120000 (symlink)
index e98b996ed5ab30b38d9e9b24601c9b6e7abea6e1..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../bpf-filter.hh
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..46b7eed9dc1bb3ed7fe11ceea2ad7fe4764adf3a
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "config.h"
+
+#include <unordered_map>
+
+#include "iputils.hh"
+#include "lock.hh"
+#include <netinet/in.h>
+#include <stdexcept>
+
+class BPFFilter
+{
+public:
+  enum class MapType : uint8_t
+  {
+    IPv4,
+    IPv6,
+    QNames,
+    Filters,
+    CIDR4,
+    CIDR6
+  };
+
+  enum class MapFormat : uint8_t
+  {
+    Legacy = 0,
+    WithActions = 1
+  };
+
+  enum class MatchAction : uint8_t
+  {
+    Pass = 0,
+    Drop = 1,
+    Truncate = 2
+  };
+  static std::string toString(MatchAction s) noexcept
+  {
+    switch (s) {
+    case MatchAction::Pass:
+      return "Pass";
+    case MatchAction::Drop:
+      return "Drop";
+    case MatchAction::Truncate:
+      return "Truncate";
+    }
+    return "Unknown";
+  }
+
+  struct MapConfiguration
+  {
+    std::string d_pinnedPath;
+    uint32_t d_maxItems{0};
+    MapType d_type;
+  };
+
+  struct CounterAndActionValue
+  {
+    uint64_t counter{0};
+    BPFFilter::MatchAction action{BPFFilter::MatchAction::Pass};
+  };
+
+  BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs, BPFFilter::MapFormat format, bool external);
+  BPFFilter(const BPFFilter&) = delete;
+  BPFFilter(BPFFilter&&) = delete;
+  BPFFilter& operator=(const BPFFilter&) = delete;
+  BPFFilter& operator=(BPFFilter&&) = delete;
+
+  void addSocket(int sock);
+  void removeSocket(int sock);
+  void block(const ComboAddress& addr, MatchAction action);
+  void addRangeRule(const Netmask& address, bool force, BPFFilter::MatchAction action);
+  void block(const DNSName& qname, MatchAction action, uint16_t qtype = 255);
+  void unblock(const ComboAddress& addr);
+  void rmRangeRule(const Netmask& address);
+  void unblock(const DNSName& qname, uint16_t qtype = 255);
+
+  std::vector<std::pair<ComboAddress, uint64_t>> getAddrStats();
+  std::vector<std::pair<Netmask, CounterAndActionValue>> getRangeRule();
+  std::vector<std::tuple<DNSName, uint16_t, uint64_t>> getQNameStats();
+
+  uint64_t getHits(const ComboAddress& requestor);
+
+  bool supportsMatchAction(MatchAction action) const;
+  bool isExternal() const;
+
+private:
+#ifdef HAVE_EBPF
+  struct Map
+  {
+    Map()
+    {
+    }
+    Map(MapConfiguration, MapFormat);
+    MapConfiguration d_config;
+    uint32_t d_count{0};
+    FDWrapper d_fd;
+  };
+
+  struct Maps
+  {
+    Map d_v4;
+    Map d_v6;
+    Map d_cidr4;
+    Map d_cidr6;
+    Map d_qnames;
+    /* The qname filter program held in d_qnamefilter is
+       stored in an eBPF map, so we can call it from the
+       main filter. This is the only entry in that map. */
+    Map d_filters;
+  };
+
+  LockGuarded<Maps> d_maps;
+
+  /* main eBPF program */
+  FDWrapper d_mainfilter;
+  /* qname filtering program */
+  FDWrapper d_qnamefilter;
+  struct CIDR4
+  {
+    uint32_t cidr;
+    struct in_addr addr;
+    explicit CIDR4(Netmask address)
+    {
+      if (!address.isIPv4()) {
+        throw std::runtime_error("ComboAddress is invalid");
+      }
+      addr = address.getNetwork().sin4.sin_addr;
+      cidr = address.getBits();
+    }
+    CIDR4() = default;
+  };
+  struct CIDR6
+  {
+    uint32_t cidr;
+    struct in6_addr addr;
+    CIDR6(Netmask address)
+    {
+      if (!address.isIPv6()) {
+        throw std::runtime_error("ComboAddress is invalid");
+      }
+      addr = address.getNetwork().sin6.sin6_addr;
+      cidr = address.getBits();
+    }
+    CIDR6() = default;
+  };
+  /* whether the maps are in the 'old' format, which we need
+     to keep to prevent going over the 4k instructions per eBPF
+     program limit in kernels < 5.2, as well as the complexity limit:
+     - 32k in Linux 3.18
+     - 64k in Linux 4.7
+     - 96k in Linux 4.12
+     - 128k in Linux 4.14,
+     - 1M in Linux 5.2 */
+  MapFormat d_mapFormat;
+
+  /* whether the filter is internal, using our own eBPF programs,
+     or external where we only update the maps but the filtering is
+     done by an external program. */
+  bool d_external;
+#endif /* HAVE_EBPF */
+};
+using CounterAndActionValue = BPFFilter::CounterAndActionValue;
deleted file mode 120000 (symlink)
index 3efd5178a2eecef00e7acdd52019bdef33d7445e..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../bpf-filter.main.ebpf
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..4b42a2ec6b71ea0237e7808d2782716bfee9b35f
--- /dev/null
@@ -0,0 +1,136 @@
+/* generated from the bpf_dns_filter() function in bpf-filter.ebpf.src */
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,16),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,ntohs(0x86dd),11),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_1,ntohs(0x0800),109),
+BPF_LD_ABS(BPF_W,-2097126),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_0,-256),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_v4.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,98),
+BPF_LD_ABS(BPF_B,-2097129),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,39),
+BPF_LD_ABS(BPF_B,-2097130),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-256),
+BPF_LD_ABS(BPF_B,-2097129),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-255),
+BPF_LD_ABS(BPF_B,-2097128),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
+BPF_LD_ABS(BPF_B,-2097127),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
+BPF_LD_ABS(BPF_B,-2097126),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
+BPF_LD_ABS(BPF_B,-2097125),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
+BPF_LD_ABS(BPF_B,-2097124),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
+BPF_LD_ABS(BPF_B,-2097123),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
+BPF_LD_ABS(BPF_B,-2097122),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
+BPF_LD_ABS(BPF_B,-2097121),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
+BPF_LD_ABS(BPF_B,-2097120),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
+BPF_LD_ABS(BPF_B,-2097119),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
+BPF_LD_ABS(BPF_B,-2097118),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
+BPF_LD_ABS(BPF_B,-2097117),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
+BPF_LD_ABS(BPF_B,-2097116),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
+BPF_LD_ABS(BPF_B,-2097115),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_v6.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_0,0,58),
+BPF_LD_ABS(BPF_B,-2097132),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_0,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,6,58),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
+BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
+BPF_MOV64_IMM(BPF_REG_1,20),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,48),
+BPF_LD_ABS(BPF_B,20),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_MOV64_IMM(BPF_REG_7,0),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_8,63,17),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,18),
+BPF_LD_ABS(BPF_H,21),
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
+BPF_LDX_MEM(BPF_H,BPF_REG_1,BPF_REG_0,8),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,255,2),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
+BPF_JMP_REG(BPF_JNE,BPF_REG_1,BPF_REG_6,3),
+BPF_MOV64_IMM(BPF_REG_1,1),
+BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
+BPF_MOV64_IMM(BPF_REG_7,0),
+BPF_MOV64_REG(BPF_REG_0,BPF_REG_7),
+BPF_EXIT_INSN(),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,52),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_8,-256),
+BPF_LD_ABS(BPF_B,21),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-65),
+BPF_ALU64_IMM(BPF_LSH,BPF_REG_2,32),
+BPF_ALU64_IMM(BPF_RSH,BPF_REG_2,32),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,32),
+BPF_MOV64_IMM(BPF_REG_3,26),
+BPF_JMP_REG(BPF_JGT,BPF_REG_3,BPF_REG_2,1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_8,60),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_STX_MEM(BPF_W,BPF_REG_6,BPF_REG_1,56),
+BPF_LD_MAP_FD(BPF_REG_2,maps->d_filters.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_6),
+BPF_MOV64_IMM(BPF_REG_3,0),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_tail_call),
+BPF_MOV64_IMM(BPF_REG_7,2147483647),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,-25),
deleted file mode 120000 (symlink)
index fd55ecbcf9221a1d4c46d3ae8c3432f1d759be29..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../bpf-filter.qname.ebpf
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..c7d6094c0872ed85619131878bdc6b595d7ba037
--- /dev/null
+/* generated from the bpf_qname_filter() function in bpf-filter.ebpf.src */
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_1),
+BPF_LDX_MEM(BPF_W,BPF_REG_8,BPF_REG_6,60),
+BPF_LDX_MEM(BPF_W,BPF_REG_7,BPF_REG_6,48),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-2),
+BPF_STX_MEM(BPF_H,BPF_REG_10,BPF_REG_1,-4),
+BPF_STX_MEM(BPF_W,BPF_REG_10,BPF_REG_1,-8),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-16),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-24),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-32),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-40),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-48),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-56),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-64),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-72),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-80),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-88),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-96),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-104),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-112),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-120),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-128),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-136),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-144),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-152),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-160),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-168),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-176),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-184),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-192),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-200),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-208),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-216),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-224),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-232),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-240),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-248),
+BPF_STX_MEM(BPF_DW,BPF_REG_10,BPF_REG_1,-256),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,52),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-256),
+BPF_LDX_MEM(BPF_W,BPF_REG_1,BPF_REG_6,56),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,1),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_1,-255),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,2),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_2,0,0),
+BPF_JMP_IMM(BPF_JNE,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,3),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4024),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-254),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,3),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,4),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,4008),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-253),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,4),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,5),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3992),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-252),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,5),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,6),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3976),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-251),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,6),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,7),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3960),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-250),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,7),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,8),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3944),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-249),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,8),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,9),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3928),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-248),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,9),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,10),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3912),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-247),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,10),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,11),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3896),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-246),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,11),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,12),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3880),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-245),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,12),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,13),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3864),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-244),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,13),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,14),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3848),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-243),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,14),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,15),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3832),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-242),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,15),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,16),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3816),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-241),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,16),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,17),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3800),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-240),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,17),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,18),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3784),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-239),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,18),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,19),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3768),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-238),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,19),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,20),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3752),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-237),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,20),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,21),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3736),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-236),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,21),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,22),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3720),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-235),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,22),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,23),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3704),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-234),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,23),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,24),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3688),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-233),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,24),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,25),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3672),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-232),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,25),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,26),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3656),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-231),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,26),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,27),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3640),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-230),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,27),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,28),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3624),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-229),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,28),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,29),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3608),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-228),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,29),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,30),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3592),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-227),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,30),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,31),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3576),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-226),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,31),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,32),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3560),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-225),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,32),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,33),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3544),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-224),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,33),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,34),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3528),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-223),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,34),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,35),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3512),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-222),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,35),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,36),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3496),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-221),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,36),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,37),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3480),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-220),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,37),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,38),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3464),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-219),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,38),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,39),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3448),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-218),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,39),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,40),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3432),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-217),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,40),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,41),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3416),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-216),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,41),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,42),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3400),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-215),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,42),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,43),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3384),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-214),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,43),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,44),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3368),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-213),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,44),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,45),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3352),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-212),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,45),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,46),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3336),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-211),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,46),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,47),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3320),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-210),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,47),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,48),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3304),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-209),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,48),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,49),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3288),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-208),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,49),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,50),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3272),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-207),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,50),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,51),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3256),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-206),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,51),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,52),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3240),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-205),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,52),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,53),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3224),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-204),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,53),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,54),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3208),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-203),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,54),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,55),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3192),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-202),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,55),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,56),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3176),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-201),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,56),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,57),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3160),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-200),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,57),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,58),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3144),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-199),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,58),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,59),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3128),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-198),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,59),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,60),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3112),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-197),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,60),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,61),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3096),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-196),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,61),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,62),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3080),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-195),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,62),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,63),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3064),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-194),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,63),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,64),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3048),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-193),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,64),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,65),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3032),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-192),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,65),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,66),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3016),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-191),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,66),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,67),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,3000),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-190),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,67),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,68),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2984),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-189),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,68),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,69),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2968),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-188),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,69),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,70),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2952),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-187),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,70),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,71),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2936),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-186),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,71),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,72),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2920),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-185),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,72),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,73),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2904),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-184),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,73),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,74),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2888),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-183),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,74),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,75),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2872),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-182),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,75),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,76),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2856),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-181),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,76),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,77),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2840),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-180),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,77),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,78),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2824),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-179),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,78),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,79),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2808),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-178),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,79),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,80),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2792),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-177),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,80),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,81),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2776),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-176),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,81),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,82),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2760),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-175),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,82),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,83),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2744),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-174),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,83),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,84),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2728),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-173),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,84),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,85),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2712),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-172),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,85),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,86),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2696),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-171),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,86),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,87),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2680),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-170),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,87),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,88),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2664),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-169),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,88),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,89),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2648),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-168),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,89),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,90),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2632),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-167),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,90),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,91),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2616),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-166),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,91),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,92),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2600),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-165),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,92),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,93),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2584),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-164),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,93),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,94),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2568),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-163),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,94),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,95),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2552),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-162),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,95),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,96),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2536),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-161),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,96),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,97),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2520),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-160),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,97),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,98),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2504),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-159),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,98),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,99),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2488),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-158),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,99),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,100),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2472),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-157),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,100),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,101),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2456),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-156),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,101),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,102),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2440),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-155),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,102),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,103),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2424),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-154),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,103),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,104),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2408),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-153),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,104),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,105),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2392),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-152),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,105),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,106),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2376),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-151),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,106),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,107),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2360),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-150),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,107),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,108),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2344),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-149),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,108),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,109),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2328),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-148),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,109),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,110),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2312),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-147),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,110),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,111),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2296),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-146),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,111),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,112),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2280),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-145),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,112),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,113),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2264),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-144),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,113),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,114),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2248),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-143),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,114),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,115),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2232),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-142),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,115),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,116),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2216),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-141),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,116),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,117),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2200),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-140),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,117),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,118),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2184),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-139),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,118),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,119),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2168),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-138),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,119),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,120),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2152),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-137),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,120),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,121),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2136),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-136),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,121),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,122),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2120),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-135),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,122),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,123),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2104),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-134),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,123),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,124),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2088),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-133),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,124),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,125),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2072),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-132),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,125),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,126),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2056),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-131),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,126),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,127),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2040),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-130),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,127),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,128),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2024),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-129),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,128),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,129),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,2008),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-128),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,129),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,130),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1992),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-127),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,130),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,131),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1976),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-126),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,131),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,132),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1960),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-125),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,132),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,133),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1944),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-124),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,133),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,134),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1928),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-123),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,134),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,135),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1912),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-122),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,135),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,136),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1896),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-121),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,136),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,137),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1880),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-120),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,137),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,138),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1864),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-119),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,138),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,139),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1848),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-118),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,139),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,140),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1832),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-117),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,140),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,141),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1816),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-116),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,141),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,142),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1800),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-115),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,142),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,143),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1784),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-114),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,143),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,144),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1768),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-113),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,144),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,145),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1752),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-112),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,145),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,146),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1736),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-111),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,146),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,147),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1720),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-110),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,147),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,148),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1704),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-109),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,148),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,149),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1688),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-108),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,149),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,150),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1672),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-107),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,150),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,151),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1656),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-106),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,151),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,152),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1640),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-105),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,152),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,153),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1624),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-104),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,153),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,154),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1608),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-103),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,154),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,155),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1592),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-102),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,155),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,156),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1576),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-101),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,156),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,157),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1560),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-100),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,157),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,158),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1544),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-99),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,158),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,159),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1528),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-98),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,159),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,160),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1512),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-97),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,160),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,161),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1496),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-96),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,161),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,162),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1480),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-95),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,162),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,163),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1464),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-94),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,163),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,164),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1448),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-93),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,164),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,165),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1432),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-92),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,165),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,166),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1416),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-91),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,166),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,167),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1400),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-90),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,167),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,168),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1384),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-89),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,168),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,169),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1368),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-88),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,169),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,170),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1352),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-87),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,170),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,171),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1336),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-86),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,171),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,172),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1320),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-85),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,172),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,173),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1304),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-84),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,173),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,174),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1288),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-83),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,174),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,175),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1272),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-82),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,175),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,176),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1256),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-81),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,176),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,177),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1240),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-80),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,177),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,178),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1224),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-79),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,178),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,179),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1208),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-78),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,179),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,180),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1192),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-77),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,180),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,181),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1176),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-76),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,181),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,182),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1160),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-75),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,182),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,183),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1144),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-74),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,183),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,184),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1128),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-73),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,184),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,185),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1112),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-72),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,185),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,186),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1096),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-71),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,186),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,187),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1080),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-70),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,187),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,188),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1064),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-69),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,188),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,189),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1048),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-68),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,189),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,190),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1032),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-67),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,190),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,191),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1016),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-66),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,191),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,192),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,1000),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-65),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,192),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,193),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,984),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-64),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,193),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,194),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,968),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-63),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,194),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,195),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,952),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-62),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,195),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,196),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,936),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-61),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,196),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,197),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,920),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-60),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,197),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,198),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,904),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-59),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,198),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,199),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,888),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-58),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,199),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,200),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,872),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-57),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,200),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,201),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,856),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-56),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,201),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,202),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,840),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-55),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,202),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,203),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,824),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-54),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,203),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,204),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,808),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-53),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,204),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,205),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,792),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-52),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,205),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,206),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,776),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-51),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,206),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,207),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,760),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-50),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,207),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,208),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,744),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-49),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,208),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,209),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,728),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-48),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,209),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,210),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,712),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-47),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,210),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,211),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,696),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-46),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,211),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,212),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,680),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-45),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,212),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,213),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,664),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-44),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,213),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,214),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,648),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-43),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,214),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,215),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,632),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-42),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,215),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,216),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,616),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-41),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,216),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,217),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,600),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-40),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,217),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,218),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,584),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-39),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,218),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,219),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,568),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-38),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,219),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,220),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,552),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-37),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,220),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,221),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,536),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-36),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,221),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,222),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,520),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-35),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,222),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,223),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,504),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-34),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,223),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,224),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,488),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-33),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,224),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,225),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,472),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-32),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,225),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,226),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,456),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-31),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,226),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,227),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,440),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-30),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,227),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,228),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,424),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-29),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,228),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,229),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,408),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-28),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,229),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,230),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,392),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-27),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,230),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,231),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,376),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-26),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,231),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,232),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,360),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-25),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,232),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,233),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,344),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-24),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,233),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,234),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,328),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-23),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,234),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,235),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,312),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-22),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,235),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,236),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,296),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-21),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,236),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,237),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,280),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-20),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,237),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,238),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,264),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-19),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,238),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,239),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,248),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-18),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,239),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,240),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,232),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-17),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,240),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,241),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,216),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-16),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,241),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,242),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,200),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-15),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,242),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,243),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,184),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-14),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,243),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,244),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,168),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-13),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,244),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,245),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,152),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-12),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,245),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,246),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,136),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-11),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,246),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,247),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,120),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-10),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,247),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,248),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,104),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-9),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,248),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,249),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,88),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-8),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,249),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,250),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,72),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-7),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,250),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,251),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,56),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-6),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,251),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,252),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,40),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-5),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,252),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,253),
+BPF_MOV64_REG(BPF_REG_8,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_8,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_8,0,24),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,6),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_8,-1),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-4),
+BPF_MOV64_REG(BPF_REG_9,BPF_REG_7),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_9,253),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_B,BPF_REG_0,BPF_REG_9,0,0),
+BPF_JMP_IMM(BPF_JSGT,BPF_REG_8,0,5),
+BPF_MOV64_IMM(BPF_REG_9,254),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_1,0,8),
+BPF_JMP_IMM(BPF_JA,BPF_REG_0,0,5),
+BPF_MOV64_REG(BPF_REG_1,BPF_REG_0),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_1,-65),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_1,255),
+BPF_JMP_IMM(BPF_JGT,BPF_REG_1,25,1),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_0,32),
+BPF_STX_MEM(BPF_B,BPF_REG_10,BPF_REG_0,-3),
+BPF_MOV64_IMM(BPF_REG_9,255),
+BPF_ALU64_REG(BPF_ADD,BPF_REG_9,BPF_REG_7),
+BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_H,BPF_REG_0,BPF_REG_9,0,0),
+BPF_MOV64_REG(BPF_REG_6,BPF_REG_0),
+BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()),
+BPF_MOV64_REG(BPF_REG_2,BPF_REG_10),
+BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256),
+BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem),
+BPF_MOV64_IMM(BPF_REG_1,2147483647),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_0,0,7),
+BPF_LDX_MEM(BPF_H,BPF_REG_2,BPF_REG_0,8),
+BPF_JMP_IMM(BPF_JEQ,BPF_REG_2,255,2),
+BPF_ALU64_IMM(BPF_AND,BPF_REG_6,65535),
+BPF_JMP_REG(BPF_JNE,BPF_REG_6,BPF_REG_2,3),
+BPF_MOV64_IMM(BPF_REG_1,1),
+BPF_RAW_INSN(BPF_STX|BPF_XADD|BPF_DW,BPF_REG_0,BPF_REG_1,0,0),
+BPF_MOV64_IMM(BPF_REG_1,0),
+BPF_MOV64_REG(BPF_REG_0,BPF_REG_1),
+BPF_EXIT_INSN(),
index 81e39c8bc983e366fc8ecd402c565d2624b2642b..aa1892f4c1f750dacfbe5f4af609e31d7800b499 100644 (file)
@@ -19,6 +19,12 @@ LT_INIT([disable-static])
 CFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -fvisibility=hidden $CFLAGS"
 CXXFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -Wmissing-declarations -Wredundant-decls -fvisibility=hidden $CXXFLAGS"
 
+AC_SUBST([pdns_configure_args], ["$ac_configure_args"])
+AC_DEFINE_UNQUOTED([DNSDIST_CONFIG_ARGS],
+  ["$pdns_configure_args"],
+  [pdns configure arguments]
+)
+
 PDNS_WITH_LIBSODIUM
 PDNS_WITH_QUICHE
 PDNS_CHECK_DNSTAP([auto])
@@ -33,7 +39,7 @@ PDNS_CHECK_PTHREAD_NP
 PDNS_CHECK_SECURE_MEMSET
 AC_FUNC_STRERROR_R
 
-BOOST_REQUIRE([1.42])
+BOOST_REQUIRE([1.54])
 
 PDNS_ENABLE_UNIT_TESTS
 PDNS_ENABLE_FUZZ_TARGETS
deleted file mode 120000 (symlink)
index 7de9446cd73ea776647911fb4dc41ccd51fb604d..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../delaypipe.cc
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..fdd828862cc55f9ce4889e2348769537480f2019
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "delaypipe.hh"
+#include "misc.hh"
+#include "gettime.hh"
+#include <thread>
+#include "threadname.hh"
+
+template <class T>
+ObjectPipe<T>::ObjectPipe()
+{
+  auto [sender, receiver] = pdns::channel::createObjectQueue<T>(pdns::channel::SenderBlockingMode::SenderBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0, false);
+  d_sender = std::move(sender);
+  d_receiver = std::move(receiver);
+}
+
+template <class T>
+void ObjectPipe<T>::close()
+{
+  d_sender.close();
+}
+
+template <class T>
+void ObjectPipe<T>::write(T& t)
+{
+  auto ptr = std::make_unique<T>(t);
+  if (!d_sender.send(std::move(ptr))) {
+    unixDie("writing to the DelayPipe");
+  }
+}
+
+template <class T>
+int ObjectPipe<T>::readTimeout(T* t, double msec)
+{
+  while (true) {
+    int ret = waitForData(d_receiver.getDescriptor(), 0, 1000 * msec);
+    if (ret < 0) {
+      if (errno == EINTR) {
+        continue;
+      }
+      unixDie("waiting for data in object pipe");
+    }
+    else if (ret == 0) {
+      return -1;
+    }
+
+    try {
+      auto tmp = d_receiver.receive();
+      if (!tmp) {
+        if (d_receiver.isClosed()) {
+          return 0;
+        }
+        continue;
+      }
+
+      *t = **tmp;
+      return 1;
+    }
+    catch (const std::exception& e) {
+      throw std::runtime_error("reading from the delay pipe: " + std::string(e.what()));
+    }
+  }
+}
+
+template <class T>
+DelayPipe<T>::DelayPipe() :
+  d_thread(&DelayPipe<T>::worker, this)
+{
+}
+
+template <class T>
+void DelayPipe<T>::gettime(struct timespec* ts)
+{
+  ::gettime(ts);
+}
+
+template <class T>
+void DelayPipe<T>::submit(T& t, int msec)
+{
+  struct timespec now;
+  gettime(&now);
+  now.tv_nsec += msec * 1e6;
+  while (now.tv_nsec > 1e9) {
+    now.tv_sec++;
+    now.tv_nsec -= 1e9;
+  }
+  Combo c{t, now};
+  d_pipe.write(c);
+}
+
+template <class T>
+DelayPipe<T>::~DelayPipe()
+{
+  d_pipe.close();
+  d_thread.join();
+}
+
+template <class T>
+void DelayPipe<T>::worker()
+{
+  setThreadName("dnsdist/delayPi");
+  Combo c;
+  for (;;) {
+    /* this code is slightly too subtle, but I don't see how it could be any simpler.
+       So we have a set of work to do, and we need to wait until the time arrives to do it.
+       Simultaneously new work might come in. So we try to combine both of these things by
+       setting a timeout on listening to the pipe over which new work comes in. This timeout
+       is equal to the wait until the first thing that needs to be done.
+
+       Two additional cases exist: we have no work to wait for, so we can wait infinitely long.
+       The other special case is that the first we have to do.. is in the past, so we need to do it
+       immediately. */
+
+    double delay = -1; // infinite
+    struct timespec now;
+    if (!d_work.empty()) {
+      gettime(&now);
+      delay = 1000 * tsdelta(d_work.begin()->first, now);
+      if (delay < 0) {
+        delay = 0; // don't wait - we have work that is late already!
+      }
+    }
+    if (delay != 0) {
+      int ret = d_pipe.readTimeout(&c, delay);
+      if (ret > 0) { // we got an object
+        d_work.emplace(c.when, c.what);
+      }
+      else if (ret == 0) { // EOF
+        break;
+      }
+      else {
+        ;
+      }
+      gettime(&now);
+    }
+
+    tscomp cmp;
+
+    for (auto iter = d_work.begin(); iter != d_work.end();) { // do the needful
+      if (cmp(iter->first, now)) {
+        iter->second();
+        d_work.erase(iter++);
+      }
+      else {
+        break;
+      }
+    }
+  }
+}
deleted file mode 120000 (symlink)
index f67d1fde09ad703f86447406721b2c150144c14a..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../delaypipe.hh
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..ebbe1888f0d7dfec353d0dcc2c524ecce261b30f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <time.h>
+#include <thread>
+
+#include "channel.hh"
+
+/**
+   General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
+   The implementation is that submitter threads create an object that represents the work, and it gets sent over a pipe
+   to the worker thread.
+
+   The worker thread meanwhile listens on this pipe (non-blocking), with a delay set to the next object that needs to be executed.
+   If meanwhile new work comes in, all objects who's time has come are executed, a new sleep time is calculated.
+*/
+
+/* ObjectPipe facilitates the type-safe passing of types over a pipe */
+
+template <class T>
+class ObjectPipe
+{
+public:
+  ObjectPipe();
+  void write(T& t);
+  int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely long. msec==0 = undefined
+  void close();
+
+private:
+  pdns::channel::Sender<T> d_sender;
+  pdns::channel::Receiver<T> d_receiver;
+};
+
+template <class T>
+class DelayPipe
+{
+public:
+  DelayPipe();
+  ~DelayPipe();
+  void submit(T& t, int msec); //!< don't try for more than 4294 msec
+
+private:
+  void worker();
+  struct Combo
+  {
+    T what;
+    struct timespec when;
+  };
+
+  double tsdelta(const struct timespec& a, const struct timespec& b) // read as a-b
+  {
+    return 1.0 * (a.tv_sec - b.tv_sec) + 1.0 * (a.tv_nsec - b.tv_nsec) / 1000000000.0;
+  }
+
+  ObjectPipe<Combo> d_pipe;
+  struct tscomp
+  {
+    bool operator()(const struct timespec& a, const struct timespec& b) const
+    {
+      return std::tie(a.tv_sec, a.tv_nsec) < std::tie(b.tv_sec, b.tv_nsec);
+    }
+  };
+  std::multimap<struct timespec, T, tscomp> d_work;
+  void gettime(struct timespec* ts);
+  std::thread d_thread;
+};
+
+#include "delaypipe.cc"
index b28c78da1c2565680c51eb3e55996d4de3e9d6f7..2a0115abd32bc949717d0800dd40feb34170e16e 100644 (file)
@@ -873,7 +873,7 @@ int DNSCryptContext::encryptQuery(PacketBuffer& packet, size_t maximumSize, cons
 bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
 {
   bool success = false;
-  DNSCryptCertSignedData::ResolverPrivateKeyType providerPrivateKey;
+  DNSCryptCertSignedData::ResolverPrivateKeyType providerPrivateKey{};
   sodium_mlock(providerPrivateKey.data(), providerPrivateKey.size());
   sodium_memzero(providerPrivateKey.data(), providerPrivateKey.size());
 
index dfb4c9bf81dc1fe5180f5bc6220208e8f3f8c0cc..516848f9a05dfad3211908cb4ef0e242b949c05d 100644 (file)
@@ -115,8 +115,8 @@ struct DNSCryptCertSignedData
   using ResolverPublicKeyType = std::array<unsigned char, DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE>;
   using ResolverPrivateKeyType = std::array<unsigned char, DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE>;
   using ClientMagicType = std::array<unsigned char, DNSCRYPT_CLIENT_MAGIC_SIZE>;
-  ResolverPublicKeyType resolverPK;
-  ClientMagicType clientMagic;
+  ResolverPublicKeyType resolverPK{};
+  ClientMagicType clientMagic{};
   uint32_t serial{0};
   uint32_t tsStart{0};
   uint32_t tsEnd{0};
@@ -148,10 +148,10 @@ public:
   using ESVersionType = std::array<unsigned char, 2>;
   using ProtocolMinorVersionType = std::array<unsigned char, 2>;
   using CertMagicType = std::array<unsigned char, DNSCRYPT_CERT_MAGIC_SIZE>;
-  CertMagicType magic;
-  ESVersionType esVersion;
-  ProtocolMinorVersionType protocolMinorVersion;
-  std::array<unsigned char, DNSCRYPT_SIGNATURE_SIZE> signature;
+  CertMagicType magic{};
+  ESVersionType esVersion{};
+  ProtocolMinorVersionType protocolMinorVersion{};
+  std::array<unsigned char, DNSCRYPT_SIGNATURE_SIZE> signature{};
   DNSCryptCertSignedData signedData;
 };
 
@@ -259,7 +259,7 @@ public:
   void getCertificateResponse(time_t now, PacketBuffer& response) const;
   int encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp);
 
-  static const size_t s_minUDPLength = 256;
+  static constexpr size_t s_minUDPLength = 256;
 
 private:
   static void fillServerNonce(DNSCryptNonceType& nonce);
diff --git a/pdns/dnsdistdist/dnsdist-actions.hh b/pdns/dnsdistdist/dnsdist-actions.hh
new file mode 100644 (file)
index 0000000..5bb08a0
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+/* so what could you do:
+   drop,
+   fake up nxdomain,
+   provide actual answer,
+   allow & and stop processing,
+   continue processing,
+   modify header:    (servfail|refused|notimp), set TC=1,
+   send to pool */
+
+struct DNSQuestion;
+struct DNSResponse;
+
+class DNSAction
+{
+public:
+  enum class Action : uint8_t
+  {
+    Drop,
+    Nxdomain,
+    Refused,
+    Spoof,
+    Allow,
+    HeaderModify,
+    Pool,
+    Delay,
+    Truncate,
+    ServFail,
+    None,
+    NoOp,
+    NoRecurse,
+    SpoofRaw,
+    SpoofPacket,
+    SetTag,
+  };
+  static std::string typeToString(const Action& action)
+  {
+    switch (action) {
+    case Action::Drop:
+      return "Drop";
+    case Action::Nxdomain:
+      return "Send NXDomain";
+    case Action::Refused:
+      return "Send Refused";
+    case Action::Spoof:
+      return "Spoof an answer";
+    case Action::SpoofPacket:
+      return "Spoof a raw answer from bytes";
+    case Action::SpoofRaw:
+      return "Spoof an answer from raw bytes";
+    case Action::Allow:
+      return "Allow";
+    case Action::HeaderModify:
+      return "Modify the header";
+    case Action::Pool:
+      return "Route to a pool";
+    case Action::Delay:
+      return "Delay";
+    case Action::Truncate:
+      return "Truncate over UDP";
+    case Action::ServFail:
+      return "Send ServFail";
+    case Action::SetTag:
+      return "Set Tag";
+    case Action::None:
+    case Action::NoOp:
+      return "Do nothing";
+    case Action::NoRecurse:
+      return "Set rd=0";
+    }
+
+    return "Unknown";
+  }
+
+  virtual Action operator()(DNSQuestion*, std::string* ruleresult) const = 0;
+  virtual ~DNSAction() = default;
+  virtual std::string toString() const = 0;
+  virtual std::map<std::string, double> getStats() const
+  {
+    return {{}};
+  }
+  virtual void reload()
+  {
+  }
+};
+
+class DNSResponseAction
+{
+public:
+  enum class Action : uint8_t
+  {
+    Allow,
+    Delay,
+    Drop,
+    HeaderModify,
+    ServFail,
+    Truncate,
+    None
+  };
+  virtual Action operator()(DNSResponse*, std::string* ruleresult) const = 0;
+  virtual ~DNSResponseAction() = default;
+  virtual std::string toString() const = 0;
+  virtual void reload()
+  {
+  }
+};
index 9cb96d83a226b0e88a1075d247e195a13def212c..84095c4a2e2b63000ad9011ce9880040864e36c1 100644 (file)
@@ -22,6 +22,7 @@
 #include "dnsdist-async.hh"
 #include "dnsdist-internal-queries.hh"
 #include "dolog.hh"
+#include "mplexer.hh"
 #include "threadname.hh"
 
 namespace dnsdist
@@ -222,8 +223,7 @@ static bool resumeResponse(std::unique_ptr<CrossProtocolQuery>&& response)
     auto& ids = response->query.d_idstate;
     DNSResponse dnsResponse = response->getDR();
 
-    LocalHolders holders;
-    auto result = processResponseAfterRules(response->query.d_buffer, *holders.cacheInsertedRespRuleActions, dnsResponse, ids.cs->muted);
+    auto result = processResponseAfterRules(response->query.d_buffer, dnsResponse, ids.cs->muted);
     if (!result) {
       /* easy */
       return true;
@@ -284,9 +284,8 @@ bool resumeQuery(std::unique_ptr<CrossProtocolQuery>&& query)
   }
 
   DNSQuestion dnsQuestion = query->getDQ();
-  LocalHolders holders;
 
-  auto result = processQueryAfterRules(dnsQuestion, holders, query->downstream);
+  auto result = processQueryAfterRules(dnsQuestion, query->downstream);
   if (result == ProcessQueryResult::Drop) {
     /* easy */
     return true;
index c0b8453ae6be550e37c11e73ff338521756d7c0e..7a337d25b54f51cf0676767ef2492222c147c674 100644 (file)
@@ -59,7 +59,7 @@ private:
     uint16_t d_queryID;
   };
 
-  typedef multi_index_container<
+  using content_t = multi_index_container<
     Entry,
     indexed_by<
       ordered_unique<tag<IDTag>,
@@ -68,8 +68,7 @@ private:
                        member<Entry, uint16_t, &Entry::d_queryID>,
                        member<Entry, uint16_t, &Entry::d_asyncID>>>,
       ordered_non_unique<tag<TTDTag>,
-                         member<Entry, struct timeval, &Entry::d_ttd>>>>
-    content_t;
+                         member<Entry, struct timeval, &Entry::d_ttd>>>>;
 
   static void pickupExpired(content_t&, const struct timeval& now, std::list<std::pair<uint16_t, std::unique_ptr<CrossProtocolQuery>>>& expiredEvents);
   static struct timeval getNextTTD(const content_t&);
index 7f5603482f155214702d814fa2735fd3e954096b..d493d3f9aa1f68036fe345cb52746b28db82a5f2 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+#include <boost/format.hpp>
+
 #include "config.h"
 #include "dnsdist.hh"
+#include "dnsdist-backend.hh"
 #include "dnsdist-backoff.hh"
 #include "dnsdist-metrics.hh"
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-random.hh"
 #include "dnsdist-rings.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-xsk.hh"
 #include "dolog.hh"
@@ -143,7 +147,7 @@ bool DownstreamState::reconnect(bool initialAttempt)
       connected = true;
     }
     catch (const std::runtime_error& error) {
-      if (initialAttempt || g_verbose) {
+      if (initialAttempt || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what());
       }
       connected = false;
@@ -236,6 +240,7 @@ void DownstreamState::stop()
 void DownstreamState::hash()
 {
   vinfolog("Computing hashes for id=%s and weight=%d", *d_config.id, d_config.d_weight);
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
   auto w = d_config.d_weight;
   auto idStr = boost::str(boost::format("%s") % *d_config.id);
   auto lockedHashes = hashes.write_lock();
@@ -243,7 +248,8 @@ void DownstreamState::hash()
   lockedHashes->reserve(w);
   while (w > 0) {
     std::string uuid = boost::str(boost::format("%s-%d") % idStr % w);
-    unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), g_hashperturb);
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): sorry, it's the burtle API
+    unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), hashPerturbation);
     lockedHashes->push_back(wshash);
     --w;
   }
@@ -300,23 +306,19 @@ DownstreamState::DownstreamState(DownstreamState::Config&& config, std::shared_p
 
   setName(d_config.name);
 
-  if (d_tlsCtx) {
-    if (!d_config.d_dohPath.empty()) {
+  if (d_tlsCtx && !d_config.d_dohPath.empty()) {
 #ifdef HAVE_NGHTTP2
-      setupDoHClientProtocolNegotiation(d_tlsCtx);
-
-      if (g_configurationDone && g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads == 0) {
-        throw std::runtime_error("Error: setOutgoingDoHWorkerThreads() is set to 0 so no outgoing DoH worker thread is available to serve queries");
-      }
-
-      if (!g_outgoingDoHWorkerThreads || *g_outgoingDoHWorkerThreads == 0) {
-        g_outgoingDoHWorkerThreads = 1;
-      }
-#endif /* HAVE_NGHTTP2 */
+    auto outgoingDoHWorkerThreads = dnsdist::configuration::getImmutableConfiguration().d_outgoingDoHWorkers;
+    if (dnsdist::configuration::isImmutableConfigurationDone() && outgoingDoHWorkerThreads && *outgoingDoHWorkerThreads == 0) {
+      throw std::runtime_error("Error: setOutgoingDoHWorkerThreads() is set to 0 so no outgoing DoH worker thread is available to serve queries");
     }
-    else {
-      setupDoTProtocolNegotiation(d_tlsCtx);
+
+    if (!dnsdist::configuration::isImmutableConfigurationDone() && (!outgoingDoHWorkerThreads || *outgoingDoHWorkerThreads == 0)) {
+      dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& immutableConfig) {
+        immutableConfig.d_outgoingDoHWorkers = 1;
+      });
     }
+#endif /* HAVE_NGHTTP2 */
   }
 
   if (connect && !isTCPOnly()) {
@@ -352,11 +354,12 @@ void DownstreamState::start()
 
 void DownstreamState::connectUDPSockets()
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     idStates.clear();
   }
   else {
-    idStates.resize(g_maxOutstanding);
+    idStates.resize(config.d_maxUDPOutstanding);
   }
   sockets.resize(d_config.d_numberOfSockets);
 
@@ -396,8 +399,8 @@ int DownstreamState::pickSocketForSending()
     return sockets[0];
   }
 
-  size_t idx;
-  if (s_randomizeSockets) {
+  size_t idx{0};
+  if (dnsdist::configuration::getImmutableConfiguration().d_randomizeUDPSocketsToBackend) {
     idx = dnsdist::getRandomValue(numberOfSockets);
   }
   else {
@@ -419,14 +422,10 @@ void DownstreamState::pickSocketsReadyForReceiving(std::vector<int>& ready)
   (*mplexer.lock())->getAvailableFDs(ready, 1000);
 }
 
-bool DownstreamState::s_randomizeSockets{false};
-bool DownstreamState::s_randomizeIDs{false};
-int DownstreamState::s_udpTimeout{2};
-
-static bool isIDSExpired(const IDState& ids)
+static bool isIDSExpired(const IDState& ids, uint8_t udpTimeout)
 {
   auto age = ids.age.load();
-  return age > DownstreamState::s_udpTimeout;
+  return age > udpTimeout;
 }
 
 void DownstreamState::handleUDPTimeout(IDState& ids)
@@ -478,11 +477,13 @@ void DownstreamState::handleUDPTimeouts()
     return;
   }
 
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  const auto udpTimeout = config.d_udpTimeout;
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
     for (auto it = map->begin(); it != map->end(); ) {
       auto& ids = it->second;
-      if (isIDSExpired(ids)) {
+      if (isIDSExpired(ids, udpTimeout)) {
         handleUDPTimeout(ids);
         it = map->erase(it);
         continue;
@@ -497,7 +498,7 @@ void DownstreamState::handleUDPTimeouts()
         if (!ids.isInUse()) {
           continue;
         }
-        if (!isIDSExpired(ids)) {
+        if (!isIDSExpired(ids, udpTimeout)) {
           ++ids.age;
           continue;
         }
@@ -506,7 +507,7 @@ void DownstreamState::handleUDPTimeouts()
           continue;
         }
         /* check again, now that we have locked this state */
-        if (ids.isInUse() && isIDSExpired(ids)) {
+        if (ids.isInUse() && isIDSExpired(ids, udpTimeout)) {
           handleUDPTimeout(ids);
         }
       }
@@ -516,7 +517,8 @@ void DownstreamState::handleUDPTimeouts()
 
 uint16_t DownstreamState::saveState(InternalQueryState&& state)
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     /* if the state is already in use we will retry,
        up to 5 five times. The last selected one is used
        even if it was already in use */
@@ -578,7 +580,8 @@ uint16_t DownstreamState::saveState(InternalQueryState&& state)
 
 void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
 
     auto [it, inserted] = map->emplace(id, IDState());
@@ -619,8 +622,8 @@ void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
 std::optional<InternalQueryState> DownstreamState::getState(uint16_t id)
 {
   std::optional<InternalQueryState> result = std::nullopt;
-
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
 
     auto it = map->find(id);
@@ -803,7 +806,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
     currentCheckFailures = 0;
     consecutiveSuccessfulChecks++;
 
-    if (!upStatus) {
+    if (!upStatus.load(std::memory_order_relaxed)) {
       /* we were previously marked as "down" and had a successful health-check,
          let's see if this is enough to move to the "up" state or if we need
          more successful health-checks for that */
@@ -834,7 +837,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
 
     currentCheckFailures++;
 
-    if (upStatus) {
+    if (upStatus.load(std::memory_order_relaxed)) {
       /* we were previously marked as "up" and failed a health-check,
          let's see if this is enough to move to the "down" state or if
          need more failed checks for that */
@@ -853,7 +856,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
     }
   }
 
-  if (newState != upStatus) {
+  if (newState != upStatus.load(std::memory_order_relaxed)) {
     /* we are actually moving to a new state */
     if (!IsAnyAddress(d_config.remote)) {
       infolog("Marking downstream %s as '%s'", getNameWithAddr(), newState ? "up" : "down");
@@ -864,7 +867,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
     }
 
     setUpStatus(newState);
-    if (g_snmpAgent && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendBackendStatusChangeTrap(*this);
     }
   }
@@ -905,10 +908,9 @@ void DownstreamState::registerXsk(std::vector<std::shared_ptr<XskSocket>>& xsks)
   d_config.sourceMACAddr = d_xskSockets.at(0)->getSourceMACAddress();
 
   for (auto& xsk : d_xskSockets) {
-    auto xskInfo = XskWorker::create();
+    auto xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, xsk->sharedEmptyFrameOffset);
     d_xskInfos.push_back(xskInfo);
     xsk->addWorker(xskInfo);
-    xskInfo->sharedEmptyFrameOffset = xsk->sharedEmptyFrameOffset;
   }
   reconnect(false);
 }
@@ -1002,3 +1004,17 @@ void ServerPool::removeServer(shared_ptr<DownstreamState>& server)
   }
   *servers = std::move(newServers);
 }
+
+namespace dnsdist::backend
+{
+void registerNewBackend(std::shared_ptr<DownstreamState>& backend)
+{
+  dnsdist::configuration::updateRuntimeConfiguration([&backend](dnsdist::configuration::RuntimeConfiguration& config) {
+    auto& backends = config.d_backends;
+    backends.push_back(backend);
+    std::stable_sort(backends.begin(), backends.end(), [](const std::shared_ptr<DownstreamState>& lhs, const std::shared_ptr<DownstreamState>& rhs) {
+      return lhs->d_config.order < rhs->d_config.order;
+    });
+  });
+}
+}
diff --git a/pdns/dnsdistdist/dnsdist-backend.hh b/pdns/dnsdistdist/dnsdist-backend.hh
new file mode 100644 (file)
index 0000000..2821f56
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <memory>
+
+struct DownstreamState;
+
+namespace dnsdist::backend
+{
+void registerNewBackend(std::shared_ptr<DownstreamState>& backend);
+}
index d6323d8b3224844bc78f0eeec935acaad077344e..5832585a896d69c42802d928b4c3dd063c868c82 100644 (file)
@@ -51,7 +51,7 @@ bool DNSDistPacketCache::getClientSubnet(const PacketBuffer& packet, size_t qnam
   uint16_t optRDPosition = 0;
   size_t remaining = 0;
 
-  int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
+  int res = dnsdist::getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
 
   if (res == 0) {
     size_t ecsOptionStartPosition = 0;
index 2be36ed3827b7accdaf1e6f25fa6ff8f737ff0e4..040783b68a956fd23a1d8ae26870a17d25e29277 100644 (file)
 #endif
 
 #include "dnsdist-carbon.hh"
+#include "dnsdist-cache.hh"
 #include "dnsdist.hh"
 #include "dnsdist-backoff.hh"
+#include "dnsdist-configuration.hh"
+#include "dnsdist-frontend.hh"
 #include "dnsdist-metrics.hh"
 
 #ifndef DISABLE_CARBON
@@ -36,8 +39,6 @@
 namespace dnsdist
 {
 
-LockGuarded<Carbon::Config> Carbon::s_config;
-
 static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
 {
   const auto& server = endpoint.server;
@@ -60,12 +61,9 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
         if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
           str << (*val)->load();
         }
-        else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+        else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
           str << (*adval)->load();
         }
-        else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
-          str << **dval;
-        }
         else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
           str << (*func)(entry.d_name);
         }
@@ -73,8 +71,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
       }
     }
 
-    auto states = g_dstates.getLocal();
-    for (const auto& state : *states) {
+    for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
       string serverName = state->getName().empty() ? state->d_config.remote.toStringWithPort() : state->getName();
       boost::replace_all(serverName, ".", "_");
       string base = namespace_name;
@@ -115,7 +112,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
     }
 
     std::map<std::string, uint64_t> frontendDuplicates;
-    for (const auto& front : g_frontends) {
+    for (const auto& front : dnsdist::getFrontends()) {
       if (front->udpFD == -1 && front->tcpFD == -1) {
         continue;
       }
@@ -176,8 +173,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
       }
     }
 
-    auto localPools = g_pools.getLocal();
-    for (const auto& entry : *localPools) {
+    for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
       string poolName = entry.first;
       boost::replace_all(poolName, ".", "_");
       if (poolName.empty()) {
@@ -225,7 +221,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
     {
       std::map<std::string, uint64_t> dohFrontendDuplicates;
       const string base = "dnsdist." + hostname + ".main.doh.";
-      for (const auto& doh : g_dohlocals) {
+      for (const auto& doh : dnsdist::getDoHFrontends()) {
         string name = doh->d_tlsContext.d_addr.toStringWithPort();
         boost::replace_all(name, ".", "_");
         boost::replace_all(name, ":", "_");
@@ -270,7 +266,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
 
     {
       std::string qname;
-      auto records = g_qcount.records.write_lock();
+      auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
       for (const auto& record : *records) {
         qname = record.first;
         boost::replace_all(qname, ".", "_");
@@ -297,7 +293,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
   return true;
 }
 
-static void carbonHandler(Carbon::Endpoint&& endpoint)
+static void carbonHandler(const Carbon::Endpoint& endpoint)
 {
   setThreadName("dnsdist/carbon");
   const auto intervalUSec = endpoint.interval * 1000 * 1000;
@@ -338,41 +334,29 @@ static void carbonHandler(Carbon::Endpoint&& endpoint)
   }
 }
 
-bool Carbon::addEndpoint(Carbon::Endpoint&& endpoint)
+Carbon::Endpoint Carbon::newEndpoint(const std::string& address, std::string ourName, uint64_t interval, const std::string& namespace_name, const std::string& instance_name)
 {
-  if (endpoint.ourname.empty()) {
+  if (ourName.empty()) {
     try {
-      endpoint.ourname = getCarbonHostName();
+      ourName = getCarbonHostName();
     }
-    catch (const std::exception& e) {
-      throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + e.what());
+    catch (const std::exception& exp) {
+      throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + exp.what());
     }
   }
-
-  auto config = s_config.lock();
-  if (config->d_running) {
-    // we already started the threads, let's just spawn a new one
-    std::thread newHandler(carbonHandler, std::move(endpoint));
-    newHandler.detach();
-  }
-  else {
-    config->d_endpoints.push_back(std::move(endpoint));
-  }
-  return true;
+  return Carbon::Endpoint{ComboAddress(address, 2003),
+                          !namespace_name.empty() ? namespace_name : "dnsdist",
+                          std::move(ourName),
+                          !instance_name.empty() ? instance_name : "main",
+                          interval < std::numeric_limits<unsigned int>::max() ? static_cast<unsigned int>(interval) : 30};
 }
 
-void Carbon::run()
+void Carbon::run(const std::vector<Carbon::Endpoint>& endpoints)
 {
-  auto config = s_config.lock();
-  if (config->d_running) {
-    throw std::runtime_error("The carbon threads are already running");
-  }
-  for (auto& endpoint : config->d_endpoints) {
-    std::thread newHandler(carbonHandler, std::move(endpoint));
+  for (const auto& endpoint : endpoints) {
+    std::thread newHandler(carbonHandler, endpoint);
     newHandler.detach();
   }
-  config->d_endpoints.clear();
-  config->d_running = true;
 }
 
 }
index 0fb04d4f03352d346e4dd38cbb4ff7c4e697bd21..96c9f96daceeddf0c6d4f1353a28e4ecd5daa97b 100644 (file)
 #include "config.h"
 
 #ifndef DISABLE_CARBON
-
-#include <thread>
+#include <string>
 #include "iputils.hh"
-#include "lock.hh"
 
 namespace dnsdist
 {
@@ -43,17 +41,8 @@ public:
     unsigned int interval;
   };
 
-  static bool addEndpoint(Endpoint&& endpoint);
-  static void run();
-
-private:
-  struct Config
-  {
-    std::vector<Endpoint> d_endpoints;
-    bool d_running{false};
-  };
-
-  static LockGuarded<Config> s_config;
+  static Endpoint newEndpoint(const std::string& address, std::string ourName, uint64_t interval, const std::string& namespace_name, const std::string& instance_name);
+  static void run(const std::vector<Endpoint>& endpoints);
 };
 
 }
index 3cf55d5a414d469793f338877a831d59b43a8c7a..9827bbc33fecc90b65e5b8d6252f8234946ddd53 100644 (file)
@@ -24,6 +24,7 @@
 #include <map>
 #include "iputils.hh"
 #include "lock.hh"
+#include "dnsdist-configuration.hh"
 
 namespace dnsdist
 {
@@ -32,12 +33,13 @@ class IncomingConcurrentTCPConnectionsManager
 public:
   static bool accountNewTCPConnection(const ComboAddress& from)
   {
-    if (s_maxTCPConnectionsPerClient == 0) {
+    const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+    if (maxConnsPerClient == 0) {
       return true;
     }
     auto db = s_tcpClientsConcurrentConnectionsCount.lock();
     auto& count = (*db)[from];
-    if (count >= s_maxTCPConnectionsPerClient) {
+    if (count >= maxConnsPerClient) {
       return false;
     }
     ++count;
@@ -46,7 +48,8 @@ public:
 
   static void accountClosedTCPConnection(const ComboAddress& from)
   {
-    if (s_maxTCPConnectionsPerClient == 0) {
+    const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+    if (maxConnsPerClient == 0) {
       return;
     }
     auto db = s_tcpClientsConcurrentConnectionsCount.lock();
@@ -57,14 +60,8 @@ public:
     }
   }
 
-  static void setMaxTCPConnectionsPerClient(size_t max)
-  {
-    s_maxTCPConnectionsPerClient = max;
-  }
-
 private:
   static LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> s_tcpClientsConcurrentConnectionsCount;
-  static size_t s_maxTCPConnectionsPerClient;
 };
 
 }
diff --git a/pdns/dnsdistdist/dnsdist-configuration.cc b/pdns/dnsdistdist/dnsdist-configuration.cc
new file mode 100644 (file)
index 0000000..70875b8
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-configuration.hh"
+#include "sholder.hh"
+
+namespace dnsdist::configuration
+{
+static GlobalStateHolder<RuntimeConfiguration> s_currentRuntimeConfiguration;
+static ImmutableConfiguration s_immutableConfiguration;
+static std::atomic<bool> s_immutableConfigurationDone{false};
+
+const RuntimeConfiguration& getCurrentRuntimeConfiguration()
+{
+  static thread_local auto t_threadLocalConfiguration = s_currentRuntimeConfiguration.getLocal();
+  return *t_threadLocalConfiguration;
+}
+
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator)
+{
+  s_currentRuntimeConfiguration.modify(mutator);
+}
+
+void updateImmutableConfiguration(const std::function<void(ImmutableConfiguration&)>& mutator)
+{
+  if (isImmutableConfigurationDone()) {
+    throw std::runtime_error("Trying to update an immutable setting at runtime!");
+  }
+
+  mutator(s_immutableConfiguration);
+}
+
+const ImmutableConfiguration& getImmutableConfiguration()
+{
+  return s_immutableConfiguration;
+}
+
+bool isImmutableConfigurationDone()
+{
+  return s_immutableConfigurationDone.load();
+}
+
+void setImmutableConfigurationDone()
+{
+  if (s_immutableConfigurationDone.exchange(true)) {
+    throw std::runtime_error("Trying to seal the runtime-immutable configuration a second time");
+  }
+}
+}
diff --git a/pdns/dnsdistdist/dnsdist-configuration.hh b/pdns/dnsdistdist/dnsdist-configuration.hh
new file mode 100644 (file)
index 0000000..bfde451
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "config.h"
+#include "credentials.hh"
+#include "dnsdist-actions.hh"
+#include "dnsdist-carbon.hh"
+#include "dnsdist-query-count.hh"
+#include "dnsdist-rule-chains.hh"
+#include "iputils.hh"
+
+class ServerPolicy;
+struct ServerPool;
+struct DownstreamState;
+struct ClientState;
+
+using servers_t = std::vector<std::shared_ptr<DownstreamState>>;
+
+namespace dnsdist::configuration
+{
+/* This part of the configuration is compile-time only */
+/* when we add EDNS to a query, we don't want to advertise
+   a large buffer size */
+static constexpr size_t s_EdnsUDPPayloadSize{512};
+static constexpr uint16_t s_defaultPayloadSizeSelfGenAnswers = 1232;
+static constexpr uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
+static_assert(s_defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
+
+/* this part of the configuration can only be updated at configuration
+   time, and is immutable once the configuration phase is over */
+struct ImmutableConfiguration
+{
+  std::set<std::string> d_capabilitiesToRetain;
+  std::vector<uint32_t> d_tcpFastOpenKey;
+  std::vector<std::shared_ptr<ClientState>> d_frontends;
+#ifdef __linux__
+  // On Linux this gives us 128k pending queries (default is 8192 queries),
+  // which should be enough to deal with huge spikes
+  uint64_t d_maxTCPQueuedConnections{10000};
+  size_t d_tcpInternalPipeBufferSize{1048576U};
+#else
+  uint64_t d_maxTCPQueuedConnections{1000};
+  size_t d_tcpInternalPipeBufferSize{0};
+#endif
+  double d_weightedBalancingFactor{0};
+  double d_consistentHashBalancingFactor{0};
+  std::optional<uint64_t> d_outgoingDoHWorkers{std::nullopt};
+  uint64_t d_consoleMaxConcurrentConnections{0};
+  uint64_t d_outgoingDoHMaxIdleTime{300};
+  uint64_t d_outgoingTCPMaxIdleTime{300};
+  uint64_t d_outgoingDoHCleanupInterval{60};
+  uint64_t d_outgoingTCPCleanupInterval{60};
+  uint64_t d_outgoingDoHMaxIdlePerBackend{10};
+  uint64_t d_outgoingTCPMaxIdlePerBackend{10};
+  uint64_t d_maxTCPClientThreads{0};
+  size_t d_maxTCPConnectionsPerClient{0};
+  size_t d_udpVectorSize{1};
+  size_t d_ringsCapacity{10000};
+  size_t d_ringsNumberOfShards{10};
+  size_t d_ringsNbLockTries{5};
+  uint32_t d_socketUDPSendBuffer{0};
+  uint32_t d_socketUDPRecvBuffer{0};
+  uint32_t d_hashPerturbation{0};
+  uint16_t d_maxUDPOutstanding{std::numeric_limits<uint16_t>::max()};
+  uint8_t d_udpTimeout{2};
+  bool d_randomizeUDPSocketsToBackend{false};
+  bool d_randomizeIDsToBackend{false};
+  bool d_ringsRecordQueries{true};
+  bool d_ringsRecordResponses{true};
+};
+
+/* this part of the configuration can be updated at runtime via
+   a RCU-like mechanism */
+struct RuntimeConfiguration
+{
+  rules::RuleChains d_ruleChains;
+  servers_t d_backends;
+#ifndef DISABLE_CARBON
+  std::vector<dnsdist::Carbon::Endpoint> d_carbonEndpoints;
+#endif /* DISABLE_CARBON */
+  std::map<std::string, std::shared_ptr<ServerPool>> d_pools;
+  std::shared_ptr<const CredentialsHolder> d_webPassword;
+  std::shared_ptr<const CredentialsHolder> d_webAPIKey;
+  std::optional<std::unordered_map<std::string, std::string>> d_webCustomHeaders;
+  std::shared_ptr<ServerPolicy> d_lbPolicy;
+  NetmaskGroup d_ACL;
+  NetmaskGroup d_proxyProtocolACL;
+  NetmaskGroup d_consoleACL;
+  NetmaskGroup d_webServerACL;
+  std::optional<ComboAddress> d_webServerAddress{std::nullopt};
+  dnsdist::QueryCount::Configuration d_queryCountConfig;
+  ComboAddress d_consoleServerAddress{"127.0.0.1:5199"};
+  std::string d_consoleKey;
+  std::string d_secPollSuffix{"secpoll.powerdns.com."};
+  std::string d_apiConfigDirectory;
+  uint64_t d_dynBlocksPurgeInterval{60};
+  size_t d_maxTCPQueriesPerConn{0};
+  size_t d_maxTCPConnectionDuration{0};
+  size_t d_proxyProtocolMaximumSize{512};
+  uint32_t d_staleCacheEntriesTTL{0};
+  uint32_t d_secPollInterval{3600};
+  uint32_t d_consoleOutputMsgMaxSize{10000000};
+  uint16_t d_payloadSizeSelfGenAnswers{s_defaultPayloadSizeSelfGenAnswers};
+  uint16_t d_tcpRecvTimeout{2};
+  uint16_t d_tcpSendTimeout{2};
+  /* rfc7871: "11.1. Privacy" */
+  uint16_t d_ECSSourcePrefixV4{24};
+  uint16_t d_ECSSourcePrefixV6{56};
+  uint16_t d_cacheCleaningDelay{60};
+  uint16_t d_cacheCleaningPercentage{100};
+  uint16_t d_tlsSessionCacheCleanupDelay{60};
+  uint16_t d_tlsSessionCacheSessionValidity{600};
+  uint16_t d_tlsSessionCacheMaxSessionsPerBackend{20};
+  DNSAction::Action d_dynBlockAction{DNSAction::Action::Drop};
+  bool d_apiRequiresAuthentication{true};
+  bool d_dashboardRequiresAuthentication{true};
+  bool d_statsRequireAuthentication{true};
+  bool d_truncateTC{false};
+  bool d_fixupCase{false};
+  bool d_queryCountEnabled{false};
+  bool d_ecsOverride{false};
+  bool d_verbose{false};
+  bool d_verboseHealthChecks{false};
+  bool d_apiReadWrite{false};
+  bool d_roundrobinFailOnNoServer{false};
+  bool d_servFailOnNoPolicy{false};
+  bool d_allowEmptyResponse{false};
+  bool d_dropEmptyQueries{false};
+  bool d_snmpEnabled{false};
+  bool d_snmpTrapsEnabled{false};
+  bool d_consoleEnabled{false};
+  bool d_logConsoleConnections{true};
+  bool d_addEDNSToSelfGeneratedResponses{true};
+  bool d_applyACLToProxiedClients{false};
+};
+
+/* Be careful not to hold on this for too long, it can be invalidated
+   by the next call to getCurrentRuntimeConfiguration() from the
+   same thread, so better be sure that any function you are not calling
+   while holding to this reference does not call getCurrentRuntimeConfiguration()
+   itself. When in doubt, better call getCurrentRuntimeConfiguration() twice.
+*/
+const RuntimeConfiguration& getCurrentRuntimeConfiguration();
+/* Get the runtime-immutable configuration */
+const ImmutableConfiguration& getImmutableConfiguration();
+/* Update the runtime-immutable part of the configuration. This function can only be called
+   during configuration time (isConfigurationDone() returns false), and will throw otherwise. */
+void updateImmutableConfiguration(const std::function<void(ImmutableConfiguration&)>& mutator);
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator);
+/* Whether parsing the configuration is done, meaning the runtime-immutable part of the
+   configuration is now sealed */
+bool isImmutableConfigurationDone();
+void setImmutableConfigurationDone();
+}
index 6696843fd91e1ff743d3c56df1855faebd4c6e3d..12926eeedf94dcf0f022a973a2a1ffc14d3df376 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifdef HAVE_LIBEDIT
 #if defined(__OpenBSD__) || defined(__NetBSD__)
-// If this is not undeffed, __attribute__ wil be redefined by /usr/include/readline/rlstdc.h
+// If this is not undeffed, __attribute__ will be redefined by /usr/include/readline/rlstdc.h
 #undef __STRICT_ANSI__
 #include <readline/readline.h>
 #include <readline/history.h>
 #include "dnsdist.hh"
 #include "dnsdist-console.hh"
 #include "dnsdist-crypto.hh"
+#include "dnsdist-lua.hh"
 #include "threadname.hh"
 
-GlobalStateHolder<NetmaskGroup> g_consoleACL;
-vector<pair<struct timeval, string>> g_confDelta;
-std::string g_consoleKey;
-bool g_logConsoleConnections{true};
-bool g_consoleEnabled{false};
-uint32_t g_consoleOutputMsgMaxSize{10000000};
+static LockGuarded<std::vector<pair<timeval, string>>> s_confDelta;
 
 static ConcurrentConnectionManager s_connManager(100);
 
@@ -96,12 +92,6 @@ private:
   FDWrapper d_fileDesc;
 };
 
-void setConsoleMaximumConcurrentConnections(size_t max)
-{
-  s_connManager.setMaxConcurrentConnections(max);
-}
-
-// MUST BE CALLED UNDER A LOCK - right now the LuaLock
 static void feedConfigDelta(const std::string& line)
 {
   if (line.empty()) {
@@ -109,7 +99,15 @@ static void feedConfigDelta(const std::string& line)
   }
   timeval now{};
   gettimeofday(&now, nullptr);
-  g_confDelta.emplace_back(now, line);
+  s_confDelta.lock()->emplace_back(now, line);
+}
+
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta()
+{
+  return *(s_confDelta.lock());
+}
 }
 
 #ifdef HAVE_LIBEDIT
@@ -156,7 +154,7 @@ static ConsoleCommandResult getMsgLen32(int fileDesc, uint32_t* len)
     }
 
     *len = ntohl(raw);
-    if (*len > g_consoleOutputMsgMaxSize) {
+    if (*len > dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize) {
       return ConsoleCommandResult::TooLarge;
     }
 
@@ -181,7 +179,8 @@ static bool putMsgLen32(int fileDesc, uint32_t len)
 
 static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string& line, dnsdist::crypto::authenticated::Nonce& readingNonce, dnsdist::crypto::authenticated::Nonce& writingNonce, const bool outputEmptyLine)
 {
-  string msg = dnsdist::crypto::authenticated::encryptSym(line, g_consoleKey, writingNonce);
+  const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
+  string msg = dnsdist::crypto::authenticated::encryptSym(line, consoleKey, writingNonce);
   const auto msgLen = msg.length();
   if (msgLen > std::numeric_limits<uint32_t>::max()) {
     cerr << "Encrypted message is too long to be sent to the server, " << std::to_string(msgLen) << " > " << std::numeric_limits<uint32_t>::max() << endl;
@@ -201,7 +200,7 @@ static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string&
     return commandResult;
   }
   if (commandResult == ConsoleCommandResult::TooLarge) {
-    cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << g_consoleOutputMsgMaxSize << "), closing that connection" << endl;
+    cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize << "), closing that connection" << endl;
     return commandResult;
   }
 
@@ -216,21 +215,27 @@ static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string&
   msg.clear();
   msg.resize(len);
   readn2(fileDesc, msg.data(), len);
-  msg = dnsdist::crypto::authenticated::decryptSym(msg, g_consoleKey, readingNonce);
+  msg = dnsdist::crypto::authenticated::decryptSym(msg, consoleKey, readingNonce);
   cout << msg;
   cout.flush();
 
   return ConsoleCommandResult::Valid;
 }
 
-void doClient(ComboAddress server, const std::string& command)
+namespace dnsdist::console
+{
+void doClient(const std::string& command)
 {
-  if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+  //coverity[auto_causes_copy]
+  const auto consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
+  //coverity[auto_causes_copy]
+  const auto server = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleServerAddress;
+  if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
     cerr << "The currently configured console key is not valid, please configure a valid key using the setKey() directive" << endl;
     return;
   }
 
-  if (g_verbose) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
     cout << "Connecting to " << server.toStringWithPort() << endl;
   }
 
@@ -471,10 +476,11 @@ void doConsole()
     }
   }
 }
+}
 
 #ifndef DISABLE_COMPLETION
 /**** CARGO CULT CODE AHEAD ****/
-const std::vector<ConsoleKeyword> g_consoleKeywords
+static const std::vector<dnsdist::console::ConsoleKeyword> s_consoleKeywords
 {
   /* keyword, function, parameters, description */
   {"addACL", true, "netmask", "add to the ACL set who can use this server"},
@@ -838,7 +844,8 @@ const std::vector<ConsoleKeyword> g_consoleKeywords
     {"topResponseRules", true, "[top][, vars]", "show `top` response rules"},
     {"topRules", true, "[top][, vars]", "show `top` rules"},
     {"topSelfAnsweredResponseRules", true, "[top][, vars]", "show `top` self-answered response rules"},
-    {"topSlow", true, "[top][, limit][, labels]", "show `top` queries slower than `limit` milliseconds, grouped by last `labels` labels"},
+    {"topSlow", true, "[top][, limit][, labels]", "show `top` queries slower than `limit` milliseconds (timeouts excepted), grouped by last `labels` labels"},
+    {"topTimeouts", true, "[top][, labels]", "show `top` queries that timed out, grouped by last `labels` labels"},
     {"TrailingDataRule", true, "", "Matches if the query has trailing data"},
     {"truncateTC", true, "bool", "if set (defaults to no starting with dnsdist 1.2.0) truncate TC=1 answers so they are actually empty. Fixes an issue for PowerDNS Authoritative Server 2.9.22. Note: turning this on breaks compatibility with RFC 6891."},
     {"unregisterDynBPFFilter", true, "DynBPFFilter", "unregister this dynamic BPF filter"},
@@ -851,7 +858,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords
 #if defined(HAVE_LIBEDIT)
 extern "C"
 {
-  static char* my_generator(const char* text, int state)
+  static char* dnsdist_completion_generator(const char* text, int state)
   {
     string textStr(text);
     /* to keep it readable, we try to keep only 4 keywords per line
@@ -862,7 +869,7 @@ extern "C"
       s_counter = 0;
     }
 
-    for (const auto& keyword : g_consoleKeywords) {
+    for (const auto& keyword : s_consoleKeywords) {
       if (boost::starts_with(keyword.name, textStr) && counter++ == s_counter) {
         std::string value(keyword.name);
         s_counter++;
@@ -878,12 +885,12 @@ extern "C"
     return nullptr;
   }
 
-  char** my_completion(const char* text, int start, int end)
+  static char** dnsdist_completion_callback(const char* text, int start, int end)
   {
     char** matches = nullptr;
     if (start == 0) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): readline
-      matches = rl_completion_matches(const_cast<char*>(text), &my_generator);
+      matches = rl_completion_matches(const_cast<char*>(text), &dnsdist_completion_generator);
     }
 
     // skip default filename completion.
@@ -895,6 +902,33 @@ extern "C"
 #endif /* HAVE_LIBEDIT */
 #endif /* DISABLE_COMPLETION */
 
+namespace dnsdist::console
+{
+#ifndef DISABLE_COMPLETION
+const std::vector<ConsoleKeyword>& getConsoleKeywords()
+{
+  return s_consoleKeywords;
+}
+#endif /* DISABLE_COMPLETION */
+
+void setupCompletion()
+{
+#ifndef DISABLE_COMPLETION
+#ifdef HAVE_LIBEDIT
+  rl_attempted_completion_function = dnsdist_completion_callback;
+  rl_completion_append_character = 0;
+#endif /* DISABLE_COMPLETION */
+#endif /* HAVE_LIBEDIT */
+}
+
+void clearHistory()
+{
+#ifdef HAVE_LIBEDIT
+  clear_history();
+#endif /* HAVE_LIBEDIT */
+  s_confDelta.lock()->clear();
+}
+
 static void controlClientThread(ConsoleConnection&& conn)
 {
   try {
@@ -902,6 +936,8 @@ static void controlClientThread(ConsoleConnection&& conn)
 
     setTCPNoDelay(conn.getFD());
 
+    //coverity[auto_causes_copy]
+    const auto consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
     dnsdist::crypto::authenticated::Nonce theirs;
     dnsdist::crypto::authenticated::Nonce ours;
     dnsdist::crypto::authenticated::Nonce readingNonce;
@@ -926,10 +962,11 @@ static void controlClientThread(ConsoleConnection&& conn)
       }
 
       std::string line;
+      //coverity[tainted_data]
       line.resize(len);
       readn2(conn.getFD(), line.data(), len);
 
-      line = dnsdist::crypto::authenticated::decryptSym(line, g_consoleKey, readingNonce);
+      line = dnsdist::crypto::authenticated::decryptSym(line, consoleKey, readingNonce);
 
       string response;
       try {
@@ -1021,11 +1058,11 @@ static void controlClientThread(ConsoleConnection&& conn)
       catch (const LuaContext::SyntaxErrorException& e) {
         response = "Error: " + string(e.what()) + ": ";
       }
-      response = dnsdist::crypto::authenticated::encryptSym(response, g_consoleKey, writingNonce);
+      response = dnsdist::crypto::authenticated::encryptSym(response, consoleKey, writingNonce);
       putMsgLen32(conn.getFD(), response.length());
       writen2(conn.getFD(), response.c_str(), response.length());
     }
-    if (g_logConsoleConnections) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_logConsoleConnections) {
       infolog("Closed control connection from %s", conn.getClient().toStringWithPort());
     }
   }
@@ -1034,11 +1071,13 @@ static void controlClientThread(ConsoleConnection&& conn)
   }
 }
 
-// NOLINTNEXTLINE(performance-unnecessary-value-param): this is thread
-void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
+void controlThread(Socket&& acceptFD)
 {
   try {
     setThreadName("dnsdist/control");
+    const ComboAddress local = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleServerAddress;
+    s_connManager.setMaxConcurrentConnections(dnsdist::configuration::getImmutableConfiguration().d_consoleMaxConcurrentConnections);
+
     ComboAddress client;
     // make sure that the family matches the one from the listening IP,
     // so that getSocklen() returns the correct size later, otherwise
@@ -1046,25 +1085,25 @@ void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
     client.sin4.sin_family = local.sin4.sin_family;
 
     int sock{-1};
-    auto localACL = g_consoleACL.getLocal();
     infolog("Accepting control connections on %s", local.toStringWithPort());
 
-    while ((sock = SAccept(acceptFD->getHandle(), client)) >= 0) {
-
+    while ((sock = SAccept(acceptFD.getHandle(), client)) >= 0) {
+      const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
       FDWrapper socket(sock);
-      if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+      if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
         vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort());
         continue;
       }
 
-      if (!localACL->match(client)) {
+      const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+      if (!runtimeConfig.d_consoleACL.match(client)) {
         vinfolog("Control connection from %s dropped because of ACL", client.toStringWithPort());
         continue;
       }
 
       try {
         ConsoleConnection conn(client, std::move(socket));
-        if (g_logConsoleConnections) {
+        if (runtimeConfig.d_logConsoleConnections) {
           warnlog("Got control connection from %s", client.toStringWithPort());
         }
 
@@ -1080,11 +1119,4 @@ void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
     errlog("Control thread died: %s", e.what());
   }
 }
-
-void clearConsoleHistory()
-{
-#ifdef HAVE_LIBEDIT
-  clear_history();
-#endif /* HAVE_LIBEDIT */
-  g_confDelta.clear();
 }
index dd833c49e473f3346beac57c1b0cdc392f0c9959..ef27bc0a1be408cbfed0700c2d228236bf87d9d2 100644 (file)
  */
 #pragma once
 
+#include <vector>
+#include <string>
+
 #include "config.h"
 #include "sstuff.hh"
 
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta();
+void doClient(const std::string& command);
+void doConsole();
+void controlThread(Socket&& acceptFD);
+void clearHistory();
+
 #ifndef DISABLE_COMPLETION
 struct ConsoleKeyword
 {
@@ -42,23 +53,8 @@ struct ConsoleKeyword
     return res;
   }
 };
-extern const std::vector<ConsoleKeyword> g_consoleKeywords;
-extern "C"
-{
-  char** my_completion(const char* text, int start, int end);
-}
 
+const std::vector<ConsoleKeyword>& getConsoleKeywords();
 #endif /* DISABLE_COMPLETION */
-
-extern GlobalStateHolder<NetmaskGroup> g_consoleACL;
-extern std::string g_consoleKey; // in theory needs locking
-extern bool g_logConsoleConnections;
-extern bool g_consoleEnabled;
-extern uint32_t g_consoleOutputMsgMaxSize;
-
-void doClient(ComboAddress server, const std::string& command);
-void doConsole();
-void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local);
-void clearConsoleHistory();
-
-void setConsoleMaximumConcurrentConnections(size_t max);
+void setupCompletion();
+}
index bba713bb6f43170689c860cc4649c75f9837a7b7..07a2a85c6e70ffe4deeb7c293872917b83c6b78a 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "config.h"
 #include "dnsdist-discovery.hh"
+#include "dnsdist-backend.hh"
 #include "dnsdist.hh"
 #include "dnsdist-random.hh"
 #include "dnsparser.hh"
@@ -235,6 +236,7 @@ static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& exis
 
 bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
 {
+  const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
   const auto& backend = upgradeableBackend.d_ds;
   const auto& addr = backend->d_config.remote;
   try {
@@ -276,7 +278,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     uint16_t responseSize = 0;
     auto got = readn2WithTimeout(sock.getHandle(), &responseSize, sizeof(responseSize), remainingTime);
     if (got != sizeof(responseSize)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the ADD upgrade response size from backend %s: %d", addr.toStringWithPort(), got);
       }
       return false;
@@ -286,14 +288,14 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
 
     got = readn2WithTimeout(sock.getHandle(), packet.data(), packet.size(), remainingTime);
     if (got != packet.size()) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the ADD upgrade response from backend %s: %d", addr.toStringWithPort(), got);
       }
       return false;
     }
 
     if (packet.size() <= sizeof(struct dnsheader)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Too short answer of size %d received from the backend %s", packet.size(), addr.toStringWithPort());
       }
       return false;
@@ -302,14 +304,14 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     struct dnsheader d;
     memcpy(&d, packet.data(), sizeof(d));
     if (d.id != id) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid ID (%d / %d) received from the backend %s", d.id, id, addr.toStringWithPort());
       }
       return false;
     }
 
     if (d.rcode != RCode::NoError) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Response code '%s' received from the backend %s for '%s'", RCode::to_s(d.rcode), addr.toStringWithPort(), s_discoveryDomain);
       }
 
@@ -317,7 +319,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     }
 
     if (ntohs(d.qdcount) != 1) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer (qdcount %d) received from the backend %s", ntohs(d.qdcount), addr.toStringWithPort());
       }
       return false;
@@ -328,7 +330,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     DNSName receivedName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
 
     if (receivedName != s_discoveryDomain || receivedType != s_discoveryType || receivedClass != QClass::IN) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the backend %s", receivedName, s_discoveryDomain, QType(receivedType).toString(), s_discoveryType.toString(), QClass(receivedClass).toString(), QClass::IN.toString(), addr.toStringWithPort());
       }
       return false;
@@ -447,42 +449,38 @@ bool ServiceDiscovery::tryToUpgradeBackend(const UpgradeableBackend& backend)
 
     infolog("Added automatically upgraded server %s", newServer->getNameWithAddr());
 
-    auto localPools = g_pools.getCopy();
     if (!newServer->d_config.pools.empty()) {
       for (const auto& poolName : newServer->d_config.pools) {
-        addServerToPool(localPools, poolName, newServer);
+        addServerToPool(poolName, newServer);
       }
     }
     else {
-      addServerToPool(localPools, "", newServer);
+      addServerToPool("", newServer);
     }
 
     newServer->start();
 
-    auto states = g_dstates.getCopy();
-    states.push_back(newServer);
     /* remove the existing backend if needed */
     if (!backend.keepAfterUpgrade) {
-      for (auto it = states.begin(); it != states.end(); ++it) {
-        if (*it == backend.d_ds) {
-          states.erase(it);
-          break;
+      dnsdist::configuration::updateRuntimeConfiguration([&backend](dnsdist::configuration::RuntimeConfiguration& runtimeConfig) {
+        auto& backends = runtimeConfig.d_backends;
+        for (auto backendIt = backends.begin(); backendIt != backends.end(); ++backendIt) {
+          if (*backendIt == backend.d_ds) {
+            backends.erase(backendIt);
+            break;
+          }
         }
-      }
+      });
 
       for (const string& poolName : backend.d_ds->d_config.pools) {
-        removeServerFromPool(localPools, poolName, backend.d_ds);
+        removeServerFromPool(poolName, backend.d_ds);
       }
       /* the server might also be in the default pool */
-      removeServerFromPool(localPools, "", backend.d_ds);
+      removeServerFromPool("", backend.d_ds);
     }
 
-    std::stable_sort(states.begin(), states.end(), [](const decltype(newServer)& a, const decltype(newServer)& b) {
-      return a->d_config.order < b->d_config.order;
-    });
+    dnsdist::backend::registerNewBackend(newServer);
 
-    g_pools.setState(localPools);
-    g_dstates.setState(states);
     if (!backend.keepAfterUpgrade) {
       backend.d_ds->stop();
     }
index a15f2d5e9f54e99a59aedb5aace7f5d473dfe8ee..bfe0be3e07ed28bb51defbb6397b3c1d3bf0c6ec 100644 (file)
@@ -214,4 +214,23 @@ namespace PacketMangling
     return true;
   }
 }
+
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config)
+{
+  if (config.setAA) {
+    dnsheader.aa = *config.setAA;
+  }
+  if (config.setAD) {
+    dnsheader.ad = *config.setAD;
+  }
+  else {
+    dnsheader.ad = false;
+  }
+  if (config.setRA) {
+    dnsheader.ra = *config.setRA;
+  }
+  else {
+    dnsheader.ra = dnsheader.rd; // for good measure
+  }
+}
 }
index 4f7cdaded409702940563ef87f5e313ae8eeec7e..67d74a344205cacac42f67f1663fff9d99efc3a0 100644 (file)
@@ -60,4 +60,13 @@ namespace PacketMangling
   bool editDNSHeaderFromPacket(PacketBuffer& packet, const std::function<bool(dnsheader& header)>& editFunction);
   bool editDNSHeaderFromRawPacket(void* packet, const std::function<bool(dnsheader& header)>& editFunction);
 }
+
+struct ResponseConfig
+{
+  boost::optional<bool> setAA{boost::none};
+  boost::optional<bool> setAD{boost::none};
+  boost::optional<bool> setRA{boost::none};
+  uint32_t ttl{60};
+};
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config);
 }
diff --git a/pdns/dnsdistdist/dnsdist-dnsquestion.cc b/pdns/dnsdistdist/dnsdist-dnsquestion.cc
new file mode 100644 (file)
index 0000000..dde891b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist.hh"
+#include "dnsdist-configuration.hh"
+#include "dnsdist-dnsparser.hh"
+
+std::string DNSQuestion::getTrailingData() const
+{
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+  const auto* message = reinterpret_cast<const char*>(this->getData().data());
+  const uint16_t messageLen = getDNSPacketLength(message, this->getData().size());
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  return {message + messageLen, this->getData().size() - messageLen};
+}
+
+bool DNSQuestion::setTrailingData(const std::string& tail)
+{
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+  const char* message = reinterpret_cast<const char*>(this->data.data());
+  const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+  this->data.resize(messageLen);
+  if (!tail.empty()) {
+    if (!hasRoomFor(tail.size())) {
+      return false;
+    }
+    this->data.insert(this->data.end(), tail.begin(), tail.end());
+  }
+  return true;
+}
+
+bool DNSQuestion::editHeader(const std::function<bool(dnsheader&)>& editFunction)
+{
+  if (data.size() < sizeof(dnsheader)) {
+    throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
+  }
+  return dnsdist::PacketMangling::editDNSHeaderFromPacket(data, editFunction);
+}
+
+DNSQuestion::DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_) :
+  data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV6), ecsOverride(dnsdist::configuration::getCurrentRuntimeConfiguration().d_ecsOverride)
+{
+}
index 7f4ee53462f6103d91f65f24ce81236dace6a53e..a8dbd28ffdf9991189fe5709780985135a8ccfc9 100644 (file)
@@ -1,13 +1,12 @@
-
 #include "dnsdist.hh"
 #include "dnsdist-dynblocks.hh"
 #include "dnsdist-metrics.hh"
-
-GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
-GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-DNSAction::Action g_dynBlockAction = DNSAction::Action::Drop;
+#include "sholder.hh"
 
 #ifndef DISABLE_DYNBLOCKS
+static GlobalStateHolder<ClientAddressDynamicRules> s_dynblockNMG;
+static GlobalStateHolder<SuffixDynamicRules> s_dynblockSMT;
+
 void DynBlockRulesGroup::apply(const timespec& now)
 {
   counts_t counts;
@@ -29,7 +28,7 @@ void DynBlockRulesGroup::apply(const timespec& now)
     return;
   }
 
-  boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>> blocks;
+  boost::optional<ClientAddressDynamicRules> blocks;
   bool updated = false;
 
   for (const auto& entry : counts) {
@@ -115,7 +114,7 @@ void DynBlockRulesGroup::apply(const timespec& now)
   }
 
   if (updated && blocks) {
-    g_dynblockNMG.setState(std::move(*blocks));
+    s_dynblockNMG.setState(std::move(*blocks));
   }
 
   applySMT(now, statNodeRoot);
@@ -157,7 +156,7 @@ void DynBlockRulesGroup::applySMT(const struct timespec& now, StatNode& statNode
 
   if (!namesToBlock.empty()) {
     updated = false;
-    SuffixMatchTree<DynBlock> smtBlocks = g_dynblockSMT.getCopy();
+    auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
     for (auto& [name, parameters] : namesToBlock) {
       if (parameters.d_reason || parameters.d_action) {
         DynBlockRule rule(d_suffixMatchRule);
@@ -174,7 +173,7 @@ void DynBlockRulesGroup::applySMT(const struct timespec& now, StatNode& statNode
       }
     }
     if (updated) {
-      g_dynblockSMT.setState(std::move(smtBlocks));
+      s_dynblockSMT.setState(std::move(smtBlocks));
     }
   }
 }
@@ -202,19 +201,19 @@ bool DynBlockRulesGroup::checkIfResponseCodeMatches(const Rings::Response& respo
 
 /* return the actual action that will be taken by that block:
    - either the one set on that block, if any
-   - or the one set with setDynBlocksAction in g_dynBlockAction
+   - or the one set with setDynBlocksAction
 */
 static DNSAction::Action getActualAction(const DynBlock& block)
 {
   if (block.action != DNSAction::Action::None) {
     return block.action;
   }
-  return g_dynBlockAction;
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
 }
 
 namespace dnsdist::DynamicBlocks
 {
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet)
+bool addOrRefreshBlock(ClientAddressDynamicRules& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet)
 {
   unsigned int count = 0;
   bool expired = false;
@@ -279,7 +278,7 @@ bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const
   return true;
 }
 
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet)
+bool addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet)
 {
   unsigned int count = 0;
   /* be careful, if you try to insert a longer suffix
@@ -311,12 +310,13 @@ bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now
   if (!beQuiet && (got == nullptr || expired)) {
     warnlog("Inserting dynamic block for %s for %d seconds: %s", dblock.domain, dblock.until.tv_sec - now.tv_sec, dblock.reason);
   }
-  blocks.add(dblock.domain, std::move(dblock));
+  auto domain = dblock.domain;
+  blocks.add(domain, std::move(dblock));
   return true;
 }
 }
 
-void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
+void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
 {
   /* network exclusions are address-based only (no port) */
   if (d_excludedSubnets.match(requestor.getNetwork())) {
@@ -332,7 +332,7 @@ void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock,
     dblock.tagSettings = rule.d_tagSettings;
   }
   if (!blocks) {
-    blocks = g_dynblockNMG.getCopy();
+    blocks = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
   }
 
   updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, std::move(dblock), d_beQuiet);
@@ -346,7 +346,7 @@ void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock,
   }
 }
 
-void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
+void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
 {
   if (d_excludedDomains.check(name)) {
     /* do not add a block for excluded domains */
@@ -493,7 +493,7 @@ void DynBlockMaintenance::purgeExpired(const struct timespec& now)
   // since the block happens in kernel space.
   uint64_t bpfBlocked = 0;
   {
-    auto blocks = g_dynblockNMG.getLocal();
+    auto blocks = s_dynblockNMG.getLocal();
     std::vector<AddressAndPortRange> toRemove;
     for (const auto& entry : *blocks) {
       if (!(now < entry.second.until)) {
@@ -516,29 +516,29 @@ void DynBlockMaintenance::purgeExpired(const struct timespec& now)
       }
     }
     if (!toRemove.empty()) {
-      auto updated = g_dynblockNMG.getCopy();
+      auto updated = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
       for (const auto& entry : toRemove) {
         updated.erase(entry);
       }
-      g_dynblockNMG.setState(std::move(updated));
+      s_dynblockNMG.setState(std::move(updated));
       dnsdist::metrics::g_stats.dynBlocked += bpfBlocked;
     }
   }
 
   {
     std::vector<DNSName> toRemove;
-    auto blocks = g_dynblockSMT.getLocal();
-    blocks->visit([&toRemove, now](const SuffixMatchTree<DynBlock>& node) {
+    auto blocks = s_dynblockSMT.getLocal();
+    blocks->visit([&toRemove, now](const SuffixDynamicRules& node) {
       if (!(now < node.d_value.until)) {
         toRemove.push_back(node.d_value.domain);
       }
     });
     if (!toRemove.empty()) {
-      auto updated = g_dynblockSMT.getCopy();
+      auto updated = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
       for (const auto& entry : toRemove) {
         updated.remove(entry);
       }
-      g_dynblockSMT.setState(std::move(updated));
+      s_dynblockSMT.setState(std::move(updated));
     }
   }
 }
@@ -550,7 +550,7 @@ std::map<std::string, std::list<std::pair<AddressAndPortRange, unsigned int>>> D
     return results;
   }
 
-  auto blocks = g_dynblockNMG.getLocal();
+  auto blocks = s_dynblockNMG.getLocal();
   for (const auto& entry : *blocks) {
     auto& topsForReason = results[entry.second.reason];
     uint64_t value = entry.second.blocks.load();
@@ -583,8 +583,8 @@ std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaint
     return results;
   }
 
-  auto blocks = g_dynblockSMT.getLocal();
-  blocks->visit([&results, topN](const SuffixMatchTree<DynBlock>& node) {
+  auto blocks = s_dynblockSMT.getLocal();
+  blocks->visit([&results, topN](const SuffixDynamicRules& node) {
     auto& topsForReason = results[node.d_value.reason];
     if (topsForReason.size() < topN || topsForReason.front().second < node.d_value.blocks) {
       auto newEntry = std::pair(node.d_value.domain, node.d_value.blocks.load());
@@ -612,8 +612,6 @@ struct DynBlockEntryStat
 std::list<DynBlockMaintenance::MetricsSnapshot> DynBlockMaintenance::s_metricsData;
 
 LockGuarded<DynBlockMaintenance::Tops> DynBlockMaintenance::s_tops;
-size_t DynBlockMaintenance::s_topN{20};
-time_t DynBlockMaintenance::s_expiredDynBlocksPurgeInterval{60};
 
 void DynBlockMaintenance::collectMetrics()
 {
@@ -773,13 +771,14 @@ void DynBlockMaintenance::run()
   static const time_t metricsGenerationInterval = 60;
 
   time_t now = time(nullptr);
-  time_t nextExpiredPurge = now + s_expiredDynBlocksPurgeInterval;
-  time_t nextMetricsCollect = now + metricsCollectionInterval;
+  auto purgeInterval = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlocksPurgeInterval;
+  time_t nextExpiredPurge = now + static_cast<time_t>(purgeInterval);
+  time_t nextMetricsCollect = now + static_cast<time_t>(metricsCollectionInterval);
   time_t nextMetricsGeneration = now + metricsGenerationInterval;
 
   while (true) {
     time_t sleepDelay = std::numeric_limits<time_t>::max();
-    if (s_expiredDynBlocksPurgeInterval > 0) {
+    if (purgeInterval > 0) {
       sleepDelay = std::min(sleepDelay, (nextExpiredPurge - now));
     }
     sleepDelay = std::min(sleepDelay, (nextMetricsCollect - now));
@@ -807,21 +806,21 @@ void DynBlockMaintenance::run()
         nextMetricsGeneration = now + metricsGenerationInterval;
       }
 
-      if (s_expiredDynBlocksPurgeInterval > 0 && now >= nextExpiredPurge) {
-        struct timespec tspec
-        {
-        };
+      purgeInterval = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlocksPurgeInterval;
+      if (purgeInterval > 0 && now >= nextExpiredPurge) {
+        timespec tspec{};
         gettime(&tspec);
         purgeExpired(tspec);
 
         now = time(nullptr);
-        nextExpiredPurge = now + s_expiredDynBlocksPurgeInterval;
+        nextExpiredPurge = now + static_cast<time_t>(purgeInterval);
       }
     }
     catch (const std::exception& e) {
       warnlog("Error in the dynamic block maintenance thread: %s", e.what());
     }
     catch (...) {
+      vinfolog("Unhandled error in the dynamic block maintenance thread");
     }
   }
 }
@@ -994,4 +993,52 @@ std::string DynBlockRulesGroup::DynBlockCacheMissRatioRule::toString() const
   return result.str();
 }
 
+namespace dnsdist::DynamicBlocks
+{
+const ClientAddressDynamicRules& getClientAddressDynamicRules()
+{
+  static thread_local auto t_localRules = s_dynblockNMG.getLocal();
+  return *t_localRules;
+}
+
+ClientAddressDynamicRules getClientAddressDynamicRulesCopy()
+{
+  return s_dynblockNMG.getCopy();
+}
+
+const SuffixDynamicRules& getSuffixDynamicRules()
+{
+  static thread_local auto t_localRules = s_dynblockSMT.getLocal();
+  return *t_localRules;
+}
+
+SuffixDynamicRules getSuffixDynamicRulesCopy()
+{
+  return s_dynblockSMT.getCopy();
+}
+
+void setClientAddressDynamicRules(ClientAddressDynamicRules&& rules)
+{
+  s_dynblockNMG.setState(std::move(rules));
+}
+
+void setSuffixDynamicRules(SuffixDynamicRules&& rules)
+{
+  s_dynblockSMT.setState(std::move(rules));
+}
+
+void clearClientAddressDynamicRules()
+{
+  ClientAddressDynamicRules emptyNMG;
+  setClientAddressDynamicRules(std::move(emptyNMG));
+}
+
+void clearSuffixDynamicRules()
+{
+  SuffixDynamicRules emptySMT;
+  setSuffixDynamicRules(std::move(emptySMT));
+}
+
+}
+
 #endif /* DISABLE_DYNBLOCKS */
index 2cb39fcc28ddd3946ee414f614b08ced4e6a1961..7c240f5fd26ca1362b74f1c8aece1863aa3dc73a 100644 (file)
@@ -33,6 +33,8 @@ extern "C"
 #include "dnsdist-lua-inspection-ffi.h"
 }
 
+#include "ext/luawrapper/include/LuaContext.hpp"
+
 // dnsdist_ffi_stat_node_t is a lightuserdata
 template <>
 struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*>
@@ -68,7 +70,76 @@ struct dnsdist_ffi_stat_node_t
   SMTBlockParameters& d_blockParameters;
 };
 
+struct DynBlock
+{
+  DynBlock()
+  {
+    until.tv_sec = 0;
+    until.tv_nsec = 0;
+  }
+
+  DynBlock(const std::string& reason_, const struct timespec& until_, const DNSName& domain_, DNSAction::Action action_) :
+    reason(reason_), domain(domain_), until(until_), action(action_)
+  {
+  }
+
+  DynBlock(const DynBlock& rhs) :
+    reason(rhs.reason), domain(rhs.domain), until(rhs.until), tagSettings(rhs.tagSettings), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
+  {
+    blocks.store(rhs.blocks);
+  }
+
+  DynBlock(DynBlock&& rhs) :
+    reason(std::move(rhs.reason)), domain(std::move(rhs.domain)), until(rhs.until), tagSettings(std::move(rhs.tagSettings)), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
+  {
+    blocks.store(rhs.blocks);
+  }
+
+  DynBlock& operator=(const DynBlock& rhs)
+  {
+    reason = rhs.reason;
+    until = rhs.until;
+    domain = rhs.domain;
+    action = rhs.action;
+    blocks.store(rhs.blocks);
+    warning = rhs.warning;
+    bpf = rhs.bpf;
+    tagSettings = rhs.tagSettings;
+    return *this;
+  }
+
+  DynBlock& operator=(DynBlock&& rhs)
+  {
+    reason = std::move(rhs.reason);
+    until = rhs.until;
+    domain = std::move(rhs.domain);
+    action = rhs.action;
+    blocks.store(rhs.blocks);
+    warning = rhs.warning;
+    bpf = rhs.bpf;
+    tagSettings = std::move(rhs.tagSettings);
+    return *this;
+  }
+
+  struct TagSettings
+  {
+    std::string d_name;
+    std::string d_value;
+  };
+
+  string reason;
+  DNSName domain;
+  timespec until{};
+  std::shared_ptr<TagSettings> tagSettings{nullptr};
+  mutable std::atomic<uint32_t> blocks{0};
+  DNSAction::Action action{DNSAction::Action::None};
+  bool warning{false};
+  bool bpf{false};
+};
+
 using dnsdist_ffi_dynamic_block_inserted_hook = std::function<void(uint8_t type, const char* key, const char* reason, uint8_t action, uint64_t duration, bool warning)>;
+using ClientAddressDynamicRules = NetmaskTree<DynBlock, AddressAndPortRange>;
+using SuffixDynamicRules = SuffixMatchTree<DynBlock>;
 
 class DynBlockRulesGroup
 {
@@ -290,15 +361,15 @@ private:
   void applySMT(const struct timespec& now, StatNode& statNodeRoot);
   bool checkIfQueryTypeMatches(const Rings::Query& query);
   bool checkIfResponseCodeMatches(const Rings::Response& response);
-  void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
-  void addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
+  void addOrRefreshBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
+  void addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
 
-  void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+  void addBlock(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
   {
     addOrRefreshBlock(blocks, now, requestor, rule, updated, false);
   }
 
-  void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+  void handleWarning(boost::optional<ClientAddressDynamicRules>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
   {
     addOrRefreshBlock(blocks, now, requestor, rule, updated, true);
   }
@@ -358,8 +429,6 @@ public:
   static std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> getTopSuffixes(size_t topN);
   static void purgeExpired(const struct timespec& now);
 
-  static time_t s_expiredDynBlocksPurgeInterval;
-
 private:
   static void collectMetrics();
   static void generateMetrics();
@@ -380,12 +449,21 @@ private:
   /* s_metricsData should only be accessed by the dynamic blocks maintenance thread so it does not need a lock */
   // need N+1 datapoints to be able to do the diff after a collection point has been reached
   static std::list<MetricsSnapshot> s_metricsData;
-  static size_t s_topN;
+  static constexpr size_t s_topN{20};
 };
 
 namespace dnsdist::DynamicBlocks
 {
-bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet);
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet);
+bool addOrRefreshBlock(ClientAddressDynamicRules& blocks, const timespec& now, const AddressAndPortRange& requestor, DynBlock&& dblock, bool beQuiet);
+bool addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const timespec& now, DynBlock&& dblock, bool beQuiet);
+
+const ClientAddressDynamicRules& getClientAddressDynamicRules();
+const SuffixDynamicRules& getSuffixDynamicRules();
+ClientAddressDynamicRules getClientAddressDynamicRulesCopy();
+SuffixDynamicRules getSuffixDynamicRulesCopy();
+void setClientAddressDynamicRules(ClientAddressDynamicRules&& rules);
+void setSuffixDynamicRules(SuffixDynamicRules&& rules);
+void clearClientAddressDynamicRules();
+void clearSuffixDynamicRules();
 }
 #endif /* DISABLE_DYNBLOCKS */
index ab09f6dc0f46aa054b4797e556f71addb474cc45..2f76f9fcafdfd8ccbe48bda06665c5cf6f9a05a1 100644 (file)
@@ -21,6 +21,8 @@
  */
 #include "dnsdist-dynbpf.hh"
 
+std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
+
 bool DynBPFFilter::block(const ComboAddress& addr, const struct timespec& until)
 {
   bool inserted = false;
index cfb5d6b3c2ada4ca57535bb9f1ed4982aa8249a0..c9eca259ed39d30ac25fefd3439cf71faaeafc0c 100644 (file)
@@ -75,3 +75,5 @@ private:
   };
   LockGuarded<Data> d_data;
 };
+
+extern std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
index 988345640745df06b77b93ea0912671543d73d61..782be6b75a65d80b7538778030486ba8610d1e81 100644 (file)
 #include "ednsoptions.hh"
 #include "ednssubnet.hh"
 
-/* when we add EDNS to a query, we don't want to advertise
-   a large buffer size */
-size_t g_EdnsUDPPayloadSize = 512;
-static const uint16_t defaultPayloadSizeSelfGenAnswers = 1232;
-static_assert(defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
-uint16_t g_PayloadSizeSelfGenAnswers{defaultPayloadSizeSelfGenAnswers};
-
-/* draft-ietf-dnsop-edns-client-subnet-04 "11.1.  Privacy" */
-uint16_t g_ECSSourcePrefixV4 = 24;
-uint16_t g_ECSSourcePrefixV6 = 56;
-
-bool g_ECSOverride{false};
-bool g_addEDNSToSelfGeneratedResponses{true};
-
 int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
 {
   if (initialPacket.size() < sizeof(dnsheader)) {
@@ -256,12 +242,12 @@ bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket,
       /* addOrReplaceEDNSOption will set it to false if there is already an existing option */
       optionAdded = true;
       addOrReplaceEDNSOption(options, optionToReplace, optionAdded, overrideExisting, newOptionContent);
-      packetWriter.addOpt(recordHeader.d_class, edns0.extRCode, edns0.extFlags, options, edns0.version);
+      packetWriter.addOpt(recordHeader.d_class, edns0.extRCode, ntohs(edns0.extFlags), options, edns0.version);
     }
   }
 
   if (ednsAdded) {
-    packetWriter.addOpt(g_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
+    packetWriter.addOpt(dnsdist::configuration::s_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
     optionAdded = true;
   }
 
@@ -394,8 +380,10 @@ int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optL
   return ENOENT;
 }
 
+namespace dnsdist
+{
 /* extract the start of the OPT RR in a QUERY packet if any */
-int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining)
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t qnameWireLength, uint16_t* optRDPosition, size_t* remaining)
 {
   if (optRDPosition == nullptr || remaining == nullptr) {
     throw std::runtime_error("Invalid values passed to getEDNSOptionsStart");
@@ -403,7 +391,7 @@ int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_
 
   const dnsheader_aligned dnsHeader(packet.data());
 
-  if (offset >= packet.size()) {
+  if (qnameWireLength >= packet.size()) {
     return ENOENT;
   }
 
@@ -411,7 +399,7 @@ int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_
     return ENOENT;
   }
 
-  size_t pos = sizeof(dnsheader) + offset;
+  size_t pos = sizeof(dnsheader) + qnameWireLength;
   pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
 
   if (pos >= packet.size()) {
@@ -442,6 +430,7 @@ int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_
 
   return 0;
 }
+}
 
 void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength)
 {
@@ -545,7 +534,7 @@ bool parseEDNSOptions(const DNSQuestion& dnsQuestion)
 
   size_t remaining = 0;
   uint16_t optRDPosition{};
-  int res = getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+  int res = dnsdist::getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
 
   if (res == 0) {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -585,7 +574,7 @@ static bool addECSToExistingOPT(PacketBuffer& packet, size_t maximumSize, const
 
 static bool addEDNSWithECS(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
 {
-  if (!generateOptRR(newECSOption, packet, maximumSize, g_EdnsUDPPayloadSize, 0, false)) {
+  if (!generateOptRR(newECSOption, packet, maximumSize, dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
     return false;
   }
 
@@ -630,7 +619,7 @@ bool handleEDNSClientSubnet(PacketBuffer& packet, const size_t maximumSize, cons
   uint16_t optRDPosition = 0;
   size_t remaining = 0;
 
-  int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
+  int res = dnsdist::getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
 
   if (res != 0) {
     /* no EDNS but there might be another record in additional (TSIG?) */
@@ -918,7 +907,7 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dnsQuestion, bool nxd, const DNSNa
   bool hadEDNS = false;
   bool dnssecOK = false;
 
-  if (g_addEDNSToSelfGeneratedResponses) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
     uint16_t payloadSize = 0;
     uint16_t zValue = 0;
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -997,7 +986,7 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dnsQuestion, bool nxd, const DNSNa
 
   if (hadEDNS) {
     /* now we need to add a new OPT record */
-    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
   }
 
   return true;
@@ -1010,7 +999,7 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dnsQuestion)
   size_t remaining = 0;
 
   auto& packet = dnsQuestion.getMutableData();
-  int res = getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+  int res = dnsdist::getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
 
   if (res != 0) {
     /* if the initial query did not have EDNS0, we are done */
@@ -1036,63 +1025,115 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dnsQuestion)
     return true;
   });
 
-  if (g_addEDNSToSelfGeneratedResponses) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
     /* now we need to add a new OPT record */
-    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
   }
 
   /* otherwise we are just fine */
   return true;
 }
 
+namespace dnsdist
+{
+static std::optional<size_t> getEDNSRecordPosition(const DNSQuestion& dnsQuestion)
+{
+  try {
+    const auto& packet = dnsQuestion.getData();
+    if (packet.size() <= sizeof(dnsheader)) {
+      return std::nullopt;
+    }
+
+    uint16_t optRDPosition = 0;
+    size_t remaining = 0;
+    auto res = getEDNSOptionsStart(packet, dnsQuestion.ids.qname.wirelength(), &optRDPosition, &remaining);
+    if (res != 0) {
+      return std::nullopt;
+    }
+
+    if (optRDPosition < DNS_TTL_SIZE) {
+      return std::nullopt;
+    }
+
+    return optRDPosition - DNS_TTL_SIZE;
+  }
+  catch (...) {
+    return std::nullopt;
+  }
+}
+
 // goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
 int getEDNSZ(const DNSQuestion& dnsQuestion)
 {
   try {
-    const auto& dnsHeader = dnsQuestion.getHeader();
-    if (ntohs(dnsHeader->qdcount) != 1 || dnsHeader->ancount != 0 || ntohs(dnsHeader->arcount) != 1 || dnsHeader->nscount != 0) {
+    auto position = getEDNSRecordPosition(dnsQuestion);
+
+    if (!position) {
       return 0;
     }
 
-    if (dnsQuestion.getData().size() <= sizeof(dnsheader)) {
+    const auto& packet = dnsQuestion.getData();
+    if ((*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= packet.size()) {
       return 0;
     }
 
-    size_t pos = sizeof(dnsheader) + dnsQuestion.ids.qname.wirelength() + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+    return 0x100 * packet.at(*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) + packet.at(*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1);
+  }
+  catch (...) {
+    return 0;
+  }
+}
 
-    if (dnsQuestion.getData().size() <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
-      return 0;
+std::optional<uint8_t> getEDNSVersion(const DNSQuestion& dnsQuestion)
+{
+  try {
+    auto position = getEDNSRecordPosition(dnsQuestion);
+
+    if (!position) {
+      return std::nullopt;
     }
 
     const auto& packet = dnsQuestion.getData();
-    if (packet.at(pos) != 0) {
-      /* not root, so not a valid OPT record */
-      return 0;
+    if ((*position + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) >= packet.size()) {
+      return std::nullopt;
     }
 
-    pos++;
+    return packet.at(*position + EDNS_EXTENDED_RCODE_SIZE);
+  }
+  catch (...) {
+    return std::nullopt;
+  }
+}
 
-    uint16_t qtype = packet.at(pos) * 256 + packet.at(pos + 1);
-    pos += DNS_TYPE_SIZE;
-    pos += DNS_CLASS_SIZE;
+std::optional<uint8_t> getEDNSExtendedRCode(const DNSQuestion& dnsQuestion)
+{
+  try {
+    auto position = getEDNSRecordPosition(dnsQuestion);
 
-    if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= packet.size()) {
-      return 0;
+    if (!position) {
+      return std::nullopt;
     }
 
-    return 0x100 * packet.at(pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE) + packet.at(pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1);
+    const auto& packet = dnsQuestion.getData();
+    if ((*position + EDNS_EXTENDED_RCODE_SIZE) >= packet.size()) {
+      return std::nullopt;
+    }
+
+    return packet.at(*position);
   }
   catch (...) {
-    return 0;
+    return std::nullopt;
   }
 }
 
+}
+
 bool queryHasEDNS(const DNSQuestion& dnsQuestion)
 {
   uint16_t optRDPosition = 0;
   size_t ecsRemaining = 0;
 
-  int res = getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &ecsRemaining);
+  int res = dnsdist::getEDNSOptionsStart(dnsQuestion.getData(), dnsQuestion.ids.qname.wirelength(), &optRDPosition, &ecsRemaining);
   return res == 0;
 }
 
@@ -1150,7 +1191,7 @@ bool setEDNSOption(DNSQuestion& dnsQuestion, uint16_t ednsCode, const std::strin
   }
 
   auto& data = dnsQuestion.getMutableData();
-  if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+  if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
     dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
       header.arcount = htons(1);
       return true;
@@ -1196,7 +1237,7 @@ bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uint
     buffer.resize(sizeof(dnsheader) + qnameLength + sizeof(uint16_t) + sizeof(uint16_t));
     if (hadEDNS) {
       DNSQuestion dnsQuestion(state, buffer);
-      if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, g_PayloadSizeSelfGenAnswers, 0)) {
+      if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0)) {
         return false;
       }
     }
index 94eccc1a1d7b9a953a9f5017326c95826c0a69b8..0c6a4780ed29e1427099c9316b66d6ea19bb08ca 100644 (file)
@@ -31,9 +31,6 @@ struct DNSQuestion;
 // root label (1), type (2), class (2), ttl (4) + rdlen (2)
 static const size_t optRecordMinimumSize = 11;
 
-extern size_t g_EdnsUDPPayloadSize;
-extern uint16_t g_PayloadSizeSelfGenAnswers;
-
 int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent);
 bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent);
 int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optLen, bool* last);
@@ -41,7 +38,6 @@ bool generateOptRR(const std::string& optRData, PacketBuffer& res, size_t maximu
 void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
 int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove);
 int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent);
-int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining);
 bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
 bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
 bool addEDNSToQueryTurnedResponse(DNSQuestion& dnsQuestion);
@@ -52,7 +48,6 @@ bool handleEDNSClientSubnet(PacketBuffer& packet, size_t maximumSize, size_t qna
 
 bool parseEDNSOptions(const DNSQuestion& dnsQuestion);
 
-int getEDNSZ(const DNSQuestion& dnsQuestion);
 bool queryHasEDNS(const DNSQuestion& dnsQuestion);
 bool getEDNS0Record(const PacketBuffer& packet, EDNS0Record& edns0);
 
@@ -62,4 +57,12 @@ struct InternalQueryState;
 namespace dnsdist
 {
 bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uint8_t rcode, bool clearAnswers);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+int getEDNSOptionsStart(const PacketBuffer& packet, const size_t qnameWireLength, uint16_t* optRDPosition, size_t* remaining);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+int getEDNSZ(const DNSQuestion& dnsQuestion);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+std::optional<uint8_t> getEDNSVersion(const DNSQuestion& dnsQuestion);
+/* this method only works for queries (qdcount == 1, ancount == nscount == 0, arcount == 1) */
+std::optional<uint8_t> getEDNSExtendedRCode(const DNSQuestion& dnsQuestion);
 }
diff --git a/pdns/dnsdistdist/dnsdist-frontend.cc b/pdns/dnsdistdist/dnsdist-frontend.cc
new file mode 100644 (file)
index 0000000..8e75ee3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-frontend.hh"
+#include "dnsdist.hh"
+#include "dnsdist-configuration.hh"
+
+namespace dnsdist
+{
+
+const std::vector<std::shared_ptr<ClientState>>& getFrontends()
+{
+  return dnsdist::configuration::getImmutableConfiguration().d_frontends;
+}
+
+std::vector<std::shared_ptr<DNSCryptContext>> getDNSCryptFrontends()
+{
+  std::vector<std::shared_ptr<DNSCryptContext>> results;
+  for (const auto& frontend : getFrontends()) {
+    if (frontend->getProtocol() == dnsdist::Protocol::DNSCryptUDP || frontend->getProtocol() == dnsdist::Protocol::DNSCryptTCP) {
+      results.push_back(frontend->dnscryptCtx);
+    }
+  }
+  return results;
+}
+
+std::vector<std::shared_ptr<TLSFrontend>> getDoTFrontends()
+{
+  std::vector<std::shared_ptr<TLSFrontend>> results;
+  for (const auto& frontend : getFrontends()) {
+    if (frontend->getProtocol() == dnsdist::Protocol::DoT) {
+      results.push_back(frontend->tlsFrontend);
+    }
+  }
+  return results;
+}
+
+std::vector<std::shared_ptr<DOHFrontend>> getDoHFrontends()
+{
+  std::vector<std::shared_ptr<DOHFrontend>> results;
+  for (const auto& frontend : getFrontends()) {
+    if (frontend->getProtocol() == dnsdist::Protocol::DoH) {
+      results.push_back(frontend->dohFrontend);
+    }
+  }
+  return results;
+}
+
+std::vector<std::shared_ptr<DOQFrontend>> getDoQFrontends()
+{
+  std::vector<std::shared_ptr<DOQFrontend>> results;
+  for (const auto& frontend : getFrontends()) {
+    if (frontend->getProtocol() == dnsdist::Protocol::DoQ) {
+      results.push_back(frontend->doqFrontend);
+    }
+  }
+  return results;
+}
+
+std::vector<std::shared_ptr<DOH3Frontend>> getDoH3Frontends()
+{
+  std::vector<std::shared_ptr<DOH3Frontend>> results;
+  for (const auto& frontend : getFrontends()) {
+    if (frontend->getProtocol() == dnsdist::Protocol::DoH3) {
+      results.push_back(frontend->doh3Frontend);
+    }
+  }
+  return results;
+}
+}
similarity index 56%
rename from pdns/doh.hh
rename to pdns/dnsdistdist/dnsdist-frontend.hh
index 58a26f16918f6e33da6ecd2ed728800c25e324c3..fe7f1c2a92f81c0c46416b972d8ae4ef6056d9be 100644 (file)
  */
 #pragma once
 
-#include "config.h"
-
-#ifdef HAVE_DNS_OVER_HTTPS
-#ifdef HAVE_LIBH2OEVLOOP
-
-#include <ctime>
 #include <memory>
-#include <string>
-
-struct CrossProtocolQuery;
-struct DNSQuestion;
-
-std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
+#include <vector>
 
-#include "dnsdist-doh-common.hh"
+struct ClientState;
+class DNSCryptContext;
+class TLSFrontend;
+struct DOHFrontend;
+struct DOQFrontend;
+struct DOH3Frontend;
 
-struct H2ODOHFrontend : public DOHFrontend
+namespace dnsdist
 {
-public:
-
-  void setup() override;
-  void reloadCertificates() override;
-
-  void rotateTicketsKey(time_t now) override;
-  void loadTicketsKeys(const std::string& keyFile) override;
-  void handleTicketsKeyRotation() override;
-  std::string getNextTicketsKeyRotation() const override;
-  size_t getTicketsKeysCount() override;
-};
-
-void dohThread(ClientState* clientState);
-
-#endif /* HAVE_LIBH2OEVLOOP */
-#endif /* HAVE_DNS_OVER_HTTPS  */
+const std::vector<std::shared_ptr<ClientState>>& getFrontends();
+std::vector<std::shared_ptr<DNSCryptContext>> getDNSCryptFrontends();
+std::vector<std::shared_ptr<TLSFrontend>> getDoTFrontends();
+std::vector<std::shared_ptr<DOHFrontend>> getDoHFrontends();
+std::vector<std::shared_ptr<DOQFrontend>> getDoQFrontends();
+std::vector<std::shared_ptr<DOH3Frontend>> getDoH3Frontends();
+}
index 36805573e7842624ecefe7ecc223e7270f92250a..7f02b24f76d017729f4c68d4f38770d34e134e91 100644 (file)
 #include "tcpiohandler-mplexer.hh"
 #include "dnswriter.hh"
 #include "dolog.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-random.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-session-cache.hh"
 
-bool g_verboseHealthChecks{false};
-
 struct HealthCheckData
 {
   enum class TCPState : uint8_t
@@ -66,11 +65,12 @@ struct HealthCheckData
 
 static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   const auto& downstream = data->d_ds;
   try {
     if (data->d_buffer.size() < sizeof(dnsheader)) {
       ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader));
       }
       return false;
@@ -79,7 +79,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     dnsheader_aligned responseHeader(data->d_buffer.data());
     if (responseHeader.get()->id != data->d_queryID) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID);
       }
       return false;
@@ -87,7 +87,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (!responseHeader.get()->qr) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr());
       }
       return false;
@@ -95,7 +95,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (responseHeader.get()->rcode == RCode::ServFail) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr());
       }
       return false;
@@ -103,7 +103,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (downstream->d_config.mustResolve && (responseHeader.get()->rcode == RCode::NXDomain || responseHeader.get()->rcode == RCode::Refused)) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
       }
       return false;
@@ -116,7 +116,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (receivedName != data->d_checkName || receivedType != data->d_checkType || receivedClass != data->d_checkClass) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
       }
       return false;
@@ -124,13 +124,13 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
   }
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
     }
     return false;
   }
   catch (...) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
     }
     return false;
@@ -181,6 +181,7 @@ private:
 static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
 {
   auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
 
   ssize_t got = 0;
   ComboAddress from;
@@ -202,7 +203,7 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
         return;
       }
 
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
       }
       ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
@@ -216,7 +217,7 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 
   /* we are using a connected socket but hey.. */
   if (from != data->d_ds->d_config.remote) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort());
     }
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
@@ -288,13 +289,15 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    if (g_verboseHealthChecks) {
+    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what());
     }
   }
   catch (...) {
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    if (g_verboseHealthChecks) {
+    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", data->d_ds->getNameWithAddr());
     }
   }
@@ -302,6 +305,7 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 
 bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initialCheck)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   try {
     uint16_t queryID = dnsdist::getRandomDNSID();
     DNSName checkName = downstream->d_config.checkName;
@@ -350,7 +354,7 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
 #ifdef SO_BINDTODEVICE
     if (!downstream->d_config.sourceItfName.empty()) {
       int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, downstream->d_config.sourceItfName.c_str(), downstream->d_config.sourceItfName.length());
-      if (res != 0 && g_verboseHealthChecks) {
+      if (res != 0 && verboseHealthChecks) {
         infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror());
       }
     }
@@ -382,7 +386,7 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
       ssize_t sent = udpClientSendRequestToBackend(downstream, data->d_udpSocket.getHandle(), packet, true);
       if (sent < 0) {
         int ret = errno;
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret);
         }
         return false;
@@ -435,13 +439,13 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
     return true;
   }
   catch (const std::exception& e) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
     }
     return false;
   }
   catch (...) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
     }
     return false;
@@ -450,13 +454,14 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
 
 void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   while (mplexer.getWatchedFDCount(false) > 0 || mplexer.getWatchedFDCount(true) > 0) {
     struct timeval now
     {
     };
     int ret = mplexer.run(&now, 100);
     if (ret == -1) {
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Error while waiting for the health check response from backends: %d", ret);
       }
       break;
@@ -485,7 +490,7 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         else {
           mplexer.removeReadFD(timeout.first);
         }
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
 
@@ -496,13 +501,13 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         /* this is not supposed to happen as the file descriptor has to be
            there for us to reach that code, and the submission code should not throw,
            but let's provide a nice error message if it ever does. */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
         }
       }
       catch (...) {
         /* this is even less likely to happen */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
       }
@@ -517,7 +522,7 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
       try {
         /* UDP does not block while writing, H2 is handled separately */
         data->d_ioState.reset();
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
 
@@ -527,13 +532,13 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
       catch (const std::exception& e) {
         /* this is not supposed to happen as the submission code should not throw,
            but let's provide a nice error message if it ever does. */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
         }
       }
       catch (...) {
         /* this is even less likely to happen */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
       }
index e9da6c66de8b0eb56baadb0c0fc57e78461822d0..fa3cf57aa81849b0b79650b40582307ceee2bca8 100644 (file)
@@ -25,7 +25,5 @@
 #include "mplexer.hh"
 #include "sstuff.hh"
 
-extern bool g_verboseHealthChecks;
-
 bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initial = false);
 void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial = false);
index b4e3532619acba185df68dec0242143f25803425..337a062669d89a38ef0d8cfb49b269c977210949 100644 (file)
@@ -27,9 +27,6 @@
 #include "dolog.hh"
 #include "dns_random.hh"
 
-GlobalStateHolder<ServerPolicy> g_policy;
-bool g_roundrobinFailOnNoServer{false};
-
 static constexpr size_t s_staticArrayCutOff = 16;
 template <typename T> using DynamicIndexArray = std::vector<std::pair<T, size_t>>;
 template <typename T> using StaticIndexArray = std::array<std::pair<T, size_t>, s_staticArrayCutOff>;
@@ -84,16 +81,15 @@ shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVec
   return leastOutstanding(servers, dq);
 }
 
-double g_weightedBalancingFactor = 0;
-
 template <class T> static std::shared_ptr<DownstreamState> getValRandom(const ServerPolicy::NumberedServerVector& servers, T& poss, const unsigned int val, const double targetLoad)
 {
   constexpr int max = std::numeric_limits<int>::max();
   int sum = 0;
 
   size_t usableServers = 0;
+  const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
   for (const auto& d : servers) {      // w=1, w=10 -> 1, 11
-    if (d.second->isUp() && (g_weightedBalancingFactor == 0 || (d.second->outstanding <= (targetLoad * d.second->d_config.d_weight)))) {
+    if (d.second->isUp() && (weightedBalancingFactor == 0 || (static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight)))) {
       // Don't overflow sum when adding high weights
       if (d.second->d_config.d_weight > max - sum) {
         sum = max;
@@ -125,8 +121,8 @@ static shared_ptr<DownstreamState> valrandom(const unsigned int val, const Serve
 {
   using ValRandomType = int;
   double targetLoad = std::numeric_limits<double>::max();
-
-  if (g_weightedBalancingFactor > 0) {
+  const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+  if (weightedBalancingFactor > 0) {
     /* we start with one, representing the query we are currently handling */
     double currentLoad = 1;
     size_t totalWeight = 0;
@@ -138,7 +134,7 @@ static shared_ptr<DownstreamState> valrandom(const unsigned int val, const Serve
     }
 
     if (totalWeight > 0) {
-      targetLoad = (currentLoad / totalWeight) * g_weightedBalancingFactor;
+      targetLoad = (currentLoad / static_cast<double>(totalWeight)) * weightedBalancingFactor;
     }
   }
 
@@ -157,9 +153,6 @@ shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVector& se
   return valrandom(dns_random_uint32(), servers);
 }
 
-uint32_t g_hashperturb;
-double g_consistentHashBalancingFactor = 0;
-
 shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash)
 {
   return valrandom(hash, servers);
@@ -167,7 +160,8 @@ shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedServerVe
 
 shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
 {
-  return whashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+  return whashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
 }
 
 shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t qhash)
@@ -177,7 +171,8 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
   shared_ptr<DownstreamState> ret = nullptr, first = nullptr;
 
   double targetLoad = std::numeric_limits<double>::max();
-  if (g_consistentHashBalancingFactor > 0) {
+  const auto consistentHashBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+  if (consistentHashBalancingFactor > 0) {
     /* we start with one, representing the query we are currently handling */
     double currentLoad = 1;
     size_t totalWeight = 0;
@@ -189,12 +184,12 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
     }
 
     if (totalWeight > 0) {
-      targetLoad = (currentLoad / totalWeight) * g_consistentHashBalancingFactor;
+      targetLoad = (currentLoad / static_cast<double>(totalWeight)) * consistentHashBalancingFactor;
     }
   }
 
   for (const auto& d: servers) {
-    if (d.second->isUp() && (g_consistentHashBalancingFactor == 0 || d.second->outstanding <= (targetLoad * d.second->d_config.d_weight))) {
+    if (d.second->isUp() && (consistentHashBalancingFactor == 0 || static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight))) {
       // make sure hashes have been computed
       if (!d.second->hashesComputed) {
         d.second->hash();
@@ -229,7 +224,8 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
 
 shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
 {
-  return chashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+  return chashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
 }
 
 shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
@@ -248,7 +244,7 @@ shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector&
   }
 
   if (candidates.empty()) {
-    if (g_roundrobinFailOnNoServer) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_roundrobinFailOnNoServer) {
       return shared_ptr<DownstreamState>();
     }
     for (auto& d : servers) {
@@ -260,31 +256,37 @@ shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector&
   return servers.at(candidates.at((counter++) % candidates.size()) - 1).second;
 }
 
-const std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const pools_t& pools, const std::string& poolName)
+std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const std::string& poolName)
 {
-  std::shared_ptr<ServerPool> pool = getPool(pools, poolName);
+  std::shared_ptr<ServerPool> pool = getPool(poolName);
   return pool->getServers();
 }
 
-std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName)
+std::shared_ptr<ServerPool> createPoolIfNotExists(const string& poolName)
 {
-  std::shared_ptr<ServerPool> pool;
-  pools_t::iterator it = pools.find(poolName);
-  if (it != pools.end()) {
-    pool = it->second;
+  {
+    const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+    const auto poolIt = pools.find(poolName);
+    if (poolIt != pools.end()) {
+      return poolIt->second;
+    }
   }
-  else {
-    if (!poolName.empty())
-      vinfolog("Creating pool %s", poolName);
-    pool = std::make_shared<ServerPool>();
-    pools.insert(std::pair<std::string, std::shared_ptr<ServerPool> >(poolName, pool));
+
+  if (!poolName.empty()) {
+    vinfolog("Creating pool %s", poolName);
   }
+
+  auto pool = std::make_shared<ServerPool>();
+  dnsdist::configuration::updateRuntimeConfiguration([&poolName,&pool](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_pools.emplace(poolName, pool);
+  });
+
   return pool;
 }
 
-void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy)
+void setPoolPolicy(const string& poolName, std::shared_ptr<ServerPolicy> policy)
 {
-  std::shared_ptr<ServerPool> pool = createPoolIfNotExists(pools, poolName);
+  std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
   if (!poolName.empty()) {
     vinfolog("Setting pool %s server selection policy to %s", poolName, policy->getName());
   } else {
@@ -293,9 +295,9 @@ void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<Serve
   pool->policy = std::move(policy);
 }
 
-void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server)
+void addServerToPool(const string& poolName, std::shared_ptr<DownstreamState> server)
 {
-  std::shared_ptr<ServerPool> pool = createPoolIfNotExists(pools, poolName);
+  std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
   if (!poolName.empty()) {
     vinfolog("Adding server to pool %s", poolName);
   } else {
@@ -304,9 +306,9 @@ void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<Dow
   pool->addServer(server);
 }
 
-void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server)
+void removeServerFromPool(const string& poolName, std::shared_ptr<DownstreamState> server)
 {
-  std::shared_ptr<ServerPool> pool = getPool(pools, poolName);
+  std::shared_ptr<ServerPool> pool = getPool(poolName);
 
   if (!poolName.empty()) {
     vinfolog("Removing server from pool %s", poolName);
@@ -318,15 +320,15 @@ void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_pt
   pool->removeServer(server);
 }
 
-std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName)
+std::shared_ptr<ServerPool> getPool(const std::string& poolName)
 {
-  pools_t::const_iterator it = pools.find(poolName);
-
-  if (it == pools.end()) {
+  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+  auto poolIt = pools.find(poolName);
+  if (poolIt == pools.end()) {
     throw std::out_of_range("No pool named " + poolName);
   }
 
-  return it->second;
+  return poolIt->second;
 }
 
 ServerPolicy::ServerPolicy(const std::string& name_, const std::string& code): d_name(name_), d_perThreadPolicyCode(code), d_isLua(true), d_isFFI(true), d_isPerThread(true)
@@ -336,24 +338,30 @@ ServerPolicy::ServerPolicy(const std::string& name_, const std::string& code): d
   auto ret = tmpContext.executeCode<ServerPolicy::ffipolicyfunc_t>(code);
 }
 
-thread_local ServerPolicy::PerThreadState ServerPolicy::t_perThreadState;
+struct ServerPolicy::PerThreadState
+{
+  LuaContext d_luaContext;
+  std::unordered_map<std::string, ffipolicyfunc_t> d_policies;
+};
+
+thread_local std::unique_ptr<ServerPolicy::PerThreadState> ServerPolicy::t_perThreadState;
 
 const ServerPolicy::ffipolicyfunc_t& ServerPolicy::getPerThreadPolicy() const
 {
   auto& state = t_perThreadState;
-  if (!state.d_initialized) {
-    setupLuaLoadBalancingContext(state.d_luaContext);
-    state.d_initialized = true;
+  if (!state) {
+    state = std::make_unique<ServerPolicy::PerThreadState>();
+    setupLuaLoadBalancingContext(state->d_luaContext);
   }
 
-  const auto& it = state.d_policies.find(d_name);
-  if (it != state.d_policies.end()) {
-    return it->second;
+  const auto& policyIt = state->d_policies.find(d_name);
+  if (policyIt != state->d_policies.end()) {
+    return policyIt->second;
   }
 
-  auto newPolicy = state.d_luaContext.executeCode<ServerPolicy::ffipolicyfunc_t>(d_perThreadPolicyCode);
-  state.d_policies[d_name] = std::move(newPolicy);
-  return state.d_policies.at(d_name);
+  auto newPolicy = state->d_luaContext.executeCode<ServerPolicy::ffipolicyfunc_t>(d_perThreadPolicyCode);
+  state->d_policies[d_name] = std::move(newPolicy);
+  return state->d_policies.at(d_name);
 }
 
 std::shared_ptr<DownstreamState> ServerPolicy::getSelectedBackend(const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) const
index 78fcb22016b2cc29ea059dd354f21aa5fe8461c0..3ddc4ec592d502867c184239614c2d4506030eee 100644 (file)
@@ -25,6 +25,7 @@ struct dnsdist_ffi_servers_list_t;
 struct dnsdist_ffi_server_t;
 struct dnsdist_ffi_dnsquestion_t;
 
+struct DNSQuestion;
 struct DownstreamState;
 
 struct PerThreadPoliciesState;
@@ -35,8 +36,8 @@ public:
   template <class T>
   using NumberedVector = std::vector<std::pair<unsigned int, T>>;
   using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
-  typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
-  typedef std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)> ffipolicyfunc_t;
+  using policyfunc_t = std::function<std::shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)>;
+  using ffipolicyfunc_t = std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)>;
 
   ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_) :
     d_name(name_), d_policy(std::move(policy_)), d_isLua(isLua_)
@@ -68,15 +69,10 @@ public:
   }
 
 private:
-  struct PerThreadState
-  {
-    LuaContext d_luaContext;
-    std::unordered_map<std::string, ffipolicyfunc_t> d_policies;
-    bool d_initialized{false};
-  };
+  struct PerThreadState;
 
   const ffipolicyfunc_t& getPerThreadPolicy() const;
-  static thread_local PerThreadState t_perThreadState;
+  static thread_local std::unique_ptr<PerThreadState> t_perThreadState;
 
 public:
   std::string d_name;
@@ -92,14 +88,14 @@ public:
 
 struct ServerPool;
 
-using pools_t = map<std::string, std::shared_ptr<ServerPool>>;
-std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
-std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
-void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<ServerPolicy> policy);
-void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
-void removeServerFromPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server);
+using pools_t = std::map<std::string, std::shared_ptr<ServerPool>>;
+std::shared_ptr<ServerPool> getPool(const std::string& poolName);
+std::shared_ptr<ServerPool> createPoolIfNotExists(const string& poolName);
+void setPoolPolicy(const string& poolName, std::shared_ptr<ServerPolicy> policy);
+void addServerToPool(const string& poolName, std::shared_ptr<DownstreamState> server);
+void removeServerFromPool(const string& poolName, std::shared_ptr<DownstreamState> server);
 
-const std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const map<std::string, std::shared_ptr<ServerPool>>& pools, const std::string& poolName);
+std::shared_ptr<const ServerPolicy::NumberedServerVector> getDownstreamCandidates(const std::string& poolName);
 
 std::shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 
@@ -110,8 +106,3 @@ std::shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedSer
 std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 std::shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash);
 std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
-
-extern double g_consistentHashBalancingFactor;
-extern double g_weightedBalancingFactor;
-extern uint32_t g_hashperturb;
-extern bool g_roundrobinFailOnNoServer;
index 51348375f016fec54ffa17801f30f98f0f186d74..5d6be53d5234548463b582f03498efbe57bce65c 100644 (file)
@@ -33,6 +33,7 @@
 #include "dnsdist-proxy-protocol.hh"
 #include "dnsdist-kvs.hh"
 #include "dnsdist-rule-chains.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-svc.hh"
 
 #include "dnstap.hh"
@@ -254,7 +255,7 @@ std::map<std::string, double> TeeAction::getStats() const
 void TeeAction::worker()
 {
   setThreadName("dnsdist/TeeWork");
-  std::array<char, s_udpIncomingBufferSize> packet{};
+  std::array<char, dnsdist::configuration::s_udpIncomingBufferSize> packet{};
   ssize_t res = 0;
   const dnsheader_aligned dnsheader(packet.data());
   for (;;) {
@@ -383,13 +384,13 @@ public:
   {
     return "set rcode " + std::to_string(d_rcode);
   }
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
   uint8_t d_rcode;
 };
 
@@ -413,13 +414,13 @@ public:
   {
     return "set ercode " + ERCode::to_s(d_rcode);
   }
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
   uint8_t d_rcode;
 };
 
@@ -436,7 +437,6 @@ public:
         throw std::runtime_error("Unable to generate a valid SVC record from the supplied parameters");
       }
 
-      d_totalPayloadsSize += payload.size();
       d_payloads.push_back(std::move(payload));
 
       for (const auto& hint : param.second.ipv4hints) {
@@ -451,72 +451,28 @@ public:
 
   DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
   {
-    /* it will likely be a bit bigger than that because of additionals */
-    auto numberOfRecords = d_payloads.size();
-    const auto qnameWireLength = dnsquestion->ids.qname.wirelength();
-    if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize)) {
+    if (!dnsdist::svc::generateSVCResponse(*dnsquestion, d_payloads, d_additionals4, d_additionals6, d_responseConfig)) {
       return Action::None;
     }
 
-    PacketBuffer newPacket;
-    newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize);
-    GenericDNSPacketWriter<PacketBuffer> packetWriter(newPacket, dnsquestion->ids.qname, dnsquestion->ids.qtype);
-    for (const auto& payload : d_payloads) {
-      packetWriter.startRecord(dnsquestion->ids.qname, dnsquestion->ids.qtype, d_responseConfig.ttl);
-      packetWriter.xfrBlob(payload);
-      packetWriter.commit();
-    }
-
-    if (newPacket.size() < dnsquestion->getMaximumSize()) {
-      for (const auto& additional : d_additionals4) {
-        packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
-        packetWriter.xfrCAWithoutPort(4, additional.second);
-        packetWriter.commit();
-      }
-    }
-
-    if (newPacket.size() < dnsquestion->getMaximumSize()) {
-      for (const auto& additional : d_additionals6) {
-        packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
-        packetWriter.xfrCAWithoutPort(6, additional.second);
-        packetWriter.commit();
-      }
-    }
-
-    if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
-      bool dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
-      packetWriter.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
-      packetWriter.commit();
-    }
-
-    if (newPacket.size() >= dnsquestion->getMaximumSize()) {
-      /* sorry! */
-      return Action::None;
-    }
-
-    packetWriter.getHeader()->id = dnsquestion->getHeader()->id;
-    packetWriter.getHeader()->qr = true; // for good measure
-    setResponseHeadersFromConfig(*packetWriter.getHeader(), d_responseConfig);
-    dnsquestion->getMutableData() = std::move(newPacket);
-
     return Action::HeaderModify;
   }
+
   [[nodiscard]] std::string toString() const override
   {
     return "spoof SVC record ";
   }
 
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
   std::vector<std::vector<uint8_t>> d_payloads{};
   std::set<std::pair<DNSName, ComboAddress>> d_additionals4{};
   std::set<std::pair<DNSName, ComboAddress>> d_additionals6{};
-  size_t d_totalPayloadsSize{0};
 };
 
 class TCAction : public DNSAction
@@ -951,9 +907,9 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string*
 
   bool dnssecOK = false;
   bool hadEDNS = false;
-  if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
     hadEDNS = true;
-    dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
+    dnssecOK = ((dnsdist::getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
   }
 
   auto& data = dnsquestion->getMutableData();
@@ -1054,7 +1010,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string*
   });
 
   if (hadEDNS && !raw) {
-    addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
+    addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
   }
 
   return Action::HeaderModify;
@@ -1104,7 +1060,7 @@ public:
     }
 
     auto& data = dnsquestion->getMutableData();
-    if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+    if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
       dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
         header.arcount = htons(1);
         return true;
@@ -1189,7 +1145,7 @@ public:
   {
     auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
     if (!filepointer) {
-      if (!d_verboseOnly || g_verbose) {
+      if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         if (d_includeTimestamp) {
           infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dnsquestion->getQueryRealTime().tv_sec), static_cast<unsigned long>(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id);
         }
@@ -1301,7 +1257,7 @@ public:
   {
     auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
     if (!filepointer) {
-      if (!d_verboseOnly || g_verbose) {
+      if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         if (d_includeTimestamp) {
           infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast<unsigned long long>(response->getQueryRealTime().tv_sec), static_cast<unsigned long>(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id);
         }
@@ -1758,7 +1714,7 @@ public:
   }
   DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
   {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(*dnsquestion, d_reason);
     }
 
@@ -1965,7 +1921,7 @@ public:
   }
   DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
   {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(*response, d_reason);
     }
 
@@ -2094,13 +2050,13 @@ public:
     return "return an HTTP status of " + std::to_string(d_code);
   }
 
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
   PacketBuffer d_body;
   std::string d_contentType;
   int d_code;
@@ -2258,15 +2214,15 @@ public:
 
   [[nodiscard]] std::string toString() const override
   {
-    return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA";
+    return std::string(d_nxd ? "NXD" : "NODATA") + " with SOA";
   }
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
 
   DNSName d_zone;
   DNSName d_mname;
@@ -2420,8 +2376,8 @@ private:
   EDNSExtendedError d_ede;
 };
 
-template <typename T, typename ActionT>
-static void addAction(GlobalStateHolder<vector<T>>* someRuleActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
+template <typename ActionT, typename IdentifierT>
+static void addAction(IdentifierT identifier, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
 {
   setLuaSideEffect();
 
@@ -2432,14 +2388,14 @@ static void addAction(GlobalStateHolder<vector<T>>* someRuleActions, const luadn
   checkAllParametersConsumed("addAction", params);
 
   auto rule = makeRule(var, "addAction");
-  someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions) {
-    ruleactions.push_back({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
+  dnsdist::configuration::updateRuntimeConfiguration([identifier, &rule, &action, &name, &uuid, creationOrder](dnsdist::configuration::RuntimeConfiguration& config) {
+    dnsdist::rules::add(config.d_ruleChains, identifier, std::move(rule), action, std::move(name), uuid, creationOrder);
   });
 }
 
 using responseParams_t = std::unordered_map<std::string, boost::variant<bool, uint32_t>>;
 
-static void parseResponseConfig(boost::optional<responseParams_t>& vars, ResponseConfig& config)
+static void parseResponseConfig(boost::optional<responseParams_t>& vars, dnsdist::ResponseConfig& config)
 {
   getOptionalValue<uint32_t>(vars, "ttl", config.ttl);
   getOptionalValue<bool>(vars, "aa", config.setAA);
@@ -2447,25 +2403,6 @@ static void parseResponseConfig(boost::optional<responseParams_t>& vars, Respons
   getOptionalValue<bool>(vars, "ra", config.setRA);
 }
 
-void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config)
-{
-  if (config.setAA) {
-    dnsheader.aa = *config.setAA;
-  }
-  if (config.setAD) {
-    dnsheader.ad = *config.setAD;
-  }
-  else {
-    dnsheader.ad = false;
-  }
-  if (config.setRA) {
-    dnsheader.ra = *config.setRA;
-  }
-  else {
-    dnsheader.ra = dnsheader.rd; // for good measure
-  }
-}
-
 // NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
 void setupLuaActions(LuaContext& luaCtx)
 {
@@ -2481,20 +2418,21 @@ void setupLuaActions(LuaContext& luaCtx)
     return std::make_shared<dnsdist::rules::RuleAction>(ruleaction);
   });
 
-  for (const auto& chain : dnsdist::rules::getRuleChains()) {
+  for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) {
     auto fullName = std::string("add") + chain.prefix + std::string("Action");
     luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
         throw std::runtime_error(fullName + "() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
       }
 
-      addAction(&chain.holder, var, boost::get<std::shared_ptr<DNSAction>>(era), params);
+      addAction(chain.identifier, var, boost::get<std::shared_ptr<DNSAction>>(era), params);
     });
     fullName = std::string("get") + chain.prefix + std::string("Action");
     luaCtx.writeFunction(fullName, [&chain](unsigned int num) {
       setLuaNoSideEffect();
       boost::optional<std::shared_ptr<DNSAction>> ret;
-      auto ruleactions = chain.holder.getCopy();
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& ruleactions = dnsdist::rules::getRuleChain(chains, chain.identifier);
       if (num < ruleactions.size()) {
         ret = ruleactions[num].d_action;
       }
@@ -2502,14 +2440,14 @@ void setupLuaActions(LuaContext& luaCtx)
     });
   }
 
-  for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
+  for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) {
     const auto fullName = std::string("add") + chain.prefix + std::string("ResponseAction");
     luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
       if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
         throw std::runtime_error(fullName + "() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
       }
 
-      addAction(&chain.holder, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
+      addAction(chain.identifier, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
     });
   }
 
index 9297dbccad81d75d9524170d0e86c09e3f91d87f..bf6c47361c9eb52ad2690cf3b9abd89bf04f254d 100644 (file)
@@ -25,6 +25,7 @@
 #include "dnsdist-ecs.hh"
 #include "dnsdist-internal-queries.hh"
 #include "dnsdist-lua.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsparser.hh"
 
 // NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
@@ -121,7 +122,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
     }
     dnsQuestion.ids.d_protoBufData->d_requestorID = newValue; });
   luaCtx.registerFunction<bool (DNSQuestion::*)() const>("getDO", [](const DNSQuestion& dnsQuestion) {
-    return getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
+    return dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
   });
   luaCtx.registerFunction<std::string (DNSQuestion::*)() const>("getContent", [](const DNSQuestion& dnsQuestion) {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -169,7 +170,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
 
   luaCtx.registerFunction<void (DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dnsQuestion, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(dnsQuestion, reason ? *reason : "");
     }
 #endif /* HAVE_NET_SNMP */
@@ -422,7 +423,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
     editDNSPacketTTL(reinterpret_cast<char*>(dnsResponse.getMutableData().data()), dnsResponse.getData().size(), editFunc);
   });
   luaCtx.registerFunction<bool (DNSResponse::*)() const>("getDO", [](const DNSResponse& dnsQuestion) {
-    return getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
+    return dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO;
   });
   luaCtx.registerFunction<std::string (DNSResponse::*)() const>("getContent", [](const DNSResponse& dnsQuestion) {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -496,7 +497,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
 
   luaCtx.registerFunction<void (DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dnsResponse, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(dnsResponse, reason ? *reason : "");
     }
 #endif /* HAVE_NET_SNMP */
index f71bf37516de58b4bbd36e8be4a0e9a62ae3cb07..65470b2b870df40924927609a35972fdbd962522 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "config.h"
 #include "dnsdist.hh"
+#include "dnsdist-cache.hh"
 #include "dnsdist-lua.hh"
 
 #include <boost/lexical_cast.hpp>
index e2bf8aef86961b4c96b750aab90f2939cdd02302..f08746d9f5b2ed3cbf486171d91d30081f7e17a3 100644 (file)
@@ -23,6 +23,9 @@
 #include "config.h"
 #include "dnsdist.hh"
 #include "dnsdist-async.hh"
+#include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
+#include "dnsdist-frontend.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-resolver.hh"
 #include "dnsdist-svc.hh"
@@ -31,8 +34,7 @@
 #include "dolog.hh"
 #include "xsk.hh"
 
-// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
-void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
+void setupLuaBindingsLogging(LuaContext& luaCtx)
 {
   luaCtx.writeFunction("vinfolog", [](const string& arg) {
     vinfolog("%s", arg);
@@ -50,7 +52,11 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
     g_outputBuffer += arg;
     g_outputBuffer += "\n";
   });
+}
 
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
+void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
+{
   /* Exceptions */
   luaCtx.registerFunction<string (std::exception_ptr::*)() const>("__tostring", [](const std::exception_ptr& eptr) -> std::string {
     try {
@@ -113,15 +119,11 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
   /* DownstreamState */
   luaCtx.registerFunction<void (DownstreamState::*)(int)>("setQPS", [](DownstreamState& state, int lim) { state.qps = lim > 0 ? QPSLimiter(lim, lim) : QPSLimiter(); });
   luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
-    auto localPools = g_pools.getCopy();
-    addServerToPool(localPools, pool, state);
-    g_pools.setState(localPools);
+    addServerToPool(pool, state);
     state->d_config.pools.insert(pool);
   });
   luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
-    auto localPools = g_pools.getCopy();
-    removeServerFromPool(localPools, pool, state);
-    g_pools.setState(localPools);
+    removeServerFromPool(pool, state);
     state->d_config.pools.erase(pool);
   });
   luaCtx.registerFunction<uint64_t (DownstreamState::*)() const>("getOutstanding", [](const DownstreamState& state) { return state.outstanding.load(); });
@@ -144,7 +146,10 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
   });
   luaCtx.registerFunction<std::string (DownstreamState::*)() const>("getName", [](const DownstreamState& state) -> const std::string& { return state.getName(); });
   luaCtx.registerFunction<std::string (DownstreamState::*)() const>("getNameWithAddr", [](const DownstreamState& state) -> const std::string& { return state.getNameWithAddr(); });
-  luaCtx.registerMember("upStatus", &DownstreamState::upStatus);
+  luaCtx.registerMember<bool(DownstreamState::*)>(
+    "upStatus",
+    [](const DownstreamState& state) -> bool { return state.upStatus.load(std::memory_order_relaxed); },
+    [](DownstreamState& state, bool newStatus) { state.upStatus.store(newStatus); });
   luaCtx.registerMember<int(DownstreamState::*)>(
     "weight",
     [](const DownstreamState& state) -> int { return state.d_config.d_weight; },
@@ -257,7 +262,9 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
   luaCtx.registerFunction<bool (ComboAddress::*)() const>("isIPv6", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET6; });
   luaCtx.registerFunction<bool (ComboAddress::*)() const>("isMappedIPv4", [](const ComboAddress& addr) { return addr.isMappedIPv4(); });
   luaCtx.registerFunction<ComboAddress (ComboAddress::*)() const>("mapToIPv4", [](const ComboAddress& addr) { return addr.mapToIPv4(); });
-  luaCtx.registerFunction<bool (nmts_t::*)(const ComboAddress&)>("match", [](nmts_t& set, const ComboAddress& addr) { return set.match(addr); });
+#ifndef DISABLE_DYNBLOCKS
+  luaCtx.registerFunction<bool (ClientAddressDynamicRules::*)(const ComboAddress&) const>("match", [](const ClientAddressDynamicRules& set, const ComboAddress& addr) { return set.match(addr); });
+#endif /* DISABLE_DYNBLOCKS */
 #endif /* DISABLE_COMBO_ADDR_BINDINGS */
 
 #ifndef DISABLE_DNSNAME_BINDINGS
@@ -666,12 +673,12 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter>& bpf) {
     std::string res;
-    if (!g_configurationDone) {
+    if (!dnsdist::configuration::isImmutableConfigurationDone()) {
       throw std::runtime_error("attachToAllBinds() cannot be used at configuration time!");
       return;
     }
     if (bpf) {
-      for (const auto& frontend : g_frontends) {
+      for (const auto& frontend : dnsdist::getFrontends()) {
         frontend->attachFilter(bpf, frontend->getSocket());
       }
     }
@@ -734,7 +741,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_XSK
   using xskopt_t = LuaAssociativeTable<boost::variant<uint32_t, std::string>>;
   luaCtx.writeFunction("newXsk", [client](xskopt_t opts) {
-    if (g_configurationDone) {
+    if (dnsdist::configuration::isImmutableConfigurationDone()) {
       throw std::runtime_error("newXsk() only can be used at configuration time!");
     }
     if (client) {
index c254b6ad73d97da343bcf2591724de873fd48e58..da6197891c3521deb8cae37a0230c3993d310830 100644 (file)
@@ -83,7 +83,9 @@ bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* d
 uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
 bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
 uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
 void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize) __attribute__ ((visibility ("default")));
 const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label) __attribute__ ((visibility ("default")));
 size_t dnsdist_ffi_dnsquestion_get_tag_raw(const dnsdist_ffi_dnsquestion_t* dq, const char* label, char* buffer, size_t bufferSize) __attribute__ ((visibility ("default")));
@@ -177,6 +179,7 @@ typedef struct dnsdist_ffi_proxy_protocol_value {
 
 size_t dnsdist_ffi_generate_proxy_protocol_payload(size_t addrSize, const void* srcAddr, const void* dstAddr, uint16_t srcPort, uint16_t dstPort, bool tcp, size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values, void* out, size_t outSize) __attribute__ ((visibility ("default")));
 size_t dnsdist_ffi_dnsquestion_generate_proxy_protocol_payload(const dnsdist_ffi_dnsquestion_t* dq, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values, void* out, const size_t outSize) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_add_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values) __attribute__ ((visibility ("default")));
 
 typedef struct dnsdist_ffi_domain_list_t dnsdist_ffi_domain_list_t;
 typedef struct dnsdist_ffi_address_list_t dnsdist_ffi_address_list_t;
@@ -285,3 +288,16 @@ const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(con
 void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t*) __attribute__ ((visibility ("default")));
 
 uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive) __attribute__ ((visibility ("default")));
+
+typedef struct dnsdist_ffi_svc_record_parameters dnsdist_ffi_svc_record_parameters;
+bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters) __attribute__ ((visibility ("default")));
+
+bool dnsdist_ffi_dnsquestion_generate_svc_response(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_svc_record_parameters** parametersList, size_t parametersListSize, uint32_t ttl) __attribute__ ((visibility ("default")));
index 2c77b35d7fabe662fe6d0eab6de2342e5318f840..b54a069010cc4ab2c6ace7f4ecc4c3bcd5ab7b25 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "dnsdist-async.hh"
+#include "dnsdist-cache.hh"
 #include "dnsdist-dnsparser.hh"
 #include "dnsdist-dynblocks.hh"
 #include "dnsdist-ecs.hh"
@@ -31,6 +32,8 @@
 #include "dnsdist-lua.hh"
 #include "dnsdist-ecs.hh"
 #include "dnsdist-rings.hh"
+#include "dnsdist-svc.hh"
+#include "dnsdist-snmp.hh"
 #include "dolog.hh"
 
 uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
@@ -232,9 +235,21 @@ uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquest
   return 0;
 }
 
-bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq)
+bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
 {
-  return getEDNSZ(*dq->dq) & EDNS_HEADER_FLAG_DO;
+  return (dnsdist::getEDNSZ(*dnsQuestion->dq) & EDNS_HEADER_FLAG_DO) != 0;
+}
+
+uint8_t dnsdist_ffi_dnsquestion_get_edns_version(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+  auto version = dnsdist::getEDNSVersion(*dnsQuestion->dq);
+  return version ? *version : 0U;
+}
+
+uint8_t dnsdist_ffi_dnsquestion_get_edns_extended_rcode(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+  auto rcode = dnsdist::getEDNSExtendedRCode(*dnsQuestion->dq);
+  return rcode ? *rcode : 0U;
 }
 
 void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
@@ -584,7 +599,7 @@ bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, co
 
 void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
 {
-  if (g_snmpAgent && g_snmpTrapsEnabled) {
+  if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
     g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
   }
 }
@@ -1006,6 +1021,7 @@ void setupLuaLoadBalancingContext(LuaContext& luaCtx)
 {
   setupLuaBindings(luaCtx, true, false);
   setupLuaBindingsDNSQuestion(luaCtx);
+  setupLuaBindingsLogging(luaCtx);
   setupLuaBindingsKVS(luaCtx, true);
   setupLuaVars(luaCtx);
 
@@ -1017,6 +1033,7 @@ void setupLuaLoadBalancingContext(LuaContext& luaCtx)
 void setupLuaFFIPerThreadContext(LuaContext& luaCtx)
 {
   setupLuaVars(luaCtx);
+  setupLuaBindingsLogging(luaCtx);
 
 #ifdef LUAJIT_VERSION
   luaCtx.executeCode(getLuaFFIWrappers());
@@ -1083,6 +1100,25 @@ size_t dnsdist_ffi_dnsquestion_generate_proxy_protocol_payload(const dnsdist_ffi
   return payload.size();
 }
 
+bool dnsdist_ffi_dnsquestion_add_proxy_protocol_values(dnsdist_ffi_dnsquestion_t* dnsQuestion, const size_t valuesCount, const dnsdist_ffi_proxy_protocol_value_t* values)
+{
+  if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || values == nullptr || valuesCount == 0) {
+    return false;
+  }
+
+  if (!dnsQuestion->dq->proxyProtocolValues) {
+    dnsQuestion->dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
+  }
+
+  dnsQuestion->dq->proxyProtocolValues->reserve(dnsQuestion->dq->proxyProtocolValues->size() + valuesCount);
+  for (size_t idx = 0; idx < valuesCount; idx++) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): the Lua FFI API is a C API..
+    dnsQuestion->dq->proxyProtocolValues->push_back({ std::string(values[idx].value, values[idx].size), values[idx].type });
+  }
+
+  return true;
+}
+
 struct dnsdist_ffi_domain_list_t
 {
   std::vector<std::string> d_domains;
@@ -1138,13 +1174,13 @@ size_t dnsdist_ffi_packetcache_get_domain_list_by_addr(const char* poolName, con
     return 0;
   }
 
-  const auto localPools = g_pools.getCopy();
-  auto it = localPools.find(poolName);
-  if (it == localPools.end()) {
+  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+  auto poolIt = pools.find(poolName);
+  if (poolIt == pools.end()) {
     return 0;
   }
 
-  auto pool = it->second;
+  auto pool = poolIt->second;
   if (!pool->packetCache) {
     return 0;
   }
@@ -1187,13 +1223,13 @@ size_t dnsdist_ffi_packetcache_get_address_list_by_domain(const char* poolName,
     return 0;
   }
 
-  const auto localPools = g_pools.getCopy();
-  auto it = localPools.find(poolName);
-  if (it == localPools.end()) {
+  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+  auto poolIt = pools.find(poolName);
+  if (poolIt == pools.end()) {
     return 0;
   }
 
-  auto pool = it->second;
+  auto pool = poolIt->second;
   if (!pool->packetCache) {
     return 0;
   }
@@ -1839,7 +1875,8 @@ bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, ui
     timespec until{now};
     until.tv_sec += duration;
     DynBlock dblock{message, until, DNSName(), static_cast<DNSAction::Action>(action)};
-    auto slow = g_dynblockNMG.getCopy();
+
+    auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
     if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
       dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
       dblock.tagSettings->d_name = tagKey;
@@ -1847,8 +1884,8 @@ bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, ui
         dblock.tagSettings->d_value = tagValue;
       }
     }
-    if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
-      g_dynblockNMG.setState(slow);
+    if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
+      dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
       return true;
     }
   }
@@ -1886,7 +1923,7 @@ bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message,
     timespec until{now};
     until.tv_sec += duration;
     DynBlock dblock{message, until, domain, static_cast<DNSAction::Action>(action)};
-    auto slow = g_dynblockSMT.getCopy();
+    auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
     if (dblock.action == DNSAction::Action::SetTag && tagKey != nullptr) {
       dblock.tagSettings = std::make_shared<DynBlock::TagSettings>();
       dblock.tagSettings->d_name = tagKey;
@@ -1894,8 +1931,8 @@ bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message,
         dblock.tagSettings->d_value = tagValue;
       }
     }
-    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
-      g_dynblockSMT.setState(slow);
+    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
+      dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
       return true;
     }
   }
@@ -1924,13 +1961,11 @@ size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t*
 
   auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
 
-  struct timespec now
-  {
-  };
+  timespec now{};
   gettime(&now);
 
-  auto fullCopy = g_dynblockNMG.getCopy();
-  for (const auto& entry : fullCopy) {
+  const auto& dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+  for (const auto& entry : dynamicRules) {
     const auto& client = entry.first;
     const auto& details = entry.second;
     if (!(now < details.until)) {
@@ -1941,7 +1976,7 @@ size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t*
     if (g_defaultBPFFilter && details.bpf) {
       counter += g_defaultBPFFilter->getHits(client.getNetwork());
     }
-    list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : g_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
+    list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
   }
 
   auto count = list->d_entries.size();
@@ -1957,13 +1992,12 @@ size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_lis
 
   auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
 
-  struct timespec now
-  {
-  };
+  timespec now{};
   gettime(&now);
 
-  auto fullCopy = g_dynblockSMT.getCopy();
-  fullCopy.visit([&now, &list](const SuffixMatchTree<DynBlock>& node) {
+  const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+  const auto& smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+  smtBlocks.visit([&now, &list, defaultAction](const SuffixMatchTree<DynBlock>& node) {
     if (!(now < node.d_value.until)) {
       return;
     }
@@ -1973,7 +2007,7 @@ size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_lis
       key = entry.domain.toString();
     }
     if (entry.action == DNSAction::Action::None) {
-      entry.action = g_dynBlockAction;
+      entry.action = defaultAction;
     }
     list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
   });
@@ -2027,3 +2061,136 @@ uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataS
 
   return burtle(data, dataSize, seed);
 }
+
+struct dnsdist_ffi_svc_record_parameters
+{
+  SVCRecordParameters parameters;
+};
+
+bool dnsdist_ffi_svc_record_parameters_new(const char* targetName, uint16_t priority, bool noDefaultALPN, dnsdist_ffi_svc_record_parameters** out)
+{
+  if (targetName == nullptr || out == nullptr) {
+    return false;
+  }
+  try {
+    auto parameters = std::make_unique<dnsdist_ffi_svc_record_parameters>();
+    parameters->parameters.target = DNSName(targetName);
+    parameters->parameters.priority = priority;
+    parameters->parameters.noDefaultAlpn = noDefaultALPN;
+    *out = parameters.release();
+    return true;
+  }
+  catch (const std::exception& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.what());
+  }
+  catch (const PDNSException& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_new: %s", exp.reason);
+  }
+  catch (...) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_new");
+  }
+
+  return false;
+}
+
+void dnsdist_ffi_svc_record_parameters_set_port(dnsdist_ffi_svc_record_parameters* parameters, uint16_t port)
+{
+  if (parameters == nullptr) {
+    return;
+  }
+  parameters->parameters.port = port;
+}
+
+void dnsdist_ffi_svc_record_parameters_set_ech(dnsdist_ffi_svc_record_parameters* parameters, const char* ech, size_t echLen)
+{
+  if (parameters == nullptr || ech == nullptr || echLen == 0) {
+    return;
+  }
+  parameters->parameters.ech = std::string(ech, echLen);
+}
+
+void dnsdist_ffi_svc_record_parameters_set_additional_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key, const char* value, size_t valueLen)
+{
+  if (parameters == nullptr || (value == nullptr && valueLen != 0)) {
+    return;
+  }
+  parameters->parameters.additionalParams.emplace_back(key, std::string(value, valueLen));
+}
+
+void dnsdist_ffi_svc_record_parameters_add_mandatory_param(dnsdist_ffi_svc_record_parameters* parameters, uint16_t key)
+{
+  if (parameters == nullptr) {
+    return;
+  }
+  parameters->parameters.mandatoryParams.insert(key);
+}
+
+void dnsdist_ffi_svc_record_parameters_add_alpn(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+  if (parameters == nullptr || value == nullptr || valueLen == 0) {
+    return;
+  }
+  parameters->parameters.alpns.emplace_back(value, valueLen);
+}
+
+void dnsdist_ffi_svc_record_parameters_add_ipv4_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+  if (parameters == nullptr || value == nullptr || valueLen == 0) {
+    return;
+  }
+  try {
+    parameters->parameters.ipv4hints.emplace_back(ComboAddress(std::string(value, valueLen)));
+  }
+  catch (const std::exception& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
+  }
+  catch (const PDNSException& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
+  }
+  catch (...) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
+  }
+}
+
+void dnsdist_ffi_svc_record_parameters_add_ipv6_hint(dnsdist_ffi_svc_record_parameters* parameters, const char* value, size_t valueLen)
+{
+  if (parameters == nullptr || value == nullptr || valueLen == 0) {
+    return;
+  }
+  try {
+    parameters->parameters.ipv6hints.emplace_back(ComboAddress(std::string(value, valueLen)));
+  }
+  catch (const std::exception& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.what());
+  }
+  catch (const PDNSException& exp) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint: %s", exp.reason);
+  }
+  catch (...) {
+    errlog("Exception in dnsdist_ffi_svc_record_parameters_add_ipv4_hint");
+  }
+}
+
+bool dnsdist_ffi_dnsquestion_generate_svc_response(dnsdist_ffi_dnsquestion_t* dnsQuestion, const dnsdist_ffi_svc_record_parameters** parametersList, size_t parametersListSize, uint32_t ttl)
+{
+  if (dnsQuestion == nullptr || parametersList == nullptr || parametersListSize == 0) {
+    return false;
+  }
+  std::vector<SVCRecordParameters> parameters;
+  parameters.reserve(parametersListSize);
+  for (size_t idx = 0; idx < parametersListSize; idx++) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): this is a C API
+    const auto* parameter = parametersList[idx];
+    if (parameter == nullptr) {
+      return false;
+    }
+    parameters.push_back(parameter->parameters);
+  }
+  return dnsdist::svc::generateSVCResponse(*dnsQuestion->dq, ttl, parameters);
+}
+
+void dnsdist_ffi_svc_record_parameters_free(dnsdist_ffi_svc_record_parameters* parameters)
+{
+  // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
+  delete parameters;
+}
index a91003b971ad0ae557d05665325ae4c000dc6a39..d620c2455493de2aa39ad19910d098886846bd85 100644 (file)
@@ -27,6 +27,8 @@ extern "C" {
 #include "dnsdist-lua-ffi-interface.h"
 }
 
+#include "ext/luawrapper/include/LuaContext.hpp"
+
 // dnsdist_ffi_dnsquestion_t is a lightuserdata
 template<>
 struct LuaContext::Pusher<dnsdist_ffi_dnsquestion_t*> {
index c5ccb48915c14d171c456a7811477d3fff2d59eb..2904cd37926a07351de3cdef8468c9f308916660 100644 (file)
@@ -2,9 +2,13 @@
 #include "dnsdist-lua-hooks.hh"
 #include "dnsdist-lua.hh"
 #include "lock.hh"
+#include "tcpiohandler.hh"
 
 namespace dnsdist::lua::hooks
 {
+using MaintenanceCallback = std::function<void()>;
+using TicketsKeyAddedHook = std::function<void(const char*, size_t)>;
+
 static LockGuarded<std::vector<MaintenanceCallback>> s_maintenanceHooks;
 
 void runMaintenanceHooks(const LuaContext& context)
@@ -15,7 +19,7 @@ void runMaintenanceHooks(const LuaContext& context)
   }
 }
 
-void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback)
+static void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback)
 {
   (void)context;
   s_maintenanceHooks.lock()->push_back(std::move(callback));
@@ -26,12 +30,29 @@ void clearMaintenanceHooks()
   s_maintenanceHooks.lock()->clear();
 }
 
+static void setTicketsKeyAddedHook(const LuaContext& context, const TicketsKeyAddedHook& hook)
+{
+  TLSCtx::setTicketsKeyAddedHook([hook](const std::string& key) {
+    try {
+      auto lua = g_lua.lock();
+      hook(key.c_str(), key.size());
+    }
+    catch (const std::exception& exp) {
+      warnlog("Error calling the Lua hook after new tickets key has been added: %s", exp.what());
+    }
+  });
+}
+
 void setupLuaHooks(LuaContext& luaCtx)
 {
   luaCtx.writeFunction("addMaintenanceCallback", [&luaCtx](const MaintenanceCallback& callback) {
     setLuaSideEffect();
     addMaintenanceCallback(luaCtx, callback);
   });
+  luaCtx.writeFunction("setTicketsKeyAddedHook", [&luaCtx](const TicketsKeyAddedHook& hook) {
+    setLuaSideEffect();
+    setTicketsKeyAddedHook(luaCtx, hook);
+  });
 }
 
 }
index 11a9084883ee8a74585acc611bb10bdb9ea3fae8..e35c0f10ac5f9b03a32500ef02fd90399d2ced61 100644 (file)
@@ -27,9 +27,7 @@ class LuaContext;
 
 namespace dnsdist::lua::hooks
 {
-using MaintenanceCallback = std::function<void()>;
 void runMaintenanceHooks(const LuaContext& context);
-void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback);
 void clearMaintenanceHooks();
 void setupLuaHooks(LuaContext& luaCtx);
 }
index 7e6742e1ec2fc24e019e0a2516a4f42e2c3fc18e..2ad3999f7c2e549bd7a6726fb65a8bcb26f104b0 100644 (file)
 #include <fcntl.h>
 
 #include "dnsdist.hh"
-#include "dnsdist-lua.hh"
+#include "dnsdist-console.hh"
 #include "dnsdist-dynblocks.hh"
+#include "dnsdist-frontend.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-tcp.hh"
@@ -259,10 +261,10 @@ static counts_t exceedRespByterate(unsigned int rate, int seconds)
 // NOLINTNEXTLINE(bugprone-exception-escape)
 struct GrepQParams
 {
-  boost::optional<Netmask> netmask;
-  boost::optional<DNSName> name;
+  std::optional<Netmask> netmask;
+  std::optional<DNSName> name;
+  std::optional<unsigned int> msec;
   pdns::UniqueFilePtr outputFile{nullptr};
-  int msec = -1;
 };
 
 static std::optional<GrepQParams> parseGrepQParams(const LuaTypeOrArrayOf<std::string>& inp, boost::optional<LuaAssociativeTable<std::string>>& options)
@@ -302,21 +304,31 @@ static std::optional<GrepQParams> parseGrepQParams(const LuaTypeOrArrayOf<std::s
   for (const auto& filter : filters) {
     try {
       result.netmask = Netmask(filter);
+      continue;
     }
     catch (...) {
-      if (boost::ends_with(filter, "ms") && sscanf(filter.c_str(), "%ums", &result.msec) != 0) {
-        ;
+      /* that's OK, let's try something else */
+    }
+
+    if (boost::ends_with(filter, "ms")) {
+      /* skip the ms at the end */
+      const auto msecStr = filter.substr(0, filter.size() - 2);
+      try {
+        result.msec = pdns::checked_stoi<unsigned int>(msecStr);
+        continue;
       }
-      else {
-        try {
-          result.name = DNSName(filter);
-        }
-        catch (...) {
-          g_outputBuffer = "Could not parse '" + filter + "' as domain name or netmask";
-          return std::nullopt;
-        }
+      catch (...) {
+        /* that's OK, let's try to parse as a DNS name */
       }
     }
+
+    try {
+      result.name = DNSName(filter);
+    }
+    catch (...) {
+      g_outputBuffer = "Could not parse '" + filter + "' as domain name or netmask";
+      return std::nullopt;
+    }
   }
   return result;
 }
@@ -341,8 +353,8 @@ static bool ringEntryMatches(const GrepQParams& params, const C& entry)
 
   constexpr bool response = std::is_same_v<C, Rings::Response>;
   if constexpr (response) {
-    if (params.msec != -1) {
-      msecmatch = (entry.usec / 1000 > static_cast<unsigned int>(params.msec));
+    if (params.msec) {
+      msecmatch = (entry.usec / 1000 > *params.msec);
     }
   }
 
@@ -485,7 +497,7 @@ void setupLuaInspection(LuaContext& luaCtx)
       }
       totalEntries += rings.back().size();
     }
-    vector<std::unordered_map<string, boost::variant<string, unsigned int>>> ret;
+    vector<std::unordered_map<string, boost::variant<unsigned int, string>>> ret;
     ret.reserve(totalEntries);
     for (const auto& ring : rings) {
       for (const auto& entry : ring) {
@@ -506,11 +518,18 @@ void setupLuaInspection(LuaContext& luaCtx)
 
   luaCtx.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
 
-  luaCtx.writeFunction("getSlowResponses", [](uint64_t top, uint64_t msec, boost::optional<int> labels) {
-    return getGenResponses(top, labels, [msec](const Rings::Response& resp) { return resp.usec > msec * 1000; });
+  luaCtx.writeFunction("getSlowResponses", [](uint64_t top, uint64_t msec, boost::optional<int> labels, boost::optional<bool> timeouts) {
+    return getGenResponses(top, labels, [msec, timeouts](const Rings::Response& resp) {
+      if (timeouts && *timeouts) {
+        return resp.usec == std::numeric_limits<unsigned int>::max();
+      }
+      return resp.usec > msec * 1000 && resp.usec != std::numeric_limits<unsigned int>::max();
+    });
   });
 
-  luaCtx.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+  luaCtx.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec, labels, false)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+
+  luaCtx.executeCode(R"(function topTimeouts(top, labels) top = top or 10; for k,v in ipairs(getSlowResponses(top, 0, labels, true)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
 
   luaCtx.writeFunction("getTopBandwidth", [](uint64_t top) {
     setLuaNoSideEffect();
@@ -523,7 +542,7 @@ void setupLuaInspection(LuaContext& luaCtx)
   luaCtx.writeFunction("delta", []() {
     setLuaNoSideEffect();
     // we hold the lua lock already!
-    for (const auto& entry : g_confDelta) {
+    for (const auto& entry : dnsdist::console::getConfigurationDelta()) {
       tm entryTime{};
       localtime_r(&entry.first.tv_sec, &entryTime);
       std::array<char, 80> date{};
@@ -584,7 +603,7 @@ void setupLuaInspection(LuaContext& luaCtx)
       fprintf(params.outputFile.get(), "%s", headLine.c_str());
     }
 
-    if (params.msec == -1) {
+    if (!params.msec) {
       for (const auto& entry : queries) {
         if (!ringEntryMatches(params, entry)) {
           continue;
@@ -709,10 +728,11 @@ void setupLuaInspection(LuaContext& luaCtx)
 
   luaCtx.writeFunction("showTCPStats", [] {
     setLuaNoSideEffect();
+    const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
     ostringstream ret;
     boost::format fmt("%-12d %-12d %-12d %-12d");
     ret << (fmt % "Workers" % "Max Workers" % "Queued" % "Max Queued") << endl;
-    ret << (fmt % g_tcpclientthreads->getThreadsCount() % (g_maxTCPClientThreads ? *g_maxTCPClientThreads : 0) % g_tcpclientthreads->getQueuedCount() % g_maxTCPQueuedConnections) << endl;
+    ret << (fmt % g_tcpclientthreads->getThreadsCount() % immutableConfig.d_maxTCPClientThreads % g_tcpclientthreads->getQueuedCount() % immutableConfig.d_maxTCPQueuedConnections) << endl;
     ret << endl;
 
     ret << "Frontends:" << endl;
@@ -720,7 +740,7 @@ void setupLuaInspection(LuaContext& luaCtx)
     ret << (fmt % "#" % "Address" % "Connections" % "Max concurrent conn" % "Died reading query" % "Died sending response" % "Gave up" % "Client timeouts" % "Downstream timeouts" % "Avg queries/conn" % "Avg duration" % "TLS new sessions" % "TLS Resumptions" % "TLS unknown ticket keys" % "TLS inactive ticket keys" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other") << endl;
 
     size_t counter = 0;
-    for (const auto& frontend : g_frontends) {
+    for (const auto& frontend : dnsdist::getFrontends()) {
       ret << (fmt % counter % frontend->local.toStringWithPort() % frontend->tcpCurrentConnections % frontend->tcpMaxConcurrentConnections % frontend->tcpDiedReadingQuery % frontend->tcpDiedSendingResponse % frontend->tcpGaveUp % frontend->tcpClientTimeouts % frontend->tcpDownstreamTimeouts % frontend->tcpAvgQueriesPerConnection % frontend->tcpAvgConnectionDuration % frontend->tlsNewSessions % frontend->tlsResumptions % frontend->tlsUnknownTicketKey % frontend->tlsInactiveTicketKey % frontend->tls10queries % frontend->tls11queries % frontend->tls12queries % frontend->tls13queries % frontend->tlsUnknownqueries) << endl;
       ++counter;
     }
@@ -730,9 +750,8 @@ void setupLuaInspection(LuaContext& luaCtx)
     fmt = boost::format("%-3d %-20.20s %-20.20s %-20d %-20d %-25d %-25d %-20d %-20d %-20d %-20d %-20d %-20d %-20d %-20d %-20f %-20f");
     ret << (fmt % "#" % "Name" % "Address" % "Connections" % "Max concurrent conn" % "Died sending query" % "Died reading response" % "Gave up" % "Read timeouts" % "Write timeouts" % "Connect timeouts" % "Too many conn" % "Total connections" % "Reused connections" % "TLS resumptions" % "Avg queries/conn" % "Avg duration") << endl;
 
-    auto states = g_dstates.getLocal();
     counter = 0;
-    for (const auto& backend : *states) {
+    for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
       ret << (fmt % counter % backend->getName() % backend->d_config.remote.toStringWithPort() % backend->tcpCurrentConnections % backend->tcpMaxConcurrentConnections % backend->tcpDiedSendingQuery % backend->tcpDiedReadingResponse % backend->tcpGaveUp % backend->tcpReadTimeouts % backend->tcpWriteTimeouts % backend->tcpConnectTimeouts % backend->tcpTooManyConcurrentConnections % backend->tcpNewConnections % backend->tcpReusedConnections % backend->tlsResumptions % backend->tcpAvgQueriesPerConnection % backend->tcpAvgConnectionDuration) << endl;
       ++counter;
     }
@@ -748,7 +767,7 @@ void setupLuaInspection(LuaContext& luaCtx)
     ret << (fmt % "#" % "Address" % "DH key too small" % "Inappropriate fallback" % "No shared cipher" % "Unknown cipher type" % "Unknown exchange type" % "Unknown protocol" % "Unsupported EC" % "Unsupported protocol") << endl;
 
     size_t counter = 0;
-    for (const auto& frontend : g_frontends) {
+    for (const auto& frontend : dnsdist::getFrontends()) {
       if (!frontend->hasTLS()) {
         continue;
       }
@@ -802,12 +821,9 @@ void setupLuaInspection(LuaContext& luaCtx)
       if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
         second = std::to_string((*val)->load());
       }
-      else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+      else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
         second = (flt % (*adval)->load()).str();
       }
-      else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
-        second = (flt % (**dval)).str();
-      }
       else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
         second = std::to_string((*func)(entry.d_name));
       }
@@ -1039,7 +1055,28 @@ void setupLuaInspection(LuaContext& luaCtx)
   /* DynBlock object accessors */
   luaCtx.registerMember("reason", &DynBlock::reason);
   luaCtx.registerMember("domain", &DynBlock::domain);
-  luaCtx.registerMember("until", &DynBlock::until);
+  luaCtx.registerMember<DynBlock, timespec>(
+    "until", [](const DynBlock& block) {
+      timespec nowMonotonic{};
+      gettime(&nowMonotonic);
+      timespec nowRealTime{};
+      gettime(&nowRealTime, true);
+
+      auto seconds = block.until.tv_sec - nowMonotonic.tv_sec;
+      auto nseconds = block.until.tv_nsec - nowMonotonic.tv_nsec;
+      if (nseconds < 0) {
+        seconds -= 1;
+        nseconds += 1000000000;
+      }
+
+      nowRealTime.tv_sec += seconds;
+      nowRealTime.tv_nsec += nseconds;
+      if (nowRealTime.tv_nsec > 1000000000) {
+        nowRealTime.tv_sec += 1;
+        nowRealTime.tv_nsec -= 1000000000;
+      }
+
+      return nowRealTime; }, [](DynBlock& block, [[maybe_unused]] timespec until) {});
   luaCtx.registerMember<DynBlock, unsigned int>(
     "blocks", [](const DynBlock& block) { return block.blocks.load(); }, [](DynBlock& block, [[maybe_unused]] unsigned int blocks) {});
   luaCtx.registerMember("action", &DynBlock::action);
@@ -1060,7 +1097,7 @@ void setupLuaInspection(LuaContext& luaCtx)
                          parseDynamicActionOptionalParameters("addDynBlockSMT", rule, action, optionalParameters);
 
                          bool needUpdate = false;
-                         auto slow = g_dynblockSMT.getCopy();
+                         auto smtBlocks = dnsdist::DynamicBlocks::getSuffixDynamicRulesCopy();
                          for (const auto& capair : names) {
                            DNSName domain(capair.second);
                            domain.makeUsLowerCase();
@@ -1068,13 +1105,13 @@ void setupLuaInspection(LuaContext& luaCtx)
                            until.tv_sec += actualSeconds;
                            DynBlock dblock{msg, until, domain, action ? *action : DNSAction::Action::None};
                            dblock.tagSettings = rule.d_tagSettings;
-                           if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, std::move(dblock), false)) {
+                           if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(smtBlocks, now, std::move(dblock), false)) {
                              needUpdate = true;
                            }
                          }
 
                          if (needUpdate) {
-                           g_dynblockSMT.setState(slow);
+                           dnsdist::DynamicBlocks::setSuffixDynamicRules(std::move(smtBlocks));
                          }
                        });
 
@@ -1113,9 +1150,9 @@ void setupLuaInspection(LuaContext& luaCtx)
                          DynBlock dblock{msg, until, DNSName(), action ? *action : DNSAction::Action::None};
                          dblock.tagSettings = rule.d_tagSettings;
 
-                         auto slow = g_dynblockNMG.getCopy();
-                         if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, std::move(dblock), false)) {
-                           g_dynblockNMG.setState(slow);
+                         auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
+                         if (dnsdist::DynamicBlocks::addOrRefreshBlock(dynamicRules, now, target, std::move(dblock), false)) {
+                           dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
                          }
                        });
 #endif /* DISABLE_DYNBLOCKS */
index a4d7adbcfdd32714dd093feab654f5f5b39199a9..10937c03fcdf29853298713d42c6d85623871214 100644 (file)
@@ -128,91 +128,120 @@ static std::string rulesToString(const std::vector<T>& rules, boost::optional<ru
   return result;
 }
 
-template <typename T>
-static void showRules(GlobalStateHolder<vector<T>>* someRuleActions, boost::optional<ruleparams_t>& vars)
+template <typename IdentifierT>
+static void showRules(IdentifierT identifier, boost::optional<ruleparams_t>& vars)
 {
   setLuaNoSideEffect();
 
-  auto rules = someRuleActions->getLocal();
-  g_outputBuffer += rulesToString(*rules, vars);
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  const auto& rules = dnsdist::rules::getRuleChain(chains, identifier);
+  g_outputBuffer += rulesToString(rules, vars);
 }
 
-template <typename T>
-static void rmRule(GlobalStateHolder<vector<T>>* someRuleActions, const boost::variant<unsigned int, std::string>& ruleID)
+template <typename ChainTypeT, typename RuleTypeT>
+static bool removeRuleFromChain(ChainTypeT& rules, const std::function<bool(const RuleTypeT& rule)>& matchFunction)
+{
+  auto removeIt = std::remove_if(rules.begin(),
+                                 rules.end(),
+                                 matchFunction);
+  if (removeIt == rules.end()) {
+    g_outputBuffer = "Error: no rule matched\n";
+    return false;
+  }
+  rules.erase(removeIt,
+              rules.end());
+  return true;
+}
+
+template <typename ChainIdentifierT>
+static void rmRule(ChainIdentifierT chainIdentifier, const boost::variant<unsigned int, std::string>& ruleID)
 {
-  setLuaSideEffect();
-  auto rules = someRuleActions->getCopy();
   if (const auto* str = boost::get<std::string>(&ruleID)) {
     try {
       const auto uuid = getUniqueID(*str);
-      auto removeIt = std::remove_if(rules.begin(),
-                                     rules.end(),
-                                     [&uuid](const T& rule) { return rule.d_id == uuid; });
-      if (removeIt == rules.end()) {
-        g_outputBuffer = "Error: no rule matched\n";
-        return;
-      }
-      rules.erase(removeIt,
-                  rules.end());
+      dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, &uuid](dnsdist::configuration::RuntimeConfiguration& config) {
+        constexpr bool isResponseChain = std::is_same_v<ChainIdentifierT, dnsdist::rules::ResponseRuleChain>;
+        if constexpr (isResponseChain) {
+          auto& rules = dnsdist::rules::getResponseRuleChain(config.d_ruleChains, chainIdentifier);
+          std::function<bool(const dnsdist::rules::ResponseRuleAction&)> matchFunction = [&uuid](const dnsdist::rules::ResponseRuleAction& rule) -> bool { return rule.d_id == uuid; };
+          removeRuleFromChain(rules, matchFunction);
+        }
+        else {
+          auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+          std::function<bool(const dnsdist::rules::RuleAction&)> matchFunction = [&uuid](const dnsdist::rules::RuleAction& rule) -> bool { return rule.d_id == uuid; };
+          removeRuleFromChain(rules, matchFunction);
+        }
+      });
     }
     catch (const std::runtime_error& e) {
-      /* it was not an UUID, let's see if it was a name instead */
-      auto removeIt = std::remove_if(rules.begin(),
-                                     rules.end(),
-                                     [&str](const T& rule) { return rule.d_name == *str; });
-      if (removeIt == rules.end()) {
-        g_outputBuffer = "Error: no rule matched\n";
-        return;
-      }
-      rules.erase(removeIt,
-                  rules.end());
+      dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, &str](dnsdist::configuration::RuntimeConfiguration& config) {
+        constexpr bool isResponseChain = std::is_same_v<ChainIdentifierT, dnsdist::rules::ResponseRuleChain>;
+        if constexpr (isResponseChain) {
+          auto& rules = dnsdist::rules::getResponseRuleChain(config.d_ruleChains, chainIdentifier);
+          std::function<bool(const dnsdist::rules::ResponseRuleAction&)> matchFunction = [&str](const dnsdist::rules::ResponseRuleAction& rule) -> bool { return rule.d_name == *str; };
+          removeRuleFromChain(rules, matchFunction);
+        }
+        else {
+          auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+          std::function<bool(const dnsdist::rules::RuleAction&)> matchFunction = [&str](const dnsdist::rules::RuleAction& rule) -> bool { return rule.d_name == *str; };
+          removeRuleFromChain(rules, matchFunction);
+        }
+      });
     }
   }
   else if (const auto* pos = boost::get<unsigned int>(&ruleID)) {
-    if (*pos >= rules.size()) {
-      g_outputBuffer = "Error: attempt to delete non-existing rule\n";
-      return;
-    }
-    rules.erase(rules.begin() + *pos);
+    dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, pos](dnsdist::configuration::RuntimeConfiguration& config) {
+      auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+      if (*pos >= rules.size()) {
+        g_outputBuffer = "Error: attempt to delete non-existing rule\n";
+        return;
+      }
+      rules.erase(rules.begin() + *pos);
+    });
   }
-  someRuleActions->setState(std::move(rules));
+  setLuaSideEffect();
 }
 
-template <typename T>
-static void moveRuleToTop(GlobalStateHolder<vector<T>>* someRuleActions)
+template <typename IdentifierTypeT>
+static void moveRuleToTop(IdentifierTypeT chainIdentifier)
 {
   setLuaSideEffect();
-  auto rules = someRuleActions->getCopy();
-  if (rules.empty()) {
-    return;
-  }
-  auto subject = *rules.rbegin();
-  rules.erase(std::prev(rules.end()));
-  rules.insert(rules.begin(), subject);
-  someRuleActions->setState(std::move(rules));
+  dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier](dnsdist::configuration::RuntimeConfiguration& config) {
+    auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+    if (rules.empty()) {
+      return;
+    }
+    //coverity[auto_causes_copy]
+    auto subject = *rules.rbegin();
+    rules.erase(std::prev(rules.end()));
+    rules.insert(rules.begin(), subject);
+  });
+  setLuaSideEffect();
 }
 
-template <typename T>
-static void mvRule(GlobalStateHolder<vector<T>>* someRespRuleActions, unsigned int from, unsigned int destination)
+template <typename IdentifierTypeT>
+static void mvRule(IdentifierTypeT chainIdentifier, unsigned int from, unsigned int destination)
 {
-  setLuaSideEffect();
-  auto rules = someRespRuleActions->getCopy();
-  if (from >= rules.size() || destination > rules.size()) {
-    g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
-    return;
-  }
-  auto subject = rules[from];
-  rules.erase(rules.begin() + from);
-  if (destination > rules.size()) {
-    rules.push_back(subject);
-  }
-  else {
-    if (from < destination) {
-      --destination;
+  dnsdist::configuration::updateRuntimeConfiguration([chainIdentifier, from, &destination](dnsdist::configuration::RuntimeConfiguration& config) {
+    auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chainIdentifier);
+    if (from >= rules.size() || destination > rules.size()) {
+      g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
+      return;
     }
-    rules.insert(rules.begin() + destination, subject);
-  }
-  someRespRuleActions->setState(std::move(rules));
+    //coverity[auto_causes_copy]
+    auto subject = rules[from];
+    rules.erase(rules.begin() + from);
+    if (destination > rules.size()) {
+      rules.push_back(subject);
+    }
+    else {
+      if (from < destination) {
+        --destination;
+      }
+      rules.insert(rules.begin() + destination, subject);
+    }
+  });
+  setLuaSideEffect();
 }
 
 template <typename T>
@@ -262,7 +291,7 @@ static LuaArray<T> toLuaArray(std::vector<T>&& rules)
 }
 
 template <typename T>
-static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<int, std::string>& selector)
+static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<unsigned int, std::string>& selector)
 {
   if (const auto* str = boost::get<std::string>(&selector)) {
     /* let's see if this a UUID */
@@ -283,7 +312,7 @@ static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const
       }
     }
   }
-  else if (const auto* pos = boost::get<int>(&selector)) {
+  else if (const auto* pos = boost::get<unsigned int>(&selector)) {
     /* this will throw a std::out_of_range exception if the
        supplied position is out of bounds, this is fine */
     return rules.at(*pos);
@@ -333,90 +362,100 @@ void setupLuaRules(LuaContext& luaCtx)
 
   luaCtx.registerFunction<std::shared_ptr<DNSResponseAction> (dnsdist::rules::ResponseRuleAction::*)() const>("getAction", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_action; });
 
-  for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
+  for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) {
     luaCtx.writeFunction("show" + chain.prefix + "ResponseRules", [&chain](boost::optional<ruleparams_t> vars) {
-      showRules(&chain.holder, vars);
+      showRules(chain.identifier, vars);
     });
     luaCtx.writeFunction("rm" + chain.prefix + "ResponseRule", [&chain](const boost::variant<unsigned int, std::string>& identifier) {
-      rmRule(&chain.holder, identifier);
+      rmRule(chain.identifier, identifier);
     });
     luaCtx.writeFunction("mv" + chain.prefix + "ResponseRuleToTop", [&chain]() {
-      moveRuleToTop(&chain.holder);
+      moveRuleToTop(chain.identifier);
     });
     luaCtx.writeFunction("mv" + chain.prefix + "ResponseRule", [&chain](unsigned int from, unsigned int dest) {
-      mvRule(&chain.holder, from, dest);
+      mvRule(chain.identifier, from, dest);
     });
-    luaCtx.writeFunction("get" + chain.prefix + "ResponseRule", [&chain](const boost::variant<int, std::string>& selector) -> boost::optional<dnsdist::rules::ResponseRuleAction> {
-      auto rules = chain.holder.getLocal();
-      return getRuleFromSelector(*rules, selector);
+    luaCtx.writeFunction("get" + chain.prefix + "ResponseRule", [&chain](const boost::variant<unsigned int, std::string>& selector) -> boost::optional<dnsdist::rules::ResponseRuleAction> {
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+      return getRuleFromSelector(rules, selector);
     });
 
     luaCtx.writeFunction("getTop" + chain.prefix + "ResponseRules", [&chain](boost::optional<unsigned int> top) {
       setLuaNoSideEffect();
-      auto rules = chain.holder.getLocal();
-      return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+      return toLuaArray(getTopRules(rules, (top ? *top : 10)));
     });
 
     luaCtx.writeFunction("top" + chain.prefix + "ResponseRules", [&chain](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
       setLuaNoSideEffect();
-      auto rules = chain.holder.getLocal();
-      return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getResponseRuleChain(chains, chain.identifier);
+      return rulesToString(getTopRules(rules, (top ? *top : 10)), vars);
     });
 
     luaCtx.writeFunction("clear" + chain.prefix + "ResponseRules", [&chain]() {
       setLuaSideEffect();
-      chain.holder.modify([](std::remove_reference_t<decltype(chain.holder)>::value_type& ruleactions) {
-        ruleactions.clear();
+      dnsdist::configuration::updateRuntimeConfiguration([&chain](dnsdist::configuration::RuntimeConfiguration& config) {
+        auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+        rules.clear();
       });
     });
   }
 
-  for (const auto& chain : dnsdist::rules::getRuleChains()) {
+  for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) {
     luaCtx.writeFunction("show" + chain.prefix + "Rules", [&chain](boost::optional<ruleparams_t> vars) {
-      showRules(&chain.holder, vars);
+      showRules(chain.identifier, vars);
     });
     luaCtx.writeFunction("rm" + chain.prefix + "Rule", [&chain](const boost::variant<unsigned int, std::string>& identifier) {
-      rmRule(&chain.holder, identifier);
+      rmRule(chain.identifier, identifier);
     });
     luaCtx.writeFunction("mv" + chain.prefix + "RuleToTop", [&chain]() {
-      moveRuleToTop(&chain.holder);
+      moveRuleToTop(chain.identifier);
     });
     luaCtx.writeFunction("mv" + chain.prefix + "Rule", [&chain](unsigned int from, unsigned int dest) {
-      mvRule(&chain.holder, from, dest);
+      mvRule(chain.identifier, from, dest);
     });
     luaCtx.writeFunction("get" + chain.prefix + "Rule", [&chain](const boost::variant<int, std::string>& selector) -> boost::optional<dnsdist::rules::RuleAction> {
-      auto rules = chain.holder.getLocal();
-      return getRuleFromSelector(*rules, selector);
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+      return getRuleFromSelector(rules, selector);
     });
 
     luaCtx.writeFunction("getTop" + chain.prefix + "Rules", [&chain](boost::optional<unsigned int> top) {
       setLuaNoSideEffect();
-      auto rules = chain.holder.getLocal();
-      return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+      return toLuaArray(getTopRules(rules, (top ? *top : 10)));
     });
 
     luaCtx.writeFunction("top" + chain.prefix + "Rules", [&chain](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
       setLuaNoSideEffect();
-      auto rules = chain.holder.getLocal();
-      return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& rules = dnsdist::rules::getRuleChain(chains, chain.identifier);
+
+      return rulesToString(getTopRules(rules, (top ? *top : 10)), vars);
     });
 
     luaCtx.writeFunction("clear" + chain.prefix + "Rules", [&chain]() {
       setLuaSideEffect();
-      chain.holder.modify([](std::remove_reference_t<decltype(chain.holder)>::value_type& ruleactions) {
-        ruleactions.clear();
+      dnsdist::configuration::updateRuntimeConfiguration([&chain](dnsdist::configuration::RuntimeConfiguration& config) {
+        auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+        rules.clear();
       });
     });
 
     luaCtx.writeFunction("set" + chain.prefix + "Rules", [&chain](const LuaArray<std::shared_ptr<dnsdist::rules::RuleAction>>& newruleactions) {
       setLuaSideEffect();
-      chain.holder.modify([newruleactions](std::remove_reference_t<decltype(chain.holder)>::value_type& gruleactions) {
-        gruleactions.clear();
+      dnsdist::configuration::updateRuntimeConfiguration([&chain, &newruleactions](dnsdist::configuration::RuntimeConfiguration& config) {
+        auto& rules = dnsdist::rules::getRuleChain(config.d_ruleChains, chain.identifier);
+        rules.clear();
         for (const auto& pair : newruleactions) {
           const auto& newruleaction = pair.second;
           if (newruleaction->d_action) {
             auto rule = newruleaction->d_rule;
-            gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
+            rules.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
           }
         }
       });
index 0498aed4fcf9ebe010cdd501d8b87e201fa39ae6..cd7e47f91ed78d0d9715528e502498caa4fb19c2 100644 (file)
 #include "dnsdist-lua.hh"
 #include "dnsdist-web.hh"
 
-void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler);
+namespace dnsdist::webserver
+{
+void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler, bool isLua);
+}
 
 void setupLuaWeb(LuaContext& luaCtx)
 {
 #ifndef DISABLE_LUA_WEB_HANDLERS
   luaCtx.writeFunction("registerWebHandler", [](const std::string& path, std::function<void(const YaHTTP::Request*, YaHTTP::Response*)> handler) {
     /* LuaWrapper does a copy for objects passed by reference, so we pass a pointer */
-    registerWebHandler(path, [handler](const YaHTTP::Request& req, YaHTTP::Response& resp) { handler(&req, &resp); });
+    dnsdist::webserver::registerWebHandler(path, [handler](const YaHTTP::Request& req, YaHTTP::Response& resp) { handler(&req, &resp); }, true);
   });
 
   luaCtx.registerMember<std::string(YaHTTP::Request::*)>("path", [](const YaHTTP::Request& req) -> std::string { return req.url.path; }, [](YaHTTP::Request& req, const std::string& path) { (void) path; });
@@ -78,4 +81,3 @@ void setupLuaWeb(LuaContext& luaCtx)
   });
 #endif /* DISABLE_LUA_WEB_HANDLERS */
 }
-
index c526a93cc2d6d0855b479b36b270b7bc4df8a803..2d939e3c2c8fb518b3410a042712591e792409fa 100644 (file)
 #include <vector>
 
 #include "dnsdist.hh"
+#include "dnsdist-backend.hh"
+#include "dnsdist-cache.hh"
 #include "dnsdist-carbon.hh"
 #include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-console.hh"
 #include "dnsdist-crypto.hh"
 #include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
 #include "dnsdist-discovery.hh"
 #include "dnsdist-ecs.hh"
+#include "dnsdist-frontend.hh"
 #include "dnsdist-healthchecks.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-lua-hooks.hh"
@@ -57,7 +62,7 @@
 #include "dnsdist-rings.hh"
 #include "dnsdist-secpoll.hh"
 #include "dnsdist-session-cache.hh"
-#include "dnsdist-tcp-downstream.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-web.hh"
 
 #include "base64.hh"
 
 using std::thread;
 
-static boost::optional<std::vector<std::function<void(void)>>> g_launchWork = boost::none;
-
-boost::tribool g_noLuaSideEffect;
-static bool g_included{false};
+static boost::tribool s_noLuaSideEffect;
 
 /* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
    Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
    has done so before on this invocation, this call won't be part of delta() output */
 void setLuaNoSideEffect()
 {
-  if (g_noLuaSideEffect == false) {
+  if (s_noLuaSideEffect == false) {
     // there has been a side effect already
     return;
   }
-  g_noLuaSideEffect = true;
+  s_noLuaSideEffect = true;
 }
 
 void setLuaSideEffect()
 {
-  g_noLuaSideEffect = false;
+  s_noLuaSideEffect = false;
 }
 
 bool getLuaNoSideEffect()
 {
-  if (g_noLuaSideEffect) {
+  if (s_noLuaSideEffect) {
     // NOLINTNEXTLINE(readability-simplify-boolean-expr): it's a tribool, not a boolean
     return true;
   }
@@ -113,7 +115,7 @@ bool getLuaNoSideEffect()
 
 void resetLuaSideEffect()
 {
-  g_noLuaSideEffect = boost::logic::indeterminate;
+  s_noLuaSideEffect = boost::logic::indeterminate;
 }
 
 using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>, std::shared_ptr<XskSocket>>>;
@@ -303,7 +305,7 @@ static void LuaThread(const std::string& code)
 
 static bool checkConfigurationTime(const std::string& name)
 {
-  if (!g_configurationDone) {
+  if (!dnsdist::configuration::isImmutableConfigurationDone()) {
     return true;
   }
   g_outputBuffer = name + " cannot be used at runtime!\n";
@@ -442,7 +444,9 @@ static void handleNewServerSourceParameter(boost::optional<newserver_t>& vars, D
         }
 #ifdef SO_BINDTODEVICE
         /* we need to retain CAP_NET_RAW to be able to set SO_BINDTODEVICE in the health checks */
-        g_capabilitiesToRetain.insert("CAP_NET_RAW");
+        dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& currentConfig) {
+          currentConfig.d_capabilitiesToRetain.insert("CAP_NET_RAW");
+        });
 #endif
       }
       else {
@@ -456,7 +460,7 @@ static void handleNewServerSourceParameter(boost::optional<newserver_t>& vars, D
 static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 {
   luaCtx.writeFunction("inClientStartup", [client]() {
-    return client && !g_configurationDone;
+    return client && !dnsdist::configuration::isImmutableConfigurationDone();
   });
 
   luaCtx.writeFunction("inConfigCheck", [configCheck]() {
@@ -572,7 +576,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                          if (getOptionalValue<std::string>(vars, "tls", valueStr) > 0) {
                            serverPort = 853;
                            config.d_tlsParams.d_provider = valueStr;
-                           tlsCtx = getTLSContext(config.d_tlsParams);
 
                            if (getOptionalValue<std::string>(vars, "dohPath", valueStr) > 0) {
 #if !defined(HAVE_DNS_OVER_HTTPS) || !defined(HAVE_NGHTTP2)
@@ -581,9 +584,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
                              serverPort = 443;
                              config.d_dohPath = valueStr;
+                             config.d_tlsParams.d_alpn = TLSFrontend::ALPN::DoH;
 
                              getOptionalValue<bool>(vars, "addXForwardedHeaders", config.d_addXForwardedHeaders);
                            }
+                           else {
+                             config.d_tlsParams.d_alpn = TLSFrontend::ALPN::DoT;
+                           }
+
+                           tlsCtx = getTLSContext(config.d_tlsParams);
                          }
 
                          try {
@@ -649,7 +658,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_XSK
                          LuaArray<std::shared_ptr<XskSocket>> luaXskSockets;
                          if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
-                           if (g_configurationDone) {
+                           if (dnsdist::configuration::isImmutableConfigurationDone()) {
                              throw std::runtime_error("Adding a server with xsk at runtime is not supported");
                            }
                            std::vector<std::shared_ptr<XskSocket>> xskSockets;
@@ -686,34 +695,23 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
                          /* this needs to be done _AFTER_ the order has been set,
                             since the server are kept ordered inside the pool */
-                         auto localPools = g_pools.getCopy();
                          if (!ret->d_config.pools.empty()) {
                            for (const auto& poolName : ret->d_config.pools) {
-                             addServerToPool(localPools, poolName, ret);
+                             addServerToPool(poolName, ret);
                            }
                          }
                          else {
-                           addServerToPool(localPools, "", ret);
+                           addServerToPool("", ret);
                          }
-                         g_pools.setState(localPools);
 
                          if (ret->connected) {
-                           if (g_launchWork) {
-                             g_launchWork->push_back([ret]() {
-                               ret->start();
-                             });
-                           }
-                           else {
+                           if (!dnsdist::configuration::isImmutableConfigurationDone()) {
                              ret->start();
                            }
                          }
 
-                         auto states = g_dstates.getCopy();
-                         states.push_back(ret);
-                         std::stable_sort(states.begin(), states.end(), [](const decltype(ret)& lhs, const decltype(ret)& rhs) {
-                           return lhs->d_config.order < rhs->d_config.order;
-                         });
-                         g_dstates.setState(states);
+                         dnsdist::backend::registerNewBackend(ret);
+
                          checkAllParametersConsumed("newServer", vars);
                          return ret;
                        });
@@ -722,13 +720,12 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                        [](boost::variant<std::shared_ptr<DownstreamState>, int, std::string> var) {
                          setLuaSideEffect();
                          shared_ptr<DownstreamState> server = nullptr;
-                         auto states = g_dstates.getCopy();
                          if (auto* rem = boost::get<shared_ptr<DownstreamState>>(&var)) {
                            server = *rem;
                          }
                          else if (auto* str = boost::get<std::string>(&var)) {
                            const auto uuid = getUniqueID(*str);
-                           for (auto& state : states) {
+                           for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
                              if (*state->d_config.id == uuid) {
                                server = state;
                              }
@@ -736,34 +733,246 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                          }
                          else {
                            int idx = boost::get<int>(var);
-                           server = states.at(idx);
+                           server = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends.at(idx);
                          }
                          if (!server) {
                            throw std::runtime_error("unable to locate the requested server");
                          }
-                         auto localPools = g_pools.getCopy();
                          for (const string& poolName : server->d_config.pools) {
-                           removeServerFromPool(localPools, poolName, server);
+                           removeServerFromPool(poolName, server);
                          }
-                         /* the server might also be in the default pool */
-                         removeServerFromPool(localPools, "", server);
-                         g_pools.setState(localPools);
-                         states.erase(remove(states.begin(), states.end(), server), states.end());
-                         g_dstates.setState(states);
+
+                         try {
+                           /* the server might also be in the default pool */
+                           removeServerFromPool("", server);
+                         }
+                         catch (const std::out_of_range& exp) {
+                           /* but the default pool might not exist yet, this is fine */
+                         }
+
+                         dnsdist::configuration::updateRuntimeConfiguration([&server](dnsdist::configuration::RuntimeConfiguration& config) {
+                           config.d_backends.erase(std::remove(config.d_backends.begin(), config.d_backends.end(), server), config.d_backends.end());
+                         });
+
                          server->stop();
                        });
 
-  luaCtx.writeFunction("truncateTC", [](bool value) { setLuaSideEffect(); g_truncateTC = value; });
-  luaCtx.writeFunction("fixupCase", [](bool value) { setLuaSideEffect(); g_fixupCase = value; });
+  struct BooleanConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, bool newValue)> mutator;
+  };
+  static const std::vector<BooleanConfigurationItems> booleanConfigItems{
+    {"truncateTC", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_truncateTC = newValue; }},
+    {"fixupCase", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_fixupCase = newValue; }},
+    {"setECSOverride", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_ecsOverride = newValue; }},
+    {"setQueryCount", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_queryCountConfig.d_enabled = newValue; }},
+    {"setVerbose", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verbose = newValue; }},
+    {"setVerboseHealthChecks", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verboseHealthChecks = newValue; }},
+    {"setServFailWhenNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_servFailOnNoPolicy = newValue; }},
+    {"setRoundRobinFailOnNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_roundrobinFailOnNoServer = newValue; }},
+    {"setDropEmptyQueries", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_dropEmptyQueries = newValue; }},
+    {"setAllowEmptyResponse", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_allowEmptyResponse = newValue; }},
+    {"setConsoleConnectionsLogging", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_logConsoleConnections = newValue; }},
+    {"setProxyProtocolApplyACLToProxiedClients", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_applyACLToProxiedClients = newValue; }},
+    {"setAddEDNSToSelfGeneratedResponses", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_addEDNSToSelfGeneratedResponses = newValue; }},
+  };
+  struct UnsignedIntegerConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, uint64_t value)> mutator;
+    const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+  };
+  static const std::vector<UnsignedIntegerConfigurationItems> unsignedIntegerConfigItems{
+    {"setCacheCleaningDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningDelay = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setCacheCleaningPercentage", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningPercentage = newValue; }, 100U},
+    {"setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheMaxSessionsPerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setOutgoingTLSSessionsCacheCleanupDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheCleanupDelay = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setOutgoingTLSSessionsCacheMaxTicketValidity", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheSessionValidity = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setECSSourcePrefixV4", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV4 = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setECSSourcePrefixV6", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV6 = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setTCPRecvTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpRecvTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setTCPSendTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpSendTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setMaxTCPQueriesPerConnection", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPQueriesPerConn = newValue; }, std::numeric_limits<uint64_t>::max()},
+    {"setMaxTCPConnectionDuration", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPConnectionDuration = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setStaleCacheEntriesTTL", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_staleCacheEntriesTTL = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setConsoleOutputMaxMsgSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_consoleOutputMsgMaxSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_SECPOLL
+    {"setSecurityPollInterval", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_secPollInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_SECPOLL */
+    {"setProxyProtocolMaximumPayloadSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), newValue); }, std::numeric_limits<uint32_t>::max()},
+    {"setPayloadSizeOnSelfGeneratedAnswers", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) {
+       if (newValue < 512) {
+         warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
+         g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
+         newValue = 512;
+       }
+       if (newValue > dnsdist::configuration::s_udpIncomingBufferSize) {
+         warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", dnsdist::configuration::s_udpIncomingBufferSize);
+         g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(dnsdist::configuration::s_udpIncomingBufferSize) + " instead";
+         newValue = dnsdist::configuration::s_udpIncomingBufferSize;
+       }
+       config.d_payloadSizeSelfGenAnswers = newValue;
+     },
+     std::numeric_limits<uint64_t>::max()},
+#ifndef DISABLE_DYNBLOCKS
+    {"setDynBlocksPurgeInterval", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_dynBlocksPurgeInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_DYNBLOCKS */
+  };
+
+  struct StringConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, const std::string& value)> mutator;
+  };
+  static const std::vector<StringConfigurationItems> stringConfigItems{
+#ifndef DISABLE_SECPOLL
+    {"setSecurityPollSuffix", [](dnsdist::configuration::RuntimeConfiguration& config, const std::string& newValue) { config.d_secPollSuffix = newValue; }},
+#endif /* DISABLE_SECPOLL */
+  };
+
+  for (const auto& item : booleanConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](bool value) {
+      setLuaSideEffect();
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  for (const auto& item : unsignedIntegerConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+      setLuaSideEffect();
+      checkParameterBound(item.name, value, item.maximumValue);
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  for (const auto& item : stringConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](const std::string& value) {
+      setLuaSideEffect();
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  struct BooleanImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, bool newValue)> mutator;
+  };
+  static const std::vector<BooleanImmutableConfigurationItems> booleanImmutableConfigItems{
+    {"setRandomizedOutgoingSockets", [](dnsdist::configuration::ImmutableConfiguration& config, bool newValue) { config.d_randomizeUDPSocketsToBackend = newValue; }},
+    {"setRandomizedIdsOverUDP", [](dnsdist::configuration::ImmutableConfiguration& config, bool newValue) { config.d_randomizeIDsToBackend = newValue; }},
+  };
+  struct UnsignedIntegerImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, uint64_t value)> mutator;
+    const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+  };
+  static const std::vector<UnsignedIntegerImmutableConfigurationItems> unsignedIntegerImmutableConfigItems
+  {
+    {"setMaxTCPQueuedConnections", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPQueuedConnections = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setMaxTCPClientThreads", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPClientThreads = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setMaxTCPConnectionsPerClient", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxTCPConnectionsPerClient = newValue; }, std::numeric_limits<uint64_t>::max()},
+      {"setTCPInternalPipeBufferSize", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_tcpInternalPipeBufferSize = newValue; }, std::numeric_limits<uint64_t>::max()},
+      {"setMaxCachedTCPConnectionsPerDownstream", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPMaxIdlePerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setTCPDownstreamCleanupInterval", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPCleanupInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+      {"setTCPDownstreamMaxIdleTime", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingTCPMaxIdleTime = newValue; }, std::numeric_limits<uint16_t>::max()},
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+      {"setOutgoingDoHWorkerThreads", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHWorkers = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setMaxIdleDoHConnectionsPerDownstream", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHMaxIdlePerBackend = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setDoHDownstreamCleanupInterval", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHCleanupInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+      {"setDoHDownstreamMaxIdleTime", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_outgoingDoHMaxIdleTime = newValue; }, std::numeric_limits<uint16_t>::max()},
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+      {"setMaxUDPOutstanding", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_maxUDPOutstanding = newValue; }, std::numeric_limits<uint16_t>::max()},
+      {"setWHashedPertubation", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_hashPerturbation = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_RECVMMSG
+      {"setUDPMultipleMessagesVectorSize", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_udpVectorSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_RECVMMSG */
+      {"setUDPTimeout", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_udpTimeout = newValue; }, std::numeric_limits<uint8_t>::max()},
+      {"setConsoleMaximumConcurrentConnections", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_consoleMaxConcurrentConnections = newValue; }, std::numeric_limits<uint32_t>::max()},
+      {"setRingBuffersLockRetries", [](dnsdist::configuration::ImmutableConfiguration& config, uint64_t newValue) { config.d_ringsNbLockTries = newValue; }, std::numeric_limits<uint64_t>::max()},
+  };
+
+  struct DoubleImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::ImmutableConfiguration& config, double value)> mutator;
+    const double maximumValue{1.0};
+  };
+  static const std::vector<DoubleImmutableConfigurationItems> doubleImmutableConfigItems{
+    {"setConsistentHashingBalancingFactor", [](dnsdist::configuration::ImmutableConfiguration& config, double newValue) { config.d_consistentHashBalancingFactor = newValue; }, 1.0},
+    {"setWeightedBalancingFactor", [](dnsdist::configuration::ImmutableConfiguration& config, double newValue) { config.d_weightedBalancingFactor = newValue; }, 1.0},
+  };
+
+  for (const auto& item : booleanConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](bool value) {
+      try {
+        dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+    });
+  }
+
+  for (const auto& item : unsignedIntegerImmutableConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+      checkParameterBound(item.name, value, item.maximumValue);
+      try {
+        dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::ImmutableConfiguration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+    });
+  }
+  for (const auto& item : doubleImmutableConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](double value) {
+      if (value > item.maximumValue) {
+        g_outputBuffer = "Invalid value passed to " + item.name + "()!\n";
+        errlog("Invalid value passed to %s()!", item.name);
+        return;
+      }
+
+      try {
+        dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::ImmutableConfiguration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+      setLuaSideEffect();
+    });
+  }
 
-  luaCtx.writeFunction("addACL", [](const std::string& domain) {
+  luaCtx.writeFunction("getVerbose", []() { return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose; });
+
+  luaCtx.writeFunction("addACL", [](const std::string& mask) {
     setLuaSideEffect();
-    g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); });
+    dnsdist::configuration::updateRuntimeConfiguration([&mask](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_ACL.addMask(mask);
+    });
   });
 
   luaCtx.writeFunction("rmACL", [](const std::string& netmask) {
     setLuaSideEffect();
-    g_ACL.modify([netmask](NetmaskGroup& nmg) { nmg.deleteMask(netmask); });
+    dnsdist::configuration::updateRuntimeConfiguration([&netmask](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_ACL.deleteMask(netmask);
+    });
   });
 
   luaCtx.writeFunction("setLocal", [client](const std::string& addr, boost::optional<localbind_t> vars) {
@@ -787,12 +996,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
     parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
 
+    auto frontends = dnsdist::configuration::getImmutableConfiguration().d_frontends;
     try {
       ComboAddress loc(addr, 53);
-      for (auto it = g_frontends.begin(); it != g_frontends.end();) {
+      for (auto it = frontends.begin(); it != frontends.end();) {
         /* DoH, DoT and DNSCrypt frontends are separate */
         if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr && (*it)->dohFrontend == nullptr) {
-          it = g_frontends.erase(it);
+          it = frontends.erase(it);
         }
         else {
           ++it;
@@ -800,8 +1010,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       }
 
       // only works pre-startup, so no sync necessary
-      auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
-      auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
       if (tcpListenQueueSize > 0) {
         tcpCS->tcpListenQueueSize = tcpListenQueueSize;
       }
@@ -816,17 +1026,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       std::shared_ptr<XskSocket> socket;
       parseXskVars(vars, socket);
       if (socket) {
-        udpCS->xskInfo = XskWorker::create();
-        udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+        udpCS->xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, socket->sharedEmptyFrameOffset);
         socket->addWorker(udpCS->xskInfo);
         socket->addWorkerRoute(udpCS->xskInfo, loc);
+        udpCS->xskInfoResponder = XskWorker::create(XskWorker::Type::OutgoingOnly, socket->sharedEmptyFrameOffset);
+        socket->addWorker(udpCS->xskInfoResponder);
         vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
       }
 #endif /* HAVE_XSK */
-      g_frontends.push_back(std::move(udpCS));
-      g_frontends.push_back(std::move(tcpCS));
+      frontends.push_back(std::move(udpCS));
+      frontends.push_back(std::move(tcpCS));
 
       checkAllParametersConsumed("setLocal", vars);
+      dnsdist::configuration::updateImmutableConfiguration([&frontends](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_frontends = std::move(frontends);
+      });
     }
     catch (const std::exception& e) {
       g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -856,8 +1070,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     try {
       ComboAddress loc(addr, 53);
       // only works pre-startup, so no sync necessary
-      auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
-      auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto udpCS = std::make_shared<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto tcpCS = std::make_shared<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
       if (tcpListenQueueSize > 0) {
         tcpCS->tcpListenQueueSize = tcpListenQueueSize;
       }
@@ -871,15 +1085,18 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       std::shared_ptr<XskSocket> socket;
       parseXskVars(vars, socket);
       if (socket) {
-        udpCS->xskInfo = XskWorker::create();
-        udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+        udpCS->xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, socket->sharedEmptyFrameOffset);
         socket->addWorker(udpCS->xskInfo);
         socket->addWorkerRoute(udpCS->xskInfo, loc);
+        udpCS->xskInfoResponder = XskWorker::create(XskWorker::Type::OutgoingOnly, socket->sharedEmptyFrameOffset);
+        socket->addWorker(udpCS->xskInfoResponder);
         vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
       }
 #endif /* HAVE_XSK */
-      g_frontends.push_back(std::move(udpCS));
-      g_frontends.push_back(std::move(tcpCS));
+      dnsdist::configuration::updateImmutableConfiguration([&udpCS, &tcpCS](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_frontends.push_back(std::move(udpCS));
+        config.d_frontends.push_back(std::move(tcpCS));
+      });
 
       checkAllParametersConsumed("addLocal", vars);
     }
@@ -900,7 +1117,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         nmg.addMask(entry.second);
       }
     }
-    g_ACL.setState(nmg);
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_ACL = std::move(nmg);
+    });
   });
 
   luaCtx.writeFunction("setACLFromFile", [](const std::string& file) {
@@ -927,12 +1146,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       nmg.addMask(line);
     }
 
-    g_ACL.setState(nmg);
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_ACL = std::move(nmg);
+    });
   });
 
   luaCtx.writeFunction("showACL", []() {
     setLuaNoSideEffect();
-    auto aclEntries = g_ACL.getLocal()->toStringVector();
+    auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
 
     for (const auto& entry : aclEntries) {
       g_outputBuffer += entry + "\n";
@@ -946,10 +1167,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #if 0
     // Useful for debugging leaks, but might lead to race under load
     // since other threads are still running.
-    for (auto& frontend : g_tlslocals) {
+    for (auto& frontend : getDoTFrontends()) {
       frontend->cleanup();
     }
-    g_tlslocals.clear();
     g_rings.clear();
 #endif /* 0 */
     pdns::coverage::dumpCoverageData();
@@ -983,8 +1203,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       uint64_t totQueries{0};
       uint64_t totDrops{0};
       int counter = 0;
-      auto states = g_dstates.getLocal();
-      for (const auto& backend : *states) {
+      for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
         string status = backend->getStatus();
         string pools;
         for (const auto& pool : backend->d_config.pools) {
@@ -1029,22 +1248,23 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     setLuaNoSideEffect();
     LuaArray<std::shared_ptr<DownstreamState>> ret;
     int count = 1;
-    for (const auto& backend : g_dstates.getCopy()) {
+    for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
       ret.emplace_back(count++, backend);
     }
     return ret;
   });
 
   luaCtx.writeFunction("getPoolServers", [](const string& pool) {
-    const auto poolServers = getDownstreamCandidates(g_pools.getCopy(), pool);
+    //coverity[auto_causes_copy]
+    const auto poolServers = getDownstreamCandidates(pool);
     return *poolServers;
   });
 
-  luaCtx.writeFunction("getServer", [client](boost::variant<int, std::string> identifier) {
+  luaCtx.writeFunction("getServer", [client](boost::variant<unsigned int, std::string> identifier) {
     if (client) {
       return std::make_shared<DownstreamState>(ComboAddress());
     }
-    auto states = g_dstates.getCopy();
+    const auto& states = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
     if (auto* str = boost::get<std::string>(&identifier)) {
       const auto uuid = getUniqueID(*str);
       for (auto& state : states) {
@@ -1053,7 +1273,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         }
       }
     }
-    else if (auto* pos = boost::get<int>(&identifier)) {
+    else if (auto* pos = boost::get<unsigned int>(&identifier)) {
       return states.at(*pos);
     }
 
@@ -1064,12 +1284,17 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifndef DISABLE_CARBON
   luaCtx.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName, boost::optional<uint64_t> interval, boost::optional<string> namespace_name, boost::optional<string> instance_name) {
     setLuaSideEffect();
-    dnsdist::Carbon::Endpoint endpoint{ComboAddress(address, 2003),
-                                       (namespace_name && !namespace_name->empty()) ? *namespace_name : "dnsdist",
-                                       ourName ? *ourName : "",
-                                       (instance_name && !instance_name->empty()) ? *instance_name : "main",
-                                       (interval && *interval < std::numeric_limits<unsigned int>::max()) ? static_cast<unsigned int>(*interval) : 30};
-    dnsdist::Carbon::addEndpoint(std::move(endpoint));
+    auto newEndpoint = dnsdist::Carbon::newEndpoint(address,
+                                                    (ourName ? *ourName : ""),
+                                                    (interval ? *interval : 30),
+                                                    (namespace_name ? *namespace_name : "dnsdist"),
+                                                    (instance_name ? *instance_name : "main"));
+    if (dnsdist::configuration::isImmutableConfigurationDone()) {
+      dnsdist::Carbon::run({newEndpoint});
+    }
+    dnsdist::configuration::updateRuntimeConfiguration([&newEndpoint](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_carbonEndpoints.push_back(std::move(newEndpoint));
+    });
   });
 #endif /* DISABLE_CARBON */
 
@@ -1087,29 +1312,26 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       return;
     }
 
-    try {
-      int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
-      SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-      SBind(sock, local);
-      SListen(sock, 5);
-      auto launch = [sock, local]() {
-        thread thr(dnsdistWebserverThread, sock, local);
+    dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_webServerAddress = local;
+    });
+
+    if (dnsdist::configuration::isImmutableConfigurationDone()) {
+      try {
+        auto sock = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+        sock.bind(local, true);
+        sock.listen(5);
+        thread thr(dnsdist::webserver::WebserverThread, std::move(sock));
         thr.detach();
-      };
-      if (g_launchWork) {
-        g_launchWork->push_back(launch);
       }
-      else {
-        launch();
+      catch (const std::exception& e) {
+        g_outputBuffer = "Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
+        errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
       }
     }
-    catch (const std::exception& e) {
-      g_outputBuffer = "Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
-      errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what());
-    }
   });
 
-  typedef LuaAssociativeTable<boost::variant<bool, std::string, LuaAssociativeTable<std::string>>> webserveropts_t;
+  using webserveropts_t = LuaAssociativeTable<boost::variant<bool, std::string, LuaAssociativeTable<std::string>>>;
 
   luaCtx.writeFunction("setWebserverConfig", [](boost::optional<webserveropts_t> vars) {
     setLuaSideEffect();
@@ -1118,64 +1340,65 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       return;
     }
 
-    bool hashPlaintextCredentials = false;
-    getOptionalValue<bool>(vars, "hashPlaintextCredentials", hashPlaintextCredentials);
-
-    std::string password;
-    std::string apiKey;
-    std::string acl;
-    LuaAssociativeTable<std::string> headers;
-    bool statsRequireAuthentication{true};
-    bool apiRequiresAuthentication{true};
-    bool dashboardRequiresAuthentication{true};
-    int maxConcurrentConnections = 0;
+    dnsdist::configuration::updateRuntimeConfiguration([&vars](dnsdist::configuration::RuntimeConfiguration& config) {
+      std::string password;
+      std::string apiKey;
+      std::string acl;
+      LuaAssociativeTable<std::string> headers;
+      bool statsRequireAuthentication{true};
+      bool apiRequiresAuthentication{true};
+      bool dashboardRequiresAuthentication{true};
+      bool hashPlaintextCredentials = false;
+      getOptionalValue<bool>(vars, "hashPlaintextCredentials", hashPlaintextCredentials);
 
-    if (getOptionalValue<std::string>(vars, "password", password) > 0) {
-      auto holder = make_unique<CredentialsHolder>(std::move(password), hashPlaintextCredentials);
-      if (!holder->wasHashed() && holder->isHashingAvailable()) {
-        infolog("Passing a plain-text password via the 'password' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+      if (getOptionalValue<std::string>(vars, "password", password) > 0) {
+        auto holder = std::make_shared<CredentialsHolder>(std::move(password), hashPlaintextCredentials);
+        if (!holder->wasHashed() && holder->isHashingAvailable()) {
+          infolog("Passing a plain-text password via the 'password' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+        }
+        config.d_webPassword = std::move(holder);
       }
 
-      setWebserverPassword(std::move(holder));
-    }
-
-    if (getOptionalValue<std::string>(vars, "apiKey", apiKey) > 0) {
-      auto holder = make_unique<CredentialsHolder>(std::move(apiKey), hashPlaintextCredentials);
-      if (!holder->wasHashed() && holder->isHashingAvailable()) {
-        infolog("Passing a plain-text API key via the 'apiKey' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+      if (getOptionalValue<std::string>(vars, "apiKey", apiKey) > 0) {
+        auto holder = std::make_shared<CredentialsHolder>(std::move(apiKey), hashPlaintextCredentials);
+        if (!holder->wasHashed() && holder->isHashingAvailable()) {
+          infolog("Passing a plain-text API key via the 'apiKey' parameter to 'setWebserverConfig()' is not advised, please consider generating a hashed one using 'hashPassword()' instead.");
+        }
+        config.d_webAPIKey = std::move(holder);
       }
 
-      setWebserverAPIKey(std::move(holder));
-    }
-
-    if (getOptionalValue<std::string>(vars, "acl", acl) > 0) {
-      setWebserverACL(acl);
-    }
+      if (getOptionalValue<std::string>(vars, "acl", acl) > 0) {
+        NetmaskGroup ACLnmg;
+        ACLnmg.toMasks(acl);
+        config.d_webServerACL = std::move(ACLnmg);
+      }
 
-    if (getOptionalValue<decltype(headers)>(vars, "customHeaders", headers) > 0) {
-      setWebserverCustomHeaders(headers);
-    }
+      if (getOptionalValue<decltype(headers)>(vars, "customHeaders", headers) > 0) {
+        config.d_webCustomHeaders = std::move(headers);
+      }
 
-    if (getOptionalValue<bool>(vars, "statsRequireAuthentication", statsRequireAuthentication) > 0) {
-      setWebserverStatsRequireAuthentication(statsRequireAuthentication);
-    }
+      if (getOptionalValue<bool>(vars, "statsRequireAuthentication", statsRequireAuthentication) > 0) {
+        config.d_statsRequireAuthentication = statsRequireAuthentication;
+      }
 
-    if (getOptionalValue<bool>(vars, "apiRequiresAuthentication", apiRequiresAuthentication) > 0) {
-      setWebserverAPIRequiresAuthentication(apiRequiresAuthentication);
-    }
+      if (getOptionalValue<bool>(vars, "apiRequiresAuthentication", apiRequiresAuthentication) > 0) {
+        config.d_apiRequiresAuthentication = apiRequiresAuthentication;
+      }
 
-    if (getOptionalValue<bool>(vars, "dashboardRequiresAuthentication", dashboardRequiresAuthentication) > 0) {
-      setWebserverDashboardRequiresAuthentication(dashboardRequiresAuthentication);
-    }
+      if (getOptionalValue<bool>(vars, "dashboardRequiresAuthentication", dashboardRequiresAuthentication) > 0) {
+        config.d_dashboardRequiresAuthentication = dashboardRequiresAuthentication;
+      }
+    });
 
+    int maxConcurrentConnections = 0;
     if (getOptionalIntegerValue("setWebserverConfig", vars, "maxConcurrentConnections", maxConcurrentConnections) > 0) {
-      setWebserverMaxConcurrentConnections(maxConcurrentConnections);
+      dnsdist::webserver::setMaxConcurrentConnections(maxConcurrentConnections);
     }
   });
 
   luaCtx.writeFunction("showWebserverConfig", []() {
     setLuaNoSideEffect();
-    return getWebserverConfig();
+    return dnsdist::webserver::getConfig();
   });
 
   luaCtx.writeFunction("hashPassword", [](const std::string& password, boost::optional<uint64_t> workFactor) {
@@ -1190,36 +1413,32 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     ComboAddress local(str, 5199);
 
     if (client || configCheck) {
-      g_serverControl = local;
       return;
     }
 
-    g_consoleEnabled = true;
+    dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleServerAddress = local;
+      config.d_consoleEnabled = true;
+    });
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
-    if (g_configurationDone && g_consoleKey.empty()) {
+    if (dnsdist::configuration::isImmutableConfigurationDone() && dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) {
       warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
     }
 #endif
 
-    try {
-      auto sock = std::make_shared<Socket>(local.sin4.sin_family, SOCK_STREAM, 0);
-      sock->bind(local, true);
-      sock->listen(5);
-      auto launch = [sock = std::move(sock), local]() {
-        std::thread consoleControlThread(controlThread, sock, local);
+    if (dnsdist::configuration::isImmutableConfigurationDone()) {
+      try {
+        auto sock = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+        sock.bind(local, true);
+        sock.listen(5);
+        std::thread consoleControlThread(dnsdist::console::controlThread, std::move(sock));
         consoleControlThread.detach();
-      };
-      if (g_launchWork) {
-        g_launchWork->emplace_back(std::move(launch));
       }
-      else {
-        launch();
+      catch (const std::exception& exp) {
+        g_outputBuffer = "Unable to bind to control socket on " + local.toStringWithPort() + ": " + exp.what();
+        errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what());
       }
     }
-    catch (std::exception& e) {
-      g_outputBuffer = "Unable to bind to control socket on " + local.toStringWithPort() + ": " + e.what();
-      errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), e.what());
-    }
   });
 
   luaCtx.writeFunction("addConsoleACL", [](const std::string& netmask) {
@@ -1228,7 +1447,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     warnlog("Allowing remote access to the console while neither libsodium not libcrypto support has been enabled is not secure, and will result in cleartext communications");
 #endif
 
-    g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
+    dnsdist::configuration::updateRuntimeConfiguration([&netmask](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleACL.addMask(netmask);
+    });
   });
 
   luaCtx.writeFunction("setConsoleACL", [](LuaTypeOrArrayOf<std::string> inp) {
@@ -1247,7 +1468,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         nmg.addMask(entry.second);
       }
     }
-    g_consoleACL.setState(nmg);
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleACL = std::move(nmg);
+    });
   });
 
   luaCtx.writeFunction("showConsoleACL", []() {
@@ -1257,22 +1480,17 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
 #endif
 
-    auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+    auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
 
     for (const auto& entry : aclEntries) {
       g_outputBuffer += entry + "\n";
     }
   });
 
-  luaCtx.writeFunction("setConsoleMaximumConcurrentConnections", [](uint64_t max) {
-    setLuaSideEffect();
-    setConsoleMaximumConcurrentConnections(max);
-  });
-
   luaCtx.writeFunction("clearQueryCounters", []() {
     unsigned int size{0};
     {
-      auto records = g_qcount.records.write_lock();
+      auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
       size = records->size();
       records->clear();
     }
@@ -1283,9 +1501,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getQueryCounters", [](boost::optional<uint64_t> optMax) {
     setLuaNoSideEffect();
-    auto records = g_qcount.records.read_lock();
+    auto records = dnsdist::QueryCount::g_queryCountRecords.read_lock();
     g_outputBuffer = "query counting is currently: ";
-    g_outputBuffer += g_qcount.enabled ? "enabled" : "disabled";
+    g_outputBuffer += dnsdist::configuration::getCurrentRuntimeConfiguration().d_queryCountConfig.d_enabled ? "enabled" : "disabled";
     g_outputBuffer += (boost::format(" (%d records in buffer)\n") % records->size()).str();
 
     boost::format fmt("%-3d %s: %d request(s)\n");
@@ -1296,10 +1514,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled = enabled; });
-
-  luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
-    g_qcount.filter = std::move(func);
+  luaCtx.writeFunction("setQueryCountFilter", [](dnsdist::QueryCount::Configuration::Filter func) {
+    dnsdist::configuration::updateRuntimeConfiguration([&func](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_queryCountConfig.d_filter = std::move(func);
+    });
   });
 
   luaCtx.writeFunction("makeKey", []() {
@@ -1308,7 +1526,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 
   luaCtx.writeFunction("setKey", [](const std::string& key) {
-    if (!g_configurationDone && !g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
+    if (!dnsdist::configuration::isImmutableConfigurationDone() && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
       return; // but later setKeys() trump the -k value again
     }
 #if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
@@ -1316,24 +1534,27 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
 
     setLuaSideEffect();
-    string newkey;
-    if (B64Decode(key, newkey) < 0) {
+    string newKey;
+    if (B64Decode(key, newKey) < 0) {
       g_outputBuffer = string("Unable to decode ") + key + " as Base64";
       errlog("%s", g_outputBuffer);
+      return;
     }
-    else {
-      g_consoleKey = std::move(newkey);
-    }
+
+    dnsdist::configuration::updateRuntimeConfiguration([&newKey](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleKey = std::move(newKey);
+    });
   });
 
   luaCtx.writeFunction("clearConsoleHistory", []() {
-    clearConsoleHistory();
+    dnsdist::console::clearHistory();
   });
 
   luaCtx.writeFunction("testCrypto", [](boost::optional<string> optTestMsg) {
     setLuaNoSideEffect();
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
     try {
+      const auto& consoleKey = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey;
       string testmsg;
 
       if (optTestMsg) {
@@ -1347,14 +1568,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       dnsdist::crypto::authenticated::Nonce nonce2;
       nonce1.init();
       nonce2 = nonce1;
-      string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
-      string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+      string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+      string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
 
       nonce1.increment();
       nonce2.increment();
 
-      encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
-      decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+      encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+      decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
 
       if (testmsg == decrypted) {
         g_outputBuffer = "Everything is ok!\n";
@@ -1374,150 +1595,37 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
   });
 
-  luaCtx.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout = timeout; });
-
-  luaCtx.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout = timeout; });
-
-  luaCtx.writeFunction("setUDPTimeout", [](int timeout) { DownstreamState::s_udpTimeout = timeout; });
-
-  luaCtx.writeFunction("setMaxUDPOutstanding", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxUDPOutstanding")) {
-      return;
-    }
-
-    checkParameterBound("setMaxUDPOutstanding", max);
-    g_maxOutstanding = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPClientThreads")) {
-      return;
-    }
-    g_maxTCPClientThreads = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPQueuedConnections")) {
-      return;
-    }
-    g_maxTCPQueuedConnections = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPQueriesPerConnection", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPQueriesPerConnection")) {
-      return;
-    }
-    g_maxTCPQueriesPerConn = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPConnectionsPerClient", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPConnectionsPerClient")) {
-      return;
-    }
-    dnsdist::IncomingConcurrentTCPConnectionsManager::setMaxTCPConnectionsPerClient(max);
-  });
-
-  luaCtx.writeFunction("setMaxTCPConnectionDuration", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPConnectionDuration")) {
-      return;
-    }
-    g_maxTCPConnectionDuration = max;
-  });
-
-  luaCtx.writeFunction("setMaxCachedTCPConnectionsPerDownstream", [](uint64_t max) {
-    setTCPDownstreamMaxIdleConnectionsPerBackend(max);
-  });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
-  luaCtx.writeFunction("setMaxIdleDoHConnectionsPerDownstream", [](uint64_t max) {
-    setDoHDownstreamMaxIdleConnectionsPerBackend(max);
-  });
-
-  luaCtx.writeFunction("setOutgoingDoHWorkerThreads", [](uint64_t workers) {
-    if (!checkConfigurationTime("setOutgoingDoHWorkerThreads")) {
-      return;
-    }
-    g_outgoingDoHWorkerThreads = workers;
-  });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
-      return;
-    }
-    TLSSessionCache::setMaxTicketsPerBackend(max);
-  });
-
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheCleanupDelay", [](time_t delay) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheCleanupDelay")) {
-      return;
-    }
-    TLSSessionCache::setCleanupDelay(delay);
-  });
-
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketValidity", [](time_t validity) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketValidity")) {
-      return;
-    }
-    TLSSessionCache::setSessionValidity(validity);
-  });
-
   luaCtx.writeFunction("getOutgoingTLSSessionCacheSize", []() {
     setLuaNoSideEffect();
     return g_sessionCache.getSize();
   });
 
-  luaCtx.writeFunction("setCacheCleaningDelay", [](uint64_t delay) {
-    checkParameterBound("setCacheCleaningDelay", delay, std::numeric_limits<uint32_t>::max());
-    g_cacheCleaningDelay = delay;
-  });
-
-  luaCtx.writeFunction("setCacheCleaningPercentage", [](uint64_t percentage) {
-    if (percentage < 100) {
-      g_cacheCleaningPercentage = percentage;
-    }
-    else {
-      g_cacheCleaningPercentage = 100;
-    }
-  });
-
-  luaCtx.writeFunction("setECSSourcePrefixV4", [](uint64_t prefix) {
-    checkParameterBound("setECSSourcePrefixV4", prefix, std::numeric_limits<uint16_t>::max());
-    g_ECSSourcePrefixV4 = prefix;
-  });
-
-  luaCtx.writeFunction("setECSSourcePrefixV6", [](uint64_t prefix) {
-    checkParameterBound("setECSSourcePrefixV6", prefix, std::numeric_limits<uint16_t>::max());
-    g_ECSSourcePrefixV6 = prefix;
-  });
-
-  luaCtx.writeFunction("setECSOverride", [](bool override) { g_ECSOverride = override; });
-
 #ifndef DISABLE_DYNBLOCKS
   luaCtx.writeFunction("showDynBlocks", []() {
     setLuaNoSideEffect();
-    auto slow = g_dynblockNMG.getCopy();
+    const auto dynBlockDefaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+    const auto& clientAddressDynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
     timespec now{};
     gettime(&now);
     boost::format fmt("%-24s %8d %8d %-10s %-20s %-10s %s\n");
     g_outputBuffer = (fmt % "What" % "Seconds" % "Blocks" % "Warning" % "Action" % "eBPF" % "Reason").str();
-    for (const auto& entry : slow) {
+    for (const auto& entry : clientAddressDynamicRules) {
       if (now < entry.second.until) {
         uint64_t counter = entry.second.blocks;
         if (g_defaultBPFFilter && entry.second.bpf) {
           counter += g_defaultBPFFilter->getHits(entry.first.getNetwork());
         }
-        g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
+        g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : dynBlockDefaultAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
       }
     }
-    auto slow2 = g_dynblockSMT.getCopy();
-    slow2.visit([&now, &fmt](const SuffixMatchTree<DynBlock>& node) {
+    const auto& suffixDynamicRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+    suffixDynamicRules.visit([&now, &fmt, dynBlockDefaultAction](const SuffixMatchTree<DynBlock>& node) {
       if (now < node.d_value.until) {
         string dom("empty");
         if (!node.d_value.domain.empty()) {
           dom = node.d_value.domain.toString();
         }
-        g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction) % "" % node.d_value.reason).str();
+        g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : dynBlockDefaultAction) % "" % node.d_value.reason).str();
       }
     });
   });
@@ -1528,8 +1636,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     gettime(&now);
 
     LuaAssociativeTable<DynBlock> entries;
-    auto fullCopy = g_dynblockNMG.getCopy();
-    for (const auto& blockPair : fullCopy) {
+    const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+    for (const auto& blockPair : dnsdist::DynamicBlocks::getClientAddressDynamicRules()) {
       const auto& requestor = blockPair.first;
       if (!(now < blockPair.second.until)) {
         continue;
@@ -1539,7 +1647,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         entry.blocks += g_defaultBPFFilter->getHits(requestor.getNetwork());
       }
       if (entry.action == DNSAction::Action::None) {
-        entry.action = g_dynBlockAction;
+        entry.action = defaultAction;
       }
       entries.emplace(requestor.toString(), std::move(entry));
     }
@@ -1552,8 +1660,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     gettime(&now);
 
     LuaAssociativeTable<DynBlock> entries;
-    auto fullCopy = g_dynblockSMT.getCopy();
-    fullCopy.visit([&now, &entries](const SuffixMatchTree<DynBlock>& node) {
+    const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
+    const auto& suffixDynamicRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+    suffixDynamicRules.visit([&now, &entries, defaultAction](const SuffixMatchTree<DynBlock>& node) {
       if (!(now < node.d_value.until)) {
         return;
       }
@@ -1563,7 +1672,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         key = entry.domain.toString();
       }
       if (entry.action == DNSAction::Action::None) {
-        entry.action = g_dynBlockAction;
+        entry.action = defaultAction;
       }
       entries.emplace(std::move(key), std::move(entry));
     });
@@ -1572,10 +1681,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("clearDynBlocks", []() {
     setLuaSideEffect();
-    nmts_t nmg;
-    g_dynblockNMG.setState(nmg);
-    SuffixMatchTree<DynBlock> smt;
-    g_dynblockSMT.setState(smt);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+    dnsdist::DynamicBlocks::clearSuffixDynamicRules();
   });
 
 #ifndef DISABLE_DEPRECATED_DYNBLOCK
@@ -1585,7 +1692,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                            return;
                          }
                          setLuaSideEffect();
-                         auto slow = g_dynblockNMG.getCopy();
+                         auto dynamicRules = dnsdist::DynamicBlocks::getClientAddressDynamicRulesCopy();
+
                          timespec now{};
                          gettime(&now);
                          timespec until{now};
@@ -1595,7 +1703,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                            unsigned int count = 0;
                            /* this legacy interface does not support ranges or ports, use DynBlockRulesGroup instead */
                            AddressAndPortRange requestor(capair.first, capair.first.isIPv4() ? 32 : 128, 0);
-                           auto* got = slow.lookup(requestor);
+                           auto* got = dynamicRules.lookup(requestor);
                            bool expired = false;
                            if (got != nullptr) {
                              if (until < got->second.until) {
@@ -1615,17 +1723,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                            if (got == nullptr || expired) {
                              warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg);
                            }
-                           slow.insert(requestor).second = std::move(dblock);
+                           dynamicRules.insert(requestor).second = std::move(dblock);
                          }
-                         g_dynblockNMG.setState(slow);
+                         dnsdist::DynamicBlocks::setClientAddressDynamicRules(std::move(dynamicRules));
                        });
 
   luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
-    if (!checkConfigurationTime("setDynBlocksAction")) {
-      return;
-    }
     if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
-      g_dynBlockAction = action;
+      dnsdist::configuration::updateRuntimeConfiguration([action](dnsdist::configuration::RuntimeConfiguration& config) {
+        config.d_dynBlockAction = action;
+      });
     }
     else {
       errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
@@ -1633,10 +1740,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 #endif /* DISABLE_DEPRECATED_DYNBLOCK */
-
-  luaCtx.writeFunction("setDynBlocksPurgeInterval", [](uint64_t interval) {
-    DynBlockMaintenance::s_expiredDynBlocksPurgeInterval = static_cast<time_t>(interval);
-  });
 #endif /* DISABLE_DYNBLOCKS */
 
 #ifdef HAVE_DNSCRYPT
@@ -1686,13 +1789,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
 
       /* UDP */
-      auto clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
       clientState->dnscryptCtx = ctx;
-      g_dnsCryptLocals.push_back(ctx);
-      g_frontends.push_back(std::move(clientState));
+
+      dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_frontends.push_back(std::move(clientState));
+      });
 
       /* TCP */
-      clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      clientState = std::make_shared<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
       clientState->dnscryptCtx = std::move(ctx);
       if (tcpListenQueueSize > 0) {
         clientState->tcpListenQueueSize = tcpListenQueueSize;
@@ -1704,7 +1809,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
       }
 
-      g_frontends.push_back(std::move(clientState));
+      dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_frontends.push_back(std::move(clientState));
+      });
     }
     catch (const std::exception& e) {
       errlog("Error during addDNSCryptBind() processing: %s", e.what());
@@ -1720,7 +1827,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     size_t idx = 0;
 
     std::unordered_set<std::shared_ptr<DNSCryptContext>> contexts;
-    for (const auto& frontend : g_frontends) {
+    for (const auto& frontend : dnsdist::getFrontends()) {
       const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
       if (!ctx || contexts.count(ctx) != 0) {
         continue;
@@ -1736,15 +1843,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   luaCtx.writeFunction("getDNSCryptBind", [](uint64_t idx) {
     setLuaNoSideEffect();
     std::shared_ptr<DNSCryptContext> ret = nullptr;
-    if (idx < g_dnsCryptLocals.size()) {
-      ret = g_dnsCryptLocals.at(idx);
+    auto frontends = dnsdist::getDNSCryptFrontends();
+    if (idx < frontends.size()) {
+      ret = frontends.at(idx);
     }
     return ret;
   });
 
   luaCtx.writeFunction("getDNSCryptBindCount", []() {
     setLuaNoSideEffect();
-    return g_dnsCryptLocals.size();
+    return dnsdist::getDNSCryptFrontends().size();
   });
 #endif /* HAVE_DNSCRYPT */
 
@@ -1756,12 +1864,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       //             1        2         3                4
       ret << (fmt % "Name" % "Cache" % "ServerPolicy" % "Servers") << endl;
 
-      const auto localPools = g_pools.getCopy();
-      for (const auto& entry : localPools) {
+      //coverity[auto_causes_copy]
+      const auto defaultPolicyName = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName();
+      //coverity[auto_causes_copy]
+      const auto pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+      for (const auto& entry : pools) {
         const string& name = entry.first;
         const std::shared_ptr<ServerPool> pool = entry.second;
         string cache = pool->packetCache != nullptr ? pool->packetCache->toString() : "";
-        string policy = g_policy.getLocal()->getName();
+        string policy = defaultPolicyName;
         if (pool->policy != nullptr) {
           policy = pool->policy->getName();
         }
@@ -1793,8 +1904,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     setLuaNoSideEffect();
     LuaArray<std::string> ret;
     int count = 1;
-    const auto localPools = g_pools.getCopy();
-    for (const auto& entry : localPools) {
+    const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+    for (const auto& entry : pools) {
       const string& name = entry.first;
       ret.emplace_back(count++, name);
     }
@@ -1805,15 +1916,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (client) {
       return std::make_shared<ServerPool>();
     }
-    auto localPools = g_pools.getCopy();
-    std::shared_ptr<ServerPool> pool = createPoolIfNotExists(localPools, poolName);
-    g_pools.setState(localPools);
+    std::shared_ptr<ServerPool> pool = createPoolIfNotExists(poolName);
     return pool;
   });
 
-  luaCtx.writeFunction("setVerbose", [](bool verbose) { g_verbose = verbose; });
-  luaCtx.writeFunction("getVerbose", []() { return g_verbose; });
-  luaCtx.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks = verbose; });
   luaCtx.writeFunction("setVerboseLogDestination", [](const std::string& dest) {
     if (!checkConfigurationTime("setVerboseLogDestination")) {
       return;
@@ -1848,11 +1954,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, levelPrefix);
   });
 
-  luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint64_t ttl) {
-    checkParameterBound("setStaleCacheEntriesTTL", ttl, std::numeric_limits<uint32_t>::max());
-    g_staleCacheEntriesTTL = ttl;
-  });
-
   luaCtx.writeFunction("showBinds", []() {
     setLuaNoSideEffect();
     try {
@@ -1862,7 +1963,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       ret << (fmt % "#" % "Address" % "Protocol" % "Queries") << endl;
 
       size_t counter = 0;
-      for (const auto& front : g_frontends) {
+      for (const auto& front : dnsdist::getFrontends()) {
         ret << (fmt % counter % front->local.toStringWithPort() % front->getType() % front->queries) << endl;
         counter++;
       }
@@ -1877,22 +1978,23 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   luaCtx.writeFunction("getBind", [](uint64_t num) {
     setLuaNoSideEffect();
     ClientState* ret = nullptr;
-    if (num < g_frontends.size()) {
-      ret = g_frontends[num].get();
+    auto frontends = dnsdist::getFrontends();
+    if (num < frontends.size()) {
+      ret = frontends[num].get();
     }
     return ret;
   });
 
   luaCtx.writeFunction("getBindCount", []() {
     setLuaNoSideEffect();
-    return g_frontends.size();
+    return dnsdist::getFrontends().size();
   });
 
   luaCtx.writeFunction("help", [](boost::optional<std::string> command) {
     setLuaNoSideEffect();
     g_outputBuffer = "";
 #ifndef DISABLE_COMPLETION
-    for (const auto& keyword : g_consoleKeywords) {
+    for (const auto& keyword : dnsdist::console::getConsoleKeywords()) {
       if (!command) {
         g_outputBuffer += keyword.toString() + "\n";
       }
@@ -1979,7 +2081,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (!checkConfigurationTime("includeDirectory")) {
       return;
     }
-    if (g_included) {
+    static bool s_included{false};
+
+    if (s_included) {
       errlog("includeDirectory() cannot be used recursively!");
       g_outputBuffer = "includeDirectory() cannot be used recursively!\n";
       return;
@@ -2026,7 +2130,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
     std::sort(files.begin(), files.end());
 
-    g_included = true;
+    s_included = true;
 
     for (const auto& file : files) {
       std::ifstream ifs(file);
@@ -2041,121 +2145,84 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         luaCtx.executeCode(ifs);
       }
       catch (...) {
-        g_included = false;
+        s_included = false;
         throw;
       }
 
       luaCtx.executeCode(ifs);
     }
 
-    g_included = false;
+    s_included = false;
   });
 
   luaCtx.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
-    setLuaSideEffect();
-    g_apiReadWrite = writable;
-    if (apiConfigDir) {
+    if (apiConfigDir && (*apiConfigDir).empty()) {
+      errlog("The API configuration directory value cannot be empty!");
+      g_outputBuffer = "The API configuration directory value cannot be empty!";
+      return;
+    }
+    dnsdist::configuration::updateRuntimeConfiguration([writable, &apiConfigDir](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_apiReadWrite = writable;
       if (!(*apiConfigDir).empty()) {
-        g_apiConfigDirectory = *apiConfigDir;
-      }
-      else {
-        errlog("The API configuration directory value cannot be empty!");
-        g_outputBuffer = "The API configuration directory value cannot be empty!";
+        config.d_apiConfigDirectory = *apiConfigDir;
       }
-    }
-  });
-
-  luaCtx.writeFunction("setServFailWhenNoServer", [](bool servfail) {
-    setLuaSideEffect();
-    g_servFailOnNoPolicy = servfail;
-  });
-
-  luaCtx.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+    });
     setLuaSideEffect();
-    g_roundrobinFailOnNoServer = fail;
   });
 
-  luaCtx.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
-    setLuaSideEffect();
-    if (factor >= 1.0) {
-      g_consistentHashBalancingFactor = factor;
-    }
-    else {
-      errlog("Invalid value passed to setConsistentHashingBalancingFactor()!");
-      g_outputBuffer = "Invalid value passed to setConsistentHashingBalancingFactor()!\n";
+  luaCtx.writeFunction("setRingBuffersSize", [client](uint64_t capacity, boost::optional<uint64_t> numberOfShards) {
+    if (client) {
       return;
     }
-  });
-
-  luaCtx.writeFunction("setWeightedBalancingFactor", [](double factor) {
     setLuaSideEffect();
-    if (factor >= 1.0) {
-      g_weightedBalancingFactor = factor;
+    try {
+      dnsdist::configuration::updateImmutableConfiguration([capacity, numberOfShards](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_ringsCapacity = capacity;
+        if (numberOfShards) {
+          config.d_ringsNumberOfShards = *numberOfShards;
+        }
+      });
     }
-    else {
-      errlog("Invalid value passed to setWeightedBalancingFactor()!");
-      g_outputBuffer = "Invalid value passed to setWeightedBalancingFactor()!\n";
-      return;
+    catch (const std::exception& exp) {
+      g_outputBuffer = "setRingBuffersSize cannot be used at runtime!\n";
+      errlog("setRingBuffersSize cannot be used at runtime!");
     }
   });
 
-  luaCtx.writeFunction("setRingBuffersSize", [client](uint64_t capacity, boost::optional<uint64_t> numberOfShards) {
-    setLuaSideEffect();
-    if (!checkConfigurationTime("setRingBuffersSize")) {
+  luaCtx.writeFunction("setRingBuffersOptions", [client](const LuaAssociativeTable<boost::variant<bool, uint64_t>>& options) {
+    if (client) {
       return;
     }
-    if (!client) {
-      g_rings.setCapacity(capacity, numberOfShards ? *numberOfShards : 10);
-    }
-    else {
-      g_rings.setCapacity(0, 1);
-    }
-  });
-
-  luaCtx.writeFunction("setRingBuffersLockRetries", [](uint64_t retries) {
-    setLuaSideEffect();
-    g_rings.setNumberOfLockRetries(retries);
-  });
-
-  luaCtx.writeFunction("setRingBuffersOptions", [](const LuaAssociativeTable<boost::variant<bool, uint64_t>>& options) {
     setLuaSideEffect();
-    if (!checkConfigurationTime("setRingBuffersOptions")) {
-      return;
-    }
-    if (options.count("lockRetries") > 0) {
-      auto retries = boost::get<uint64_t>(options.at("lockRetries"));
-      g_rings.setNumberOfLockRetries(retries);
-    }
-    if (options.count("recordQueries") > 0) {
-      auto record = boost::get<bool>(options.at("recordQueries"));
-      g_rings.setRecordQueries(record);
+    try {
+      dnsdist::configuration::updateImmutableConfiguration([&options](dnsdist::configuration::ImmutableConfiguration& config) {
+        if (options.count("lockRetries") > 0) {
+          config.d_ringsNbLockTries = boost::get<uint64_t>(options.at("lockRetries"));
+        }
+        if (options.count("recordQueries") > 0) {
+          config.d_ringsRecordQueries = boost::get<bool>(options.at("recordQueries"));
+        }
+        if (options.count("recordResponses") > 0) {
+          config.d_ringsRecordResponses = boost::get<bool>(options.at("recordResponses"));
+        }
+      });
     }
-    if (options.count("recordResponses") > 0) {
-      auto record = boost::get<bool>(options.at("recordResponses"));
-      g_rings.setRecordResponses(record);
+    catch (const std::exception& exp) {
+      g_outputBuffer = "setRingBuffersOption cannot be used at runtime!\n";
+      errlog("setRingBuffersOption cannot be used at runtime!");
     }
   });
 
-  luaCtx.writeFunction("setWHashedPertubation", [](uint64_t perturb) {
-    setLuaSideEffect();
-    checkParameterBound("setWHashedPertubation", perturb, std::numeric_limits<uint32_t>::max());
-    g_hashperturb = perturb;
-  });
-
-  luaCtx.writeFunction("setTCPInternalPipeBufferSize", [](uint64_t size) { g_tcpInternalPipeBufferSize = size; });
   luaCtx.writeFunction("setTCPFastOpenKey", [](const std::string& keyString) {
-    setLuaSideEffect();
-    std::array<uint32_t, 4> key{};
-    // NOLINTNEXTLINE(readability-container-data-pointer)
-    auto ret = sscanf(keyString.c_str(), "%" SCNx32 "-%" SCNx32 "-%" SCNx32 "-%" SCNx32, &key[0], &key[1], &key[2], &key[3]);
-    if (ret != 4) {
+    std::vector<uint32_t> key(4);
+    auto ret = sscanf(keyString.c_str(), "%" SCNx32 "-%" SCNx32 "-%" SCNx32 "-%" SCNx32, &key.at(0), &key.at(1), &key.at(2), &key.at(3));
+    if (ret < 0 || static_cast<size_t>(ret) != key.size()) {
       g_outputBuffer = "Invalid value passed to setTCPFastOpenKey()!\n";
       return;
     }
-    extern vector<uint32_t> g_TCPFastOpenKey;
-    for (const auto byte : key) {
-      g_TCPFastOpenKey.push_back(byte);
-    }
+    dnsdist::configuration::updateImmutableConfiguration([&key](dnsdist::configuration::ImmutableConfiguration& config) {
+      config.d_tcpFastOpenKey = std::move(key);
+    });
   });
 
 #ifdef HAVE_NET_SNMP
@@ -2166,19 +2233,25 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (!checkConfigurationTime("snmpAgent")) {
       return;
     }
-    if (g_snmpEnabled) {
-      errlog("snmpAgent() cannot be used twice!");
-      g_outputBuffer = "snmpAgent() cannot be used twice!\n";
-      return;
+
+    {
+      if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpEnabled) {
+        errlog("snmpAgent() cannot be used twice!");
+        g_outputBuffer = "snmpAgent() cannot be used twice!\n";
+        return;
+      }
     }
 
-    g_snmpEnabled = true;
-    g_snmpTrapsEnabled = enableTraps;
+    dnsdist::configuration::updateRuntimeConfiguration([enableTraps](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_snmpEnabled = true;
+      config.d_snmpTrapsEnabled = enableTraps;
+    });
+
     g_snmpAgent = std::make_unique<DNSDistSNMPAgent>("dnsdist", daemonSocket ? *daemonSocket : std::string());
   });
 
   luaCtx.writeFunction("sendCustomTrap", [](const std::string& str) {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendCustomTrap(str);
     }
   });
@@ -2187,65 +2260,65 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifndef DISABLE_POLICIES_BINDINGS
   luaCtx.writeFunction("setServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy) {
     setLuaSideEffect();
-    g_policy.setState(*policy);
+    dnsdist::configuration::updateRuntimeConfiguration([&policy](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = policy;
+    });
   });
 
   luaCtx.writeFunction("setServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy) {
     setLuaSideEffect();
-    g_policy.setState(ServerPolicy{name, std::move(policy), true});
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy), true);
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
 
   luaCtx.writeFunction("setServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy) {
     setLuaSideEffect();
-    auto pol = ServerPolicy(name, std::move(policy));
-    g_policy.setState(std::move(pol));
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
 
   luaCtx.writeFunction("setServerPolicyLuaFFIPerThread", [](const string& name, const std::string& policyCode) {
     setLuaSideEffect();
-    auto pol = ServerPolicy(name, policyCode);
-    g_policy.setState(std::move(pol));
+    auto policy = std::make_shared<ServerPolicy>(name, policyCode);
+    dnsdist::configuration::updateRuntimeConfiguration([&policy](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(policy);
+    });
   });
 
   luaCtx.writeFunction("showServerPolicy", []() {
     setLuaSideEffect();
-    g_outputBuffer = g_policy.getLocal()->getName() + "\n";
+    g_outputBuffer = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() + "\n";
   });
 
   luaCtx.writeFunction("setPoolServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy, const string& pool) {
     setLuaSideEffect();
-    auto localPools = g_pools.getCopy();
-    setPoolPolicy(localPools, pool, policy);
-    g_pools.setState(localPools);
+    setPoolPolicy(pool, policy);
   });
 
   luaCtx.writeFunction("setPoolServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy, const string& pool) {
     setLuaSideEffect();
-    auto localPools = g_pools.getCopy();
-    setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
-    g_pools.setState(localPools);
+    setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
   });
 
   luaCtx.writeFunction("setPoolServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy, const string& pool) {
     setLuaSideEffect();
-    auto localPools = g_pools.getCopy();
-    setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
-    g_pools.setState(localPools);
+    setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
   });
 
   luaCtx.writeFunction("setPoolServerPolicyLuaFFIPerThread", [](const string& name, const std::string& policyCode, const std::string& pool) {
     setLuaSideEffect();
-    auto localPools = g_pools.getCopy();
-    setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policyCode}));
-    g_pools.setState(localPools);
+    setPoolPolicy(pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policyCode}));
   });
 
   luaCtx.writeFunction("showPoolServerPolicy", [](const std::string& pool) {
     setLuaSideEffect();
-    auto localPools = g_pools.getCopy();
-    auto poolObj = getPool(localPools, pool);
+    auto poolObj = getPool(pool);
     if (poolObj->policy == nullptr) {
-      g_outputBuffer = g_policy.getLocal()->getName() + "\n";
+      g_outputBuffer = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() + "\n";
     }
     else {
       g_outputBuffer = poolObj->policy->getName() + "\n";
@@ -2253,47 +2326,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 #endif /* DISABLE_POLICIES_BINDINGS */
 
-  luaCtx.writeFunction("setTCPDownstreamCleanupInterval", [](uint64_t interval) {
-    setLuaSideEffect();
-    checkParameterBound("setTCPDownstreamCleanupInterval", interval);
-    setTCPDownstreamCleanupInterval(interval);
-  });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
-  luaCtx.writeFunction("setDoHDownstreamCleanupInterval", [](uint64_t interval) {
-    setLuaSideEffect();
-    checkParameterBound("setDoHDownstreamCleanupInterval", interval);
-    setDoHDownstreamCleanupInterval(interval);
-  });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
-  luaCtx.writeFunction("setTCPDownstreamMaxIdleTime", [](uint64_t max) {
-    setLuaSideEffect();
-    checkParameterBound("setTCPDownstreamMaxIdleTime", max);
-    setTCPDownstreamMaxIdleTime(max);
-  });
-
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
-  luaCtx.writeFunction("setDoHDownstreamMaxIdleTime", [](uint64_t max) {
-    setLuaSideEffect();
-    checkParameterBound("setDoHDownstreamMaxIdleTime", max);
-    setDoHDownstreamMaxIdleTime(max);
-  });
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-
-  luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
-    g_logConsoleConnections = enabled;
-  });
-
-  luaCtx.writeFunction("setConsoleOutputMaxMsgSize", [](uint64_t size) {
-    checkParameterBound("setConsoleOutputMaxMsgSize", size, std::numeric_limits<uint32_t>::max());
-    g_consoleOutputMsgMaxSize = size;
-  });
-
   luaCtx.writeFunction("setProxyProtocolACL", [](LuaTypeOrArrayOf<std::string> inp) {
-    if (!checkConfigurationTime("setProxyProtocolACL")) {
-      return;
-    }
     setLuaSideEffect();
     NetmaskGroup nmg;
     if (auto* str = boost::get<string>(&inp)) {
@@ -2304,56 +2337,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         nmg.addMask(entry.second);
       }
     }
-    g_proxyProtocolACL = std::move(nmg);
-  });
-
-  luaCtx.writeFunction("setProxyProtocolApplyACLToProxiedClients", [](bool apply) {
-    if (!checkConfigurationTime("setProxyProtocolApplyACLToProxiedClients")) {
-      return;
-    }
-    setLuaSideEffect();
-    g_applyACLToProxiedClients = apply;
-  });
-
-  luaCtx.writeFunction("setProxyProtocolMaximumPayloadSize", [](uint64_t size) {
-    if (!checkConfigurationTime("setProxyProtocolMaximumPayloadSize")) {
-      return;
-    }
-    setLuaSideEffect();
-    g_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), size);
-  });
-
-#ifndef DISABLE_RECVMMSG
-  luaCtx.writeFunction("setUDPMultipleMessagesVectorSize", [](uint64_t vSize) {
-    if (!checkConfigurationTime("setUDPMultipleMessagesVectorSize")) {
-      return;
-    }
-#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-    setLuaSideEffect();
-    g_udpVectorSize = vSize;
-#else
-      errlog("recvmmsg() support is not available!");
-      g_outputBuffer = "recvmmsg support is not available!\n";
-#endif
-  });
-#endif /* DISABLE_RECVMMSG */
-
-  luaCtx.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
-    g_addEDNSToSelfGeneratedResponses = add;
-  });
-
-  luaCtx.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint64_t payloadSize) {
-    if (payloadSize < 512) {
-      warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
-      g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
-      payloadSize = 512;
-    }
-    if (payloadSize > s_udpIncomingBufferSize) {
-      warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", s_udpIncomingBufferSize);
-      g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(s_udpIncomingBufferSize) + " instead";
-      payloadSize = s_udpIncomingBufferSize;
-    }
-    g_PayloadSizeSelfGenAnswers = payloadSize;
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL = std::move(nmg);
+    });
   });
 
 #ifndef DISABLE_SECPOLL
@@ -2361,22 +2347,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     setLuaNoSideEffect();
     g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
   });
-
-  luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
-    if (!checkConfigurationTime("setSecurityPollSuffix")) {
-      return;
-    }
-    g_secPollSuffix = suffix;
-  });
-
-  luaCtx.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
-    if (newInterval <= 0) {
-      warnlog("setSecurityPollInterval() should be > 0, skipping");
-      g_outputBuffer = "setSecurityPollInterval() should be > 0, skipping";
-    }
-
-    g_secPollInterval = newInterval;
-  });
 #endif /* DISABLE_SECPOLL */
 
   luaCtx.writeFunction("setSyslogFacility", [](boost::variant<int, std::string> facility) {
@@ -2464,7 +2434,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     return result;
   });
 
-  luaCtx.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>> certFiles, boost::optional<boost::variant<std::string, LuaArray<std::string>>> keyFiles, boost::optional<LuaTypeOrArrayOf<std::string>> urls, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addDOHLocal", [client](const std::string& addr, boost::optional<boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>> certFiles, boost::optional<LuaTypeOrArrayOf<std::string>> keyFiles, boost::optional<LuaTypeOrArrayOf<std::string>> urls, boost::optional<localbind_t> vars) {
     if (client) {
       return;
     }
@@ -2612,8 +2582,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       }
     }
 
-    g_dohlocals.push_back(frontend);
-    auto clientState = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+    auto clientState = std::make_shared<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
     clientState->dohFrontend = std::move(frontend);
     clientState->d_additionalAddresses = std::move(additionalAddresses);
 
@@ -2623,14 +2592,17 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (tcpMaxConcurrentConnections > 0) {
       clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
     }
-    g_frontends.push_back(std::move(clientState));
+
+    dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+      config.d_frontends.push_back(std::move(clientState));
+    });
 #else /* HAVE_DNS_OVER_HTTPS */
       throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
 #endif /* HAVE_DNS_OVER_HTTPS */
   });
 
   // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
-  luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles, boost::optional<localbind_t> vars) {
     if (client) {
       return;
     }
@@ -2693,19 +2665,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
       checkAllParametersConsumed("addDOH3Local", vars);
     }
-    g_doh3locals.push_back(frontend);
-    auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+
+    auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
     clientState->doh3Frontend = frontend;
     clientState->d_additionalAddresses = std::move(additionalAddresses);
 
-    g_frontends.push_back(std::move(clientState));
+    dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+      config.d_frontends.push_back(std::move(clientState));
+    });
 #else
       throw std::runtime_error("addDOH3Local() called but DNS over HTTP/3 support is not present!");
 #endif
   });
 
   // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
-  luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+  luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles, boost::optional<localbind_t> vars) {
     if (client) {
       return;
     }
@@ -2768,12 +2742,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
       checkAllParametersConsumed("addDOQLocal", vars);
     }
-    g_doqlocals.push_back(frontend);
-    auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+
+    auto clientState = std::make_shared<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
     clientState->doqFrontend = std::move(frontend);
     clientState->d_additionalAddresses = std::move(additionalAddresses);
 
-    g_frontends.push_back(std::move(clientState));
+    dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+      config.d_frontends.push_back(std::move(clientState));
+    });
 #else
       throw std::runtime_error("addDOQLocal() called but DNS over QUIC support is not present!");
 #endif
@@ -2787,7 +2763,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
       ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
       size_t counter = 0;
-      for (const auto& ctx : g_doqlocals) {
+      for (const auto& ctx : dnsdist::getDoQFrontends()) {
         ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doqUnsupportedVersionErrors % ctx->d_doqInvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
         counter++;
       }
@@ -2810,12 +2786,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
     setLuaNoSideEffect();
     try {
-      if (index < g_doqlocals.size()) {
-        result = g_doqlocals.at(index);
+      auto doqFrontends = dnsdist::getDoQFrontends();
+      if (index < doqFrontends.size()) {
+        result = doqFrontends.at(index);
       }
       else {
-        errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, g_doqlocals.size());
-        g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doqlocals.size()) + " frontend(s)\n";
+        errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, doqFrontends.size());
+        g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(doqFrontends.size()) + " frontend(s)\n";
       }
     }
     catch (const std::exception& e) {
@@ -2827,7 +2804,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getDOQFrontendCount", []() {
     setLuaNoSideEffect();
-    return g_doqlocals.size();
+    return dnsdist::getDoQFrontends().size();
   });
 
   luaCtx.registerFunction<void (std::shared_ptr<DOQFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOQFrontend>& frontend) {
@@ -2845,7 +2822,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
       ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
       size_t counter = 0;
-      for (const auto& ctx : g_dohlocals) {
+      for (const auto& ctx : dnsdist::getDoHFrontends()) {
         ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http2Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
         counter++;
       }
@@ -2868,7 +2845,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
       ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
       size_t counter = 0;
-      for (const auto& ctx : g_doh3locals) {
+      for (const auto& ctx : dnsdist::getDoH3Frontends()) {
         ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doh3UnsupportedVersionErrors % ctx->d_doh3InvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
         counter++;
       }
@@ -2891,12 +2868,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
     setLuaNoSideEffect();
     try {
-      if (index < g_doh3locals.size()) {
-        result = g_doh3locals.at(index);
+      auto doh3Frontends = dnsdist::getDoH3Frontends();
+      if (index < doh3Frontends.size()) {
+        result = doh3Frontends.at(index);
       }
       else {
-        errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, g_doh3locals.size());
-        g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doh3locals.size()) + " frontend(s)\n";
+        errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, doh3Frontends.size());
+        g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(doh3Frontends.size()) + " frontend(s)\n";
       }
     }
     catch (const std::exception& e) {
@@ -2908,7 +2886,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getDOH3FrontendCount", []() {
     setLuaNoSideEffect();
-    return g_doh3locals.size();
+    return dnsdist::getDoH3Frontends().size();
   });
 
   luaCtx.registerFunction<void (std::shared_ptr<DOH3Frontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOH3Frontend>& frontend) {
@@ -2927,7 +2905,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       g_outputBuffer = "\n- HTTP/1:\n\n";
       ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
       size_t counter = 0;
-      for (const auto& ctx : g_dohlocals) {
+      for (const auto& ctx : dnsdist::getDoHFrontends()) {
         ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
         counter++;
       }
@@ -2937,7 +2915,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       g_outputBuffer += "\n- HTTP/2:\n\n";
       ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
       counter = 0;
-      for (const auto& ctx : g_dohlocals) {
+      for (const auto& ctx : dnsdist::getDoHFrontends()) {
         ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
         counter++;
       }
@@ -2960,12 +2938,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_DNS_OVER_HTTPS
     setLuaNoSideEffect();
     try {
-      if (index < g_dohlocals.size()) {
-        result = g_dohlocals.at(index);
+      auto dohFrontends = dnsdist::getDoHFrontends();
+      if (index < dohFrontends.size()) {
+        result = dohFrontends.at(index);
       }
       else {
-        errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, g_dohlocals.size());
-        g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
+        errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, dohFrontends.size());
+        g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(dohFrontends.size()) + " frontend(s)\n";
       }
     }
     catch (const std::exception& e) {
@@ -2980,7 +2959,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getDOHFrontendCount", []() {
     setLuaNoSideEffect();
-    return g_dohlocals.size();
+    return dnsdist::getDoHFrontends().size();
   });
 
   luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOHFrontend>& frontend) {
@@ -2989,7 +2968,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles)>("loadNewCertificatesAndKeys", [](const std::shared_ptr<DOHFrontend>& frontend, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles) {
+  luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, LuaTypeOrArrayOf<std::string> keyFiles)>("loadNewCertificatesAndKeys", [](const std::shared_ptr<DOHFrontend>& frontend, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles) {
 #ifdef HAVE_DNS_OVER_HTTPS
     if (frontend != nullptr) {
       if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
@@ -3103,7 +3082,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         vinfolog("Loading default TLS provider '%s'", provider);
       }
       // only works pre-startup, so no sync necessary
-      auto clientState = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+      auto clientState = std::make_shared<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
       clientState->tlsFrontend = frontend;
       clientState->d_additionalAddresses = std::move(additionalAddresses);
       if (tcpListenQueueSize > 0) {
@@ -3116,8 +3095,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
       }
 
-      g_tlslocals.push_back(clientState->tlsFrontend);
-      g_frontends.push_back(std::move(clientState));
+      dnsdist::configuration::updateImmutableConfiguration([&clientState](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_frontends.push_back(std::move(clientState));
+      });
     }
     catch (const std::exception& e) {
       g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -3136,7 +3116,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       //             1    2           3                 4                  5
       ret << (fmt % "#" % "Address" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
       size_t counter = 0;
-      for (const auto& ctx : g_tlslocals) {
+      for (const auto& ctx : dnsdist::getDoTFrontends()) {
         ret << (fmt % counter % ctx->d_addr.toStringWithPort() % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
         counter++;
       }
@@ -3155,13 +3135,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     std::shared_ptr<TLSCtx> result = nullptr;
 #ifdef HAVE_DNS_OVER_TLS
     setLuaNoSideEffect();
+    const auto tlsFrontends = dnsdist::getDoTFrontends();
     try {
-      if (index < g_tlslocals.size()) {
-        result = g_tlslocals.at(index)->getContext();
+      if (index < tlsFrontends.size()) {
+        result = tlsFrontends.at(index)->getContext();
       }
       else {
-        errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, g_tlslocals.size());
-        g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
+        errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, tlsFrontends.size());
+        g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(tlsFrontends.size()) + " context(s)\n";
       }
     }
     catch (const std::exception& e) {
@@ -3179,12 +3160,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_DNS_OVER_TLS
     setLuaNoSideEffect();
     try {
-      if (index < g_tlslocals.size()) {
-        result = g_tlslocals.at(index);
+      auto tlsFrontends = dnsdist::getDoTFrontends();
+      if (index < tlsFrontends.size()) {
+        result = tlsFrontends.at(index);
       }
       else {
-        errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, g_tlslocals.size());
-        g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
+        errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, tlsFrontends.size());
+        g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(tlsFrontends.size()) + " frontend(s)\n";
       }
     }
     catch (const std::exception& e) {
@@ -3199,7 +3181,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getTLSFrontendCount", []() {
     setLuaNoSideEffect();
-    return g_tlslocals.size();
+    return dnsdist::getDoTFrontends().size();
   });
 
   luaCtx.registerFunction<void (std::shared_ptr<TLSCtx>::*)()>("rotateTicketsKey", [](std::shared_ptr<TLSCtx>& ctx) {
@@ -3257,7 +3239,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 
   luaCtx.writeFunction("reloadAllCertificates", []() {
-    for (auto& frontend : g_frontends) {
+    for (const auto& frontend : dnsdist::getFrontends()) {
       if (!frontend) {
         continue;
       }
@@ -3294,9 +3276,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse = allow; });
-  luaCtx.writeFunction("setDropEmptyQueries", [](bool drop) { extern bool g_dropEmptyQueries; g_dropEmptyQueries = drop; });
-
 #if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN) && !defined(DISABLE_OCSP_STAPLING)
   luaCtx.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
     if (client) {
@@ -3308,17 +3287,22 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif /* HAVE_LIBSSL && HAVE_OCSP_BASIC_SIGN && !DISABLE_OCSP_STAPLING */
 
   luaCtx.writeFunction("addCapabilitiesToRetain", [](LuaTypeOrArrayOf<std::string> caps) {
-    if (!checkConfigurationTime("addCapabilitiesToRetain")) {
-      return;
-    }
-    setLuaSideEffect();
-    if (caps.type() == typeid(std::string)) {
-      g_capabilitiesToRetain.insert(boost::get<std::string>(caps));
+    try {
+      dnsdist::configuration::updateImmutableConfiguration([&caps](dnsdist::configuration::ImmutableConfiguration& config) {
+        if (caps.type() == typeid(std::string)) {
+          config.d_capabilitiesToRetain.insert(boost::get<std::string>(caps));
+        }
+        else if (caps.type() == typeid(LuaArray<std::string>)) {
+          for (const auto& cap : boost::get<LuaArray<std::string>>(caps)) {
+            config.d_capabilitiesToRetain.insert(cap.second);
+          }
+        }
+      });
+      setLuaSideEffect();
     }
-    else if (caps.type() == typeid(LuaArray<std::string>)) {
-      for (const auto& cap : boost::get<LuaArray<std::string>>(caps)) {
-        g_capabilitiesToRetain.insert(cap.second);
-      }
+    catch (const std::exception& exp) {
+      g_outputBuffer = "addCapabilitiesToRetain cannot be used at runtime!\n";
+      errlog("addCapabilitiesToRetain cannot be used at runtime!");
     }
   });
 
@@ -3326,23 +3310,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (client) {
       return;
     }
-    if (!checkConfigurationTime("setUDPSocketBufferSizes")) {
-      return;
-    }
     checkParameterBound("setUDPSocketBufferSizes", recv, std::numeric_limits<uint32_t>::max());
     checkParameterBound("setUDPSocketBufferSizes", snd, std::numeric_limits<uint32_t>::max());
-    setLuaSideEffect();
 
-    g_socketUDPSendBuffer = snd;
-    g_socketUDPRecvBuffer = recv;
-  });
-
-  luaCtx.writeFunction("setRandomizedOutgoingSockets", [](bool randomized) {
-    DownstreamState::s_randomizeSockets = randomized;
-  });
-
-  luaCtx.writeFunction("setRandomizedIdsOverUDP", [](bool randomized) {
-    DownstreamState::s_randomizeIDs = randomized;
+    try {
+      dnsdist::configuration::updateImmutableConfiguration([snd, recv](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_socketUDPSendBuffer = snd;
+        config.d_socketUDPRecvBuffer = recv;
+      });
+      setLuaSideEffect();
+    }
+    catch (const std::exception& exp) {
+      g_outputBuffer = "setUDPSocketBufferSizes cannot be used at runtime!\n";
+      errlog("setUDPSocketBufferSizes cannot be used at runtime!");
+    }
   });
 
 #if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
@@ -3429,12 +3410,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 }
 
-vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
+void setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
 {
-  // this needs to exist only during the parsing of the configuration
-  // and cannot be captured by lambdas
-  g_launchWork = std::vector<std::function<void(void)>>();
-
   setupLuaActions(luaCtx);
   setupLuaConfig(luaCtx, client, configCheck);
   setupLuaBindings(luaCtx, client, configCheck);
@@ -3442,6 +3419,7 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
   setupLuaBindingsDNSParser(luaCtx);
   setupLuaBindingsDNSQuestion(luaCtx);
   setupLuaBindingsKVS(luaCtx, client);
+  setupLuaBindingsLogging(luaCtx);
   setupLuaBindingsNetwork(luaCtx, client);
   setupLuaBindingsPacketCache(luaCtx, client);
   setupLuaBindingsProtoBuf(luaCtx, client, configCheck);
@@ -3468,8 +3446,4 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
   }
 
   luaCtx.executeCode(ifs);
-
-  auto ret = *g_launchWork;
-  g_launchWork = boost::none;
-  return ret;
 }
index 8a6363300a5c13689aff273e203d7715788b5d2b..e2be6dca1e806d104a4765f2c19d8374ffab0ec4 100644 (file)
  */
 #pragma once
 
+#include <random>
+
 #include "dolog.hh"
 #include "dnsdist.hh"
+#include "dnsdist-dnsparser.hh"
 #include "dnsparser.hh"
-#include <random>
 
-struct ResponseConfig
-{
-  boost::optional<bool> setAA{boost::none};
-  boost::optional<bool> setAD{boost::none};
-  boost::optional<bool> setRA{boost::none};
-  uint32_t ttl{60};
-};
-void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config);
+#include "ext/luawrapper/include/LuaContext.hpp"
+
+extern RecursiveLockGuarded<LuaContext> g_lua;
+extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
 
 class SpoofAction : public DNSAction
 {
@@ -88,13 +86,13 @@ public:
     return ret;
   }
 
-  [[nodiscard]] ResponseConfig& getResponseConfig()
+  [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
   {
     return d_responseConfig;
   }
 
 private:
-  ResponseConfig d_responseConfig;
+  dnsdist::ResponseConfig d_responseConfig;
   static thread_local std::default_random_engine t_randomEngine;
   std::vector<ComboAddress> d_addrs;
   std::unordered_set<uint16_t> d_types;
@@ -170,7 +168,6 @@ template <class T>
 using LuaTypeOrArrayOf = boost::variant<T, LuaArray<T>>;
 
 using luaruleparams_t = LuaAssociativeTable<std::string>;
-using nmts_t = NetmaskTree<DynBlock, AddressAndPortRange>;
 
 using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
 std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom);
@@ -178,13 +175,14 @@ std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& ca
 void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder);
 void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max());
 
-vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
+void setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
 void setupLuaActions(LuaContext& luaCtx);
 void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck);
 void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client);
 void setupLuaBindingsDNSParser(LuaContext& luaCtx);
 void setupLuaBindingsDNSQuestion(LuaContext& luaCtx);
 void setupLuaBindingsKVS(LuaContext& luaCtx, bool client);
+void setupLuaBindingsLogging(LuaContext& luaCtx);
 void setupLuaBindingsNetwork(LuaContext& luaCtx, bool client);
 void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client);
 void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck);
index d47236ea8b60aca39a96f6379ab0f8c516735985..89f13bef65dba4563a3ac5954ba9c51379d75806 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "dnsdist-metrics.hh"
 #include "dnsdist.hh"
+#include "dnsdist-dynblocks.hh"
 #include "dnsdist-web.hh"
 
 namespace dnsdist::metrics
@@ -63,7 +64,7 @@ struct MutableGauge
   }
   ~MutableGauge() = default;
 
-  mutable pdns::stat_t_trait<double> d_value{0};
+  mutable pdns::stat_double_t d_value{0};
 };
 
 static SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> s_customCounters;
@@ -145,7 +146,9 @@ Stats::Stats() :
     {"cpu-user-msec", getCPUTimeUser},
     {"fd-usage", getOpenFileDescriptors},
     {"dyn-blocked", &dynBlocked},
-    {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
+#ifndef DISABLE_DYNBLOCKS
+    {"dyn-block-nmg-size", [](const std::string&) { return dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(); }},
+#endif /* DISABLE_DYNBLOCKS */
     {"security-status", &securityStatus},
     {"doh-query-pipe-full", &dohQueryPipeFull},
     {"doh-response-pipe-full", &dohResponsePipeFull},
@@ -177,7 +180,7 @@ std::optional<std::string> declareCustomMetric(const std::string& name, const st
     if (itp.second) {
       g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customCounters)[name].d_value});
       dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
-      addMetricDefinition(def);
+      dnsdist::webserver::addMetricDefinition(def);
     }
   }
   else if (type == "gauge") {
@@ -186,7 +189,7 @@ std::optional<std::string> declareCustomMetric(const std::string& name, const st
     if (itp.second) {
       g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customGauges)[name].d_value});
       dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
-      addMetricDefinition(def);
+      dnsdist::webserver::addMetricDefinition(def);
     }
   }
   else {
index 8e899cedeafa76c4e5c5521838ef4b8491b5d97e..47a3fb84078bb1798606d4ca4667c471e1c51224 100644 (file)
@@ -81,14 +81,14 @@ struct Stats
   stat_t tcpQueryPipeFull{0};
   stat_t tcpCrossProtocolQueryPipeFull{0};
   stat_t tcpCrossProtocolResponsePipeFull{0};
-  double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
-  double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
-  double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
-  double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
-  double latencyDoQAvg100{0}, latencyDoQAvg1000{0}, latencyDoQAvg10000{0}, latencyDoQAvg1000000{0};
-  double latencyDoH3Avg100{0}, latencyDoH3Avg1000{0}, latencyDoH3Avg10000{0}, latencyDoH3Avg1000000{0};
+  pdns::stat_double_t latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
+  pdns::stat_double_t latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
+  pdns::stat_double_t latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
+  pdns::stat_double_t latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
+  pdns::stat_double_t latencyDoQAvg100{0}, latencyDoQAvg1000{0}, latencyDoQAvg10000{0}, latencyDoQAvg1000000{0};
+  pdns::stat_double_t latencyDoH3Avg100{0}, latencyDoH3Avg1000{0}, latencyDoH3Avg10000{0}, latencyDoH3Avg1000000{0};
   using statfunction_t = std::function<uint64_t(const std::string&)>;
-  using entry_t = std::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
+  using entry_t = std::variant<stat_t*, pdns::stat_double_t*, statfunction_t>;
   struct EntryPair
   {
     std::string d_name;
index 797def327e56104f3febed829418aa9703dbcc88..9907938dae43651e2966c37a7323b61c6980e417 100644 (file)
@@ -362,7 +362,7 @@ void IncomingHTTP2Connection::handleIO()
   gettimeofday(&now, nullptr);
 
   try {
-    if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+    if (maxConnectionDurationReached(dnsdist::configuration::getCurrentRuntimeConfiguration().d_maxTCPConnectionDuration, now)) {
       vinfolog("Terminating DoH connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
       stopIO();
       d_connectionClosing = true;
@@ -401,9 +401,6 @@ void IncomingHTTP2Connection::handleIO()
           }
         }
         else {
-          d_currentPos = 0;
-          d_proxyProtocolNeed = 0;
-          d_buffer.clear();
           d_state = State::waitingForQuery;
           handleConnectionReady();
         }
@@ -805,8 +802,7 @@ void IncomingHTTP2Connection::handleIncomingQuery(IncomingHTTP2Connection::Pendi
     processForwardedForHeader(query.d_headers, d_proxiedRemote);
 
     /* second ACL lookup based on the updated address */
-    auto& holders = d_threadData.holders;
-    if (!holders.acl->match(d_proxiedRemote)) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(d_proxiedRemote)) {
       ++dnsdist::metrics::g_stats.aclDrops;
       vinfolog("Query from %s (%s) (DoH) dropped because of ACL", d_ci.remote.toStringWithPort(), d_proxiedRemote.toStringWithPort());
       handleImmediateResponse(403, "DoH query not allowed because of ACL");
@@ -1154,17 +1150,18 @@ uint32_t IncomingHTTP2Connection::getConcurrentStreamsCount() const
 
 boost::optional<struct timeval> IncomingHTTP2Connection::getIdleClientReadTTD(struct timeval now) const
 {
+  const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
   auto idleTimeout = d_ci.cs->dohFrontend->d_idleTimeout;
-  if (g_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
+  if (currentConfig.d_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
     return boost::none;
   }
 
-  if (g_maxTCPConnectionDuration > 0) {
+  if (currentConfig.d_maxTCPConnectionDuration > 0) {
     auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
-    if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+    if (elapsed < 0 || (static_cast<size_t>(elapsed) >= currentConfig.d_maxTCPConnectionDuration)) {
       return now;
     }
-    auto remaining = g_maxTCPConnectionDuration - elapsed;
+    auto remaining = currentConfig.d_maxTCPConnectionDuration - elapsed;
     if (idleTimeout == 0 || remaining <= static_cast<size_t>(idleTimeout)) {
       now.tv_sec += static_cast<time_t>(remaining);
       return now;
index 68d4f92962e2fbfb016997fb5b3b0b7ba73e35f5..e42ff741af75a0d8542d94377d17fba72af4d670 100644 (file)
@@ -43,7 +43,6 @@
 
 std::atomic<uint64_t> g_dohStatesDumpRequested{0};
 std::unique_ptr<DoHClientCollection> g_dohClientThreads{nullptr};
-std::optional<uint16_t> g_outgoingDoHWorkerThreads{std::nullopt};
 
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
 class DoHConnectionToBackend : public ConnectionToBackend
@@ -923,16 +922,6 @@ static void dohClientThread(pdns::channel::Receiver<CrossProtocolQuery>&& receiv
     errlog("Fatal error in outgoing DoH thread: %s", e.what());
   }
 }
-
-static bool select_next_proto_callback(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen)
-{
-  if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
-    vinfolog("The remote DoH backend did not advertise " NGHTTP2_PROTO_VERSION_ID);
-    return false;
-  }
-  return true;
-}
-
 #endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
 
 struct DoHClientCollection::DoHWorkerThread
@@ -987,7 +976,8 @@ void DoHClientCollection::addThread()
 {
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
   try {
-    auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
+    auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
     vinfolog("Adding DoH Client thread");
     std::lock_guard<std::mutex> lock(d_mutex);
@@ -1023,15 +1013,16 @@ void DoHClientCollection::addThread()
 bool initDoHWorkers()
 {
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
-  if (!g_outgoingDoHWorkerThreads) {
+  auto outgoingDoHWorkerThreads = dnsdist::configuration::getImmutableConfiguration().d_outgoingDoHWorkers;
+  if (!outgoingDoHWorkerThreads) {
     /* Unless the value has been set to 0 explicitly, always start at least one outgoing DoH worker thread, in case a DoH backend
        is added at a later time. */
-    g_outgoingDoHWorkerThreads = 1;
+    outgoingDoHWorkerThreads = 1;
   }
 
-  if (g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads > 0) {
-    g_dohClientThreads = std::make_unique<DoHClientCollection>(*g_outgoingDoHWorkerThreads);
-    for (size_t idx = 0; idx < *g_outgoingDoHWorkerThreads; idx++) {
+  if (outgoingDoHWorkerThreads && *outgoingDoHWorkerThreads > 0) {
+    g_dohClientThreads = std::make_unique<DoHClientCollection>(*outgoingDoHWorkerThreads);
+    for (size_t idx = 0; idx < *outgoingDoHWorkerThreads; idx++) {
       g_dohClientThreads->addThread();
     }
   }
@@ -1041,22 +1032,6 @@ bool initDoHWorkers()
 #endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
 }
 
-bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
-  if (ctx == nullptr) {
-    return false;
-  }
-#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
-  /* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */
-  const std::vector<std::vector<uint8_t>> h2Alpns = {{'h', '2'}};
-  ctx->setALPNProtos(h2Alpns);
-  ctx->setNextProtocolSelectCallback(select_next_proto_callback);
-  return true;
-#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-  return false;
-#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
-}
-
 bool sendH2Query(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, std::shared_ptr<TCPQuerySender>& sender, InternalQuery&& query, bool healthCheck)
 {
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
index 6e38f28cc383f1c12d76b5821b59414a7c118fe2..043b4977e1efe352f5bbccdda4164bdc5bc708df 100644 (file)
@@ -57,12 +57,10 @@ private:
 
 extern std::unique_ptr<DoHClientCollection> g_dohClientThreads;
 extern std::atomic<uint64_t> g_dohStatesDumpRequested;
-extern std::optional<uint16_t> g_outgoingDoHWorkerThreads;
 
 class TLSCtx;
 
 bool initDoHWorkers();
-bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx);
 
 /* opens a new HTTP/2 connection to the supplied backend (attached to the supplied multiplexer), sends the query,
    waits for the response to come back or an error to occur then notifies the sender, closing the connection. */
index d19e87206e2f47249a97f4ec6e6a3efda17d2a5e..01056b1d5a4398d5f7db8f73c02fde39540a7636 100644 (file)
  */
 
 #include "dnsdist-proxy-protocol.hh"
+
+#include "dnsdist.hh"
 #include "dnsdist-metrics.hh"
 #include "dolog.hh"
 
-NetmaskGroup g_proxyProtocolACL;
-size_t g_proxyProtocolMaximumSize = 512;
-bool g_applyACLToProxiedClients = false;
-
 std::string getProxyProtocolPayload(const DNSQuestion& dq)
 {
   return makeProxyHeader(dq.overTCP(), dq.ids.origRemote, dq.ids.origDest, dq.proxyProtocolValues ? *dq.proxyProtocolValues : std::vector<ProxyProtocolValue>());
@@ -72,7 +70,7 @@ bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source
 
 bool expectProxyProtocolFrom(const ComboAddress& remote)
 {
-  return g_proxyProtocolACL.match(remote);
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolACL.match(remote);
 }
 
 bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGroup& acl, PacketBuffer& query, ComboAddress& realRemote, ComboAddress& realDestination, std::vector<ProxyProtocolValue>& values)
@@ -86,7 +84,7 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
     vinfolog("Ignoring invalid proxy protocol (%d, %d) query over %s from %s", query.size(), used, (isTCP ? "TCP" : "UDP"), remote.toStringWithPort());
     return false;
   }
-  else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
+  if (static_cast<size_t>(used) > dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolMaximumSize) {
     vinfolog("Proxy protocol header in %s packet from %s is larger than proxy-protocol-maximum-size (%d), dropping", (isTCP ? "TCP" : "UDP"), remote.toStringWithPort(), used);
     ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
     return false;
@@ -100,7 +98,7 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
     return false;
   }
 
-  if (proxyProto && g_applyACLToProxiedClients) {
+  if (proxyProto && dnsdist::configuration::getCurrentRuntimeConfiguration().d_applyACLToProxiedClients) {
     if (!acl.match(realRemote)) {
       vinfolog("Query from %s dropped because of ACL", realRemote.toStringWithPort());
       ++dnsdist::metrics::g_stats.aclDrops;
index de7674a2dbaa27069bf0f79b32db85f62d6f3fd4..6e4234d6be531c2a62161ae8060978a7d095aa80 100644 (file)
  */
 #pragma once
 
-#include "dnsdist.hh"
+#include <string>
 
-extern NetmaskGroup g_proxyProtocolACL;
-extern size_t g_proxyProtocolMaximumSize;
-extern bool g_applyACLToProxiedClients;
+#include "iputils.hh"
+#include "noinitvector.hh"
+#include "proxy-protocol.hh"
+
+struct DNSQuestion;
 
 std::string getProxyProtocolPayload(const DNSQuestion& dq);
 
diff --git a/pdns/dnsdistdist/dnsdist-query-count.cc b/pdns/dnsdistdist/dnsdist-query-count.cc
new file mode 100644 (file)
index 0000000..8387f28
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-query-count.hh"
+
+namespace dnsdist::QueryCount
+{
+SharedLockGuarded<Records> g_queryCountRecords;
+}
similarity index 67%
rename from pdns/pdns_hw.cc
rename to pdns/dnsdistdist/dnsdist-query-count.hh
index 3d8576a771585e7c3a7056b5ea1e748efa53f817..bb9d589cba118111e9cd396d4feb06b8d4a213a6 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/ordered_index.hpp>
-#include <boost/multi_index/key_extractors.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
 
-#include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
+#pragma once
+
+#include <functional>
+#include <unordered_map>
 #include <string>
-#include <sstream>
+#include <tuple>
+
+#include "lock.hh"
+
+struct DNSQuestion;
 
-#include "namespaces.hh"
-int main()
+namespace dnsdist::QueryCount
 {
-        ostringstream str;
-        str << "Everything is ok!"<<"\n"; // FIXME400: boost test?
-        exit(0);
+struct Configuration
+{
+  using Filter = std::function<std::tuple<bool, std::string>(const DNSQuestion* dq)>;
+  Configuration() = default;
+  Filter d_filter;
+  bool d_enabled{false};
+};
+
+using Records = std::unordered_map<std::string, unsigned int>;
+extern SharedLockGuarded<Records> g_queryCountRecords;
 }
index ba55561fede9b4f9bcc7bf6e77ead816ebe56fc2..a25f84cf8697ad2b02879325ed9c9e12dff464de 100644 (file)
 
 #include "dnsdist-rings.hh"
 
-void Rings::setCapacity(size_t newCapacity, size_t numberOfShards)
-{
-  if (d_initialized) {
-    throw std::runtime_error("Rings::setCapacity() should not be called once the rings have been initialized");
-  }
-  d_capacity = newCapacity;
-  d_numberOfShards = numberOfShards;
-}
-
-void Rings::init()
+void Rings::init(size_t capacity, size_t numberOfShards, size_t nbLockRetries, bool recordQueries, bool recordResponses)
 {
   if (d_initialized.exchange(true)) {
     throw std::runtime_error("Rings::init() should only be called once");
   }
 
+  d_capacity = capacity;
+  d_numberOfShards = numberOfShards;
+  d_nbLockTries = nbLockRetries;
+  d_recordQueries = recordQueries;
+  d_recordResponses = recordResponses;
   if (d_numberOfShards <= 1) {
     d_nbLockTries = 0;
   }
@@ -61,26 +57,6 @@ void Rings::init()
   d_nbResponseEntries = 0;
 }
 
-void Rings::setNumberOfLockRetries(size_t retries)
-{
-  if (d_numberOfShards <= 1) {
-    d_nbLockTries = 0;
-  }
-  else {
-    d_nbLockTries = retries;
-  }
-}
-
-void Rings::setRecordQueries(bool record)
-{
-  d_recordQueries = record;
-}
-
-void Rings::setRecordResponses(bool record)
-{
-  d_recordResponses = record;
-}
-
 size_t Rings::numDistinctRequestors()
 {
   std::set<ComboAddress, ComboAddress::addressOnlyLessThan> requestors;
index a98b72110f1bb22b73b5bcc6a1df874f8554c580..91b90e361196fb6ac5f08bd1770ea3af1c928709 100644 (file)
@@ -73,22 +73,11 @@ struct Rings
     LockGuarded<boost::circular_buffer<Response>> respRing;
   };
 
-  Rings(size_t capacity = 10000, size_t numberOfShards = 10, size_t nbLockTries = 5, bool keepLockingStats = false) :
-    d_blockingQueryInserts(0), d_blockingResponseInserts(0), d_deferredQueryInserts(0), d_deferredResponseInserts(0), d_nbQueryEntries(0), d_nbResponseEntries(0), d_currentShardId(0), d_capacity(capacity), d_numberOfShards(numberOfShards), d_nbLockTries(nbLockTries), d_keepLockingStats(keepLockingStats)
-  {
-  }
-
   std::unordered_map<int, vector<boost::variant<string, double>>> getTopBandwidth(unsigned int numentries);
   size_t numDistinctRequestors();
-  /* this function should not be called after init() has been called */
-  void setCapacity(size_t newCapacity, size_t numberOfShards);
 
   /* This function should only be called at configuration time before any query or response has been inserted */
-  void init();
-
-  void setNumberOfLockRetries(size_t retries);
-  void setRecordQueries(bool);
-  void setRecordResponses(bool);
+  void init(size_t capacity, size_t numberOfShards, size_t nbLockRetries = 5, bool recordQueries = true, bool recordResponses = true);
 
   size_t getNumberOfShards() const
   {
@@ -125,13 +114,13 @@ struct Rings
 #endif
         return;
       }
-      if (d_keepLockingStats) {
+      if (s_keepLockingStats) {
         ++d_deferredQueryInserts;
       }
     }
 
     /* out of luck, let's just wait */
-    if (d_keepLockingStats) {
+    if (s_keepLockingStats) {
       ++d_blockingResponseInserts;
     }
     auto& shard = getOneShard();
@@ -152,13 +141,13 @@ struct Rings
         insertResponseLocked(*lock, when, requestor, name, qtype, usec, size, dh, backend, protocol);
         return;
       }
-      if (d_keepLockingStats) {
+      if (s_keepLockingStats) {
         ++d_deferredResponseInserts;
       }
     }
 
     /* out of luck, let's just wait */
-    if (d_keepLockingStats) {
+    if (s_keepLockingStats) {
       ++d_blockingResponseInserts;
     }
     auto& shard = getOneShard();
@@ -204,10 +193,10 @@ struct Rings
   }
 
   std::vector<std::unique_ptr<Shard>> d_shards;
-  pdns::stat_t d_blockingQueryInserts;
-  pdns::stat_t d_blockingResponseInserts;
-  pdns::stat_t d_deferredQueryInserts;
-  pdns::stat_t d_deferredResponseInserts;
+  pdns::stat_t d_blockingQueryInserts{0};
+  pdns::stat_t d_blockingResponseInserts{0};
+  pdns::stat_t d_deferredQueryInserts{0};
+  pdns::stat_t d_deferredResponseInserts{0};
 
 private:
   size_t getShardId()
@@ -248,15 +237,16 @@ private:
     ring.push_back({requestor, backend, name, when, dh, usec, size, qtype, protocol});
   }
 
-  std::atomic<size_t> d_nbQueryEntries;
-  std::atomic<size_t> d_nbResponseEntries;
-  std::atomic<size_t> d_currentShardId;
+  static constexpr bool s_keepLockingStats{false};
+
+  std::atomic<size_t> d_nbQueryEntries{0};
+  std::atomic<size_t> d_nbResponseEntries{0};
+  std::atomic<size_t> d_currentShardId{0};
   std::atomic<bool> d_initialized{false};
 
-  size_t d_capacity;
-  size_t d_numberOfShards;
-  size_t d_nbLockTries = 5;
-  bool d_keepLockingStats{false};
+  size_t d_capacity{10000};
+  size_t d_numberOfShards{10};
+  size_t d_nbLockTries{5};
   bool d_recordQueries{true};
   bool d_recordResponses{true};
 };
index 1c79fd0a24e9920d23dc57579f4d703e21b05769..57e7b74ea06fb23c373c16344c4c6123bfe6eeb5 100644 (file)
 
 namespace dnsdist::rules
 {
-GlobalStateHolder<std::vector<RuleAction>> s_ruleActions;
-GlobalStateHolder<std::vector<RuleAction>> s_cacheMissRuleActions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_respruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_cachehitrespruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_selfansweredrespruleactions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_cacheInsertedRespRuleActions;
-GlobalStateHolder<std::vector<ResponseRuleAction>> s_XFRRespRuleActions;
-
 static const std::vector<ResponseRuleChainDescription> s_responseRuleChains{
-  {"", "response-rules", s_respruleactions},
-  {"CacheHit", "cache-hit-response-rules", s_cachehitrespruleactions},
-  {"CacheInserted", "cache-inserted-response-rules", s_selfansweredrespruleactions},
-  {"SelfAnswered", "self-answered-response-rules", s_cacheInsertedRespRuleActions},
-  {"XFR", "xfr-response-rules", s_XFRRespRuleActions},
+  {"", "response-rules", ResponseRuleChain::ResponseRules},
+  {"CacheHit", "cache-hit-response-rules", ResponseRuleChain::CacheHitResponseRules},
+  {"CacheInserted", "cache-inserted-response-rules", ResponseRuleChain::CacheInsertedResponseRules},
+  {"SelfAnswered", "self-answered-response-rules", ResponseRuleChain::SelfAnsweredResponseRules},
+  {"XFR", "xfr-response-rules", ResponseRuleChain::XFRResponseRules},
 };
 
-const std::vector<ResponseRuleChainDescription>& getResponseRuleChains()
+const std::vector<ResponseRuleChainDescription>& getResponseRuleChainDescriptions()
 {
   return s_responseRuleChains;
 }
 
-GlobalStateHolder<std::vector<ResponseRuleAction>>& getResponseRuleChainHolder(ResponseRuleChain chain)
-{
-  return s_responseRuleChains.at(static_cast<size_t>(chain)).holder;
-}
-
 static const std::vector<RuleChainDescription> s_ruleChains{
-  {"", "rules", s_ruleActions},
-  {"CacheMiss", "cache-miss-rules", s_cacheMissRuleActions},
+  {"", "rules", RuleChain::Rules},
+  {"CacheMiss", "cache-miss-rules", RuleChain::CacheMissRules},
 };
 
-const std::vector<RuleChainDescription>& getRuleChains()
+const std::vector<RuleChainDescription>& getRuleChainDescriptions()
 {
   return s_ruleChains;
 }
 
-GlobalStateHolder<std::vector<RuleAction>>& getRuleChainHolder(RuleChain chain)
+std::vector<RuleAction>& getRuleChain(RuleChains& chains, RuleChain chain)
+{
+  switch (chain) {
+  case RuleChain::Rules:
+    return chains.d_ruleActions;
+  case RuleChain::CacheMissRules:
+    return chains.d_cacheMissRuleActions;
+  }
+
+  throw std::runtime_error("Trying to accept an invalid rule chain");
+}
+
+const std::vector<RuleAction>& getRuleChain(const RuleChains& chains, RuleChain chain)
+{
+  switch (chain) {
+  case RuleChain::Rules:
+    return chains.d_ruleActions;
+  case RuleChain::CacheMissRules:
+    return chains.d_cacheMissRuleActions;
+  }
+
+  throw std::runtime_error("Trying to accept an invalid rule chain");
+}
+
+std::vector<ResponseRuleAction>& getRuleChain(RuleChains& chains, ResponseRuleChain chain)
+{
+  return getResponseRuleChain(chains, chain);
+}
+
+const std::vector<ResponseRuleAction>& getRuleChain(const RuleChains& chains, ResponseRuleChain chain)
 {
-  return s_ruleChains.at(static_cast<size_t>(chain)).holder;
+  return getResponseRuleChain(chains, chain);
 }
+
+std::vector<ResponseRuleAction>& getResponseRuleChain(RuleChains& chains, ResponseRuleChain chain)
+{
+  switch (chain) {
+  case ResponseRuleChain::ResponseRules:
+    return chains.d_respruleactions;
+  case ResponseRuleChain::CacheHitResponseRules:
+    return chains.d_cachehitrespruleactions;
+  case ResponseRuleChain::CacheInsertedResponseRules:
+    return chains.d_cacheInsertedRespRuleActions;
+  case ResponseRuleChain::SelfAnsweredResponseRules:
+    return chains.d_selfansweredrespruleactions;
+  case ResponseRuleChain::XFRResponseRules:
+    return chains.d_XFRRespRuleActions;
+  }
+
+  throw std::runtime_error("Trying to accept an invalid response rule chain");
+}
+
+const std::vector<ResponseRuleAction>& getResponseRuleChain(const RuleChains& chains, ResponseRuleChain chain)
+{
+  switch (chain) {
+  case ResponseRuleChain::ResponseRules:
+    return chains.d_respruleactions;
+  case ResponseRuleChain::CacheHitResponseRules:
+    return chains.d_cachehitrespruleactions;
+  case ResponseRuleChain::CacheInsertedResponseRules:
+    return chains.d_cacheInsertedRespRuleActions;
+  case ResponseRuleChain::SelfAnsweredResponseRules:
+    return chains.d_selfansweredrespruleactions;
+  case ResponseRuleChain::XFRResponseRules:
+    return chains.d_XFRRespRuleActions;
+  }
+
+  throw std::runtime_error("Trying to accept an invalid response rule chain");
+}
+
+void add(RuleChains& chains, RuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder)
+{
+  auto& chain = getRuleChain(chains, identifier);
+  chain.push_back({selector, action, std::move(name), uuid, creationOrder});
+}
+
+void add(RuleChains& chains, ResponseRuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSResponseAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder)
+{
+  auto& chain = getResponseRuleChain(chains, identifier);
+  chain.push_back({selector, action, std::move(name), uuid, creationOrder});
+}
+
 }
index 5d2220cdd5651b92e336be72f6a51c17ebc245a3..47657635ca00eaf058562412b9f425d9db0ded9a 100644 (file)
@@ -25,7 +25,6 @@
 #include <string>
 #include <vector>
 
-#include "sholder.hh"
 #include "uuid-utils.hh"
 
 class DNSRule;
@@ -43,21 +42,18 @@ struct RuleAction
   uint64_t d_creationOrder;
 };
 
-struct RuleChainDescription
-{
-  std::string prefix;
-  std::string metricName;
-  GlobalStateHolder<std::vector<RuleAction>>& holder;
-};
-
 enum class RuleChain : uint8_t
 {
   Rules = 0,
   CacheMissRules = 1,
 };
 
-const std::vector<RuleChainDescription>& getRuleChains();
-GlobalStateHolder<std::vector<RuleAction>>& getRuleChainHolder(RuleChain chain);
+struct RuleChainDescription
+{
+  const std::string prefix;
+  const std::string metricName;
+  const RuleChain identifier;
+};
 
 struct ResponseRuleAction
 {
@@ -79,12 +75,30 @@ enum class ResponseRuleChain : uint8_t
 
 struct ResponseRuleChainDescription
 {
-  std::string prefix;
-  std::string metricName;
-  GlobalStateHolder<std::vector<ResponseRuleAction>>& holder;
+  const std::string prefix;
+  const std::string metricName;
+  const ResponseRuleChain identifier;
 };
 
-const std::vector<ResponseRuleChainDescription>& getResponseRuleChains();
-GlobalStateHolder<std::vector<ResponseRuleAction>>& getResponseRuleChainHolder(ResponseRuleChain chain);
+struct RuleChains
+{
+  std::vector<RuleAction> d_ruleActions;
+  std::vector<RuleAction> d_cacheMissRuleActions;
+  std::vector<ResponseRuleAction> d_respruleactions;
+  std::vector<ResponseRuleAction> d_cachehitrespruleactions;
+  std::vector<ResponseRuleAction> d_selfansweredrespruleactions;
+  std::vector<ResponseRuleAction> d_cacheInsertedRespRuleActions;
+  std::vector<ResponseRuleAction> d_XFRRespRuleActions;
+};
 
+const std::vector<RuleChainDescription>& getRuleChainDescriptions();
+std::vector<RuleAction>& getRuleChain(RuleChains& chains, RuleChain chain);
+const std::vector<RuleAction>& getRuleChain(const RuleChains& chains, RuleChain chain);
+const std::vector<ResponseRuleChainDescription>& getResponseRuleChainDescriptions();
+std::vector<ResponseRuleAction>& getRuleChain(RuleChains& chains, ResponseRuleChain chain);
+const std::vector<ResponseRuleAction>& getRuleChain(const RuleChains& chains, ResponseRuleChain chain);
+std::vector<ResponseRuleAction>& getResponseRuleChain(RuleChains& chains, ResponseRuleChain chain);
+const std::vector<ResponseRuleAction>& getResponseRuleChain(const RuleChains& chains, ResponseRuleChain chain);
+void add(RuleChains& chains, RuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder);
+void add(RuleChains& chains, ResponseRuleChain identifier, const std::shared_ptr<DNSRule>& selector, const std::shared_ptr<DNSResponseAction>& action, std::string&& name, const boost::uuids::uuid& uuid, uint64_t creationOrder);
 }
index d0f2fcb70d417c37816c2f0ebc0c2137234cdc29..129da7c8b96fffbbbb2b6d0181c7759eebc5b15e 100644 (file)
@@ -30,6 +30,7 @@
 #include "dnsdist.hh"
 #include "dnsdist-ecs.hh"
 #include "dnsdist-kvs.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-lua-ffi.hh"
 #include "dolog.hh"
 #include "dnsparser.hh"
@@ -415,7 +416,7 @@ public:
   }
   bool matches(const DNSQuestion* dq) const override
   {
-    return dq->getHeader()->cd || (getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO);    // turns out dig sets ad by default..
+    return dq->getHeader()->cd || (dnsdist::getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO);    // turns out dig sets ad by default..
   }
 
   string toString() const override
@@ -1104,13 +1105,13 @@ private:
 class PoolAvailableRule : public DNSRule
 {
 public:
-  PoolAvailableRule(const std::string& poolname) : d_pools(&g_pools), d_poolname(poolname)
+  PoolAvailableRule(const std::string& poolname) : d_poolname(poolname)
   {
   }
 
   bool matches(const DNSQuestion* dq) const override
   {
-    return (getPool(*d_pools, d_poolname)->countServers(true) > 0);
+    return (getPool(d_poolname)->countServers(true) > 0);
   }
 
   string toString() const override
@@ -1118,20 +1119,19 @@ public:
     return "pool '" + d_poolname + "' is available";
   }
 private:
-  mutable LocalStateHolder<pools_t> d_pools;
   std::string d_poolname;
 };
 
 class PoolOutstandingRule : public DNSRule
 {
 public:
-  PoolOutstandingRule(const std::string& poolname, const size_t limit) : d_pools(&g_pools), d_poolname(poolname), d_limit(limit)
+  PoolOutstandingRule(const std::string& poolname, const size_t limit) : d_poolname(poolname), d_limit(limit)
   {
   }
 
   bool matches(const DNSQuestion* dq) const override
   {
-    return (getPool(*d_pools, d_poolname)->poolLoad()) > d_limit;
+    return (getPool(d_poolname)->poolLoad()) > d_limit;
   }
 
   string toString() const override
@@ -1139,7 +1139,6 @@ public:
     return "pool '" + d_poolname + "' outstanding > " + std::to_string(d_limit);
   }
 private:
-  mutable LocalStateHolder<pools_t> d_pools;
   std::string d_poolname;
   size_t d_limit;
 };
index 26c48ba90194dccd33bef8471c89fd1cd8271381..213b43f436843910ad4166c660cf1e1ad7e0b146 100644 (file)
@@ -91,6 +91,8 @@ static std::string getFirstTXTAnswer(const std::string& answer)
 
 static std::string getSecPollStatus(const std::string& queriedName, int timeout=2)
 {
+  const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+
   const DNSName sentName(queriedName);
   std::vector<uint8_t> packet;
   DNSPacketWriter pw(packet, sentName, QType::TXT);
@@ -108,13 +110,13 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     string reply;
     int ret = waitForData(sock.getHandle(), timeout, 0);
     if (ret < 0) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the secpoll response from stub resolver %s: %d", dest.toString(), ret);
       }
       continue;
     }
     else if (ret == 0) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Timeout while waiting for the secpoll response from stub resolver %s", dest.toString());
       }
       continue;
@@ -124,14 +126,14 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
       sock.read(reply);
     }
     catch(const std::exception& e) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while reading for the secpoll response from stub resolver %s: %s", dest.toString(), e.what());
       }
       continue;
     }
 
     if (reply.size() <= sizeof(struct dnsheader)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Too short answer of size %d received from the secpoll stub resolver %s", reply.size(), dest.toString());
       }
       continue;
@@ -140,14 +142,14 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     struct dnsheader d;
     memcpy(&d, reply.c_str(), sizeof(d));
     if (d.id != pw.getHeader()->id) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid ID (%d / %d) received from the secpoll stub resolver %s", d.id, pw.getHeader()->id, dest.toString());
       }
       continue;
     }
 
     if (d.rcode != RCode::NoError) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Response code '%s' received from the secpoll stub resolver %s for '%s'", RCode::to_s(d.rcode), dest.toString(), queriedName);
       }
 
@@ -159,7 +161,7 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     }
 
     if (ntohs(d.qdcount) != 1 || ntohs(d.ancount) != 1) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer (qdcount %d / ancount %d) received from the secpoll stub resolver %s", ntohs(d.qdcount), ntohs(d.ancount), dest.toString());
       }
       continue;
@@ -170,7 +172,7 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     DNSName receivedName(reply.c_str(), reply.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
 
     if (receivedName != sentName || receivedType != QType::TXT || receivedClass != QClass::IN) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the secpoll stub resolver %s", receivedName, sentName, QType(receivedType).toString(), QType(QType::TXT).toString(), QClass(receivedClass).toString(), QClass::IN.toString(), dest.toString());
       }
       continue;
@@ -182,12 +184,12 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
   throw std::runtime_error("Unable to get a valid Security Status update");
 }
 
-static bool g_secPollDone{false};
-std::string g_secPollSuffix{"secpoll.powerdns.com."};
-time_t g_secPollInterval{3600};
-
+namespace dnsdist::secpoll
+{
 void doSecPoll(const std::string& suffix)
 {
+  static bool s_secPollDone{false};
+
   if (suffix.empty()) {
     return;
   }
@@ -211,7 +213,7 @@ void doSecPoll(const std::string& suffix)
     int securityStatus = std::stoi(split.first);
     std::string securityMessage = split.second;
 
-    if (securityStatus == 1 && !g_secPollDone) {
+    if (securityStatus == 1 && !s_secPollDone) {
       infolog("Polled security status of version %s at startup, no known issues reported: %s", std::string(VERSION), securityMessage);
     }
     if (securityStatus == 2) {
@@ -222,14 +224,14 @@ void doSecPoll(const std::string& suffix)
     }
 
     dnsdist::metrics::g_stats.securityStatus = securityStatus;
-    g_secPollDone = true;
+    s_secPollDone = true;
     return;
   }
   catch (const std::exception& e) {
     if (releaseVersion) {
       warnlog("Error while retrieving the security update for version %s: %s", version, e.what());
     }
-    else if (!g_secPollDone) {
+    else if (!s_secPollDone) {
       infolog("Error while retrieving the security update for version %s: %s", version, e.what());
     }
   }
@@ -237,13 +239,14 @@ void doSecPoll(const std::string& suffix)
   if (releaseVersion) {
     warnlog("Failed to retrieve security status update for '%s' on %s", pkgv, queriedName);
   }
-  else if (!g_secPollDone) {
+  else if (!s_secPollDone) {
     infolog("Not validating response for security status update, this is a non-release version.");
 
     /* for non-released versions, there is no use sending the same message several times,
        let's just accept that there will be no security polling for this exact version */
-    g_secPollDone = true;
+    s_secPollDone = true;
   }
 }
+}
 
 #endif /* DISABLE_SECPOLL */
index 1a376a8eada1d8956556cab041a2fdc9e9c4512d..f2977081edcbead50041755b8e2fa79bd6000685 100644 (file)
 
 #ifndef DISABLE_SECPOLL
 #include <string>
-#include <ctime>
-
-extern std::string g_secPollSuffix;
-extern time_t g_secPollInterval;
 
+namespace dnsdist::secpoll
+{
 void doSecPoll(const std::string& suffix);
+}
 #endif /* DISABLE_SECPOLL */
index 42ba272ed4b75885148ef7546c17de8da8fe8d92..de4e6c3639a9b93349aa674286040181d2f85fa3 100644 (file)
  */
 #include "dnsdist-session-cache.hh"
 
-TLSSessionCache g_sessionCache;
+#include "dnsdist-configuration.hh"
 
-time_t TLSSessionCache::s_cleanupDelay{60};
-time_t TLSSessionCache::s_sessionValidity{600};
-uint16_t TLSSessionCache::s_maxSessionsPerBackend{20};
+TLSSessionCache g_sessionCache;
 
 void TLSSessionCache::cleanup(time_t now, LockGuardedHolder<TLSSessionCache::CacheData>& data)
 {
-  time_t cutOff = now + s_sessionValidity;
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  time_t cutOff = now + runtimeConfig.d_tlsSessionCacheSessionValidity;
 
   for (auto it = data->d_sessions.begin(); it != data->d_sessions.end();) {
     if (it->second.d_lastUsed > cutOff || it->second.d_sessions.size() == 0) {
@@ -40,7 +39,7 @@ void TLSSessionCache::cleanup(time_t now, LockGuardedHolder<TLSSessionCache::Cac
     }
   }
 
-  data->d_nextCleanup = now + s_cleanupDelay;
+  data->d_nextCleanup = now + runtimeConfig.d_tlsSessionCacheCleanupDelay;
 }
 
 void TLSSessionCache::putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions)
@@ -50,9 +49,10 @@ void TLSSessionCache::putSessions(const boost::uuids::uuid& backendID, time_t no
     cleanup(now, data);
   }
 
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
   for (auto& session : sessions) {
     auto& entry = data->d_sessions[backendID];
-    if (entry.d_sessions.size() >= s_maxSessionsPerBackend) {
+    if (entry.d_sessions.size() >= runtimeConfig.d_tlsSessionCacheMaxSessionsPerBackend) {
       entry.d_sessions.pop_back();
     }
     entry.d_sessions.push_front(std::move(session));
index 1881fb1af5e5bd6f433545b818d3a13a8788c861..f4e4cdbaad266843ecc6f15215738ff6754aab27 100644 (file)
@@ -38,28 +38,9 @@ public:
   void putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions);
   std::unique_ptr<TLSSession> getSession(const boost::uuids::uuid& backendID, time_t now);
 
-  static void setCleanupDelay(time_t delay)
-  {
-    s_cleanupDelay = delay;
-  }
-
-  static void setSessionValidity(time_t validity)
-  {
-    s_sessionValidity = validity;
-  }
-
-  static void setMaxTicketsPerBackend(uint16_t max)
-  {
-    s_maxSessionsPerBackend = max;
-  }
-
   size_t getSize();
 
 private:
-  static time_t s_cleanupDelay;
-  static time_t s_sessionValidity;
-  static uint16_t s_maxSessionsPerBackend;
-
   struct BackendEntry
   {
     std::deque<std::unique_ptr<TLSSession>> d_sessions;
index 34e9c7cdd3858adf8a35ad82cf2b430735239926..cbd8c619d999659a4dfd6edf03f6199fe4070f0c 100644 (file)
@@ -1,14 +1,21 @@
 
 #include "dnsdist-snmp.hh"
+#include "dnsdist-dynblocks.hh"
 #include "dnsdist-metrics.hh"
 #include "dolog.hh"
 
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
 std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
 
 #ifdef HAVE_NET_SNMP
 
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
 #define DNSDIST_OID 1, 3, 6, 1, 4, 1, 43315, 3
 #define DNSDIST_STATS_OID DNSDIST_OID, 1
 #define DNSDIST_STATS_TABLE_OID DNSDIST_OID, 2
@@ -133,8 +140,8 @@ static int handleFloatStats(netsnmp_mib_handler* handler,
     return SNMP_ERR_GENERR;
   }
 
-  if (const auto& val = std::get_if<double*>(&stIt->second)) {
-    std::string str(std::to_string(**val));
+  if (const auto& val = std::get_if<pdns::stat_double_t*>(&stIt->second)) {
+    std::string str(std::to_string((*val)->load()));
     snmp_set_var_typed_value(requests->requestvb,
                              ASN_OCTET_STR,
                              str.c_str(),
@@ -145,7 +152,7 @@ static int handleFloatStats(netsnmp_mib_handler* handler,
   return SNMP_ERR_GENERR;
 }
 
-static void registerFloatStat(const char* name, const OIDStat& statOID, double* ptr)
+static void registerFloatStat(const char* name, const OIDStat& statOID, pdns::stat_double_t* ptr)
 {
   if (statOID.size() != OID_LENGTH(queriesOID)) {
     errlog("Invalid OID for SNMP Float statistic %s", name);
@@ -272,11 +279,11 @@ static netsnmp_variable_list* backendStatTable_get_first_data_point(void** loop_
 
   /* get a copy of the shared_ptrs so they are not
      destroyed while we process the request */
-  auto dstates = g_dstates.getLocal();
+  auto backends = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
   s_servers.clear();
-  s_servers.reserve(dstates->size());
-  for (const auto& server : *dstates) {
-    s_servers.push_back(server);
+  s_servers.reserve(backends.size());
+  for (auto& server : backends) {
+    s_servers.push_back(std::move(server));
   }
 
   return backendStatTable_get_next_data_point(loop_context,
@@ -387,12 +394,9 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap(const DownstreamState& dss)
   const string backendStatus = dss.getStatus();
   netsnmp_variable_list* varList = nullptr;
 
-  snmp_varlist_add_variable(&varList,
-                            snmpTrapOID.data(),
-                            snmpTrapOID.size(),
-                            ASN_OBJECT_ID,
-                            backendStatusChangeTrapOID.data(),
-                            backendStatusChangeTrapOID.size() * sizeof(oid));
+  addSNMPTrapOID(&varList,
+                 backendStatusChangeTrapOID.data(),
+                 backendStatusChangeTrapOID.size() * sizeof(oid));
 
   snmp_varlist_add_variable(&varList,
                             backendNameOID.data(),
@@ -426,12 +430,9 @@ bool DNSDistSNMPAgent::sendCustomTrap(const std::string& reason)
 #ifdef HAVE_NET_SNMP
   netsnmp_variable_list* varList = nullptr;
 
-  snmp_varlist_add_variable(&varList,
-                            snmpTrapOID.data(),
-                            snmpTrapOID.size(),
-                            ASN_OBJECT_ID,
-                            customTrapOID.data(),
-                            customTrapOID.size() * sizeof(oid));
+  addSNMPTrapOID(&varList,
+                 customTrapOID.data(),
+                 customTrapOID.size() * sizeof(oid));
 
   snmp_varlist_add_variable(&varList,
                             trapReasonOID.data(),
@@ -462,12 +463,9 @@ bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dnsQuestion, const std::st
 
   netsnmp_variable_list* varList = nullptr;
 
-  snmp_varlist_add_variable(&varList,
-                            snmpTrapOID.data(),
-                            snmpTrapOID.size(),
-                            ASN_OBJECT_ID,
-                            actionTrapOID.data(),
-                            actionTrapOID.size() * sizeof(oid));
+  addSNMPTrapOID(&varList,
+                 actionTrapOID.data(),
+                 actionTrapOID.size() * sizeof(oid));
 
   snmp_varlist_add_variable(&varList,
                             socketFamilyOID.data(),
@@ -600,7 +598,7 @@ DNSDistSNMPAgent::DNSDistSNMPAgent(const std::string& name, const std::string& d
   registerGauge64Stat("cpuUserMSec", cpuUserMSecOID, &getCPUTimeUser);
   registerGauge64Stat("cpuSysMSec", cpuSysMSecOID, &getCPUTimeSystem);
   registerGauge64Stat("fdUsage", fdUsageOID, &getOpenFileDescriptors);
-  registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, [](const std::string&) { return g_dynblockNMG.getLocal()->size(); });
+  registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, [](const std::string&) { return dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(); });
   registerGauge64Stat("securityStatus", securityStatusOID, [](const std::string&) { return dnsdist::metrics::g_stats.securityStatus.load(); });
   registerGauge64Stat("realMemoryUsage", realMemoryUsageOID, &getRealMemoryUsage);
 
index 7c1deff9b321586c9e8953ebfc03973e0b81857f..13a83bf8695de1f540eae3df45f005fde71c8f39 100644 (file)
@@ -35,3 +35,5 @@ public:
   bool sendCustomTrap(const std::string& reason);
   bool sendDNSTrap(const DNSQuestion&, const std::string& reason = "");
 };
+
+extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
index ffd42fd649433594226f768fcf51e432874dc909..574cc9eea1e3f52a4c193329077055df54b0dfd3 100644 (file)
@@ -20,6 +20,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include "dnsdist-svc.hh"
+#include "dnsdist.hh"
+#include "dnsdist-ecs.hh"
+#include "dnsdist-lua.hh"
 #include "dnswriter.hh"
 #include "svc-records.hh"
 
@@ -131,3 +134,94 @@ struct SVCRecordParameters parseSVCParameters(const svcParamsLua_t& params)
   }
   return parameters;
 }
+
+namespace dnsdist::svc
+{
+bool generateSVCResponse(DNSQuestion& dnsQuestion, const std::vector<std::vector<uint8_t>>& svcRecordPayloads, const std::set<std::pair<DNSName, ComboAddress>>& additionals4, const std::set<std::pair<DNSName, ComboAddress>>& additionals6, const ResponseConfig& responseConfig)
+{
+  /* it will likely be a bit bigger than that because of additionals */
+  size_t totalPayloadsSize = 0;
+  for (const auto& payload : svcRecordPayloads) {
+    totalPayloadsSize += payload.size();
+  }
+  const auto numberOfRecords = svcRecordPayloads.size();
+  const auto qnameWireLength = dnsQuestion.ids.qname.wirelength();
+  if (dnsQuestion.getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totalPayloadsSize)) {
+    return false;
+  }
+
+  PacketBuffer newPacket;
+  newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totalPayloadsSize);
+  GenericDNSPacketWriter<PacketBuffer> packetWriter(newPacket, dnsQuestion.ids.qname, dnsQuestion.ids.qtype);
+  for (const auto& payload : svcRecordPayloads) {
+    packetWriter.startRecord(dnsQuestion.ids.qname, dnsQuestion.ids.qtype, responseConfig.ttl);
+    packetWriter.xfrBlob(payload);
+    packetWriter.commit();
+  }
+
+  if (newPacket.size() < dnsQuestion.getMaximumSize()) {
+    for (const auto& additional : additionals4) {
+      packetWriter.startRecord(additional.first.isRoot() ? dnsQuestion.ids.qname : additional.first, QType::A, responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+      packetWriter.xfrCAWithoutPort(4, additional.second);
+      packetWriter.commit();
+    }
+  }
+
+  if (newPacket.size() < dnsQuestion.getMaximumSize()) {
+    for (const auto& additional : additionals6) {
+      packetWriter.startRecord(additional.first.isRoot() ? dnsQuestion.ids.qname : additional.first, QType::AAAA, responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+      packetWriter.xfrCAWithoutPort(6, additional.second);
+      packetWriter.commit();
+    }
+  }
+
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (runtimeConfig.d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+    bool dnssecOK = ((dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
+    packetWriter.addOpt(runtimeConfig.d_payloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
+    packetWriter.commit();
+  }
+
+  if (newPacket.size() >= dnsQuestion.getMaximumSize()) {
+    /* sorry! */
+    return false;
+  }
+
+  packetWriter.getHeader()->id = dnsQuestion.getHeader()->id;
+  packetWriter.getHeader()->qr = true; // for good measure
+  setResponseHeadersFromConfig(*packetWriter.getHeader(), responseConfig);
+  dnsQuestion.getMutableData() = std::move(newPacket);
+
+  return true;
+}
+
+bool generateSVCResponse(DNSQuestion& dnsQuestion, uint32_t ttl, const std::vector<SVCRecordParameters>& parameters)
+{
+  std::vector<std::vector<uint8_t>> payloads;
+  std::set<std::pair<DNSName, ComboAddress>> additionals4;
+  std::set<std::pair<DNSName, ComboAddress>> additionals6;
+  ResponseConfig responseConfig;
+  responseConfig.setAA = true;
+  responseConfig.ttl = ttl;
+
+  payloads.reserve(parameters.size());
+  for (const auto& parameter : parameters) {
+    std::vector<uint8_t> payload;
+    if (!generateSVCPayload(payload, parameter)) {
+      throw std::runtime_error("Unable to generate a valid SVC record from the supplied parameters");
+    }
+
+    payloads.push_back(std::move(payload));
+
+    for (const auto& hint : parameter.ipv4hints) {
+      additionals4.insert({parameter.target, ComboAddress(hint)});
+    }
+
+    for (const auto& hint : parameter.ipv6hints) {
+      additionals6.insert({parameter.target, ComboAddress(hint)});
+    }
+  }
+
+  return generateSVCResponse(dnsQuestion, payloads, additionals4, additionals6, responseConfig);
+}
+}
index d0a1a8c961b3da0660234518c7545a22d0ef274d..742683c3901a571ba48d66c01084e034721351fe 100644 (file)
@@ -49,18 +49,29 @@ struct SVCRecordParameters
   bool noDefaultAlpn{false};
 };
 
-typedef std::unordered_map<
+using svcParamsLua_t = std::unordered_map<
   std::string,
   boost::variant<
     uint16_t,
     bool,
     std::string,
     std::vector<std::pair<int, std::string>>,
-    std::vector<std::pair<int, ComboAddress>>>>
-  svcParamsLua_t;
+    std::vector<std::pair<int, ComboAddress>>>>;
 
 struct SVCRecordParameters parseSVCParameters(const svcParamsLua_t& params);
 
 bool generateSVCPayload(std::vector<uint8_t>& payload, uint16_t priority, const DNSName& target, const std::set<uint16_t>& mandatoryParams, const std::vector<std::string>& alpns, bool noDefaultAlpn, std::optional<uint16_t> port, const std::string& ech, const std::vector<ComboAddress>& ipv4hints, const std::vector<ComboAddress>& ipv6hints, const std::vector<std::pair<uint16_t, std::string>>& additionalParams);
 
 bool generateSVCPayload(std::vector<uint8_t>& payload, const SVCRecordParameters& parameters);
+
+struct DNSQuestion;
+namespace dnsdist
+{
+struct ResponseConfig;
+}
+
+namespace dnsdist::svc
+{
+bool generateSVCResponse(DNSQuestion& dnsQuestion, const std::vector<std::vector<uint8_t>>& svcRecordPayloads, const std::set<std::pair<DNSName, ComboAddress>>& additionals4, const std::set<std::pair<DNSName, ComboAddress>>& additionals6, const dnsdist::ResponseConfig& d_responseConfig);
+bool generateSVCResponse(DNSQuestion& dnsQuestion, uint32_t ttl, const std::vector<SVCRecordParameters>& parameters);
+}
index 0e828939d5758e33c4f992775b543d2086cca02f..5c269695f689b581e938b480525942b8a9d780b6 100644 (file)
@@ -191,11 +191,11 @@ static bool getSerialFromIXFRQuery(TCPQuery& query)
     MOADNSParser parser(true, reinterpret_cast<const char*>(query.d_buffer.data() + sizeof(uint16_t) + proxyPayloadSize), payloadSize);
 
     for (const auto& record : parser.d_answers) {
-      if (record.first.d_place != DNSResourceRecord::AUTHORITY || record.first.d_class != QClass::IN || record.first.d_type != QType::SOA) {
+      if (record.d_place != DNSResourceRecord::AUTHORITY || record.d_class != QClass::IN || record.d_type != QType::SOA) {
         return false;
       }
 
-      auto unknownContent = getRR<UnknownRecordContent>(record.first);
+      auto unknownContent = getRR<UnknownRecordContent>(record);
       if (!unknownContent) {
         return false;
       }
@@ -815,11 +815,11 @@ bool TCPConnectionToBackend::isXFRFinished(const TCPResponse& response, TCPQuery
     }
     else {
       for (const auto& record : parser.d_answers) {
-        if (record.first.d_class != QClass::IN || record.first.d_type != QType::SOA) {
+        if (record.d_class != QClass::IN || record.d_type != QType::SOA) {
           continue;
         }
 
-        auto unknownContent = getRR<UnknownRecordContent>(record.first);
+        auto unknownContent = getRR<UnknownRecordContent>(record);
         if (!unknownContent) {
           continue;
         }
index 0cbd806c1164ad59cca8ecc370ee2e7708c7fb98..df177c877825b7fb44507e86514209d94393abed 100644 (file)
@@ -10,14 +10,10 @@ class TCPClientThreadData
 {
 public:
   TCPClientThreadData():
-    localRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal()), localCacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), localXFRRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::XFRResponseRules).getLocal()), mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()))
+    mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()))
   {
   }
 
-  LocalHolders holders;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localXFRRespRuleActions;
   std::unique_ptr<FDMultiplexer> mplexer{nullptr};
   pdns::channel::Receiver<ConnectionInfo> queryReceiver;
   pdns::channel::Receiver<CrossProtocolQuery> crossProtocolQueryReceiver;
@@ -31,7 +27,7 @@ public:
   enum class QueryProcessingResult : uint8_t { Forwarded, TooSmall, InvalidHeaders, Dropped, SelfAnswered, NoBackend, Asynchronous };
   enum class ProxyProtocolResult : uint8_t { Reading, Done, Error };
 
-  IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{g_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
+  IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
   {
     d_origDest.reset();
     d_origDest.sin4.sin_family = d_ci.remote.sin4.sin_family;
@@ -57,47 +53,49 @@ public:
 
   boost::optional<struct timeval> getClientReadTTD(struct timeval now) const
   {
-    if (g_maxTCPConnectionDuration == 0 && g_tcpRecvTimeout == 0) {
+    const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpRecvTimeout == 0) {
       return boost::none;
     }
 
-    if (g_maxTCPConnectionDuration > 0) {
+    if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
       auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
-      if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+      if (elapsed < 0 || (static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration)) {
         return now;
       }
-      auto remaining = g_maxTCPConnectionDuration - elapsed;
-      if (g_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(g_tcpRecvTimeout)) {
+      auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+      if (runtimeConfiguration.d_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpRecvTimeout)) {
         now.tv_sec += remaining;
         return now;
       }
     }
 
-    now.tv_sec += g_tcpRecvTimeout;
+    now.tv_sec += runtimeConfiguration.d_tcpRecvTimeout;
     return now;
   }
 
   boost::optional<struct timeval> getClientWriteTTD(const struct timeval& now) const
   {
-    if (g_maxTCPConnectionDuration == 0 && g_tcpSendTimeout == 0) {
+    const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpSendTimeout == 0) {
       return boost::none;
     }
 
-    struct timeval res = now;
+    timeval res(now);
 
-    if (g_maxTCPConnectionDuration > 0) {
+    if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
       auto elapsed = res.tv_sec - d_connectionStartTime.tv_sec;
-      if (elapsed < 0 || static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration) {
+      if (elapsed < 0 || static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration) {
         return res;
       }
-      auto remaining = g_maxTCPConnectionDuration - elapsed;
-      if (g_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(g_tcpSendTimeout)) {
+      auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+      if (runtimeConfiguration.d_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpSendTimeout)) {
         res.tv_sec += remaining;
         return res;
       }
     }
 
-    res.tv_sec += g_tcpSendTimeout;
+    res.tv_sec += runtimeConfiguration.d_tcpSendTimeout;
     return res;
   }
 
index 240f4fbf02cc59ea90412a3cb51e0d43a4bf45ab..d2516352146c551bb1e9039f38cf526572f2050f 100644 (file)
@@ -23,6 +23,7 @@
 #include <thread>
 #include <netinet/tcp.h>
 #include <queue>
+#include <boost/format.hpp>
 
 #include "dnsdist.hh"
 #include "dnsdist-concurrent-connections.hh"
    Let's start naively.
 */
 
-size_t g_maxTCPQueriesPerConn{0};
-size_t g_maxTCPConnectionDuration{0};
-
-#ifdef __linux__
-// On Linux this gives us 128k pending queries (default is 8192 queries),
-// which should be enough to deal with huge spikes
-size_t g_tcpInternalPipeBufferSize{1048576U};
-uint64_t g_maxTCPQueuedConnections{10000};
-#else
-size_t g_tcpInternalPipeBufferSize{0};
-uint64_t g_maxTCPQueuedConnections{1000};
-#endif
-
-int g_tcpRecvTimeout{2};
-int g_tcpSendTimeout{2};
 std::atomic<uint64_t> g_tcpStatesDumpRequested{0};
 
 LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> dnsdist::IncomingConcurrentTCPConnectionsManager::s_tcpClientsConcurrentConnectionsCount;
-size_t dnsdist::IncomingConcurrentTCPConnectionsManager::s_maxTCPConnectionsPerClient = 0;
 
 IncomingTCPConnectionState::~IncomingTCPConnectionState()
 {
@@ -142,11 +127,13 @@ TCPClientCollection::TCPClientCollection(size_t maxThreads, std::vector<ClientSt
 void TCPClientCollection::addTCPClientThread(std::vector<ClientState*>& tcpAcceptStates)
 {
   try {
-    auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
 
-    auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
-    auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
+
+    auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
     vinfolog("Adding TCP Client thread");
 
@@ -170,7 +157,7 @@ void TCPClientCollection::addTCPClientThread(std::vector<ClientState*>& tcpAccep
     ++d_numthreads;
   }
   catch (const std::exception& e) {
-    errlog("Error creating TCP worker: %", e.what());
+    errlog("Error creating TCP worker: %s", e.what());
   }
 }
 
@@ -251,12 +238,13 @@ bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now)
     return false;
   }
 
-  if (g_maxTCPQueriesPerConn != 0 && d_queriesCount > g_maxTCPQueriesPerConn) {
-    vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, g_maxTCPQueriesPerConn);
+  const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (currentConfig.d_maxTCPQueriesPerConn != 0 && d_queriesCount > currentConfig.d_maxTCPQueriesPerConn) {
+    vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, currentConfig.d_maxTCPQueriesPerConn);
     return false;
   }
 
-  if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+  if (maxConnectionDurationReached(currentConfig.d_maxTCPConnectionDuration, now)) {
     vinfolog("not accepting new queries from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
     return false;
   }
@@ -502,7 +490,7 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe
     try {
       auto& ids = response.d_idstate;
       std::shared_ptr<DownstreamState> backend = response.d_ds ? response.d_ds : (response.d_connection ? response.d_connection->getDS() : nullptr);
-      if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend)) {
+      if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend, dnsdist::configuration::getCurrentRuntimeConfiguration().d_allowEmptyResponse)) {
         state->terminateClientConnection();
         return;
       }
@@ -516,7 +504,7 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe
 
       memcpy(&response.d_cleartextDH, dnsResponse.getHeader().get(), sizeof(response.d_cleartextDH));
 
-      if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dnsResponse, false)) {
+      if (!processResponse(response.d_buffer, dnsResponse, false)) {
         state->terminateClientConnection();
         return;
       }
@@ -748,7 +736,7 @@ IncomingTCPConnectionState::QueryProcessingResult IncomingTCPConnectionState::ha
   }
 
   std::shared_ptr<DownstreamState> backend;
-  auto result = processQuery(dnsQuestion, d_threadData.holders, backend);
+  auto result = processQuery(dnsQuestion, backend);
 
   if (result == ProcessQueryResult::Asynchronous) {
     /* we are done for now */
@@ -905,7 +893,7 @@ IncomingTCPConnectionState::ProxyProtocolResult IncomingTCPConnectionState::hand
       else {
         /* proxy header received */
         std::vector<ProxyProtocolValue> proxyProtocolValues;
-        if (!handleProxyProtocol(d_ci.remote, true, *d_threadData.holders.acl, d_buffer, d_proxiedRemote, d_proxiedDestination, proxyProtocolValues)) {
+        if (!handleProxyProtocol(d_ci.remote, true, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, d_buffer, d_proxiedRemote, d_proxiedDestination, proxyProtocolValues)) {
           vinfolog("Error handling the Proxy Protocol received from TCP client %s", d_ci.remote.toStringWithPort());
           return ProxyProtocolResult::Error;
         }
@@ -914,6 +902,9 @@ IncomingTCPConnectionState::ProxyProtocolResult IncomingTCPConnectionState::hand
           d_proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
         }
 
+        d_currentPos = 0;
+        d_proxyProtocolNeed = 0;
+        d_buffer.clear();
         return ProxyProtocolResult::Done;
       }
     }
@@ -1068,7 +1059,7 @@ void IncomingTCPConnectionState::handleIO()
     iostate = IOState::Done;
     IOStateGuard ioGuard(d_ioState);
 
-    if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+    if (maxConnectionDurationReached(dnsdist::configuration::getCurrentRuntimeConfiguration().d_maxTCPConnectionDuration, now)) {
       vinfolog("Terminating TCP connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
       // will be handled by the ioGuard
       // handleNewIOState(state, IOState::Done, fd, handleIOCallback);
@@ -1096,15 +1087,14 @@ void IncomingTCPConnectionState::handleIO()
       if (!d_lastIOBlocked && d_state == State::readingProxyProtocolHeader) {
         auto status = handleProxyProtocolPayload();
         if (status == ProxyProtocolResult::Done) {
+          d_buffer.resize(sizeof(uint16_t));
+
           if (isProxyPayloadOutsideTLS()) {
             d_state = State::doingHandshake;
             iostate = handleHandshake(now);
           }
           else {
             d_state = State::readingQuerySize;
-            d_buffer.resize(sizeof(uint16_t));
-            d_currentPos = 0;
-            d_proxyProtocolNeed = 0;
           }
         }
         else if (status == ProxyProtocolResult::Error) {
@@ -1218,8 +1208,11 @@ void IncomingTCPConnectionState::notifyIOError(const struct timeval& now, TCPRes
   }
 }
 
-static bool processXFRResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& xfrRespRuleActions, DNSResponse& dnsResponse)
+static bool processXFRResponse(PacketBuffer& response, DNSResponse& dnsResponse)
 {
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  const auto& xfrRespRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::XFRResponseRules);
+
   if (!applyRulesToResponse(xfrRespRuleActions, dnsResponse)) {
     return false;
   }
@@ -1249,7 +1242,7 @@ void IncomingTCPConnectionState::handleXFRResponse(const struct timeval& now, TC
   dnsResponse.d_incomingTCPState = state;
   memcpy(&response.d_cleartextDH, dnsResponse.getHeader().get(), sizeof(response.d_cleartextDH));
 
-  if (!processXFRResponse(response.d_buffer, *state->d_threadData.localXFRRespRuleActions, dnsResponse)) {
+  if (!processXFRResponse(response.d_buffer, dnsResponse)) {
     state->terminateClientConnection();
     return;
   }
@@ -1384,8 +1377,6 @@ struct TCPAcceptorParam
   // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
   ClientState& clientState;
   ComboAddress local;
-  // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
-  LocalStateHolder<NetmaskGroup>& acl;
   int socket{-1};
 };
 
@@ -1507,14 +1498,13 @@ static void tcpClientThread(pdns::channel::Receiver<ConnectionInfo>&& queryRecei
     data.mplexer->addReadFD(data.crossProtocolResponseReceiver.getDescriptor(), handleCrossProtocolResponse, &data);
 
     /* only used in single acceptor mode for now */
-    auto acl = g_ACL.getLocal();
     std::vector<TCPAcceptorParam> acceptParams;
     acceptParams.reserve(tcpAcceptStates.size());
 
     for (auto& state : tcpAcceptStates) {
-      acceptParams.emplace_back(TCPAcceptorParam{*state, state->local, acl, state->tcpFD});
+      acceptParams.emplace_back(TCPAcceptorParam{*state, state->local, state->tcpFD});
       for (const auto& [addr, socket] : state->d_additionalAddresses) {
-        acceptParams.emplace_back(TCPAcceptorParam{*state, addr, acl, socket});
+        acceptParams.emplace_back(TCPAcceptorParam{*state, addr, socket});
       }
     }
 
@@ -1560,7 +1550,6 @@ static void tcpClientThread(pdns::channel::Receiver<ConnectionInfo>&& queryRecei
 static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadData* threadData)
 {
   auto& clientState = param.clientState;
-  auto& acl = param.acl;
   const bool checkACL = clientState.dohFrontend == nullptr || (!clientState.dohFrontend->d_trustForwardedForHeader && clientState.dohFrontend->d_earlyACLDrop);
   const int socket = param.socket;
   bool tcpClientCountIncremented = false;
@@ -1585,7 +1574,7 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
       throw std::runtime_error((boost::format("accepting new connection on socket: %s") % stringerror()).str());
     }
 
-    if (checkACL && !acl->match(remote)) {
+    if (checkACL && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
       ++dnsdist::metrics::g_stats.aclDrops;
       vinfolog("Dropped TCP connection from %s because of ACL", remote.toStringWithPort());
       return;
@@ -1608,7 +1597,8 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
 
     setTCPNoDelay(connInfo.fd); // disable NAGLE
 
-    if (g_maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= g_maxTCPQueuedConnections) {
+    const auto maxTCPQueuedConnections = dnsdist::configuration::getImmutableConfiguration().d_maxTCPQueuedConnections;
+    if (maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= maxTCPQueuedConnections) {
       vinfolog("Dropping TCP connection from %s because we have too many queued already", remote.toStringWithPort());
       return;
     }
@@ -1664,14 +1654,13 @@ void tcpAcceptorThread(const std::vector<ClientState*>& states)
 {
   setThreadName("dnsdist/tcpAcce");
 
-  auto acl = g_ACL.getLocal();
   std::vector<TCPAcceptorParam> params;
   params.reserve(states.size());
 
   for (const auto& state : states) {
-    params.emplace_back(TCPAcceptorParam{*state, state->local, acl, state->tcpFD});
+    params.emplace_back(TCPAcceptorParam{*state, state->local, state->tcpFD});
     for (const auto& [addr, socket] : state->d_additionalAddresses) {
-      params.emplace_back(TCPAcceptorParam{*state, addr, acl, socket});
+      params.emplace_back(TCPAcceptorParam{*state, addr, socket});
     }
   }
 
index 7fe717b1d30ae5c590297904cd81635a1442d58d..5cdfead09cd0629898ac6f2818deac53b4996dd3 100644 (file)
 #include "base64.hh"
 #include "connection-management.hh"
 #include "dnsdist.hh"
+#include "dnsdist-cache.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-dynblocks.hh"
+#include "dnsdist-dynbpf.hh"
+#include "dnsdist-frontend.hh"
 #include "dnsdist-healthchecks.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-metrics.hh"
 #include "dnsdist-prometheus.hh"
 #include "dnsdist-rings.hh"
 #include "threadname.hh"
 #include "sstuff.hh"
 
-struct WebserverConfig
-{
-  WebserverConfig()
-  {
-    acl.toMasks("127.0.0.1, ::1");
-  }
-
-  NetmaskGroup acl;
-  std::unique_ptr<CredentialsHolder> password;
-  std::unique_ptr<CredentialsHolder> apiKey;
-  boost::optional<std::unordered_map<std::string, std::string>> customHeaders;
-  bool apiRequiresAuthentication{true};
-  bool dashboardRequiresAuthentication{true};
-  bool statsRequireAuthentication{true};
-};
-
-bool g_apiReadWrite{false};
-LockGuarded<WebserverConfig> g_webserverConfig;
-std::string g_apiConfigDirectory;
-
-static ConcurrentConnectionManager s_connManager(100);
-
-std::string getWebserverConfig()
-{
-  ostringstream out;
-
-  {
-    auto config = g_webserverConfig.lock();
-    out << "Current web server configuration:" << endl;
-    out << "ACL: " << config->acl.toString() << endl;
-    out << "Custom headers: ";
-    if (config->customHeaders) {
-      out << endl;
-      for (const auto& header : *config->customHeaders) {
-        out << " - " << header.first << ": " << header.second << endl;
-      }
-    }
-    else {
-      out << "None" << endl;
-    }
-    out << "API requires authentication: " << (config->apiRequiresAuthentication ? "yes" : "no") << endl;
-    out << "Dashboard requires authentication: " << (config->dashboardRequiresAuthentication ? "yes" : "no") << endl;
-    out << "Statistics require authentication: " << (config->statsRequireAuthentication ? "yes" : "no") << endl;
-    out << "Password: " << (config->password ? "set" : "unset") << endl;
-    out << "API key: " << (config->apiKey ? "set" : "unset") << endl;
-  }
-  out << "API writable: " << (g_apiReadWrite ? "yes" : "no") << endl;
-  out << "API configuration directory: " << g_apiConfigDirectory << endl;
-  out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
-
-  return out.str();
-}
-
-class WebClientConnection
-{
-public:
-  WebClientConnection(const ComboAddress& client, int socketDesc) :
-    d_client(client), d_socket(socketDesc)
-  {
-    if (!s_connManager.registerConnection()) {
-      throw std::runtime_error("Too many concurrent web client connections");
-    }
-  }
-  WebClientConnection(WebClientConnection&& rhs) noexcept :
-    d_client(rhs.d_client), d_socket(std::move(rhs.d_socket))
-  {
-  }
-  WebClientConnection(const WebClientConnection&) = delete;
-  WebClientConnection& operator=(const WebClientConnection&) = delete;
-  WebClientConnection& operator=(WebClientConnection&& rhs) noexcept
-  {
-    d_client = rhs.d_client;
-    d_socket = std::move(rhs.d_socket);
-    return *this;
-  }
-
-  ~WebClientConnection()
-  {
-    if (d_socket.getHandle() != -1) {
-      s_connManager.releaseConnection();
-    }
-  }
-
-  [[nodiscard]] const Socket& getSocket() const
-  {
-    return d_socket;
-  }
-
-  [[nodiscard]] const ComboAddress& getClient() const
-  {
-    return d_client;
-  }
-
-private:
-  ComboAddress d_client;
-  Socket d_socket;
-};
-
 #ifndef DISABLE_PROMETHEUS
 static MetricDefinitionStorage s_metricDefinitions;
 
@@ -226,6 +133,86 @@ std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{
 };
 #endif /* DISABLE_PROMETHEUS */
 
+namespace dnsdist::webserver
+{
+static ConcurrentConnectionManager s_connManager(100);
+
+std::string getConfig()
+{
+  ostringstream out;
+
+  {
+    const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    out << "Current web server configuration:" << endl;
+    out << "ACL: " << config.d_webServerACL.toString() << endl;
+    out << "Custom headers: ";
+    if (config.d_webCustomHeaders) {
+      out << endl;
+      for (const auto& header : *config.d_webCustomHeaders) {
+        out << " - " << header.first << ": " << header.second << endl;
+      }
+    }
+    else {
+      out << "None" << endl;
+    }
+    out << "API requires authentication: " << (config.d_apiRequiresAuthentication ? "yes" : "no") << endl;
+    out << "Dashboard requires authentication: " << (config.d_dashboardRequiresAuthentication ? "yes" : "no") << endl;
+    out << "Statistics require authentication: " << (config.d_statsRequireAuthentication ? "yes" : "no") << endl;
+    out << "Password: " << (config.d_webPassword ? "set" : "unset") << endl;
+    out << "API key: " << (config.d_webAPIKey ? "set" : "unset") << endl;
+    out << "API writable: " << (config.d_apiReadWrite ? "yes" : "no") << endl;
+    out << "API configuration directory: " << config.d_apiConfigDirectory << endl;
+    out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
+  }
+
+  return out.str();
+}
+
+class WebClientConnection
+{
+public:
+  WebClientConnection(const ComboAddress& client, int socketDesc) :
+    d_client(client), d_socket(socketDesc)
+  {
+    if (!s_connManager.registerConnection()) {
+      throw std::runtime_error("Too many concurrent web client connections");
+    }
+  }
+  WebClientConnection(WebClientConnection&& rhs) noexcept :
+    d_client(rhs.d_client), d_socket(std::move(rhs.d_socket))
+  {
+  }
+  WebClientConnection(const WebClientConnection&) = delete;
+  WebClientConnection& operator=(const WebClientConnection&) = delete;
+  WebClientConnection& operator=(WebClientConnection&& rhs) noexcept
+  {
+    d_client = rhs.d_client;
+    d_socket = std::move(rhs.d_socket);
+    return *this;
+  }
+
+  ~WebClientConnection()
+  {
+    if (d_socket.getHandle() != -1) {
+      s_connManager.releaseConnection();
+    }
+  }
+
+  [[nodiscard]] const Socket& getSocket() const
+  {
+    return d_socket;
+  }
+
+  [[nodiscard]] const ComboAddress& getClient() const
+  {
+    return d_client;
+  }
+
+private:
+  ComboAddress d_client;
+  Socket d_socket;
+};
+
 bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
 {
 #ifndef DISABLE_PROMETHEUS
@@ -238,17 +225,18 @@ bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition&
 #ifndef DISABLE_WEB_CONFIG
 static bool apiWriteConfigFile(const string& filebasename, const string& content)
 {
-  if (!g_apiReadWrite) {
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!runtimeConfig.d_apiReadWrite) {
     warnlog("Not writing content to %s since the API is read-only", filebasename);
     return false;
   }
 
-  if (g_apiConfigDirectory.empty()) {
+  if (runtimeConfig.d_apiConfigDirectory.empty()) {
     vinfolog("Not writing content to %s since the API configuration directory is not set", filebasename);
     return false;
   }
 
-  string filename = g_apiConfigDirectory + "/" + filebasename + ".conf";
+  string filename = runtimeConfig.d_apiConfigDirectory + "/" + filebasename + ".conf";
   ofstream ofconf(filename.c_str());
   if (!ofconf) {
     errlog("Could not open configuration fragment file '%s' for writing: %s", filename, stringerror());
@@ -277,7 +265,7 @@ static void apiSaveACL(const NetmaskGroup& nmg)
 }
 #endif /* DISABLE_WEB_CONFIG */
 
-static bool checkAPIKey(const YaHTTP::Request& req, const std::unique_ptr<CredentialsHolder>& apiKey)
+static bool checkAPIKey(const YaHTTP::Request& req, const std::shared_ptr<const CredentialsHolder>& apiKey)
 {
   if (!apiKey) {
     return false;
@@ -291,7 +279,7 @@ static bool checkAPIKey(const YaHTTP::Request& req, const std::unique_ptr<Creden
   return false;
 }
 
-static bool checkWebPassword(const YaHTTP::Request& req, const std::unique_ptr<CredentialsHolder>& password, bool dashboardRequiresAuthentication)
+static bool checkWebPassword(const YaHTTP::Request& req, const std::shared_ptr<const CredentialsHolder>& password, bool dashboardRequiresAuthentication)
 {
   if (!dashboardRequiresAuthentication) {
     return true;
@@ -338,26 +326,26 @@ static bool isAStatsRequest(const YaHTTP::Request& req)
 
 static bool handleAuthorization(const YaHTTP::Request& req)
 {
-  auto config = g_webserverConfig.lock();
+  const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
 
   if (isAStatsRequest(req)) {
-    if (config->statsRequireAuthentication) {
+    if (config.d_statsRequireAuthentication) {
       /* Access to the stats is allowed for both API and Web users */
-      return checkAPIKey(req, config->apiKey) || checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+      return checkAPIKey(req, config.d_webAPIKey) || checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
     }
     return true;
   }
 
   if (isAnAPIRequest(req)) {
     /* Access to the API requires a valid API key */
-    if (!config->apiRequiresAuthentication || checkAPIKey(req, config->apiKey)) {
+    if (!config.d_apiRequiresAuthentication || checkAPIKey(req, config.d_webAPIKey)) {
       return true;
     }
 
-    return isAnAPIRequestAllowedWithWebAuth(req) && checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+    return isAnAPIRequestAllowedWithWebAuth(req) && checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
   }
 
-  return checkWebPassword(req, config->password, config->dashboardRequiresAuthentication);
+  return checkWebPassword(req, config.d_webPassword, config.d_dashboardRequiresAuthentication);
 }
 
 static bool isMethodAllowed(const YaHTTP::Request& req)
@@ -365,7 +353,7 @@ static bool isMethodAllowed(const YaHTTP::Request& req)
   if (req.method == "GET") {
     return true;
   }
-  if (req.method == "PUT" && g_apiReadWrite) {
+  if (req.method == "PUT" && dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
     if (req.url.path == "/api/v1/servers/localhost/config/allow-from") {
       return true;
     }
@@ -382,7 +370,8 @@ static bool isMethodAllowed(const YaHTTP::Request& req)
 
 static bool isClientAllowedByACL(const ComboAddress& remote)
 {
-  return g_webserverConfig.lock()->acl.match(remote);
+  const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  return config.d_webServerACL.match(remote);
 }
 
 static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
@@ -391,7 +380,7 @@ static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
   if (origin != req.headers.end()) {
     if (req.method == "OPTIONS") {
       /* Pre-flight request */
-      if (g_apiReadWrite) {
+      if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
         resp.headers["Access-Control-Allow-Methods"] = "GET, PUT";
       }
       else {
@@ -408,7 +397,7 @@ static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
   }
 }
 
-static void addSecurityHeaders(YaHTTP::Response& resp, const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
+static void addSecurityHeaders(YaHTTP::Response& resp, const std::optional<std::unordered_map<std::string, std::string>>& customHeaders)
 {
   static const std::vector<std::pair<std::string, std::string>> headers = {
     {"X-Content-Type-Options", "nosniff"},
@@ -429,7 +418,7 @@ static void addSecurityHeaders(YaHTTP::Response& resp, const boost::optional<std
   }
 }
 
-static void addCustomHeaders(YaHTTP::Response& resp, const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
+static void addCustomHeaders(YaHTTP::Response& resp, const std::optional<std::unordered_map<std::string, std::string>>& customHeaders)
 {
   if (!customHeaders) {
     return;
@@ -443,14 +432,13 @@ static void addCustomHeaders(YaHTTP::Response& resp, const boost::optional<std::
 }
 
 template <typename T>
-static json11::Json::array someResponseRulesToJson(GlobalStateHolder<vector<T>>* someResponseRules)
+static json11::Json::array someResponseRulesToJson(const std::vector<T>& someResponseRules)
 {
   using namespace json11;
   Json::array responseRules;
   int num = 0;
-  auto localResponseRules = someResponseRules->getLocal();
-  responseRules.reserve(localResponseRules->size());
-  for (const auto& rule : *localResponseRules) {
+  responseRules.reserve(someResponseRules.size());
+  for (const auto& rule : someResponseRules) {
     responseRules.emplace_back(Json::object{
       {"id", num++},
       {"creationOrder", static_cast<double>(rule.d_creationOrder)},
@@ -466,10 +454,9 @@ static json11::Json::array someResponseRulesToJson(GlobalStateHolder<vector<T>>*
 
 #ifndef DISABLE_PROMETHEUS
 template <typename T>
-static void addRulesToPrometheusOutput(std::ostringstream& output, GlobalStateHolder<vector<T>>& rules)
+static void addRulesToPrometheusOutput(std::ostringstream& output, const std::vector<T>& rules)
 {
-  auto localRules = rules.getLocal();
-  for (const auto& entry : *localRules) {
+  for (const auto& entry : rules) {
     std::string identifier = !entry.d_name.empty() ? entry.d_name : boost::uuids::to_string(entry.d_id);
     output << "dnsdist_rule_hits{id=\"" << identifier << "\"} " << entry.d_rule->d_matches << "\n";
   }
@@ -484,6 +471,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   static const std::set<std::string> metricBlacklist = {"special-memory-usage", "latency-count", "latency-sum"};
   {
     auto entries = dnsdist::metrics::g_stats.entries.read_lock();
+    std::unordered_set<std::string> helpAndTypeSent;
     for (const auto& entry : *entries) {
       const auto& metricName = entry.d_name;
 
@@ -515,19 +503,19 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
       // for these we have the help and types encoded in the sources
       // but we need to be careful about labels in custom metrics
       std::string helpName = prometheusMetricName.substr(0, prometheusMetricName.find('{'));
-      output << "# HELP " << helpName << " " << metricDetails.description << "\n";
-      output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
+      if (helpAndTypeSent.count(helpName) == 0) {
+        helpAndTypeSent.insert(helpName);
+        output << "# HELP " << helpName << " " << metricDetails.description << "\n";
+        output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
+      }
       output << prometheusMetricName << " ";
 
       if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
         output << (*val)->load();
       }
-      else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+      else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
         output << (*adval)->load();
       }
-      else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
-        output << **dval;
-      }
       else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
         output << (*func)(entry.d_name);
       }
@@ -554,7 +542,6 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   output << "dnsdist_latency_sum " << dnsdist::metrics::g_stats.latencySum << "\n";
   output << "dnsdist_latency_count " << dnsdist::metrics::g_stats.latencyCount << "\n";
 
-  auto states = g_dstates.getLocal();
   const string statesbase = "dnsdist_server_";
 
   // clang-format off
@@ -621,7 +608,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   output << "# HELP " << statesbase << "healthcheckfailuresinvalid "      << "Number of health check attempts where the DNS response was invalid"                   << "\n";
   output << "# TYPE " << statesbase << "healthcheckfailuresinvalid "      << "counter"                                                                              << "\n";
 
-  for (const auto& state : *states) {
+  for (const auto& state : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
     string serverName;
 
     if (state->getName().empty()) {
@@ -710,7 +697,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   output << "# TYPE " << frontsbase << "tlshandshakefailures " << "counter" << "\n";
 
   std::map<std::string,uint64_t> frontendDuplicates;
-  for (const auto& front : g_frontends) {
+  for (const auto& front : dnsdist::getFrontends()) {
     if (front->udpFD == -1 && front->tcpFD == -1) {
       continue;
     }
@@ -796,7 +783,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
 #ifdef HAVE_DNS_OVER_HTTPS
   std::map<std::string,uint64_t> dohFrontendDuplicates;
-  for(const auto& doh : g_dohlocals) {
+  for(const auto& doh : dnsdist::getDoHFrontends()) {
     const string frontName = doh->d_tlsContext.d_addr.toStringWithPort();
     uint64_t threadNumber = 0;
     auto dupPair = frontendDuplicates.emplace(frontName, 1);
@@ -835,7 +822,6 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   }
 #endif /* HAVE_DNS_OVER_HTTPS */
 
-  auto localPools = g_pools.getLocal();
   const string cachebase = "dnsdist_pool_";
   output << "# HELP dnsdist_pool_servers " << "Number of servers in that pool" << "\n";
   output << "# TYPE dnsdist_pool_servers " << "gauge" << "\n";
@@ -863,7 +849,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   output << "# HELP dnsdist_pool_cache_cleanup_count_total " << "Number of times the cache has been scanned to remove expired entries, if any" << "\n";
   output << "# TYPE dnsdist_pool_cache_cleanup_count_total " << "counter" << "\n";
 
-  for (const auto& entry : *localPools) {
+  for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
     string poolName = entry.first;
 
     if (poolName.empty()) {
@@ -892,11 +878,14 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   output << "# HELP dnsdist_rule_hits " << "Number of hits of that rule" << "\n";
   output << "# TYPE dnsdist_rule_hits " << "counter" << "\n";
-  for (const auto& chain : dnsdist::rules::getRuleChains()) {
-    addRulesToPrometheusOutput(output, chain.holder);
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  for (const auto& chainDescription : dnsdist::rules::getRuleChainDescriptions()) {
+    const auto& chain = dnsdist::rules::getRuleChain(chains, chainDescription.identifier);
+    addRulesToPrometheusOutput(output, chain);
   }
-  for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
-    addRulesToPrometheusOutput(output, chain.holder);
+  for (const auto& chainDescription : dnsdist::rules::getResponseRuleChainDescriptions()) {
+    const auto& chain = dnsdist::rules::getResponseRuleChain(chains, chainDescription.identifier);
+    addRulesToPrometheusOutput(output, chain);
   }
 
 #ifndef DISABLE_DYNBLOCKS
@@ -941,12 +930,9 @@ static void addStatsToJSONObject(Json::object& obj)
     if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
       obj.emplace(entry.d_name, (double)(*val)->load());
     }
-    else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+    else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&entry.d_value)) {
       obj.emplace(entry.d_name, (*adval)->load());
     }
-    else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
-      obj.emplace(entry.d_name, (**dval));
-    }
     else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
       obj.emplace(entry.d_name, (double)(*func)(entry.d_name));
     }
@@ -965,6 +951,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   }
 
   const string& command = req.getvars.at("command");
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
 
   if (command == "stats") {
     auto obj = Json::object{
@@ -972,7 +959,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
       {"packetcache-misses", 0},
       {"over-capacity-drops", 0},
       {"too-old-drops", 0},
-      {"server-policy", g_policy.getLocal()->getName()}};
+      {"server-policy", runtimeConfig.d_lbPolicy->getName()}};
 
     addStatsToJSONObject(obj);
 
@@ -983,10 +970,10 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   else if (command == "dynblocklist") {
     Json::object obj;
 #ifndef DISABLE_DYNBLOCKS
-    auto nmg = g_dynblockNMG.getLocal();
     timespec now{};
     gettime(&now);
-    for (const auto& entry : *nmg) {
+    const auto& dynamicClientAddressRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+    for (const auto& entry : dynamicClientAddressRules) {
       if (!(now < entry.second.until)) {
         continue;
       }
@@ -998,14 +985,14 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
         {"reason", entry.second.reason},
         {"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
         {"blocks", static_cast<double>(counter)},
-        {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+        {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
         {"warning", entry.second.warning},
         {"ebpf", entry.second.bpf}};
       obj.emplace(entry.first.toString(), thing);
     }
 
-    auto smt = g_dynblockSMT.getLocal();
-    smt->visit([&now, &obj](const SuffixMatchTree<DynBlock>& node) {
+    const auto& dynamicSuffixRules = dnsdist::DynamicBlocks::getSuffixDynamicRules();
+    dynamicSuffixRules.visit([&now, &obj, &runtimeConfig](const SuffixMatchTree<DynBlock>& node) {
       if (!(now < node.d_value.until)) {
         return;
       }
@@ -1017,7 +1004,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
         {"reason", node.d_value.reason},
         {"seconds", static_cast<double>(node.d_value.until.tv_sec - now.tv_sec)},
         {"blocks", static_cast<double>(node.d_value.blocks)},
-        {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction)},
+        {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : runtimeConfig.d_dynBlockAction)},
         {"ebpf", node.d_value.bpf}};
       obj.emplace(dom, thing);
     });
@@ -1041,8 +1028,8 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
       }
     }
     if (g_defaultBPFFilter) {
-      auto nmg = g_dynblockNMG.getLocal();
-      for (const auto& entry : *nmg) {
+      const auto& dynamicClientAddressRules = dnsdist::DynamicBlocks::getClientAddressDynamicRules();
+      for (const auto& entry : dynamicClientAddressRules) {
         if (!(now < entry.second.until) || !entry.second.bpf) {
           continue;
         }
@@ -1051,7 +1038,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
           {"reason", entry.second.reason},
           {"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
           {"blocks", static_cast<double>(counter)},
-          {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+          {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
           {"warning", entry.second.warning},
         };
         obj.emplace(entry.first.toString(), thing);
@@ -1078,7 +1065,7 @@ static void addServerToJSON(Json::array& servers, int identifier, const std::sha
     status = "DOWN";
   }
   else {
-    status = (backend->upStatus ? "up" : "down");
+    status = (backend->upStatus.load(std::memory_order_relaxed) ? "up" : "down");
   }
 
   Json::array pools;
@@ -1146,17 +1133,17 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   Json::array servers;
   {
-    auto localServers = g_dstates.getLocal();
-    servers.reserve(localServers->size());
-    for (const auto& server : *localServers) {
+    const auto& localServers = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
+    servers.reserve(localServers.size());
+    for (const auto& server : localServers) {
       addServerToJSON(servers, num++, server);
     }
   }
 
   Json::array frontends;
   num = 0;
-  frontends.reserve(g_frontends.size());
-  for (const auto& front : g_frontends) {
+  frontends.reserve(dnsdist::getFrontends().size());
+  for (const auto& front : dnsdist::getFrontends()) {
     if (front->udpFD == -1 && front->tcpFD == -1) {
       continue;
     }
@@ -1211,9 +1198,10 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   Json::array dohs;
 #ifdef HAVE_DNS_OVER_HTTPS
   {
-    dohs.reserve(g_dohlocals.size());
+    const auto dohFrontends = dnsdist::getDoHFrontends();
+    dohs.reserve(dohFrontends.size());
     num = 0;
-    for (const auto& doh : g_dohlocals) {
+    for (const auto& doh : dohFrontends) {
       dohs.emplace_back(Json::object{
         {"id", num++},
         {"address", doh->d_tlsContext.d_addr.toStringWithPort()},
@@ -1244,10 +1232,10 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   Json::array pools;
   {
-    auto localPools = g_pools.getLocal();
     num = 0;
-    pools.reserve(localPools->size());
-    for (const auto& pool : *localPools) {
+    const auto& localPools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+    pools.reserve(localPools.size());
+    for (const auto& pool : localPools) {
       const auto& cache = pool.second->packetCache;
       Json::object entry{
         {"id", num++},
@@ -1269,7 +1257,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   string acl;
   {
-    auto aclEntries = g_ACL.getLocal()->toStringVector();
+    auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
 
     for (const auto& entry : aclEntries) {
       if (!acl.empty()) {
@@ -1282,7 +1270,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   string localaddressesStr;
   {
     std::set<std::string> localaddresses;
-    for (const auto& front : g_frontends) {
+    for (const auto& front : dnsdist::getFrontends()) {
       localaddresses.insert(front->local.toStringWithPort());
     }
     for (const auto& addr : localaddresses) {
@@ -1308,12 +1296,13 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   /* unfortunately DNSActions have getStats(),
      and DNSResponseActions do not. */
-  for (const auto& chain : dnsdist::rules::getRuleChains()) {
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  for (const auto& chainDescription : dnsdist::rules::getRuleChainDescriptions()) {
     Json::array rules;
-    auto localRules = chain.holder.getLocal();
+    const auto& chain = dnsdist::rules::getRuleChain(chains, chainDescription.identifier);
     num = 0;
-    rules.reserve(localRules->size());
-    for (const auto& lrule : *localRules) {
+    rules.reserve(chain.size());
+    for (const auto& lrule : chain) {
       Json::object rule{
         {"id", num++},
         {"creationOrder", (double)lrule.d_creationOrder},
@@ -1325,12 +1314,13 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
         {"action-stats", lrule.d_action->getStats()}};
       rules.emplace_back(std::move(rule));
     }
-    responseObject[chain.metricName] = std::move(rules);
+    responseObject[chainDescription.metricName] = std::move(rules);
   }
 
-  for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
-    auto responseRules = someResponseRulesToJson(&chain.holder);
-    responseObject[chain.metricName] = std::move(responseRules);
+  for (const auto& chainDescription : dnsdist::rules::getResponseRuleChainDescriptions()) {
+    const auto& chain = dnsdist::rules::getResponseRuleChain(chains, chainDescription.identifier);
+    auto responseRules = someResponseRulesToJson(chain);
+    responseObject[chainDescription.metricName] = std::move(responseRules);
   }
 
   resp.headers["Content-Type"] = "application/json";
@@ -1349,9 +1339,9 @@ static void handlePoolStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   resp.status = 200;
   Json::array doc;
 
-  auto localPools = g_pools.getLocal();
-  const auto poolIt = localPools->find(poolName->second);
-  if (poolIt == localPools->end()) {
+  const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+  const auto poolIt = pools.find(poolName->second);
+  if (poolIt == pools.end()) {
     resp.status = 404;
     return;
   }
@@ -1406,18 +1396,12 @@ static void handleStatsOnly(const YaHTTP::Request& req, YaHTTP::Response& resp)
           {"name", item.d_name},
           {"value", (double)(*val)->load()}});
       }
-      else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&item.d_value)) {
+      else if (const auto& adval = std::get_if<pdns::stat_double_t*>(&item.d_value)) {
         doc.emplace_back(Json::object{
           {"type", "StatisticItem"},
           {"name", item.d_name},
           {"value", (*adval)->load()}});
       }
-      else if (const auto& dval = std::get_if<double*>(&item.d_value)) {
-        doc.emplace_back(Json::object{
-          {"type", "StatisticItem"},
-          {"name", item.d_name},
-          {"value", (**dval)}});
-      }
       else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&item.d_value)) {
         doc.emplace_back(Json::object{
           {"type", "StatisticItem"},
@@ -1438,23 +1422,25 @@ static void handleConfigDump(const YaHTTP::Request& req, YaHTTP::Response& resp)
   resp.status = 200;
 
   Json::array doc;
-  typedef boost::variant<bool, double, std::string> configentry_t;
+  const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+  using configentry_t = boost::variant<bool, double, std::string>;
   std::vector<std::pair<std::string, configentry_t>> configEntries{
-    {"acl", g_ACL.getLocal()->toString()},
-    {"allow-empty-response", g_allowEmptyResponse},
-    {"control-socket", g_serverControl.toStringWithPort()},
-    {"ecs-override", g_ECSOverride},
-    {"ecs-source-prefix-v4", (double)g_ECSSourcePrefixV4},
-    {"ecs-source-prefix-v6", (double)g_ECSSourcePrefixV6},
-    {"fixup-case", g_fixupCase},
-    {"max-outstanding", (double)g_maxOutstanding},
-    {"server-policy", g_policy.getLocal()->getName()},
-    {"stale-cache-entries-ttl", (double)g_staleCacheEntriesTTL},
-    {"tcp-recv-timeout", (double)g_tcpRecvTimeout},
-    {"tcp-send-timeout", (double)g_tcpSendTimeout},
-    {"truncate-tc", g_truncateTC},
-    {"verbose", g_verbose},
-    {"verbose-health-checks", g_verboseHealthChecks}};
+    {"acl", runtimeConfiguration.d_ACL.toString()},
+    {"allow-empty-response", runtimeConfiguration.d_allowEmptyResponse},
+    {"control-socket", runtimeConfiguration.d_consoleServerAddress.toStringWithPort()},
+    {"ecs-override", runtimeConfiguration.d_ecsOverride},
+    {"ecs-source-prefix-v4", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV4)},
+    {"ecs-source-prefix-v6", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV6)},
+    {"fixup-case", runtimeConfiguration.d_fixupCase},
+    {"max-outstanding", static_cast<double>(immutableConfig.d_maxUDPOutstanding)},
+    {"server-policy", runtimeConfiguration.d_lbPolicy->getName()},
+    {"stale-cache-entries-ttl", static_cast<double>(runtimeConfiguration.d_staleCacheEntriesTTL)},
+    {"tcp-recv-timeout", static_cast<double>(runtimeConfiguration.d_tcpRecvTimeout)},
+    {"tcp-send-timeout", static_cast<double>(runtimeConfiguration.d_tcpSendTimeout)},
+    {"truncate-tc", runtimeConfiguration.d_truncateTC},
+    {"verbose", runtimeConfiguration.d_verbose},
+    {"verbose-health-checks", runtimeConfiguration.d_verboseHealthChecks}};
   for (const auto& item : configEntries) {
     if (const auto& bval = boost::get<bool>(&item.second)) {
       doc.emplace_back(Json::object{
@@ -1508,7 +1494,9 @@ static void handleAllowFrom(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
         if (resp.status == 200) {
           infolog("Updating the ACL via the API to %s", nmg.toString());
-          g_ACL.setState(nmg);
+          dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+            config.d_ACL = nmg;
+          });
           apiSaveACL(nmg);
         }
       }
@@ -1521,7 +1509,7 @@ static void handleAllowFrom(const YaHTTP::Request& req, YaHTTP::Response& resp)
     }
   }
   if (resp.status == 200) {
-    auto aclEntries = g_ACL.getLocal()->toStringVector();
+    auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
 
     Json::object obj{
       {"type", "ConfigSetting"},
@@ -1584,7 +1572,7 @@ static void handleCacheManagement(const YaHTTP::Request& req, YaHTTP::Response&
 
   std::shared_ptr<ServerPool> pool;
   try {
-    pool = getPool(g_pools.getCopy(), poolName->second);
+    pool = getPool(poolName->second);
   }
   catch (const std::exception& e) {
     resp.status = 404;
@@ -1717,14 +1705,20 @@ static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp)
 }
 
 using WebHandler = std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>;
-static SharedLockGuarded<std::unordered_map<std::string, WebHandler>> s_webHandlers;
+struct WebHandlerContext
+{
+  WebHandler d_handler;
+  bool d_isLua{false};
+};
+
+static SharedLockGuarded<std::unordered_map<std::string, WebHandlerContext>> s_webHandlers;
 
-void registerWebHandler(const std::string& endpoint, WebHandler handler);
+void registerWebHandler(const std::string& endpoint, WebHandler handler, bool isLua = false);
 
-void registerWebHandler(const std::string& endpoint, WebHandler handler)
+void registerWebHandler(const std::string& endpoint, WebHandler handler, bool isLua)
 {
   auto handlers = s_webHandlers.write_lock();
-  (*handlers)[endpoint] = std::move(handler);
+  (*handlers)[endpoint] = WebHandlerContext{std::move(handler), isLua};
 }
 
 void clearWebHandlers()
@@ -1839,10 +1833,9 @@ static void connectionThread(WebClientConnection&& conn)
     resp.version = req.version;
 
     {
-      auto config = g_webserverConfig.lock();
-
-      addCustomHeaders(resp, config->customHeaders);
-      addSecurityHeaders(resp, config->customHeaders);
+      const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+      addCustomHeaders(resp, config.d_webCustomHeaders);
+      addSecurityHeaders(resp, config.d_webCustomHeaders);
     }
     /* indicate that the connection will be closed after completion of the response */
     resp.headers["Connection"] = "close";
@@ -1868,17 +1861,23 @@ static void connectionThread(WebClientConnection&& conn)
       resp.status = 405;
     }
     else {
-      WebHandler handler;
+      std::optional<WebHandlerContext> handlerCtx{std::nullopt};
       {
         auto handlers = s_webHandlers.read_lock();
         const auto webHandlersIt = handlers->find(req.url.path);
         if (webHandlersIt != handlers->end()) {
-          handler = webHandlersIt->second;
+          handlerCtx = webHandlersIt->second;
         }
       }
 
-      if (handler) {
-        handler(req, resp);
+      if (handlerCtx) {
+        if (handlerCtx->d_isLua) {
+          auto lua = g_lua.lock();
+          handlerCtx->d_handler(req, resp);
+        }
+        else {
+          handlerCtx->d_handler(req, resp);
+        }
       }
       else {
         resp.status = 404;
@@ -1901,64 +1900,21 @@ static void connectionThread(WebClientConnection&& conn)
   }
 }
 
-void setWebserverAPIKey(std::unique_ptr<CredentialsHolder>&& apiKey)
-{
-  auto config = g_webserverConfig.lock();
-
-  if (apiKey) {
-    config->apiKey = std::move(apiKey);
-  }
-  else {
-    config->apiKey.reset();
-  }
-}
-
-void setWebserverPassword(std::unique_ptr<CredentialsHolder>&& password)
-{
-  g_webserverConfig.lock()->password = std::move(password);
-}
-
-void setWebserverACL(const std::string& acl)
-{
-  NetmaskGroup newACL;
-  newACL.toMasks(acl);
-
-  g_webserverConfig.lock()->acl = std::move(newACL);
-}
-
-void setWebserverCustomHeaders(const boost::optional<std::unordered_map<std::string, std::string>>& customHeaders)
-{
-  g_webserverConfig.lock()->customHeaders = customHeaders;
-}
-
-void setWebserverStatsRequireAuthentication(bool require)
-{
-  g_webserverConfig.lock()->statsRequireAuthentication = require;
-}
-
-void setWebserverAPIRequiresAuthentication(bool require)
-{
-  g_webserverConfig.lock()->apiRequiresAuthentication = require;
-}
-
-void setWebserverDashboardRequiresAuthentication(bool require)
-{
-  g_webserverConfig.lock()->dashboardRequiresAuthentication = require;
-}
-
-void setWebserverMaxConcurrentConnections(size_t max)
+void setMaxConcurrentConnections(size_t max)
 {
   s_connManager.setMaxConcurrentConnections(max);
 }
 
-void dnsdistWebserverThread(int sock, const ComboAddress& local)
+void WebserverThread(Socket sock)
 {
   setThreadName("dnsdist/webserv");
+  //coverity[auto_causes_copy]
+  const auto local = *dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress;
   infolog("Webserver launched on %s", local.toStringWithPort());
 
   {
-    auto config = g_webserverConfig.lock();
-    if (!config->password && config->dashboardRequiresAuthentication) {
+    const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (!config.d_webPassword && config.d_dashboardRequiresAuthentication) {
       warnlog("Webserver launched on %s without a password set!", local.toStringWithPort());
     }
   }
@@ -1966,7 +1922,7 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local)
   for (;;) {
     try {
       ComboAddress remote(local);
-      int fileDesc = SAccept(sock, remote);
+      int fileDesc = SAccept(sock.getHandle(), remote);
 
       if (!isClientAllowedByACL(remote)) {
         vinfolog("Connection to webserver from client %s is not allowed, closing", remote.toStringWithPort());
@@ -1985,3 +1941,4 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local)
     }
   }
 }
+}
index d707e464c52e71461473aa541460b377e09a89cd..9acff20f9807cd0a7893d0242edddcabd2e8d553 100644 (file)
@@ -2,21 +2,14 @@
 
 #include "credentials.hh"
 #include "dnsdist-prometheus.hh"
+#include "sstuff.hh"
 
-void setWebserverAPIKey(std::unique_ptr<CredentialsHolder>&& apiKey);
-void setWebserverPassword(std::unique_ptr<CredentialsHolder>&& password);
-void setWebserverACL(const std::string& acl);
-void setWebserverCustomHeaders(const boost::optional<std::unordered_map<std::string, std::string> >& customHeaders);
-void setWebserverAPIRequiresAuthentication(bool);
-void setWebserverDashboardRequiresAuthentication(bool);
-void setWebserverStatsRequireAuthentication(bool);
-void setWebserverMaxConcurrentConnections(size_t);
-
-void dnsdistWebserverThread(int sock, const ComboAddress& local);
-
+namespace dnsdist::webserver
+{
+void WebserverThread(Socket sock);
+void setMaxConcurrentConnections(size_t max);
 void registerBuiltInWebHandlers();
 void clearWebHandlers();
-
-std::string getWebserverConfig();
-
+std::string getConfig();
 bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def);
+}
index 8ef59833a19689a106ed6f6757cb380963cc9219..5572ce61e102d499353546948a5e74db23d265fd 100644 (file)
@@ -39,8 +39,6 @@ void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<Xs
 {
   try {
     setThreadName("dnsdist/XskResp");
-    auto localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-    auto localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
     auto pollfds = getPollFdsForWorker(*xskInfo);
     while (!dss->isStopped()) {
       poll(pollfds.data(), pollfds.size(), -1);
@@ -48,11 +46,7 @@ void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<Xs
       if ((pollfds[0].revents & POLLIN) != 0) {
         needNotify = true;
         xskInfo->cleanSocketNotification();
-#if defined(__SANITIZE_THREAD__)
-        xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
-        xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
+        xskInfo->processIncomingFrames([&](XskPacket& packet) {
           if (packet.getDataLen() < sizeof(dnsheader)) {
             xskInfo->markAsFree(packet);
             return;
@@ -75,9 +69,9 @@ void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<Xs
             /* fallback to sending the packet via normal socket */
             ids->xskPacketHeader.clear();
           }
-          if (!processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids))) {
+          if (!processResponderPacket(dss, response, std::move(*ids))) {
             xskInfo->markAsFree(packet);
-            infolog("XSK packet pushed to queue because processResponderPacket failed");
+            vinfolog("XSK packet dropped because processResponderPacket failed");
             return;
           }
           if (response.size() > packet.getCapacity()) {
@@ -114,11 +108,11 @@ void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<Xs
   }
 }
 
-bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol)
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, bool& expectProxyProtocol)
 {
   const auto& from = packet.getFromAddr();
   expectProxyProtocol = expectProxyProtocolFrom(from);
-  if (!holders.acl->match(from) && !expectProxyProtocol) {
+  if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(from) && !expectProxyProtocol) {
     vinfolog("Query from %s dropped because of ACL", from.toStringWithPort());
     ++dnsdist::metrics::g_stats.aclDrops;
     return false;
@@ -171,11 +165,7 @@ void XskRouter(std::shared_ptr<XskSocket> xsk)
         if ((fds.at(fdIndex).revents & POLLIN) != 0) {
           ready--;
           const auto& info = xsk->getWorkerByDescriptor(fds.at(fdIndex).fd);
-#if defined(__SANITIZE_THREAD__)
-          info->outgoingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
-          info->outgoingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
+          info->processOutgoingFrames([&](XskPacket& packet) {
             if ((packet.getFlags() & XskPacket::UPDATE) == 0) {
               xsk->markAsFree(packet);
               return;
@@ -204,22 +194,13 @@ void XskClientThread(ClientState* clientState)
 {
   setThreadName("dnsdist/xskClient");
   auto xskInfo = clientState->xskInfo;
-  LocalHolders holders;
 
   for (;;) {
-#if defined(__SANITIZE_THREAD__)
-    while (xskInfo->incomingPacketsQueue.lock()->read_available() == 0U) {
-#else
-    while (xskInfo->incomingPacketsQueue.read_available() == 0U) {
-#endif
+    while (!xskInfo->hasIncomingFrames()) {
       xskInfo->waitForXskSocket();
     }
-#if defined(__SANITIZE_THREAD__)
-    xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
-#else
-    xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
-#endif
-      if (XskProcessQuery(*clientState, holders, packet)) {
+    xskInfo->processIncomingFrames([&](XskPacket& packet) {
+      if (XskProcessQuery(*clientState, packet)) {
         packet.updatePacket();
         xskInfo->pushToSendQueue(packet);
       }
index f677b78604dc3d72691a5f5f5d636628cc97cb50..4a08533d3a16905c7eac5c04f8a0f2ac7d94ecdc 100644 (file)
@@ -33,8 +33,8 @@ class XskWorker;
 namespace dnsdist::xsk
 {
 void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<XskWorker> xskInfo);
-bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol);
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet);
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, bool& expectProxyProtocol);
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet);
 void XskRouter(std::shared_ptr<XskSocket> xsk);
 void XskClientThread(ClientState* clientState);
 void addDestinationAddress(const ComboAddress& addr);
index 6e5ca522488c1103ea0bf2673bb66a953b892e45..0efef3add929eac901134e9e9eaa7ab6d9d670b3 100644 (file)
 #include <sys/resource.h>
 #include <unistd.h>
 
-#ifdef HAVE_LIBEDIT
-#if defined(__OpenBSD__) || defined(__NetBSD__)
-// If this is not undeffed, __attribute__ wil be redefined by /usr/include/readline/rlstdc.h
-#undef __STRICT_ANSI__
-#include <readline/readline.h>
-#else
-#include <editline/readline.h>
-#endif
-#endif /* HAVE_LIBEDIT */
-
 #include "dnsdist-systemd.hh"
 #ifdef HAVE_SYSTEMD
 #include <systemd/sd-daemon.h>
 #include "dnsdist-async.hh"
 #include "dnsdist-cache.hh"
 #include "dnsdist-carbon.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-console.hh"
 #include "dnsdist-crypto.hh"
 #include "dnsdist-discovery.hh"
-#include "dnsdist-dnsparser.hh"
 #include "dnsdist-dynblocks.hh"
 #include "dnsdist-ecs.hh"
 #include "dnsdist-edns.hh"
+#include "dnsdist-frontend.hh"
 #include "dnsdist-healthchecks.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-lua-hooks.hh"
@@ -67,7 +58,9 @@
 #include "dnsdist-random.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-secpoll.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
+#include "dnsdist-tcp-downstream.hh"
 #include "dnsdist-web.hh"
 #include "dnsdist-xsk.hh"
 
@@ -78,7 +71,6 @@
 #include "doh.hh"
 #include "dolog.hh"
 #include "dnsname.hh"
-#include "dnsparser.hh"
 #include "ednsoptions.hh"
 #include "gettime.hh"
 #include "lock.hh"
    on the Lua side we can't do that. */
 
 using std::thread;
-bool g_verbose;
 
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-uint32_t g_staleCacheEntriesTTL{0};
-bool g_allowEmptyResponse{false};
-
-GlobalStateHolder<NetmaskGroup> g_ACL;
 string g_outputBuffer;
 
-std::vector<std::shared_ptr<TLSFrontend>> g_tlslocals;
-std::vector<std::shared_ptr<DOHFrontend>> g_dohlocals;
-std::vector<std::shared_ptr<DOQFrontend>> g_doqlocals;
-std::vector<std::shared_ptr<DOH3Frontend>> g_doh3locals;
-std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
-
 shared_ptr<BPFFilter> g_defaultBPFFilter{nullptr};
-std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
 
-std::vector<std::unique_ptr<ClientState>> g_frontends;
-GlobalStateHolder<pools_t> g_pools;
-size_t g_udpVectorSize{1};
-std::vector<uint32_t> g_TCPFastOpenKey;
 /* UDP: the grand design. Per socket we listen on for incoming queries there is one thread.
    Then we have a bunch of connected sockets for talking to downstream servers.
    We send directly to those sockets.
@@ -138,18 +113,6 @@ std::vector<uint32_t> g_TCPFastOpenKey;
  */
 
 Rings g_rings;
-QueryCount g_qcount;
-
-GlobalStateHolder<servers_t> g_dstates;
-
-bool g_servFailOnNoPolicy{false};
-bool g_truncateTC{false};
-bool g_fixupCase{false};
-bool g_dropEmptyQueries{false};
-uint32_t g_socketUDPSendBuffer{0};
-uint32_t g_socketUDPRecvBuffer{0};
-
-std::set<std::string> g_capabilitiesToRetain;
 
 // we are not willing to receive a bigger UDP response than that, no matter what
 static constexpr size_t s_maxUDPResponsePacketSize{4096U};
@@ -177,14 +140,14 @@ static void sendfromto(int sock, const PacketBuffer& buffer, const ComboAddress&
   }
 }
 
-static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength)
+static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength, bool addEDNSToSelfGeneratedResponses)
 {
   try {
     bool hadEDNS = false;
     uint16_t payloadSize = 0;
     uint16_t zValue = 0;
 
-    if (g_addEDNSToSelfGeneratedResponses) {
+    if (addEDNSToSelfGeneratedResponses) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
       hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(packet.data()), packet.size(), &payloadSize, &zValue);
     }
@@ -222,42 +185,10 @@ struct DelayedPacket
 static std::unique_ptr<DelayPipe<DelayedPacket>> g_delay{nullptr};
 #endif /* DISABLE_DELAY_PIPE */
 
-std::string DNSQuestion::getTrailingData() const
-{
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-  const auto* message = reinterpret_cast<const char*>(this->getData().data());
-  const uint16_t messageLen = getDNSPacketLength(message, this->getData().size());
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  return {message + messageLen, this->getData().size() - messageLen};
-}
-
-bool DNSQuestion::setTrailingData(const std::string& tail)
-{
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-  const char* message = reinterpret_cast<const char*>(this->data.data());
-  const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
-  this->data.resize(messageLen);
-  if (!tail.empty()) {
-    if (!hasRoomFor(tail.size())) {
-      return false;
-    }
-    this->data.insert(this->data.end(), tail.begin(), tail.end());
-  }
-  return true;
-}
-
-bool DNSQuestion::editHeader(const std::function<bool(dnsheader&)>& editFunction)
-{
-  if (data.size() < sizeof(dnsheader)) {
-    throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
-  }
-  return dnsdist::PacketMangling::editDNSHeaderFromPacket(data, editFunction);
-}
-
 static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
 {
-  constexpr auto doAvg = [](double& var, double n, double weight) {
-    var = (weight - 1) * var / weight + n / weight;
+  constexpr auto doAvg = [](pdns::stat_double_t& var, double n, double weight) {
+    var.store((weight - 1) * var.load() / weight + n / weight);
   };
 
   if (protocol == dnsdist::Protocol::DoUDP || protocol == dnsdist::Protocol::DNSCryptUDP) {
@@ -320,7 +251,7 @@ static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
   }
 }
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
 {
   if (response.size() < sizeof(dnsheader)) {
     return false;
@@ -336,7 +267,7 @@ bool responseContentMatches(const PacketBuffer& response, const DNSName& qname,
   }
 
   if (dnsHeader->qdcount == 0) {
-    if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || g_allowEmptyResponse) {
+    if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || allowEmptyResponse) {
       return true;
     }
 
@@ -407,7 +338,7 @@ static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t
     return true;
   }
 
-  if (g_fixupCase) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_fixupCase) {
     const auto& realname = qname.getStorage();
     if (response.size() >= (sizeof(dnsheader) + realname.length())) {
       memcpy(&response.at(sizeof(dnsheader)), realname.c_str(), realname.length());
@@ -532,7 +463,7 @@ bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>&
             header.qr = true;
             return true;
           });
-          truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+          truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
           ++dnsdist::metrics::g_stats.ruleTruncated;
           return true;
         }
@@ -550,7 +481,7 @@ bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>&
   return true;
 }
 
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
 {
   bool zeroScope = false;
   if (!fixUpResponse(response, dnsResponse.ids.qname, dnsResponse.ids.origFlags, dnsResponse.ids.ednsAdded, dnsResponse.ids.ecsAdded, dnsResponse.ids.useZeroScope ? &zeroScope : nullptr)) {
@@ -580,6 +511,8 @@ bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist
 
     dnsResponse.ids.packetCache->insert(cacheKey, zeroScope ? boost::none : dnsResponse.ids.subnet, dnsResponse.ids.cacheFlags, dnsResponse.ids.dnssecOK, dnsResponse.ids.qname, dnsResponse.ids.qtype, dnsResponse.ids.qclass, response, dnsResponse.ids.forwardedOverUDP, dnsResponse.getHeader()->rcode, dnsResponse.ids.tempFailureTTL);
 
+    const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+    const auto& cacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules);
     if (!applyRulesToResponse(cacheInsertedRespRuleActions, dnsResponse)) {
       return false;
     }
@@ -606,8 +539,11 @@ bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist
   return true;
 }
 
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
 {
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  const auto& respRuleActions = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::ResponseRules);
+
   if (!applyRulesToResponse(respRuleActions, dnsResponse)) {
     return false;
   }
@@ -616,18 +552,19 @@ bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::R
     return true;
   }
 
-  return processResponseAfterRules(response, cacheInsertedRespRuleActions, dnsResponse, muted);
+  return processResponseAfterRules(response, dnsResponse, muted);
 }
 
 static size_t getInitialUDPPacketBufferSize(bool expectProxyProtocol)
 {
-  static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
+  static_assert(dnsdist::configuration::s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
 
-  if (!expectProxyProtocol || g_proxyProtocolACL.empty()) {
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!expectProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
     return s_initialUDPPacketBufferSize;
   }
 
-  return s_initialUDPPacketBufferSize + g_proxyProtocolMaximumSize;
+  return s_initialUDPPacketBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
 }
 
 static size_t getMaximumIncomingPacketSize(const ClientState& clientState)
@@ -636,11 +573,12 @@ static size_t getMaximumIncomingPacketSize(const ClientState& clientState)
     return getInitialUDPPacketBufferSize(clientState.d_enableProxyProtocol);
   }
 
-  if (!clientState.d_enableProxyProtocol || g_proxyProtocolACL.empty()) {
-    return s_udpIncomingBufferSize;
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!clientState.d_enableProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
+    return dnsdist::configuration::s_udpIncomingBufferSize;
   }
 
-  return s_udpIncomingBufferSize + g_proxyProtocolMaximumSize;
+  return dnsdist::configuration::s_udpIncomingBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
 }
 
 bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
@@ -688,20 +626,20 @@ void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff,
   doLatencyStats(incomingProtocol, udiff);
 }
 
-static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, const std::shared_ptr<DownstreamState>& backend, bool isAsync, bool selfGenerated)
+static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& response, const std::shared_ptr<DownstreamState>& backend, bool isAsync, bool selfGenerated)
 {
   DNSResponse dnsResponse(ids, response, backend);
 
   if (ids.udpPayloadSize > 0 && response.size() > ids.udpPayloadSize) {
     vinfolog("Got a response of size %d while the initial UDP payload size was %d, truncating", response.size(), ids.udpPayloadSize);
-    truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+    truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
     dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsResponse.getMutableData(), [](dnsheader& header) {
       header.tc = true;
       return true;
     });
   }
-  else if (dnsResponse.getHeader()->tc && g_truncateTC) {
-    truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+  else if (dnsResponse.getHeader()->tc && dnsdist::configuration::getCurrentRuntimeConfiguration().d_truncateTC) {
+    truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
   }
 
   /* when the answer is encrypted in place, we need to get a copy
@@ -710,7 +648,7 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
   memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
 
   if (!isAsync) {
-    if (!processResponse(response, respRuleActions, cacheInsertedRespRuleActions, dnsResponse, ids.cs != nullptr && ids.cs->muted)) {
+    if (!processResponse(response, dnsResponse, ids.cs != nullptr && ids.cs->muted)) {
       return;
     }
 
@@ -751,13 +689,13 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
   }
 }
 
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids)
 {
 
   const dnsheader_aligned dnsHeader(response.data());
   auto queryId = dnsHeader->id;
 
-  if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss)) {
+  if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss, dnsdist::configuration::getCurrentRuntimeConfiguration().d_allowEmptyResponse)) {
     dss->restoreState(queryId, std::move(ids));
     return false;
   }
@@ -783,7 +721,7 @@ bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer&
     return false;
   }
 
-  handleResponseForUDPClient(ids, response, localRespRuleActions, cacheInsertedRespRuleActions, dss, false, false);
+  handleResponseForUDPClient(ids, response, dss, false, false);
   return true;
 }
 
@@ -792,8 +730,6 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
 {
   try {
     setThreadName("dnsdist/respond");
-    auto localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-    auto localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
     const size_t initialBufferSize = getInitialUDPPacketBufferSize(false);
     /* allocate one more byte so we can detect truncation */
     PacketBuffer response(initialBufferSize + 1);
@@ -852,9 +788,9 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
             continue;
           }
 
-          if (processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfo) {
+          if (processResponderPacket(dss, response, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfoResponder) {
 #ifdef HAVE_XSK
-            auto& xskInfo = ids->cs->xskInfo;
+            auto& xskInfo = ids->cs->xskInfoResponder;
             auto xskPacket = xskInfo->getEmptyFrame();
             if (!xskPacket) {
               continue;
@@ -888,8 +824,7 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
   }
 }
 
-LockGuarded<LuaContext> g_lua{LuaContext()};
-ComboAddress g_serverControl{"127.0.0.1:5199"};
+RecursiveLockGuarded<LuaContext> g_lua{LuaContext()};
 
 static void spoofResponseFromString(DNSQuestion& dnsQuestion, const string& spoofContent, bool raw)
 {
@@ -1054,30 +989,34 @@ static bool applyRulesChainToQuery(const std::vector<dnsdist::rules::RuleAction>
   return !drop;
 }
 
-static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, const timespec& now)
+static bool applyRulesToQuery(DNSQuestion& dnsQuestion, const timespec& now)
 {
   if (g_rings.shouldRecordQueries()) {
     g_rings.insertQuery(now, dnsQuestion.ids.origRemote, dnsQuestion.ids.qname, dnsQuestion.ids.qtype, dnsQuestion.getData().size(), *dnsQuestion.getHeader(), dnsQuestion.getProtocol());
   }
 
-  if (g_qcount.enabled) {
-    string qname = dnsQuestion.ids.qname.toLogString();
-    bool countQuery{true};
-    if (g_qcount.filter) {
-      auto lock = g_lua.lock();
-      std::tie(countQuery, qname) = g_qcount.filter(&dnsQuestion);
-    }
-
-    if (countQuery) {
-      auto records = g_qcount.records.write_lock();
-      if (records->count(qname) == 0) {
-        (*records)[qname] = 0;
+  {
+    const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (runtimeConfig.d_queryCountConfig.d_enabled) {
+      string qname = dnsQuestion.ids.qname.toLogString();
+      bool countQuery{true};
+      if (runtimeConfig.d_queryCountConfig.d_filter) {
+        auto lock = g_lua.lock();
+        std::tie(countQuery, qname) = runtimeConfig.d_queryCountConfig.d_filter(&dnsQuestion);
+      }
+
+      if (countQuery) {
+        auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
+        if (records->count(qname) == 0) {
+          (*records)[qname] = 0;
+        }
+        (*records)[qname]++;
       }
-      (*records)[qname]++;
     }
   }
 
 #ifndef DISABLE_DYNBLOCKS
+  const auto defaultDynBlockAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
   auto setRCode = [&dnsQuestion](uint8_t rcode) {
     dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [rcode](dnsheader& header) {
       header.rcode = rcode;
@@ -1087,7 +1026,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
   };
 
   /* the Dynamic Block mechanism supports address and port ranges, so we need to pass the full address and port */
-  if (auto* got = holders.dynNMGBlock->lookup(AddressAndPortRange(dnsQuestion.ids.origRemote, dnsQuestion.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
+  if (auto* got = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(dnsQuestion.ids.origRemote, dnsQuestion.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
     auto updateBlockStats = [&got]() {
       ++dnsdist::metrics::g_stats.dynBlocked;
       got->second.blocks++;
@@ -1096,7 +1035,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     if (now < got->second.until) {
       DNSAction::Action action = got->second.action;
       if (action == DNSAction::Action::None) {
-        action = g_dynBlockAction;
+        action = defaultDynBlockAction;
       }
 
       switch (action) {
@@ -1164,7 +1103,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     }
   }
 
-  if (auto* got = holders.dynSMTBlock->lookup(dnsQuestion.ids.qname)) {
+  if (auto* got = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(dnsQuestion.ids.qname)) {
     auto updateBlockStats = [&got]() {
       ++dnsdist::metrics::g_stats.dynBlocked;
       got->blocks++;
@@ -1173,7 +1112,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     if (now < got->until) {
       DNSAction::Action action = got->action;
       if (action == DNSAction::Action::None) {
-        action = g_dynBlockAction;
+        action = defaultDynBlockAction;
       }
       switch (action) {
       case DNSAction::Action::NoOp:
@@ -1239,7 +1178,9 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
   }
 #endif /* DISABLE_DYNBLOCKS */
 
-  return applyRulesChainToQuery(*holders.ruleactions, dnsQuestion);
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  const auto& queryRules = dnsdist::rules::getRuleChain(chains, dnsdist::rules::RuleChain::Rules);
+  return applyRulesChainToQuery(queryRules, dnsQuestion);
 }
 
 ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& backend, const int socketDesc, const PacketBuffer& request, bool healthCheck)
@@ -1280,7 +1221,7 @@ ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ba
   return result;
 }
 
-static bool isUDPQueryAcceptable(ClientState& clientState, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, bool& expectProxyProtocol)
+static bool isUDPQueryAcceptable(ClientState& clientState, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, bool& expectProxyProtocol)
 {
   if ((msgh->msg_flags & MSG_TRUNC) != 0) {
     /* message was too large for our buffer */
@@ -1291,7 +1232,7 @@ static bool isUDPQueryAcceptable(ClientState& clientState, LocalHolders& holders
   }
 
   expectProxyProtocol = clientState.d_enableProxyProtocol && expectProxyProtocolFrom(remote);
-  if (!holders.acl->match(remote) && !expectProxyProtocol) {
+  if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote) && !expectProxyProtocol) {
     vinfolog("Query from %s dropped because of ACL", remote.toStringWithPort());
     ++dnsdist::metrics::g_stats.aclDrops;
     return false;
@@ -1356,7 +1297,7 @@ bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientSta
 
   if (dnsHeader.qdcount == 0) {
     ++dnsdist::metrics::g_stats.emptyQueries;
-    if (g_dropEmptyQueries) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_dropEmptyQueries) {
       return false;
     }
   }
@@ -1391,14 +1332,17 @@ struct mmsghdr
 #endif
 
 /* self-generated responses or cache hits */
-static bool prepareOutgoingResponse(LocalHolders& holders, const ClientState& clientState, DNSQuestion& dnsQuestion, bool cacheHit)
+static bool prepareOutgoingResponse(const ClientState& clientState, DNSQuestion& dnsQuestion, bool cacheHit)
 {
   std::shared_ptr<DownstreamState> backend{nullptr};
   DNSResponse dnsResponse(dnsQuestion.ids, dnsQuestion.getMutableData(), backend);
   dnsResponse.d_incomingTCPState = dnsQuestion.d_incomingTCPState;
   dnsResponse.ids.selfGenerated = true;
 
-  if (!applyRulesToResponse(cacheHit ? *holders.cacheHitRespRuleactions : *holders.selfAnsweredRespRuleactions, dnsResponse)) {
+  const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+  const auto& cacheHitRespRules = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::CacheHitResponseRules);
+  const auto& selfAnsweredRespRules = dnsdist::rules::getResponseRuleChain(chains, dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules);
+  if (!applyRulesToResponse(cacheHit ? cacheHitRespRules : selfAnsweredRespRules, dnsResponse)) {
     return false;
   }
 
@@ -1431,11 +1375,11 @@ static bool prepareOutgoingResponse(LocalHolders& holders, const ClientState& cl
   return true;
 }
 
-static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion& dnsQuestion, LocalHolders& holders)
+static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion& dnsQuestion)
 {
   fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags);
 
-  if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) {
+  if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, false)) {
     return ProcessQueryResult::Drop;
   }
 
@@ -1455,30 +1399,30 @@ static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion&
   return ProcessQueryResult::SendAnswer;
 }
 
-static void selectBackendForOutgoingQuery(DNSQuestion& dnsQuestion, const std::shared_ptr<ServerPool>& serverPool, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+static void selectBackendForOutgoingQuery(DNSQuestion& dnsQuestion, const std::shared_ptr<ServerPool>& serverPool, std::shared_ptr<DownstreamState>& selectedBackend)
 {
   std::shared_ptr<ServerPolicy> poolPolicy = serverPool->policy;
-  const auto& policy = poolPolicy != nullptr ? *poolPolicy : *(holders.policy);
+  const auto& policy = poolPolicy != nullptr ? *poolPolicy : *dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
   const auto servers = serverPool->getServers();
   selectedBackend = policy.getSelectedBackend(*servers, dnsQuestion);
 }
 
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
 {
   const uint16_t queryId = ntohs(dnsQuestion.getHeader()->id);
 
   try {
     if (dnsQuestion.getHeader()->qr) { // something turned it into a response
-      return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders);
+      return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion);
     }
-    std::shared_ptr<ServerPool> serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName);
+    std::shared_ptr<ServerPool> serverPool = getPool(dnsQuestion.ids.poolName);
     dnsQuestion.ids.packetCache = serverPool->packetCache;
-    selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend);
+    selectBackendForOutgoingQuery(dnsQuestion, serverPool, selectedBackend);
 
-    uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
+    uint32_t allowExpired = selectedBackend ? 0 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_staleCacheEntriesTTL;
 
     if (dnsQuestion.ids.packetCache && !dnsQuestion.ids.skipCache) {
-      dnsQuestion.ids.dnssecOK = (getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0;
+      dnsQuestion.ids.dnssecOK = (dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0;
     }
 
     if (dnsQuestion.useECS && ((selectedBackend && selectedBackend->d_config.useECS) || (!selectedBackend && serverPool->getECS()))) {
@@ -1490,7 +1434,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
 
           vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), dnsQuestion.ids.protocol.toString(), dnsQuestion.getData().size());
 
-          if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+          if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
             return ProcessQueryResult::Drop;
           }
 
@@ -1528,7 +1472,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
 
         vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), dnsQuestion.ids.protocol.toString(), dnsQuestion.getData().size());
 
-        if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+        if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
           return ProcessQueryResult::Drop;
         }
 
@@ -1539,7 +1483,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
       if (dnsQuestion.ids.protocol == dnsdist::Protocol::DoH && !forwardedOverUDP) {
         /* do a second-lookup for UDP responses, but we do not want TC=1 answers */
         if (dnsQuestion.ids.packetCache->get(dnsQuestion, dnsQuestion.getHeader()->id, &dnsQuestion.ids.cacheKeyUDP, dnsQuestion.ids.subnet, dnsQuestion.ids.dnssecOK, true, allowExpired, false, false, true)) {
-          if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, true)) {
+          if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, true)) {
             return ProcessQueryResult::Drop;
           }
 
@@ -1553,27 +1497,32 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
 
       ++dnsdist::metrics::g_stats.cacheMisses;
 
+      //coverity[auto_causes_copy]
       const auto existingPool = dnsQuestion.ids.poolName;
-      if (!applyRulesChainToQuery(*holders.cacheMissRuleActions, dnsQuestion)) {
+      const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains;
+      const auto& cacheMissRuleActions = dnsdist::rules::getRuleChain(chains, dnsdist::rules::RuleChain::CacheMissRules);
+
+      if (!applyRulesChainToQuery(cacheMissRuleActions, dnsQuestion)) {
         return ProcessQueryResult::Drop;
       }
       if (dnsQuestion.getHeader()->qr) { // something turned it into a response
-        return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders);
+        return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion);
       }
       /* let's be nice and allow the selection of a different pool,
          but no second cache-lookup for you */
       if (dnsQuestion.ids.poolName != existingPool) {
-        serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName);
+        serverPool = getPool(dnsQuestion.ids.poolName);
         dnsQuestion.ids.packetCache = serverPool->packetCache;
-        selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend);
+        selectBackendForOutgoingQuery(dnsQuestion, serverPool, selectedBackend);
       }
     }
 
     if (!selectedBackend) {
+      auto servFailOnNoPolicy = dnsdist::configuration::getCurrentRuntimeConfiguration().d_servFailOnNoPolicy;
       ++dnsdist::metrics::g_stats.noPolicy;
 
-      vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
-      if (g_servFailOnNoPolicy) {
+      vinfolog("%s query for %s|%s from %s, no downstream server available", servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
+      if (servFailOnNoPolicy) {
         dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
           header.rcode = RCode::ServFail;
           header.qr = true;
@@ -1582,7 +1531,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
 
         fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags);
 
-        if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) {
+        if (!prepareOutgoingResponse(*dnsQuestion.ids.cs, dnsQuestion, false)) {
           return ProcessQueryResult::Drop;
         }
         ++dnsdist::metrics::g_stats.responses;
@@ -1636,10 +1585,7 @@ public:
 
     auto& ids = response.d_idstate;
 
-    static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-    static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
-    handleResponseForUDPClient(ids, response.d_buffer, *localRespRuleActions, *localCacheInsertedRespRuleActions, response.d_ds, response.isAsync(), response.d_idstate.selfGenerated);
+    handleResponseForUDPClient(ids, response.d_buffer, response.d_ds, response.isAsync(), response.d_idstate.selfGenerated);
   }
 
   void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
@@ -1695,7 +1641,7 @@ std::unique_ptr<CrossProtocolQuery> getUDPCrossProtocolQueryFromDQ(DNSQuestion&
   return std::make_unique<UDPCrossProtocolQuery>(std::move(dnsQuestion.getMutableData()), std::move(dnsQuestion.ids), nullptr);
 }
 
-ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
 {
   const uint16_t queryId = ntohs(dnsQuestion.getHeader()->id);
 
@@ -1712,10 +1658,10 @@ ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders,
         header.qr = true;
         return true;
       });
-      return processQueryAfterRules(dnsQuestion, holders, selectedBackend);
+      return processQueryAfterRules(dnsQuestion, selectedBackend);
     }
 
-    if (!applyRulesToQuery(holders, dnsQuestion, now)) {
+    if (!applyRulesToQuery(dnsQuestion, now)) {
       return ProcessQueryResult::Drop;
     }
 
@@ -1723,7 +1669,7 @@ ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders,
       return ProcessQueryResult::Asynchronous;
     }
 
-    return processQueryAfterRules(dnsQuestion, holders, selectedBackend);
+    return processQueryAfterRules(dnsQuestion, selectedBackend);
   }
   catch (const std::exception& e) {
     vinfolog("Got an error while parsing a %s query from %s, id %d: %s", (dnsQuestion.overTCP() ? "TCP" : "UDP"), dnsQuestion.ids.origRemote.toStringWithPort(), queryId, e.what());
@@ -1797,7 +1743,7 @@ bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstrea
   return true;
 }
 
-static void processUDPQuery(ClientState& clientState, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, PacketBuffer& query, std::vector<mmsghdr>* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
+static void processUDPQuery(ClientState& clientState, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, PacketBuffer& query, std::vector<mmsghdr>* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
 {
   assert(responsesVect == nullptr || (queuedResponses != nullptr && respIOV != nullptr && respCBuf != nullptr));
   uint16_t queryId = 0;
@@ -1809,7 +1755,7 @@ static void processUDPQuery(ClientState& clientState, LocalHolders& holders, con
 
   try {
     bool expectProxyProtocol = false;
-    if (!isUDPQueryAcceptable(clientState, holders, msgh, remote, dest, expectProxyProtocol)) {
+    if (!isUDPQueryAcceptable(clientState, msgh, remote, dest, expectProxyProtocol)) {
       return;
     }
     /* dest might have been updated, if we managed to harvest the destination address */
@@ -1828,7 +1774,7 @@ static void processUDPQuery(ClientState& clientState, LocalHolders& holders, con
     }
 
     std::vector<ProxyProtocolValue> proxyProtocolValues;
-    if (expectProxyProtocol && !handleProxyProtocol(remote, false, *holders.acl, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
+    if (expectProxyProtocol && !handleProxyProtocol(remote, false, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
       return;
     }
 
@@ -1875,7 +1821,7 @@ static void processUDPQuery(ClientState& clientState, LocalHolders& holders, con
     }
 
     std::shared_ptr<DownstreamState> backend{nullptr};
-    auto result = processQuery(dnsQuestion, holders, backend);
+    auto result = processQuery(dnsQuestion, backend);
 
     if (result == ProcessQueryResult::Drop || result == ProcessQueryResult::Asynchronous) {
       return;
@@ -1931,7 +1877,7 @@ static void processUDPQuery(ClientState& clientState, LocalHolders& holders, con
 #ifdef HAVE_XSK
 namespace dnsdist::xsk
 {
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet)
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet)
 {
   uint16_t queryId = 0;
   const auto& remote = packet.getFromAddr();
@@ -1947,13 +1893,13 @@ bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket&
 
   try {
     bool expectProxyProtocol = false;
-    if (!XskIsQueryAcceptable(packet, clientState, holders, expectProxyProtocol)) {
+    if (!XskIsQueryAcceptable(packet, clientState, expectProxyProtocol)) {
       return false;
     }
 
     auto query = packet.clonePacketBuffer();
     std::vector<ProxyProtocolValue> proxyProtocolValues;
-    if (expectProxyProtocol && !handleProxyProtocol(remote, false, *holders.acl, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
+    if (expectProxyProtocol && !handleProxyProtocol(remote, false, dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
       return false;
     }
 
@@ -1998,7 +1944,7 @@ bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket&
       dnsQuestion.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
     }
     std::shared_ptr<DownstreamState> backend{nullptr};
-    auto result = processQuery(dnsQuestion, holders, backend);
+    auto result = processQuery(dnsQuestion, backend);
 
     if (result == ProcessQueryResult::Drop) {
       return false;
@@ -2059,7 +2005,7 @@ bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket&
 
 #ifndef DISABLE_RECVMMSG
 #if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-static void MultipleMessagesUDPClientThread(ClientState* clientState, LocalHolders& holders)
+static void MultipleMessagesUDPClientThread(ClientState* clientState)
 {
   struct MMReceiver
   {
@@ -2070,7 +2016,7 @@ static void MultipleMessagesUDPClientThread(ClientState* clientState, LocalHolde
     /* used by HarvestDestinationAddress */
     cmsgbuf_aligned cbuf{};
   };
-  const size_t vectSize = g_udpVectorSize;
+  const size_t vectSize = dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize;
 
   if (vectSize > std::numeric_limits<uint16_t>::max()) {
     throw std::runtime_error("The value of setUDPMultipleMessagesVectorSize is too high, the maximum value is " + std::to_string(std::numeric_limits<uint16_t>::max()));
@@ -2131,7 +2077,7 @@ static void MultipleMessagesUDPClientThread(ClientState* clientState, LocalHolde
       }
 
       recvData[msgIdx].packet.resize(got);
-      processUDPQuery(*clientState, holders, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, &outMsgVec, &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
+      processUDPQuery(*clientState, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, &outMsgVec, &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
     }
 
     /* immediate (not delayed or sent to a backend) responses (mostly from a rule, dynamic block
@@ -2154,11 +2100,10 @@ static void udpClientThread(std::vector<ClientState*> states)
 {
   try {
     setThreadName("dnsdist/udpClie");
-    LocalHolders holders;
 #ifndef DISABLE_RECVMMSG
 #if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-    if (g_udpVectorSize > 1) {
-      MultipleMessagesUDPClientThread(states.at(0), holders);
+    if (dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize > 1) {
+      MultipleMessagesUDPClientThread(states.at(0));
     }
     else
 #endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */
@@ -2183,7 +2128,7 @@ static void udpClientThread(std::vector<ClientState*> states)
       ComboAddress remote;
       ComboAddress dest;
 
-      auto handleOnePacket = [&packet, &iov, &holders, &msgh, &remote, &dest, initialBufferSize](const UDPStateParam& param) {
+      auto handleOnePacket = [&packet, &iov, &msgh, &remote, &dest, initialBufferSize](const UDPStateParam& param) {
         packet.resize(initialBufferSize);
         iov.iov_base = &packet.at(0);
         iov.iov_len = packet.size();
@@ -2198,7 +2143,7 @@ static void udpClientThread(std::vector<ClientState*> states)
 
         packet.resize(static_cast<size_t>(got));
 
-        processUDPQuery(*param.cs, holders, &msgh, remote, dest, packet, nullptr, nullptr, nullptr, nullptr);
+        processUDPQuery(*param.cs, &msgh, remote, dest, packet, nullptr, nullptr, nullptr, nullptr);
       };
 
       std::vector<UDPStateParam> params;
@@ -2268,10 +2213,6 @@ static void udpClientThread(std::vector<ClientState*> states)
   }
 }
 
-boost::optional<uint64_t> g_maxTCPClientThreads{boost::none};
-pdns::stat16_t g_cacheCleaningDelay{60};
-pdns::stat16_t g_cacheCleaningPercentage{100};
-
 static void maintThread()
 {
   setThreadName("dnsdist/main");
@@ -2302,15 +2243,15 @@ static void maintThread()
     }
 
     counter++;
-    if (counter >= g_cacheCleaningDelay) {
+    if (counter >= dnsdist::configuration::getCurrentRuntimeConfiguration().d_cacheCleaningDelay) {
       /* keep track, for each cache, of whether we should keep
        expired entries */
       std::map<std::shared_ptr<DNSDistPacketCache>, bool> caches;
 
       /* gather all caches actually used by at least one pool, and see
          if something prevents us from cleaning the expired entries */
-      auto localPools = g_pools.getLocal();
-      for (const auto& entry : *localPools) {
+      const auto& pools = dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools;
+      for (const auto& entry : pools) {
         const auto& pool = entry.second;
 
         auto packetCache = pool->packetCache;
@@ -2338,7 +2279,7 @@ static void maintThread()
           continue;
         }
         const auto& packetCache = pair.first;
-        size_t upTo = (packetCache->getMaxEntries() * (100 - g_cacheCleaningPercentage)) / 100;
+        size_t upTo = (packetCache->getMaxEntries() * (100 - dnsdist::configuration::getCurrentRuntimeConfiguration().d_cacheCleaningPercentage)) / 100;
         packetCache->purgeExpired(upTo, now);
       }
       counter = 0;
@@ -2361,13 +2302,15 @@ static void secPollThread()
   setThreadName("dnsdist/secpoll");
 
   for (;;) {
+    const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+
     try {
-      doSecPoll(g_secPollSuffix);
+      dnsdist::secpoll::doSecPoll(runtimeConfig.d_secPollSuffix);
     }
     catch (...) {
     }
     // coverity[store_truncates_time_t]
-    std::this_thread::sleep_for(std::chrono::seconds(g_secPollInterval));
+    std::this_thread::sleep_for(std::chrono::seconds(runtimeConfig.d_secPollInterval));
   }
 }
 #endif /* DISABLE_SECPOLL */
@@ -2382,7 +2325,6 @@ static void healthChecksThread()
     .tv_sec = 0,
     .tv_usec = 0
   };
-  auto states = g_dstates.getLocal(); // this points to the actual shared_ptrs!
 
   for (;;) {
     timeval now{};
@@ -2397,7 +2339,10 @@ static void healthChecksThread()
     }
 
     std::unique_ptr<FDMultiplexer> mplexer{nullptr};
-    for (const auto& dss : *states) {
+    // this points to the actual shared_ptrs!
+    //coverity[auto_causes_copy]
+    const auto servers = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
+    for (const auto& dss : servers) {
       dss->updateStatisticsInfo();
 
       dss->handleUDPTimeouts();
@@ -2407,7 +2352,7 @@ static void healthChecksThread()
       }
 
       if (!mplexer) {
-        mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(states->size()));
+        mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(servers.size()));
       }
 
       if (!queueHealthCheck(mplexer, dss)) {
@@ -2477,30 +2422,31 @@ static void dropUserPrivs(uid_t uid)
 
 static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCount)
 {
+  const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
   /* stdin, stdout, stderr */
   rlim_t requiredFDsCount = 3;
-  auto backends = g_dstates.getLocal();
+  const auto& backends = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends;
   /* UDP sockets to backends */
   size_t backendUDPSocketsCount = 0;
-  for (const auto& backend : *backends) {
+  for (const auto& backend : backends) {
     backendUDPSocketsCount += backend->sockets.size();
   }
   requiredFDsCount += backendUDPSocketsCount;
   /* TCP sockets to backends */
-  if (g_maxTCPClientThreads) {
-    requiredFDsCount += (backends->size() * (*g_maxTCPClientThreads));
+  if (immutableConfig.d_maxTCPClientThreads > 0) {
+    requiredFDsCount += (backends.size() * immutableConfig.d_maxTCPClientThreads);
   }
   /* listening sockets */
   requiredFDsCount += udpBindsCount;
   requiredFDsCount += tcpBindsCount;
   /* number of TCP connections currently served, assuming 1 connection per worker thread which is of course not right */
-  if (g_maxTCPClientThreads) {
-    requiredFDsCount += *g_maxTCPClientThreads;
+  if (immutableConfig.d_maxTCPClientThreads > 0) {
+    requiredFDsCount += immutableConfig.d_maxTCPClientThreads;
     /* max pipes for communicating between TCP acceptors and client threads */
-    requiredFDsCount += (*g_maxTCPClientThreads * 2);
+    requiredFDsCount += (immutableConfig.d_maxTCPClientThreads * 2);
   }
   /* max TCP queued connections */
-  requiredFDsCount += g_maxTCPQueuedConnections;
+  requiredFDsCount += immutableConfig.d_maxTCPQueuedConnections;
   /* DelayPipe pipe */
   requiredFDsCount += 2;
   /* syslog socket */
@@ -2525,10 +2471,10 @@ static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCoun
   }
 }
 
-static bool g_warned_ipv6_recvpktinfo = false;
-
 static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr, int& socket, bool tcp, bool warn)
 {
+  const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+  static bool s_warned_ipv6_recvpktinfo = false;
   (void)warn;
   socket = SSocket(addr.sin4.sin_family, !tcp ? SOCK_DGRAM : SOCK_STREAM, 0);
 
@@ -2541,8 +2487,8 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
 #ifdef TCP_FASTOPEN
       SSetsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, clientState.fastOpenQueueSize);
 #ifdef TCP_FASTOPEN_KEY
-      if (!g_TCPFastOpenKey.empty()) {
-        auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, g_TCPFastOpenKey.data(), g_TCPFastOpenKey.size() * sizeof(g_TCPFastOpenKey[0]));
+      if (!immutableConfig.d_tcpFastOpenKey.empty()) {
+        auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, immutableConfig.d_tcpFastOpenKey.data(), immutableConfig.d_tcpFastOpenKey.size() * sizeof(immutableConfig.d_tcpFastOpenKey[0]));
         if (res == -1) {
           throw runtime_error("setsockopt for level IPPROTO_TCP and opname TCP_FASTOPEN_KEY failed: " + stringerror());
         }
@@ -2566,9 +2512,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
     int one = 1;
     (void)setsockopt(socket, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
 #ifdef IPV6_RECVPKTINFO
-    if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !g_warned_ipv6_recvpktinfo) {
+    if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !s_warned_ipv6_recvpktinfo) {
       warnlog("Warning: IPV6_RECVPKTINFO setsockopt failed: %s", stringerror());
-      g_warned_ipv6_recvpktinfo = true;
+      s_warned_ipv6_recvpktinfo = true;
     }
 #endif
   }
@@ -2605,9 +2551,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
   }
 
   if (!tcp) {
-    if (g_socketUDPSendBuffer > 0) {
+    if (immutableConfig.d_socketUDPSendBuffer > 0) {
       try {
-        setSocketSendBuffer(socket, g_socketUDPSendBuffer);
+        setSocketSendBuffer(socket, immutableConfig.d_socketUDPSendBuffer);
       }
       catch (const std::exception& e) {
         warnlog(e.what());
@@ -2625,9 +2571,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
       }
     }
 
-    if (g_socketUDPRecvBuffer > 0) {
+    if (immutableConfig.d_socketUDPRecvBuffer > 0) {
       try {
-        setSocketReceiveBuffer(socket, g_socketUDPRecvBuffer);
+        setSocketReceiveBuffer(socket, immutableConfig.d_socketUDPRecvBuffer);
       }
       catch (const std::exception& e) {
         warnlog(e.what());
@@ -2700,40 +2646,40 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
   }
 }
 
-static void setUpLocalBind(std::unique_ptr<ClientState>& cstate)
+static void setUpLocalBind(ClientState& cstate)
 {
   /* skip some warnings if there is an identical UDP context */
-  bool warn = !cstate->tcp || cstate->tlsFrontend != nullptr || cstate->dohFrontend != nullptr;
-  int& descriptor = !cstate->tcp ? cstate->udpFD : cstate->tcpFD;
+  bool warn = !cstate.tcp || cstate.tlsFrontend != nullptr || cstate.dohFrontend != nullptr;
+  int& descriptor = !cstate.tcp ? cstate.udpFD : cstate.tcpFD;
   (void)warn;
 
-  setupLocalSocket(*cstate, cstate->local, descriptor, cstate->tcp, warn);
+  setupLocalSocket(cstate, cstate.local, descriptor, cstate.tcp, warn);
 
-  for (auto& [addr, socket] : cstate->d_additionalAddresses) {
-    setupLocalSocket(*cstate, addr, socket, true, false);
+  for (auto& [addr, socket] : cstate.d_additionalAddresses) {
+    setupLocalSocket(cstate, addr, socket, true, false);
   }
 
-  if (cstate->tlsFrontend != nullptr) {
-    if (!cstate->tlsFrontend->setupTLS()) {
-      errlog("Error while setting up TLS on local address '%s', exiting", cstate->local.toStringWithPort());
+  if (cstate.tlsFrontend != nullptr) {
+    if (!cstate.tlsFrontend->setupTLS()) {
+      errlog("Error while setting up TLS on local address '%s', exiting", cstate.local.toStringWithPort());
       _exit(EXIT_FAILURE);
     }
   }
 
-  if (cstate->dohFrontend != nullptr) {
-    cstate->dohFrontend->setup();
+  if (cstate.dohFrontend != nullptr) {
+    cstate.dohFrontend->setup();
   }
-  if (cstate->doqFrontend != nullptr) {
-    cstate->doqFrontend->setup();
+  if (cstate.doqFrontend != nullptr) {
+    cstate.doqFrontend->setup();
   }
-  if (cstate->doh3Frontend != nullptr) {
-    cstate->doh3Frontend->setup();
+  if (cstate.doh3Frontend != nullptr) {
+    cstate.doh3Frontend->setup();
   }
 
-  cstate->ready = true;
+  cstate.ready = true;
 }
 
-struct
+struct CommandLineParameters
 {
   vector<string> locals;
   vector<string> remotes;
@@ -2744,9 +2690,7 @@ struct
   string config;
   string uid;
   string gid;
-} g_cmdLine;
-
-std::atomic<bool> g_configurationDone{false};
+};
 
 static void usage()
 {
@@ -2804,16 +2748,13 @@ static void cleanupLuaObjects()
 {
   /* when our coverage mode is enabled, we need to make sure
      that the Lua objects are destroyed before the Lua contexts. */
-  for (const auto& chain : dnsdist::rules::getRuleChains()) {
-    chain.holder.setState({});
-  }
-  for (const auto& chain : dnsdist::rules::getResponseRuleChains()) {
-    chain.holder.setState({});
-  }
-  g_dstates.setState({});
-  g_policy.setState(ServerPolicy());
-  g_pools.setState({});
-  clearWebHandlers();
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_ruleChains = dnsdist::rules::RuleChains();
+    config.d_lbPolicy = std::make_shared<ServerPolicy>();
+    config.d_pools.clear();
+    config.d_backends.clear();
+  });
+  dnsdist::webserver::clearWebHandlers();
   dnsdist::lua::hooks::clearMaintenanceHooks();
 }
 #endif /* defined(COVERAGE) || (defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)) */
@@ -2844,6 +2785,11 @@ static void sigTermHandler([[maybe_unused]] int sig)
   if (dnsdist::g_asyncHolder) {
     dnsdist::g_asyncHolder->stop();
   }
+
+  for (auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+    backend->stop();
+  }
+
   {
     auto lock = g_lua.lock();
     cleanupLuaObjects();
@@ -2940,9 +2886,18 @@ static void reportFeatures()
   cout << "systemd";
 #endif
   cout << endl;
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
+#ifdef DNSDIST_CONFIG_ARGS
+#define double_escape(s) #s
+#define escape_quotes(s) double_escape(s)
+  // NOLINTEND(cppcoreguidelines-macro-usage)
+  cout << "Configured with: " << escape_quotes(DNSDIST_CONFIG_ARGS) << endl;
+#undef escape_quotes
+#undef double_escape
+#endif
 }
 
-static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
+static void parseParameters(int argc, char** argv, CommandLineParameters& cmdLine, ComboAddress& clientAddress)
 {
   const std::array<struct option, 16> longopts{{{"acl", required_argument, nullptr, 'a'},
                                                 {"check-config", no_argument, nullptr, 1},
@@ -2962,6 +2917,8 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
                                                 {nullptr, 0, nullptr, 0}}};
   int longindex = 0;
   string optstring;
+  dnsdist::configuration::RuntimeConfiguration newConfig;
+
   while (true) {
     // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
     int gotChar = getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts.data(), &longindex);
@@ -2970,28 +2927,28 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
     }
     switch (gotChar) {
     case 1:
-      g_cmdLine.checkConfig = true;
+      cmdLine.checkConfig = true;
       break;
     case 2:
       dnsdist::logging::LoggingConfiguration::setSyslog(false);
       break;
     case 3:
-      g_cmdLine.beSupervised = true;
+      cmdLine.beSupervised = true;
       break;
     case 4:
       dnsdist::logging::LoggingConfiguration::setLogTimestamps(true);
       break;
     case 'C':
-      g_cmdLine.config = optarg;
+      cmdLine.config = optarg;
       break;
     case 'c':
-      g_cmdLine.beClient = true;
+      cmdLine.beClient = true;
       break;
     case 'e':
-      g_cmdLine.command = optarg;
+      cmdLine.command = optarg;
       break;
     case 'g':
-      g_cmdLine.gid = optarg;
+      cmdLine.gid = optarg;
       break;
     case 'h':
       cout << "dnsdist " << VERSION << endl;
@@ -3002,29 +2959,35 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
       break;
     case 'a':
       optstring = optarg;
-      g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
+      newConfig.d_ACL.addMask(optstring);
       break;
     case 'k':
 #if defined HAVE_LIBSODIUM || defined(HAVE_LIBCRYPTO)
-      if (B64Decode(string(optarg), g_consoleKey) < 0) {
+    {
+      std::string consoleKey;
+      if (B64Decode(string(optarg), consoleKey) < 0) {
         cerr << "Unable to decode key '" << optarg << "'." << endl;
         // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
         exit(EXIT_FAILURE);
       }
+      dnsdist::configuration::updateRuntimeConfiguration([&consoleKey](dnsdist::configuration::RuntimeConfiguration& config) {
+        config.d_consoleKey = std::move(consoleKey);
+      });
+    }
 #else
       cerr << "dnsdist has been built without libsodium or libcrypto, -k/--setkey is unsupported." << endl;
       // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
       exit(EXIT_FAILURE);
 #endif
-      break;
+    break;
     case 'l':
-      g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
+      cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
       break;
     case 'u':
-      g_cmdLine.uid = optarg;
+      cmdLine.uid = optarg;
       break;
     case 'v':
-      g_verbose = true;
+      newConfig.d_verbose = true;
       break;
     case 'V':
       reportFeatures();
@@ -3045,60 +3008,60 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
 
   // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): argv
   for (const auto* ptr = argv; *ptr != nullptr; ++ptr) {
-    if (g_cmdLine.beClient) {
+    if (cmdLine.beClient) {
       clientAddress = ComboAddress(*ptr, 5199);
     }
     else {
-      g_cmdLine.remotes.emplace_back(*ptr);
+      cmdLine.remotes.emplace_back(*ptr);
     }
   }
+
+  dnsdist::configuration::updateRuntimeConfiguration([&newConfig](dnsdist::configuration::RuntimeConfiguration& config) {
+    config = std::move(newConfig);
+  });
 }
 static void setupPools()
 {
-  auto pools = g_pools.getCopy();
-  {
-    bool precompute = false;
-    if (g_policy.getLocal()->getName() == "chashed") {
-      precompute = true;
-    }
-    else {
-      for (const auto& entry : pools) {
-        if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
-          precompute = true;
-          break;
-        }
+  bool precompute = false;
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName() == "chashed") {
+    precompute = true;
+  }
+  else {
+    for (const auto& entry : dnsdist::configuration::getCurrentRuntimeConfiguration().d_pools) {
+      if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
+        precompute = true;
+        break;
       }
     }
-    if (precompute) {
-      vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
-      // pre compute hashes
-      auto backends = g_dstates.getLocal();
-      for (const auto& backend : *backends) {
-        if (backend->d_config.d_weight < 100) {
-          vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
-        }
-
-        backend->hash();
+  }
+  if (precompute) {
+    vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
+    // pre compute hashes
+    for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+      if (backend->d_config.d_weight < 100) {
+        vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
       }
+
+      backend->hash();
     }
   }
 }
 
-static void dropPrivileges()
+static void dropPrivileges(const CommandLineParameters& cmdLine)
 {
   uid_t newgid = getegid();
   gid_t newuid = geteuid();
 
-  if (!g_cmdLine.gid.empty()) {
-    newgid = strToGID(g_cmdLine.gid);
+  if (!cmdLine.gid.empty()) {
+    newgid = strToGID(cmdLine.gid);
   }
 
-  if (!g_cmdLine.uid.empty()) {
-    newuid = strToUID(g_cmdLine.uid);
+  if (!cmdLine.uid.empty()) {
+    newuid = strToUID(cmdLine.uid);
   }
 
   bool retainedCapabilities = true;
-  if (!g_capabilitiesToRetain.empty() && (getegid() != newgid || geteuid() != newuid)) {
+  if (!dnsdist::configuration::getImmutableConfiguration().d_capabilitiesToRetain.empty() && (getegid() != newgid || geteuid() != newuid)) {
     retainedCapabilities = keepCapabilitiesAfterSwitchingIDs();
   }
 
@@ -3129,40 +3092,46 @@ static void dropPrivileges()
        or as an unprivileged user with ambient
        capabilities like CAP_NET_BIND_SERVICE.
     */
-    dropCapabilities(g_capabilitiesToRetain);
+    dropCapabilities(dnsdist::configuration::getImmutableConfiguration().d_capabilitiesToRetain);
   }
   catch (const std::exception& e) {
     warnlog("%s", e.what());
   }
 }
 
-static void initFrontends()
+static void initFrontends(const CommandLineParameters& cmdLine)
 {
-  if (!g_cmdLine.locals.empty()) {
-    for (auto it = g_frontends.begin(); it != g_frontends.end();) {
+  auto frontends = dnsdist::configuration::getImmutableConfiguration().d_frontends;
+
+  if (!cmdLine.locals.empty()) {
+    for (auto it = frontends.begin(); it != frontends.end();) {
       /* DoH, DoT and DNSCrypt frontends are separate */
       if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr && (*it)->doqFrontend == nullptr && (*it)->doh3Frontend == nullptr) {
-        it = g_frontends.erase(it);
+        it = frontends.erase(it);
       }
       else {
         ++it;
       }
     }
 
-    for (const auto& loc : g_cmdLine.locals) {
+    for (const auto& loc : cmdLine.locals) {
       /* UDP */
-      g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
+      frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
       /* TCP */
-      g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
+      frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
     }
   }
 
-  if (g_frontends.empty()) {
+  if (frontends.empty()) {
     /* UDP */
-    g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
+    frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
     /* TCP */
-    g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
+    frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
   }
+
+  dnsdist::configuration::updateImmutableConfiguration([&frontends](dnsdist::configuration::ImmutableConfiguration& config) {
+    config.d_frontends = std::move(frontends);
+  });
 }
 
 namespace dnsdist
@@ -3178,7 +3147,7 @@ static void startFrontends()
 
   std::vector<ClientState*> tcpStates;
   std::vector<ClientState*> udpStates;
-  for (auto& clientState : g_frontends) {
+  for (const auto& clientState : dnsdist::getFrontends()) {
 #ifdef HAVE_XSK
     if (clientState->xskInfo) {
       dnsdist::xsk::addDestinationAddress(clientState->local);
@@ -3258,17 +3227,52 @@ static void startFrontends()
 }
 }
 
+struct ListeningSockets
+{
+  Socket d_consoleSocket{-1};
+  Socket d_webServerSocket{-1};
+};
+
+static ListeningSockets initListeningSockets()
+{
+  ListeningSockets result;
+  const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+
+  if (currentConfig.d_consoleEnabled) {
+    const auto& local = currentConfig.d_consoleServerAddress;
+    try {
+      result.d_consoleSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+      result.d_consoleSocket.bind(local, true);
+      result.d_consoleSocket.listen(5);
+    }
+    catch (const std::exception& exp) {
+      errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what());
+    }
+  }
+
+  if (currentConfig.d_webServerAddress) {
+    const auto& local = *currentConfig.d_webServerAddress;
+    try {
+      result.d_webServerSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+      result.d_webServerSocket.bind(local, true);
+      result.d_webServerSocket.listen(5);
+    }
+    catch (const std::exception& exp) {
+      errlog("Unable to bind to web server socket on %s: %s", local.toStringWithPort(), exp.what());
+    }
+  }
+
+  return result;
+}
+
 int main(int argc, char** argv)
 {
   try {
+    CommandLineParameters cmdLine{};
     size_t udpBindsCount = 0;
     size_t tcpBindsCount = 0;
-#ifdef HAVE_LIBEDIT
-#ifndef DISABLE_COMPLETION
-    rl_attempted_completion_function = my_completion;
-    rl_completion_append_character = 0;
-#endif /* DISABLE_COMPLETION */
-#endif /* HAVE_LIBEDIT */
+
+    dnsdist::console::setupCompletion();
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast): SIG_IGN macro
     signal(SIGPIPE, SIG_IGN);
@@ -3286,7 +3290,9 @@ int main(int argc, char** argv)
     }
 #endif
     dnsdist::initRandom();
-    g_hashperturb = dnsdist::getRandomValue(0xffffffff);
+    dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& config) {
+      config.d_hashPerturbation = dnsdist::getRandomValue(0xffffffff);
+    });
 
 #ifdef HAVE_XSK
     try {
@@ -3299,19 +3305,22 @@ int main(int argc, char** argv)
 #endif /* HAVE_XSK */
 
     ComboAddress clientAddress = ComboAddress();
-    g_cmdLine.config = SYSCONFDIR "/dnsdist.conf";
+    cmdLine.config = SYSCONFDIR "/dnsdist.conf";
 
-    parseParameters(argc, argv, clientAddress);
+    parseParameters(argc, argv, cmdLine, clientAddress);
 
-    ServerPolicy leastOutstandingPol{"leastOutstanding", leastOutstanding, false};
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::make_shared<ServerPolicy>("leastOutstanding", leastOutstanding, false);
+    });
 
-    g_policy.setState(leastOutstandingPol);
-    if (g_cmdLine.beClient || !g_cmdLine.command.empty()) {
-      setupLua(*(g_lua.lock()), true, false, g_cmdLine.config);
+    if (cmdLine.beClient || !cmdLine.command.empty()) {
+      setupLua(*(g_lua.lock()), true, false, cmdLine.config);
       if (clientAddress != ComboAddress()) {
-        g_serverControl = clientAddress;
+        dnsdist::configuration::updateRuntimeConfiguration([&clientAddress](dnsdist::configuration::RuntimeConfiguration& config) {
+          config.d_consoleServerAddress = clientAddress;
+        });
       }
-      doClient(g_serverControl, g_cmdLine.command);
+      dnsdist::console::doClient(cmdLine.command);
 #ifdef COVERAGE
       exit(EXIT_SUCCESS);
 #else
@@ -3319,25 +3328,25 @@ int main(int argc, char** argv)
 #endif
     }
 
-    auto acl = g_ACL.getCopy();
-    if (acl.empty()) {
-      for (const auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"}) {
-        acl.addMask(addr);
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      auto& acl = config.d_ACL;
+      if (acl.empty()) {
+        for (const auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"}) {
+          acl.addMask(addr);
+        }
       }
-      g_ACL.setState(acl);
-    }
+      for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
+        config.d_consoleACL.addMask(mask);
+      }
+      config.d_webServerACL.toMasks("127.0.0.1, ::1");
+    });
 
-    auto consoleACL = g_consoleACL.getCopy();
-    for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
-      consoleACL.addMask(mask);
-    }
-    g_consoleACL.setState(consoleACL);
-    registerBuiltInWebHandlers();
+    dnsdist::webserver::registerBuiltInWebHandlers();
 
-    if (g_cmdLine.checkConfig) {
-      setupLua(*(g_lua.lock()), false, true, g_cmdLine.config);
+    if (cmdLine.checkConfig) {
+      setupLua(*(g_lua.lock()), false, true, cmdLine.config);
       // No exception was thrown
-      infolog("Configuration '%s' OK!", g_cmdLine.config);
+      infolog("Configuration '%s' OK!", cmdLine.config);
 #ifdef COVERAGE
       cleanupLuaObjects();
       exit(EXIT_SUCCESS);
@@ -3350,19 +3359,16 @@ int main(int argc, char** argv)
 
     dnsdist::g_asyncHolder = std::make_unique<dnsdist::AsynchronousHolder>();
 
-    auto todo = setupLua(*(g_lua.lock()), false, false, g_cmdLine.config);
-
-    setupPools();
-
-    initFrontends();
+    /* create the default pool no matter what */
+    createPoolIfNotExists("");
 
-    g_configurationDone = true;
+    setupLua(*(g_lua.lock()), false, false, cmdLine.config);
 
-    g_rings.init();
+    setupPools();
 
-    for (auto& frontend : g_frontends) {
-      setUpLocalBind(frontend);
+    initFrontends(cmdLine);
 
+    for (const auto& frontend : dnsdist::getFrontends()) {
       if (!frontend->tcp) {
         ++udpBindsCount;
       }
@@ -3371,9 +3377,38 @@ int main(int argc, char** argv)
       }
     }
 
+    if (dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
+      dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::ImmutableConfiguration& config) {
+        config.d_maxTCPClientThreads = static_cast<size_t>(10);
+      });
+    }
+
+    dnsdist::configuration::setImmutableConfigurationDone();
+
+    {
+      const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+      setTCPDownstreamMaxIdleConnectionsPerBackend(immutableConfig.d_outgoingTCPMaxIdlePerBackend);
+      setTCPDownstreamMaxIdleTime(immutableConfig.d_outgoingTCPMaxIdleTime);
+      setTCPDownstreamCleanupInterval(immutableConfig.d_outgoingTCPCleanupInterval);
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+      setDoHDownstreamMaxIdleConnectionsPerBackend(immutableConfig.d_outgoingDoHMaxIdlePerBackend);
+      setDoHDownstreamMaxIdleTime(immutableConfig.d_outgoingDoHMaxIdleTime);
+      setDoHDownstreamCleanupInterval(immutableConfig.d_outgoingDoHCleanupInterval);
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+    }
+
+    {
+      const auto& config = dnsdist::configuration::getImmutableConfiguration();
+      g_rings.init(config.d_ringsCapacity, config.d_ringsNumberOfShards, config.d_ringsNbLockTries, config.d_ringsRecordQueries, config.d_ringsRecordResponses);
+    }
+
+    for (const auto& frontend : dnsdist::getFrontends()) {
+      setUpLocalBind(*frontend);
+    }
+
     {
       std::string acls;
-      auto aclEntries = g_ACL.getLocal()->toStringVector();
+      auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.toStringVector();
       for (const auto& aclEntry : aclEntries) {
         if (!acls.empty()) {
           acls += ", ";
@@ -3384,7 +3419,7 @@ int main(int argc, char** argv)
     }
     {
       std::string acls;
-      auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+      auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
       for (const auto& entry : aclEntries) {
         if (!acls.empty()) {
           acls += ", ";
@@ -3394,13 +3429,15 @@ int main(int argc, char** argv)
       infolog("Console ACL allowing connections from: %s", acls.c_str());
     }
 
+    auto listeningSockets = initListeningSockets();
+
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
-    if (g_consoleEnabled && g_consoleKey.empty()) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleEnabled && dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleKey.empty()) {
       warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
     }
 #endif
 
-    dropPrivileges();
+    dropPrivileges(cmdLine);
 
     /* this need to be done _after_ dropping privileges */
 #ifndef DISABLE_DELAY_PIPE
@@ -3411,45 +3448,52 @@ int main(int argc, char** argv)
       g_snmpAgent->run();
     }
 
-    if (!g_maxTCPClientThreads) {
-      g_maxTCPClientThreads = static_cast<size_t>(10);
-    }
-    else if (*g_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
-      warnlog("setMaxTCPClientThreads() has been set to 0 while we are accepting TCP connections, raising to 1");
-      g_maxTCPClientThreads = 1;
-    }
-
     /* we need to create the TCP worker threads before the
        acceptor ones, otherwise we might crash when processing
        the first TCP query */
 #ifndef USE_SINGLE_ACCEPTOR_THREAD
-    g_tcpclientthreads = std::make_unique<TCPClientCollection>(*g_maxTCPClientThreads, std::vector<ClientState*>());
+    const auto maxTCPClientThreads = dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads;
+    /* the limit is completely arbitrary: hopefully high enough not to trigger too many false positives
+       but low enough to be useful */
+    if (maxTCPClientThreads >= 50U) {
+      warnlog("setMaxTCPClientThreads(%d) might create a large number of TCP connections to backends, and is probably not needed, please consider lowering it", maxTCPClientThreads);
+    }
+    g_tcpclientthreads = std::make_unique<TCPClientCollection>(maxTCPClientThreads, std::vector<ClientState*>());
 #endif
 
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
     initDoHWorkers();
 #endif
 
-    for (auto& todoItem : todo) {
-      todoItem();
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleEnabled) {
+      std::thread consoleControlThread(dnsdist::console::controlThread, std::move(listeningSockets.d_consoleSocket));
+      consoleControlThread.detach();
+    }
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress) {
+      std::thread webServerThread(dnsdist::webserver::WebserverThread, std::move(listeningSockets.d_webServerSocket));
+      webServerThread.detach();
     }
 
-    auto localPools = g_pools.getCopy();
-    /* create the default pool no matter what */
-    createPoolIfNotExists(localPools, "");
-    if (!g_cmdLine.remotes.empty()) {
-      for (const auto& address : g_cmdLine.remotes) {
+    for (const auto& backend : dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends) {
+      if (backend->connected) {
+        backend->start();
+      }
+    }
+
+    if (!cmdLine.remotes.empty()) {
+      for (const auto& address : cmdLine.remotes) {
         DownstreamState::Config config;
         config.remote = ComboAddress(address, 53);
         auto ret = std::make_shared<DownstreamState>(std::move(config), nullptr, true);
-        addServerToPool(localPools, "", ret);
+        addServerToPool("", ret);
         ret->start();
-        g_dstates.modify([&ret](servers_t& servers) { servers.push_back(std::move(ret)); });
+        dnsdist::configuration::updateRuntimeConfiguration([&ret](dnsdist::configuration::RuntimeConfiguration& runtimeConfig) {
+          runtimeConfig.d_backends.push_back(std::move(ret));
+        });
       }
     }
-    g_pools.setState(localPools);
 
-    if (g_dstates.getLocal()->empty()) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends.empty()) {
       errlog("No downstream servers defined: all packets will get dropped");
       // you might define them later, but you need to know
     }
@@ -3457,7 +3501,8 @@ int main(int argc, char** argv)
     checkFileDescriptorsLimits(udpBindsCount, tcpBindsCount);
 
     {
-      auto states = g_dstates.getCopy(); // it is a copy, but the internal shared_ptrs are the real deal
+      //coverity[auto_causes_copy]
+      const auto states = dnsdist::configuration::getCurrentRuntimeConfiguration().d_backends; // it is a copy, but the internal shared_ptrs are the real deal
       auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(states.size()));
       for (auto& dss : states) {
 
@@ -3481,7 +3526,7 @@ int main(int argc, char** argv)
     dnsdist::ServiceDiscovery::run();
 
 #ifndef DISABLE_CARBON
-    dnsdist::Carbon::run();
+    dnsdist::Carbon::run(dnsdist::configuration::getCurrentRuntimeConfiguration().d_carbonEndpoints);
 #endif /* DISABLE_CARBON */
 
     thread stattid(maintThread);
@@ -3495,13 +3540,13 @@ int main(int argc, char** argv)
 #endif /* DISABLE_DYNBLOCKS */
 
 #ifndef DISABLE_SECPOLL
-    if (!g_secPollSuffix.empty()) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_secPollSuffix.empty()) {
       thread secpollthread(secPollThread);
       secpollthread.detach();
     }
 #endif /* DISABLE_SECPOLL */
 
-    if (g_cmdLine.beSupervised) {
+    if (cmdLine.beSupervised) {
 #ifdef HAVE_SYSTEMD
       sd_notify(0, "READY=1");
 #endif
@@ -3509,7 +3554,7 @@ int main(int argc, char** argv)
     }
     else {
       healththread.detach();
-      doConsole();
+      dnsdist::console::doConsole();
     }
 #ifdef COVERAGE
     cleanupLuaObjects();
index cf4da8f6f50dc76f8a71c7896dfab27c39e18152..d4bd9b9cb7c3a2f6eb43480e9a4047ed878f80df 100644 (file)
@@ -22,7 +22,6 @@
 #pragma once
 
 #include "config.h"
-#include "ext/luawrapper/include/LuaContext.hpp"
 
 #include <condition_variable>
 #include <memory>
 #include <unistd.h>
 #include <unordered_map>
 
-#include <boost/variant.hpp>
-
+#include "bpf-filter.hh"
 #include "circular_buffer.hh"
-#include "dnscrypt.hh"
-#include "dnsdist-cache.hh"
-#include "dnsdist-dynbpf.hh"
 #include "dnsdist-idstate.hh"
 #include "dnsdist-lbpolicies.hh"
 #include "dnsdist-protocols.hh"
 #include "misc.hh"
 #include "mplexer.hh"
 #include "noinitvector.hh"
-#include "sholder.hh"
-#include "tcpiohandler.hh"
 #include "uuid-utils.hh"
 #include "proxy-protocol.hh"
 #include "stat_t.hh"
 
 uint64_t uptimeOfProcess(const std::string& str);
 
-extern uint16_t g_ECSSourcePrefixV4;
-extern uint16_t g_ECSSourcePrefixV6;
-extern bool g_ECSOverride;
-
 using QTag = std::unordered_map<string, string>;
 
 class IncomingTCPConnectionState;
@@ -71,10 +60,7 @@ struct ClientState;
 
 struct DNSQuestion
 {
-  DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_) :
-    data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), ecsOverride(g_ECSOverride)
-  {
-  }
+  DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_);
   DNSQuestion(const DNSQuestion&) = delete;
   DNSQuestion& operator=(const DNSQuestion&) = delete;
   DNSQuestion(DNSQuestion&&) = default;
@@ -210,184 +196,6 @@ struct DNSResponse : DNSQuestion
   const std::shared_ptr<DownstreamState>& d_downstream;
 };
 
-/* so what could you do:
-   drop,
-   fake up nxdomain,
-   provide actual answer,
-   allow & and stop processing,
-   continue processing,
-   modify header:    (servfail|refused|notimp), set TC=1,
-   send to pool */
-
-class DNSAction
-{
-public:
-  enum class Action : uint8_t
-  {
-    Drop,
-    Nxdomain,
-    Refused,
-    Spoof,
-    Allow,
-    HeaderModify,
-    Pool,
-    Delay,
-    Truncate,
-    ServFail,
-    None,
-    NoOp,
-    NoRecurse,
-    SpoofRaw,
-    SpoofPacket,
-    SetTag,
-  };
-  static std::string typeToString(const Action& action)
-  {
-    switch (action) {
-    case Action::Drop:
-      return "Drop";
-    case Action::Nxdomain:
-      return "Send NXDomain";
-    case Action::Refused:
-      return "Send Refused";
-    case Action::Spoof:
-      return "Spoof an answer";
-    case Action::SpoofPacket:
-      return "Spoof a raw answer from bytes";
-    case Action::SpoofRaw:
-      return "Spoof an answer from raw bytes";
-    case Action::Allow:
-      return "Allow";
-    case Action::HeaderModify:
-      return "Modify the header";
-    case Action::Pool:
-      return "Route to a pool";
-    case Action::Delay:
-      return "Delay";
-    case Action::Truncate:
-      return "Truncate over UDP";
-    case Action::ServFail:
-      return "Send ServFail";
-    case Action::SetTag:
-      return "Set Tag";
-    case Action::None:
-    case Action::NoOp:
-      return "Do nothing";
-    case Action::NoRecurse:
-      return "Set rd=0";
-    }
-
-    return "Unknown";
-  }
-
-  virtual Action operator()(DNSQuestion*, string* ruleresult) const = 0;
-  virtual ~DNSAction()
-  {
-  }
-  virtual string toString() const = 0;
-  virtual std::map<string, double> getStats() const
-  {
-    return {{}};
-  }
-  virtual void reload()
-  {
-  }
-};
-
-class DNSResponseAction
-{
-public:
-  enum class Action : uint8_t
-  {
-    Allow,
-    Delay,
-    Drop,
-    HeaderModify,
-    ServFail,
-    Truncate,
-    None
-  };
-  virtual Action operator()(DNSResponse*, string* ruleresult) const = 0;
-  virtual ~DNSResponseAction()
-  {
-  }
-  virtual string toString() const = 0;
-  virtual void reload()
-  {
-  }
-};
-
-struct DynBlock
-{
-  DynBlock()
-  {
-    until.tv_sec = 0;
-    until.tv_nsec = 0;
-  }
-
-  DynBlock(const std::string& reason_, const struct timespec& until_, const DNSName& domain_, DNSAction::Action action_) :
-    reason(reason_), domain(domain_), until(until_), action(action_)
-  {
-  }
-
-  DynBlock(const DynBlock& rhs) :
-    reason(rhs.reason), domain(rhs.domain), until(rhs.until), tagSettings(rhs.tagSettings), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
-  {
-    blocks.store(rhs.blocks);
-  }
-
-  DynBlock(DynBlock&& rhs) :
-    reason(std::move(rhs.reason)), domain(std::move(rhs.domain)), until(rhs.until), tagSettings(std::move(rhs.tagSettings)), action(rhs.action), warning(rhs.warning), bpf(rhs.bpf)
-  {
-    blocks.store(rhs.blocks);
-  }
-
-  DynBlock& operator=(const DynBlock& rhs)
-  {
-    reason = rhs.reason;
-    until = rhs.until;
-    domain = rhs.domain;
-    action = rhs.action;
-    blocks.store(rhs.blocks);
-    warning = rhs.warning;
-    bpf = rhs.bpf;
-    tagSettings = rhs.tagSettings;
-    return *this;
-  }
-
-  DynBlock& operator=(DynBlock&& rhs)
-  {
-    reason = std::move(rhs.reason);
-    until = rhs.until;
-    domain = std::move(rhs.domain);
-    action = rhs.action;
-    blocks.store(rhs.blocks);
-    warning = rhs.warning;
-    bpf = rhs.bpf;
-    tagSettings = std::move(rhs.tagSettings);
-    return *this;
-  }
-
-  struct TagSettings
-  {
-    std::string d_name;
-    std::string d_value;
-  };
-
-  string reason;
-  DNSName domain;
-  timespec until{};
-  std::shared_ptr<TagSettings> tagSettings{nullptr};
-  mutable std::atomic<uint32_t> blocks{0};
-  DNSAction::Action action{DNSAction::Action::None};
-  bool warning{false};
-  bool bpf{false};
-};
-
-extern GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
-
-extern vector<pair<struct timeval, std::string>> g_confDelta;
-
 using pdns::stat_t;
 
 class BasicQPSLimiter
@@ -502,27 +310,12 @@ private:
   bool d_passthrough{true};
 };
 
-typedef std::unordered_map<string, unsigned int> QueryCountRecords;
-typedef std::function<std::tuple<bool, string>(const DNSQuestion* dq)> QueryCountFilter;
-struct QueryCount
-{
-  QueryCount()
-  {
-  }
-  ~QueryCount()
-  {
-  }
-  SharedLockGuarded<QueryCountRecords> records;
-  QueryCountFilter filter;
-  bool enabled{false};
-};
-
-extern QueryCount g_qcount;
-
 class XskPacket;
 class XskSocket;
 class XskWorker;
 
+class DNSCryptContext;
+
 struct ClientState
 {
   ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_, bool enableProxyProtocol) :
@@ -551,9 +344,9 @@ struct ClientState
   stat_t tls12queries{0}; // valid DNS queries received via TLSv1.2
   stat_t tls13queries{0}; // valid DNS queries received via TLSv1.3
   stat_t tlsUnknownqueries{0}; // valid DNS queries received via unknown TLS version
-  pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
+  pdns::stat_double_t tcpAvgQueriesPerConnection{0.0};
   /* in ms */
-  pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
+  pdns::stat_double_t tcpAvgConnectionDuration{0.0};
   std::set<int> cpus;
   std::string interface;
   ComboAddress local;
@@ -565,6 +358,7 @@ struct ClientState
   std::shared_ptr<DOH3Frontend> doh3Frontend{nullptr};
   std::shared_ptr<BPFFilter> d_filter{nullptr};
   std::shared_ptr<XskWorker> xskInfo{nullptr};
+  std::shared_ptr<XskWorker> xskInfoResponder{nullptr};
   size_t d_maxInFlightQueriesPerConn{1};
   size_t d_tcpConcurrentConnectionsLimit{0};
   int udpFD{-1};
@@ -722,6 +516,7 @@ struct ClientState
 };
 
 struct CrossProtocolQuery;
+class FDMultiplexer;
 
 struct DownstreamState : public std::enable_shared_from_this<DownstreamState>
 {
@@ -859,11 +654,11 @@ struct DownstreamState : public std::enable_shared_from_this<DownstreamState>
   stat_t tcpReusedConnections{0};
   stat_t tcpNewConnections{0};
   stat_t tlsResumptions{0};
-  pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
+  pdns::stat_double_t tcpAvgQueriesPerConnection{0.0};
   /* in ms */
-  pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
-  pdns::stat_t_trait<double> queryLoad{0.0};
-  pdns::stat_t_trait<double> dropRate{0.0};
+  pdns::stat_double_t tcpAvgConnectionDuration{0.0};
+  pdns::stat_double_t queryLoad{0.0};
+  pdns::stat_double_t dropRate{0.0};
 
   SharedLockGuarded<std::vector<unsigned int>> hashes;
   LockGuarded<std::unique_ptr<FDMultiplexer>> mplexer{nullptr};
@@ -903,7 +698,7 @@ public:
   uint16_t currentCheckFailures{0};
   std::atomic<bool> hashesComputed{false};
   std::atomic<bool> connected{false};
-  bool upStatus{false};
+  std::atomic<bool> upStatus{false};
 
 private:
   void handleUDPTimeout(IDState& ids);
@@ -942,7 +737,7 @@ public:
     else if (d_config.availability == Availability::Up) {
       return true;
     }
-    return upStatus;
+    return upStatus.load(std::memory_order_relaxed);
   }
 
   void setUp()
@@ -952,8 +747,8 @@ public:
 
   void setUpStatus(bool newStatus)
   {
-    upStatus = newStatus;
-    if (!upStatus) {
+    upStatus.store(newStatus);
+    if (!newStatus) {
       latencyUsec = 0.0;
       latencyUsecTCP = 0.0;
     }
@@ -999,7 +794,7 @@ public:
       status = "DOWN";
     }
     else {
-      status = (upStatus ? "up" : "down");
+      status = (upStatus.load(std::memory_order_relaxed) ? "up" : "down");
     }
     return status;
   }
@@ -1091,16 +886,11 @@ public:
     }
     return latencyUsec;
   }
-
-  static int s_udpTimeout;
-  static bool s_randomizeSockets;
-  static bool s_randomizeIDs;
 };
-using servers_t = vector<std::shared_ptr<DownstreamState>>;
 
 void responderThread(std::shared_ptr<DownstreamState> dss);
-extern LockGuarded<LuaContext> g_lua;
-extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
+
+class DNSDistPacketCache;
 
 class DNSRule
 {
@@ -1156,45 +946,7 @@ enum ednsHeaderFlags
   EDNS_HEADER_FLAG_DO = 32768
 };
 
-extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-extern DNSAction::Action g_dynBlockAction;
-
-extern GlobalStateHolder<ServerPolicy> g_policy;
-extern GlobalStateHolder<servers_t> g_dstates;
-extern GlobalStateHolder<pools_t> g_pools;
-extern GlobalStateHolder<NetmaskGroup> g_ACL;
-
-extern ComboAddress g_serverControl; // not changed during runtime
-
-extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
-extern std::vector<shared_ptr<DOHFrontend>> g_dohlocals;
-extern std::vector<shared_ptr<DOQFrontend>> g_doqlocals;
-extern std::vector<shared_ptr<DOH3Frontend>> g_doh3locals;
-extern std::vector<std::unique_ptr<ClientState>> g_frontends;
-extern bool g_truncateTC;
-extern bool g_fixupCase;
-extern int g_tcpRecvTimeout;
-extern int g_tcpSendTimeout;
-extern uint16_t g_maxOutstanding;
-extern std::atomic<bool> g_configurationDone;
-extern boost::optional<uint64_t> g_maxTCPClientThreads;
-extern uint64_t g_maxTCPQueuedConnections;
-extern size_t g_maxTCPQueriesPerConn;
-extern size_t g_maxTCPConnectionDuration;
-extern size_t g_tcpInternalPipeBufferSize;
-extern pdns::stat16_t g_cacheCleaningDelay;
-extern pdns::stat16_t g_cacheCleaningPercentage;
-extern uint32_t g_staleCacheEntriesTTL;
-extern bool g_apiReadWrite;
-extern std::string g_apiConfigDirectory;
-extern bool g_servFailOnNoPolicy;
-extern size_t g_udpVectorSize;
-extern bool g_allowEmptyResponse;
-extern uint32_t g_socketUDPSendBuffer;
-extern uint32_t g_socketUDPRecvBuffer;
-
 extern shared_ptr<BPFFilter> g_defaultBPFFilter;
-extern std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
 
 void tcpAcceptorThread(const std::vector<ClientState*>& states);
 
@@ -1203,24 +955,15 @@ void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ sid
 bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
 void resetLuaSideEffect(); // reset to indeterminate state
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse);
 
 bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState);
 
-extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
+class DNSCryptQuery;
+
 bool handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, time_t now, PacketBuffer& response);
 bool checkDNSCryptQuery(const ClientState& clientState, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
 
-#include "dnsdist-snmp.hh"
-
-extern bool g_snmpEnabled;
-extern bool g_snmpTrapsEnabled;
-extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
-extern bool g_addEDNSToSelfGeneratedResponses;
-
-extern std::set<std::string> g_capabilitiesToRetain;
-static const uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
-
 enum class ProcessQueryResult : uint8_t
 {
   Drop,
@@ -1229,34 +972,15 @@ enum class ProcessQueryResult : uint8_t
   Asynchronous
 };
 
+#include "dnsdist-actions.hh"
 #include "dnsdist-rule-chains.hh"
 
-struct LocalHolders
-{
-  LocalHolders() :
-    acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::Rules).getLocal()), cacheMissRuleActions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::CacheMissRules).getLocal()), cacheHitRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheHitResponseRules).getLocal()), cacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), selfAnsweredRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules).getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal())
-  {
-  }
-
-  LocalStateHolder<NetmaskGroup> acl;
-  LocalStateHolder<ServerPolicy> policy;
-  LocalStateHolder<vector<dnsdist::rules::RuleAction>> ruleactions;
-  LocalStateHolder<vector<dnsdist::rules::RuleAction>> cacheMissRuleActions;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> cacheHitRespRuleactions;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> cacheInsertedRespRuleActions;
-  LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> selfAnsweredRespRuleactions;
-  LocalStateHolder<servers_t> servers;
-  LocalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> dynNMGBlock;
-  LocalStateHolder<SuffixMatchTree<DynBlock>> dynSMTBlock;
-  LocalStateHolder<pools_t> pools;
-};
-
-ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted);
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend);
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend);
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted);
 bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dnsQuestion, std::string& ruleresult, bool& drop);
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted);
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids);
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted);
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids);
 bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, DNSResponse& dnsResponse);
 
 bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend = true);
index eb75e7632a511bd478340c2f8e0f6195c9b521a8..bd810fd912cbe7d868fbec3c7b7b415a95a0564a 100644 (file)
@@ -25,10 +25,10 @@ LimitNOFILE=16384
 # LimitMEMLOCK=infinity
 
 # Sandboxing
-# Note: adding CAP_SYS_ADMIN (or CAP_BPF for Linux >= 5.8) is required to use eBPF support,
+# Note: adding CAP_SYS_ADMIN is required to use eBPF support,
 # and CAP_NET_RAW to be able to set the source interface to contact a backend
 # If an AppArmor policy is in use, it might have to be updated to allow dnsdist to keep the
-# capability: adding a 'capability bpf,' (for CAP_BPF) line to the policy is usually enough.
+# capability: adding a 'capability sys_admin,' line to the policy is usually enough.
 CapabilityBoundingSet=CAP_NET_BIND_SERVICE
 AmbientCapabilities=CAP_NET_BIND_SERVICE
 LockPersonality=true
index 2905b95e96c9259f696ee44d87ea0a052a8178d6..4efe883a1f86cd7749c9344488f2c3cb59a17072 100644 (file)
@@ -1,16 +1,16 @@
 eBPF Socket Filtering
 =====================
 
-:program:`dnsdist` can use `eBPF <http://www.brendangregg.com/ebpf.html>`_ socket filtering on recent Linux kernels (4.1+) built with eBPF support (``CONFIG_BPF``, ``CONFIG_BPF_SYSCALL``, ideally ``CONFIG_BPF_JIT``). It requires dnsdist to have the ``CAP_SYS_ADMIN`` capabilities at startup, or the more restrictive ``CAP_BPF`` one since Linux 5.8.
+:program:`dnsdist` can use `eBPF <http://www.brendangregg.com/ebpf.html>`_ socket filtering on recent Linux kernels (4.1+) built with eBPF support (``CONFIG_BPF``, ``CONFIG_BPF_SYSCALL``, ideally ``CONFIG_BPF_JIT``). It requires dnsdist to have the ``CAP_SYS_ADMIN`` capabilities at startup.
 
 .. note::
-   To retain the required capability, ``CAP_SYS_ADMIN`` or ``CAP_BPF`` depending on the Linux kernel version, it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
+   To retain the required capability, ``CAP_SYS_ADMIN``, it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
 
 .. note::
-   eBPF can be used by unprivileged users lacking the ``CAP_SYS_ADMIN`` (or ``CAP_BPF``) capability on some kernels, depending on the value of the ``kernel.unprivileged_bpf_disabled`` sysctl. Since 5.15 that kernel build setting ``BPF_UNPRIV_DEFAULT_OFF`` is enabled by default, which prevents unprivileged users from using eBPF.
+   eBPF can be used by unprivileged users lacking the ``CAP_SYS_ADMIN`` capability on some kernels, depending on the value of the ``kernel.unprivileged_bpf_disabled`` sysctl. Since 5.15 that kernel build setting ``BPF_UNPRIV_DEFAULT_OFF`` is enabled by default, which prevents unprivileged users from using eBPF.
 
 .. note::
-   ``AppArmor`` users might need to update their policy to allow dnsdist to keep the ``CAP_SYS_ADMIN`` (or ``CAP_BPF``) capability. Adding a ``capability bpf,`` (for ``CAP_BPF``) line to the policy file is usually enough.
+   ``AppArmor`` users might need to update their policy to allow dnsdist to keep the ``CAP_SYS_ADMIN`` capability. Adding a ``capability sys_admin,`` line to the policy file is usually enough.
 
 .. note::
    In addition to keeping the correct capability, large maps might require an increase of ``RLIMIT_MEMLOCK``, as mentioned below.
@@ -129,4 +129,3 @@ The first, legacy format is still used because of the limitations of eBPF socket
 XDP programs are more powerful than eBPF socket filtering ones as they are not limited to accepting or denying a packet, but can immediately craft and send an answer. They are also executed a bit earlier in the kernel networking path so can provide better performance.
 
 A sample program using the maps populated by dnsdist in an external XDP program can be found in the `contrib/ directory of our git repository <https://github.com/PowerDNS/pdns/tree/master/contrib>`__. That program supports answering with a TC=1 response instead of simply dropping the packet.
-
index 0160f2d7cf1abe369ab6911626afbefbd175571e..e247c98b8e43be7ad7421238b4628deff9d8523d 100644 (file)
@@ -24,3 +24,4 @@ These chapters contain information on the advanced features of dnsdist
    internal-design
    asynchronous-processing
    xsk
+   zero-scope
index 62b54c5ec970bae7094306319f467247a1b664d1..f09d7e47c36975c391a11bf2a886009eca771470 100644 (file)
@@ -4,19 +4,94 @@ Passing the source address to the backend
 dnsdist, as a load-balancer, receives the UDP datagrams and terminates the TCP connections with the client. It therefore knows the source IP address and port of that client, as well as the original destination address, port, and protocol.
 Very often the backend needs to know that information as well, to pass EDNS Client Subnet to an authoritative server, to do GeoIP-based processing or even custom filtering.
 
-There are several ways to pass that information using dnsdist: EDNS Client Subnet, X-Proxied-For and the Proxy Protocol.
+There are several ways to pass that information using dnsdist: the :ref:`Proxy Protocol` and :ref:`EDNS Client Subnet<EDNS Client Subnet>`.
+
+When the backend supports it (ISC Bind, Knot, Knot Resolver, PowerDNS Authoritative, PowerDNS Recursor, Unbound, HAProxy, nginx, postfix and many others do), the proxy protocol is the best option.
+
+.. note::
+  X-Proxied-For (XPF) was a third option but it has been deprecated for a while, and support has been removed in 2.0.0.
+
+.. _Proxy Protocol:
+
+Proxy Protocol
+--------------
+
+.. note:
+  The Proxy Protocol has been designed by the HAProxy folks for HTTP over TCP, but is generic enough to be used in other places, and is a de-facto standard with implementations in ISC Bind, Knot, Knot Resolver, PowerDNS Authoritative, PowerDNS Recursor, Unbound, HAProxy, nginx, postfix and many others.
+  It works by pre-pending a small header at the very beginning of a UDP datagram or TCP connection, which holds the initial source and destination addresses and ports, and can also contain several custom values in a Type-Length-Value format. More information about the Proxy Protocol can be found at https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt
+
+From dnsdist to its backend
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To enable the use of the Proxy Protocol between dnsdist and its backend, the ``useProxyProtocol`` parameter can be used when creating a :func:`new server <newServer>`:
+
+.. code-block:: lua
+
+  newServer{address="192.0.2.1:53", useProxyProtocol=true}
+
+This parameter indicates whether a Proxy Protocol version 2 (binary) header should be prepended to the query before forwarding it to the backend, over UDP or TCP.
+
+Both the PowerDNS Authoritative Server and the Recursor can parse PROXYv2 headers, if configured to do so with their `proxy-protocol-from` setting::
+
+  proxy-protocol-from=192.0.2.2
+
+For more information, see the `authoritative server's documentation <https://doc.powerdns.com/authoritative/settings.html#proxy-protocol-from>`_ or the `recursor's documentation <https://docs.powerdns.com/recursor/settings.html#proxy-protocol-from>`_.
+
+From clients to dnsdist
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Such a Proxy Protocol header can also be passed from the client to dnsdist, using :func:`setProxyProtocolACL` to specify which clients to accept it from:
+
+.. code-block:: lua
+
+  setProxyProtocolACL({'192.0.2.0/24'})
+
+Note that a Proxy Protocol payload will be required from these clients, regular DNS queries will no longer be accepted if they are not preceded by a Proxy Protocol payload.
+
+If :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
+
+Passing additional information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Custom values can be added to the header via :meth:`DNSQuestion:addProxyProtocolValue`, :meth:`DNSQuestion:setProxyProtocolValues`, :func:`SetAdditionalProxyProtocolValueAction` and :func:`SetProxyProtocolValuesAction`.
+
+Be careful that Proxy Protocol values are sent once at the beginning of the TCP connection for TCP and DoT queries.
+That means that values received on an incoming TCP connection will be inherited by subsequent queries received over the same incoming TCP connection, if any, but values set to a query will not be inherited by subsequent queries.
+
+Please also note that the maximum size of a Proxy Protocol header dnsdist is willing to accept is 512 bytes by default, although it can be set via :func:`setProxyProtocolMaximumPayloadSize`.
+
+.. _EDNS Client Subnet:
 
 Using EDNS Client Subnet
 ------------------------
 
-EDNS Client Subnet (ECS) is a standardized EDNS option designed to pass a bit of information about the client from a resolver to authoritative servers. While it was not designed with our use-case in mind, it can be used by dnsdist to send the source IP, but only the source IP, to its backend.
+.. note:
+  EDNS Client Subnet (ECS) is a standardized EDNS option designed to pass a bit of information about the client from a resolver to authoritative servers. While it was not designed with our use-case in mind, it can be used by dnsdist to send the source IP, but only the source IP, to its backend.
+
+In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``useClientSubnet`` parameter can be used when creating a :func:`new server <newServer>`:
+
+.. code-block:: lua
+
+  newServer{address="192.0.2.1:53", useClientSubnet=true}
 
-In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``useClientSubnet`` parameter can be used when creating a :func:`new server <newServer>`. This parameter indicates whether an EDNS Client Subnet option should be added to the request.
+This parameter indicates whether an EDNS Client Subnet option should be added to the request.
 
 The default source prefix-length is 24 for IPv4 and 56 for IPv6, meaning that for a query received from 192.0.2.42, the EDNS Client Subnet value sent to the backend will be 192.0.2.0.
-This can be changed with :func:`setECSSourcePrefixV4` and :func:`setECSSourcePrefixV6`.
+This can be changed with :func:`setECSSourcePrefixV4` and :func:`setECSSourcePrefixV6`:
+
+.. code-block:: lua
 
-If the incoming request already contains an EDNS Client Subnet value, it will not be overridden unless :func:`setECSOverride` is set to ``true``.
+  setECSSourcePrefixV4(32)
+  setECSSourcePrefixV6(128)
+
+If the incoming request already contains an EDNS Client Subnet value, it will not be overridden unless :func:`setECSOverride` is set to ``true``:
+
+.. code-block:: lua
+
+  setECSOverride(true)
+
+Advanced usage
+^^^^^^^^^^^^^^
 
 In addition to the global settings, rules and Lua bindings can alter this behavior per query:
 
@@ -26,7 +101,11 @@ In addition to the global settings, rules and Lua bindings can alter this behavi
 
 In effect this means that for the EDNS Client Subnet option to be added to the request, ``useClientSubnet`` should be set to ``true`` for the backend used (default to ``false``) and ECS should not have been disabled by calling :func:`SetDisableECSAction` or setting ``dq.useECS`` to ``false`` (default to true).
 
-Note that any trailing data present in the incoming query is removed when an OPT record has to be inserted.
+Drawbacks
+^^^^^^^^^
+
+.. warning::
+  Note that any trailing data present in the incoming query is removed when an OPT record has to be inserted.
 
 In addition to the drawback that it can only pass the source IP address, and the fact that it needs to override any existing ECS option, adding that option requires parsing and editing the query, as well as parsing and editing the response in most cases.
 
@@ -46,27 +125,6 @@ In addition to the drawback that it can only pass the source IP address, and the
 | Response, EDNS with ECS    | remove or edit the ECS option if needed         |
 +----------------------------+-------------------------------------------------+
 
-Proxy Protocol
---------------
-
-The Proxy Protocol has been designed by the HAProxy folks for HTTP over TCP, but is generic enough to be used in other places, and is a de-facto standard with implementations in nginx and postfix, for example.
-It works by pre-pending a small header at the very beginning of a UDP datagram or TCP connection, which holds the initial source and destination addresses and ports, and can also contain several custom values in a Type-Length-Value format. More information about the Proxy Protocol can be found at https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt
-
-In order to use it in dnsdist, the ``useProxyProtocol`` parameter can be used when creating a :func:`new server <newServer>`.
-This parameter indicates whether a Proxy Protocol version 2 (binary) header should be prepended to the query before forwarding it to the backend, over UDP or TCP.
-Such a Proxy Protocol header can also be passed from the client to dnsdist, using :func:`setProxyProtocolACL` to specify which clients to accept it from. Note that a proxy protocol payload will be required from these clients, regular DNS queries will no longer be accepted if they are not preceded by a proxy protocol payload.
-
-If :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
-
-Custom values can be added to the header via :meth:`DNSQuestion:addProxyProtocolValue`, :meth:`DNSQuestion:setProxyProtocolValues`, :func:`SetAdditionalProxyProtocolValueAction` and :func:`SetProxyProtocolValuesAction`.
-Be careful that Proxy Protocol values are sent once at the beginning of the TCP connection for TCP and DoT queries.
-That means that values received on an incoming TCP connection will be inherited by subsequent queries received over the same incoming TCP connection, if any, but values set to a query will not be inherited by subsequent queries.
-Please also note that the maximum size of a Proxy Protocol header dnsdist is willing to accept is 512 bytes by default, although it can be set via :func:`setProxyProtocolMaximumPayloadSize`.
-
-dnsdist 1.5.0 only supports outgoing Proxy Protocol. Support for parsing incoming Proxy Protocol headers has been implemented in 1.6.0, except for DoH where it does not make sense anyway, since HTTP headers already provide a mechanism for that.
-
-Both the PowerDNS Authoritative Server and the Recursor can parse PROXYv2 headers, if configured to do so with their `proxy-protocol-from` setting.
-
 X-Proxied-For
 -------------
 
@@ -85,16 +143,13 @@ That might be an issue by allowing clients to spoof their source address by addi
 
   addAction(RecordsTypeCountRule(DNSSection.Additional, 65280, 1, 65535), DropAction())
 
+.. _Influence on caching:
+
 Influence on caching
 --------------------
 
 When dnsdist's packet cache is in use, it is important to note that the cache lookup is done **after** adding ECS, because it prevents serving the same response to clients from different subnets when ECS is passed to an authoritative server doing GeoIP, or to a backend doing custom filtering.
-However that means that passing a narrow ECS source will effectively kill dnsdist's cache ratio, since a given answer will only be a cache hit for clients in the same ECS subnet. Therefore, unless a broad ECS source (greater than 24, for example) is used, it's better to disable caching.
-
-One exception to that rule is the zero-scope feature, which allows dnsdist to detect that a response sent by the backend has a 0-scope ECS value, indicating that the answer is not ECS-specific and can be used for all clients. dnsdist will then store the answer in its packet cache using the initial query, before ECS has been added.
-For that feature to work, dnsdist will look up twice into the packet cache when a query arrives, first without and then with ECS. That way, when most of the responses sent by a backend are not ECS-specific and can be served to all clients, dnsdist will still be able to have a great cache-hit ratio for non ECS-specific entries.
-
-That feature is enabled by setting ``disableZeroScope=false`` on :func:`newServer` (default) and ``parseECS=true`` on :func:`newPacketCache` (not the default).
+However that means that passing a narrow ECS source will effectively kill dnsdist's cache ratio, since a given answer will only be a cache hit for clients in the same ECS subnet. Therefore, unless a broad ECS source (greater than 24, for example) is used, it's better to disable caching. The zero-scope feature can be enabled to mitigate this drawback, as described in :doc:`zero-scope`.
 
 
 Things are different for the proxy protocol, because dnsdist then does the cache lookup **before** adding the payload. It means that caching can still be enabled as long as the response is not source-dependent, but should be disabled otherwise.
index 6fdef8cd22d78a2e4fcbaaa1004a6df415198d98..85a5692e5efb957d141f7fbeb912b8c1c4407a77 100644 (file)
@@ -34,7 +34,7 @@ To be able to use more CPU cores for UDP queries processing, it is possible to u
 Note that this require ``SO_REUSEPORT`` support in the underlying operating system (added for example in Linux 3.9).
 Please also be aware that doing so will increase lock contention and might not therefore scale linearly, as discussed below.
 
-Another possibility is to use the reuseport option to run several dnsdist processes in parallel on the same host, thus avoiding the lock contention issue at the cost of having to deal with the fact that the different processes will not share informations, like statistics or DDoS offenders.
+Another possibility is to use the reuseport option to run several dnsdist processes in parallel on the same host, thus avoiding the lock contention issue at the cost of having to deal with the fact that the different processes will not share information, like statistics or DDoS offenders.
 
 The UDP threads handling the responses from the backends do not use a lot of CPU, but if needed it is also possible to add the same backend several times to the dnsdist configuration to distribute the load over several responder threads::
 
@@ -101,7 +101,7 @@ Before 1.4.0, a TCP thread could only handle a single incoming connection at a t
 Note that before 1.6.0 the TCP worker threads were created at runtime, adding a new thread when the existing ones seemed to struggle with the load, until the maximum number of threads had been reached. Starting with 1.6.0 the configured number of worker threads are immediately created at startup.
 
 The maximum number of threads in the TCP / DNS over TLS pool is controlled by the :func:`setMaxTCPClientThreads` directive, and defaults to 10.
-This number can be increased to handle a large number of simultaneous TCP / DNS over TLS connections.
+This number can be increased to handle a large number of simultaneous TCP / DNS over TLS connections, but the default value should already be enough for most setups.
 
 If all the TCP threads are busy, new TCP connections are queued while they wait to be picked up. The maximum number of queued connections can be configured with :func:`setMaxTCPQueuedConnections` and defaults to 1000 (10000 on Linux since 1.6.0). Note that the size of the internal pipe used to distribute queries might need to be increased as well, using :func:`setTCPInternalPipeBufferSize`.
 Any value larger than 0 will cause new connections to be dropped if there are already too many queued.
index d701ffd56a47630222ab96e4c2ea72376b4d0618..d85f307c54316c2d637d86d0338891b4692dad34 100644 (file)
@@ -1,7 +1,7 @@
 ``AF_XDP`` / ``XSK``
 ====================
 
-Since 1.9.0, :program:`dnsdist` can use `AF_XDP <https://www.kernel.org/doc/html/v4.18/networking/af_xdp.html>`_ for high performance UDP packet processing recent Linux kernels (4.18+). It requires :program:`dnsdist` to have the ``CAP_NET_ADMIN`` and ``CAP_SYS_ADMIN`` capabilities at startup, and to have been compiled with the ``--with-xsk`` configure option.
+Since 1.9.0, :program:`dnsdist` can use `AF_XDP <https://www.kernel.org/doc/html/v4.18/networking/af_xdp.html>`_ for high performance UDP packet processing recent Linux kernels (4.18+). It requires :program:`dnsdist` to have the ``CAP_NET_ADMIN``, ``CAP_SYS_ADMIN`` and ``CAP_NET_RAW`` capabilities at startup, and to have been compiled with the ``--with-xsk`` configure option.
 
 .. note::
    To retain the required capabilities it is necessary to call :func:`addCapabilitiesToRetain` during startup, as :program:`dnsdist` drops capabilities after startup.
@@ -129,3 +129,15 @@ then with:
    :alt: AF_XDP CPU
 
 The first run handled roughly 1 million QPS, the second run 2.5 millions, with the CPU usage being much lower in the ``AF_XDP`` case.
+
+Running under systemd
+---------------------
+
+:program:`dnsdist` needs quite a few more additional permissions to use ``AF_XDP``:
+
+- to access the ``BPF`` maps directory, it needs to be able to go into the ``/sys/fs/bpf`` directory: one option is to ``chmod o+x /sys/fs/bpf``, a safer one is to restrict that to the ``dnsdist`` user instead via ``chgrp dnsdist /sys/fs/bpf && chmod g+x /sys/fs/bpf``
+- to read the ``BPF`` maps themselves, they need to be readable by the ``dnsdist`` user: ``chown -R dnsdist:dnsdist /sys/fs/bpf/dnsdist/``
+- to create ``AF_XDP`` sockets: add ``AF_XDP`` to ``RestrictAddressFamilies`` in the systemd unit file
+- to load a BPF program: add ``CAP_SYS_ADMIN`` to ``CapabilityBoundingSet`` and ``AmbientCapabilities`` in the systemd unit file
+- to create raw network sockets: add ``CAP_NET_RAW`` to ``CapabilityBoundingSet`` and ``AmbientCapabilities`` in the systemd unit file
+- and finally to lock enough memory: ensure that ``LimitMEMLOCK=infinity`` is set in the systemd unit file
diff --git a/pdns/dnsdistdist/docs/advanced/zero-scope.rst b/pdns/dnsdistdist/docs/advanced/zero-scope.rst
new file mode 100644 (file)
index 0000000..dbce6d3
--- /dev/null
@@ -0,0 +1,13 @@
+EDNS Client Subnet Zero Scope
+==================================
+
+As described in :doc:`Passing the source address to the backend <passing-source-address>`, :program:`dnsdist` can add an ``EDNS`` Client Subnet option to an incoming query to provide the downstream server with the address of the client talking to it. The downstream server can then potentially use this knowledge to reply with a response that has been tailored for this specific client, and should not be served to any other client. By default :program:`dnsdist` ensures that such a response is only served to intended client from its internal packet cache, including the added ``EDNS`` Client Subnet option in the data that is hashed to compute the cache key. This is the safest option, but is not optimal because some responses were not actually tied to a specific client subnet and could have been used for all of them. The downstream server can signal this by setting the scope in the ``EDNS`` Client Subnet option included in the response.
+
+This is where the zero-scope feature comes to play, allowing :program:`dnsdist` to parse and detect that a response sent by the backend has a scope value set to ``0``, indicating that the answer is not specific to a given client subnet and can be used for all of them. :program:`dnsdist` will then store the answer in its packet cache using the initial query as the key, before the ``EDNS`` Client Subnet option has been added.
+
+The second step needed for that feature to work properly is for :program:`dnsdist` to look up twice into the packet cache when a query arrives, first without and then with the ``EDNS`` Client Subnet option. That way, when most of the responses sent by a backend are not specific and can be served to all clients, :program:`dnsdist` will still be able to have a great cache-hit ratio for non specific entries.
+
+This feature is enabled when:
+
+* ``disableZeroScope=true`` is not set on :func:`newServer` (the default is ``false``)
+* and ``parseECS=true`` is set on :func:`newPacketCache` (which is not the default).
index a1351cd0e7d36b1531e287ba5a1dc06513864715..e783bdd76a56eef286fa6975eb50584e89b5942c 100644 (file)
@@ -1,6 +1,161 @@
 Changelog
 =========
 
+.. changelog::
+  :version: 1.8.4
+  :released: 20th of September 2024
+
+  Please review the :doc:`Upgrade Guide <../upgrade_guide>` before upgrading from versions < 1.8.x.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14467
+
+    Fix a compilation issue with clang by switching to ``pdns::views::UnsignedCharView``
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14680
+    :tickets: 14562
+
+    Fix build with boost 1.86.0
+
+  .. change::
+    :tags: Bug Fixes, DNS over TLS
+    :pullreq: 14679
+
+    Prevent a data race in incoming DNS over TLS connections by storing the ``OpenSSLTLSIOCtx`` in the connection
+
+.. changelog::
+  :version: 1.9.6
+  :released: 16th of July 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14436
+
+    Fix a race in the XSK/AF_XDP backend handling code
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14437
+
+    dns.cc: use pdns::views::UnsignedCharView
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14438
+
+    Make the logging functions available to all Lua environments
+
+  .. change::
+    :tags: Bug Fixes, Metrics
+    :pullreq: 14439
+    :tickets: 14395
+
+    Dedup Prometheus help and type lines for custom metrics with labels
+
+  .. change::
+    :tags: New Features
+    :pullreq: 14449
+
+    Add support for a callback when a new tickets key is added
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14450
+
+    Handle Quiche >= 0.22.0
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14452
+
+    Don't include openssl/engine.h if it's not going to be used (Sander Hoentjen)
+
+.. changelog::
+  :version: 1.9.5
+  :released: 20th of June 2024
+
+  .. change::
+    :tags: Bug Fixes, DNS over HTTPS
+    :pullreq: 14163
+
+    Reply to HTTP/2 PING frames immediately
+
+  .. change::
+    :tags: Bug Fixes, DNS over QUIC, DNS over HTTP3
+    :pullreq: 14166
+
+    Use the correct source IP for outgoing QUIC datagrams
+
+  .. change::
+    :tags: Bug Fixes, Webserver
+    :pullreq: 14170
+
+    Prevent a race when calling ``registerWebHandler`` at runtime
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14331
+
+    Syslog should be enabled by default
+
+  .. change::
+    :tags: Bug Fixes, DNS over HTTPS
+    :pullreq: 14332
+
+    Log the correct amount of bytes sent for DoH w/ nghttp2
+
+  .. change::
+    :tags: Bug Fixes, Webserver
+    :pullreq: 14333
+
+    Enforce a maximum number of HTTP request fields and a maximum HTTP request line size
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14334
+
+    Fix a warning when compiling the unit tests without XSK
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14335
+
+    autoconf: allow prerelease systemd versions (Chris Hofstaedtler)
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14336
+    :tickets: 14279
+
+    Edit the systemd unit file, ``CAP_BPF`` is no longer enough
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14337
+
+    Fix 'Error creating TCP worker' error message
+
+  .. change::
+    :tags: New Features
+    :pullreq: 14338
+
+    Add a Lua FFI function to set proxy protocol values
+
+  .. change::
+    :tags: New Features
+    :pullreq: 14339
+
+    Add Lua FFI bindings to generate SVC responses
+
+  .. change::
+    :tags: Bug Fixes, Webserver
+    :pullreq: 14342
+
+    Fix a race condition with custom Lua web handlers
+
 .. changelog::
   :version: 1.9.4
   :released: 13th of May 2024
@@ -5269,7 +5424,7 @@ Changelog
     :tags: Improvements
     :pullreq: 6637
 
-    Don't copy unitialized values of SuffixMatchTree
+    Don't copy uninitialized values of SuffixMatchTree
 
   .. change::
     :tags: Improvements
index 3defabcfd0b3cd2cf88168062144694a560ba4fd..1f8cce7f0d8d1eac4f4ebbd2266e116b1a3304cc 100644 (file)
@@ -290,7 +290,7 @@ The following actions exist.
 
   .. versionadded:: 1.5.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return a :ref:`DNSAction`. If the Lua code fails, ServFail is returned.
 
@@ -300,7 +300,7 @@ The following actions exist.
 
   .. versionadded:: 1.7.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return a :ref:`DNSAction`. If the Lua code fails, ServFail is returned.
 
@@ -314,7 +314,7 @@ The following actions exist.
 
   .. versionadded:: 1.7.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return a :ref:`DNSResponseAction`. If the Lua code fails, ServFail is returned.
 
@@ -328,7 +328,7 @@ The following actions exist.
 
   .. versionadded:: 1.5.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return a :ref:`DNSResponseAction`. If the Lua code fails, ServFail is returned.
 
index 0beb97fbbca661d6b63f27a84ffd344bd95fbd78..b33cf556c39792b9f81dd8ca86f8b76adefe9e0f 100644 (file)
@@ -42,7 +42,7 @@ Global configuration
   .. versionadded:: 1.7.0
 
   Accept a Linux capability as a string, or a list of these, to retain after startup so that privileged operations can still be performed at runtime.
-  Keeping ``CAP_BPF`` on kernel 5.8+ for example allows loading eBPF programs and altering eBPF maps at runtime even if the ``kernel.unprivileged_bpf_disabled`` sysctl is set.
+  Keeping ``CAP_SYS_ADMIN`` on kernel 5.8+ for example allows loading eBPF programs and altering eBPF maps at runtime even if the ``kernel.unprivileged_bpf_disabled`` sysctl is set.
   Note that this does not grant the capabilities to the process, doing so might be done by running it as root which we don't advise, or by adding capabilities via the systemd unit file, for example.
   Please also be aware that switching to a different user via ``--uid`` will still drop all capabilities.
 
@@ -390,9 +390,23 @@ Webserver configuration
   .. versionadded:: 1.7.0
 
   Hash the supplied password using a random salt, and returns a string that can be used with :func:`setWebserverConfig`.
+  For example, to get a hashed version of the ``test`` password:
 
-  :param string - password: The password to hash
-  :param int - workFactor: The work factor to use for the hash function (currently scrypt), as a power of two. Default is 1024.
+  .. code-block:: sh
+
+    > hashPassword('test')
+    $scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=
+
+  The full string can then be used with :func:`setWebserverConfig`:
+
+  .. code-block:: lua
+
+    setWebserverConfig({password="$scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=",
+                        apiKey="$scrypt$ln=10,p=1,r=8$RSYJ2QDmdlkNYMyqZF/FWw==$JQTftQCvAXR4Qtrg0lQmvrzgYEo3/PjEeuV4/2Oq1Vg=",
+                        acl="127.0.0.1/32"})
+
+  :param string password: The password to hash
+  :param int workFactor: The work factor to use for the hash function (currently scrypt), as a power of two. Default is 1024.
 
 .. function:: webserver(listen_address [, password[, apikey[, customHeaders[, acl]]]])
 
@@ -560,7 +574,7 @@ EDNS Client Subnet
 
 .. function:: setECSOverride(bool)
 
-  When ``useClientSubnet`` in :func:`newServer` is set and dnsdist adds an EDNS Client Subnet Client option to the query, override an existing option already present in the query, if any.
+  When ``useClientSubnet`` in :func:`newServer` is set and dnsdist adds an EDNS Client Subnet Client option to the query, override an existing option already present in the query, if any. Please see :doc:`../advanced/passing-source-address` for more information.
   Note that it's not recommended to enable ``setECSOverride`` in front of an authoritative server responding with EDNS Client Subnet information as mismatching data (ECS scopes) can confuse clients and lead to SERVFAIL responses on downstream nameservers.
 
   :param bool: Whether to override an existing EDNS Client Subnet option present in the query. Defaults to false
@@ -684,7 +698,7 @@ Servers
     ``maxCheckFailures``                     ``number``            "Allow ``number`` check failures before declaring the backend down, default: 1"
     ``checkInterval``                        ``number``            "The time in seconds between health checks"
     ``mustResolve``                          ``bool``              "Set to true when the health check MUST return a RCODE different from NXDomain, ServFail and Refused. Default is false, meaning that every RCODE except ServFail is considered valid"
-    ``useClientSubnet``                      ``bool``              "Add the client's IP address in the EDNS Client Subnet option when forwarding the query to this backend"
+    ``useClientSubnet``                      ``bool``              "Add the client's IP address in the EDNS Client Subnet option when forwarding the query to this backend. Default is false. Please see :doc:`../advanced/passing-source-address` for more information"
     ``source``                               ``string``            "The source address or interface to use for queries to this backend, by default this is left to the kernel's address selection.
                                                              The following formats are supported:
 
@@ -692,7 +706,7 @@ Servers
                                                              - interface name, e.g. ``""eth0""``
                                                              - address@interface, e.g. ``""192.0.2.2@eth0""`` "
     ``sockets``                              ``number``            "Number of UDP sockets (and thus source ports) used toward the backend server, defaults to a single one. Note that for backends which are multithreaded, this setting will have an effect on the number of cores that will be used to process traffic from dnsdist. For example you may want to set 'sockets' to a number somewhat higher than the number of worker threads configured in the backend, particularly if the Linux kernel is being used to distribute traffic to multiple threads listening on the same socket (via `reuseport`). See also :func:`setRandomizedOutgoingSockets`."
-    ``disableZeroScope``                     ``bool``              "Disable the EDNS Client Subnet 'zero scope' feature, which does a cache lookup for an answer valid for all subnets (ECS scope of 0) before adding ECS information to the query and doing the regular lookup. This requires the ``parseECS`` option of the corresponding cache to be set to true"
+    ``disableZeroScope``                     ``bool``              "Disable the EDNS Client Subnet :doc:`../advanced/zero-scope` feature, which does a cache lookup for an answer valid for all subnets (ECS scope of 0) before adding ECS information to the query and doing the regular lookup. Default is false. This requires the ``parseECS`` option of the corresponding cache to be set to true"
     ``rise``                                 ``number``               "Require ``number`` consecutive successful checks before declaring the backend up, default: 1"
     ``useProxyProtocol``                     ``bool``              "Add a proxy protocol header to the query, passing along the client's IP address and port along with the original destination address and port. Default is disabled."
     ``reconnectOnUp``                        ``bool``              "Close and reopen the sockets when a server transits from Down to Up. This helps when an interface is missing when dnsdist is started. Default is disabled."
@@ -979,7 +993,7 @@ See :doc:`../guides/cache` for a how to.
   * ``maxTTL=86400``: int - Cap the TTL for records to his number.
   * ``minTTL=0``: int - Don't cache entries with a TTL lower than this.
   * ``numberOfShards=20``: int - Number of shards to divide the cache into, to reduce lock contention. Used to be 1 (no shards) before 1.6.0, and is now 20.
-  * ``parseECS=false``: bool - Whether any EDNS Client Subnet option present in the query should be extracted and stored to be able to detect hash collisions involving queries with the same qname, qtype and qclass but a different incoming ECS value. Enabling this option adds a parsing cost and only makes sense if at least one backend might send different responses based on the ECS value, so it's disabled by default. Enabling this option is required for the 'zero scope' option to work
+  * ``parseECS=false``: bool - Whether any EDNS Client Subnet option present in the query should be extracted and stored to be able to detect hash collisions involving queries with the same qname, qtype and qclass but a different incoming ECS value. Enabling this option adds a parsing cost and only makes sense if at least one backend might send different responses based on the ECS value, so it's disabled by default. Enabling this option is required for the :doc:`../advanced/zero-scope` option to work
   * ``staleTTL=60``: int - When the backend servers are not reachable, and global configuration ``setStaleCacheEntriesTTL`` is set appropriately, TTL that will be used when a stale cache entry is returned.
   * ``temporaryFailureTTL=60``: int - On a SERVFAIL or REFUSED from the backend, cache for this amount of seconds..
   * ``cookieHashing=false``: bool - If true, EDNS Cookie values will be hashed, resulting in separate entries for different cookies in the packet cache. This is required if the backend is sending answers with EDNS Cookies, otherwise a client might receive an answer with the wrong cookie.
@@ -1368,10 +1382,10 @@ Status, Statistics and More
     ``options`` optional parameter added
 
   This function shows all backend servers currently configured and some statistics.
-  These statics have the following fields:
+  These statistics have the following fields:
 
   * ``#`` - The number of the server, can be used as the argument for :func:`getServer`
-  * ``UUID`` - The UUID of the backend. Can be set with the ``id`` option of :func:`newServer`
+  * ``Name`` - The name of the backend, if any
   * ``Address`` - The IP address and port of the server
   * ``State`` - The current state of the server
   * ``Qps`` - Current number of queries per second
@@ -1381,8 +1395,11 @@ Status, Statistics and More
   * ``Queries`` - Total amount of queries sent to this server
   * ``Drops`` - Number of queries that were dropped by this server
   * ``Drate`` - Number of queries dropped per second by this server
-  * ``Lat`` - The latency of this server in milliseconds
+  * ``Lat`` - The latency of this server, for queries forwarded over UDP, in milliseconds
+  * ``Outstanding`` - The current number of in-flight queries
   * ``Pools`` - The pools this server belongs to
+  * ``UUID`` - The UUID of the backend, only displayed when the ``showUUIDs`` option is set. Can be set with the ``id`` option of :func:`newServer`
+  * ``TCP`` - The latency of this server, for queries forwarded over TCP, in milliseconds
 
   :param table options: A table with key: value pairs with display options.
 
@@ -1504,6 +1521,9 @@ Status, Statistics and More
 
 .. function:: topSlow([num[, limit[, labels]]])
 
+  .. versionchanged:: 1.9.7
+    queries that timed out are no longer reported by ``topSlow``, see :func:`topTimeouts` instead
+
   Print the ``num`` slowest queries that are slower than ``limit`` milliseconds.
   Optionally grouped by the rightmost ``labels`` DNS labels.
 
@@ -1511,6 +1531,16 @@ Status, Statistics and More
   :param int limit: Show queries slower than this amount of milliseconds, defaults to 2000
   :param int label: Number of labels to cut down to
 
+.. function:: topTimeouts([num[, labels]])
+
+  .. versionadded:: 1.9.7
+
+  Print the ``num`` queries that timed out the most.
+  Optionally grouped by the rightmost ``labels`` DNS labels.
+
+  :param int num: Number to show, defaults to 10
+  :param int label: Number of labels to cut down to
+
 .. _dynblocksref:
 
 Dynamic Blocks
@@ -1530,7 +1560,7 @@ Dynamic Blocks
   :param int clientIPMask: The network mask to apply to the address. Default is 32 for IPv4, 128 for IPv6.
   :param int clientIPPortMask: The port mask to use to specify a range of ports to match, when the clients are behind a CG-NAT.
 
-  Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action paramater.
+  Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action parameter.
 
 .. function:: addDynBlocks(addresses, message[, seconds=10[, action]])
 
@@ -1543,7 +1573,7 @@ Dynamic Blocks
   :param int seconds: The number of seconds this block to expire
   :param int action: The action to take when the dynamic block matches, see :ref:`DNSAction <DNSAction>`. (default to DNSAction.None, meaning the one set with :func:`setDynBlocksAction` is used)
 
-  Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action paramater.
+  Please see the documentation for :func:`setDynBlocksAction` to confirm which actions are supported by the action parameter.
 
 .. function:: clearDynBlocks()
 
@@ -2173,6 +2203,17 @@ Other functions
   Code is supplied as a string, not as a function object.
   Note that this function does nothing in 'client' or 'config-check' modes.
 
+.. function:: setTicketsKeyAddedHook(callback)
+
+  .. versionadded:: 1.9.6
+
+  Set a Lua function that will be called everytime a new tickets key is added. The function receives:
+
+  * the key content as a string
+  * the keylen as an integer
+
+  See :doc:`../advanced/tls-sessions-management` for more information.
+
 .. function:: submitToMainThread(cmd, dict)
 
   .. versionadded:: 1.8.0
index a5040c7598cf23c3d58dce9ad93653df8f6c2864..4160c511705c03bebddcd290ff630a227393e37e 100755 (executable)
@@ -127,7 +127,7 @@ These constants represent an Action that can be returned from :func:`LuaAction`
  * ``DNSAction.Pool``: use the specified pool to forward this query
  * ``DNSAction.Refused``: return a response with a Refused rcode
  * ``DNSAction.ServFail``: return a response with a ServFail rcode
- * ``DNSAction.SetTag``: set a tag, see :function:`SetTagAction` (only used for Dynamic Block actions, see meth:`DNSQuestion:setTag` to set a tag from Lua)
+ * ``DNSAction.SetTag``: set a tag, see :func:`SetTagAction` (only used for Dynamic Block actions, see meth:`DNSQuestion:setTag` to set a tag from Lua)
  * ``DNSAction.Spoof``: spoof the response using the supplied IPv4 (A), IPv6 (AAAA) or string (CNAME) value. TTL will be 60 seconds.
  * ``DNSAction.SpoofPacket``: spoof the response using the supplied raw packet
  * ``DNSAction.SpoofRaw``: spoof the response using the supplied raw value as record data (see also :meth:`DNSQuestion:spoof` and :func:`dnsdist_ffi_dnsquestion_spoof_raw` to spoof multiple values)
index 9da5b96055725357b2af1f03f4c5a67f613c2cd0..0d5418b6186a73594ccaef2988c27101a78fca9f 100644 (file)
@@ -22,9 +22,10 @@ To use FrameStream transport, :program:`dnsdist` must have been built with `libf
   :param string path: A local AF_UNIX socket path. Note that most platforms have a rather short limit on the length.
   :param table options: A table with key: value pairs with options.
 
-  The following options apply to the settings of the framestream library. Refer to the documentation of that
-  library for the default and allowed values for these options, as well as their exact descriptions.
-  For all these options, absence or a zero value has the effect of using the library-provided default value.
+  The following options apply to the settings of the `framestream library
+  <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default and
+  allowed values for these options, as well as their exact descriptions. For all these options, absence or a
+  zero value has the effect of using the library-provided default value.
 
   * ``bufferHint=0``: unsigned
   * ``flushTimeout=0``: unsigned
@@ -45,9 +46,10 @@ To use FrameStream transport, :program:`dnsdist` must have been built with `libf
   :param string address: An IP:PORT combination where the logger will connect to.
   :param table options: A table with key: value pairs with options.
 
-  The following options apply to the settings of the framestream library. Refer to the documentation of that
-  library for the default and allowed values for these options, as well as their exact descriptions.
-  For all these options, absence or a zero value has the effect of using the library-provided default value.
+  The following options apply to the settings of the `framestream library
+  <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default and
+  allowed values for these options, as well as their exact descriptions. For all these options, absence or a
+  zero value has the effect of using the library-provided default value.
 
   * ``bufferHint=0``: unsigned
   * ``flushTimeout=0``: unsigned
index 32dbd84d006969088ed471f13ea603bf9ae83675..b2098b896959dacf66da193b02efad8d4c0571bf 100644 (file)
@@ -109,7 +109,7 @@ Selectors can be combined via :func:`AndRule`, :func:`OrRule` and :func:`NotRule
 
   .. versionadded:: 1.7.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return true if the query matches, or false otherwise. If the Lua code fails, false is returned.
 
@@ -123,7 +123,7 @@ Selectors can be combined via :func:`AndRule`, :func:`OrRule` and :func:`NotRule
 
   .. versionadded:: 1.5.0
 
-  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi.hh``.
+  Invoke a Lua FFI function that accepts a pointer to a ``dnsdist_ffi_dnsquestion_t`` object, whose bindings are defined in ``dnsdist-lua-ffi-interface.h``.
 
   The ``function`` should return true if the query matches, or false otherwise. If the Lua code fails, false is returned.
 
index c6147313f121e5a61b1ddb90d40f3095142aa806..1614793ec55b2ffe4a6624c1f06e18916d91af58 100644 (file)
@@ -40,6 +40,11 @@ Tuning related functions
   .. versionchanged:: 1.7.0
     The default value has been set back to 10.
 
+  .. warning::
+
+    Be wary of using a too large value for this setting. :program:`dnsdist` keeps a per-thread cache of TCP connections to its backends so using a large value could, in addition to creating a lot of threads,
+    lead to a very high number of TCP connections to the backends. PowerDNS Recursor, for example, has a low default limit (128) for the number of incoming TCP connections it is willing to accept.
+
   Set the maximum of TCP client threads, handling TCP connections. Before 1.4.0 a TCP thread could only handle a single incoming TCP connection at a time, while after 1.4.0 it can handle a larger number of them simultaneously.
 
   Note that before 1.6.0 the TCP worker threads were created at runtime, adding a new thread when the existing ones seemed to struggle with the load, until the maximum number of threads had been reached. Starting with 1.6.0 the configured number of worker threads are immediately created at startup.
index 7c3631cc42cdfeb93e824bfad1105b39c5d26a0e..ff38967d66ea246409bb56a56223d8c6c8432eb3 100644 (file)
@@ -1,5 +1,5 @@
 #
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
 # by the following command:
 #
 #    pip-compile --generate-hashes requirements.in
@@ -14,9 +14,9 @@ babel==2.14.0 \
     --hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
     --hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
     # via sphinx
-certifi==2024.2.2 \
-    --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
-    --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
+certifi==2024.7.4 \
+    --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+    --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
     # via requests
 changelog==0.5.8 \
     --hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
@@ -212,9 +212,9 @@ python-dateutil==2.8.2 \
     --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
     --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
     # via fake-factory
-requests==2.31.0 \
-    --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
-    --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+requests==2.32.2 \
+    --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
+    --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
     # via sphinx
 six==1.16.0 \
     --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
@@ -257,9 +257,9 @@ sphinxcontrib-websupport==1.2.4 \
     --hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
     --hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
     # via sphinx
-urllib3==2.2.0 \
-    --hash=sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20 \
-    --hash=sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224
+urllib3==2.2.2 \
+    --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+    --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
     # via requests
 
 # WARNING: The following packages were not pinned, but pip requires them to be
index f75cc10383b46bddfa469c231cd8c51521145f6e..6fb5b2939cdc2d256e34c58d5fbab6e235d1a761 100644 (file)
@@ -207,7 +207,6 @@ struct DOHServerConfig
   DOHServerConfig& operator=(DOHServerConfig&&) = delete;
   ~DOHServerConfig() = default;
 
-  LocalHolders holders;
   std::set<std::string, std::less<>> paths;
   h2o_globalconf_t h2o_config{};
   h2o_context_t h2o_ctx{};
@@ -503,12 +502,9 @@ public:
     memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
 
     if (!response.isAsync()) {
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
       dr.ids.du = std::move(dohUnit);
 
-      if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false)) {
+      if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, dr, false)) {
         if (dr.ids.du) {
           dohUnit = getDUFromIDS(dr.ids);
           dohUnit->status_code = 503;
@@ -699,7 +695,6 @@ static void processDOHQuery(DOHUnitUniquePtr&& unit, bool inMainThread = false)
 
     remote = ids.origRemote;
     DOHServerConfig* dsc = unit->dsc;
-    auto& holders = dsc->holders;
     ClientState& clientState = *dsc->clientState;
 
     if (unit->query.size() < sizeof(dnsheader) || unit->query.size() > std::numeric_limits<uint16_t>::max()) {
@@ -760,7 +755,7 @@ static void processDOHQuery(DOHUnitUniquePtr&& unit, bool inMainThread = false)
     ids.cs = &clientState;
     dnsQuestion.sni = std::move(unit->sni);
     ids.du = std::move(unit);
-    auto result = processQuery(dnsQuestion, holders, downstream);
+    auto result = processQuery(dnsQuestion, downstream);
 
     if (result == ProcessQueryResult::Drop) {
       unit = getDUFromIDS(ids);
@@ -1075,8 +1070,7 @@ static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
       }
     }
 
-    auto& holders = dsc->holders;
-    if (!holders.acl->match(remote)) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
       ++dnsdist::metrics::g_stats.aclDrops;
       vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort());
       h2o_send_error_403(req, "Forbidden", "DoH query not allowed because of ACL", 0);
@@ -1387,7 +1381,7 @@ static void on_accept(h2o_socket_t *listener, const char *err)
     return;
   }
 
-  if (dsc->dohFrontend->d_earlyACLDrop && !dsc->dohFrontend->d_trustForwardedForHeader && !dsc->holders.acl->match(remote)) {
+  if (dsc->dohFrontend->d_earlyACLDrop && !dsc->dohFrontend->d_trustForwardedForHeader && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
     ++dnsdist::metrics::g_stats.aclDrops;
     vinfolog("Dropping DoH connection from %s because of ACL", remote.toStringWithPort());
     h2o_socket_close(sock);
@@ -1650,15 +1644,12 @@ void DOHUnit::handleUDPResponse(PacketBuffer&& udpResponse, InternalQueryState&&
     }
   }
   if (!dohUnit->truncated) {
-    static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-    static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
     DNSResponse dnsResponse(dohUnit->ids, udpResponse, dohUnit->downstream);
     dnsheader cleartextDH{};
     memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
 
     dnsResponse.ids.du = std::move(dohUnit);
-    if (!processResponse(udpResponse, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+    if (!processResponse(udpResponse, dnsResponse, false)) {
       if (dnsResponse.ids.du) {
         dohUnit = getDUFromIDS(dnsResponse.ids);
         dohUnit->status_code = 503;
deleted file mode 120000 (symlink)
index 3b4ad59bc89eb8f7946a72828f900138ccaba763..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../doh.hh
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..04fe358ec5110aa6e111738b822ef864686dfcf1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "config.h"
+
+#ifdef HAVE_DNS_OVER_HTTPS
+#ifdef HAVE_LIBH2OEVLOOP
+
+#include <ctime>
+#include <memory>
+#include <string>
+
+struct CrossProtocolQuery;
+struct DNSQuestion;
+
+std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
+
+#include "dnsdist-doh-common.hh"
+
+struct H2ODOHFrontend : public DOHFrontend
+{
+public:
+  void setup() override;
+  void reloadCertificates() override;
+
+  void rotateTicketsKey(time_t now) override;
+  void loadTicketsKeys(const std::string& keyFile) override;
+  void handleTicketsKeyRotation() override;
+  std::string getNextTicketsKeyRotation() const override;
+  size_t getTicketsKeysCount() override;
+};
+
+void dohThread(ClientState* clientState);
+
+#endif /* HAVE_LIBH2OEVLOOP */
+#endif /* HAVE_DNS_OVER_HTTPS  */
index 7ff4748f1551521e65daa445cbec8d17d0b9932a..661e9c61822366d885c376138cfdf3025a846000 100644 (file)
@@ -96,7 +96,6 @@ struct DOH3ServerConfig
 
   using ConnectionsMap = std::map<PacketBuffer, H3Connection>;
 
-  LocalHolders holders;
   ConnectionsMap d_connections;
   QuicheConfig config;
   QuicheHTTP3Config http3config;
@@ -142,12 +141,9 @@ public:
 
     if (!response.isAsync()) {
 
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
       dnsResponse.ids.doh3u = std::move(unit);
 
-      if (!processResponse(dnsResponse.ids.doh3u->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+      if (!processResponse(dnsResponse.ids.doh3u->response, dnsResponse, false)) {
         if (dnsResponse.ids.doh3u) {
 
           sendBackDOH3Unit(std::move(dnsResponse.ids.doh3u), "Response dropped by rules");
@@ -491,10 +487,9 @@ static void processDOH3Query(DOH3UnitUniquePtr&& doh3Unit)
 
     remote = unit->ids.origRemote;
     DOH3ServerConfig* dsc = unit->dsc;
-    auto& holders = dsc->holders;
     ClientState& clientState = *dsc->clientState;
 
-    if (!holders.acl->match(remote)) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
       vinfolog("Query from %s (DoH3) dropped because of ACL", remote.toStringWithPort());
       ++dnsdist::metrics::g_stats.aclDrops;
       unit->response.clear();
@@ -562,7 +557,7 @@ static void processDOH3Query(DOH3UnitUniquePtr&& doh3Unit)
     });
     unit->ids.cs = &clientState;
 
-    auto result = processQuery(dnsQuestion, holders, downstream);
+    auto result = processQuery(dnsQuestion, downstream);
     if (result == ProcessQueryResult::Drop) {
       unit->status_code = 403;
       handleImmediateResponse(std::move(unit), "DoH3 dropped query");
index e757b1a96883474b5954e7315c32b54e2379459d..661fe5c2b5f96885be1aa95a1e3876d3f22277f0 100644 (file)
@@ -91,7 +91,6 @@ struct DOQServerConfig
 
   using ConnectionsMap = std::map<PacketBuffer, Connection>;
 
-  LocalHolders holders;
   ConnectionsMap d_connections;
   QuicheConfig config;
   ClientState* clientState{nullptr};
@@ -135,13 +134,9 @@ public:
     memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
 
     if (!response.isAsync()) {
-
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::ResponseRules).getLocal();
-      static thread_local LocalStateHolder<vector<dnsdist::rules::ResponseRuleAction>> localCacheInsertedRespRuleActions = dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal();
-
       dnsResponse.ids.doqu = std::move(unit);
 
-      if (!processResponse(dnsResponse.ids.doqu->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+      if (!processResponse(dnsResponse.ids.doqu->response, dnsResponse, false)) {
         if (dnsResponse.ids.doqu) {
 
           sendBackDOQUnit(std::move(dnsResponse.ids.doqu), "Response dropped by rules");
@@ -267,7 +262,12 @@ static bool tryWriteResponse(Connection& conn, const uint64_t streamID, PacketBu
 {
   size_t pos = 0;
   while (pos < response.size()) {
+#ifdef HAVE_QUICHE_STREAM_ERROR_CODES
+    uint64_t quicheErrorCode{0};
+    auto res = quiche_conn_stream_send(conn.d_conn.get(), streamID, &response.at(pos), response.size() - pos, true, &quicheErrorCode);
+#else
     auto res = quiche_conn_stream_send(conn.d_conn.get(), streamID, &response.at(pos), response.size() - pos, true);
+#endif
     if (res == QUICHE_ERR_DONE) {
       response.erase(response.begin(), response.begin() + static_cast<ssize_t>(pos));
       return false;
@@ -408,10 +408,9 @@ static void processDOQQuery(DOQUnitUniquePtr&& doqUnit)
 
     remote = unit->ids.origRemote;
     DOQServerConfig* dsc = unit->dsc;
-    auto& holders = dsc->holders;
     ClientState& clientState = *dsc->clientState;
 
-    if (!holders.acl->match(remote)) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
       vinfolog("Query from %s (DoQ) dropped because of ACL", remote.toStringWithPort());
       ++dnsdist::metrics::g_stats.aclDrops;
       unit->response.clear();
@@ -475,7 +474,7 @@ static void processDOQQuery(DOQUnitUniquePtr&& doqUnit)
     });
     unit->ids.cs = &clientState;
 
-    auto result = processQuery(dnsQuestion, holders, downstream);
+    auto result = processQuery(dnsQuestion, downstream);
     if (result == ProcessQueryResult::Drop) {
       handleImmediateResponse(std::move(unit), "DoQ dropped query");
       return;
@@ -606,9 +605,17 @@ static void handleReadableStream(DOQFrontend& frontend, ClientState& clientState
     bool fin = false;
     auto existingLength = streamBuffer.size();
     streamBuffer.resize(existingLength + 512);
+#ifdef HAVE_QUICHE_STREAM_ERROR_CODES
+    uint64_t quicheErrorCode{0};
+    auto received = quiche_conn_stream_recv(conn.d_conn.get(), streamID,
+                                            &streamBuffer.at(existingLength), 512,
+                                            &fin,
+                                            &quicheErrorCode);
+#else
     auto received = quiche_conn_stream_recv(conn.d_conn.get(), streamID,
                                             &streamBuffer.at(existingLength), 512,
                                             &fin);
+#endif
     if (received == 0 || received == QUICHE_ERR_DONE) {
       streamBuffer.resize(existingLength);
       return;
index 5c3297bc7821f45861a1788832a22b93c156d29d..672fe0f79f225c0e4ec30648bf464ed05906e581 100644 (file)
@@ -10,10 +10,17 @@ AC_DEFUN([PDNS_WITH_QUICHE], [
 
   AS_IF([test "x$with_quiche" != "xno"], [
     AS_IF([test "x$with_quiche" = "xyes" -o "x$with_quiche" = "xauto"], [
-      PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
+      PKG_CHECK_MODULES([QUICHE], [quiche >= 0.22.0], [
         [HAVE_QUICHE=1]
         AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
-      ], [ : ])
+        AC_DEFINE([HAVE_QUICHE_STREAM_ERROR_CODES], [1], [Define to 1 if the Quiche API includes error code in quiche_conn_stream_recv and quiche_conn_stream_send])
+      ], [
+        # Quiche is older than 0.22.0, or no Quiche at all
+        PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
+          [HAVE_QUICHE=1]
+          AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
+        ], [ : ])
+      ])
     ])
   ])
   AM_CONDITIONAL([HAVE_QUICHE], [test "x$QUICHE_LIBS" != "x"])
index fca9fd209de6e3419761aeab2066ad7449fa2b6f..8b89539c2eb89f524a4650ba77fc7969b5a08553 100644 (file)
@@ -34,8 +34,6 @@
 #include "dolog.hh"
 #include <unistd.h>
 
-bool g_verbose{false};
-
 BOOST_AUTO_TEST_SUITE(test_dnscrypt_cc)
 
 #ifdef HAVE_DNSCRYPT
index a7bb4e37b39a48a94c3fbbc45434ef4c279f5bd1..caf5d42c5b90142c67bad557e09051a28ab02558 100644 (file)
@@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(test_Response)
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
 
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::A));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::AAAA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, newTarget);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::A));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::AAAA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, newTarget);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
   }
 
   {
@@ -156,14 +156,14 @@ BOOST_AUTO_TEST_CASE(test_Response)
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
 
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::A));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::AAAA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, notTheTarget);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::A));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::AAAA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, notTheTarget);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
   }
 
   {
@@ -194,18 +194,18 @@ BOOST_AUTO_TEST_CASE(test_Response)
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
 
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 3U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::CNAME));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, newTarget);
-    auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0).first);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::CNAME));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, newTarget);
+    auto content = getRR<UnknownRecordContent>(mdp.d_answers.at(0));
     BOOST_REQUIRE(content != nullptr);
     BOOST_CHECK_EQUAL(content->getRawContent().size(), notTheTarget.getStorage().size());
 
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::A));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, notTheTarget);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::A));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, notTheTarget);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(2).d_name, g_rootdnsname);
   }
 
   {
@@ -259,11 +259,11 @@ BOOST_AUTO_TEST_CASE(test_Response)
 
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 7U);
     for (const auto& answer : mdp.d_answers) {
-      if (answer.first.d_type == QType::OPT) {
+      if (answer.d_type == QType::OPT) {
         continue;
       }
-      BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
-      BOOST_CHECK_EQUAL(answer.first.d_name, newTarget);
+      BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+      BOOST_CHECK_EQUAL(answer.d_name, newTarget);
     }
   }
 
@@ -322,11 +322,11 @@ BOOST_AUTO_TEST_CASE(test_Response)
 
       BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 8U);
       for (const auto& answer : mdp.d_answers) {
-        if (answer.first.d_type == QType::OPT) {
+        if (answer.d_type == QType::OPT) {
           continue;
         }
-        BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
-        BOOST_CHECK_EQUAL(answer.first.d_name, target);
+        BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+        BOOST_CHECK_EQUAL(answer.d_name, target);
       }
     }
 
@@ -344,11 +344,11 @@ BOOST_AUTO_TEST_CASE(test_Response)
 
       BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 8U);
       for (const auto& answer : mdp.d_answers) {
-        if (answer.first.d_type == QType::OPT) {
+        if (answer.d_type == QType::OPT) {
           continue;
         }
-        BOOST_CHECK_EQUAL(answer.first.d_class, QClass::IN);
-        BOOST_CHECK_EQUAL(answer.first.d_name, newTarget);
+        BOOST_CHECK_EQUAL(answer.d_class, QClass::IN);
+        BOOST_CHECK_EQUAL(answer.d_name, newTarget);
       }
     }
   }
@@ -377,9 +377,9 @@ BOOST_AUTO_TEST_CASE(test_Response)
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
 
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::ALIAS));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, target);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::ALIAS));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, target);
   }
 }
 
index df8f4d87fafe89d5819d59a3b415d2c0c9e06d05..33e8140ee2f2199a7453bd18582973acbd5f0db9 100644 (file)
 #include <boost/test/unit_test.hpp>
 
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-cache.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-web.hh"
 #include "dnsparser.hh"
 #include "dnswriter.hh"
 
-bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
+bool dnsdist::webserver::addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
 {
   return true;
 }
@@ -236,7 +238,7 @@ BOOST_AUTO_TEST_CASE(test_Query)
   }
 
   {
-    BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), g_ECSSourcePrefixV4);
+    BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4);
     dnsdist_ffi_dnsquestion_set_ecs_prefix_length(&lightDQ, 65535);
     BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), 65535U);
   }
@@ -250,14 +252,11 @@ BOOST_AUTO_TEST_CASE(test_Query)
 
   {
     BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_trailing_data(&lightDQ, nullptr), 0U);
-#if 0
-    // DNSQuestion::setTrailingData() and DNSQuestion::getTrailingData() are currently stubs in the test runner
     std::string garbage("thisissomegarbagetrailingdata");
     BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_set_trailing_data(&lightDQ, garbage.data(), garbage.size()), true);
     const char* buffer = nullptr;
     BOOST_REQUIRE_EQUAL(dnsdist_ffi_dnsquestion_get_trailing_data(&lightDQ, &buffer), garbage.size());
     BOOST_CHECK_EQUAL(garbage, std::string(buffer));
-#endif
   }
 
   {
@@ -474,10 +473,10 @@ BOOST_AUTO_TEST_CASE(test_PacketCache)
   testPool->packetCache = packetCache;
   std::string poolWithNoCacheName("test-pool-without-cache");
   auto testPoolWithNoCache = std::make_shared<ServerPool>();
-  auto localPools = g_pools.getCopy();
-  localPools.emplace(poolName, testPool);
-  localPools.emplace(poolWithNoCacheName, testPoolWithNoCache);
-  g_pools.setState(localPools);
+  dnsdist::configuration::updateRuntimeConfiguration([&poolName, &testPool, &poolWithNoCacheName, &testPoolWithNoCache](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_pools.emplace(poolName, testPool);
+    config.d_pools.emplace(poolWithNoCacheName, testPoolWithNoCache);
+  });
 
   {
     dnsdist_ffi_domain_list_t* list = nullptr;
@@ -575,6 +574,53 @@ BOOST_AUTO_TEST_CASE(test_ProxyProtocol)
   }
 }
 
+BOOST_AUTO_TEST_CASE(test_ProxyProtocolQuery)
+{
+  InternalQueryState ids;
+  ids.origRemote = ComboAddress("192.0.2.1:4242");
+  ids.origDest = ComboAddress("192.0.2.255:53");
+  ids.qtype = QType::A;
+  ids.qclass = QClass::IN;
+  ids.protocol = dnsdist::Protocol::DoUDP;
+  ids.qname = DNSName("www.powerdns.com.");
+  ids.queryRealTime.start();
+  PacketBuffer query;
+  GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
+  pwQ.getHeader()->rd = 1;
+  pwQ.getHeader()->id = htons(42);
+
+  DNSQuestion dnsQuestion(ids, query);
+  dnsdist_ffi_dnsquestion_t lightDQ(&dnsQuestion);
+
+  std::vector<dnsdist_ffi_proxy_protocol_value> values;
+  values.push_back({"test-value", 10U, 1U});
+
+  {
+    auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(nullptr, values.size(), values.data());
+    BOOST_CHECK_EQUAL(added, false);
+  }
+
+  {
+    auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, 0, values.data());
+    BOOST_CHECK_EQUAL(added, false);
+  }
+
+  {
+    auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, values.size(), nullptr);
+    BOOST_CHECK_EQUAL(added, false);
+  }
+
+  {
+    auto added = dnsdist_ffi_dnsquestion_add_proxy_protocol_values(&lightDQ, values.size(), values.data());
+    BOOST_CHECK_EQUAL(added, true);
+    BOOST_REQUIRE(dnsQuestion.proxyProtocolValues != nullptr);
+    BOOST_REQUIRE_EQUAL(dnsQuestion.proxyProtocolValues->size(), values.size());
+    BOOST_CHECK_EQUAL(dnsQuestion.proxyProtocolValues->at(0).type, values.at(0).type);
+    BOOST_REQUIRE_EQUAL(dnsQuestion.proxyProtocolValues->at(0).content.size(), values.at(0).size);
+    BOOST_CHECK_EQUAL(memcmp(dnsQuestion.proxyProtocolValues->at(0).content.data(), values.at(0).value, values.at(0).size), 0);
+  }
+}
+
 BOOST_AUTO_TEST_CASE(test_PacketOverlay)
 {
   const DNSName target("powerdns.com.");
@@ -703,7 +749,7 @@ BOOST_AUTO_TEST_CASE(test_RingBuffers)
   gettime(&now);
 
   g_rings.reset();
-  g_rings.init();
+  g_rings.init(10000, 10);
   BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
 
   g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
@@ -839,4 +885,64 @@ BOOST_AUTO_TEST_CASE(test_hash)
   }
 }
 
+BOOST_AUTO_TEST_CASE(test_SVC_Generation)
+{
+  dnsdist_ffi_svc_record_parameters* parameters{nullptr};
+
+  {
+    /* invalid parameters */
+    BOOST_CHECK_EQUAL(dnsdist_ffi_svc_record_parameters_new(nullptr, 0, false, &parameters), false);
+    BOOST_CHECK_EQUAL(dnsdist_ffi_svc_record_parameters_new("powerdns.com.", 0, false, nullptr), false);
+  }
+
+  BOOST_REQUIRE_EQUAL(dnsdist_ffi_svc_record_parameters_new("powerdns.com.", 1, true, &parameters), true);
+  BOOST_REQUIRE(parameters != nullptr);
+
+  {
+    /* invalid parameters */
+    dnsdist_ffi_svc_record_parameters_set_port(nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_set_ech(nullptr, "alpn", 4);
+    dnsdist_ffi_svc_record_parameters_set_additional_param(nullptr, 7, "/dns-query{?dns}", 16);
+    dnsdist_ffi_svc_record_parameters_set_additional_param(parameters, 7, nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_mandatory_param(nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_alpn(nullptr, "h2", 2);
+    dnsdist_ffi_svc_record_parameters_add_alpn(parameters, nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_ipv4_hint(parameters, nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_ipv4_hint(nullptr, nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_ipv6_hint(parameters, nullptr, 0);
+    dnsdist_ffi_svc_record_parameters_add_ipv6_hint(nullptr, nullptr, 0);
+    dnsdist_ffi_dnsquestion_generate_svc_response(nullptr, nullptr, 0, 0);
+  }
+
+  dnsdist_ffi_svc_record_parameters_set_port(parameters, 443);
+  dnsdist_ffi_svc_record_parameters_set_ech(parameters, "binary", 6);
+  dnsdist_ffi_svc_record_parameters_set_additional_param(parameters, 7, "/dns-query{?dns}", 16);
+  dnsdist_ffi_svc_record_parameters_add_mandatory_param(parameters, 7);
+  dnsdist_ffi_svc_record_parameters_add_alpn(parameters, "h2", 2);
+  dnsdist_ffi_svc_record_parameters_add_ipv4_hint(parameters, "9.9.9.9", 8);
+  dnsdist_ffi_svc_record_parameters_add_ipv6_hint(parameters, "2620:fe::fe", 11);
+
+  {
+    InternalQueryState ids;
+    ids.origRemote = ComboAddress("192.0.2.1:4242");
+    ids.origDest = ComboAddress("192.0.2.255:53");
+    ids.qtype = QType::A;
+    ids.qclass = QClass::IN;
+    ids.protocol = dnsdist::Protocol::DoUDP;
+    ids.qname = DNSName("www.powerdns.com.");
+    ids.queryRealTime.start();
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
+    pwQ.getHeader()->rd = 1;
+    pwQ.getHeader()->id = htons(42);
+
+    DNSQuestion dnsQuestion(ids, query);
+    dnsdist_ffi_dnsquestion_t lightDQ(&dnsQuestion);
+    std::array<const dnsdist_ffi_svc_record_parameters*, 1> list = {parameters};
+    BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_generate_svc_response(&lightDQ, list.data(), list.size(), 42), true);
+  }
+
+  dnsdist_ffi_svc_record_parameters_free(parameters);
+}
+
 BOOST_AUTO_TEST_SUITE_END();
index a6fa8ff834ce6fdf2848639229d027549010d1a4..1cca05f66c40ae82e7a953f4eef4c152cb247902 100644 (file)
@@ -31,6 +31,7 @@
 #include "dnsdist.hh"
 #include "dnsdist-ecs.hh"
 #include "dnsdist-internal-queries.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-xsk.hh"
 
 #include "ednscookies.hh"
 #include "ednssubnet.hh"
 
-ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
 {
   return ProcessQueryResult::Drop;
 }
 
-bool processResponseAfterRules(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponseAfterRules(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
 {
   return false;
 }
@@ -84,14 +85,14 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap([[maybe_unused]] DownstreamSt
 #ifdef HAVE_XSK
 namespace dnsdist::xsk
 {
-bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet)
+bool XskProcessQuery(ClientState& clientState, XskPacket& packet)
 {
   return false;
 }
 }
 #endif /* HAVE_XSK */
 
-bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& localRespRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, InternalQueryState&& ids)
 {
   return false;
 }
@@ -1488,7 +1489,7 @@ static int getZ(const DNSName& qname, const uint16_t qtype, const uint16_t qclas
 
   auto dnsQuestion = DNSQuestion(ids, query);
 
-  return getEDNSZ(dnsQuestion);
+  return dnsdist::getEDNSZ(dnsQuestion);
 }
 
 BOOST_AUTO_TEST_CASE(test_getEDNSZ)
@@ -1592,6 +1593,131 @@ BOOST_AUTO_TEST_CASE(test_getEDNSZ)
   }
 }
 
+BOOST_AUTO_TEST_CASE(test_getEDNSVersion)
+{
+  const DNSName qname("www.powerdns.com.");
+  const uint16_t qtype = QType::A;
+  const uint16_t qclass = QClass::IN;
+  const GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+
+  auto getVersion = [&qname](PacketBuffer& query) {
+    InternalQueryState ids;
+    ids.protocol = dnsdist::Protocol::DoUDP;
+    ids.qname = qname;
+    ids.qtype = qtype;
+    ids.qclass = qclass;
+    ids.origDest = ComboAddress("127.0.0.1");
+    ids.origRemote = ComboAddress("127.0.0.1");
+    ids.queryRealTime.start();
+
+    auto dnsQuestion = DNSQuestion(ids, query);
+
+    return dnsdist::getEDNSVersion(dnsQuestion);
+  };
+
+  {
+    /* no EDNS */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.commit();
+
+    BOOST_CHECK(getVersion(query) == std::nullopt);
+  }
+
+  {
+    /* truncated EDNS */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+    packetWriter.commit();
+
+    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
+    BOOST_CHECK(getVersion(query) == std::nullopt);
+  }
+
+  {
+    /* valid EDNS, no options */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 0, 0);
+    packetWriter.commit();
+
+    BOOST_CHECK_EQUAL(*getVersion(query), 0U);
+  }
+
+  {
+    /* EDNS version 255 */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO, opts, 255U);
+    packetWriter.commit();
+
+    BOOST_CHECK_EQUAL(*getVersion(query), 255U);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_getEDNSExtendedRCode)
+{
+  const DNSName qname("www.powerdns.com.");
+  const uint16_t qtype = QType::A;
+  const uint16_t qclass = QClass::IN;
+
+  auto getExtendedRCode = [&qname](PacketBuffer& query) {
+    InternalQueryState ids;
+    ids.protocol = dnsdist::Protocol::DoUDP;
+    ids.qname = qname;
+    ids.qtype = qtype;
+    ids.qclass = qclass;
+    ids.origDest = ComboAddress("127.0.0.1");
+    ids.origRemote = ComboAddress("127.0.0.1");
+    ids.queryRealTime.start();
+
+    auto dnsQuestion = DNSQuestion(ids, query);
+
+    return dnsdist::getEDNSExtendedRCode(dnsQuestion);
+  };
+
+  {
+    /* no EDNS */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.commit();
+
+    BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
+  }
+
+  {
+    /* truncated EDNS */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
+    packetWriter.commit();
+
+    query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* TTL */ 2));
+    BOOST_CHECK(getExtendedRCode(query) == std::nullopt);
+  }
+
+  {
+    /* valid EDNS, no options */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 0, 0);
+    packetWriter.commit();
+
+    BOOST_CHECK_EQUAL(*getExtendedRCode(query), 0U);
+  }
+
+  {
+    /* EDNS extended RCode 4095 (15 for the normal RCode, 255 for the EDNS part) */
+    PacketBuffer query;
+    GenericDNSPacketWriter<PacketBuffer> packetWriter(query, qname, qtype, qclass, 0);
+    packetWriter.addOpt(512, 4095U, EDNS_HEADER_FLAG_DO);
+    packetWriter.commit();
+
+    BOOST_CHECK_EQUAL(*getExtendedRCode(query), 255U);
+  }
+}
+
 BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
 {
   InternalQueryState ids;
@@ -1621,7 +1747,9 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     packetWriter.commit();
 
     auto dnsQuestion = turnIntoResponse(ids, query);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
+    BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
     BOOST_CHECK_EQUAL(zValue, 0);
@@ -1637,7 +1765,9 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
 
     query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
     auto dnsQuestion = turnIntoResponse(ids, query, false);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK(dnsdist::getEDNSVersion(dnsQuestion) == std::nullopt);
+    BOOST_CHECK(dnsdist::getEDNSExtendedRCode(dnsQuestion) == std::nullopt);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), false);
     BOOST_CHECK_EQUAL(zValue, 0);
@@ -1652,11 +1782,13 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     packetWriter.commit();
 
     auto dnsQuestion = turnIntoResponse(ids, query);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, 0);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1667,11 +1799,13 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     packetWriter.commit();
 
     auto dnsQuestion = turnIntoResponse(ids, query);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1682,11 +1816,13 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     packetWriter.commit();
 
     auto dnsQuestion = turnIntoResponse(ids, query);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), 0);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, 0);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1697,11 +1833,13 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     packetWriter.commit();
 
     auto dnsQuestion = turnIntoResponse(ids, query);
-    BOOST_CHECK_EQUAL(getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+    BOOST_CHECK_EQUAL(dnsdist::getEDNSZ(dnsQuestion), EDNS_HEADER_FLAG_DO);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSVersion(dnsQuestion), 0U);
+    BOOST_CHECK_EQUAL(*dnsdist::getEDNSExtendedRCode(dnsQuestion), 0U);
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 }
 
@@ -1729,13 +1867,13 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
     packetWriter.getHeader()->rcode = RCode::NXDomain;
     packetWriter.commit();
 
-    int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
 
     BOOST_CHECK_EQUAL(res, ENOENT);
 
     /* truncated packet (should not matter) */
     query.resize(query.size() - 1);
-    res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
 
     BOOST_CHECK_EQUAL(res, ENOENT);
   }
@@ -1747,7 +1885,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
     packetWriter.addOpt(512, 0, 0);
     packetWriter.commit();
 
-    int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
 
     BOOST_CHECK_EQUAL(res, 0);
     BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
@@ -1756,7 +1894,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
     /* truncated packet */
     query.resize(query.size() - 1);
 
-    res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
     BOOST_CHECK_EQUAL(res, ENOENT);
   }
 
@@ -1767,7 +1905,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
     packetWriter.addOpt(512, 0, 0, opts);
     packetWriter.commit();
 
-    int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    int res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
 
     BOOST_CHECK_EQUAL(res, 0);
     BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
@@ -1775,7 +1913,7 @@ BOOST_AUTO_TEST_CASE(test_getEDNSOptionsStart)
 
     /* truncated options (should not matter for this test) */
     query.resize(query.size() - 1);
-    res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
+    res = dnsdist::getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
     BOOST_CHECK_EQUAL(res, 0);
     BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
     BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
@@ -1986,9 +2124,9 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
   }
   {
     /* now with incoming EDNS */
@@ -2009,11 +2147,11 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
   }
 
   /* test No Data */
@@ -2036,9 +2174,9 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
   }
   {
     /* now with incoming EDNS */
@@ -2059,11 +2197,11 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 2U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
   }
 
   /* SOA in the authority section*/
@@ -2089,9 +2227,9 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
   }
   {
     /* now with incoming EDNS */
@@ -2112,11 +2250,11 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
   }
 
   /* test No Data */
@@ -2139,9 +2277,9 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
   }
   {
     /* now with incoming EDNS */
@@ -2162,11 +2300,11 @@ BOOST_AUTO_TEST_CASE(test_setNegativeAndAdditionalSOA)
     BOOST_CHECK_EQUAL(mdp.d_header.nscount, 1U);
     BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
     BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 2U);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::SOA));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, DNSName("zone."));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::OPT));
-    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, g_rootdnsname);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::SOA));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, DNSName("zone."));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_type, static_cast<uint16_t>(QType::OPT));
+    BOOST_CHECK_EQUAL(mdp.d_answers.at(1).d_name, g_rootdnsname);
   }
 }
 
@@ -2281,14 +2419,14 @@ BOOST_AUTO_TEST_CASE(test_setEDNSOption)
   BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
   BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
   BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1U);
-  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::OPT));
-  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, g_rootdnsname);
+  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::OPT));
+  BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, g_rootdnsname);
 
   EDNS0Record edns0{};
   BOOST_REQUIRE(getEDNS0Record(dnsQuestion.getData(), edns0));
   BOOST_CHECK_EQUAL(edns0.version, 0U);
   BOOST_CHECK_EQUAL(edns0.extRCode, 0U);
-  BOOST_CHECK_EQUAL(edns0.extFlags, EDNS_HEADER_FLAG_DO);
+  BOOST_CHECK_EQUAL(ntohs(edns0.extFlags), EDNS_HEADER_FLAG_DO);
 
   BOOST_REQUIRE(parseEDNSOptions(dnsQuestion));
   BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
index e535ba3cb4d6268f9c3f88e79dff961a3451208b..3b7d09efbaa1f5884e7200c4fdbe3539bbf1d4d4 100644 (file)
@@ -135,7 +135,10 @@ BOOST_AUTO_TEST_CASE(test_TimeoutFailClose)
   // the event should be triggered after 10 ms, but we have seen
   // many spurious failures on our CI, likely because the box is
   // overloaded, so sleep for up to 100 ms to be sure
-  for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+  for (size_t counter = 0; counter < 10; counter++) {
+    if (holder->empty() && sender->errorRaised.load()) {
+      break;
+    }
     usleep(10000);
   }
 
@@ -168,7 +171,10 @@ BOOST_AUTO_TEST_CASE(test_AddingExpiredEvent)
   // but we have seen many spurious failures on our CI,
   // likely because the box is overloaded, so sleep for up to
   // 100 ms to be sure
-  for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+  for (size_t counter = 0; counter < 10; counter++) {
+    if (holder->empty() && sender->errorRaised.load()) {
+      break;
+    }
     usleep(10000);
   }
 
index 0bcbb98128957e014dbd33ca9dcf19525ee1e717..388389f66fba9c649e070e3fe9ef08ee1a6a7735 100644 (file)
@@ -24,7 +24,7 @@ struct TestFixture
   TestFixture()
   {
     g_rings.reset();
-    g_rings.init();
+    g_rings.init(10000, 10);
   }
   ~TestFixture()
   {
@@ -68,7 +68,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     size_t numberOfQueries = 45 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -80,8 +80,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -90,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     size_t numberOfQueries = (50 * numberOfSeconds) + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -99,10 +99,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -115,7 +115,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     /* clear the rings and dynamic blocks */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     /* Insert 100 qps from a given client in the last 10s
        this should trigger the rule */
@@ -132,10 +132,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * numberOfSeconds);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
 
     /* now we clean up the dynamic blocks, simulating an admin removing the block */
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
     /* we apply the rules again, but as if we were 20s in the future.
        Since we have a time windows of 10s nothing should be added,
        regardless of the number of queries
@@ -143,10 +143,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     struct timespec later = now;
     later.tv_sec += 20;
     dbrg.apply(later);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
 
     /* just in case */
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     /* we apply the rules again, this tile as if we were 5s in the future.
        Since we have a time windows of 10s, and 100 qps over 5s then 0 qps over 5s
@@ -155,10 +155,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     later = now;
     later.tv_sec += 5;
     dbrg.apply(later);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
 
     /* clean up */
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     /* we apply the rules again, this tile as if we were 6s in the future.
        Since we have a time windows of 10s, and 100 qps over 4s then 0 qps over 6s
@@ -167,7 +167,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
     later = now;
     later.tv_sec += 6;
     dbrg.apply(later);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
   }
 }
 
@@ -209,7 +209,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     size_t numberOfQueries = 45 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -221,8 +221,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
   }
 
   {
@@ -231,7 +231,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     size_t numberOfQueries = (50 * numberOfSeconds) + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       ComboAddress requestor("2001:db8::" + std::to_string(idx));
@@ -241,11 +241,11 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
 
     {
       /* beginning of the range should be blocked */
-      const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16))->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16))->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -257,7 +257,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     {
       /* end of the range should be blocked as well */
       ComboAddress end("2001:0db8:0000:0000:ffff:ffff:ffff:ffff");
-      const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(end, 128, 16))->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(end, 128, 16))->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -269,7 +269,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture)
     {
       /* outside of the range should NOT */
       ComboAddress out("2001:0db8:0000:0001::0");
-      BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(out, 128, 16)) == nullptr);
+      BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(out, 128, 16)) == nullptr);
     }
   }
 }
@@ -312,7 +312,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
     size_t numberOfQueries = 45 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -324,8 +324,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(requestor1, 128, 16)) == nullptr);
   }
 
   {
@@ -334,7 +334,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
     size_t numberOfQueries = (50 * numberOfSeconds) + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       ComboAddress requestor("192.0.2.1:" + std::to_string(idx));
@@ -344,11 +344,11 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
 
     {
       /* beginning of the port range should be blocked */
-      const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16))->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16))->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -359,7 +359,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
 
     {
       /* end of the range should be blocked as well */
-      const auto& block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16383"), 32, 16))->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16383"), 32, 16))->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -370,13 +370,13 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
 
     {
       /* outside of the range should not */
-      BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
+      BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
     }
 
     /* we (again) insert just above 50 qps from several clients the same IPv4 port range, this should update the block which will
        check by looking at the blocked counter */
     {
-      auto block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
+      auto* block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
       BOOST_REQUIRE(block != nullptr);
       BOOST_CHECK_EQUAL(block->second.blocks, 0U);
       block->second.blocks = 42U;
@@ -394,16 +394,16 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture)
 
     dbrg.apply(now);
 
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
     {
       /* previous address/port should still be blocked */
-      auto block = g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
+      auto* block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:0"), 32, 16));
       BOOST_REQUIRE(block != nullptr);
       BOOST_CHECK_EQUAL(block->second.blocks, 42U);
     }
 
     /* but not a different one */
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(AddressAndPortRange(ComboAddress("192.0.2.1:16384"), 32, 16)) == nullptr);
 
   }
 }
@@ -428,8 +428,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses, TestFixture
 
   /* 100k entries, one shard */
   g_rings.reset();
-  g_rings.setCapacity(1000000, 1);
-  g_rings.init();
+  g_rings.init(1000000, 1);
 
   size_t numberOfSeconds = 10;
   size_t blockDuration = 60;
@@ -455,7 +454,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses, TestFixture
     size_t numberOfQueries = 45;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t timeIdx = 0; timeIdx < 100; timeIdx++) {
       struct timespec when = now;
@@ -471,8 +470,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses, TestFixture
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * 100);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 }
 
@@ -509,7 +508,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     size_t numberOfQueries = 45 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -517,8 +516,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -527,7 +526,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     size_t numberOfQueries = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, QType::A, size, dnsHeader, protocol);
@@ -535,8 +534,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -545,7 +544,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     size_t numberOfQueries = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -553,10 +552,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -603,7 +602,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     size_t numberOfResponses = 45 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < numberOfResponses; idx++) {
@@ -612,8 +611,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -621,7 +620,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     size_t numberOfResponses = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = RCode::FormErr;
     for (size_t idx = 0; idx < numberOfResponses; idx++) {
@@ -630,8 +629,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -640,7 +639,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     size_t numberOfResponses = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < numberOfResponses; idx++) {
@@ -649,10 +648,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -698,7 +697,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
        this should not trigger the rule */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < 20; idx++) {
@@ -711,15 +710,15 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
     /* insert just 50 FormErrs and nothing else, from a given client in the last 10s */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = RCode::FormErr;
     for (size_t idx = 0; idx < 50; idx++) {
@@ -728,8 +727,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -737,7 +736,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
        this should trigger the rule this time */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < 21; idx++) {
@@ -750,10 +749,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(block.until.tv_sec, now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -767,7 +766,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
        this should NOT trigger the rule since we don't have more than 50 queries */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < 11; idx++) {
@@ -780,8 +779,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 }
 
@@ -821,7 +820,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate, TestFixture) {
     size_t numberOfResponses = 99 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < numberOfResponses; idx++) {
@@ -830,8 +829,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -839,7 +838,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate, TestFixture) {
     size_t numberOfResponses = 100 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     dnsHeader.rcode = rcode;
     for (size_t idx = 0; idx < numberOfResponses; idx++) {
@@ -848,10 +847,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -900,7 +899,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
        this should not trigger the rule */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < 20; idx++) {
       g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
@@ -911,8 +910,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -920,7 +919,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
        this should trigger the rule this time */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < 51; idx++) {
       g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
@@ -931,10 +930,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(block.until.tv_sec, now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -948,7 +947,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
        this should NOT trigger the rule since we don't have more than 50 queries */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < 40; idx++) {
       g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
@@ -959,8 +958,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   /* the global cache-hit rate is too low, should not trigger */
@@ -970,7 +969,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
     /* insert 51 cache misses and 49 hits from a given client in the last 10s */
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < 51; idx++) {
       g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
@@ -981,8 +980,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_REQUIRE(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 }
 
@@ -1019,7 +1018,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     size_t numberOfQueries = 20 * numberOfSeconds;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -1027,8 +1026,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) == nullptr);
   }
 
   {
@@ -1037,7 +1036,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     size_t numberOfQueries = 20 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -1045,12 +1044,12 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
 
     {
-      const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -1073,12 +1072,12 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
 
     {
-      const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -1102,12 +1101,12 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
 
     {
-      const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       /* should have been updated */
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
@@ -1125,7 +1124,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     size_t numberOfQueries = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -1133,12 +1132,12 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
 
     {
-      const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
       BOOST_CHECK_EQUAL(block.reason, reason);
       BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
       BOOST_CHECK(block.domain.empty());
@@ -1186,7 +1185,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Ranges, TestFixture) {
     size_t numberOfQueries = 50 * numberOfSeconds + 1;
     g_rings.clear();
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     for (size_t idx = 0; idx < numberOfQueries; idx++) {
       g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
@@ -1195,10 +1194,10 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Ranges, TestFixture) {
     BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * 2);
 
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
-    BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
-    const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1U);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1) != nullptr);
+    BOOST_CHECK(dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor2) == nullptr);
+    const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor1)->second;
     BOOST_CHECK_EQUAL(block.reason, reason);
     BOOST_CHECK_EQUAL(static_cast<size_t>(block.until.tv_sec), now.tv_sec + blockDuration);
     BOOST_CHECK(block.domain.empty());
@@ -1229,14 +1228,13 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
 
   g_rings.reset();
   /* 10M entries, only one shard */
-  g_rings.setCapacity(10000000, 1);
-  g_rings.init();
+  g_rings.init(10000000, 1);
 
   {
     DynBlockRulesGroup dbrg;
     dbrg.setQuiet(true);
     g_rings.clear();
-    g_dynblockNMG.setState(emptyNMG);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
 
     {
       /* block above 0 qps for numberOfSeconds seconds, no warning */
@@ -1253,11 +1251,11 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
 
     /* we apply the rules, all clients should be blocked */
     dbrg.apply(now);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 256U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 256U);
 
     for (size_t idx = 0; idx < 256; idx++) {
       const ComboAddress requestor("192.0.2." + std::to_string(idx));
-      const auto& block = g_dynblockNMG.getLocal()->lookup(requestor)->second;
+      const auto& block = dnsdist::DynamicBlocks::getClientAddressDynamicRules().lookup(requestor)->second;
       /* simulate that:
          - .1 does 1 query
          ...
@@ -1283,7 +1281,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     struct timespec expired = now;
     expired.tv_sec += blockDuration + 1;
     DynBlockMaintenance::purgeExpired(expired);
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
   }
 
   {
@@ -1291,8 +1289,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     DynBlockRulesGroup dbrg;
     dbrg.setQuiet(true);
     g_rings.clear();
-    g_dynblockNMG.setState(emptyNMG);
-    g_dynblockSMT.setState(emptySMT);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+    dnsdist::DynamicBlocks::clearSuffixDynamicRules();
 
     {
       DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
@@ -1315,7 +1313,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
 
     for (size_t idx = 0; idx < 256; idx++) {
       const DNSName name(DNSName(std::to_string(idx)) + qname);
-      const auto* block = g_dynblockSMT.getLocal()->lookup(name);
+      const auto* block = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(name);
       BOOST_REQUIRE(block != nullptr);
       BOOST_REQUIRE(block->action == action);
       /* simulate that:
@@ -1343,7 +1341,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     struct timespec expired = now;
     expired.tv_sec += blockDuration + 1;
     DynBlockMaintenance::purgeExpired(expired);
-    BOOST_CHECK(g_dynblockSMT.getLocal()->getNodes().empty());
+    BOOST_CHECK(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().empty());
   }
 
   {
@@ -1351,8 +1349,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     DynBlockRulesGroup dbrg;
     dbrg.setQuiet(true);
     g_rings.clear();
-    g_dynblockNMG.setState(emptyNMG);
-    g_dynblockSMT.setState(emptySMT);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+    dnsdist::DynamicBlocks::clearSuffixDynamicRules();
 
     {
       DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
@@ -1375,7 +1373,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
 
     for (size_t idx = 0; idx < 256; idx++) {
       const DNSName name(DNSName(std::to_string(idx)) + qname);
-      const auto* block = g_dynblockSMT.getLocal()->lookup(name);
+      const auto* block = dnsdist::DynamicBlocks::getSuffixDynamicRules().lookup(name);
       BOOST_REQUIRE(block != nullptr);
       BOOST_REQUIRE(block->action == DNSAction::Action::Truncate);
       /* simulate that:
@@ -1403,7 +1401,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     struct timespec expired = now;
     expired.tv_sec += blockDuration + 1;
     DynBlockMaintenance::purgeExpired(expired);
-    BOOST_CHECK(g_dynblockSMT.getLocal()->getNodes().empty());
+    BOOST_CHECK(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().empty());
   }
 
 #ifdef BENCH_DYNBLOCKS
@@ -1412,8 +1410,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     DynBlockRulesGroup dbrg;
     dbrg.setQuiet(true);
     g_rings.clear();
-    g_dynblockNMG.setState(emptyNMG);
-    g_dynblockSMT.setState(emptySMT);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+    dnsdist::DynamicBlocks::clearSuffixDynamicRules();
 
     {
       DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
@@ -1457,7 +1455,7 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     sw.start();
     DynBlockMaintenance::purgeExpired(expired);
     cerr<<"removed 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
-    BOOST_CHECK_EQUAL(g_dynblockSMT.getLocal()->getNodes().size(), 0U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getSuffixDynamicRules().getNodes().size(), 0U);
   }
 #endif
 
@@ -1467,8 +1465,8 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     DynBlockRulesGroup dbrg;
     dbrg.setQuiet(true);
     g_rings.clear();
-    g_dynblockNMG.setState(emptyNMG);
-    g_dynblockSMT.setState(emptySMT);
+    dnsdist::DynamicBlocks::clearClientAddressDynamicRules();
+    dnsdist::DynamicBlocks::clearSuffixDynamicRules();
     {
       DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
       dbrg.setQueryRate(std::move(rule));
@@ -1492,19 +1490,19 @@ BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
     StopWatch sw;
     sw.start();
     dbrg.apply(now);
-    cerr<<"added "<<g_dynblockNMG.getLocal()->size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1000000U);
+    cerr<<"added "<<dnsdist::DynamicBlocks::getClientAddressDynamicRules().size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 1000000U);
 
     sw.start();
     auto top = DynBlockMaintenance::getTopNetmasks(20);
-    cerr<<"scanned "<<g_dynblockNMG.getLocal()->size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
+    cerr<<"scanned "<<dnsdist::DynamicBlocks::getClientAddressDynamicRules().size()<<" entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
 
     struct timespec expired = now;
     expired.tv_sec += blockDuration + 1;
     sw.start();
     DynBlockMaintenance::purgeExpired(expired);
     cerr<<"removed 1000000 entries in "<<std::to_string(sw.udiff()/1024)<<"ms"<<endl;
-    BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+    BOOST_CHECK_EQUAL(dnsdist::DynamicBlocks::getClientAddressDynamicRules().size(), 0U);
   }
 #endif
 }
index 013d0ba7c7faf7b42506e81f0459024962d55170..e641dc63715475c6ae7d3d4fe34a17ce2a7da73a 100644 (file)
 #include "dnsdist.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-snmp.hh"
 #include "dolog.hh"
 
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-
 #include "ext/luawrapper/include/LuaContext.hpp"
-LockGuarded<LuaContext> g_lua{LuaContext()};
+RecursiveLockGuarded<LuaContext> g_lua{LuaContext()};
 
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
 std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
 
 #if BENCH_POLICIES
-bool g_verbose{true};
 #include "dnsdist-rings.hh"
 Rings g_rings;
-GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
-GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
 #endif /* BENCH_POLICIES */
 
-GlobalStateHolder<pools_t> g_pools;
-std::vector<std::unique_ptr<ClientState>> g_frontends;
-
 /* add stub implementations, we don't want to include the corresponding object files
    and their dependencies */
 
@@ -41,18 +32,6 @@ bool TLSFrontend::setupTLS()
   return true;
 }
 
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
-std::string DNSQuestion::getTrailingData() const
-{
-  return "";
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
-bool DNSQuestion::setTrailingData(const std::string& tail)
-{
-  return false;
-}
-
 // NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
 bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dnsQuestion, const std::string& reason)
 {
@@ -80,7 +59,6 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
 }
 
 string g_outputBuffer;
-std::atomic<bool> g_configurationDone{false};
 
 static DNSQuestion getDQ(const DNSName* providedName = nullptr)
 {
@@ -102,9 +80,6 @@ static DNSQuestion getDQ(const DNSName* providedName = nullptr)
 static void benchPolicy(const ServerPolicy& pol)
 {
 #if BENCH_POLICIES
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
-
   std::vector<DNSName> names;
   names.reserve(1000);
   for (size_t idx = 0; idx < 1000; idx++) {
@@ -129,8 +104,6 @@ static void benchPolicy(const ServerPolicy& pol)
     }
   }
   cerr << pol.name << " took " << std::to_string(sw.udiff()) << " us for " << names.size() << endl;
-
-  g_verbose = existingVerboseValue;
 #endif /* BENCH_POLICIES */
 }
 
@@ -138,12 +111,17 @@ static void resetLuaContext()
 {
   /* we need to reset this before cleaning the Lua state because the server policy might holds
      a reference to a Lua function (Lua policies) */
-  g_policy.setState(ServerPolicy("leastOutstanding", leastOutstanding, false));
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_lbPolicy = std::make_shared<ServerPolicy>("leastOutstanding", leastOutstanding, false);
+  });
+  /* we actually need this line to clear the cached state for this thread */
+  BOOST_REQUIRE_EQUAL(dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy->getName(), "leastOutstanding");
   *(g_lua.lock()) = LuaContext();
 }
 
 BOOST_AUTO_TEST_SUITE(dnsdistlbpolicies)
 
+#if 0
 BOOST_AUTO_TEST_CASE(test_firstAvailable)
 {
   auto dnsQuestion = getDQ();
@@ -223,17 +201,23 @@ BOOST_AUTO_TEST_CASE(test_roundRobin)
   ServerPolicy::NumberedServerVector servers;
 
   /* selecting a server on an empty server list */
-  g_roundrobinFailOnNoServer = false;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = false;
+  });
   auto server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server == nullptr);
 
   servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
 
-  /* servers start as 'down' but the RR policy returns a server unless g_roundrobinFailOnNoServer is set */
-  g_roundrobinFailOnNoServer = true;
+  /* servers start as 'down' but the RR policy returns a server unless d_roundrobinFailOnNoServer is set */
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = true;
+  });
   server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server == nullptr);
-  g_roundrobinFailOnNoServer = false;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = false;
+  });
   server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server != nullptr);
 
@@ -466,8 +450,10 @@ BOOST_AUTO_TEST_CASE(test_whashed)
 
 BOOST_AUTO_TEST_CASE(test_chashed)
 {
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
+  bool existingVerboseValue = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_verbose = false;
+  });
 
   std::vector<DNSName> names;
   names.reserve(1000);
@@ -549,8 +535,11 @@ BOOST_AUTO_TEST_CASE(test_chashed)
   BOOST_CHECK_GT(got, expected / 2);
   BOOST_CHECK_LT(got, expected * 2);
 
-  g_verbose = existingVerboseValue;
+  dnsdist::configuration::updateRuntimeConfiguration([existingVerboseValue](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_verbose = existingVerboseValue;
+  });
 }
+#endif
 
 BOOST_AUTO_TEST_CASE(test_lua)
 {
@@ -571,12 +560,17 @@ BOOST_AUTO_TEST_CASE(test_lua)
   )foo";
   resetLuaContext();
   g_lua.lock()->writeFunction("setServerPolicyLua", [](const string& name, const ServerPolicy::policyfunc_t& policy) {
-    g_policy.setState(ServerPolicy{name, policy, true});
+    auto pol = std::make_shared<ServerPolicy>(name, policy, true);
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
     for (size_t idx = 1; idx <= 10; idx++) {
@@ -588,7 +582,7 @@ BOOST_AUTO_TEST_CASE(test_lua)
 
     for (const auto& name : names) {
       auto dnsQuestion = getDQ(&name);
-      auto server = pol.getSelectedBackend(servers, dnsQuestion);
+      auto server = pol->getSelectedBackend(servers, dnsQuestion);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -602,11 +596,11 @@ BOOST_AUTO_TEST_CASE(test_lua)
     }
     BOOST_CHECK_EQUAL(total, names.size());
 
-    benchPolicy(pol);
+    benchPolicy(*pol);
   }
   resetLuaContext();
 }
-
+#if 0
 #ifdef LUAJIT_VERSION
 
 BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
@@ -632,12 +626,16 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
   resetLuaContext();
   g_lua.lock()->executeCode(getLuaFFIWrappers());
   g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
-    g_policy.setState(ServerPolicy(name, policy));
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
     for (size_t idx = 1; idx <= 10; idx++) {
@@ -649,7 +647,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
 
     for (const auto& name : names) {
       auto dnsQuestion = getDQ(&name);
-      auto server = pol.getSelectedBackend(servers, dnsQuestion);
+      auto server = pol->getSelectedBackend(servers, dnsQuestion);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -663,7 +661,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
     }
     BOOST_CHECK_EQUAL(total, names.size());
 
-    benchPolicy(pol);
+    benchPolicy(*pol);
   }
   resetLuaContext();
 }
@@ -686,12 +684,16 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_no_server_available)
   resetLuaContext();
   g_lua.lock()->executeCode(getLuaFFIWrappers());
   g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& policyName, ServerPolicy::ffipolicyfunc_t policy) {
-    g_policy.setState(ServerPolicy(policyName, std::move(policy)));
+    auto pol = std::make_shared<ServerPolicy>(policyName, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     for (size_t idx = 1; idx <= 10; idx++) {
       servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
@@ -700,7 +702,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_no_server_available)
     BOOST_REQUIRE_EQUAL(servers.size(), 10U);
 
     auto dnsQuestion = getDQ(&dnsName);
-    auto server = pol.getSelectedBackend(servers, dnsQuestion);
+    auto server = pol->getSelectedBackend(servers, dnsQuestion);
     BOOST_REQUIRE(server == nullptr);
   }
   resetLuaContext();
@@ -728,12 +730,16 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed)
   resetLuaContext();
   g_lua.lock()->executeCode(getLuaFFIWrappers());
   g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
-    g_policy.setState(ServerPolicy(name, policy));
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
     for (size_t idx = 1; idx <= 10; idx++) {
@@ -745,7 +751,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed)
 
     for (const auto& name : names) {
       auto dnsQuestion = getDQ(&name);
-      auto server = pol.getSelectedBackend(servers, dnsQuestion);
+      auto server = pol->getSelectedBackend(servers, dnsQuestion);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -759,7 +765,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed)
     }
     BOOST_CHECK_EQUAL(total, names.size());
 
-    benchPolicy(pol);
+    benchPolicy(*pol);
   }
   resetLuaContext();
 }
@@ -784,12 +790,16 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed)
   resetLuaContext();
   g_lua.lock()->executeCode(getLuaFFIWrappers());
   g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
-    g_policy.setState(ServerPolicy(name, policy));
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
     for (size_t idx = 1; idx <= 10; idx++) {
@@ -801,7 +811,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed)
 
     for (const auto& name : names) {
       auto dnsQuestion = getDQ(&name);
-      auto server = pol.getSelectedBackend(servers, dnsQuestion);
+      auto server = pol->getSelectedBackend(servers, dnsQuestion);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -815,16 +825,13 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed)
     }
     BOOST_CHECK_EQUAL(total, names.size());
 
-    benchPolicy(pol);
+    benchPolicy(*pol);
   }
   resetLuaContext();
 }
 
 BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
 {
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
-
   std::vector<DNSName> names;
   names.reserve(1000);
   for (size_t idx = 0; idx < 1000; idx++) {
@@ -843,12 +850,16 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
   resetLuaContext();
   g_lua.lock()->executeCode(getLuaFFIWrappers());
   g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
-    g_policy.setState(ServerPolicy(name, policy));
+    auto pol = std::make_shared<ServerPolicy>(name, std::move(policy));
+    dnsdist::configuration::updateRuntimeConfiguration([&pol](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_lbPolicy = std::move(pol);
+    });
   });
   g_lua.lock()->executeCode(policySetupStr);
 
   {
-    ServerPolicy pol = g_policy.getCopy();
+    const auto& pol = dnsdist::configuration::getCurrentRuntimeConfiguration().d_lbPolicy;
+    BOOST_REQUIRE(pol != nullptr);
     ServerPolicy::NumberedServerVector servers;
     std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
     for (size_t idx = 1; idx <= 10; idx++) {
@@ -864,7 +875,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
 
     for (const auto& name : names) {
       auto dnsQuestion = getDQ(&name);
-      auto server = pol.getSelectedBackend(servers, dnsQuestion);
+      auto server = pol->getSelectedBackend(servers, dnsQuestion);
       BOOST_REQUIRE(serversMap.count(server) == 1);
       ++serversMap[server];
     }
@@ -878,12 +889,11 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
     }
     BOOST_CHECK_EQUAL(total, names.size());
 
-    benchPolicy(pol);
+    benchPolicy(*pol);
   }
-  g_verbose = existingVerboseValue;
   resetLuaContext();
 }
 
 #endif /* LUAJIT_VERSION */
-
+#endif
 BOOST_AUTO_TEST_SUITE_END()
index c3f555a2257efaef054b952112e73717c949a286..a24341f13ab6b8eab7a7a22e2096d22b0f81c7d6 100644 (file)
@@ -472,7 +472,6 @@ private:
     /* we _NEED_ to set this function to empty otherwise we might get what was set
        by the last test, and we might not like it at all */
     s_processQuery = nullptr;
-    g_proxyProtocolACL.clear();
   }
 };
 
index f7d2f31750dd419aae93462626b65ad203397986..08794b320a893f08331a6ab9a2f783d00c1d6a8e 100644 (file)
@@ -708,7 +708,7 @@ static void threadMangler(unsigned int offset)
   }
 }
 
-AtomicCounter g_missing;
+static std::atomic<uint64_t> s_missing{0};
 
 static void threadReader(unsigned int offset)
 {
@@ -731,7 +731,7 @@ static void threadReader(unsigned int offset)
       DNSQuestion dnsQuestion(ids, query);
       bool found = s_localCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
       if (!found) {
-        g_missing++;
+        s_missing++;
       }
     }
   }
@@ -767,7 +767,7 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded)
       thr.join();
     }
 
-    BOOST_CHECK((s_localCache.getDeferredInserts() + s_localCache.getDeferredLookups() + s_localCache.getInsertCollisions()) >= g_missing);
+    BOOST_CHECK((s_localCache.getDeferredInserts() + s_localCache.getDeferredLookups() + s_localCache.getInsertCollisions()) >= s_missing.load());
   }
   catch (const PDNSException& e) {
     cerr << "Had error: " << e.reason << endl;
index 77450c8b051d7a30dcf452e03d886bb4d8e9baeb..ad81e1ec391925eee878e010b4d567313816e391 100644 (file)
@@ -15,8 +15,8 @@ BOOST_AUTO_TEST_SUITE(dnsdistrings_cc)
 
 static void test_ring(size_t maxEntries, size_t numberOfShards, size_t nbLockTries)
 {
-  Rings rings(maxEntries, numberOfShards, nbLockTries);
-  rings.init();
+  Rings rings;
+  rings.init(maxEntries, numberOfShards, nbLockTries);
   size_t entriesPerShard = maxEntries / numberOfShards;
 
   BOOST_CHECK_EQUAL(rings.getNumberOfShards(), numberOfShards);
@@ -208,8 +208,8 @@ BOOST_AUTO_TEST_CASE(test_Rings_Threaded) {
   dnsdist::Protocol protocol = dnsdist::Protocol::DoUDP;
   dnsdist::Protocol outgoingProtocol = dnsdist::Protocol::DoUDP;
 
-  Rings rings(numberOfEntries, numberOfShards, lockAttempts, true);
-  rings.init();
+  Rings rings;
+  rings.init(numberOfEntries, numberOfShards, lockAttempts, true);
 #if defined(DNSDIST_RINGS_WITH_MACADDRESS)
   Rings::Query query({requestor, qname, now, dh, size, qtype, protocol, dnsdist::MacAddress(), false});
 #else
index 8f7363a29ec2ce96958851dc03217bb6cf9754a0..7457fb3bb16f1005d60d72574537803f586855dc 100644 (file)
@@ -10,7 +10,6 @@
 
 #include "dnsdist-rules.hh"
 
-void checkParameterBound(const std::string& parameter, uint64_t value, size_t max);
 void checkParameterBound(const std::string& parameter, uint64_t value, size_t max)
 {
   if (value > max) {
@@ -145,10 +144,8 @@ BOOST_AUTO_TEST_CASE(test_poolOutstandingRule) {
 
   BOOST_CHECK_EQUAL(sp.poolLoad(), 400U + 30U);
 
-  auto localPool = g_pools.getCopy();
-  addServerToPool(localPool, "test", ds1);
-  addServerToPool(localPool, "test", ds2);
-  g_pools.setState(localPool);
+  addServerToPool("test", ds1);
+  addServerToPool("test", ds2);
 
   PoolOutstandingRule pOR1("test", 10);
   BOOST_CHECK_EQUAL(pOR1.matches(&dq), true);
index 2934616ff769dec7272fa9ba599c4b5159e46109..bcf6ea10aa21a7839b4a9f286f5fd1b8701f6805 100644 (file)
 #include "dnsdist-tcp-downstream.hh"
 #include "dnsdist-tcp-upstream.hh"
 
-GlobalStateHolder<NetmaskGroup> g_ACL;
-GlobalStateHolder<servers_t> g_dstates;
-
-QueryCount g_qcount;
-
 const bool TCPIOHandler::s_disableConnectForUnitTests = true;
 
 bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
@@ -62,23 +57,23 @@ void handleResponseSent(const InternalQueryState& ids, double udiff, const Combo
 
 std::function<ProcessQueryResult(DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
 
-ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
+ProcessQueryResult processQuery(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)
 {
   if (s_processQuery) {
-    return s_processQuery(dq, selectedBackend);
+    return s_processQuery(dnsQuestion, selectedBackend);
   }
 
   return ProcessQueryResult::Drop;
 }
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
 {
   return true;
 }
 
 static std::function<bool(PacketBuffer& response, DNSResponse& dr, bool muted)> s_processResponse;
 
-bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::ResponseRuleAction>& respRuleActions, const std::vector<dnsdist::rules::ResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dnsResponse, bool muted)
+bool processResponse(PacketBuffer& response, DNSResponse& dnsResponse, bool muted)
 {
   if (s_processResponse) {
     return s_processResponse(response, dnsResponse, muted);
@@ -456,8 +451,9 @@ struct TestFixture
     s_backendReadBuffer.clear();
     s_backendWriteBuffer.clear();
 
-    g_proxyProtocolACL.clear();
-    g_verbose = false;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.clear();
+    });
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
     /* we _NEED_ to set this function to empty otherwise we might get what was set
@@ -482,6 +478,7 @@ static void testInit(const std::string& name, TCPClientThreadData& threadData)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   auto tlsCtx = std::make_shared<MockupTLSCtx>();
@@ -656,7 +653,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
     for (const auto& cbData : expiredReadConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -692,7 +689,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
     for (const auto& cbData : expiredWriteConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -729,6 +726,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   auto tlsCtx = std::make_shared<MockupTLSCtx>();
@@ -751,8 +749,10 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> reading PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
 
     auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
     BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
@@ -791,8 +791,11 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> Invalid PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
+
     auto proxyPayload = std::vector<uint8_t>(s_proxyProtocolMinimumHeaderSize);
     std::fill(proxyPayload.begin(), proxyPayload.end(), 0);
 
@@ -818,8 +821,11 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> timeout while reading PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
+
     auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
     BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
     s_readBuffer = query;
@@ -843,7 +849,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
     for (const auto& cbData : expiredReadConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -1660,7 +1666,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
     /* 101 queries on the same connection, check that the maximum number of queries kicks in */
     TEST_INIT("=> 101 queries on the same connection");
 
-    g_maxTCPQueriesPerConn = 100;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_maxTCPQueriesPerConn = 100;
+    });
 
     size_t count = 101;
 
@@ -1714,7 +1722,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
     /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
-    g_maxTCPQueriesPerConn = 0;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_maxTCPQueriesPerConn = 0;
+    });
 #endif
   }
 
@@ -1757,8 +1767,10 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
   }
 }
 
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   /* enable out-of-order on the front side */
@@ -1952,7 +1964,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     TEST_INIT("=> 3 queries sent to the backend, 1 self-answered, 1 new query sent to the backend which responds to the first query right away, then to the last one, then the connection to the backend times out");
 
     // increase the client timeout for that test, we want the backend to timeout first
-    g_tcpRecvTimeout = 5;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 5;
+    });
 
     PacketBuffer expectedWriteBuffer;
     PacketBuffer expectedBackendWriteBuffer;
@@ -2092,7 +2106,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
     // restore the client timeout
-    g_tcpRecvTimeout = 2;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 2;
+    });
   }
 
   {
@@ -2252,7 +2268,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -2527,7 +2543,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -2543,7 +2559,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -3557,7 +3573,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
     /* make sure that the backend's timeout is shorter than the client's */
     backend->d_config.tcpConnectTimeout = 1;
-    g_tcpRecvTimeout = 5;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 5;
+    });
 
     bool timeout = false;
     s_steps = {
@@ -3616,7 +3634,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
     /* restore */
     backend->d_config.tcpSendTimeout = 30;
-    g_tcpRecvTimeout = 2;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 2;
+    });
 
     /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
     /* we have no connection to clear, because there was a timeout! */
@@ -3876,7 +3896,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -3899,6 +3919,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   /* enable out-of-order on the front side */
@@ -4160,7 +4181,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
diff --git a/pdns/dnsdistdist/test-sholder_hh.cc b/pdns/dnsdistdist/test-sholder_hh.cc
new file mode 120000 (symlink)
index 0000000..eb240e5
--- /dev/null
@@ -0,0 +1 @@
+../test-sholder_hh.cc
\ No newline at end of file
index 66b82aaf6963bf8065a499a62d15279a41671b88..dfa7a34e03b3710ebba69ba1f4ce4bfb87f44539 100644 (file)
@@ -19,6 +19,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+
+#define BOOST_TEST_NO_MAIN
+
 #ifndef BOOST_TEST_DYN_LINK
 #define BOOST_TEST_DYN_LINK
 #endif
 #endif
 #include <boost/test/unit_test.hpp>
 
+// entry point:
+int main(int argc, char* argv[])
+{
+  setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
+  return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
+}
 
deleted file mode 120000 (symlink)
index 3258a93cb1421d46adf233a77aa7677d77430207..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../xsk.cc
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..5851f1b9b79ee341f35851420895cd598e464123
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_XSK
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <fcntl.h>
+#include <iterator>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdexcept>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <vector>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+extern "C"
+{
+#include <xdp/libxdp.h>
+}
+
+#include "gettime.hh"
+#include "xsk.hh"
+
+/* we need to include the linux specific headers AFTER the regular
+   ones, because it then detects that some types have already been
+   defined (sockaddr_in6 for example) and does not attempt to
+   re-define them, which otherwise breaks the C++ One Definition Rule
+*/
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_xdp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+
+#ifdef DEBUG_UMEM
+namespace
+{
+struct UmemEntryStatus
+{
+  enum class Status : uint8_t
+  {
+    Free,
+    FillQueue,
+    Received,
+    TXQueue
+  };
+  Status status{Status::Free};
+};
+
+LockGuarded<std::map<std::pair<void*, uint64_t>, UmemEntryStatus>> s_umems;
+
+void checkUmemIntegrity(const char* function, int line, std::shared_ptr<LockGuarded<vector<uint64_t>>> vect, uint64_t offset, const std::set<UmemEntryStatus::Status>& validStatuses, UmemEntryStatus::Status newStatus)
+{
+  auto umems = s_umems.lock();
+  auto& umemState = umems->at({vect.get(), offset});
+  if (validStatuses.count(umemState.status) == 0) {
+    std::cerr << "UMEM integrity check failed at " << function << ": " << line << ": status of " << (void*)vect.get() << ", " << offset << " is " << static_cast<int>(umemState.status) << ", expected: ";
+    for (const auto status : validStatuses) {
+      std::cerr << static_cast<int>(status) << " ";
+    }
+    std::cerr << std::endl;
+    abort();
+  }
+  umemState.status = newStatus;
+}
+}
+#endif /* DEBUG_UMEM */
+
+constexpr bool XskSocket::isPowOfTwo(uint32_t value) noexcept
+{
+  return value != 0 && (value & (value - 1)) == 0;
+}
+
+int XskSocket::firstTimeout()
+{
+  if (waitForDelay.empty()) {
+    return -1;
+  }
+  timespec now{};
+  gettime(&now);
+  const auto& firstTime = waitForDelay.top().getSendTime();
+  const auto res = timeDifference(now, firstTime);
+  if (res <= 0) {
+    return 0;
+  }
+  return res;
+}
+
+XskSocket::XskSocket(size_t frameNum_, std::string ifName_, uint32_t queue_id, const std::string& xskMapPath) :
+  frameNum(frameNum_), ifName(std::move(ifName_)), socket(nullptr, xsk_socket__delete), sharedEmptyFrameOffset(std::make_shared<LockGuarded<vector<uint64_t>>>())
+{
+  if (!isPowOfTwo(frameNum_) || !isPowOfTwo(frameSize)
+      || !isPowOfTwo(fqCapacity) || !isPowOfTwo(cqCapacity) || !isPowOfTwo(rxCapacity) || !isPowOfTwo(txCapacity)) {
+    throw std::runtime_error("The number of frame , the size of frame and the capacity of rings must is a pow of 2");
+  }
+  getMACFromIfName();
+
+  memset(&cq, 0, sizeof(cq));
+  memset(&fq, 0, sizeof(fq));
+  memset(&tx, 0, sizeof(tx));
+  memset(&rx, 0, sizeof(rx));
+
+  xsk_umem_config umemCfg{};
+  umemCfg.fill_size = fqCapacity;
+  umemCfg.comp_size = cqCapacity;
+  umemCfg.frame_size = frameSize;
+  umemCfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
+  umemCfg.flags = 0;
+  umem.umemInit(frameNum_ * frameSize, &cq, &fq, &umemCfg);
+
+  {
+    xsk_socket_config socketCfg{};
+    socketCfg.rx_size = rxCapacity;
+    socketCfg.tx_size = txCapacity;
+    socketCfg.bind_flags = XDP_USE_NEED_WAKEUP;
+    socketCfg.xdp_flags = XDP_FLAGS_SKB_MODE;
+    socketCfg.libxdp_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
+    xsk_socket* tmp = nullptr;
+    auto ret = xsk_socket__create(&tmp, ifName.c_str(), queue_id, umem.umem, &rx, &tx, &socketCfg);
+    if (ret != 0) {
+      throw std::runtime_error("Error creating a xsk socket of if_name " + ifName + ": " + stringerror(ret));
+    }
+    socket = std::unique_ptr<xsk_socket, decltype(&xsk_socket__delete)>(tmp, xsk_socket__delete);
+  }
+
+  uniqueEmptyFrameOffset.reserve(frameNum);
+  {
+    for (uint64_t idx = 0; idx < frameNum; idx++) {
+      uniqueEmptyFrameOffset.push_back(idx * frameSize + XDP_PACKET_HEADROOM);
+#ifdef DEBUG_UMEM
+      {
+        auto umems = s_umems.lock();
+        (*umems)[{sharedEmptyFrameOffset.get(), idx * frameSize + XDP_PACKET_HEADROOM}] = UmemEntryStatus();
+      }
+#endif /* DEBUG_UMEM */
+    }
+  }
+
+  fillFq(fqCapacity);
+
+  const auto xskfd = xskFd();
+  fds.push_back(pollfd{
+    .fd = xskfd,
+    .events = POLLIN,
+    .revents = 0});
+
+  const auto xskMapFd = FDWrapper(bpf_obj_get(xskMapPath.c_str()));
+
+  if (xskMapFd.getHandle() < 0) {
+    throw std::runtime_error("Error getting BPF map from path '" + xskMapPath + "'");
+  }
+
+  auto ret = bpf_map_update_elem(xskMapFd.getHandle(), &queue_id, &xskfd, 0);
+  if (ret != 0) {
+    throw std::runtime_error("Error inserting into xsk_map '" + xskMapPath + "': " + std::to_string(ret));
+  }
+}
+
+// see xdp.h in contrib/
+struct IPv4AndPort
+{
+  uint32_t addr;
+  uint16_t port;
+};
+struct IPv6AndPort
+{
+  struct in6_addr addr;
+  uint16_t port;
+};
+
+static FDWrapper getDestinationMap(const std::string& mapPath)
+{
+  auto destMapFd = FDWrapper(bpf_obj_get(mapPath.c_str()));
+  if (destMapFd.getHandle() < 0) {
+    throw std::runtime_error("Error getting the XSK destination addresses map path '" + mapPath + "'");
+  }
+  return destMapFd;
+}
+
+void XskSocket::clearDestinationMap(const std::string& mapPath, bool isV6)
+{
+  auto destMapFd = getDestinationMap(mapPath);
+  if (!isV6) {
+    IPv4AndPort prevKey{};
+    IPv4AndPort key{};
+    while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+      bpf_map_delete_elem(destMapFd.getHandle(), &key);
+      prevKey = key;
+    }
+  }
+  else {
+    IPv6AndPort prevKey{};
+    IPv6AndPort key{};
+    while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+      bpf_map_delete_elem(destMapFd.getHandle(), &key);
+      prevKey = key;
+    }
+  }
+}
+
+void XskSocket::addDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+  auto destMapFd = getDestinationMap(mapPath);
+  bool value = true;
+  if (destination.isIPv4()) {
+    IPv4AndPort key{};
+    key.addr = destination.sin4.sin_addr.s_addr;
+    key.port = destination.sin4.sin_port;
+    auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+    if (ret != 0) {
+      throw std::runtime_error("Error inserting into xsk_map '" + mapPath + "': " + std::to_string(ret));
+    }
+  }
+  else {
+    IPv6AndPort key{};
+    key.addr = destination.sin6.sin6_addr;
+    key.port = destination.sin6.sin6_port;
+    auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+    if (ret != 0) {
+      throw std::runtime_error("Error inserting into XSK destination addresses map '" + mapPath + "': " + std::to_string(ret));
+    }
+  }
+}
+
+void XskSocket::removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+  auto destMapFd = getDestinationMap(mapPath);
+  if (destination.isIPv4()) {
+    IPv4AndPort key{};
+    key.addr = destination.sin4.sin_addr.s_addr;
+    key.port = destination.sin4.sin_port;
+    bpf_map_delete_elem(destMapFd.getHandle(), &key);
+  }
+  else {
+    IPv6AndPort key{};
+    key.addr = destination.sin6.sin6_addr;
+    key.port = destination.sin6.sin6_port;
+    bpf_map_delete_elem(destMapFd.getHandle(), &key);
+  }
+}
+
+void XskSocket::fillFq(uint32_t fillSize) noexcept
+{
+  if (uniqueEmptyFrameOffset.size() < fillSize) {
+    auto frames = sharedEmptyFrameOffset->lock();
+    const auto moveSize = std::min(static_cast<size_t>(fillSize), frames->size());
+    if (moveSize > 0) {
+      // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+      uniqueEmptyFrameOffset.insert(uniqueEmptyFrameOffset.end(), std::make_move_iterator(frames->end() - moveSize), std::make_move_iterator(frames->end()));
+      frames->resize(frames->size() - moveSize);
+    }
+  }
+  else if (uniqueEmptyFrameOffset.size() > (10 * fillSize)) {
+    // if we have less than holdThreshold frames in the shared queue (which might be an issue
+    // when the XskWorker needs empty frames), move frames from the unique container into the
+    // shared one. This might not be optimal right now.
+    auto frames = sharedEmptyFrameOffset->lock();
+    if (frames->size() < holdThreshold) {
+      const auto moveSize = std::min(holdThreshold - frames->size(), uniqueEmptyFrameOffset.size());
+      if (moveSize > 0) {
+        // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+        frames->insert(frames->end(), std::make_move_iterator(uniqueEmptyFrameOffset.end() - moveSize), std::make_move_iterator(uniqueEmptyFrameOffset.end()));
+        uniqueEmptyFrameOffset.resize(uniqueEmptyFrameOffset.size() - moveSize);
+      }
+    }
+  }
+
+  fillSize = std::min(fillSize, static_cast<uint32_t>(uniqueEmptyFrameOffset.size()));
+  if (fillSize == 0) {
+    auto frames = sharedEmptyFrameOffset->lock();
+    return;
+  }
+
+  uint32_t idx{0};
+  auto toFill = xsk_ring_prod__reserve(&fq, fillSize, &idx);
+  if (toFill == 0) {
+    return;
+  }
+  uint32_t processed = 0;
+  for (; processed < toFill; processed++) {
+    *xsk_ring_prod__fill_addr(&fq, idx++) = uniqueEmptyFrameOffset.back();
+#ifdef DEBUG_UMEM
+    checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Free}, UmemEntryStatus::Status::FillQueue);
+#endif /* DEBUG_UMEM */
+    uniqueEmptyFrameOffset.pop_back();
+  }
+
+  xsk_ring_prod__submit(&fq, processed);
+}
+
+int XskSocket::wait(int timeout)
+{
+  auto waitAtMost = std::min(timeout, firstTimeout());
+  return poll(fds.data(), fds.size(), waitAtMost);
+}
+
+[[nodiscard]] uint64_t XskSocket::frameOffset(const XskPacket& packet) const noexcept
+{
+  return packet.getFrameOffsetFrom(umem.bufBase);
+}
+
+[[nodiscard]] int XskSocket::xskFd() const noexcept
+{
+  return xsk_socket__fd(socket.get());
+}
+
+void XskSocket::send(std::vector<XskPacket>& packets)
+{
+  while (!packets.empty()) {
+    auto packetSize = packets.size();
+    if (packetSize > std::numeric_limits<uint32_t>::max()) {
+      packetSize = std::numeric_limits<uint32_t>::max();
+    }
+    size_t toSend = std::min(static_cast<uint32_t>(packetSize), txCapacity);
+    uint32_t idx{0};
+    auto toFill = xsk_ring_prod__reserve(&tx, toSend, &idx);
+    if (toFill == 0) {
+      return;
+    }
+
+    size_t queued = 0;
+    for (const auto& packet : packets) {
+      if (queued == toFill) {
+        break;
+      }
+      *xsk_ring_prod__tx_desc(&tx, idx++) = {
+        .addr = frameOffset(packet),
+        .len = packet.getFrameLen(),
+        .options = 0};
+#ifdef DEBUG_UMEM
+      checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::Received}, UmemEntryStatus::Status::TXQueue);
+#endif /* DEBUG_UMEM */
+      queued++;
+    }
+    xsk_ring_prod__submit(&tx, toFill);
+    packets.erase(packets.begin(), packets.begin() + toFill);
+  }
+}
+
+std::vector<XskPacket> XskSocket::recv(uint32_t recvSizeMax, uint32_t* failedCount)
+{
+  uint32_t idx{0};
+  std::vector<XskPacket> res;
+  // how many descriptors to packets have been filled
+  const auto recvSize = xsk_ring_cons__peek(&rx, recvSizeMax, &idx);
+  if (recvSize == 0) {
+    return res;
+  }
+
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+  const auto baseAddr = reinterpret_cast<uint64_t>(umem.bufBase);
+  uint32_t failed = 0;
+  uint32_t processed = 0;
+  res.reserve(recvSize);
+  for (; processed < recvSize; processed++) {
+    try {
+      const auto* desc = xsk_ring_cons__rx_desc(&rx, idx++);
+      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr)
+      XskPacket packet = XskPacket(reinterpret_cast<uint8_t*>(desc->addr + baseAddr), desc->len, frameSize);
+#ifdef DEBUG_UMEM
+      checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, frameOffset(packet), {UmemEntryStatus::Status::FillQueue}, UmemEntryStatus::Status::Received);
+#endif /* DEBUG_UMEM */
+
+      if (!packet.parse(false)) {
+        ++failed;
+        markAsFree(packet);
+      }
+      else {
+        res.push_back(packet);
+      }
+    }
+    catch (const std::exception& exp) {
+      ++failed;
+      ++processed;
+      break;
+    }
+    catch (...) {
+      ++failed;
+      ++processed;
+      break;
+    }
+  }
+
+  // this releases the descriptor, but not the packet (umem entries)
+  // which will only be made available again when pushed into the fill
+  // queue
+  xsk_ring_cons__release(&rx, processed);
+  if (failedCount != nullptr) {
+    *failedCount = failed;
+  }
+
+  return res;
+}
+
+void XskSocket::pickUpReadyPacket(std::vector<XskPacket>& packets)
+{
+  timespec now{};
+  gettime(&now);
+  while (!waitForDelay.empty() && timeDifference(now, waitForDelay.top().getSendTime()) <= 0) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+    auto& top = const_cast<XskPacket&>(waitForDelay.top());
+    packets.push_back(top);
+    waitForDelay.pop();
+  }
+}
+
+void XskSocket::recycle(size_t size) noexcept
+{
+  uint32_t idx{0};
+  const auto completeSize = xsk_ring_cons__peek(&cq, size, &idx);
+  if (completeSize == 0) {
+    return;
+  }
+  uniqueEmptyFrameOffset.reserve(uniqueEmptyFrameOffset.size() + completeSize);
+  uint32_t processed = 0;
+  for (; processed < completeSize; ++processed) {
+    uniqueEmptyFrameOffset.push_back(*xsk_ring_cons__comp_addr(&cq, idx++));
+#ifdef DEBUG_UMEM
+    checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+  }
+  xsk_ring_cons__release(&cq, processed);
+}
+
+void XskSocket::XskUmem::umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config)
+{
+  size = memSize;
+  bufBase = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  if (bufBase == MAP_FAILED) {
+    throw std::runtime_error("mmap failed");
+  }
+  auto ret = xsk_umem__create(&umem, bufBase, size, fillQueue, completionQueue, config);
+  if (ret != 0) {
+    munmap(bufBase, size);
+    throw std::runtime_error("Error creating a umem of size " + std::to_string(size) + ": " + stringerror(ret));
+  }
+}
+
+std::string XskSocket::getMetrics() const
+{
+  xdp_statistics stats{};
+  socklen_t optlen = sizeof(stats);
+  int err = getsockopt(xskFd(), SOL_XDP, XDP_STATISTICS, &stats, &optlen);
+  if (err != 0) {
+    return "";
+  }
+  if (optlen != sizeof(struct xdp_statistics)) {
+    return "";
+  }
+
+  ostringstream ret;
+  ret << "RX dropped: " << std::to_string(stats.rx_dropped) << std::endl;
+  ret << "RX invalid descs: " << std::to_string(stats.rx_invalid_descs) << std::endl;
+  ret << "TX invalid descs: " << std::to_string(stats.tx_invalid_descs) << std::endl;
+  ret << "RX ring full: " << std::to_string(stats.rx_ring_full) << std::endl;
+  ret << "RX fill ring empty descs: " << std::to_string(stats.rx_fill_ring_empty_descs) << std::endl;
+  ret << "TX ring empty descs: " << std::to_string(stats.tx_ring_empty_descs) << std::endl;
+  return ret.str();
+}
+
+[[nodiscard]] std::string XskSocket::getXDPMode() const
+{
+#ifdef HAVE_BPF_XDP_QUERY
+  unsigned int itfIdx = if_nametoindex(ifName.c_str());
+  if (itfIdx == 0) {
+    return "unable to get interface index";
+  }
+  bpf_xdp_query_opts info{};
+  info.sz = sizeof(info);
+  int ret = bpf_xdp_query(static_cast<int>(itfIdx), 0, &info);
+  if (ret != 0) {
+    return {};
+  }
+  switch (info.attach_mode) {
+  case XDP_ATTACHED_DRV:
+  case XDP_ATTACHED_HW:
+    return "native";
+  case XDP_ATTACHED_SKB:
+    return "emulated";
+  default:
+    return "unknown";
+  }
+#else /* HAVE_BPF_XDP_QUERY */
+  return "undetected";
+#endif /* HAVE_BPF_XDP_QUERY */
+}
+
+void XskSocket::markAsFree(const XskPacket& packet)
+{
+  auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+  checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, sharedEmptyFrameOffset, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+  uniqueEmptyFrameOffset.push_back(offset);
+}
+
+XskSocket::XskUmem::~XskUmem()
+{
+  if (umem != nullptr) {
+    xsk_umem__delete(umem);
+  }
+  if (bufBase != nullptr) {
+    munmap(bufBase, size);
+  }
+}
+
+[[nodiscard]] size_t XskPacket::getL4HeaderOffset() const noexcept
+{
+  return sizeof(ethhdr) + (v6 ? (sizeof(ipv6hdr)) : sizeof(iphdr));
+}
+
+[[nodiscard]] size_t XskPacket::getDataOffset() const noexcept
+{
+  return getL4HeaderOffset() + sizeof(udphdr);
+}
+
+[[nodiscard]] size_t XskPacket::getDataSize() const noexcept
+{
+  return frameLength - getDataOffset();
+}
+
+[[nodiscard]] ethhdr XskPacket::getEthernetHeader() const noexcept
+{
+  ethhdr ethHeader{};
+  if (frameLength >= sizeof(ethHeader)) {
+    memcpy(&ethHeader, frame, sizeof(ethHeader));
+  }
+  return ethHeader;
+}
+
+void XskPacket::setEthernetHeader(const ethhdr& ethHeader) noexcept
+{
+  if (frameLength < sizeof(ethHeader)) {
+    frameLength = sizeof(ethHeader);
+  }
+  memcpy(frame, &ethHeader, sizeof(ethHeader));
+}
+
+[[nodiscard]] iphdr XskPacket::getIPv4Header() const noexcept
+{
+  iphdr ipv4Header{};
+  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv4Header)));
+  assert(!v6);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(&ipv4Header, frame + sizeof(ethhdr), sizeof(ipv4Header));
+  return ipv4Header;
+}
+
+void XskPacket::setIPv4Header(const iphdr& ipv4Header) noexcept
+{
+  assert(frameLength >= (sizeof(ethhdr) + sizeof(iphdr)));
+  assert(!v6);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(frame + sizeof(ethhdr), &ipv4Header, sizeof(ipv4Header));
+}
+
+[[nodiscard]] ipv6hdr XskPacket::getIPv6Header() const noexcept
+{
+  ipv6hdr ipv6Header{};
+  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+  assert(v6);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(&ipv6Header, frame + sizeof(ethhdr), sizeof(ipv6Header));
+  return ipv6Header;
+}
+
+void XskPacket::setIPv6Header(const ipv6hdr& ipv6Header) noexcept
+{
+  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+  assert(v6);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(frame + sizeof(ethhdr), &ipv6Header, sizeof(ipv6Header));
+}
+
+[[nodiscard]] udphdr XskPacket::getUDPHeader() const noexcept
+{
+  udphdr udpHeader{};
+  assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(&udpHeader, frame + getL4HeaderOffset(), sizeof(udpHeader));
+  return udpHeader;
+}
+
+void XskPacket::setUDPHeader(const udphdr& udpHeader) noexcept
+{
+  assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(frame + getL4HeaderOffset(), &udpHeader, sizeof(udpHeader));
+}
+
+bool XskPacket::parse(bool fromSetHeader)
+{
+  if (frameLength <= sizeof(ethhdr)) {
+    return false;
+  }
+
+  auto ethHeader = getEthernetHeader();
+  uint8_t l4Protocol{0};
+  if (ethHeader.h_proto == htons(ETH_P_IP)) {
+    if (frameLength < (sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr))) {
+      return false;
+    }
+    v6 = false;
+    auto ipHeader = getIPv4Header();
+    if (ipHeader.ihl != (static_cast<uint8_t>(sizeof(iphdr) / 4))) {
+      // ip options is not supported now!
+      return false;
+    }
+    // check ip.check == ipv4Checksum() is not needed!
+    // We check it in BPF program
+    // we don't, actually.
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    from = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    to = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+    l4Protocol = ipHeader.protocol;
+    if (!fromSetHeader && (frameLength - sizeof(ethhdr)) != ntohs(ipHeader.tot_len)) {
+      // too small, or too large (trailing data), go away
+      return false;
+    }
+  }
+  else if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+    if (frameLength < (sizeof(ethhdr) + sizeof(ipv6hdr) + sizeof(udphdr))) {
+      return false;
+    }
+    v6 = true;
+    auto ipHeader = getIPv6Header();
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    from = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    to = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+    l4Protocol = ipHeader.nexthdr;
+    if (!fromSetHeader && (frameLength - (sizeof(ethhdr) + sizeof(ipv6hdr))) != ntohs(ipHeader.payload_len)) {
+      return false;
+    }
+  }
+  else {
+    return false;
+  }
+
+  if (l4Protocol != IPPROTO_UDP) {
+    return false;
+  }
+
+  // check udp.check == ipv4Checksum() is not needed!
+  // We check it in BPF program
+  // we don't, actually.
+  auto udpHeader = getUDPHeader();
+  if (!fromSetHeader) {
+    // Because of XskPacket::setHeader
+    if (getDataOffset() > frameLength) {
+      return false;
+    }
+
+    if (getDataSize() + sizeof(udphdr) != ntohs(udpHeader.len)) {
+      return false;
+    }
+  }
+
+  from.setPort(ntohs(udpHeader.source));
+  to.setPort(ntohs(udpHeader.dest));
+  return true;
+}
+
+uint32_t XskPacket::getDataLen() const noexcept
+{
+  return getDataSize();
+}
+
+uint32_t XskPacket::getFrameLen() const noexcept
+{
+  return frameLength;
+}
+
+size_t XskPacket::getCapacity() const noexcept
+{
+  return frameSize;
+}
+
+void XskPacket::changeDirectAndUpdateChecksum() noexcept
+{
+  auto ethHeader = getEthernetHeader();
+  {
+    std::array<uint8_t, ETH_ALEN> tmp{};
+    static_assert(tmp.size() == sizeof(ethHeader.h_dest), "Size Error");
+    static_assert(tmp.size() == sizeof(ethHeader.h_source), "Size Error");
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+    memcpy(tmp.data(), ethHeader.h_dest, tmp.size());
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+    memcpy(ethHeader.h_dest, ethHeader.h_source, tmp.size());
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+    memcpy(ethHeader.h_source, tmp.data(), tmp.size());
+  }
+  if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+    // IPV6
+    auto ipv6 = getIPv6Header();
+    std::swap(ipv6.daddr, ipv6.saddr);
+    ipv6.nexthdr = IPPROTO_UDP;
+
+    auto udp = getUDPHeader();
+    std::swap(udp.dest, udp.source);
+    udp.len = htons(getDataSize() + sizeof(udp));
+    udp.check = 0;
+    /* needed to get the correct checksum */
+    setIPv6Header(ipv6);
+    setUDPHeader(udp);
+    // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+    // implementations do the same
+    // udp.check = tcp_udp_v6_checksum(&ipv6);
+    rewriteIpv6Header(&ipv6, getFrameLen());
+    setIPv6Header(ipv6);
+    setUDPHeader(udp);
+  }
+  else if (ethHeader.h_proto == htons(ETH_P_IP)) {
+    // IPV4
+    auto ipv4 = getIPv4Header();
+    std::swap(ipv4.daddr, ipv4.saddr);
+    ipv4.protocol = IPPROTO_UDP;
+
+    auto udp = getUDPHeader();
+    std::swap(udp.dest, udp.source);
+    udp.len = htons(getDataSize() + sizeof(udp));
+    udp.check = 0;
+    /* needed to get the correct checksum */
+    setIPv4Header(ipv4);
+    setUDPHeader(udp);
+    // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+    // implementations do the same
+    // udp.check = tcp_udp_v4_checksum(&ipv4);
+    rewriteIpv4Header(&ipv4, getFrameLen());
+    setIPv4Header(ipv4);
+    setUDPHeader(udp);
+  }
+  setEthernetHeader(ethHeader);
+}
+
+void XskPacket::rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept
+{
+  ipv4header->version = 4;
+  ipv4header->ihl = sizeof(iphdr) / 4;
+  ipv4header->tos = 0;
+  ipv4header->tot_len = htons(frameLen - sizeof(ethhdr));
+  ipv4header->id = 0;
+  ipv4header->frag_off = 0;
+  ipv4header->ttl = DefaultTTL;
+  ipv4header->check = 0;
+  ipv4header->check = ipv4Checksum(ipv4header);
+}
+
+void XskPacket::rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept
+{
+  ipv6header->version = 6;
+  ipv6header->priority = 0;
+  ipv6header->payload_len = htons(frameLen - sizeof(ethhdr) - sizeof(ipv6hdr));
+  ipv6header->hop_limit = DefaultTTL;
+  memset(&ipv6header->flow_lbl, 0, sizeof(ipv6header->flow_lbl));
+}
+
+bool XskPacket::isIPV6() const noexcept
+{
+  return v6;
+}
+
+XskPacket::XskPacket(uint8_t* frame_, size_t dataSize, size_t frameSize_) :
+  frame(frame_), frameLength(dataSize), frameSize(frameSize_ - XDP_PACKET_HEADROOM)
+{
+}
+
+PacketBuffer XskPacket::clonePacketBuffer() const
+{
+  const auto size = getDataSize();
+  PacketBuffer tmp(size);
+  if (size > 0) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    memcpy(tmp.data(), frame + getDataOffset(), size);
+  }
+  return tmp;
+}
+
+bool XskPacket::setPayload(const PacketBuffer& buf)
+{
+  const auto bufSize = buf.size();
+  const auto currentCapacity = getCapacity();
+  if (bufSize == 0 || bufSize > currentCapacity) {
+    return false;
+  }
+  flags |= UPDATE;
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  memcpy(frame + getDataOffset(), buf.data(), bufSize);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  frameLength = getDataOffset() + bufSize;
+  return true;
+}
+
+void XskPacket::addDelay(const int relativeMilliseconds) noexcept
+{
+  gettime(&sendTime);
+  sendTime.tv_nsec += static_cast<int64_t>(relativeMilliseconds) * 1000000L;
+  sendTime.tv_sec += sendTime.tv_nsec / 1000000000L;
+  sendTime.tv_nsec %= 1000000000L;
+}
+
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept
+{
+  return lhs.getSendTime() < rhs.getSendTime();
+}
+
+const ComboAddress& XskPacket::getFromAddr() const noexcept
+{
+  return from;
+}
+
+const ComboAddress& XskPacket::getToAddr() const noexcept
+{
+  return to;
+}
+
+void XskWorker::notify(int desc)
+{
+  uint64_t value = 1;
+  ssize_t res = 0;
+  while ((res = write(desc, &value, sizeof(value))) == EINTR) {
+  }
+  if (res != sizeof(value)) {
+    throw runtime_error("Unable Wake Up XskSocket Failed");
+  }
+}
+
+XskWorker::XskWorker(XskWorker::Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames) :
+  d_sharedEmptyFrameOffset(frames), d_type(type), workerWaker(createEventfd()), xskSocketWaker(createEventfd())
+{
+}
+
+void XskWorker::pushToProcessingQueue(XskPacket& packet)
+{
+  if (d_type == Type::OutgoingOnly) {
+    throw std::runtime_error("Trying to push an incoming packet into an outgoing-only XSK Worker");
+  }
+  if (!d_incomingPacketsQueue.push(packet)) {
+    markAsFree(packet);
+  }
+}
+
+void XskWorker::pushToSendQueue(XskPacket& packet)
+{
+  if (!d_outgoingPacketsQueue.push(packet)) {
+    markAsFree(packet);
+  }
+}
+
+const void* XskPacket::getPayloadData() const
+{
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  return frame + getDataOffset();
+}
+
+void XskPacket::setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept
+{
+  auto ethHeader = getEthernetHeader();
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  memcpy(ethHeader.h_dest, toMAC.data(), toMAC.size());
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  memcpy(ethHeader.h_source, fromMAC.data(), fromMAC.size());
+  setEthernetHeader(ethHeader);
+  to = to_;
+  from = from_;
+  v6 = !to.isIPv4();
+  flags = 0;
+}
+
+void XskPacket::rewrite() noexcept
+{
+  flags |= REWRITE;
+  auto ethHeader = getEthernetHeader();
+  if (!v6) {
+    ethHeader.h_proto = htons(ETH_P_IP);
+
+    auto ipHeader = getIPv4Header();
+    ipHeader.daddr = to.sin4.sin_addr.s_addr;
+    ipHeader.saddr = from.sin4.sin_addr.s_addr;
+    ipHeader.protocol = IPPROTO_UDP;
+
+    auto udpHeader = getUDPHeader();
+    udpHeader.source = from.sin4.sin_port;
+    udpHeader.dest = to.sin4.sin_port;
+    udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+    udpHeader.check = 0;
+    /* needed to get the correct checksum */
+    setIPv4Header(ipHeader);
+    setUDPHeader(udpHeader);
+    // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+    // implementations do the same
+    // udpHeader.check = tcp_udp_v4_checksum(&ipHeader);
+    rewriteIpv4Header(&ipHeader, getFrameLen());
+    setIPv4Header(ipHeader);
+    setUDPHeader(udpHeader);
+  }
+  else {
+    ethHeader.h_proto = htons(ETH_P_IPV6);
+
+    auto ipHeader = getIPv6Header();
+    memcpy(&ipHeader.daddr, &to.sin6.sin6_addr, sizeof(ipHeader.daddr));
+    memcpy(&ipHeader.saddr, &from.sin6.sin6_addr, sizeof(ipHeader.saddr));
+    ipHeader.nexthdr = IPPROTO_UDP;
+
+    auto udpHeader = getUDPHeader();
+    udpHeader.source = from.sin6.sin6_port;
+    udpHeader.dest = to.sin6.sin6_port;
+    udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+    udpHeader.check = 0;
+    /* needed to get the correct checksum */
+    setIPv6Header(ipHeader);
+    setUDPHeader(udpHeader);
+    // do not bother setting the UDP checksum: 0 is a valid value and most AF_XDP
+    // implementations do the same
+    // udpHeader.check = tcp_udp_v6_checksum(&ipHeader);
+    setIPv6Header(ipHeader);
+    setUDPHeader(udpHeader);
+  }
+
+  setEthernetHeader(ethHeader);
+}
+
+[[nodiscard]] __be16 XskPacket::ipv4Checksum(const struct iphdr* ipHeader) noexcept
+{
+  auto partial = ip_checksum_partial(ipHeader, sizeof(iphdr), 0);
+  return ip_checksum_fold(partial);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v4_checksum(const struct iphdr* ipHeader) const noexcept
+{
+  // ip options is not supported !!!
+  const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+  auto sum = tcp_udp_v4_header_checksum_partial(ipHeader->saddr, ipHeader->daddr, ipHeader->protocol, l4Length);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+  return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v6_checksum(const struct ipv6hdr* ipv6) const noexcept
+{
+  const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+  uint64_t sum = tcp_udp_v6_header_checksum_partial(&ipv6->saddr, &ipv6->daddr, ipv6->nexthdr, l4Length);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+  return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] uint64_t XskPacket::ip_checksum_partial(const void* ptr, const size_t len, uint64_t sum) noexcept
+{
+  size_t position{0};
+  /* Main loop: 32 bits at a time */
+  for (position = 0; position < len; position += sizeof(uint32_t)) {
+    uint32_t value{};
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+    sum += value;
+  }
+
+  /* Handle un-32bit-aligned trailing bytes */
+  if ((len - position) >= 2) {
+    uint16_t value{};
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+    sum += value;
+    position += sizeof(value);
+  }
+
+  if ((len - position) > 0) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    const auto* ptr8 = static_cast<const uint8_t*>(ptr) + position;
+    sum += ntohs(*ptr8 << 8); /* RFC says pad last byte */
+  }
+
+  return sum;
+}
+
+[[nodiscard]] __be16 XskPacket::ip_checksum_fold(uint64_t sum) noexcept
+{
+  while ((sum & ~0xffffffffULL) != 0U) {
+    sum = (sum >> 32) + (sum & 0xffffffffULL);
+  }
+  while ((sum & 0xffff0000ULL) != 0U) {
+    sum = (sum >> 16) + (sum & 0xffffULL);
+  }
+
+  return static_cast<__be16>(~sum);
+}
+
+#ifndef __packed
+#define packed_attribute __attribute__((packed))
+#else
+#define packed_attribute __packed
+#endif
+
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept
+{
+  struct header
+  {
+    __be32 src_ip;
+    __be32 dst_ip;
+    __uint8_t mbz;
+    __uint8_t protocol;
+    __be16 length;
+  };
+  /* The IPv4 pseudo-header is defined in RFC 793, Section 3.1. */
+  struct ipv4_pseudo_header_t
+  {
+    /* We use a union here to avoid aliasing issues with gcc -O2 */
+    union
+    {
+      header packed_attribute fields;
+      // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+      uint32_t words[3];
+    };
+  };
+  ipv4_pseudo_header_t pseudo_header{};
+  static_assert(sizeof(pseudo_header) == 12, "IPv4 pseudo-header size is incorrect");
+
+  /* Fill in the pseudo-header. */
+  pseudo_header.fields.src_ip = src_ip;
+  pseudo_header.fields.dst_ip = dst_ip;
+  pseudo_header.fields.mbz = 0;
+  pseudo_header.fields.protocol = protocol;
+  pseudo_header.fields.length = htons(len);
+  return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept
+{
+  struct header
+  {
+    struct in6_addr src_ip;
+    struct in6_addr dst_ip;
+    __be32 length;
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+    __uint8_t mbz[3];
+    __uint8_t next_header;
+  };
+  /* The IPv6 pseudo-header is defined in RFC 2460, Section 8.1. */
+  struct ipv6_pseudo_header_t
+  {
+    /* We use a union here to avoid aliasing issues with gcc -O2 */
+    union
+    {
+      header packed_attribute fields;
+      // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+      uint32_t words[10];
+    };
+  };
+  ipv6_pseudo_header_t pseudo_header{};
+  static_assert(sizeof(pseudo_header) == 40, "IPv6 pseudo-header size is incorrect");
+
+  /* Fill in the pseudo-header. */
+  pseudo_header.fields.src_ip = *src_ip;
+  pseudo_header.fields.dst_ip = *dst_ip;
+  pseudo_header.fields.length = htonl(len);
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  memset(pseudo_header.fields.mbz, 0, sizeof(pseudo_header.fields.mbz));
+  pseudo_header.fields.next_header = protocol;
+  return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+void XskPacket::setHeader(PacketBuffer& buf)
+{
+  memcpy(frame, buf.data(), buf.size());
+  frameLength = buf.size();
+  buf.clear();
+  flags = 0;
+  if (!parse(true)) {
+    throw std::runtime_error("Error setting the XSK frame header");
+  }
+}
+
+PacketBuffer XskPacket::cloneHeaderToPacketBuffer() const
+{
+  const auto size = getFrameLen() - getDataSize();
+  PacketBuffer tmp(size);
+  memcpy(tmp.data(), frame, size);
+  return tmp;
+}
+
+int XskWorker::createEventfd()
+{
+  auto desc = ::eventfd(0, EFD_CLOEXEC);
+  if (desc < 0) {
+    throw runtime_error("Unable create eventfd");
+  }
+  return desc;
+}
+
+void XskWorker::waitForXskSocket() const noexcept
+{
+  uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+void XskWorker::notifyXskSocket() const
+{
+  notify(xskSocketWaker);
+}
+
+std::shared_ptr<XskWorker> XskWorker::create(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames)
+{
+  return std::make_shared<XskWorker>(type, frames);
+}
+
+void XskSocket::addWorker(std::shared_ptr<XskWorker> worker)
+{
+  const auto socketWaker = worker->xskSocketWaker.getHandle();
+  worker->setUmemBufBase(umem.bufBase);
+  d_workers.insert({socketWaker, std::move(worker)});
+  fds.push_back(pollfd{
+    .fd = socketWaker,
+    .events = POLLIN,
+    .revents = 0});
+};
+
+void XskSocket::addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest)
+{
+  d_workerRoutes.lock()->insert({dest, worker});
+}
+
+void XskSocket::removeWorkerRoute(const ComboAddress& dest)
+{
+  d_workerRoutes.lock()->erase(dest);
+}
+
+void XskWorker::setUmemBufBase(uint8_t* base)
+{
+  d_umemBufBase = base;
+}
+
+uint64_t XskWorker::frameOffset(const XskPacket& packet) const noexcept
+{
+  return packet.getFrameOffsetFrom(d_umemBufBase);
+}
+
+void XskWorker::notifyWorker() const
+{
+  notify(workerWaker);
+}
+
+bool XskWorker::hasIncomingFrames()
+{
+  if (d_type == Type::OutgoingOnly) {
+    throw std::runtime_error("Looking for incoming packets in an outgoing-only XSK Worker");
+  }
+
+  return d_incomingPacketsQueue.read_available() != 0U;
+}
+
+void XskWorker::processIncomingFrames(const std::function<void(XskPacket& packet)>& callback)
+{
+  if (d_type == Type::OutgoingOnly) {
+    throw std::runtime_error("Looking for incoming packets in an outgoing-only XSK Worker");
+  }
+
+  d_incomingPacketsQueue.consume_all(callback);
+}
+
+void XskWorker::processOutgoingFrames(const std::function<void(XskPacket& packet)>& callback)
+{
+  d_outgoingPacketsQueue.consume_all(callback);
+}
+
+void XskSocket::getMACFromIfName()
+{
+  ifreq ifr{};
+  auto desc = FDWrapper(::socket(AF_INET, SOCK_DGRAM, 0));
+  if (desc < 0) {
+    throw std::runtime_error("Error creating a socket to get the MAC address of interface " + ifName);
+  }
+
+  if (ifName.size() >= IFNAMSIZ) {
+    throw std::runtime_error("Unable to get MAC address for interface " + ifName + ": name too long");
+  }
+
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  strncpy(ifr.ifr_name, ifName.c_str(), ifName.length() + 1);
+  if (ioctl(desc.getHandle(), SIOCGIFHWADDR, &ifr) < 0 || ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+    throw std::runtime_error("Error getting MAC address for interface " + ifName);
+  }
+  static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= std::tuple_size<decltype(source)>{}, "The size of an ARPHRD_ETHER MAC address is smaller than expected");
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  memcpy(source.data(), ifr.ifr_hwaddr.sa_data, source.size());
+}
+
+[[nodiscard]] int XskSocket::timeDifference(const timespec& lhs, const timespec& rhs) noexcept
+{
+  const auto res = lhs.tv_sec * 1000 + lhs.tv_nsec / 1000000L - (rhs.tv_sec * 1000 + rhs.tv_nsec / 1000000L);
+  return static_cast<int>(res);
+}
+
+void XskWorker::cleanWorkerNotification() const noexcept
+{
+  uint64_t value = read(xskSocketWaker, &value, sizeof(value));
+}
+
+void XskWorker::cleanSocketNotification() const noexcept
+{
+  uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info)
+{
+  std::vector<pollfd> fds;
+  int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+  if (timerfd < 0) {
+    throw std::runtime_error("create_timerfd failed");
+  }
+  fds.push_back(pollfd{
+    .fd = info.workerWaker,
+    .events = POLLIN,
+    .revents = 0,
+  });
+  fds.push_back(pollfd{
+    .fd = timerfd,
+    .events = POLLIN,
+    .revents = 0,
+  });
+  return fds;
+}
+
+std::optional<XskPacket> XskWorker::getEmptyFrame()
+{
+  auto frames = d_sharedEmptyFrameOffset->lock();
+  if (frames->empty()) {
+    return std::nullopt;
+  }
+  auto offset = frames->back();
+  frames->pop_back();
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  return XskPacket(offset + d_umemBufBase, 0, d_frameSize);
+}
+
+void XskWorker::markAsFree(const XskPacket& packet)
+{
+  auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+  checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, d_sharedEmptyFrameOffset, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+  {
+    auto frames = d_sharedEmptyFrameOffset->lock();
+    frames->push_back(offset);
+  }
+}
+
+uint32_t XskPacket::getFlags() const noexcept
+{
+  return flags;
+}
+
+void XskPacket::updatePacket() noexcept
+{
+  if ((flags & UPDATE) == 0U) {
+    return;
+  }
+  if ((flags & REWRITE) == 0U) {
+    changeDirectAndUpdateChecksum();
+  }
+}
+#endif /* HAVE_XSK */
deleted file mode 120000 (symlink)
index 4b1bba7374b39fac469b6a8e1f497dfb745edbcb..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../xsk.hh
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..2f3e7c372e352a232e19f42dbba1219935f62596
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+#include "config.h"
+
+#ifdef HAVE_XSK
+#include <array>
+#include <bits/types/struct_timespec.h>
+#include <boost/lockfree/spsc_queue.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <cstdint>
+#include <memory>
+#include <poll.h>
+#include <queue>
+#include <stdexcept>
+#include <string>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+#include <xdp/xsk.h>
+
+#include "iputils.hh"
+#include "lock.hh"
+#include "misc.hh"
+#include "noinitvector.hh"
+
+class XskPacket;
+class XskWorker;
+class XskSocket;
+
+using MACAddr = std::array<uint8_t, 6>;
+
+// We use an XskSocket to manage an AF_XDP Socket corresponding to a NIC queue.
+// The XDP program running in the kernel redirects the data to the XskSocket in userspace.
+// We allocate frames that are placed into the descriptors in the fill queue, allowing the kernel to put incoming packets into the frames and place descriptors into the rx queue.
+// Once we have read the descriptors from the rx queue we release them, but we own the frames.
+// After we are done with the frame, we place them into descriptors of either the fill queue (empty frames) or tx queues (packets to be sent).
+// Once the kernel is done, it places descriptors referencing these frames into the cq where we can recycle them (packets destined to the tx queue or empty frame to the fill queue).
+
+// XskSocket routes packets to multiple worker threads registered on XskSocket via XskSocket::addWorker based on the destination port number of the packet.
+// The kernel and the worker thread holding XskWorker will wake up the XskSocket through XskFd and the Eventfd corresponding to each worker thread, respectively.
+
+class XskSocket
+{
+  struct XskUmem
+  {
+    xsk_umem* umem{nullptr};
+    uint8_t* bufBase{nullptr};
+    size_t size{0};
+    void umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config);
+    ~XskUmem();
+    XskUmem() = default;
+  };
+  using WorkerContainer = std::unordered_map<int, std::shared_ptr<XskWorker>>;
+  WorkerContainer d_workers;
+  using WorkerRoutesMap = std::unordered_map<ComboAddress, std::shared_ptr<XskWorker>, ComboAddress::addressPortOnlyHash>;
+  // it might be better to move to a StateHolder for performance
+  LockGuarded<WorkerRoutesMap> d_workerRoutes;
+  // number of frames to keep in sharedEmptyFrameOffset
+  static constexpr size_t holdThreshold = 256;
+  // number of frames to insert into the fill queue
+  static constexpr size_t fillThreshold = 128;
+  static constexpr size_t frameSize = 2048;
+  // number of entries (frames) in the umem
+  const size_t frameNum;
+  // responses that have been delayed
+  std::priority_queue<XskPacket> waitForDelay;
+  MACAddr source{};
+  const std::string ifName;
+  // AF_XDP socket then worker waker sockets
+  vector<pollfd> fds;
+  // list of frames, aka (indexes of) umem entries that can be reused to fill fq,
+  // collected from packets that we could not route (unknown destination),
+  // could not parse, were dropped during processing (!UPDATE), or
+  // simply recycled from cq after being processed by the kernel
+  vector<uint64_t> uniqueEmptyFrameOffset;
+  // completion ring: queue where sent packets are stored by the kernel
+  xsk_ring_cons cq{};
+  // rx ring: queue where the incoming packets are stored, read by XskRouter
+  xsk_ring_cons rx{};
+  // fill ring: queue where umem entries available to be filled (put into rx) are stored
+  xsk_ring_prod fq{};
+  // tx ring: queue where outgoing packets are stored
+  xsk_ring_prod tx{};
+  std::unique_ptr<xsk_socket, void (*)(xsk_socket*)> socket;
+  XskUmem umem;
+
+  static constexpr uint32_t fqCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4;
+  static constexpr uint32_t cqCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 4;
+  static constexpr uint32_t rxCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 2;
+  static constexpr uint32_t txCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2;
+
+  constexpr static bool isPowOfTwo(uint32_t value) noexcept;
+  [[nodiscard]] static int timeDifference(const timespec& lhs, const timespec& rhs) noexcept;
+
+  [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+  [[nodiscard]] int firstTimeout();
+  void getMACFromIfName();
+
+public:
+  static void clearDestinationMap(const std::string& mapPath, bool isV6);
+  static void addDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+  static void removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+  static constexpr size_t getFrameSize()
+  {
+    return frameSize;
+  }
+  // list of free umem entries that can be reused
+  std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
+  XskSocket(size_t frameNum, std::string ifName, uint32_t queue_id, const std::string& xskMapPath);
+  [[nodiscard]] int xskFd() const noexcept;
+  // wait until one event has occurred
+  [[nodiscard]] int wait(int timeout);
+  // add as many packets as possible to the rx queue for sending */
+  void send(std::vector<XskPacket>& packets);
+  // look at incoming packets in rx, return them if parsing succeeeded
+  [[nodiscard]] std::vector<XskPacket> recv(uint32_t recvSizeMax, uint32_t* failedCount);
+  void addWorker(std::shared_ptr<XskWorker> worker);
+  void addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest);
+  void removeWorkerRoute(const ComboAddress& dest);
+  [[nodiscard]] std::string getMetrics() const;
+  [[nodiscard]] std::string getXDPMode() const;
+  void markAsFree(const XskPacket& packet);
+  [[nodiscard]] const std::shared_ptr<XskWorker>& getWorkerByDescriptor(int desc) const
+  {
+    return d_workers.at(desc);
+  }
+  [[nodiscard]] std::shared_ptr<XskWorker> getWorkerByDestination(const ComboAddress& destination)
+  {
+    auto routes = d_workerRoutes.lock();
+    auto workerIt = routes->find(destination);
+    if (workerIt == routes->end()) {
+      return nullptr;
+    }
+    return workerIt->second;
+  }
+  [[nodiscard]] const std::vector<pollfd>& getDescriptors() const
+  {
+    return fds;
+  }
+  [[nodiscard]] MACAddr getSourceMACAddress() const
+  {
+    return source;
+  }
+  [[nodiscard]] const std::string& getInterfaceName() const
+  {
+    return ifName;
+  }
+  // pick ups available frames from uniqueEmptyFrameOffset
+  // insert entries from uniqueEmptyFrameOffset into fq
+  void fillFq(uint32_t fillSize = fillThreshold) noexcept;
+  // picks up entries that have been processed (sent) from cq and push them into uniqueEmptyFrameOffset
+  void recycle(size_t size) noexcept;
+  // look at delayed packets, and send the ones that are ready
+  void pickUpReadyPacket(std::vector<XskPacket>& packets);
+  void pushDelayed(XskPacket& packet)
+  {
+    waitForDelay.push(packet);
+  }
+};
+
+struct ethhdr;
+struct iphdr;
+struct ipv6hdr;
+struct udphdr;
+
+class XskPacket
+{
+public:
+  enum Flags : uint32_t
+  {
+    /* whether the payload has been modified */
+    UPDATE = 1 << 0,
+    DELAY = 1 << 1,
+    /* whether the headers have already been updated */
+    REWRITE = 1 << 2
+  };
+
+private:
+  ComboAddress from;
+  ComboAddress to;
+  timespec sendTime{};
+  uint8_t* frame{nullptr};
+  size_t frameLength{0};
+  size_t frameSize{0};
+  uint32_t flags{0};
+  bool v6{false};
+
+  // You must set ipHeader.check = 0 before calling this method
+  [[nodiscard]] static __be16 ipv4Checksum(const struct iphdr*) noexcept;
+  [[nodiscard]] static uint64_t ip_checksum_partial(const void* p, size_t len, uint64_t sum) noexcept;
+  [[nodiscard]] static __be16 ip_checksum_fold(uint64_t sum) noexcept;
+  [[nodiscard]] static uint64_t tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept;
+  [[nodiscard]] static uint64_t tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept;
+  static void rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept;
+  static void rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept;
+
+  // You must set l4Header.check = 0 before calling this method
+  // ip options is not supported
+  [[nodiscard]] __be16 tcp_udp_v4_checksum(const struct iphdr*) const noexcept;
+  // You must set l4Header.check = 0 before calling this method
+  [[nodiscard]] __be16 tcp_udp_v6_checksum(const struct ipv6hdr*) const noexcept;
+  /* offset of the L4 (udphdr) header (after ethhdr and iphdr/ipv6hdr) */
+  [[nodiscard]] size_t getL4HeaderOffset() const noexcept;
+  /* offset of the data after the UDP header */
+  [[nodiscard]] size_t getDataOffset() const noexcept;
+  [[nodiscard]] size_t getDataSize() const noexcept;
+  [[nodiscard]] ethhdr getEthernetHeader() const noexcept;
+  void setEthernetHeader(const ethhdr& ethHeader) noexcept;
+  [[nodiscard]] iphdr getIPv4Header() const noexcept;
+  void setIPv4Header(const iphdr& ipv4Header) noexcept;
+  [[nodiscard]] ipv6hdr getIPv6Header() const noexcept;
+  void setIPv6Header(const ipv6hdr& ipv6Header) noexcept;
+  [[nodiscard]] udphdr getUDPHeader() const noexcept;
+  void setUDPHeader(const udphdr& udpHeader) noexcept;
+  /* exchange the source and destination addresses (ethernet and IP) */
+  void changeDirectAndUpdateChecksum() noexcept;
+
+  constexpr static uint8_t DefaultTTL = 64;
+
+public:
+  [[nodiscard]] const ComboAddress& getFromAddr() const noexcept;
+  [[nodiscard]] const ComboAddress& getToAddr() const noexcept;
+  [[nodiscard]] const void* getPayloadData() const;
+  [[nodiscard]] bool isIPV6() const noexcept;
+  [[nodiscard]] size_t getCapacity() const noexcept;
+  [[nodiscard]] uint32_t getDataLen() const noexcept;
+  [[nodiscard]] uint32_t getFrameLen() const noexcept;
+  [[nodiscard]] PacketBuffer clonePacketBuffer() const;
+  [[nodiscard]] PacketBuffer cloneHeaderToPacketBuffer() const;
+  void setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept;
+  bool setPayload(const PacketBuffer& buf);
+  /* rewrite the headers, usually after setAddr() and setPayload() have been called */
+  void rewrite() noexcept;
+  void setHeader(PacketBuffer& buf);
+  XskPacket(uint8_t* frame, size_t dataSize, size_t frameSize);
+  void addDelay(int relativeMilliseconds) noexcept;
+  /* if the payload have been updated, and the headers have not been rewritten, exchange the source
+     and destination addresses (ethernet and IP) and rewrite the headers */
+  void updatePacket() noexcept;
+  // parse IP and UDP payloads
+  bool parse(bool fromSetHeader);
+  [[nodiscard]] uint32_t getFlags() const noexcept;
+  [[nodiscard]] timespec getSendTime() const noexcept
+  {
+    return sendTime;
+  }
+  [[nodiscard]] uint64_t getFrameOffsetFrom(const uint8_t* base) const noexcept
+  {
+    return frame - base;
+  }
+};
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept;
+
+// XskWorker obtains XskPackets of specific ports in the NIC from XskSocket through cq.
+// After finishing processing the packet, XskWorker puts the packet into sq so that XskSocket decides whether to send it through the network card according to XskPacket::flags.
+// XskWorker wakes up XskSocket via xskSocketWaker after putting the packets in sq.
+class XskWorker
+{
+public:
+  enum class Type : uint8_t
+  {
+    OutgoingOnly,
+    Bidirectional
+  };
+
+private:
+  using XskPacketRing = boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>;
+  // queue of packets to be processed by this worker
+  XskPacketRing d_incomingPacketsQueue;
+  // queue of packets processed by this worker (to be sent, or discarded)
+  XskPacketRing d_outgoingPacketsQueue;
+  // list of frames that are shared with the XskRouter
+  std::shared_ptr<LockGuarded<vector<uint64_t>>> d_sharedEmptyFrameOffset;
+  uint8_t* d_umemBufBase{nullptr};
+  const size_t d_frameSize{XskSocket::getFrameSize()};
+  Type d_type;
+
+public:
+  FDWrapper workerWaker;
+  FDWrapper xskSocketWaker;
+
+  static int createEventfd();
+  static void notify(int desc);
+  static std::shared_ptr<XskWorker> create(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames);
+
+  XskWorker(Type type, const std::shared_ptr<LockGuarded<std::vector<uint64_t>>>& frames);
+  void setUmemBufBase(uint8_t* base);
+  void pushToProcessingQueue(XskPacket& packet);
+  void pushToSendQueue(XskPacket& packet);
+  bool hasIncomingFrames();
+  void processIncomingFrames(const std::function<void(XskPacket& packet)>& callback);
+  void processOutgoingFrames(const std::function<void(XskPacket& packet)>& callback);
+  void markAsFree(const XskPacket& packet);
+  // notify worker that at least one packet is available for processing
+  void notifyWorker() const;
+  // notify the router that packets are ready to be sent
+  void notifyXskSocket() const;
+  void waitForXskSocket() const noexcept;
+  void cleanWorkerNotification() const noexcept;
+  void cleanSocketNotification() const noexcept;
+  [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+  // get an empty umem entry from sharedEmptyFrameOffset
+  std::optional<XskPacket> getEmptyFrame();
+};
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info);
+#else
+class XskSocket
+{
+};
+class XskPacket
+{
+};
+class XskWorker
+{
+};
+
+#endif /* HAVE_XSK */
index e02cedb6240b3c0a5eca007542ccd6f2469a1fed..0b95ea30178a896c0cb538d5af1895cc0054fad5 100644 (file)
@@ -2,19 +2,19 @@
  * This file describes the message format used by the protobuf logging feature in PowerDNS and dnsdist.
  *
  * MIT License
- * 
+ *
  * Copyright (c) 2016-now PowerDNS.COM B.V. and its contributors.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -183,7 +183,11 @@ message PBDNSMessage {
     optional string custom = 8;                 // The name of the event for custom events
   }
   repeated Event trace = 23;
+
   optional HTTPVersion httpVersion = 24;        // HTTP version used for DNS over HTTP
+  optional uint64 workerId = 25;                // Thread id
+  optional bool packetCacheHit = 26;            // Was it a packet cache hit?
+  optional uint32 outgoingQueries = 27;         // Number of outgoing queries used to answer the query
 }
 
 message PBDNSMessageList {
index 0d9112b2ad2183649e5180be48d69edc8a0d6417..9ba8ba7fbb7401dd1155cac39a0e42427538ab03 100644 (file)
 #include <string_view>
 
 #include <boost/version.hpp>
-
-#if BOOST_VERSION >= 105300
 #include <boost/container/string.hpp>
-#endif
 
 inline bool dns_isspace(char c)
 {
@@ -176,11 +173,8 @@ public:
   inline bool canonCompare(const DNSName& rhs) const;
   bool slowCanonCompare(const DNSName& rhs) const;
 
-#if BOOST_VERSION >= 105300
   typedef boost::container::string string_t;
-#else
-  typedef std::string string_t;
-#endif
+
   const string_t& getStorage() const {
     return d_storage;
   }
index b18da82c7b0108737a47db26a611e2596abceb84..324399cd3ca886a73a8987b28bc165b5f6f6d42d 100644 (file)
@@ -112,9 +112,7 @@ ComboAddress DNSPacket::getRemote() const
 
 ComboAddress DNSPacket::getInnerRemote() const
 {
-  if (d_inner_remote)
-    return *d_inner_remote;
-  return d_remote;
+  return d_inner_remote ? *d_inner_remote : d_remote;
 }
 
 uint16_t DNSPacket::getRemotePort() const
@@ -355,7 +353,7 @@ void DNSPacket::wrapup(bool throwsOnTruncation)
         pos->dr.getContent()->toPacket(pw);
         if(pw.size() + optsize > (d_tcp ? 65535 : getMaxReplyLen())) {
           if (throwsOnTruncation) {
-            throw PDNSException("attempt to write an oversized chunk");
+            throw PDNSException("attempt to write an oversized chunk, see https://docs.powerdns.com/authoritative/settings.html#workaround-11804");
           }
           pw.rollback();
           pw.truncate();
@@ -515,15 +513,15 @@ bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, DNSName* keyname, uint16_
 
   bool gotit=false;
   for(const auto & answer : mdp.d_answers) {
-    if(answer.first.d_type == QType::TSIG && answer.first.d_class == QType::ANY) {
+    if(answer.d_type == QType::TSIG && answer.d_class == QType::ANY) {
       // cast can fail, f.e. if d_content is an UnknownRecordContent.
-      auto content = getRR<TSIGRecordContent>(answer.first);
+      auto content = getRR<TSIGRecordContent>(answer);
       if (!content) {
         g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl;
         return false;
       }
       *trc = *content;
-      *keyname = answer.first.d_name;
+      *keyname = answer.d_name;
       gotit=true;
     }
   }
@@ -548,15 +546,15 @@ bool DNSPacket::getTKEYRecord(TKEYRecordContent *tr, DNSName *keyname) const
       return false;
     }
 
-    if(answer.first.d_type == QType::TKEY) {
+    if(answer.d_type == QType::TKEY) {
       // cast can fail, f.e. if d_content is an UnknownRecordContent.
-      auto content = getRR<TKEYRecordContent>(answer.first);
+      auto content = getRR<TKEYRecordContent>(answer);
       if (!content) {
         g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl;
         return false;
       }
       *tr = *content;
-      *keyname = answer.first.d_name;
+      *keyname = answer.d_name;
       gotit=true;
     }
   }
@@ -706,16 +704,19 @@ bool DNSPacket::hasValidEDNSCookie() const
   return d_ednscookievalid;
 }
 
+void DNSPacket::setRealRemote(const Netmask& netmask) {
+  d_eso.source = netmask;
+  d_haveednssubnet = true;
+}
+
 Netmask DNSPacket::getRealRemote() const
 {
-  if(d_haveednssubnet)
-    return d_eso.source;
-  return Netmask(getInnerRemote());
+  return d_haveednssubnet ? d_eso.source : Netmask{getInnerRemote()};
 }
 
 void DNSPacket::setSocket(Utility::sock_t sock)
 {
-  d_socket=sock;
+  d_socket = sock;
 }
 
 void DNSPacket::commitD()
index 446af60f46eb569a04835078f9e5ea896d6841a0..a9bd01004831298cfbeddfe75e0085dbcf066a0a 100644 (file)
@@ -65,6 +65,7 @@ public:
   ComboAddress getRemote() const;
   ComboAddress getInnerRemote() const; // for proxy protocol
   Netmask getRealRemote() const;
+  void setRealRemote(const Netmask& netmask);
   ComboAddress getLocal() const
   {
     ComboAddress ca;
@@ -97,7 +98,7 @@ public:
 
   void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs')
 
-  /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions, 
+  /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
       Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
       DNSZoneRecord d_place field */
   void addRecord(DNSZoneRecord&&);  // adds to 'rrs'
@@ -169,7 +170,7 @@ public:
   vector<DNSZoneRecord>& getRRS() { return d_rrs; }
   bool checkForCorrectTSIG(UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc) const;
 
-  static uint16_t s_udpTruncationThreshold; 
+  static uint16_t s_udpTruncationThreshold;
   static bool s_doEDNSSubnetProcessing;
   static bool s_doEDNSCookieProcessing;
   static string s_EDNSCookieKey;
index ba4fd22982e5fde4973099101d823836ef8ccb6e..1eecaea630e80c8461f1e15b18c3ff04de2819d3 100644 (file)
@@ -305,7 +305,7 @@ void MOADNSParser::init(bool query, const std::string_view& packet)
         d_tsigPos = recordStartPos;
       }
 
-      d_answers.emplace_back(std::move(dr), pr.getPosition() - sizeof(dnsheader));
+      d_answers.emplace_back(std::move(dr));
     }
 
 #if 0
@@ -342,7 +342,7 @@ bool MOADNSParser::hasEDNS() const
   }
 
   for (const auto& record : d_answers) {
-    if (record.first.d_place == DNSResourceRecord::ADDITIONAL && record.first.d_type == QType::OPT) {
+    if (record.d_place == DNSResourceRecord::ADDITIONAL && record.d_type == QType::OPT) {
       return true;
     }
   }
index 20ce6396beb87d5dccc6c4750649f56ec904a390..07660b90ea335540d475dda2bd31ed3ba2b2274a 100644 (file)
@@ -338,6 +338,16 @@ public:
     return s.str();
   }
 
+  [[nodiscard]] std::string toString() const
+  {
+    std::string ret(d_name.toLogString());
+    ret += '|';
+    ret += QType(d_type).toString();
+    ret += '|';
+    ret += getContent()->getZoneRepresentation();
+    return ret;
+  }
+
   void setContent(const std::shared_ptr<const DNSRecordContent>& content)
   {
     d_content = content;
@@ -472,10 +482,9 @@ public:
 
   DNSName d_qname;
   uint16_t d_qclass, d_qtype;
-  //uint8_t d_rcode;
   dnsheader d_header;
 
-  typedef vector<pair<DNSRecord, uint16_t > > answers_t;
+  using answers_t = vector<DNSRecord>;
 
   //! All answers contained in this packet (everything *but* the question section)
   answers_t d_answers;
index 26a0aa0805f4b8e4bd507a2592f85110cde2f6a8..8c14559c92ecaf46c3377c9655180b1c880309d2 100644 (file)
 #include "ednsoptions.hh"
 #include "ednssubnet.hh"
 
+#include <boost/uuid/uuid_io.hpp>
+
 extern StatBag S;
 
-DNSProxy::DNSProxy(const string& remote) :
+DNSProxy::DNSProxy(const string& remote, const string& udpPortRange) :
   d_xor(dns_random_uint16())
 {
   d_resanswers = S.getPointer("recursing-answers");
@@ -53,6 +55,20 @@ DNSProxy::DNSProxy(const string& remote) :
   stringtok(addresses, remote, " ,\t");
   d_remote = ComboAddress(addresses[0], 53);
 
+  vector<string> parts;
+  stringtok(parts, udpPortRange, " ");
+  if (parts.size() != 2) {
+    throw PDNSException("DNS Proxy UDP port range must contain exactly one lower and one upper bound");
+  }
+  unsigned long portRangeLow = std::stoul(parts.at(0));
+  unsigned long portRangeHigh = std::stoul(parts.at(1));
+  if (portRangeLow < 1 || portRangeHigh > 65535) {
+    throw PDNSException("DNS Proxy UDP port range values out of valid port bounds (1 to 65535)");
+  }
+  if (portRangeLow >= portRangeHigh) {
+    throw PDNSException("DNS Proxy UDP port range upper bound " + std::to_string(portRangeHigh) + " must be higher than lower bound (" + std::to_string(portRangeLow) + ")");
+  }
+
   if ((d_sock = socket(d_remote.sin4.sin_family, SOCK_DGRAM, 0)) < 0) {
     throw PDNSException(string("socket: ") + stringerror());
   }
@@ -67,7 +83,7 @@ DNSProxy::DNSProxy(const string& remote) :
 
   unsigned int attempts = 0;
   for (; attempts < 10; attempts++) {
-    local.sin4.sin_port = htons(10000 + dns_random(50000));
+    local.sin4.sin_port = htons(portRangeLow + dns_random(portRangeHigh - portRangeLow));
 
     if (::bind(d_sock, (struct sockaddr*)&local, local.getSocklen()) >= 0) { // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
       break;
@@ -92,7 +108,7 @@ void DNSProxy::go()
   proxythread.detach();
 }
 
-//! look up qname target with r->qtype, plonk it in the answer section of 'r' with name aname
+//! look up qname 'target' with reply->qtype, plonk it in the answer section of 'reply' with name 'aname'
 bool DNSProxy::completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask)
 {
   string ECSOptionStr;
@@ -277,15 +293,15 @@ void DNSProxy::mainloop()
 
         if (mdp.d_header.rcode == RCode::NoError) {
           for (const auto& answer : mdp.d_answers) {
-            if (answer.first.d_place == DNSResourceRecord::ANSWER || (answer.first.d_place == DNSResourceRecord::AUTHORITY && answer.first.d_type == QType::SOA)) {
+            if (answer.d_place == DNSResourceRecord::ANSWER || (answer.d_place == DNSResourceRecord::AUTHORITY && answer.d_type == QType::SOA)) {
 
-              if (answer.first.d_type == iter->second.qtype || (iter->second.qtype == QType::ANY && (answer.first.d_type == QType::A || answer.first.d_type == QType::AAAA))) {
+              if (answer.d_type == iter->second.qtype || (iter->second.qtype == QType::ANY && (answer.d_type == QType::A || answer.d_type == QType::AAAA))) {
                 DNSZoneRecord dzr;
                 dzr.dr.d_name = iter->second.aname;
-                dzr.dr.d_type = answer.first.d_type;
-                dzr.dr.d_ttl = answer.first.d_ttl;
-                dzr.dr.d_place = answer.first.d_place;
-                dzr.dr.setContent(answer.first.getContent());
+                dzr.dr.d_type = answer.d_type;
+                dzr.dr.d_ttl = answer.d_ttl;
+                dzr.dr.d_place = answer.d_place;
+                dzr.dr.setContent(answer.getContent());
                 iter->second.complete->addRecord(std::move(dzr));
               }
             }
index 0ce1eefd1d61b1ad011f5624b24027f4599a53d4..b5ec5de136420cb6bf6347c024dea1c52b814d24 100644 (file)
@@ -49,7 +49,7 @@ To fix: how to remove the stale entries that will surely accumulate
 class DNSProxy
 {
 public:
-  DNSProxy(const string& remote); //!< creates socket
+  DNSProxy(const string& remote, const string& udpPortRange); //!< creates socket
   ~DNSProxy(); //<! dtor for DNSProxy
   void go(); //!< launches the actual thread
   bool completePacket(std::unique_ptr<DNSPacket>& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask);
index a7c752be1fa95ab184a284596cc75598032f7c05..8f9c0512236882e4fc2b35f11f11ef972233968e 100644 (file)
@@ -884,18 +884,18 @@ bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
   eo->d_extFlags=0;
   if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
     for(const MOADNSParser::answers_t::value_type& val :  mdp.d_answers) {
-      if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) {
-        eo->d_packetsize=val.first.d_class;
+      if(val.d_place == DNSResourceRecord::ADDITIONAL && val.d_type == QType::OPT) {
+        eo->d_packetsize=val.d_class;
 
         EDNS0Record stuff;
-        uint32_t ttl=ntohl(val.first.d_ttl);
+        uint32_t ttl=ntohl(val.d_ttl);
         static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
         memcpy(&stuff, &ttl, sizeof(stuff));
 
         eo->d_extRCode=stuff.extRCode;
         eo->d_version=stuff.version;
         eo->d_extFlags = ntohs(stuff.extFlags);
-        auto orc = getRR<OPTRecordContent>(val.first);
+        auto orc = getRR<OPTRecordContent>(val);
         if(orc == nullptr)
           return false;
         orc->getData(eo->d_options);
index 36f0db835b4f25df50c4ca13992cdd2c9509ffef..d7a87d1c1856df94430551fb9b9c1c5b30d3178a 100644 (file)
@@ -241,9 +241,11 @@ static void WeOrigSlowQueriesDelta(int& weOutstanding, int& origOutstanding, int
 
 static void compactAnswerSet(MOADNSParser::answers_t orig, set<DNSRecord>& compacted)
 {
-  for(MOADNSParser::answers_t::const_iterator i=orig.begin(); i != orig.end(); ++i)
-    if(i->first.d_place==DNSResourceRecord::ANSWER)
-      compacted.insert(i->first);
+  for (const auto& rec : orig) {
+    if (rec.d_place == DNSResourceRecord::ANSWER) {
+      compacted.insert(rec);
+    }
+  }
 }
 
 static bool isRcodeOk(int rcode)
@@ -260,11 +262,13 @@ static bool isRootReferral(const MOADNSParser::answers_t& answers)
 
   bool ok=true;
   for(MOADNSParser::answers_t::const_iterator iter = answers.begin(); iter != answers.end(); ++iter) {
-    //    cerr<<(int)iter->first.d_place<<", "<<iter->first.d_name<<" "<<iter->first.d_type<<", # "<<answers.size()<<endl;
-    if(iter->first.d_place!=2)
-      ok=false;
-    if(!iter->first.d_name.isRoot() || iter->first.d_type!=QType::NS)
-      ok=false;
+    //    cerr<<(int)iter->d_place<<", "<<iter->d_name<<" "<<iter->d_type<<", # "<<answers.size()<<endl;
+    if (iter->d_place != 2) {
+      ok = false;
+    }
+    if (!iter->d_name.isRoot() || iter->d_type != QType::NS) {
+      ok = false;
+    }
   }
   return ok;
 }
index 9322c392bfd7f695d4b465a267b9cf670f1bf8e3..3495034bf01dc3e6329611e6c4ff970afc2f8e41 100644 (file)
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-#ifdef HAVE_BOOST_GE_148
-#include "histog.hh"
-#endif
 
+#include "histog.hh"
 #include "statbag.hh"
 #include "dnspcap.hh"
 #include "dnsparser.hh"
@@ -139,10 +137,8 @@ try
     ("rd", po::value<bool>(), "If set to true, only process RD packets, to false only non-RD, unset: both")
     ("ipv4", po::value<bool>()->default_value(true), "Process IPv4 packets")
     ("ipv6", po::value<bool>()->default_value(true), "Process IPv6 packets")
-#ifdef HAVE_BOOST_GE_148
     ("log-histogram", "Write a log-histogram to file 'log-histogram'")
     ("full-histogram", po::value<double>(), "Write a log-histogram to file 'full-histogram' with this millisecond bin size")
-#endif
     ("filter-name,f", po::value<string>(), "Do statistics only for queries within this domain")
     ("load-stats,l", po::value<string>()->default_value(""), "if set, emit per-second load statistics (questions, answers, outstanding)")
     ("no-servfail-stats", "Don't include servfails in response time stats")
@@ -472,7 +468,6 @@ try
   cout.precision(4);
   sum=0;
 
-#ifdef HAVE_BOOST_GE_148
   if(g_vm.count("log-histogram")) {
     string fname = g_vm["stats-dir"].as<string>()+"/log-histogram";
     ofstream loglog(fname);
@@ -489,8 +484,6 @@ try
       throw runtime_error("Unable to write statistics to "+fname);
     writeFullHistogramFile(cumul, g_vm["full-histogram"].as<double>(), loglog);
   }
-#endif
-
 
   sum=0;
   double lastperc=0, perc=0;
index 9614ee1373d0e0cf3f1de8d48bd39bfb8ea1cdd5..32b565d75668fccb3a56b6c7e9759ee75e1e0d24 100644 (file)
@@ -21,6 +21,7 @@
  */
 #pragma once
 #include "dnsrecords.hh"
+#include "dnspacket.hh"
 
 #include <string>
 #include <vector>
@@ -291,7 +292,7 @@ string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const
 void incrementHash(std::string& raw);
 void decrementHash(std::string& raw);
 
-void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authMap, vector<DNSZoneRecord>& rrs);
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authSet, vector<DNSZoneRecord>& rrs, DNSPacket* packet=nullptr);
 
 void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
 bool validateTSIG(const std::string& packet, size_t sigPos, const TSIGTriplet& tt, const TSIGRecordContent& trc, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly, unsigned int dnsHeaderOffset=0);
index 50e81bbb1522bdd781218c77fcdf4276469d31d5..04727305ee74043556e07915db32640683fb629b 100644 (file)
@@ -31,6 +31,7 @@
 #include <boost/multi_index/sequenced_index.hpp>
 #include "dnssecinfra.hh"
 #include "dnsrecords.hh"
+#include "dnspacket.hh"
 #include "ueberbackend.hh"
 #include "lock.hh"
 
@@ -208,7 +209,7 @@ public:
   bool checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg);
   bool setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& n3p, const bool& narrow=false);
   bool unsetNSEC3PARAM(const DNSName& zname);
-  void getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL);
+  void getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL, DNSPacket* p=nullptr);
   bool isPresigned(const DNSName& zname, bool useCache=true);
   bool setPresigned(const DNSName& zname);
   bool unsetPresigned(const DNSName& zname);
@@ -303,7 +304,6 @@ private:
   static size_t s_maxEntries;
 };
 
-class DNSPacket;
 uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq);
 // for SOA-EDIT
 uint32_t calculateEditSOA(uint32_t old_serial, DNSSECKeeper& dk, const DNSName& zonename);
index e7fd007ffc0510f8cb5c07f7504c5f74573d3294..0e122c11a3192d3ba534119b7693ff007743895b 100644 (file)
@@ -145,7 +145,7 @@ static int getRRSIGsForRRSET(DNSSECKeeper& dk, const DNSName& signer, const DNSN
 // this is the entrypoint from DNSPacket
 static void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& signer, const DNSName& signQName, const DNSName& wildcardname, uint16_t signQType,
                          uint32_t signTTL, DNSResourceRecord::Place signPlace,
-                         sortedRecords_t& toSign, vector<DNSZoneRecord>& outsigned, uint32_t origTTL)
+                         sortedRecords_t& toSign, vector<DNSZoneRecord>& outsigned, uint32_t origTTL, DNSPacket* packet)
 {
   //cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
   if(toSign.empty())
@@ -153,7 +153,7 @@ static void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& sign
   vector<RRSIGRecordContent> rrcs;
   if(dk.isPresigned(signer)) {
     //cerr<<"Doing presignatures"<<endl;
-    dk.getPreRRSIGs(db, outsigned, origTTL); // does it all
+    dk.getPreRRSIGs(db, outsigned, origTTL, packet); // does it all
   }
   else {
     if(getRRSIGsForRRSET(dk, signer, wildcardname.countLabels() ? wildcardname : signQName, signQType, signTTL, toSign, rrcs) < 0)  {
@@ -203,7 +203,7 @@ static bool getBestAuthFromSet(const set<DNSName>& authSet, const DNSName& name,
   return false;
 }
 
-void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSZoneRecord>& rrs)
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSZoneRecord>& rrs, DNSPacket* packet)
 {
   stable_sort(rrs.begin(), rrs.end(), rrsigncomp);
 
@@ -222,7 +222,7 @@ void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet,
   for(auto pos = rrs.cbegin(); pos != rrs.cend(); ++pos) {
     if(pos != rrs.cbegin() && (signQType != pos->dr.d_type  || signQName != pos->dr.d_name)) {
       if (getBestAuthFromSet(authSet, authQName, signer))
-        addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+        addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL, packet);
     }
     signedRecords.push_back(*pos);
     signQName = pos->dr.d_name.makeLowerCase();
@@ -248,6 +248,6 @@ void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet,
     }
   }
   if (getBestAuthFromSet(authSet, authQName, signer))
-    addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+    addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL, packet);
   rrs.swap(signedRecords);
 }
index cc6f32516f9f9afff23cef8c229d56c4473ab191..67ed5c57d12f083bf71ccc0cd7120b88357b77f7 100644 (file)
@@ -217,11 +217,8 @@ template <typename Container> uint16_t GenericDNSPacketWriter<Container>::lookup
   */
   unsigned int bestpos=0;
   *matchLen=0;
-#if BOOST_VERSION >= 105400
-  boost::container::static_vector<uint16_t, 34> nvect, pvect;
-#else
-  vector<uint16_t> nvect, pvect;
-#endif
+  boost::container::static_vector<uint16_t, 34> nvect;
+  boost::container::static_vector<uint16_t, 34> pvect;
 
   try {
     for(auto riter= raw.cbegin(); riter < raw.cend(); ) {
index 25c49521b7e3fe84d9041bce32ccfa58ebeebdfb..2552db568439fd92be1be17cc8f512c2234e9ec5 100644 (file)
@@ -46,7 +46,7 @@
           errlog("Unable to bind to %s: %s", ca.toStringWithPort(), strerr(errno));
 
    Will log to stdout. Will syslog in any case with LOG_INFO,
-   LOG_WARNING, LOG_ERR respectively. If g_verbose=false, vinfolog is a noop.
+   LOG_WARNING, LOG_ERR respectively. If verbose=false, vinfolog is a noop.
    More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
 
    This will happily print a string to %d! Doesn't do further format processing.
@@ -81,9 +81,6 @@ void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
 }
 
 #if !defined(RECURSOR)
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-extern bool g_verbose;
-
 #ifdef DNSDIST
 namespace dnsdist::logging
 {
@@ -96,10 +93,6 @@ public:
     ISO8601
   };
 
-  static void setVerbose(bool value = true)
-  {
-    g_verbose = value;
-  }
   static void setSyslog(bool value = true)
   {
     s_syslog = value;
@@ -123,10 +116,6 @@ public:
   {
     s_verboseStream = std::move(stream);
   }
-  static bool getVerbose()
-  {
-    return g_verbose;
-  }
   static bool getSyslog()
   {
     return s_syslog;
@@ -235,9 +224,16 @@ void verboselog(const char* formatStr, const Args&... args)
 #endif /* DNSDIST */
 }
 
-#define vinfolog \
-  if (g_verbose) \
+#ifdef DNSDIST
+#include "dnsdist-configuration.hh"
+
+#define vinfolog                                                          \
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) \
   verboselog
+#else
+#define vinfolog \
+  infolog
+#endif
 
 template <typename... Args>
 void infolog(const char* formatStr, const Args&... args)
@@ -258,9 +254,8 @@ void errlog(const char* formatStr, const Args&... args)
 }
 
 #else // RECURSOR
-#define g_verbose 0
 #define vinfolog \
-  if (g_verbose) \
+  if (false)     \
   infolog
 
 template <typename... Args>
index 7c839e7b19d61e71e24298d89d79555e7b566940..9e224790fd67cd38dca09766e84e115c2ebcd51e 100644 (file)
@@ -170,7 +170,7 @@ RemoteLoggerInterface::Result FrameStreamLogger::queueData(const std::string& da
   }
   uint8_t* frame = (uint8_t*)malloc(data.length()); // NOLINT: it's the API
   if (frame == nullptr) {
-    ++d_queueFullDrops; // XXX separate count?
+    ++d_tooLargeCount;
     return Result::TooLarge;
   }
   memcpy(frame, data.c_str(), data.length());
index 711c65a17189388daa39006b9b1f55a946840c42..44657247d86aafc16e362b100c709e08c611f932 100644 (file)
@@ -63,7 +63,7 @@ public:
   {
     return Stats{.d_queued = d_framesSent,
                  .d_pipeFull = d_queueFullDrops,
-                 .d_tooLarge = 0,
+                 .d_tooLarge = d_tooLargeCount,
                  .d_otherError = d_permanentFailures};
   }
 
@@ -81,6 +81,7 @@ private:
   struct fstrm_iothr* d_iothr{nullptr};
   std::atomic<uint64_t> d_framesSent{0};
   std::atomic<uint64_t> d_queueFullDrops{0};
+  std::atomic<uint64_t> d_tooLargeCount{0};
   std::atomic<uint64_t> d_permanentFailures{0};
 
   void cleanup();
index ba088b6e4ef4ba747a182c7bb202adda2d9fde21..714bbe5ac89df08a82df9299d08b5fcef88ad0a9 100644 (file)
@@ -890,23 +890,34 @@ private:
 
       // create new tree node for the new key and
       // attach the new node under our former parent
-      auto new_child = make_unique<TreeNode>(key);
-      auto* new_node = new_child.get();
-      new_node->d_bits = bits;
-      std::swap(parent_ref, new_child); // hereafter new_child points to "this"
-      new_node->parent = parent;
+      auto new_intermediate_node = make_unique<TreeNode>(key);
+      new_intermediate_node->d_bits = bits;
+      new_intermediate_node->parent = parent;
+      auto* new_intermediate_node_raw = new_intermediate_node.get();
+
+      // hereafter new_intermediate points to "this"
+      // ie the child of the new intermediate node
+      std::swap(parent_ref, new_intermediate_node);
+      // and we now assign this to current_node so
+      // it's clear it no longer refers to the new
+      // intermediate node
+      std::unique_ptr<TreeNode> current_node = std::move(new_intermediate_node);
 
       // attach "this" node below the new node
       // (left or right depending on bit)
-      new_child->parent = new_node;
-      if (new_child->node.first.getBit(-1 - bits)) {
-        std::swap(new_node->right, new_child);
+      // technically the raw pointer escapes the duration of the
+      // unique pointer, but just below we store the unique pointer
+      // in the parent, so it lives as long as necessary
+      // coverity[escape]
+      current_node->parent = new_intermediate_node_raw;
+      if (current_node->node.first.getBit(-1 - bits)) {
+        new_intermediate_node_raw->right = std::move(current_node);
       }
       else {
-        std::swap(new_node->left, new_child);
+        new_intermediate_node_raw->left = std::move(current_node);
       }
 
-      return new_node;
+      return new_intermediate_node_raw;
     }
 
     //<! Forks branch for new key at indicated bit position
@@ -1697,7 +1708,7 @@ public:
 
     uint16_t port = d_addr.getPort();
     if (d_portMask < 16) {
-      uint16_t mask = ~(0xFFFF >> d_portMask);
+      auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
       port = port & mask;
     }
 
index ac041cb0090566925727072a9d1ecba659ff43a9..09d5d9a9f21585aa91506daa38e20b4bd2fa62a9 100644 (file)
@@ -259,40 +259,37 @@ vector<pair<vector<DNSRecord>, vector<DNSRecord>>> getIXFRDeltas(const ComboAddr
     for (auto& r: mdp.d_answers) {
       if(!primarySOA) {
         // we have not seen the first SOA record yet
-        if (r.first.d_type != QType::SOA) {
-          throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"' is not a SOA ("+QType(r.first.d_type).toString()+")");
+        if (r.d_type != QType::SOA) {
+          throw std::runtime_error("The first record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"' is not a SOA ("+QType(r.d_type).toString()+")");
         }
 
-        auto sr = getRR<SOARecordContent>(r.first);
-        if (!sr) {
+        auto soaRecord = getRR<SOARecordContent>(r);
+        if (!soaRecord) {
           throw std::runtime_error("Error getting the content of the first SOA record of the IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
         }
 
-        if(sr->d_st.serial == getRR<SOARecordContent>(oursr)->d_st.serial) {
+        if(soaRecord->d_st.serial == getRR<SOARecordContent>(oursr)->d_st.serial) {
           // we are up to date
           return ret;
         }
-        primarySOA = std::move(sr);
+        primarySOA = std::move(soaRecord);
         ++primarySOACount;
-      } else if (r.first.d_type == QType::SOA) {
-        auto sr = getRR<SOARecordContent>(r.first);
-        if (!sr) {
+      } else if (r.d_type == QType::SOA) {
+        auto soaRecord = getRR<SOARecordContent>(r);
+        if (!soaRecord) {
           throw std::runtime_error("Error getting the content of SOA record of IXFR answer for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort()+"'");
         }
 
         // we hit a marker SOA record
-        if (primarySOA->d_st.serial == sr->d_st.serial) {
+        if (primarySOA->d_st.serial == soaRecord->d_st.serial) {
           ++primarySOACount;
         }
       }
       // When we see the 2nd record, we can decide what the style is
       if (records.size() == 1 && style == Unknown) {
-        if (r.first.d_type != QType::SOA) {
-          // Non-empty AXFR style has a non-SOA record following the first SOA
-          style = AXFR;
-        }
-        else if (primarySOACount == expectedSOAForAXFR) {
-          // Empty zone AXFR style: start SOA is immediately followed by end marker SOA
+        if (r.d_type != QType::SOA || primarySOACount == expectedSOAForAXFR) {
+          // 1. Non-empty AXFR style has a non-SOA record following the first SOA
+          // 2. Empty zone AXFR style: start SOA is immediately followed by end marker SOA
           style = AXFR;
         }
         else {
@@ -301,18 +298,20 @@ vector<pair<vector<DNSRecord>, vector<DNSRecord>>> getIXFRDeltas(const ComboAddr
         }
       }
 
-      if(r.first.d_place != DNSResourceRecord::ANSWER) {
-        if(r.first.d_type == QType::TSIG)
+      if(r.d_place != DNSResourceRecord::ANSWER) {
+        if (r.d_type == QType::TSIG) {
           continue;
+        }
 
-        if(r.first.d_type == QType::OPT)
+        if (r.d_type == QType::OPT) {
           continue;
+        }
 
-        throw std::runtime_error("Unexpected record (" +QType(r.first.d_type).toString()+") in non-answer section ("+std::to_string(r.first.d_place)+") in IXFR response for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort());
+        throw std::runtime_error("Unexpected record (" +QType(r.d_type).toString()+") in non-answer section ("+std::to_string(r.d_place)+") in IXFR response for zone '"+zone.toLogString()+"' from primary '"+primary.toStringWithPort());
       }
 
-      r.first.d_name.makeUsRelative(zone);
-      records.push_back(r.first);
+      r.d_name.makeUsRelative(zone);
+      records.push_back(r);
     }
   }
 
index 9cebccded5faf871172180b5cfb3023410c73744..61eb200ef10a9e7c686f13ab6beb8bbe27f343fc 100644 (file)
@@ -1224,8 +1224,8 @@ static void tcpWorker(int tid) {
         for (auto &answer : mdp.d_answers) {
           // from dnsparser.hh:
           // typedef vector<pair<DNSRecord, uint16_t > > answers_t;
-          if (answer.first.d_type == QType::SOA && answer.first.d_place == DNSResourceRecord::AUTHORITY) {
-            clientSOA = getRR<SOARecordContent>(answer.first);
+          if (answer.d_type == QType::SOA && answer.d_place == DNSResourceRecord::AUTHORITY) {
+            clientSOA = getRR<SOARecordContent>(answer);
             if (clientSOA != nullptr) {
               break;
             }
@@ -1647,15 +1647,16 @@ static std::optional<IXFRDistConfiguration> parseConfiguration(int argc, char**
     }
 
     if (config["gid"].IsDefined()) {
+      bool gidParsed = false;
       auto gid = config["gid"].as<string>();
       try {
         configuration.gid = pdns::checked_stoi<gid_t>(gid);
+        gidParsed = true;
       }
       catch (const std::exception& e) {
-        g_log<<Logger::Error<<"Can not parse gid "<<gid<<endl;
-        had_error = true;
+        configuration.gid = 0;
       }
-      if (configuration.gid != 0) {
+      if (!gidParsed) {
         //NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
         const struct group *gr = getgrnam(gid.c_str());
         if (gr == nullptr) {
@@ -1696,15 +1697,16 @@ static std::optional<IXFRDistConfiguration> parseConfiguration(int argc, char**
     }
 
     if (config["uid"].IsDefined()) {
+      bool uidParsed = false;
       auto uid = config["uid"].as<string>();
       try {
         configuration.uid = pdns::checked_stoi<uid_t>(uid);
+        uidParsed = true;
       }
       catch (const std::exception& e) {
-        g_log<<Logger::Error<<"Can not parse uid "<<uid<<endl;
-        had_error = true;
+        configuration.uid = 0;
       }
-      if (configuration.uid != 0) {
+      if (!uidParsed) {
         //NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
         const struct passwd *pw = getpwnam(uid.c_str());
         if (pw == nullptr) {
@@ -1712,8 +1714,11 @@ static std::optional<IXFRDistConfiguration> parseConfiguration(int argc, char**
           had_error = true;
         } else {
           configuration.uid = pw->pw_uid;
+          uidParsed = true;
         }
         //NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+      }
+      if (uidParsed) {
         configuration.userInfo = getpwuid(configuration.uid);
       }
     }
@@ -1799,11 +1804,6 @@ int main(int argc, char** argv) {
     }
 
     if (configuration->uid != 0) {
-      g_log<<Logger::Notice<<"Dropping effective user-id to "<<configuration->uid<<endl;
-      if (setuid(configuration->uid) < 0) {
-        g_log<<Logger::Error<<"Could not set user id to "<<configuration->uid<<": "<<stringerror()<<endl;
-        had_error = true;
-      }
       if (configuration->userInfo == nullptr) {
         if (setgroups(0, nullptr) < 0) {
           g_log<<Logger::Error<<"Unable to drop supplementary gids: "<<stringerror()<<endl;
@@ -1815,6 +1815,12 @@ int main(int argc, char** argv) {
           had_error = true;
         }
       }
+
+      g_log<<Logger::Notice<<"Dropping effective user-id to "<<configuration->uid<<endl;
+      if (setuid(configuration->uid) < 0) {
+        g_log<<Logger::Error<<"Could not set user id to "<<configuration->uid<<": "<<stringerror()<<endl;
+        had_error = true;
+      }
     }
 
     if (had_error) {
index 40b6b2495d7465caf4b4f863160a20b729d30d0e..53e18313531d4e04c3986988cd5337b257e7f58d 100644 (file)
@@ -53,8 +53,8 @@ uint32_t getSerialFromPrimary(const ComboAddress& primary, const DNSName& zone,
   string reply;
   reply.resize(4096);
   // will throw a NetworkError on timeout
-  ssize_t got = s.readWithTimeout(&reply[0], reply.size(), timeout);
-  if (got < 0 || static_cast<size_t>(got) < sizeof(dnsheader)) {
+  size_t got = s.readWithTimeout(reply.data(), reply.size(), timeout);
+  if (got < sizeof(dnsheader)) {
     throw std::runtime_error("Invalid response size " + std::to_string(got));
   }
 
@@ -65,8 +65,8 @@ uint32_t getSerialFromPrimary(const ComboAddress& primary, const DNSName& zone,
     throw std::runtime_error("RCODE from response is not NoError but " + RCode::to_s(mdp.d_header.rcode));
   }
   for(const auto& r: mdp.d_answers) {
-    if(r.first.d_type == QType::SOA) {
-      sr = getRR<SOARecordContent>(r.first);
+    if(r.d_type == QType::SOA) {
+      sr = getRR<SOARecordContent>(r);
       if(sr != nullptr) {
         return sr->d_st.serial;
       }
index ddb638cf18b40096fcfa454965a39917e7f48dc6..0faeba0eb26b41d2801a62baeaebd6d42a4d8f4e 100644 (file)
     "default": {
         "certifi": {
             "hashes": [
-                "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
-                "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
+                "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b",
+                "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"
             ],
             "index": "pypi",
             "markers": "python_version >= '3.6'",
-            "version": "==2023.7.22"
+            "version": "==2024.7.4"
         },
         "charset-normalizer": {
             "hashes": [
         },
         "urllib3": {
             "hashes": [
-                "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07",
-                "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"
+                "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3",
+                "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"
             ],
             "index": "pypi",
             "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
-            "version": "==1.26.18"
+            "version": "==1.26.19"
         }
     },
     "develop": {}
index 2c08edbbf99dab55f5c96d2328d52569261fafd8..0e0d15888a10b34782ac9dcf1e6bfea5bee39997 100644 (file)
@@ -88,7 +88,7 @@ Zone configuration is attached as a meta data with the key `X-PDNSKEYROLLER-CONF
 
 * `version` : this json format version identifier
 * `key_style` : `single` or `split` depending on the number of keys
-* `xsk_algo` : algorithm to roll as name or number, see bellow
+* `xsk_algo` : algorithm to roll as name or number, see below
 * `xsk_frequency` : the rate at which to roll the keys
 * `xsk_keysize` : keysize in bits
 * `xsk_method` : strategy for the rollover (for now, only `prepublish` is supported)
index 3f657326c432af1e6ab2190027be8ae31b5e331c..c81127c1ff466b704c9cc9ff401a67e002f51e89 100644 (file)
@@ -1,4 +1,3 @@
-
 #include "config.h"
 #include "libssl.hh"
 
 #include <pthread.h>
 
 #include <openssl/conf.h>
+#if defined(DNSDIST) && (OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS))
 #ifndef OPENSSL_NO_ENGINE
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage): used by the preprocessor below
+#define DNSDIST_ENABLE_LIBSSL_ENGINE 1
 #include <openssl/engine.h>
 #endif
+#endif
 #include <openssl/err.h>
 #ifndef DISABLE_OCSP_STAPLING
 #include <openssl/ocsp.h>
@@ -42,6 +45,7 @@
 
 #undef CERT
 #include "misc.hh"
+#include "tcpiohandler.hh"
 
 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL)
 /* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
@@ -86,7 +90,7 @@ static std::atomic<uint64_t> s_users;
 #if OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
 static LockGuarded<std::unordered_map<std::string, std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>>> s_providers;
 #else
-#ifndef OPENSSL_NO_ENGINE
+#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
 static LockGuarded<std::unordered_map<std::string, std::unique_ptr<ENGINE, decltype(&ENGINE_free)>>> s_engines;
 #endif
 #endif
@@ -152,15 +156,13 @@ void registerOpenSSLUser()
 void unregisterOpenSSLUser()
 {
   if (s_users.fetch_sub(1) == 1) {
-#if OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS)
-#ifndef OPENSSL_NO_ENGINE
+#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
     for (auto& [name, engine] : *s_engines.lock()) {
       ENGINE_finish(engine.get());
       engine.reset();
     }
     s_engines.lock()->clear();
-#endif
-#endif
+#endif /* PDNS_ENABLE_LIBSSL_ENGINE */
 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL))
     ERR_free_strings();
 
@@ -201,12 +203,14 @@ std::pair<bool, std::string> libssl_load_provider(const std::string& providerNam
 }
 #endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
 
-#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
+#if defined(HAVE_LIBSSL) && !HAVE_TLS_PROVIDERS
 std::pair<bool, std::string> libssl_load_engine([[maybe_unused]] const std::string& engineName, [[maybe_unused]] const std::optional<std::string>& defaultString)
 {
-#ifdef OPENSSL_NO_ENGINE
+#if defined(OPENSSL_NO_ENGINE)
   return { false, "OpenSSL has been built without engine support" };
-#else
+#elif !defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
+  return { false, "SSL engine support not enabled" };
+#else /* DNSDIST_ENABLE_LIBSSL_ENGINE */
   if (s_users.load() == 0) {
     /* We need to make sure that OpenSSL has been properly initialized before loading an engine.
        This messes up our accounting a bit, so some memory might not be properly released when
@@ -236,7 +240,7 @@ std::pair<bool, std::string> libssl_load_engine([[maybe_unused]] const std::stri
 
   engines->insert({engineName, std::move(engine)});
   return { true, "" };
-#endif
+#endif /* DNSDIST_ENABLE_LIBSSL_ENGINE */
 }
 #endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
 
@@ -631,6 +635,13 @@ OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() = default;
 void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
 {
   d_ticketKeys.write_lock()->push_front(std::move(newKey));
+  if (TLSCtx::hasTicketsKeyAddedHook()) {
+    auto key = d_ticketKeys.read_lock()->front();
+    auto keyContent = key->content();
+    TLSCtx::getTicketsKeyAddedHook()(keyContent);
+    // fills mem with 0's
+    OPENSSL_cleanse(keyContent.data(), keyContent.size());
+  }
 }
 
 std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
@@ -737,6 +748,19 @@ bool OpenSSLTLSTicketKey::nameMatches(const unsigned char name[TLS_TICKETS_KEY_N
   return (memcmp(d_name, name, sizeof(d_name)) == 0);
 }
 
+std::string OpenSSLTLSTicketKey::content() const
+{
+  std::string result{};
+  result.reserve(TLS_TICKETS_KEY_NAME_SIZE + TLS_TICKETS_CIPHER_KEY_SIZE + TLS_TICKETS_MAC_KEY_SIZE);
+  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
+  result.append(reinterpret_cast<const char*>(d_name), TLS_TICKETS_KEY_NAME_SIZE);
+  result.append(reinterpret_cast<const char*>(d_cipherKey), TLS_TICKETS_CIPHER_KEY_SIZE);
+  result.append(reinterpret_cast<const char*>(d_hmacKey), TLS_TICKETS_MAC_KEY_SIZE);
+  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
+
+  return result;
+}
+
 #if OPENSSL_VERSION_MAJOR >= 3
 static const std::string sha256KeyName{"sha256"};
 #endif
@@ -1067,16 +1091,7 @@ pdns::UniqueFilePtr libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&S
 #endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
 }
 
-/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
-void libssl_set_npn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg)
-{
-#ifdef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB
-  SSL_CTX_set_next_proto_select_cb(ctx, cb, arg);
-#endif
-}
-#endif /* DISABLE_NPN */
-
+/* called in a client context, if the client advertised more than one ALPN value and the server returned more than one as well, to select the one to use. */
 void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg)
 {
 #ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
index 8dd7ff373bf6b49546a225655239ff39aa3567c7..96f6dd9a6b1a5cd05eb47547a49461f0abbaeae4 100644 (file)
@@ -105,6 +105,8 @@ public:
   bool decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const;
 #endif
 
+  [[nodiscard]] std::string content() const;
+
 private:
   unsigned char d_name[TLS_TICKETS_KEY_NAME_SIZE];
   unsigned char d_cipherKey[TLS_TICKETS_CIPHER_KEY_SIZE];
@@ -124,7 +126,6 @@ public:
 
 private:
   void addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey);
-
   SharedLockGuarded<boost::circular_buffer<std::shared_ptr<OpenSSLTLSTicketKey> > > d_ticketKeys;
 };
 
@@ -157,11 +158,6 @@ std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::st
 
 pdns::UniqueFilePtr libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile);
 
-/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
-void libssl_set_npn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg);
-#endif /* DISABLE_NPN */
-
 /* called in a server context, to select an ALPN value advertised by the client if any */
 void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg);
 /* set the supported ALPN protos in client context */
index 611d8ada02a7cecac3956c7488fc602a174dee19..254c2f87b999e5573efc72ef4801774deb02ce83 100644 (file)
@@ -82,9 +82,11 @@ class ReadWriteLock
 {
 public:
   ReadWriteLock() = default;
+  ~ReadWriteLock() = default;
 
   ReadWriteLock(const ReadWriteLock& rhs) = delete;
   ReadWriteLock(ReadWriteLock&& rhs) = delete;
+  ReadWriteLock& operator=(ReadWriteLock&&) = delete;
   ReadWriteLock& operator=(const ReadWriteLock& rhs) = delete;
 
   std::shared_mutex& getLock()
@@ -99,23 +101,29 @@ private:
 class ReadLock
 {
 public:
-  ReadLock(ReadWriteLock& lock): ReadLock(lock.getLock())
+  ReadLock(ReadWriteLock& lock) :
+    ReadLock(lock.getLock())
   {
   }
 
-  ReadLock(ReadWriteLock* lock): ReadLock(lock->getLock())
+  ReadLock(ReadWriteLock* lock) :
+    ReadLock(lock->getLock())
   {
   }
 
+  ~ReadLock() = default;
   ReadLock(const ReadLock& rhs) = delete;
   ReadLock& operator=(const ReadLock& rhs) = delete;
+  ReadLock& operator=(ReadLock&&) = delete;
+
   ReadLock(ReadLock&& rhs) noexcept :
     d_lock(std::move(rhs.d_lock))
   {
   }
 
 private:
-  ReadLock(std::shared_mutex& lock) : d_lock(lock)
+  ReadLock(std::shared_mutex& lock) :
+    d_lock(lock)
   {
   }
 
@@ -125,23 +133,29 @@ private:
 class WriteLock
 {
 public:
-  WriteLock(ReadWriteLock& lock): WriteLock(lock.getLock())
+  WriteLock(ReadWriteLock& lock) :
+    WriteLock(lock.getLock())
   {
   }
 
-  WriteLock(ReadWriteLock* lock): WriteLock(lock->getLock())
+  WriteLock(ReadWriteLock* lock) :
+    WriteLock(lock->getLock())
   {
   }
 
+  ~WriteLock() = default;
   WriteLock(const WriteLock& rhs) = delete;
   WriteLock& operator=(const WriteLock& rhs) = delete;
+  WriteLock& operator=(WriteLock&&) = delete;
+
   WriteLock(WriteLock&& rhs) noexcept :
     d_lock(std::move(rhs.d_lock))
   {
   }
 
 private:
-  WriteLock(std::shared_mutex& lock) : d_lock(lock)
+  WriteLock(std::shared_mutex& lock) :
+    d_lock(lock)
   {
   }
 
@@ -151,24 +165,30 @@ private:
 class TryReadLock
 {
 public:
-  TryReadLock(ReadWriteLock& lock): TryReadLock(lock.getLock())
+  TryReadLock(ReadWriteLock& lock) :
+    TryReadLock(lock.getLock())
   {
   }
 
-  TryReadLock(ReadWriteLock* lock): TryReadLock(lock->getLock())
+  TryReadLock(ReadWriteLock* lock) :
+    TryReadLock(lock->getLock())
   {
   }
 
+  ~TryReadLock() = default;
   TryReadLock(const TryReadLock& rhs) = delete;
+  TryReadLock(TryReadLock&&) = delete;
   TryReadLock& operator=(const TryReadLock& rhs) = delete;
+  TryReadLock& operator=(TryReadLock&&) = delete;
 
-  bool gotIt() const
+  [[nodiscard]] bool gotIt() const
   {
     return d_lock.owns_lock();
   }
 
 private:
-  TryReadLock(std::shared_mutex& lock) : d_lock(lock, std::try_to_lock)
+  TryReadLock(std::shared_mutex& lock) :
+    d_lock(lock, std::try_to_lock)
   {
   }
 
@@ -178,24 +198,30 @@ private:
 class TryWriteLock
 {
 public:
-  TryWriteLock(ReadWriteLock& lock): TryWriteLock(lock.getLock())
+  TryWriteLock(ReadWriteLock& lock) :
+    TryWriteLock(lock.getLock())
   {
   }
 
-  TryWriteLock(ReadWriteLock* lock): TryWriteLock(lock->getLock())
+  TryWriteLock(ReadWriteLock* lock) :
+    TryWriteLock(lock->getLock())
   {
   }
 
+  ~TryWriteLock() = default;
   TryWriteLock(const TryWriteLock& rhs) = delete;
+  TryWriteLock(TryWriteLock&&) = delete;
   TryWriteLock& operator=(const TryWriteLock& rhs) = delete;
+  TryWriteLock& operator=(TryWriteLock&&) = delete;
 
-  bool gotIt() const
+  [[nodiscard]] bool gotIt() const
   {
     return d_lock.owns_lock();
   }
 
 private:
-  TryWriteLock(std::shared_mutex& lock) : d_lock(lock, std::try_to_lock)
+  TryWriteLock(std::shared_mutex& lock) :
+    d_lock(lock, std::try_to_lock)
   {
   }
 
@@ -206,15 +232,18 @@ template <typename T>
 class LockGuardedHolder
 {
 public:
-  explicit LockGuardedHolder(T& value, std::mutex& mutex): d_lock(mutex), d_value(value)
+  explicit LockGuardedHolder(T& value, std::mutex& mutex) :
+    d_lock(mutex), d_value(value)
   {
   }
 
-  T& operator*() const noexcept {
+  T& operator*() const noexcept
+  {
     return d_value;
   }
 
-  T* operator->() const noexcept {
+  T* operator->() const noexcept
+  {
     return &d_value;
   }
 
@@ -227,29 +256,34 @@ template <typename T>
 class LockGuardedTryHolder
 {
 public:
-  explicit LockGuardedTryHolder(T& value, std::mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+  explicit LockGuardedTryHolder(T& value, std::mutex& mutex) :
+    d_lock(mutex, std::try_to_lock), d_value(value)
   {
   }
 
-  T& operator*() const {
+  T& operator*() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return d_value;
   }
 
-  T* operator->() const {
+  T* operator->() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return &d_value;
   }
 
-  operator bool() const noexcept {
+  operator bool() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
-  bool owns_lock() const noexcept {
+  [[nodiscard]] bool owns_lock() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
@@ -267,11 +301,13 @@ template <typename T>
 class LockGuarded
 {
 public:
-  explicit LockGuarded(const T& value): d_value(value)
+  explicit LockGuarded(const T& value) :
+    d_value(value)
   {
   }
 
-  explicit LockGuarded(T&& value): d_value(std::move(value))
+  explicit LockGuarded(T&& value) :
+    d_value(std::move(value))
   {
   }
 
@@ -297,19 +333,127 @@ private:
   T d_value;
 };
 
+template <typename T>
+class RecursiveLockGuardedHolder
+{
+public:
+  explicit RecursiveLockGuardedHolder(T& value, std::recursive_mutex& mutex) :
+    d_lock(mutex), d_value(value)
+  {
+  }
+
+  T& operator*() const noexcept
+  {
+    return d_value;
+  }
+
+  T* operator->() const noexcept
+  {
+    return &d_value;
+  }
+
+private:
+  std::lock_guard<std::recursive_mutex> d_lock;
+  T& d_value;
+};
+
+template <typename T>
+class RecursiveLockGuardedTryHolder
+{
+public:
+  explicit RecursiveLockGuardedTryHolder(T& value, std::recursive_mutex& mutex) :
+    d_lock(mutex, std::try_to_lock), d_value(value)
+  {
+  }
+
+  T& operator*() const
+  {
+    if (!owns_lock()) {
+      throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
+    }
+    return d_value;
+  }
+
+  T* operator->() const
+  {
+    if (!owns_lock()) {
+      throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
+    }
+    return &d_value;
+  }
+
+  operator bool() const noexcept
+  {
+    return d_lock.owns_lock();
+  }
+
+  [[nodiscard]] bool owns_lock() const noexcept
+  {
+    return d_lock.owns_lock();
+  }
+
+  void lock()
+  {
+    d_lock.lock();
+  }
+
+private:
+  std::unique_lock<std::recursive_mutex> d_lock;
+  T& d_value;
+};
+
+template <typename T>
+class RecursiveLockGuarded
+{
+public:
+  explicit RecursiveLockGuarded(const T& value) :
+    d_value(value)
+  {
+  }
+
+  explicit RecursiveLockGuarded(T&& value) :
+    d_value(std::move(value))
+  {
+  }
+
+  explicit RecursiveLockGuarded() = default;
+
+  RecursiveLockGuardedTryHolder<T> try_lock()
+  {
+    return RecursiveLockGuardedTryHolder<T>(d_value, d_mutex);
+  }
+
+  RecursiveLockGuardedHolder<T> lock()
+  {
+    return RecursiveLockGuardedHolder<T>(d_value, d_mutex);
+  }
+
+  RecursiveLockGuardedHolder<const T> read_only_lock()
+  {
+    return RecursiveLockGuardedHolder<const T>(d_value, d_mutex);
+  }
+
+private:
+  std::recursive_mutex d_mutex;
+  T d_value;
+};
+
 template <typename T>
 class SharedLockGuardedHolder
 {
 public:
-  explicit SharedLockGuardedHolder(T& value, std::shared_mutex& mutex): d_lock(mutex), d_value(value)
+  explicit SharedLockGuardedHolder(T& value, std::shared_mutex& mutex) :
+    d_lock(mutex), d_value(value)
   {
   }
 
-  T& operator*() const noexcept {
+  T& operator*() const noexcept
+  {
     return d_value;
   }
 
-  T* operator->() const noexcept {
+  T* operator->() const noexcept
+  {
     return &d_value;
   }
 
@@ -322,29 +466,34 @@ template <typename T>
 class SharedLockGuardedTryHolder
 {
 public:
-  explicit SharedLockGuardedTryHolder(T& value, std::shared_mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+  explicit SharedLockGuardedTryHolder(T& value, std::shared_mutex& mutex) :
+    d_lock(mutex, std::try_to_lock), d_value(value)
   {
   }
 
-  T& operator*() const {
+  T& operator*() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return d_value;
   }
 
-  T* operator->() const {
+  T* operator->() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return &d_value;
   }
 
-  operator bool() const noexcept {
+  operator bool() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
-  bool owns_lock() const noexcept {
+  [[nodiscard]] bool owns_lock() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
@@ -357,15 +506,18 @@ template <typename T>
 class SharedLockGuardedNonExclusiveHolder
 {
 public:
-  explicit SharedLockGuardedNonExclusiveHolder(const T& value, std::shared_mutex& mutex): d_lock(mutex), d_value(value)
+  explicit SharedLockGuardedNonExclusiveHolder(const T& value, std::shared_mutex& mutex) :
+    d_lock(mutex), d_value(value)
   {
   }
 
-  const T& operator*() const noexcept {
+  const T& operator*() const noexcept
+  {
     return d_value;
   }
 
-  const T* operator->() const noexcept {
+  const T* operator->() const noexcept
+  {
     return &d_value;
   }
 
@@ -378,29 +530,34 @@ template <typename T>
 class SharedLockGuardedNonExclusiveTryHolder
 {
 public:
-  explicit SharedLockGuardedNonExclusiveTryHolder(const T& value, std::shared_mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value)
+  explicit SharedLockGuardedNonExclusiveTryHolder(const T& value, std::shared_mutex& mutex) :
+    d_lock(mutex, std::try_to_lock), d_value(value)
   {
   }
 
-  const T& operator*() const {
+  const T& operator*() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return d_value;
   }
 
-  const T* operator->() const {
+  const T* operator->() const
+  {
     if (!owns_lock()) {
       throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired");
     }
     return &d_value;
   }
 
-  operator bool() const noexcept {
+  operator bool() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
-  bool owns_lock() const noexcept {
+  [[nodiscard]] bool owns_lock() const noexcept
+  {
     return d_lock.owns_lock();
   }
 
@@ -413,11 +570,13 @@ template <typename T>
 class SharedLockGuarded
 {
 public:
-  explicit SharedLockGuarded(const T& value): d_value(value)
+  explicit SharedLockGuarded(const T& value) :
+    d_value(value)
   {
   }
 
-  explicit SharedLockGuarded(T&& value): d_value(std::move(value))
+  explicit SharedLockGuarded(T&& value) :
+    d_value(std::move(value))
   {
   }
 
index 77f7caa9035e167ee32389af025cd075b4f2524c..ea8d380f0d99e9caaab5930c79a913c9d8dca26c 100644 (file)
@@ -13,8 +13,6 @@
 
 #include "ueberbackend.hh"
 
-AuthLua4::AuthLua4() { prepareContext(); }
-
 LuaContext* AuthLua4::getLua()
 {
   return d_lw.get();
@@ -84,6 +82,9 @@ void AuthLua4::postPrepareContext() {
   d_lw->registerFunction<DNSName(UpdatePolicyQuery::*)()>("getTsigName", [](UpdatePolicyQuery& upq) { return upq.tsigName; });
   d_lw->registerFunction<std::string(UpdatePolicyQuery::*)()>("getPeerPrincipal", [](UpdatePolicyQuery& upq) { return upq.peerPrincipal; });
 /* end of update policy */
+  if (!d_include_path.empty()) {
+    includePath(d_include_path);
+  }
 }
 
 void AuthLua4::postLoad() {
index fea41d640b99918dfe9d42a66c33b076ab284de7..d154df708849ecc2156c53454629a092c60338e8 100644 (file)
@@ -12,7 +12,9 @@
 class AuthLua4 : public BaseLua4
 {
 public:
-  AuthLua4();
+  AuthLua4(const std::string& includePath="") : BaseLua4(includePath) {
+    prepareContext();
+  };
   bool updatePolicy(const DNSName &qname, const QType& qtype, const DNSName &zonename, const DNSPacket& packet);
   bool axfrfilter(const ComboAddress&, const DNSName&, const DNSResourceRecord&, std::vector<DNSResourceRecord>&);
   LuaContext* getLua();
index 3984fe62e974583b2a7e8b6d85703d119ee0c3bc..b3d5d1b90f8ba0a75e0e702d4b35fad05dd6957d 100644 (file)
@@ -1,8 +1,10 @@
+#include "config.h"
 #include <cassert>
 #include <fstream>
 #include <unordered_set>
 #include <unordered_map>
 #include <typeinfo>
+#include <sys/stat.h>
 #include "logger.hh"
 #include "logging.hh"
 #include "iputils.hh"
 #include "ext/luawrapper/include/LuaContext.hpp"
 #include "dns_random.hh"
 
-BaseLua4::BaseLua4() = default;
-
-void BaseLua4::loadFile(const std::string& fname)
+void BaseLua4::loadFile(const std::string& fname, bool doPostLoad)
 {
   std::ifstream ifs(fname);
   if (!ifs) {
     auto ret = errno;
     auto msg = stringerror(ret);
-    SLOG(g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl,
-         g_slog->withName("lua")->error(Logr::Error, ret, "Unable to read configuration file", "file", Logging::Loggable(fname), "msg", Logging::Loggable(msg)));
+    g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl;
     throw std::runtime_error(msg);
   }
-  loadStream(ifs);
+  loadStream(ifs, doPostLoad);
 };
 
 void BaseLua4::loadString(const std::string &script) {
   std::istringstream iss(script);
-  loadStream(iss);
+  loadStream(iss, true);
+};
+
+void BaseLua4::includePath(const std::string& directory) {
+  std::vector<std::string> vec;
+  const std::string& suffix = "lua";
+  auto directoryError = pdns::visit_directory(directory, [this, &directory, &suffix, &vec]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+    (void)this;
+    if (boost::starts_with(name, ".")) {
+      return true; // skip any dots
+    }
+    if (boost::ends_with(name, suffix)) {
+      // build name
+      string fullName = directory + "/" + std::string(name);
+      // ensure it's readable file
+      struct stat statInfo
+      {
+      };
+      if (stat(fullName.c_str(), &statInfo) != 0 || !S_ISREG(statInfo.st_mode)) {
+        string msg = fullName + " is not a regular file";
+        g_log << Logger::Error << msg << std::endl;
+        throw PDNSException(msg);
+      }
+      vec.emplace_back(fullName);
+    }
+    return true;
+  });
+
+  if (directoryError) {
+    int err = errno;
+    string msg = directory + " is not accessible: " + stringerror(err);
+    g_log << Logger::Error << msg << std::endl;
+    throw PDNSException(msg);
+  }
+
+  std::sort(vec.begin(), vec.end(), CIStringComparePOSIX());
+
+  for(const auto& file: vec) {
+    loadFile(file, false);
+  }
 };
 
 //  By default no features
@@ -289,10 +327,12 @@ void BaseLua4::prepareContext() {
   d_lw->writeVariable("pdns", d_pd);
 }
 
-void BaseLua4::loadStream(std::istream &is) {
-  d_lw->executeCode(is);
+void BaseLua4::loadStream(std::istream &stream, bool doPostLoad) {
+  d_lw->executeCode(stream);
 
-  postLoad();
+  if (doPostLoad) {
+    postLoad();
+  }
 }
 
 BaseLua4::~BaseLua4() = default;
index 20b0159716bc93504d003209beccf1cb292395d5..1786d0ff78ccc9500e1b8df1c6ce9f72c14be9b2 100644 (file)
@@ -10,12 +10,14 @@ class BaseLua4 : public boost::noncopyable
 {
 protected:
   std::unique_ptr<LuaContext> d_lw; // this is way on top because it must get destroyed _last_
+  std::string d_include_path; // path where scripts to include at postLoad are
 
 public:
-  BaseLua4();
-  void loadFile(const std::string& fname);
-  void loadString(const std::string& script);
-  void loadStream(std::istream& is);
+  BaseLua4(const std::string &includePath) : d_include_path(includePath) {};
+  void loadFile(const std::string &fname, bool doPostLoad=true);
+  void loadString(const std::string &script);
+  void loadStream(std::istream &stream, bool doPostLoad=true);
+  void includePath(const std::string &directory);
   virtual ~BaseLua4(); // this is so unique_ptr works with an incomplete type
 protected:
   void prepareContext();
index e9b08e662387219560a0ff5603323bcb93946677..1f2344a881b5e06c70a8d8a6999dc28ca0fdc020 100644 (file)
@@ -90,6 +90,8 @@ public:
 private:
   void checkURL(const CheckDesc& cd, const bool status, const bool first = false)
   {
+    setThreadName("pdns/lua-c-url");
+
     string remstring;
     try {
       int timeout = 2;
@@ -138,6 +140,7 @@ private:
     }
   }
   void checkTCP(const CheckDesc& cd, const bool status, const bool first = false) {
+    setThreadName("pdns/lua-c-tcp");
     try {
       int timeout = 2;
       if (cd.opts.count("timeout")) {
@@ -168,6 +171,7 @@ private:
   }
   void checkThread()
   {
+    setThreadName("pdns/luaupcheck");
     while (true)
     {
       std::chrono::system_clock::time_point checkStart = std::chrono::system_clock::now();
@@ -200,6 +204,10 @@ private:
           statuses->erase(it);
         }
       }
+
+      // set thread name again, in case std::async surprised us by doing work in this thread
+      setThreadName("pdns/luaupcheck");
+
       std::this_thread::sleep_until(checkStart + std::chrono::seconds(g_luaHealthChecksInterval));
     }
   }
@@ -1391,7 +1399,7 @@ std::vector<shared_ptr<DNSRecordContent>> luaSynth(const std::string& code, cons
 {
   if(!LUA ||                  // we don't have a Lua state yet
      !g_LuaRecordSharedState) { // or we want a new one even if we had one
-    LUA = make_unique<AuthLua4>();
+    LUA = make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
     setupLuaRecords(*LUA->getLua());
   }
 
index b69155daea766b3a1dd22a61d82cb253f60d33f1..29adfc51fa1cd7d73ff2f4f48bd9535b317bd474 100644 (file)
@@ -95,24 +95,26 @@ size_t writen2(int fileDesc, const void *buf, size_t count)
   return count;
 }
 
-size_t readn2(int fd, void* buffer, size_t len)
+size_t readn2(int fileDesc, void* buffer, size_t len)
 {
-  size_t pos=0;
-  ssize_t res;
-  for(;;) {
-    res = read(fd, (char*)buffer + pos, len - pos);
-    if(res == 0)
+  size_t pos = 0;
+
+  for (;;) {
+    auto res = read(fileDesc, static_cast<char *>(buffer) + pos, len - pos); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic): it's the API
+    if (res == 0) {
       throw runtime_error("EOF while reading message");
-    if(res < 0) {
-      if (errno == EAGAIN)
+    }
+    if (res < 0) {
+      if (errno == EAGAIN) {
         throw std::runtime_error("used readn2 on non-blocking socket, got EAGAIN");
-      else
-        unixDie("failed in readn2");
+      }
+      unixDie("failed in readn2");
     }
 
-    pos+=(size_t)res;
-    if(pos == len)
+    pos += static_cast<size_t>(res);
+    if (pos == len) {
       break;
+    }
   }
   return len;
 }
@@ -282,7 +284,7 @@ auto pdns::OpenSSL::error(const std::string& errorMessage) -> std::runtime_error
     }
   }
 #endif
-  return std::runtime_error(fullErrorMessage);
+  return std::runtime_error{fullErrorMessage};
 }
 
 auto pdns::OpenSSL::error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error
index e9a0dad36a221b5a202e60dfad33ea893e996168..39fdb6c086807e81f4280ec312545b7d36259201 100644 (file)
 class DNSName;
 
 // Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
-typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
+typedef enum
+{
+  TSIG_MD5,
+  TSIG_SHA1,
+  TSIG_SHA224,
+  TSIG_SHA256,
+  TSIG_SHA384,
+  TSIG_SHA512,
+  TSIG_GSS,
+} TSIGHashEnum;
+
 namespace pdns
 {
 /**
@@ -167,7 +177,7 @@ vstringtok (Container &container, string const &in,
 
 size_t writen2(int fd, const void *buf, size_t count);
 inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
-size_t readn2(int fd, void* buffer, size_t len);
+size_t readn2(int fileDesc, void* buffer, size_t len);
 size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
 size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
 
@@ -319,9 +329,9 @@ inline double getTime()
   return now.tv_sec+now.tv_usec/1000000.0;
 }
 
-inline void unixDie(const string &why)
+[[noreturn]] inline void unixDie(const string &why)
 {
-  throw runtime_error(why+": "+stringerror());
+  throw runtime_error(why + ": " + stringerror(errno));
 }
 
 string makeHexDump(const string& str);
index f47ed2c58b5e642cf05042db2ecc905c695f1cba..a5d6dcb5ecd7bcc179b77bece4b5075d2e1a3a9a 100644 (file)
@@ -167,35 +167,35 @@ try
   string nsec3salt;
   int nsec3iters = 0;
   for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {     
-    if(i->first.d_type == QType::NSEC3)
+    if(i->d_type == QType::NSEC3)
     {
       // cerr<<"got nsec3 ["<<i->first.d_name<<"]"<<endl;
       // cerr<<i->first.d_content->getZoneRepresentation()<<endl;
-      const auto r = getRR<NSEC3RecordContent>(i->first);
-      if (!r) {
+      const auto nsec3Record = getRR<NSEC3RecordContent>(*i);
+      if (!nsec3Record) {
         continue;
       }
       // nsec3.insert(new nsec3()
       // cerr<<toBase32Hex(r.d_nexthash)<<endl;
-      nsec3s.emplace(toLower(i->first.d_name.getRawLabel(0)), toBase32Hex(r->d_nexthash));
-      nsec3salt = r->d_salt;
-      nsec3iters = r->d_iterations;
-      nsec3t.emplace(toLower(i->first.d_name.getRawLabel(0)), r->numberOfTypesSet());
+      nsec3s.emplace(toLower(i->d_name.getRawLabel(0)), toBase32Hex(nsec3Record->d_nexthash));
+      nsec3salt = nsec3Record->d_salt;
+      nsec3iters = nsec3Record->d_iterations;
+      nsec3t.emplace(toLower(i->d_name.getRawLabel(0)), nsec3Record->numberOfTypesSet());
     }
     else
     {
-      // cerr<<"namesseen.insert('"<<i->first.d_name<<"')"<<endl;
-      names.insert(i->first.d_name);
-      namesseen.insert(i->first.d_name);
+      // cerr<<"namesseen.insert('"<<i->d_name<<"')"<<endl;
+      names.insert(i->d_name);
+      namesseen.insert(i->d_name);
     }
 
-    if(i->first.d_type == QType::CNAME)
+    if(i->d_type == QType::CNAME)
     {
-      namesseen.insert(DNSName(i->first.getContent()->getZoneRepresentation()));
+      namesseen.insert(DNSName(i->getContent()->getZoneRepresentation()));
     }
 
-    cout << i->first.d_place - 1 << "\t" << i->first.d_name.toString() << "\t" << i->first.d_ttl << "\tIN\t" << DNSRecordContent::NumberToType(i->first.d_type);
-    cout << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+    cout << i->d_place - 1 << "\t" << i->d_name.toString() << "\t" << i->d_ttl << "\tIN\t" << DNSRecordContent::NumberToType(i->d_type);
+    cout << "\t" << i->getContent()->getZoneRepresentation() << "\n";
   }
 
 #if 0
index 9b593aa2da7ce762a8f751745ca05afed48c855b..91d438dab67bac9d2f63921c1849038f64b1f1e2 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+
+#include "config.h"
 #include "misc.hh"
 #include <memory>
 #include <openssl/crypto.h>
 #include <openssl/ec.h>
 #include <optional>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
 #include <openssl/obj_mac.h>
 #ifdef HAVE_LIBCRYPTO_ECDSA
 #include <openssl/ecdsa.h>
index 5c4a97e34aa9ec03018aac68a2ed22db19f8fc1a..3d385ed7b54ce6f6996d4762e270fc7a42b37b6f 100644 (file)
@@ -71,14 +71,15 @@ PacketHandler::PacketHandler():B(g_programname), d_dk(&B)
   d_doExpandALIAS = ::arg().mustDo("expand-alias");
   d_logDNSDetails= ::arg().mustDo("log-dns-details");
   string fname= ::arg()["lua-prequery-script"];
+
   if(fname.empty())
   {
     d_pdl = nullptr;
   }
   else
   {
-    d_pdl = std::make_unique<AuthLua4>();
-    d_pdl->loadFile(fname); // XXX exception handling?
+    d_pdl = std::make_unique<AuthLua4>(::arg()["lua-global-include-dir"]);
+    d_pdl->loadFile(fname);
   }
   fname = ::arg()["lua-dnsupdate-policy-script"];
   if (fname.empty())
@@ -87,11 +88,12 @@ PacketHandler::PacketHandler():B(g_programname), d_dk(&B)
   }
   else
   {
-    d_update_policy_lua = std::make_unique<AuthLua4>();
     try {
+      d_update_policy_lua = std::make_unique<AuthLua4>();
       d_update_policy_lua->loadFile(fname);
     }
-    catch (const std::runtime_error&) {
+    catch (const std::runtime_error& e) {
+      g_log<<Logger::Warning<<"Failed to load update policy - disabling: "<<e.what()<<endl;
       d_update_policy_lua = nullptr;
     }
   }
@@ -437,7 +439,7 @@ bool PacketHandler::getBestWildcard(DNSPacket& p, const DNSName &target, DNSName
             }
           }
           catch (std::exception &e) {
-            while (B.get(rr)) ;                 // don't leave DB handle in bad state
+            B.lookupEnd();                 // don't leave DB handle in bad state
 
             throw;
           }
@@ -463,7 +465,7 @@ bool PacketHandler::getBestWildcard(DNSPacket& p, const DNSName &target, DNSName
     B.lookup(QType(QType::ANY), subdomain, d_sd.domain_id, &p);
     if (B.get(rr)) {
       DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
-      while (B.get(rr)) ;
+      B.lookupEnd();
       break;
     }
     wildcard=subdomain;
@@ -499,7 +501,7 @@ DNSName PacketHandler::doAdditionalServiceProcessing(const DNSName &firstTarget,
           break;
         }
         default:
-          while (B.get(rr)) ;              // don't leave DB handle in bad state
+          B.lookupEnd();              // don't leave DB handle in bad state
 
           throw PDNSException("Unknown type (" + QType(qtype).toString() + ") for additional service processing");
       }
@@ -1621,7 +1623,7 @@ std::unique_ptr<DNSPacket> PacketHandler::doQuestion(DNSPacket& p)
             }
           }
           catch(std::exception &e) {
-            while (B.get(rr)) ;              // don't leave DB handle in bad state
+            B.lookupEnd();              // don't leave DB handle in bad state
 
             r=p.replyPacket();
             r->setRcode(RCode::ServFail);
@@ -1817,7 +1819,7 @@ std::unique_ptr<DNSPacket> PacketHandler::doQuestion(DNSPacket& p)
       }
     }
     if(doSigs)
-      addRRSigs(d_dk, B, authSet, r->getRRS());
+      addRRSigs(d_dk, B, authSet, r->getRRS(), &p);
 
     if(PC.enabled() && !noCache && p.couldBeCached())
       PC.insert(p, *r, r->getMinTTL()); // in the packet cache
index 6bc3d443c664d2910d43cecd73bd70bda81a81bf..7b30167cb76a8a166ce8abd4f7285c83aabb5472 100644 (file)
@@ -1,4 +1,7 @@
+#include "dnsname.hh"
+#include "dnsparser.hh"
 #include "dnsrecords.hh"
+#include "qtype.hh"
 #include <boost/smart_ptr/make_shared_array.hpp>
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -378,6 +381,7 @@ static int checkZone(DNSSECKeeper &dk, UeberBackend &B, const DNSName& zone, con
     if(rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) {
       addresses.insert(rr.qname);
     }
+#ifdef HAVE_LUA_RECORDS
     if(rr.qtype.getCode() == QType::LUA) {
       shared_ptr<DNSRecordContent> drc(DNSRecordContent::make(rr.qtype.getCode(), QClass::IN, rr.content));
       auto luarec = std::dynamic_pointer_cast<LUARecordContent>(drc);
@@ -386,6 +390,7 @@ static int checkZone(DNSSECKeeper &dk, UeberBackend &B, const DNSName& zone, con
         addresses.insert(rr.qname);
       }
     }
+#endif
     if(rr.qtype.getCode() == QType::A) {
       arecords.insert(rr.qname);
     }
@@ -922,10 +927,11 @@ static int increaseSerial(const DNSName& zone, DNSSECKeeper &dk)
 
   sd.db->startTransaction(zone, -1);
 
-  if (!sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, {rr})) {
-   sd.db->abortTransaction();
-   cerr<<"Backend did not replace SOA record. Backend might not support this operation."<<endl;
-   return -1;
+  auto rrs = vector<DNSResourceRecord>{rr};
+  if (!sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, rrs)) {
+    sd.db->abortTransaction();
+    cerr << "Backend did not replace SOA record. Backend might not support this operation." << endl;
+    return -1;
   }
 
   if (sd.db->doesDNSSEC()) {
@@ -2564,6 +2570,8 @@ try
     cout << "]" << endl;
     cout << "                                   Add a ZSK or KSK to zone and specify algo&bits" << endl;
     cout << "backend-cmd BACKEND CMD [CMD..]    Perform one or more backend commands" << endl;
+    cout << "backend-lookup BACKEND NAME [[TYPE] CLIENT-IP-SUBNET]" << endl;
+    cout << "                                   Perform a backend lookup of NAME, TYPE and CLIENT-IP-SUBNET" << endl;
     cout << "b2b-migrate OLD NEW                Move all data from one backend to another" << endl;
     cout << "bench-db [filename]                Bench database backend with queries, one zone per line" << endl;
     cout << "check-zone ZONE                    Check a zone for correctness" << endl;
@@ -4223,22 +4231,78 @@ try
 
     return 0;
   }
+  else if (cmds.at(0) == "backend-lookup") {
+    if (cmds.size() < 3) {
+      cerr << "Usage: backend-lookup BACKEND NAME [TYPE [CLIENT-IP-SUBNET]]" << endl;
+      return 1;
+    }
+
+    std::unique_ptr<DNSBackend> matchingBackend{nullptr};
+
+    for (auto& backend : BackendMakers().all()) {
+      if (backend->getPrefix() == cmds.at(1)) {
+        matchingBackend = std::move(backend);
+      }
+    }
+
+    if (matchingBackend == nullptr) {
+      cerr << "Unknown backend '" << cmds.at(1) << "'" << endl;
+      return 1;
+    }
+
+    QType type = QType::ANY;
+    if (cmds.size() > 3) {
+      type = DNSRecordContent::TypeToNumber(cmds.at(3));
+    }
+
+    DNSName name{cmds.at(2)};
+
+    DNSPacket queryPacket(true);
+    Netmask clientNetmask;
+    if (cmds.size() > 4) {
+      clientNetmask = cmds.at(4);
+      queryPacket.setRealRemote(clientNetmask);
+    }
+
+    matchingBackend->lookup(type, name, -1, &queryPacket);
+
+    bool found = false;
+    DNSZoneRecord resultZoneRecord;
+    while (matchingBackend->get(resultZoneRecord)) {
+      cout << resultZoneRecord.dr.d_name.toString() << "\t" << std::to_string(resultZoneRecord.dr.d_ttl) << "\t" << QClass(resultZoneRecord.dr.d_class).toString() << "\t" << DNSRecordContent::NumberToType(resultZoneRecord.dr.d_type, resultZoneRecord.dr.d_class) << "\t" << resultZoneRecord.dr.getContent()->getZoneRepresentation();
+      if (resultZoneRecord.scopeMask > 0) {
+        clientNetmask.setBits(resultZoneRecord.scopeMask);
+        cout << "\t" << "; " << clientNetmask.toString();
+      }
+      cout << endl;
+      found = true;
+    }
+    if (!found) {
+      cerr << "Backend found 0 zone record results";
+      if (type != QType::ANY) {
+        cerr << "- maybe retry with type ANY?";
+      }
+      cerr << endl;
+      return 1;
+    }
+
+    return 0;
+  }
   else {
     cerr << "Unknown command '" << cmds.at(0) << "'" << endl;
     return 1;
   }
   return 0;
 }
-catch(PDNSException& ae) {
-  cerr<<"Error: "<<ae.reason<<endl;
+catch (PDNSException& ae) {
+  cerr << "Error: " << ae.reason << endl;
   return 1;
 }
-catch(std::exception& e) {
-  cerr<<"Error: "<<e.what()<<endl;
+catch (std::exception& e) {
+  cerr << "Error: " << e.what() << endl;
   return 1;
 }
-catch(...)
-{
-  cerr<<"Caught an unknown exception"<<endl;
+catch (...) {
+  cerr << "Caught an unknown exception" << endl;
   return 1;
 }
index e8c1dceae7d6c131ea1567b19cd8f32628a1d3ba..b5f91f4a49500cae6fac9cbc7c6aca97e2cd8c61 100644 (file)
 #ifndef DISABLE_PROTOBUF
 #include "dnsparser.hh"
 
-void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& ca)
+void pdns::ProtoZero::Message::encodeComboAddress(const protozero::pbf_tag_type type, const ComboAddress& address)
 {
-  if (ca.sin4.sin_family == AF_INET) {
-    d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+  if (address.sin4.sin_family == AF_INET) {
+    d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
   }
-  else if (ca.sin4.sin_family == AF_INET6) {
-    d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+  else if (address.sin4.sin_family == AF_INET6) {
+    d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr.s6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
   }
 }
 
 void pdns::ProtoZero::Message::encodeNetmask(const protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask)
 {
   if (!subnet.empty()) {
-    ComboAddress ca(subnet.getNetwork());
-    ca.truncate(mask);
-    if (ca.sin4.sin_family == AF_INET) {
-      d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin4.sin_addr.s_addr), sizeof(ca.sin4.sin_addr.s_addr));
+    ComboAddress address(subnet.getNetwork());
+    address.truncate(mask);
+    if (address.sin4.sin_family == AF_INET) {
+      d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin4.sin_addr.s_addr), sizeof(address.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
     }
-    else if (ca.sin4.sin_family == AF_INET6) {
-      d_message.add_bytes(type, reinterpret_cast<const char*>(&ca.sin6.sin6_addr.s6_addr), sizeof(ca.sin6.sin6_addr.s6_addr));
+    else if (address.sin4.sin_family == AF_INET6) {
+      d_message.add_bytes(type, reinterpret_cast<const char*>(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr.s6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
     }
   }
 }
@@ -58,7 +58,7 @@ void pdns::ProtoZero::Message::encodeDNSName(protozero::pbf_writer& pbf, std::st
   // leaving the block will cause the sub writer to compute how much was written based on the new size and update the size accordingly
 }
 
-void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, pdns::ProtoZero::Message::TransportProtocol proto, size_t len)
+void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t qid, pdns::ProtoZero::Message::TransportProtocol proto, size_t len)
 {
   setMessageIdentity(uniqueId);
   setSocketFamily(requestor.sin4.sin_family);
@@ -67,7 +67,7 @@ void pdns::ProtoZero::Message::setRequest(const boost::uuids::uuid& uniqueId, co
   setTo(local);
   setInBytes(len);
   setTime();
-  setId(id);
+  setId(qid);
   setQuestion(qname, qtype, qclass);
   setFromPort(requestor.getPort());
   setToPort(local.getPort());
@@ -85,67 +85,67 @@ void pdns::ProtoZero::Message::addRRsFromPacket(const char* packet, const size_t
     return;
   }
 
-  const dnsheader_aligned dh(packet);
+  const dnsheader_aligned header(packet);
 
-  if (ntohs(dh->ancount) == 0) {
+  if (ntohs(header->ancount) == 0) {
     return;
   }
 
-  if (ntohs(dh->qdcount) == 0) {
+  if (ntohs(header->qdcount) == 0) {
     return;
   }
 
-  PacketReader pr(std::string_view(packet, len));
+  PacketReader packetReader(std::string_view(packet, len));
 
   size_t idx = 0;
   DNSName rrname;
-  uint16_t qdcount = ntohs(dh->qdcount);
-  uint16_t ancount = ntohs(dh->ancount);
-  uint16_t rrtype;
-  uint16_t rrclass;
+  uint16_t qdcount = ntohs(header->qdcount);
+  uint16_t ancount = ntohs(header->ancount);
+  uint16_t rrtype{};
+  uint16_t rrclass{};
   string blob;
-  struct dnsrecordheader ah;
+  dnsrecordheader recordHeader{};
 
-  rrname = pr.getName();
-  rrtype = pr.get16BitInt();
-  rrclass = pr.get16BitInt();
-  (void) rrtype;
-  (void) rrclass;
+  rrname = packetReader.getName();
+  rrtype = packetReader.get16BitInt();
+  rrclass = packetReader.get16BitInt();
+  (void)rrtype;
+  (void)rrclass;
 
   /* consume remaining qd if any */
   if (qdcount > 1) {
-    for(idx = 1; idx < qdcount; idx++) {
-      rrname = pr.getName();
-      rrtype = pr.get16BitInt();
-      rrclass = pr.get16BitInt();
-      (void) rrtype;
-      (void) rrclass;
+    for (idx = 1; idx < qdcount; idx++) {
+      rrname = packetReader.getName();
+      rrtype = packetReader.get16BitInt();
+      rrclass = packetReader.get16BitInt();
+      (void)rrtype;
+      (void)rrclass;
     }
   }
 
   /* parse AN */
   for (idx = 0; idx < ancount; idx++) {
-    rrname = pr.getName();
-    pr.getDnsrecordheader(ah);
+    rrname = packetReader.getName();
+    packetReader.getDnsrecordheader(recordHeader);
 
-    if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
-      pr.xfrBlob(blob);
+    if (recordHeader.d_type == QType::A || recordHeader.d_type == QType::AAAA) {
+      packetReader.xfrBlob(blob);
 
-      addRR(rrname, ah.d_type, ah.d_class, ah.d_ttl, blob);
-
-    } else if (ah.d_type == QType::CNAME && includeCNAME) {
+      addRR(rrname, recordHeader.d_type, recordHeader.d_class, recordHeader.d_ttl, blob);
+    }
+    else if (recordHeader.d_type == QType::CNAME && includeCNAME) {
       protozero::pbf_writer pbf_rr{d_response, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::ResponseField::rrs)};
 
       encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::name), rrname);
-      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), ah.d_type);
-      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), ah.d_class);
-      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), ah.d_ttl);
+      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::type), recordHeader.d_type);
+      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::class_), recordHeader.d_class);
+      pbf_rr.add_uint32(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::ttl), recordHeader.d_ttl);
       DNSName target;
-      pr.xfrName(target, true);
+      packetReader.xfrName(target, true);
       encodeDNSName(pbf_rr, d_buffer, static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::rdata), target);
     }
     else {
-      pr.xfrBlob(blob);
+      packetReader.xfrBlob(blob);
     }
   }
 }
index 8dd49db0df9a8073bac3f4fb41d5dd12dfca066a..b2c96c2184235012e4c0de9d0285950c0ce1d002 100644 (file)
 
 #include <protozero/pbf_writer.hpp>
 
-namespace pdns {
-  namespace ProtoZero {
-    class Message {
-    public:
-
-      enum class MetaValueField : protozero::pbf_tag_type { stringVal = 1, intVal = 2 };
-      enum class HTTPVersion : protozero::pbf_tag_type { HTTP1 = 1, HTTP2 = 2, HTTP3 = 3 };
-      enum class MetaField : protozero::pbf_tag_type { key = 1, value = 2 };
-      enum class Event : protozero::pbf_tag_type { ts = 1, event = 2, start = 3, boolVal = 4, intVal = 5, stringVal = 6, bytesVal = 7, custom = 8 };
-      enum class MessageType : int32_t { DNSQueryType = 1, DNSResponseType = 2, DNSOutgoingQueryType = 3, DNSIncomingResponseType = 4 };
-      enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23, httpVersion = 24 };
-      enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 };
-      enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 };
-      enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 };
-      enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6, DoQ = 7 };
-
-      Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer}
-      {
-      }
-
-      Message(const Message&) = delete;
-      Message(Message&&) = delete;
-      Message& operator=(const Message&) = delete;
-      Message& operator=(Message&&) = delete;
-
-      void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t id, TransportProtocol proto, size_t len);
-      void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
-
-      void setType(MessageType mtype)
-      {
-        add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
-      }
-
-      void setHTTPVersion(HTTPVersion version)
-      {
-        add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
-      }
-
-      void setMessageIdentity(const boost::uuids::uuid& uniqueId)
-      {
-        add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
-      }
-
-      void setServerIdentity(const std::string& serverIdentity)
-      {
-        add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
-      }
-
-      void setSocketFamily(int family)
-      {
-        add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
-      }
-
-      void setSocketProtocol(TransportProtocol proto)
-      {
-        add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
-      }
-
-      void setFrom(const ComboAddress& ca)
-      {
-        encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), ca);
-      }
-
-      void setTo(const ComboAddress& ca)
-      {
-        encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), ca);
-      }
-
-      void setInBytes(uint64_t len)
-      {
-        add_uint64(d_message, Field::inBytes, len);
-      }
-
-      void setTime()
-      {
-        struct timespec ts;
-        gettime(&ts, true);
-
-        setTime(ts.tv_sec, ts.tv_nsec / 1000);
-      }
-
-      void setTime(time_t sec, uint32_t usec)
-      {
-        // coverity[store_truncates_time_t]
-        add_uint32(d_message, Field::timeSec, sec);
-        add_uint32(d_message, Field::timeUsec, usec);
-      }
-
-      void setId(uint16_t id)
-      {
-        add_uint32(d_message, Field::id, ntohs(id));
-      }
-
-      void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
-      {
-        protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
-        encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
-        pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
-        pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
-      }
-
-      void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
-      {
-        protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
-        pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
-        protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
-        for (const auto& s: stringVal) {
-          pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), s);
-        }
-        for (const auto& i: intVal) {
-          pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), i);
-        }
-      }
-
-      void setEDNSSubnet(const Netmask& nm, uint8_t mask)
-      {
-        encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), nm, mask);
-      }
-
-      void setRequestorId(const std::string& req)
-      {
-        if (!req.empty()) {
-          add_string(d_message, Field::requestorId, req);
-        }
-      }
-
-      void setInitialRequestID(const boost::uuids::uuid& uniqueId)
-      {
-        add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
-      }
-
-      void setDeviceId(const std::string& id)
-      {
-        if (!id.empty()) {
-          add_string(d_message, Field::deviceId, id);
-        }
-      }
-
-      void setNewlyObservedDomain(bool nod)
-      {
-        add_bool(d_message, Field::newlyObservedDomain, nod);
-      }
-
-      void setDeviceName(const std::string& name)
-      {
-        if (!name.empty()) {
-          add_string(d_message, Field::deviceName, name);
-        }
-      }
-
-      void setFromPort(in_port_t port)
-      {
-        add_uint32(d_message, Field::fromPort, port);
-      }
-
-      void setToPort(in_port_t port)
-      {
-        add_uint32(d_message, Field::toPort, port);
-      }
-
-      void startResponse()
-      {
-        d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
-      }
-
-      void commitResponse()
-      {
-        d_response.commit();
-      }
-
-      void setResponseCode(uint8_t rcode)
-      {
-        d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
-      }
-
-      void setNetworkErrorResponseCode()
-      {
-        /* special code meaning 'network error', like a timeout */
-        d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
-      }
-
-      void setAppliedPolicy(const std::string& policy)
-      {
-        d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
-      }
-
-      void addPolicyTags(const std::unordered_set<std::string>& tags)
-      {
-        for (const auto& tag : tags) {
-          addPolicyTag(tag);
-        }
-      }
-
-      void addPolicyTag(const string& tag)
-      {
-        d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
-      }
-
-      void setQueryTime(uint32_t sec, uint32_t usec)
-      {
-        d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
-        d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
-      }
-
-      void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
-      void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
-
-    protected:
-      void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& ca);
-      void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
-      void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
-
-      static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
-      {
-        writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
-      }
-
-      static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
-      {
-        writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
-      }
-
-      static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
-      {
-        writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
-      }
-
-      static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
-      {
-        writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
-      }
-
-      static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
-      {
-        writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
-      }
-
-      static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
-      {
-        writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
-      }
-
-
-      std::string& d_buffer;
-      protozero::pbf_writer d_message;
-      protozero::pbf_writer d_response;
+namespace pdns
+{
+namespace ProtoZero
+{
+  class Message
+  {
+  public:
+    enum class MetaValueField : protozero::pbf_tag_type
+    {
+      stringVal = 1,
+      intVal = 2
     };
+    enum class HTTPVersion : protozero::pbf_tag_type
+    {
+      HTTP1 = 1,
+      HTTP2 = 2,
+      HTTP3 = 3
+    };
+    enum class MetaField : protozero::pbf_tag_type
+    {
+      key = 1,
+      value = 2
+    };
+    enum class Event : protozero::pbf_tag_type
+    {
+      ts = 1,
+      event = 2,
+      start = 3,
+      boolVal = 4,
+      intVal = 5,
+      stringVal = 6,
+      bytesVal = 7,
+      custom = 8
+    };
+    enum class MessageType : int32_t
+    {
+      DNSQueryType = 1,
+      DNSResponseType = 2,
+      DNSOutgoingQueryType = 3,
+      DNSIncomingResponseType = 4
+    };
+    enum class Field : protozero::pbf_tag_type
+    {
+      type = 1,
+      messageId = 2,
+      serverIdentity = 3,
+      socketFamily = 4,
+      socketProtocol = 5,
+      from = 6,
+      to = 7,
+      inBytes = 8,
+      timeSec = 9,
+      timeUsec = 10,
+      id = 11,
+      question = 12,
+      response = 13,
+      originalRequestorSubnet = 14,
+      requestorId = 15,
+      initialRequestId = 16,
+      deviceId = 17,
+      newlyObservedDomain = 18,
+      deviceName = 19,
+      fromPort = 20,
+      toPort = 21,
+      meta = 22,
+      trace = 23,
+      httpVersion = 24,
+      workerId = 25,
+      packetCacheHit = 26,
+      outgoingQueries = 27
+    };
+    enum class QuestionField : protozero::pbf_tag_type
+    {
+      qName = 1,
+      qType = 2,
+      qClass = 3
+    };
+    enum class ResponseField : protozero::pbf_tag_type
+    {
+      rcode = 1,
+      rrs = 2,
+      appliedPolicy = 3,
+      tags = 4,
+      queryTimeSec = 5,
+      queryTimeUsec = 6,
+      appliedPolicyType = 7,
+      appliedPolicyTrigger = 8,
+      appliedPolicyHit = 9,
+      appliedPolicyKind = 10,
+      validationState = 11
+    };
+    enum class RRField : protozero::pbf_tag_type
+    {
+      name = 1,
+      type = 2,
+      class_ = 3,
+      ttl = 4,
+      rdata = 5,
+      udr = 6
+    };
+    enum class TransportProtocol : protozero::pbf_tag_type
+    {
+      UDP = 1,
+      TCP = 2,
+      DoT = 3,
+      DoH = 4,
+      DNSCryptUDP = 5,
+      DNSCryptTCP = 6,
+      DoQ = 7
+    };
+
+    Message(std::string& buffer) :
+      d_buffer(buffer), d_message{d_buffer}
+    {
+    }
+    ~Message() = default;
+    Message(const Message&) = delete;
+    Message(Message&&) = delete;
+    Message& operator=(const Message&) = delete;
+    Message& operator=(Message&&) = delete;
+
+    void setRequest(const boost::uuids::uuid& uniqueId, const ComboAddress& requestor, const ComboAddress& local, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t qid, TransportProtocol proto, size_t len);
+    void setResponse(const DNSName& qname, uint16_t qtype, uint16_t qclass);
+
+    void setType(MessageType mtype)
+    {
+      add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
+    }
+
+    void setHTTPVersion(HTTPVersion version)
+    {
+      add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
+    }
+
+    void setMessageIdentity(const boost::uuids::uuid& uniqueId)
+    {
+      add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+    }
+
+    void setServerIdentity(const std::string& serverIdentity)
+    {
+      add_bytes(d_message, Field::serverIdentity, serverIdentity.data(), serverIdentity.length());
+    }
+
+    void setSocketFamily(int family)
+    {
+      add_enum(d_message, Field::socketFamily, family == AF_INET ? 1 : 2);
+    }
+
+    void setSocketProtocol(TransportProtocol proto)
+    {
+      add_enum(d_message, Field::socketProtocol, static_cast<int32_t>(proto));
+    }
+
+    void setFrom(const ComboAddress& address)
+    {
+      encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::from), address);
+    }
+
+    void setTo(const ComboAddress& address)
+    {
+      encodeComboAddress(static_cast<protozero::pbf_tag_type>(Field::to), address);
+    }
+
+    void setInBytes(uint64_t len)
+    {
+      add_uint64(d_message, Field::inBytes, len);
+    }
+
+    void setTime()
+    {
+      timespec timesp{};
+      gettime(&timesp, true);
+
+      setTime(timesp.tv_sec, timesp.tv_nsec / 1000);
+    }
+
+    void setTime(time_t sec, uint32_t usec)
+    {
+      // coverity[store_truncates_time_t]
+      add_uint32(d_message, Field::timeSec, sec);
+      add_uint32(d_message, Field::timeUsec, usec);
+    }
+
+    void setId(uint16_t qid)
+    {
+      add_uint32(d_message, Field::id, ntohs(qid));
+    }
+
+    void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
+    {
+      protozero::pbf_writer pbf_question{d_message, static_cast<protozero::pbf_tag_type>(Field::question)};
+      encodeDNSName(pbf_question, d_buffer, static_cast<protozero::pbf_tag_type>(QuestionField::qName), qname);
+      pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qType), qtype);
+      pbf_question.add_uint32(static_cast<protozero::pbf_tag_type>(QuestionField::qClass), qclass);
+    }
+
+    void setMeta(const std::string& key, const std::unordered_set<std::string>& stringVal, const std::unordered_set<int64_t>& intVal)
+    {
+      protozero::pbf_writer pbf_meta{d_message, static_cast<protozero::pbf_tag_type>(Field::meta)};
+      pbf_meta.add_string(static_cast<protozero::pbf_tag_type>(MetaField::key), key);
+      protozero::pbf_writer pbf_meta_value{pbf_meta, static_cast<protozero::pbf_tag_type>(MetaField::value)};
+      for (const auto& str : stringVal) {
+        pbf_meta_value.add_string(static_cast<protozero::pbf_tag_type>(MetaValueField::stringVal), str);
+      }
+      for (const auto& val : intVal) {
+        pbf_meta_value.add_uint64(static_cast<protozero::pbf_tag_type>(MetaValueField::intVal), val);
+      }
+    }
+
+    void setEDNSSubnet(const Netmask& netmask, uint8_t mask)
+    {
+      encodeNetmask(static_cast<protozero::pbf_tag_type>(Field::originalRequestorSubnet), netmask, mask);
+    }
+
+    void setRequestorId(const std::string& req)
+    {
+      if (!req.empty()) {
+        add_string(d_message, Field::requestorId, req);
+      }
+    }
+
+    void setInitialRequestID(const boost::uuids::uuid& uniqueId)
+    {
+      add_bytes(d_message, Field::initialRequestId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+    }
+
+    void setDeviceId(const std::string& deviceId)
+    {
+      if (!deviceId.empty()) {
+        add_string(d_message, Field::deviceId, deviceId);
+      }
+    }
+
+    void setNewlyObservedDomain(bool nod)
+    {
+      add_bool(d_message, Field::newlyObservedDomain, nod);
+    }
+
+    void setDeviceName(const std::string& name)
+    {
+      if (!name.empty()) {
+        add_string(d_message, Field::deviceName, name);
+      }
+    }
+
+    void setFromPort(in_port_t port)
+    {
+      add_uint32(d_message, Field::fromPort, port);
+    }
+
+    void setToPort(in_port_t port)
+    {
+      add_uint32(d_message, Field::toPort, port);
+    }
+
+    void setWorkerId(uint64_t wid)
+    {
+      add_uint64(d_message, Field::workerId, wid);
+    }
+
+    void setPacketCacheHit(bool hit)
+    {
+      add_bool(d_message, Field::packetCacheHit, hit);
+    }
+
+    void setOutgoingQueries(uint32_t num)
+    {
+      add_uint32(d_message, Field::outgoingQueries, num);
+    }
+
+    void startResponse()
+    {
+      d_response = protozero::pbf_writer{d_message, static_cast<protozero::pbf_tag_type>(Field::response)};
+    }
+
+    void commitResponse()
+    {
+      d_response.commit();
+    }
+
+    void setResponseCode(uint8_t rcode)
+    {
+      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), rcode);
+    }
+
+    void setNetworkErrorResponseCode()
+    {
+      /* special code meaning 'network error', like a timeout */
+      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::rcode), 65536);
+    }
+
+    void setAppliedPolicy(const std::string& policy)
+    {
+      d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::appliedPolicy), policy);
+    }
+
+    void addPolicyTags(const std::unordered_set<std::string>& tags)
+    {
+      for (const auto& tag : tags) {
+        addPolicyTag(tag);
+      }
+    }
+
+    void addPolicyTag(const string& tag)
+    {
+      d_response.add_string(static_cast<protozero::pbf_tag_type>(ResponseField::tags), tag);
+    }
+
+    void setQueryTime(uint32_t sec, uint32_t usec)
+    {
+      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeSec), sec);
+      d_response.add_uint32(static_cast<protozero::pbf_tag_type>(ResponseField::queryTimeUsec), usec);
+    }
+
+    void addRRsFromPacket(const char* packet, size_t len, bool includeCNAME = false);
+    void addRR(const DNSName& name, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& blob);
+
+  protected:
+    void encodeComboAddress(protozero::pbf_tag_type type, const ComboAddress& address);
+    void encodeNetmask(protozero::pbf_tag_type type, const Netmask& subnet, uint8_t mask);
+    static void encodeDNSName(protozero::pbf_writer& pbf, std::string& buffer, protozero::pbf_tag_type type, const DNSName& name);
+
+    static void add_enum(protozero::pbf_writer& writer, Field type, int32_t value)
+    {
+      writer.add_enum(static_cast<protozero::pbf_tag_type>(type), value);
+    }
+
+    static void add_bool(protozero::pbf_writer& writer, Field type, bool value)
+    {
+      writer.add_bool(static_cast<protozero::pbf_tag_type>(type), value);
+    }
+
+    static void add_uint32(protozero::pbf_writer& writer, Field type, uint32_t value)
+    {
+      writer.add_uint32(static_cast<protozero::pbf_tag_type>(type), value);
+    }
+
+    static void add_uint64(protozero::pbf_writer& writer, Field type, uint64_t value)
+    {
+      writer.add_uint64(static_cast<protozero::pbf_tag_type>(type), value);
+    }
+
+    static void add_bytes(protozero::pbf_writer& writer, Field type, const char* data, size_t len)
+    {
+      writer.add_bytes(static_cast<protozero::pbf_tag_type>(type), data, len);
+    }
+
+    static void add_string(protozero::pbf_writer& writer, Field type, const std::string& str)
+    {
+      writer.add_string(static_cast<protozero::pbf_tag_type>(type), str);
+    }
+
+    // NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
+    std::string& d_buffer;
+    protozero::pbf_writer d_message;
+    protozero::pbf_writer d_response;
+    // NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
   };
 };
+};
 
 #endif /* DISABLE_PROTOBUF */
index a44c72110f5c74cfe79367de0f89d79d34155ece..5c20d3b9c5893edd9abd94c7fe50922d47477c47 100644 (file)
@@ -37,7 +37,7 @@ struct ProxyProtocolValue
   enum class Types : uint8_t { PP_TLV_ALPN = 0x01, PP_TLV_SSL = 0x20 };
 };
 
-static const size_t s_proxyProtocolMinimumHeaderSize = 16;
+static constexpr size_t s_proxyProtocolMinimumHeaderSize = 16;
 
 std::string makeLocalProxyHeader();
 std::string makeProxyHeader(bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
index 0d8c2d01c8184d70f7dc3ed2798f168c804e031d..6d14c0950481ddfd3bda7c563969bb2d15bd4277 100644 (file)
@@ -41,6 +41,7 @@
 /dnsmessage.pb.h
 /pdns-recursor.service
 /pdns-recursor@.service
+/pubsuffix.cc
 /lua.hpp
 /test-suite.log
 /testrunner.log
index a1a3ffc0b0d871aa6af4e0ee3d89ea809fb4e447..a6427ef7042eb8066fed328356b5db260637be60 100644 (file)
@@ -42,7 +42,7 @@ BUILT_SOURCES=htmlfiles.h \
        dnslabeltext.cc
 
 CLEANFILES = htmlfiles.h \
-       recursor.conf-dist recursor.yml-dist
+       recursor.yml-dist
 
 htmlfiles.h: incfiles ${srcdir}/html/* ${srcdir}/html/js/*
        $(AM_V_GEN)$(srcdir)/incfiles > $@.tmp
@@ -68,7 +68,6 @@ EXTRA_DIST = \
        lua_hpp.mk \
        malloctrace.cc malloctrace.hh \
        mkpubsuffixcc \
-       mtasker_fcontext.cc mtasker_ucontext.cc \
        NOTICE \
        opensslsigners.hh opensslsigners.cc \
        portsmplexer.cc \
@@ -365,6 +364,7 @@ testrunner_SOURCES = \
        test-rpzloader_cc.cc \
        test-secpoll_cc.cc \
        test-settings.cc \
+       test-sholder_hh.cc \
        test-signers.cc \
        test-syncres_cc.cc \
        test-syncres_cc.hh \
@@ -552,10 +552,7 @@ pubsuffix.cc: $(srcdir)/effective_tld_names.dat
        $(srcdir)/mkpubsuffixcc $< $@
 
 ## Config file
-sysconf_DATA = recursor.conf-dist recursor.yml-dist
-
-recursor.conf-dist: pdns_recursor
-       $(AM_V_GEN)./pdns_recursor --config=default > $@
+sysconf_DATA = recursor.yml-dist
 
 recursor.yml-dist: pdns_recursor
        dir=$$(mktemp -d) && touch "$$dir/recursor.yml" && ./pdns_recursor --config-dir="$$dir" --config=default 2> /dev/null > $@ && rm "$$dir/recursor.yml" && rmdir "$$dir"
index f80eab30c0dffcc45ba9be152e47fc77ae6780b3..7103ead6ff4b12ee8ba547807b4ee4b465b26ed6 100644 (file)
@@ -60,6 +60,15 @@ rec MODULE-IDENTITY
     REVISION "202306080000Z"
     DESCRIPTION "Added metrics for NOD and UDR events"
 
+    REVISION "202405230000Z"
+    DESCRIPTION "Added metrics for maximum chain length and weight"
+
+    REVISION "202408130000Z"
+    DESCRIPTION "Added metric for chain limits reached"
+
+    REVISION "202408280000Z"
+    DESCRIPTION "Added metric for too many incoming TCP connections"
+
     ::= { powerdns 2 }
 
 powerdns               OBJECT IDENTIFIER ::= { enterprises 43315 }
@@ -1250,6 +1259,38 @@ udrEvents OBJECT-TYPE
         "Count of UDR events"
     ::= { stats 148 }
 
+maxChainLength OBJECT-TYPE
+    SYNTAX Counter64
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "Maximum chain length"
+    ::= { stats 149 }
+
+maxChainWeight OBJECT-TYPE
+    SYNTAX Counter64
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "Maximum chain weight"
+    ::= { stats 150 }
+
+chainLimits OBJECT-TYPE
+    SYNTAX Counter64
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "Chain limits reached"
+    ::= { stats 151 }
+
+tcpOverflow OBJECT-TYPE
+    SYNTAX Counter64
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "Incoming TCP limits reached"
+    ::= { stats 152 }
+
 ---
 --- Traps / Notifications
 ---
@@ -1425,7 +1466,7 @@ recGroup OBJECT-GROUP
         zoneDisallowedNotify,
         nonResolvingNameserverEntries,
         maintenanceUSec,
-        maintenanceCalls,
+        maintenanceCount,
         authrcode0Count,
         authrcode1Count,
         authrcode2Count,
@@ -1445,7 +1486,11 @@ recGroup OBJECT-GROUP
         packetCacheContended,
         packetCacheAcquired,
         nodEvents,
-        udrEvents
+        udrEvents,
+        maxChainLength,
+        maxChainWeight,
+        chainLimits,
+        tcpOverflow
     }
     STATUS current
     DESCRIPTION "Objects conformance group for PowerDNS Recursor"
index 43813f2403f8284c1fd321c0a1352c4bc35b6c11..914f903777d0e4f24119a54584b45eb554877238 100644 (file)
@@ -51,22 +51,8 @@ AC_FUNC_STRERROR_R
 
 PDNS_CHECK_CLOCK_GETTIME
 
-BOOST_REQUIRE([1.42])
-
-# Check against flat_set header that requires boost >= 1.48
-BOOST_FIND_HEADER([boost/container/flat_set.hpp], [AC_MSG_NOTICE([boost::container::flat_set not available, will fallback to std::set])])
-
-# Boost Context was introduced in 1.51 (Aug 2012), but there was an immediate
-# API break in 1.52 (Nov 2012), so we only support that, and later.
-pdns_context_library=""
-AS_IF([test $boost_major_version -ge 152], [BOOST_CONTEXT([], [no])])
-AS_IF([test x"$boost_cv_lib_context" = "xyes"], [
-  pdns_context_library="Boost Context"
-], [
-  AC_CHECK_FUNCS([getcontext makecontext swapcontext], [pdns_context_library="System V ucontexts"])
-])
-AC_MSG_CHECKING([what context library to use for MTasker])
-AS_IF([test -n "$pdns_context_library"], [AC_MSG_RESULT([$pdns_context_library])], [AC_MSG_ERROR([neither boost::context nor System V ucontexts available])])
+BOOST_REQUIRE([1.54])
+BOOST_CONTEXT([], [yes])]
 
 PDNS_ENABLE_UNIT_TESTS
 PDNS_ENABLE_REPRODUCIBLE
@@ -283,5 +269,4 @@ AS_IF([test "x$HAVE_LIBCURL" != "xn"],
   [AC_MSG_NOTICE([libcurl: yes])],
   [AC_MSG_NOTICE([libcurl: no])]
 )
-AC_MSG_NOTICE([Context library: $pdns_context_library])
 AC_MSG_NOTICE([])
index 3f718be21cea64d37c5640867e0d823a33bba9e1..3e4da20b7bb66b9be1681d0ee5801714e0962b29 100644 (file)
@@ -10,13 +10,13 @@ We support older releases with critical updates for one year after the following
 Older releases are marked end of life and receive no updates at all.
 Pre-releases do not receive immediate security updates.
 
-The currently supported release train of the PowerDNS Recursor is 5.0.
+The currently supported release train of the PowerDNS Recursor is 5.1.
 
-PowerDNS Recursor 4.9 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.0 was released.
+PowerDNS Recursor 5.0 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.1 was released.
 
-PowerDNS Recursor 4.8 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 4.9 was released.
+PowerDNS Recursor 4.9 will only receive critical updates and will be End of Life one year after PowerDNS Recursor 5.0 was released.
 
-PowerDNS Recursor 4.0 through 4.7, 3.x, and 2.x are End of Life.
+PowerDNS Recursor 4.0 through 4.8, 3.x, and 2.x are End of Life.
 
 Note: Users with a commercial agreement with PowerDNS.COM BV or Open-Xchange
 can receive extended support for releases which are End Of Life. If you are
@@ -34,10 +34,14 @@ That means that we ask you to reproduce potential issues on the latest minor rel
      - Release date
      - Critical-Only updates
      - End of Life
+   * - 5.1
+     - July 10 2024
+     - ~ February 2025
+     - ~ February 2026
    * - 5.0
      - January 10 2024
-     - ~ July 2024
-     - ~ July 2025
+     - July 10 2024
+     - July 10 2025
    * - 4.9
      - June 30 2023
      - January 10 2024
@@ -45,7 +49,7 @@ That means that we ask you to reproduce potential issues on the latest minor rel
    * - 4.8
      - December 12 2022
      - June 30 2023
-     - June 30 2024
+     - EOL June 30 2024
    * - 4.7
      - May 30 2022
      - December 12 2022
index 74a2e30535ee413b024ea4ce78c7fc64c446bbb8..0abe2fe1136810a927207a6ea1d51393f7320ef3 100644 (file)
@@ -86,3 +86,7 @@ With versions older than 4.8, there is another detail: after refreshing the root
 For example, in the default setup the root name servers are called ``[a-m].root-servers.net``, so the :program:`Recursor` will resolve the name servers of the ``.net`` domain.
 This is needed to correctly determine zone cuts to be able to decide if the ``.root-servers.net`` domain is DNSSEC protected. Newer versions solve this by querying the needed information top-down.
 
+Starting with version 5.0.0, enabling :ref:`setting-allow-no-rd` allows for queries without the recursion desired bit to be answered from cache.
+Older versions of the ``dig`` program provided by ISC do not set the RD bit on the initial ``+trace`` query causing it to sometimes fail to perform a ``+trace`` when asking a freshly restarted :program:`Recursor` despite the :ref:`setting-allow-no-rd` option being set.
+This is because there is a short while after restarting that the cache has no authoritative data on the root, so it will answer with an NODATA (NOERROR and no answer records) in that period for RD=0 queries asking for the root name servers.
+For ``dig`` this has been fixed in `BIND 9.15.1 <https://gitlab.isc.org/isc-projects/bind9/-/issues/1028>`_ by setting the RD bit.
index 7827ff2f6a24cfbd5539cbd0dcc9b997f271e988..f9e462b11233dc4964f54881f78a5303caf9eca9 100644 (file)
@@ -36,7 +36,7 @@ Starting with version 5, a Rust compiler is needed.
 
 By default, the :program:`Recursor` requires the following libraries and headers:
 
-* `Boost <http://boost.org/>`_ 1.35 or newer
+* `Boost <http://boost.org/>`_ 1.54 or newer
 * `Lua <http://www.lua.org/>`_ 5.1+ or `LuaJit <http://luajit.org/>`_
 * `OpenSSL <https://openssl.org>`_
 * For :program:`Recursor` version 5 and higher, `cargo <https://www.rust-lang.org/tools/install>`_ version 1.64 or newer.
index f3a2fde48429c110f3f3f2e1e2c327450147482e..10532bae97a08c8d5c2dc722e1e6383b40f702a1 100644 (file)
@@ -681,7 +681,7 @@ Changelogs for 4.3.x
     :pullreq: 8047
     :tickets: 8008
 
-    Another time sensistive test fixed with a fixednow construct.
+    Another time sensitive test fixed with a fixednow construct.
 
   .. change::
     :tags: New Features
index a6e6ddb14257d45346992856275595763d2a574a..7516aa84f42aac29c534e4c07ab9b10fdeb09c0a 100644 (file)
@@ -1,6 +1,63 @@
 Changelogs for 4.9.X
 ====================
 
+.. changelog::
+  :version: 4.9.8
+  :released: 23rd of July 2024
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14503
+    :tickets: 14499
+
+    Optimize processing of additionals.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14483
+    :tickets: 14471
+
+    Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14480
+    :tickets: 14404
+
+    Yahttp router: avoid unsigned underflow in route().
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14413
+    :tickets: 14400
+
+    Switch el7 builds to Oracle Linux 7.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14416
+    :tickets: 14359
+
+    dns.cc: use pdns::views::UnsignedCharView.
+
+.. changelog::
+  :version: 4.9.7
+  :released: 3rd of July 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14380
+    :tickets: 14373
+
+    Remove potential double SOA records if the target of a dns64 name is NODATA.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14352
+    :tickets: 14346
+
+    Fix TCP case for policy tags to not produce cached tags in protobuf messages.
+
 .. changelog::
   :version: 4.9.6
   :released: 14th of May 2024
index bad1a8108b609aeaf878d6d2d06b4c2eeb22839c..fb59557cf5e936f3b2bb58218f3bc3c93e27ee50 100644 (file)
@@ -3,6 +3,88 @@ Changelogs for 5.0.X
 
 Before upgrading, it is advised to read the :doc:`../upgrade`.
 
+.. changelog::
+   :version: 5.0.8
+   :released: 23rd of July 2024
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14502
+    :tickets: 14499
+
+    Limit the number of async tasks pushed to resolve NS names and optimize processing of additionals.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14482
+    :tickets: 14471
+
+    Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14479
+    :tickets: 14404
+
+    Yahttp router: avoid unsigned underflow in route().
+
+  .. change::
+    :tags: Improvements.
+    :pullreq: 14412
+    :tickets: 134400
+
+    Switch el7 builds to Oracle Linux 7.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14415
+    :tickets: 14359
+
+    dns.cc: use pdns::views::UnsignedCharView.
+
+.. changelog::
+   :version: 5.0.7
+   :released: 3rd of July 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14379
+    :tickets: 14373
+
+    Remove potential double SOA records if the target of a dns64 name is NODATA.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14351
+    :tickets: 14346
+
+    Fix TCP case for policy tags to not produce cached tags in protobuf messages.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14348
+    :tickets: 14340
+
+    Count substituted remote in case of proxy protocol.
+
+.. changelog::
+   :version: 5.0.6
+   :released: 5th of June 2024
+
+  .. change::
+    :tags:  Improvements
+    :pullreq: 14223
+    :tickets: 14197
+
+    YaHTTP: Enforce max # of request fields and max request line size.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14222
+    :tickets: 14185
+
+    Report error and adjust max-mthreads when linux map limit (vm.max_map_count) is too low to accommodate resource usage under load.
+
 .. changelog::
    :version: 5.0.5
    :released: 14th of May 2024
index 71abe192aa7931e7e750b361908a66de3e07a397..6ed78884fbc38290c794557e8031d4932d731f79 100644 (file)
@@ -3,6 +3,166 @@ Changelogs for 5.1.X
 
 Before upgrading, it is advised to read the :doc:`../upgrade`.
 
+.. changelog::
+   :version: 5.1.1
+   :released: 23rd of July 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14516
+    :tickets: 14514
+
+    Fix maintenanceCalls vs maintenanceCount in SNMP MIB.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14501
+    :tickets: 14499
+
+    Limit the number of async tasks pushed to resolve NS names and optimizer processing of additionals.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14481
+    :tickets: 14471
+
+    Dump right SOA into dumpFile and report non-relative SOA for includeSOA=true.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14478
+    :tickets: 14404
+
+    Yahttp router: avoid unsigned underflow in match().
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14477
+    :tickets: 14459
+
+    Move default Docker config to YAML.
+
+.. changelog::
+  :version: 5.1.0
+  :released: 10th of July 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14435
+
+    Fix typo in log message.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14402
+    :tickets: 14400
+
+    Switch el7 builds to Oracle Linux 7
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14389
+    :tickets: 14384
+
+    Keep Lua config in Debian/Ubuntu package as existing setups might use it, even though a fresh one does not.
+
+.. changelog::
+  :version: 5.1.0-rc1
+  :released: 25th of June 2024
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14373
+    :tickets: 14362
+
+    Don't send double SOA record in the case of a dns64 CNAME that does not resolve.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14265,14374
+    :tickets: 13935
+
+    Allow recursor.conf file to contain YAML to ease transition to YAML config.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14318
+
+    Add nsName into outgoing protobuf request/response messages.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14359
+    :tickets: 14356
+
+    dns.cc: use pdns::views::UnsignedCharView.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14346
+    :tickets: 13021
+
+    Fix TCP case for policy tags set by gettag(_ffi).
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 14340
+
+    Fix client remotes count when using proxy protocol.
+
+  .. change::
+    :tags:  Improvements
+    :pullreq: 14312
+
+    Do not add UDR field to outgoingProtobuf answer messages
+
+  .. change::
+    :tags:  Improvements
+    :pullreq: 14275
+
+    Add options for ignoring domains for UDR purposes (Ensar Sarajčić).
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14309
+
+    Make max CNAME chain length handled settable, previously fixed at 10.
+
+.. changelog::
+  :version: 5.1.0-beta1
+  :released: 6th of June 2024
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14257
+    :tickets: 13020
+
+    Add a few more fields to the protobuf messages.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14221,14258
+
+    Handle authoritative servers slow to respond when load is high better.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14206
+
+    Be a bit more strict with respect to positive answers expanded from a wildcard.
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 14111
+
+    Extra export types for protobuf messages.
+
+ .. change::
+    :tags: Improvements
+    :pullreq: 14268,14259,14260,14262
+
+    Various code cleanups and Coverity prompted fixes.
+
 .. changelog::
   :version: 5.1.0-alpha1
   :released: 15th of May 2024
diff --git a/pdns/recursordist/docs/generate-man-pages.py b/pdns/recursordist/docs/generate-man-pages.py
new file mode 120000 (symlink)
index 0000000..c19dc3b
--- /dev/null
@@ -0,0 +1 @@
+../../../docs/generate-man-pages.py
\ No newline at end of file
index e478317da4f6b07b723eca4f64c98e14860d2328..456e09f8a9bf7e250d410a0ddf33d5d21daf0c1e 100644 (file)
@@ -22,6 +22,7 @@ Comments are per-RRset.
   :property [RRSet] rrsets: RRSets in this zone
   :property [str] servers: For zones of type "Forwarded", addresses to send the queries to
   :property bool recursion_desired: For zones of type "Forwarded", Whether or not the RD bit should be set in the query
+  :property bool notify_allowed: For zones of type "Forwarded", Whether or not to permit incoming NOTIFY to wipe cache for the domain
 
 To properly process new zones, the following conditions must
 be true:
index 7cc6b66e8db989f4850e14fd50051723bb4cbe20..04097b0d88c71a3bb00fe0de6f8a0f096fcbf1bc 100644 (file)
@@ -44,7 +44,7 @@ Protobuf export to a server is enabled using the ``protobufServer()`` directive:
 
   .. versionchanged:: 5.1.0
 
-     Added support for the HTTPS, SVCB and APTR record types.
+     Added support for the HTTPS, SVCB and NAPTR record types.
 
 .. function:: protobufServer(server [[[[[[[, timeout=2], maxQueuedEntries=100], reconnectWaitTime=1], maskV4=32], maskV6=128], asyncConnect=false], taggedOnly=false])
 
@@ -100,7 +100,7 @@ While :func:`protobufServer` only exports the queries sent to the recursor from
 
   .. versionchanged:: 5.1.0
 
-     Added support for the HTTPS, SVCB and APTR records types.
+     Added support for the HTTPS, SVCB and NAPTR records types.
 
 .. function:: outgoingProtobufServer(server [[[[, timeout=2], maxQueuedEntries=100], reconnectWaitTime=1], asyncConnect=false])
 
@@ -140,9 +140,10 @@ The recursor must have been built with configure ``--enable-dnstap`` to make thi
   * ``logQueries=true``: bool - log outgoing queries
   * ``logResponses=true``: bool - log incoming responses
 
-  The following options apply to the settings of the framestream library. Refer to the documentation of that
-  library for the default values, exact description and allowable values for these options.
-  For all these options, absence or a zero value has the effect of using the library-provided default value.
+  The following options apply to the settings of the `framestream library
+  <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default
+  values, exact description and allowable values for these options. For all these options, absence or a zero
+  value has the effect of using the library-provided default value.
 
   * ``bufferHint=0``: unsigned
   * ``flushTimeout=0``: unsigned
@@ -169,9 +170,10 @@ The recursor must have been built with configure ``--enable-dnstap`` to make thi
   * ``logNODs=true``: bool - log NODs
   * ``logUDRs=false``: bool - log UDRs
 
-  The following options apply to the settings of the framestream library. Refer to the documentation of that
-  library for the default values, exact description and allowable values for these options.
-  For all these options, absence or a zero value has the effect of using the library-provided default value.
+  The following options apply to the settings of the `framestream library
+  <https://github.com/farsightsec/fstrm>`. Refer to the documentation of that library for the default
+  values, exact description and allowable values for these options. For all these options, absence or a zero
+  value has the effect of using the library-provided default value.
 
   * ``bufferHint=0``: unsigned
   * ``flushTimeout=0``: unsigned
index 903915455c7a6ed201923c09244425d98fd70f5f..c295977dafb6f13a300c6352ff97281893f8b5da 100644 (file)
@@ -231,7 +231,8 @@ The DNSQuestion object contains at least the following fields:
 
   .. attribute:: DNSQuestion.tag
 
-      The packet-cache tag set via :func:`gettag`, or 0 if it has not been set.
+      The packetcache tag set via :func:`gettag` or :func:`gettag_ffi`.
+      Default tag is zero. Internally to the recursor, the tag is interpreted as an unsigned 32-bit integer.
 
   .. attribute:: DNSQuestion.queryTime
 
index 1200019244b39eccf657e5e32aa7d47f1173e0d5..f6dcd685115e78e17c0e51ff6277844b015dae28 100644 (file)
@@ -72,10 +72,13 @@ Interception Functions
 
       The ``proxyprotocolvalues`` parameter was added.
 
-    The ``gettag`` function is invoked when the Recursor attempts to discover in which packetcache an answer is available.
+    The :func:`gettag` function is invoked when :program:`Recursor` attempts to discover in which packetcache an answer is available.
 
-    This function must return an integer, which is the tag number of the packetcache.
-    In addition to this integer, this function can return a table of policy tags.
+    This function must return an unsigned 32-bit integer, which is the tag number of the packetcache.
+    The tag is used to partition the packet cache. The default tag (when :func:`gettag` is not defined) is zero.
+    If :func:`gettag` throws an exception, the zero tag is used.
+
+    In addition to the tag, this function can return a table of policy tags and a few more values to be passed to the resolving process.
     The resulting tag number can be accessed via :attr:`dq.tag <DNSQuestion.tag>` in the :func:`preresolve` hook, and the policy tags via :meth:`dq:getPolicyTags() <DNSQuestion:getPolicyTags>` in every hook.
 
     .. versionadded:: 4.1.0
@@ -94,7 +97,7 @@ Interception Functions
 
     The tagged packetcache can e.g. be used to answer queries from cache that have e.g. been filtered for certain IPs (this logic should be implemented in :func:`gettag`).
     This ensure that queries are answered quickly compared to setting :attr:`dq.variable <DNSQuestion.variable>` to true.
-    In the latter case, repeated queries will pass through the entire Lua script.
+    In the latter case, repeated queries will not be found in the packetcache and pass through the entire resolving process, and all relevant Lua hooks wil be called.
 
     :param ComboAddress remote: The sender's IP address
     :param Netmask ednssubnet: The EDNS Client subnet that was extracted from the packet
@@ -109,15 +112,18 @@ Interception Functions
 
 .. function:: gettag_ffi(param) -> optional Lua object
 
-    .. versionadded:: 4.1.2
+   .. versionadded:: 4.1.2
 
-    .. versionchanged:: 4.3.0
+   .. versionchanged:: 4.3.0
 
       The ability to craft answers was added.
 
-    This function is the FFI counterpart of the :func:`gettag` function, and offers the same functionality.
-    It accepts a single, scalable parameter which can be accessed using :doc:`FFI accessors <ffi>`.
-    Like the non-FFI version, it has the ability to set a tag for the packetcache, policy tags, a routing tag, the :attr:`DNSQuestion.requestorId` and :attr:`DNSQuestion.deviceId` values and to fill the :attr:`DNSQuestion.data` table. It also offers ways to mark the answer as variable so it's not inserted into the packetcache, to set a cap on the TTL of the returned records, and to generate a response by adding records and setting the RCode. It can also instruct the recursor to do a proper resolution in order to follow any `CNAME` records added in this step.
+   This function is the FFI counterpart of the :func:`gettag` function, and offers the same functionality.
+   It accepts a single parameter which can be accessed and modified using :doc:`FFI accessors <ffi>`.
+
+   Like the non-FFI version, it has the ability to set a tag for the packetcache, policy tags, a routing tag, the :attr:`DNSQuestion.requestorId` and :attr:`DNSQuestion.deviceId` values and to fill the :attr:`DNSQuestion.data` table. It also offers ways to mark the answer as variable so it's not inserted into the packetcache, to set a cap on the TTL of the returned records, and to generate a response by adding records and setting the RCode. It can also instruct the recursor to do a proper resolution in order to follow any `CNAME` records added in this step.
+
+   If this function does not set the tag or an exception is thrown, the zero tag is assumed. 
 
 .. function:: prerpz(dq) -> bool
 
index 6c20957165d40a6a2d8583e7b2e16dd2c3435ef1..07811ce8ab23c6a04ba81963d2e228088e0d2767 100644 (file)
@@ -110,10 +110,8 @@ Sending metrics over SNMP
 
 The recursor can export statistics over SNMP and send traps from :doc:`Lua <lua-scripting/index>`, provided support is compiled into the Recursor and :ref:`setting-snmp-agent` set.
 
-MIB
-^^^
+For the details of all values that can be retrieved using SNMP, see the `SNMP MIB <https://github.com/PowerDNS/pdns/blob/master/pdns/recursordist/RECURSOR-MIB.txt>`_.
 
-.. literalinclude:: ../RECURSOR-MIB.txt
 
 .. _metricnames:
 
@@ -264,6 +262,10 @@ case-mismatches
 ^^^^^^^^^^^^^^^
 counts the number of mismatches in character   case since starting
 
+chain-limits
+^^^^^^^^^^^^
+counts the number of times a chain limit (size or age) has been hit
+
 chain-resends
 ^^^^^^^^^^^^^
 number of queries chained to existing outstanding   query
@@ -390,8 +392,8 @@ dnssec-result-bogus-missing-negative-indication
 
 number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records.
 
-dnssec-result-bogus-signature-no-yet-valid
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+dnssec-result-bogus-signature-not-yet-valid
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 .. versionadded:: 4.4.2
 
 number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid.
@@ -535,6 +537,14 @@ max-cache-entries
 ^^^^^^^^^^^^^^^^^
 currently configured maximum number of cache entries
 
+max-chain-length
+^^^^^^^^^^^^^^^^
+maximum chain length
+
+max-chain-weight
+^^^^^^^^^^^^^^^^
+maximum chain weight. The weight of a chain of outgoing queries is the product of the number of chained queries by the size of the response received from the external authoritative server. 
+
 max-packetcache-entries
 ^^^^^^^^^^^^^^^^^^^^^^^
 currently configured maximum number of packet cache entries
@@ -746,6 +756,12 @@ taskqueue-size
 
 number of tasks currently in the taskqueues
 
+.. _stat-tcp-overflow:
+
+tcp-overflow
+^^^^^^^^^^^^
+number of times an incoming TCP connection was closed immediately because there were too many open connections already
+
 .. _stat-tcp-client-overflow:
 
 tcp-client-overflow
index 2da15412ad1b6356425e16cef6de417f99f44518..92e7ee5faa9654f5b102ce06cd8908e926ffce91 100644 (file)
@@ -19,7 +19,7 @@ NOD is disabled by default, and must be enabled through the use of the following
 
 Once enabled the recursor will keep track of previously seen domains using the SBF data structure, which is periodically persisted to the directory specified in the ``new-domain-history-dir``, which defaults to /var/lib/pdns-recursor/nod.
 
-Administrators may wish to prevent certain domains or subdomains from ever triggering the NOD algorithm, in which case those domains must be added to the ``new-domain-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a newly observed domain.
+Administrators may wish to prevent certain domains or subdomains from ever triggering the NOD algorithm, in which case those domains must be added to the ``new-domain-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a newly observed domain. It is also possible to use ``new-domain-ignore-list-file`` to read a file with ignored domains, one domain per line.
 
 There are several ways to receive the information about newly observed domains:
 
@@ -59,6 +59,8 @@ The data is persisted to /var/lib/pdns-recursor/udr by default, which can be cha
 
 The SBF (which is maintained separately per recursor thread) cell size defaults to 67108864, which can be changed using the setting ``unique-response-db-size``. The same caveats regarding FPs/FNs apply as for NOD.
 
+Similarly to NOD, administrators may wish to prevent certain domains or subdomains from ever triggering the UDR algorithm, in which case those domains must be added to the ``udr-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a new unique domain response. It is also possible to use ``udr-ignore-list-file`` to read a file with ignored domains, one domain per line.
+
 Similarly to NOD, unique domain responses can be tracked using several mechanisms:
 
 Logging
index ac4362d1faa9cd209dac510bd30b9d18e3a0c25d..fcfd67157fc1505ca97cc22f29efb6eff4fd255c 100644 (file)
@@ -77,18 +77,24 @@ If your systems shows great imbalance in the number of queries processed per thr
 MTasker and MThreads
 --------------------
 
-PowerDNS Recursor uses a cooperative multitasking in userspace called ``MTasker``, based either on ``boost::context`` if available, or on ``System V ucontexts`` otherwise. For maximum performance, please make sure that your system supports ``boost::context``, as the alternative has been known to be quite slower.
+PowerDNS :program:`Recursor` uses a cooperative multitasking in userspace called ``MTasker``, based either on ``boost::context`` if available, or on ``System V ucontexts`` otherwise. For maximum performance, please make sure that your system supports ``boost::context``, as the alternative has been known to be quite slower.
 
 The maximum number of simultaneous MTasker threads, called ``MThreads``, can be tuned via :ref:`setting-max-mthreads`, as the default value of 2048 might not be enough for large-scale installations.
 This setting limits the number of mthreads *per physical (Posix) thread*.
 The threads that create mthreads are the distributor and worker threads.
 
-When a ``MThread`` is started, a new stack is dynamically allocated for it on the heap. The size of that stack can be configured via the :ref:`setting-stack-size` parameter, whose default value is 200 kB which should be enough in most cases.
+When a ``MThread`` is started, a new stack is dynamically allocated for it. The size of that stack can be configured via the :ref:`setting-stack-size` parameter, whose default value is 200 kB which should be enough in most cases.
 
 To reduce the cost of allocating a new stack for every query, the recursor can cache a small amount of stacks to make sure that the allocation stays cheap. This can be configured via the :ref:`setting-stack-cache-size` setting.
 This limit is per physical (Posix) thread.
 The only trade-off of enabling this cache is a slightly increased memory consumption, at worst equals to the number of stacks specified by :ref:`setting-stack-cache-size` multiplied by the size of one stack, itself specified via :ref:`setting-stack-size`.
 
+Linux limits the number of memory mappings a process can allocate by the ``vm.max_map_count`` kernel parameter.
+A single ``MThread`` stack can take up to 3 memory mappings.
+Starting with version 4.9, it is advised to check and if needed update the value of ``sysctl vm.max_map_count`` to make sure that the :program:`Recursor` can allocate enough stacks under load; suggested value is at least ``4 * (threads + 2) * max-mthreads``.
+Some Linux distributions use a default value of about one million, which should be enough for most configurations.
+Other distributions default to 64k, which can be too low for large setups.
+
 Performance tips
 ----------------
 
@@ -104,6 +110,32 @@ When running with >3000 queries per second, and running Linux versions prior to
 This is solved by rebooting with ``clock=tsc`` or upgrading to a 2.6.17 kernel.
 This is relevant if dmesg shows ``Using pmtmr for high-res timesource``.
 
+Memory usage
+------------
+
+:program:`Recursor` keeps all the data it needs in memory.
+The default configuration uses a little more than 1GB when the caches are full.
+Depending on configuration, memory usage can amount to many gigabytes for a large installation.
+
+.. warning::
+   Avoid swapping. The memory access patterns of :program:`Recursor` are random. This means
+   that it will cause trashing (the OS spending lots of time pulling in and writing out memory
+   pages) if :program:`Recursor` uses more physical memory than available and performance will be severely impacted.
+
+Below the memory usage observed for a specific test case are described.
+Please note that depending on OS, version of system libraries, version of the :program:`Recursor`, features used and usage patterns these numbers may vary.
+Test and observe your system to learn more about the memory requirements specific to your case.
+
+The most important subsystems that use memory are:
+
+- The packet cache. The amount of memory used in a test case was about 500 bytes per entry
+- The record cache. The amount of memory used in a test case was about 850 bytes per entry
+- Authoritative zones loaded. Memory usage is dependent on the size and number loaded.
+- RPZ zones loaded. Memory usage is dependent on the size and number loaded.
+- NOD DBs. Memory usage is dependent on specific settings of this subsystem.
+
+An estimate for the memory used by its caches for a :program:`Recursor` having 2 million record cache entries and 1 million packet cache entries is ``2e6 * 850 * + 1e6 * 500 = about 2GB``.
+
 Connection tracking and firewalls
 ---------------------------------
 
index edeb1b14c5973f590457ce02839e80d4cf22c5b2..28061214ebf0024f2ce8956dd4e5cf4304aec3e2 100644 (file)
@@ -1,5 +1,5 @@
 #
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
 # by the following command:
 #
 #    pip-compile --generate-hashes requirements.in
@@ -14,9 +14,9 @@ babel==2.14.0 \
     --hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
     --hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
     # via sphinx
-certifi==2024.2.2 \
-    --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
-    --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
+certifi==2024.7.4 \
+    --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+    --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
     # via requests
 changelog==0.5.8 \
     --hash=sha256:43b21840874130666b7534b76b402bbb914f8c9c413d5ea9d45850ca4767dafb \
@@ -261,9 +261,9 @@ sphinxcontrib-websupport==1.2.4 \
     --hash=sha256:4edf0223a0685a7c485ae5a156b6f529ba1ee481a1417817935b20bde1956232 \
     --hash=sha256:6fc9287dfc823fe9aa432463edd6cea47fa9ebbf488d7f289b322ffcfca075c7
     # via sphinx
-urllib3==2.2.0 \
-    --hash=sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20 \
-    --hash=sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224
+urllib3==2.2.2 \
+    --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+    --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
     # via requests
 
 # WARNING: The following packages were not pinned, but pip requires them to be
index 19473ad88100d11ba97e10118cb63e67aee33187..a586164155b2aa128f15042c84f6cfd50a335fef 100644 (file)
@@ -56,7 +56,7 @@ To log only info messages, use ``local0.=info``
 
 Cache Management
 ----------------
-Sometimes a domain fails to resolve due to an error on the domain owner's end, or records for your own domain have updated and you want your users to immediatly see them without waiting for the TTL to expire.
+Sometimes a domain fails to resolve due to an error on the domain owner's end, or records for your own domain have updated and you want your users to immediately see them without waiting for the TTL to expire.
 The :doc:`rec_control <manpages/rec_control.1>` tool can be used to selectively wipe the cache.
 
 To wipe all records for the exact name 'www.example.com'::
@@ -111,4 +111,97 @@ Do not forget to disable tracing after diagnosis is done::
 
   rec_control trace-regex
 
-
+Logging details of queries and answers
+--------------------------------------
+
+In some cases a tracing provides too much information, and we want to follow what the recursor is doing on a higher level.
+By setting :ref:`setting-yaml-logging.quiet` to ``true`` the recursor will produce a log line for each client query received and answered.
+Be aware that this causes overhead and should not be used in a high query-per-second production environment::
+
+    Jul 09 09:08:31 msg="Question" subsystem="syncres" level="0" prio="Info" tid="4" ts="1720508911.919" ecs="" mtid="1" proto="udp" qname="www.example.com" qtype="A" remote="127.0.0.1:54573"
+
+    Jul 09 09:08:32 msg="Answer" subsystem="syncres" level="0" prio="Info" tid="4" ts="1720508912.549" additional="1" answer-is-variable="0" answers="1" dotout="0" ecs="" into-packetcache="1" maxdepth="3" mtid="1" netms="617.317000" outqueries="13" proto="udp" qname="www.example.com" qtype="A" rcode="0" rd="1" remote="127.0.0.1:54573" tcpout="0" throttled="0" timeouts="0" totms="627.060000" validationState="Secure"
+
+When ``quiet`` is set to ``false``, the following keys and values are logged for questions and answers not
+answered from the packet cache.
+Refer to :doc:`appendices/structuredlogging` for more details on the common keys used for structured logging messages.
+Note that depending on record cache content a single client query can result into multiple queries to authoritative servers.
+If the exact answer is available from the record cache no outgoing queries are needed.
+
++-------------------------------------------------------------------------------------------+
+|                         **Keys common to Questions and Answers**                          |
++-----------------------+-----------------------------+-------------------------------------+
+| **Key**               | **Description**             | **Remarks**                         |
++-----------------------+-----------------------------+-------------------------------------+
+|``ecs``                |Client ECS info              |Filled in if enabled                 |
++-----------------------+-----------------------------+-------------------------------------+
+|``proto``              |Protocol used by client      |``udp`` or ``tcp``                   |
++-----------------------+-----------------------------+-------------------------------------+
+|``qname``              |Query name                   |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``qtype``              |Query type                   |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``remote``             |Client address               |IP:port combination                  |
++-----------------------+-----------------------------+-------------------------------------+
+|                               **Keys specific to Answers**                                |
++-----------------------+-----------------------------+-------------------------------------+
+|``additional``         |Number of additional records |                                     |
+|                       |in answer                    |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``answer-is-variable`` |Is answer marked variable by |e.g. ECS dependent answers           |
+|                       |recursor?                    |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``answers``            |Number of answer records in  |                                     |
+|                       |answer                       |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``dotout``             |Number of outgoing DoT       |                                     |
+|                       |queries sent to authoritative|                                     |
+|                       |servers to resolve answer    |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``into-packetcache``   |Is the answer being stored   |Variable answers (as determined by   |
+|                       |into the packetcache?        |the recursor or marked as such by Lua|
+|                       |                             |code) will not be put into the packet|
+|                       |                             |cache                                |
++-----------------------+-----------------------------+-------------------------------------+
+|``maxdepth``           |Depth of recursion needed to |Some queries need resolving multiple |
+|                       |resolve answer               |targets, e.g. to find the right      |
+|                       |                             |delegation or answers containing     |
+|                       |                             |CNAMEs                               |
++-----------------------+-----------------------------+-------------------------------------+
+|``netms``              |Time spent waiting for       |                                     |
+|                       |answers from authoritative   |                                     |
+|                       |servers                      |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``outqueries``         |Total queries sent to        |A single client query can cause      |
+|                       |authoritative servers        |multiple queries to authoritative    |
+|                       |                             |servers, depending on record cache   |
+|                       |                             |content and the query itself.        |
++-----------------------+-----------------------------+-------------------------------------+
+|``rcode``              |Result code                  |If no rcode is available (e.g. in the|
+|                       |                             |case of timeouts) this value can be  |
+|                       |                             |negative                             |
++-----------------------+-----------------------------+-------------------------------------+
+|``rd``                 |Did the client set the       |                                     |
+|                       |Recursion Desired DNS Header |                                     |
+|                       |flag?                        |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``tcpout``             |Number of outgoing TCP       |                                     |
+|                       |queries sent to authoritative|                                     |
+|                       |servers to resolve answer    |                                     |
+|                       |                             |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``throttled``          |Number of potential outgoing |If a target is throttled, the        |
+|                       |queries **not** sent out     |recursor will try another suitable   |
+|                       |because the target was marked|authoritative server (if available)  |
+|                       |as unreliable by previous    |                                     |
+|                       |interactions                 |                                     |
+|                       |                             |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``timeouts``           |Number of outgoing queries   |                                     |
+|                       |that timed out               |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``totms``              |Total time spent resolving   |                                     |
++-----------------------+-----------------------------+-------------------------------------+
+|``validationState``    |The DNSSEC status of the     |                                     |
+|                       |answer                       |                                     |
++-----------------------+-----------------------------+-------------------------------------+
index 08da067908e75faf342cba840a3e646a092ddde3..70c33f53e808879ae41fd0e768c94b4c1e30c1e0 100644 (file)
@@ -4,8 +4,35 @@ Upgrade Guide
 Before upgrading, it is advised to read the :doc:`changelog/index`.
 When upgrading several versions, please read **all** notes applying to the upgrade.
 
-5.0.5 to 5.1.0 and master
--------------------------
+5.1.0 to master
+----------------
+
+Changed behaviour
+-----------------
+The way :ref:`setting-yaml-incoming.max_tcp_clients` is enforced has changed.
+If there are too many incoming TCP connections, new connections will be accepted but then closed immediately.
+Previously, excess connections would linger in the OS listen queue until timeout or until processing of incoming TCP connections resumed due to the number of connections being processed dropping below the limit.
+There is a new metric ``tcp-overflow`` that counts the connections closed immediately.
+
+
+5.0.6 to 5.1.0
+--------------
+
+The recursor.conf configuration file may contain YAML configuration syntax and new installs using our packages from repo.powerdns.com will install a configuration file using YAML syntax.
+Note to third-party package maintainers: please start doing the same.
+
+.. warning::
+
+   If you are using the default *unmodified* ``recursor.conf`` from a previous release, it will be overwritten by an equivalent ``recursor.conf`` in YAML format by most packaging tools.
+   If you *also* have local setting files in the include directory, these are now expected to be in YAML format as well, because the format of the included files must be the same as the format of the main ``recursor.conf``.
+   This has the consequence that the previously included files will not be processed after the upgrade.
+   To work around this issue, either:
+
+   - modify the ``recursor.conf`` before upgrading so it does not get overwritten by the upgrade,
+   - copy back the original old-style ``recursor.conf`` after upgrading,
+   - or change the format of the existing included files into YAML and make sure their names have the ``.yml`` suffix.
+
+   A *modified* ``recursor.conf`` file will not be overwritten by an upgrade.
 
 New settings
 ^^^^^^^^^^^^
@@ -16,6 +43,10 @@ New settings
 - The :ref:`setting-system-resolver-ttl` setting has been introduced to set the TTL of the system resolver. The system resolver can be used to resolve forwarding names.
 - The :ref:`setting-system-resolver-interval` setting has been introduced to set the interval of resolve checks done by the system resolver.
 - The :ref:`setting-system-resolver-self-resolve-check` setting has been introduced to disable to discovery of self-resolving configurations.
+- The :ref:`setting-max-chain-length` setting has been introduced to limit the maximum number of queries that can be attached to an outgoing request chain.
+- The :ref:`setting-max-cnames-followed` setting has been introduced to limit the length of CNAME chains followed. Previously this limit was fixed at 10.
+- The :ref:`setting-new-domain-ignore-list-file`, :ref:`setting-unique-response-ignore-list` and  :ref:`setting-unique-response-ignore-list-file` settings have been introduced to filter names reported by the NOD and UDR subsystems.
+
 
 Changed settings
 ^^^^^^^^^^^^^^^^
@@ -23,6 +54,13 @@ Changed settings
 - The :ref:`setting-max-qperq` default value has been lowered to 50, and the qname-minimization special case has been removed.
 - Disabling :ref:`setting-structured-logging` is no longer supported.
 - The :ref:`setting-structured-logging-backend` setting has gained the possibility to request JSON formatted output of structured logging information.
+
+5.0.5 to 5.0.6
+--------------
+
+Changed settings
+^^^^^^^^^^^^^^^^
+
 - The :ref:`setting-max-mthreads` setting will be adjusted to a lower value if the value of ``sysctl vm.max_map_count`` is too low to support the maximum number of mthread stacks. In this case :program:`Recursor` logs an error message including the suggested value of ``vm.max_map_count`` to not cause lowering of :ref:`setting-max-mthreads`.
 
 5.0.4 to 5.0.5
diff --git a/pdns/recursordist/ext/arc4random/meson.build b/pdns/recursordist/ext/arc4random/meson.build
new file mode 120000 (symlink)
index 0000000..fc30722
--- /dev/null
@@ -0,0 +1 @@
+../../../../ext/arc4random/meson.build
\ No newline at end of file
diff --git a/pdns/recursordist/ext/json11/meson.build b/pdns/recursordist/ext/json11/meson.build
new file mode 120000 (symlink)
index 0000000..ad335bb
--- /dev/null
@@ -0,0 +1 @@
+../../../../ext/json11/meson.build
\ No newline at end of file
diff --git a/pdns/recursordist/ext/probds/meson.build b/pdns/recursordist/ext/probds/meson.build
new file mode 120000 (symlink)
index 0000000..4e5e7a6
--- /dev/null
@@ -0,0 +1 @@
+../../../../ext/probds/meson.build
\ No newline at end of file
diff --git a/pdns/recursordist/ext/yahttp/meson.build b/pdns/recursordist/ext/yahttp/meson.build
new file mode 120000 (symlink)
index 0000000..89a718d
--- /dev/null
@@ -0,0 +1 @@
+../../../../ext/yahttp/meson.build
\ No newline at end of file
diff --git a/pdns/recursordist/ext/yahttp/yahttp/meson.build b/pdns/recursordist/ext/yahttp/yahttp/meson.build
new file mode 120000 (symlink)
index 0000000..471962b
--- /dev/null
@@ -0,0 +1 @@
+../../../../../ext/yahttp/yahttp/meson.build
\ No newline at end of file
index bfcbbc71e6a88a89a3cb51ffe570f5a56db5ae45..75f3106b4938845e5e39897e893165ef2b951003 100644 (file)
@@ -799,9 +799,14 @@ void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* filePtr, const Netmask& netmask
 
 void DNSFilterEngine::Zone::dump(FILE* filePtr) const
 {
-  /* fake the SOA record */
-  auto soa = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
-  fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
+  if (DNSRecord soa = d_zoneData->d_soa; !soa.d_name.empty()) {
+    fprintf(filePtr, "%s IN SOA %s\n", soa.d_name.toString().c_str(), soa.getContent()->getZoneRepresentation().c_str());
+  }
+  else {
+    /* fake the SOA record */
+    auto soarr = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
+    fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soarr->getZoneRepresentation().c_str());
+  }
 
   for (const auto& pair : d_qpolName) {
     dumpNamedPolicy(filePtr, pair.first + d_domain, pair.second);
index af5308ad7b2972c171b680019bf56d89767b8b2a..e1b9773a4d24ffc8688cd8652bff0a8eb1e986f2 100644 (file)
@@ -34,8 +34,6 @@
 #include <unordered_set>
 #include "rec-main.hh"
 
-RecursorLua4::RecursorLua4() { prepareContext(); }
-
 boost::optional<dnsheader> RecursorLua4::DNSQuestion::getDH() const
 {
   if (dh != nullptr) {
@@ -160,7 +158,7 @@ struct DynMetric
 
 // clang-format off
 
-void RecursorLua4::postPrepareContext()
+void RecursorLua4::postPrepareContext() // NOLINT(readability-function-cognitive-complexity)
 {
   d_lw->registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dnsQuestion) -> const DNSName& { return dnsQuestion.qname; }, [](DNSQuestion& /* dnsQuestion */, const DNSName& newName) { (void) newName; });
   d_lw->registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dnsQuestion) -> uint16_t { return dnsQuestion.qtype; }, [](DNSQuestion& /* dnsQuestion */, uint16_t newType) { (void) newType; });
@@ -495,6 +493,9 @@ void RecursorLua4::postPrepareContext()
       (*event.discardedPolicies)[policy] = true;
     }
   });
+  if (!d_include_path.empty()) {
+    includePath(d_include_path);
+  }
 }
 
 // clang-format on
index a275184510d4bbf1977e843be5600d93df4b02f1..1a758abb5d9d9b000e0e0d65a65e7b92a0478926 100644 (file)
@@ -72,7 +72,11 @@ struct LuaContext::Pusher<pdns_postresolve_ffi_handle*>
 class RecursorLua4 : public BaseLua4
 {
 public:
-  RecursorLua4();
+  RecursorLua4(const std::string& includePath = "") :
+    BaseLua4(includePath)
+  {
+    prepareContext();
+  };
   RecursorLua4(const RecursorLua4&) = delete;
   RecursorLua4(RecursorLua4&&) = delete;
   RecursorLua4& operator=(const RecursorLua4&) = delete;
index 28e142ed85b75ed286394ccc61e5fe4f9d4997b0..95bdb00f527806a687d740c65509806186b3ec07 100644 (file)
@@ -154,7 +154,7 @@ static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr
 
 #endif // HAVE_FSTRM
 
-static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, size_t bytes, const boost::optional<Netmask>& srcmask)
+static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, size_t bytes, const boost::optional<Netmask>& srcmask, const std::string& nsName)
 {
   if (!outgoingLoggers) {
     return;
@@ -204,6 +204,9 @@ static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<R
     m.setEDNSSubnet(*srcmask, 128);
   }
 
+  if (!nsName.empty()) {
+    m.setMeta("nsName", {nsName}, {});
+  }
   for (auto& logger : *outgoingLoggers) {
     if (logger->logQueries()) {
       remoteLoggerQueueData(*logger, buffer);
@@ -211,7 +214,7 @@ static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<R
   }
 }
 
-static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
+static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const boost::optional<const boost::uuids::uuid&>& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const boost::optional<Netmask>& srcmask, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes, const std::string& nsName)
 {
   if (!outgoingLoggers) {
     return;
@@ -259,6 +262,9 @@ static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_pt
   if (srcmask) {
     m.setEDNSSubnet(*srcmask, 128);
   }
+  if (!nsName.empty()) {
+    m.setMeta("nsName", {nsName}, {});
+  }
 
   m.startResponse();
   m.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
@@ -270,7 +276,7 @@ static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_pt
   }
 
   for (const auto& record : records) {
-    m.addRR(record, exportTypes, false);
+    m.addRR(record, exportTypes, std::nullopt);
   }
   m.commitResponse();
 
@@ -396,6 +402,10 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
   uint16_t qid = dns_random_uint16();
   DNSPacketWriter pw(vpacket, domain, type);
   bool dnsOverTLS = SyncRes::s_dot_to_port_853 && address.getPort() == 853;
+  std::string nsName;
+  if (!context.d_nsName.empty()) {
+    nsName = context.d_nsName.toStringNoDot();
+  }
 
   pw.getHeader()->rd = sendRDQuery;
   pw.getHeader()->id = qid;
@@ -446,7 +456,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
 
   if (outgoingLoggers) {
     uuid = getUniqueID();
-    logOutgoingQuery(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask);
+    logOutgoingQuery(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, vpacket.size(), srcmask, nsName);
   }
 
   srcmask = boost::none; // this is also our return value, even if EDNS0Level == 0
@@ -468,13 +478,13 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
   if (!doTCP) {
     int queryfd;
 
-    ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd);
+    ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, weWantEDNSSubnet, &queryfd, *now);
 
     if (ret != LWResult::Result::Success) {
       return ret;
     }
 
-    if (queryfd == -1) {
+    if (queryfd <= -1) {
       *chained = true;
     }
 
@@ -503,10 +513,6 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
         // peer has closed it on error, so we retry. At some point we
         // *will* get a new connection, so this loop is not endless.
         isNew = true; // tcpconnect() might throw for new connections. In that case, we want to break the loop, scanbuild complains here, which is a false positive afaik
-        std::string nsName;
-        if (!context.d_nsName.empty()) {
-          nsName = context.d_nsName.toStringNoDot();
-        }
         isNew = tcpconnect(address, connection, dnsOverTLS, nsName);
         ret = tcpsendrecv(address, connection, localip, vpacket, len, buf);
 #ifdef HAVE_FSTRM
@@ -533,11 +539,21 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
 
   if (ret != LWResult::Result::Success) { // includes 'timeout'
     if (outgoingLoggers) {
-      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes);
+      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, 0, -1, {}, queryTime, exportTypes, nsName);
     }
     return ret;
   }
 
+  if (*chained) {
+    auto msec = lwr->d_usec / 1000;
+    if (msec > g_networkTimeoutMsec * 2 / 3) {
+      auto jitterMsec = dns_random(msec);
+      if (jitterMsec > 0) {
+        mthreadSleep(jitterMsec);
+      }
+    }
+  }
+
   buf.resize(len);
 
 #ifdef HAVE_FSTRM
@@ -560,7 +576,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
 
     if (mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
       if (outgoingLoggers) {
-        logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+        logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
       }
       lwr->d_validpacket = true;
       return LWResult::Result::Success; // this is "success", the error is set in lwr->d_rcode
@@ -579,8 +595,9 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
     }
 
     lwr->d_records.reserve(mdp.d_answers.size());
-    for (const auto& a : mdp.d_answers)
-      lwr->d_records.push_back(a.first);
+    for (const auto& answer : mdp.d_answers) {
+      lwr->d_records.push_back(answer);
+    }
 
     EDNSOpts edo;
     if (EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
@@ -607,7 +624,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
     }
 
     if (outgoingLoggers) {
-      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
     }
 
     lwr->d_validpacket = true;
@@ -625,7 +642,7 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
     t_Counters.at(rec::Counter::serverParseError)++;
 
     if (outgoingLoggers) {
-      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+      logIncomingResponse(outgoingLoggers, context.d_initialRequestId, uuid, address, domain, type, qid, doTCP, dnsOverTLS, srcmask, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes, nsName);
     }
 
     return LWResult::Result::Success; // success - oddly enough
index 8fca61fe15aff946206d374346bacf57e741ff20..58d43535e32c5e9540a991731a31c12ce82ec653 100644 (file)
@@ -69,9 +69,15 @@ public:
     Success = 1,
     PermanentError = 2 /* not transport related */,
     OSLimitError = 3,
-    Spoofed = 4 /* Spoofing attempt (too many near-misses) */
+    Spoofed = 4, /* Spoofing attempt (too many near-misses) */
+    ChainLimitError = 5,
   };
 
+  [[nodiscard]] static bool isLimitError(Result res)
+  {
+    return res == Result::OSLimitError || res == Result::ChainLimitError;
+  }
+
   vector<DNSRecord> d_records;
   int d_rcode{0};
   bool d_validpacket{false};
@@ -81,7 +87,7 @@ public:
 };
 
 LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, uint16_t qid,
-                         const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc);
+                         const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now);
 LWResult::Result arecvfrom(PacketBuffer& packet, int flags, const ComboAddress& fromAddr, size_t& len, uint16_t qid,
                            const DNSName& domain, uint16_t qtype, int fileDesc, const struct timeval& now);
 
diff --git a/pdns/recursordist/meson b/pdns/recursordist/meson
new file mode 120000 (symlink)
index 0000000..160c781
--- /dev/null
@@ -0,0 +1 @@
+../../meson
\ No newline at end of file
diff --git a/pdns/recursordist/meson.build b/pdns/recursordist/meson.build
new file mode 100644 (file)
index 0000000..ef9f4ed
--- /dev/null
@@ -0,0 +1,563 @@
+project(
+  'pdns-recursor',
+  ['c', 'cpp'],
+  version: run_command('../../builder-support' / 'gen-version', check: true).stdout().strip(),
+  license: 'GPLv2',
+  license_files: 'NOTICE',
+  meson_version: '>= 1.2.1',
+  default_options: [
+    'buildtype=debugoptimized',
+    'warning_level=2',          # TODO Move this to 3 to enable -Wpedantic
+    'cpp_std=c++17',
+  ],
+)
+add_project_arguments('-DRECURSOR', language: 'cpp')
+
+
+product_source_dir = meson.current_source_dir()
+product_build_dir = meson.current_build_dir()
+summary('Source Dir', product_source_dir, section: 'Build')
+summary('Build Dir', product_build_dir, section: 'Build')
+
+# Create the configuration object and dependencies list.
+conf = configuration_data()
+conf.set_quoted('PACKAGE_STRING', meson.project_version(), description: 'version')
+conf.set_quoted('NODCACHEDIRNOD', get_option('localstatedir') + '/nod', description: 'NOD data directory')
+conf.set_quoted('NODCACHEDIRUDR', get_option('localstatedir') + '/udr', description: 'NDR data directory')
+
+# Feature detection and system configuration
+subdir('meson' / 'config')                  # Config
+subdir('meson' / 'version')                 # Generate version define
+subdir('meson' / 'compiler-setup')          # Common compiler setup
+subdir('meson' / 'summary')                 # Print a system/project summary
+subdir('meson' / 'sysconfdir')              # Sysconfdir
+subdir('meson' / 'platform')                # Platform detection
+subdir('meson' / 'timet-size')              # Check the size of time_t
+subdir('meson' / 'timet-sign')              # Check the sign of time_t
+subdir('meson' / 'atomics')                 # Check atomics support
+subdir('meson' / 'pthread-headers')         # Check pthread headers
+subdir('meson' / 'pthread-setname')         # Pthread setname madness
+subdir('meson' / 'pthread-np')              # Pthread _np functions
+subdir('meson' / 'strerror')                # Strerror_r
+subdir('meson' / 'lua')                     # Lua
+subdir('meson' / 'hardening')               # Hardening
+subdir('meson' / 'net-libs')                # Network Libraries
+subdir('meson' / 'tm-gmtoff')               # Check for tm_gmtoff field in struct tm
+subdir('meson' / 'mmap')                    # Check for mmap
+subdir('meson' / 'libsodium')               # Libsodium-based signers
+subdir('meson' / 'libdecaf')                # Libdecaf-based signers
+subdir('meson' / 'libcrypto')               # OpenSSL-based signers
+subdir('meson' / 'libssl')                  # OpenSSL libssl
+subdir('meson' / 'libsnmp')                 # SNMP
+subdir('meson' / 'dot')                     # DNS over TLS
+subdir('meson' / 'clock-gettime')           # Clock_gettime
+subdir('meson' / 'boost')                   # Boost
+subdir('meson' / 'boost-context')           # Boost Context Switching Library
+subdir('meson' / 'boost-test')              # Boost Testing Library
+subdir('meson' / 'boost-filesystem')        # Boost File System Library
+subdir('meson' / 'reproducible')            # Reproducible Builds
+subdir('meson' / 'libsystemd')              # Systemd notification
+subdir('meson' / 'systemd')                 # Systemd and unit file handling
+subdir('meson' / 'code-coverage')           # Code coverage
+subdir('meson' / 'auto-var-init')           # Automatic Variable Initialization
+subdir('meson' / 'sanitizers')              # Sanitizers
+subdir('meson' / 'malloc-trace')            # Malloc-trace
+subdir('meson' / 'socket-dir')              # Socket Dir
+subdir('meson' / 'various-functions')       # Various Functions
+subdir('meson' / 'various-headers')         # Various Headers
+subdir('meson' / 'libresolv')               # res_query
+subdir('meson' / 'dnstap')                  # DNSTAP through libfstream
+subdir('meson' / 'libcurl')                 # Curl
+
+subdir('settings')
+
+common_sources = []
+
+fs = import('fs')
+src_dir = fs.is_dir('.') ? '.' : ''
+docs_dir = 'docs'
+# Toplevel includes
+dep_pdns = declare_dependency(include_directories: include_directories('.', src_dir))
+
+# Ext
+subdir('ext' / 'arc4random')
+subdir('ext' / 'json11')
+subdir('ext' / 'luawrapper')
+subdir('ext' / 'protozero')
+subdir('ext' / 'probds')
+subdir('ext' / 'yahttp')
+subdir('meson' / 'nod')                     # Newly Observed Domains
+
+common_sources += files(
+  src_dir / 'aggressive_nsec.cc',
+  src_dir / 'arguments.cc',
+  src_dir / 'axfr-retriever.cc',
+  src_dir / 'base32.cc',
+  src_dir / 'base64.cc',
+  src_dir / 'coverage.cc',
+  src_dir / 'credentials.cc',
+  src_dir / 'dns.cc',
+  src_dir / 'dnsname.cc',
+  src_dir / 'dnsparser.cc',
+  src_dir / 'dnsrecords.cc',
+  src_dir / 'dnssecinfra.cc',
+  src_dir / 'dnswriter.cc',
+  src_dir / 'ednsextendederror.cc',
+  src_dir / 'ednsoptions.cc',
+  src_dir / 'ednspadding.cc',
+  src_dir / 'ednssubnet.cc',
+  src_dir / 'filterpo.cc',
+  src_dir / 'gettime.cc',
+  src_dir / 'gss_context.cc',
+  src_dir / 'iputils.cc',
+  src_dir / 'ixfr.cc',
+  src_dir / 'json.cc',
+  src_dir / 'libssl.cc',
+  src_dir / 'logger.cc',
+  src_dir / 'logging.cc',
+  src_dir / 'lua-base4.cc',
+  src_dir / 'lua-recursor4.cc',
+  src_dir / 'lwres.cc',
+  src_dir / 'misc.cc',
+  src_dir / 'mtasker_context.cc',
+  src_dir / 'negcache.cc',
+  src_dir / 'nsecrecords.cc',
+  src_dir / 'protozero.cc',
+  src_dir / 'proxy-protocol.cc',
+  src_dir / 'pubsuffixloader.cc',
+  src_dir / 'qtype.cc',
+  src_dir / 'query-local-address.cc',
+  src_dir / 'rcpgenerator.cc',
+  src_dir / 'rec-carbon.cc',
+  src_dir / 'rec-eventtrace.cc',
+  src_dir / 'rec-lua-conf.cc',
+  src_dir / 'rec-protozero.cc',
+  src_dir / 'rec-responsestats.cc',
+  src_dir / 'rec-system-resolve.cc',
+  src_dir / 'rec-taskqueue.cc',
+  src_dir / 'rec-tcounters.cc',
+  src_dir / 'rec-zonetocache.cc',
+  src_dir / 'rec_channel.cc',
+  src_dir / 'rec_channel_rec.cc',
+  src_dir / 'recpacketcache.cc',
+  src_dir / 'recursor_cache.cc',
+  src_dir / 'reczones-helpers.cc',
+  src_dir / 'reczones.cc',
+  src_dir / 'remote_logger.cc',
+  src_dir / 'resolver.cc',
+  src_dir / 'rpzloader.cc',
+  src_dir / 'secpoll-recursor.cc',
+  src_dir / 'secpoll.cc',
+  src_dir / 'shuffle.cc',
+  src_dir / 'sillyrecords.cc',
+  src_dir / 'snmp-agent.cc',
+  src_dir / 'sortlist.cc',
+  src_dir / 'svc-records.cc',
+  src_dir / 'syncres.cc',
+  src_dir / 'taskqueue.cc',
+  src_dir / 'tcpiohandler.cc',
+  src_dir / 'threadname.cc',
+  src_dir / 'tsigverifier.cc',
+  src_dir / 'unix_utility.cc',
+  src_dir / 'uuid-utils.cc',
+  src_dir / 'validate.cc',
+  src_dir / 'validate-recursor.cc',
+  src_dir / 'version.cc',
+  src_dir / 'webserver.cc',
+  src_dir / 'ws-api.cc',
+  src_dir / 'ws-recursor.cc',
+  src_dir / 'zonemd.cc',
+  src_dir / 'zoneparser-tng.cc',
+)
+
+conditional_sources = {
+  'minicurl': {
+    'sources': [
+      src_dir / 'minicurl.cc',
+      src_dir / 'minicurl.hh',
+    ],
+    'condition': dep_libcurl.found(),
+  },
+  'dnstap': {
+    'sources': [
+      src_dir / 'dnstap.cc',
+      src_dir / 'fstrm_logger.cc',
+    ],
+    'condition': dep_dnstap.found(),
+  },
+  'nod': {
+    'sources': [
+      src_dir / 'nod.cc',
+    ],
+    'condition': dep_nod.found(),
+  },
+}
+
+foreach name, info: conditional_sources
+  if info['condition']
+    common_sources += files(info['sources'])
+  endif
+endforeach
+
+mplexer_sources = [src_dir / 'pollmplexer.cc']
+if have_linux
+  mplexer_sources += src_dir / 'epollmplexer.cc'
+endif
+if have_darwin
+  mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_openbsd
+  mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_freebsd
+  mplexer_sources += src_dir / 'kqueuemplexer.cc'
+endif
+if have_sunos
+  mplexer_sources += src_dir / 'devpollmplexer.cc'
+  mplexer_sources += src_dir / 'portsmplexer.cc'
+endif
+
+# Generate config.h
+config_h = configure_file(configuration: conf, output: 'config.h')
+
+sh_program = find_program('sh')
+dep_no_config_in_source_check = custom_target(
+    input: [],
+    output: ['check absense of config.h file in source directory'],
+    command: [sh_program, '-c', 'test ! -e @SOURCE_ROOT@/config.h'],
+    build_always_stale: true,
+)
+dep_no_config_in_source = declare_dependency(
+  sources: dep_no_config_in_source_check
+)
+
+html_sources = [
+  src_dir / 'html/index.html',
+  src_dir / 'html/local-2022.js',
+  src_dir / 'html/js/rickshaw.min.js',
+  src_dir / 'html/js/moment.js',
+  src_dir / 'html/js/rickshaw.js',
+  src_dir / 'html/js/d3.v3.js',
+  src_dir / 'html/js/handlebars-v4.0.11.js',
+  src_dir / 'html/js/handlebars-v4.0.11-min.js',
+  src_dir / 'html/js/d3.v3-min.js',
+  src_dir / 'html/js/moment.min.js',
+  src_dir / 'html/lines.css',
+  src_dir / 'html/legend.css',
+  src_dir / 'html/styling.css',
+  src_dir / 'html/detail.css',
+  src_dir / 'html/graph.css',
+  src_dir / 'html/powerdns-logo-220px.png',
+]
+
+incfiles = find_program('incfiles')
+
+htmlfiles = custom_target(
+  command: [incfiles, '@SOURCE_ROOT@'],
+  input: html_sources,
+  output: 'htmlfiles.h',
+  capture: true
+)
+
+dep_htmlfiles = declare_dependency(
+  sources: [htmlfiles],
+)
+
+deps = [
+  dep_pdns,
+  dep_no_config_in_source,
+  dep_rust_settings,
+  dep_boost,
+  dep_boost_context,
+  dep_threads,
+  dep_json11,
+  dep_libcrypto,
+  dep_libresolv,
+  dep_libsnmp,
+  dep_libsodium,
+  dep_libssl,
+  dep_lua,
+  dep_protozero,
+  dep_yahttp,
+  dep_htmlfiles,
+  dep_dnstap,
+  dep_libcurl,
+]
+
+# Conditional sources that need to be separated into standalone libraries for special
+# linking without implicitly getting rid of symbols.
+librec_signers_sodium = dependency('', required: false)
+if dep_libsodium.found()
+  librec_signers_sodium = declare_dependency(
+    link_whole: static_library(
+      'rec-signers-sodium',
+      sources: files(src_dir / 'sodiumsigners.cc'),
+      dependencies: [dep_boost, dep_libsodium],
+    )
+  )
+endif
+
+librec_signers_decaf = dependency('', required: false)
+if dep_libdecaf.found()
+  librec_signers_decaf = declare_dependency(
+    link_whole: static_library(
+      'rec-signers-decaf',
+      sources: files(src_dir / 'decafsigners.cc'),
+      dependencies: [dep_boost, dep_libdecaf],
+    )
+  )
+endif
+
+librec_signers_openssl = declare_dependency(
+  link_whole: static_library(
+    'rec-signers-openssl',
+    sources: files(src_dir / 'opensslsigners.cc'),
+    dependencies: [dep_boost, dep_libssl],
+  )
+)
+
+# If we have pubsuffix.cc in the source tree, use it. Otherwise download and build it.
+pubsuffix_dl_source =  'effective_tld_names.dat'
+pubsuffix_cc = src_dir / 'pubsuffix.cc'
+if not fs.is_file(pubsuffix_cc)
+  curl_command = find_program('curl', required: true)
+  pubsuffix_dl_source = custom_target(
+    'pubsuffix-dl',
+    command: [curl_command, '-s', '-S', '-o', '@OUTPUT@', 'https://publicsuffix.org/list/public_suffix_list.dat'],
+    output: pubsuffix_dl_source
+  )
+
+  mkpubsuffix_command = find_program('mkpubsuffixcc', required: true)
+  pubsuffix_cc = custom_target(
+    'pubsuffix-cc',
+    command: [mkpubsuffix_command, '@INPUT@', '@OUTPUT@'],
+    input: pubsuffix_dl_source,
+    output: 'pubsuffix.cc',
+  )
+endif
+
+dep_pubsuffix = declare_dependency(
+  sources: pubsuffix_cc
+)
+
+librec_dnslabeltext_source = src_dir / 'dnslabeltext.rl'
+librec_dnslabeltext_gen    = src_dir / 'dnslabeltext.cc'
+if not fs.is_file(librec_dnslabeltext_gen)
+  ragel = find_program('ragel', required: true)
+
+  summary('Ragel', ragel.found(), bool_yn: ragel.found(), section: 'DNS Labels')
+  summary('Ragel Path', ragel.full_path(), section: 'DNS Labels')
+  summary('Ragel Version', ragel.version(), section: 'DNS Labels')
+
+  ragel_generator = generator(
+    ragel,
+    output: '@BASENAME@.cc',
+    arguments: ['@INPUT@', '-o', '@OUTPUT@'],
+  )
+
+  librec_dnslabeltext_gen = ragel_generator.process(librec_dnslabeltext_source)
+endif
+
+librec_dnslabeltext = declare_dependency(
+  link_with: static_library(
+    'rec-dnslabeltext',
+    librec_dnslabeltext_gen,
+    dependencies: deps,
+  )
+)
+
+librec_common = declare_dependency(
+  link_with: static_library(
+    'rec-common',
+    common_sources,
+    config_h,
+    dependencies: [
+      deps,
+      dep_settings_ch,
+      librec_dnslabeltext,
+    ],
+  )
+)
+
+tools = {
+  'pdns_recursor': {
+    'main': src_dir / 'rec-main.cc',
+    'files-extra': [
+      src_dir / 'capabilities.cc',
+      src_dir / 'channel.cc',
+      src_dir / 'pdns_recursor.cc',
+      src_dir / 'rec-tcp.cc',
+      src_dir / 'rec-tcpout.cc',
+      src_dir / 'rec-snmp.cc',
+      src_dir / 'rec-tcp.cc',
+      mplexer_sources,
+    ],
+    'manpages': ['pdns_recursor.1'],
+    'deps-extra': [
+      dep_boost,
+      dep_nod,
+      dep_lua,
+      dep_protozero,
+      dep_yahttp,
+      dep_json11,
+      dep_settings,
+      dep_rust_settings,
+      dep_systemd,
+      librec_signers_openssl,
+      librec_signers_decaf,
+      librec_signers_sodium,
+      dep_pubsuffix,
+    ],
+  },
+  'rec_control': {
+    'main': src_dir / 'rec_control.cc',
+    'manpages': ['rec_control.1'],
+    'deps-extra': [
+      dep_boost,
+      dep_settings,
+      dep_rust_settings,
+    ],
+  },
+}
+
+test_sources = []
+test_sources += files(
+      src_dir / 'ednscookies.cc',
+      src_dir / 'test-aggressive_nsec_cc.cc',
+      src_dir / 'test-arguments_cc.cc',
+      src_dir / 'test-base32_cc.cc',
+      src_dir / 'test-base64_cc.cc',
+      src_dir / 'test-common.hh',
+      src_dir / 'test-credentials_cc.cc',
+      src_dir / 'test-dns_random_hh.cc',
+      src_dir / 'test-dnsname_cc.cc',
+      src_dir / 'test-dnsparser_hh.cc',
+      src_dir / 'test-dnsrecordcontent.cc',
+      src_dir / 'test-dnsrecords_cc.cc',
+      src_dir / 'test-ednsoptions_cc.cc',
+      src_dir / 'test-filterpo_cc.cc',
+      src_dir / 'test-histogram_hh.cc',
+      src_dir / 'test-iputils_hh.cc',
+      src_dir / 'test-ixfr_cc.cc',
+      src_dir / 'test-luawrapper.cc',
+      src_dir / 'test-misc_hh.cc',
+      src_dir / 'test-mplexer.cc',
+      src_dir / 'test-mtasker.cc',
+      src_dir / 'test-negcache_cc.cc',
+      src_dir / 'test-packetcache_hh.cc',
+      src_dir / 'test-rcpgenerator_cc.cc',
+      src_dir / 'test-rec-system-resolve.cc',
+      src_dir / 'test-rec-taskqueue.cc',
+      src_dir / 'test-rec-tcounters_cc.cc',
+      src_dir / 'test-rec-zonetocache.cc',
+      src_dir / 'test-recpacketcache_cc.cc',
+      src_dir / 'test-recursorcache_cc.cc',
+      src_dir / 'test-reczones-helpers.cc',
+      src_dir / 'test-rpzloader_cc.cc',
+      src_dir / 'test-secpoll_cc.cc',
+      src_dir / 'test-settings.cc',
+      src_dir / 'test-signers.cc',
+      src_dir / 'test-syncres_cc.cc',
+      src_dir / 'test-syncres_cc.hh',
+      src_dir / 'test-syncres_cc1.cc',
+      src_dir / 'test-syncres_cc10.cc',
+      src_dir / 'test-syncres_cc2.cc',
+      src_dir / 'test-syncres_cc3.cc',
+      src_dir / 'test-syncres_cc4.cc',
+      src_dir / 'test-syncres_cc5.cc',
+      src_dir / 'test-syncres_cc6.cc',
+      src_dir / 'test-syncres_cc7.cc',
+      src_dir / 'test-syncres_cc8.cc',
+      src_dir / 'test-syncres_cc9.cc',
+      src_dir / 'test-tsig.cc',
+)
+
+if enable_nod
+  test_sources += files(src_dir / 'test-nod_cc.cc')
+endif
+
+if get_option('unit-tests')
+  librec_test = declare_dependency(
+    link_whole: static_library(
+      'rec-test',
+      config_h,
+      test_sources,
+      dependencies: [
+          dep_boost,
+          dep_boost_test,
+          dep_lua,
+          dep_nod,
+          dep_settings,
+          dep_rust_settings,
+          librec_signers_openssl,
+          librec_signers_decaf,
+          librec_signers_sodium,
+      ],
+    )
+  )
+  tools += {
+    'testrunner': {
+        'main': [
+          src_dir / 'testrunner.cc',
+          mplexer_sources,
+        ],
+        'deps-extra': [
+          librec_test,
+          dep_boost_test,
+        ],
+    }
+  }
+endif
+
+man_pages = []
+foreach tool, info: tools
+  var_name = tool.underscorify()
+  main = files(info['main'])
+
+  export_dynamic = 'export-dynamic' in info ? info['export-dynamic'] : false
+  files_extra = 'files-extra' in info ? info['files-extra'] : []
+  deps_extra = 'deps-extra' in info ? info['deps-extra'] : []
+
+  set_variable(
+    var_name,
+    executable(
+      tool,
+      main,
+      config_h,
+      files_extra,
+      export_dynamic: export_dynamic,
+      dependencies: [
+        librec_common,
+        deps_extra,
+      ],
+    )
+  )
+
+  if 'manpages' in info
+    foreach man_page: info['manpages']
+      man_pages += docs_dir / 'manpages' / (man_page + '.rst')
+    endforeach
+  endif
+endforeach
+
+# Man-pages.
+py = import('python')
+python = py.find_installation('python3', modules: 'venv', required: false)
+
+summary('Python', python.found(), bool_yn: true, section: 'Manual Pages')
+summary('Path', python.full_path(), section: 'Manual Pages')
+summary('Version', python.version(), section: 'Manual Pages')
+
+if python.found()
+  run_target(
+    'man-pages',
+    command: [
+      python,
+      product_source_dir / docs_dir / 'generate-man-pages.py',
+      '--venv-name', 'venv-rec-man-pages',
+      '--requirements-file', docs_dir / 'requirements.txt',
+      '--source-directory', docs_dir,
+      '--target-directory', 'rec-man-pages',
+    ] + man_pages,
+  )
+endif
diff --git a/pdns/recursordist/meson_options.txt b/pdns/recursordist/meson_options.txt
new file mode 100644 (file)
index 0000000..52ba9f3
--- /dev/null
@@ -0,0 +1,26 @@
+option('lua', type: 'combo', choices: ['auto', 'luajit', 'lua'], value: 'auto', description: 'Lua implementation to use')
+option('hardening', type: 'feature', value: 'auto', description: 'Compiler security checks')
+option('hardening-experimental-cf', type: 'combo', choices: ['disabled', 'full', 'branch', 'return', 'check'], value: 'disabled', description: 'Control Flow hardening')
+option('hardening-experimental-scp', type: 'feature', value: 'disabled', description: 'Stack Clash Protection')
+option('hardening-fortify-source', type: 'combo', choices: ['auto', 'disabled', '1', '2', '3'], value: '2', description: 'Source fortification level')
+#option('rng-kiss', type: 'boolean', value: false, description: 'Use the unsafe KISS RNG')
+option('signers-libsodium', type: 'feature', value: 'auto', description: 'Enable libsodium-based signers')
+option('signers-libdecaf', type: 'feature', value: 'auto', description: 'Enable libdecaf-based signers')
+option('signers-libcrypto', type: 'feature', value: 'auto', description: 'Enable OpenSSL libcrypto-based signers)')
+option('signers-libcrypto-path', type: 'string', value: '', description: 'Custom path to find OpenSSL libcrypto')
+option('tls-libssl', type: 'feature', value: 'auto', description: 'OpenSSL-based TLS')
+option('dns-over-tls', type: 'boolean', value: false, description: 'DNS over TLS (requires GnuTLS or OpenSSL)')
+option('unit-tests', type: 'boolean', value: false, description: 'Build and run unit tests')
+# not relevant for rec, but accessed by boost meson.build
+option('unit-tests-backends', type: 'boolean', value: false, description: 'Build and run backend unit tests')
+option('reproducible', type: 'boolean', value: false, description: 'Reproducible builds (for distro maintainers, makes debugging difficult)')
+option('systemd', type: 'feature', value: 'auto', description: 'Systemd notification (requires libsystemd)')
+option('systemd-service-user', type: 'string', value: 'pdns', description: 'Systemd service user (setuid and unit file; user is not created)')
+option('systemd-service-group', type: 'string', value: 'pdns', description: 'Systemd service group (setgid and unit file; group is not created)')
+option('auto-var-init', type: 'combo', value: 'disabled', choices: ['zero', 'pattern', 'disabled'], description: 'Enable initialization of automatic variables')
+option('malloc-trace', type: 'boolean', value: false, description: 'Enable malloc-trace')
+option('socket-dir', type: 'string', value: '/var/run', description: 'Where the control socket lives')
+option('snmp', type: 'boolean', value: false, description: 'Enable SNMP')
+option('dnstap', type: 'feature', value: 'auto', description: 'Enable DNSTAP support through libfstrm')
+option('libcurl', type: 'feature', value: 'auto', description: 'Enable Curl support')
+option('nod', type: 'boolean', value: true, description: 'Enable Newly Obserbed Domains')
index e9d936676bd947fe88e2d8fb14f295906e9e0b98..a45f64d8326b75d6627bd5d9612a731fd8b64532 100644 (file)
@@ -81,6 +81,7 @@ public:
   }
 
   using tfunc_t = void(void*); //!< type of the pointer that starts a thread
+  uint64_t nextWaiterDelayUsec(uint64_t defusecs);
   int waitEvent(EventKey& key, EventVal* val = nullptr, unsigned int timeoutMsec = 0, const struct timeval* now = nullptr);
   void yield();
   int sendEvent(const EventKey& key, const EventVal* val = nullptr);
@@ -216,6 +217,29 @@ private:
 #include <valgrind/valgrind.h>
 #endif /* PDNS_USE_VALGRIND */
 
+template <class EventKey, class EventVal, class Cmp>
+uint64_t MTasker<EventKey, EventVal, Cmp>::nextWaiterDelayUsec(uint64_t defusecs)
+{
+  if (d_waiters.empty()) {
+    // no waiters
+    return defusecs;
+  }
+  auto& ttdindex = boost::multi_index::get<KeyTag>(d_waiters);
+  auto iter = ttdindex.begin();
+  timeval rnow{};
+  gettimeofday(&rnow, nullptr);
+  if (iter->ttd.tv_sec != 0) {
+    // we have a waiter with a timeout specified
+    if (rnow < iter->ttd) {
+      // we should not wait longer than the default timeout
+      return std::min(defusecs, uSec(iter->ttd - rnow));
+    }
+    // already expired
+    return 0;
+  }
+  return defusecs;
+}
+
 //! puts a thread to sleep waiting until a specified event arrives
 /** Threads can call waitEvent to register that they are waiting on an event with a certain key.
     If so desired, the event can carry data which is returned in val in case that is non-zero.
index 1661f2dac5d5c50d140051e7695fb32292d5022f..1bd3fd8ae12ac574f7b5cf7dce1017f5916c2915 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#ifdef HAVE_CONFIG_H
+
 #include "config.h"
+#include "mtasker_context.hh"
+#include <exception>
+#include <cassert>
+#include <type_traits>
+#include <boost/version.hpp>
+#if BOOST_VERSION < 106100
+#include <boost/context/fcontext.hpp>
+using boost::context::make_fcontext;
+#else
+#include <boost/context/detail/fcontext.hpp>
+using boost::context::detail::make_fcontext;
+#endif /* BOOST_VERSION < 106100 */
+
+// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
+#if defined(__amd64__)
+#if __CET__ & 0x1
+#define CET_ENDBR __asm("endbr64")
+#else
+#define CET_ENDBR
+#endif
+#else
+#define CET_ENDBR
+#endif
+
+#ifdef PDNS_USE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif /* PDNS_USE_VALGRIND */
+
+#ifdef HAVE_FIBER_SANITIZER
+__thread void* t_mainStack{nullptr};
+__thread size_t t_mainStackSize{0};
+#endif /* HAVE_FIBER_SANITIZER */
+
+#if BOOST_VERSION < 105600
+/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
+ * now require a reinterpret_cast rather than a static_cast, since we're
+ * casting from pdns_context_t->uc_mcontext, which is void**, to
+ * some_opaque_struct**. In later versions fcontext_t is already void*. So if
+ * you remove this, then fix the ugly.
+ */
+using fcontext_t = boost::context::fcontext_t*;
+
+/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
+static inline intptr_t
+jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
+              intptr_t const arg)
+{
+  /* If the fcontext_t is preallocated then use it, otherwise allocate one
+   * on the stack ('self') and stash a pointer away in *ofc so the returning
+   * MThread can access it. This is safe because we're suspended, so the
+   * context object always outlives the jump.
+   */
+  if (*ofc) {
+    return boost::context::jump_fcontext(*ofc, nfc, arg);
+  }
+  else {
+    boost::context::fcontext_t self;
+    *ofc = &self;
+    auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
+    *ofc = nullptr;
+    return ret;
+  }
+}
+#else
+
+#if BOOST_VERSION < 106100
+using boost::context::fcontext_t;
+using boost::context::jump_fcontext;
+#else
+using boost::context::detail::fcontext_t;
+using boost::context::detail::jump_fcontext;
+using boost::context::detail::transfer_t;
+#endif /* BOOST_VERSION < 106100 */
+
+static_assert(std::is_pointer<fcontext_t>::value,
+              "Boost Context has changed the fcontext_t type again :-(");
+#endif
+
+/* Boost context only provides a means of passing a single argument across a
+ * jump. args_t simply provides a way to pass more by reference.
+ */
+struct args_t
+{
+#if BOOST_VERSION < 106100
+  fcontext_t prev_ctx = nullptr;
+#endif
+  pdns_ucontext_t* self = nullptr;
+  std::function<void(void)>* work = nullptr;
+};
+
+extern "C"
+{
+  static void
+#if BOOST_VERSION < 106100
+  threadWrapper(intptr_t const xargs)
+  {
+#else
+  threadWrapper(transfer_t const theThread)
+  {
+#endif
+    /* Access the args passed from pdns_makecontext, and copy them directly from
+     * the calling stack on to ours (we're now using the MThreads stack).
+     * This saves heap allocating an args object, at the cost of an extra
+     * context switch to fashion this constructor-like init phase. The work
+     * function object is still only moved after we're (re)started, so may
+     * still be set or changed after a call to pdns_makecontext. This matches
+     * the behaviour of the System V implementation, which can inherently only
+     * be passed ints and pointers.
+     */
+    notifyStackSwitchDone();
+#if BOOST_VERSION < 106100
+    auto* args = reinterpret_cast<args_t*>(xargs);
+#else
+    auto* args = static_cast<args_t*>(theThread.data);
+#endif
+    auto* ctx = args->self;
+    auto* work = args->work;
+    /* we switch back to pdns_makecontext() */
+    notifyStackSwitchToKernel();
+#if BOOST_VERSION < 106100
+    jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+                  static_cast<fcontext_t>(args->prev_ctx), 0);
+#else
+    transfer_t res = jump_fcontext(theThread.fctx, nullptr);
+    CET_ENDBR;
+    /* we got switched back from pdns_swapcontext() */
+    if (res.data != nullptr) {
+      /* if res.data is not a nullptr, it holds a pointer to the context
+         we just switched from, and we need to fill it to be able to
+         switch back to it later. */
+      auto* ptr = static_cast<fcontext_t*>(res.data);
+      *ptr = res.fctx;
+    }
+#endif
+    notifyStackSwitchDone();
+    args = nullptr;
+
+    try {
+      auto start = std::move(*work);
+      start();
+    }
+    catch (...) {
+      ctx->exception = std::current_exception();
+    }
+
+    notifyStackSwitchToKernel();
+    /* Emulate the System V uc_link feature. */
+    auto* const next_ctx = ctx->uc_link->uc_mcontext;
+#if BOOST_VERSION < 106100
+    jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
+                  static_cast<fcontext_t>(next_ctx),
+                  reinterpret_cast<intptr_t>(ctx));
+#else
+    jump_fcontext(static_cast<fcontext_t>(next_ctx), nullptr);
+#endif
+
+#ifdef NDEBUG
+    __builtin_unreachable();
+#endif
+  }
+}
+
+pdns_ucontext_t::pdns_ucontext_t() :
+  uc_mcontext(nullptr), uc_link(nullptr)
+{
+#ifdef PDNS_USE_VALGRIND
+  valgrind_id = 0;
+#endif /* PDNS_USE_VALGRIND */
+}
+
+#ifdef PDNS_USE_VALGRIND
+pdns_ucontext_t::~pdns_ucontext_t()
+{
+  /* There's nothing to delete here since fcontext doesn't require anything
+   * to be heap allocated.
+   */
+  if (valgrind_id != 0) {
+    VALGRIND_STACK_DEREGISTER(valgrind_id);
+  }
+}
+#else
+pdns_ucontext_t::~pdns_ucontext_t() = default;
+#endif /* PDNS_USE_VALGRIND */
+
+void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
+{
+  /* we either switch back to threadwrapper() if it's the first time,
+     or we switch back to pdns_swapcontext(),
+     in both case we will be returning from a call to jump_fcontext(). */
+#if BOOST_VERSION < 106100
+  intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
+                               static_cast<fcontext_t>(ctx.uc_mcontext), 0);
+
+  auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
+  if (origctx && origctx->exception)
+    std::rethrow_exception(origctx->exception);
+#else
+  transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
+  CET_ENDBR;
+  if (res.data != nullptr) {
+    /* if res.data is not a nullptr, it holds a pointer to the context
+       we just switched from, and we need to fill it to be able to
+       switch back to it later. */
+    auto* ptr = static_cast<fcontext_t*>(res.data);
+    *ptr = res.fctx;
+  }
+  if (ctx.exception) {
+    std::rethrow_exception(ctx.exception);
+  }
 #endif
+}
 
-#if defined(HAVE_BOOST_CONTEXT)
-#include "mtasker_fcontext.cc" // NOLINT(bugprone-suspicious-include)
+void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
+{
+  // NOLINTBEGIN(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  assert(ctx.uc_link);
+  assert(ctx.uc_stack.size() >= 8192);
+  assert(!ctx.uc_mcontext);
+  // NOLINTEND(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+  ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
+                                  ctx.uc_stack.size() - 1, &threadWrapper);
+  args_t args;
+  args.self = &ctx;
+  args.work = &start;
+  /* jumping to threadwrapper */
+  notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
+#if BOOST_VERSION < 106100
+  jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
+                static_cast<fcontext_t>(ctx.uc_mcontext),
+                reinterpret_cast<intptr_t>(&args));
 #else
-#include "mtasker_ucontext.cc" // NOLINT(bugprone-suspicious-include)
+  transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
+                                 &args);
+  CET_ENDBR;
+  /* back from threadwrapper, updating the context */
+  ctx.uc_mcontext = res.fctx;
 #endif
+  notifyStackSwitchDone();
+}
diff --git a/pdns/recursordist/mtasker_fcontext.cc b/pdns/recursordist/mtasker_fcontext.cc
deleted file mode 100644 (file)
index e489b40..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "mtasker_context.hh"
-#include <exception>
-#include <cassert>
-#include <type_traits>
-#include <boost/version.hpp>
-#if BOOST_VERSION < 106100
-#include <boost/context/fcontext.hpp>
-using boost::context::make_fcontext;
-#else
-#include <boost/context/detail/fcontext.hpp>
-using boost::context::detail::make_fcontext;
-#endif /* BOOST_VERSION < 106100 */
-
-// __CET__ is set by the compiler if relevant, so far only relevant/tested for amd64 on OpenBSD
-#if defined(__amd64__)
-#if __CET__ & 0x1
-#define CET_ENDBR __asm("endbr64")
-#else
-#define CET_ENDBR
-#endif
-#else
-#define CET_ENDBR
-#endif
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-#if BOOST_VERSION < 105600
-/* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(),
- * now require a reinterpret_cast rather than a static_cast, since we're
- * casting from pdns_context_t->uc_mcontext, which is void**, to
- * some_opaque_struct**. In later versions fcontext_t is already void*. So if
- * you remove this, then fix the ugly.
- */
-using fcontext_t = boost::context::fcontext_t*;
-
-/* Emulate the >= 1.56 API for Boost 1.52 through 1.55 */
-static inline intptr_t
-jump_fcontext(fcontext_t* const ofc, fcontext_t const nfc,
-              intptr_t const arg)
-{
-  /* If the fcontext_t is preallocated then use it, otherwise allocate one
-   * on the stack ('self') and stash a pointer away in *ofc so the returning
-   * MThread can access it. This is safe because we're suspended, so the
-   * context object always outlives the jump.
-   */
-  if (*ofc) {
-    return boost::context::jump_fcontext(*ofc, nfc, arg);
-  }
-  else {
-    boost::context::fcontext_t self;
-    *ofc = &self;
-    auto ret = boost::context::jump_fcontext(*ofc, nfc, arg);
-    *ofc = nullptr;
-    return ret;
-  }
-}
-#else
-
-#if BOOST_VERSION < 106100
-using boost::context::fcontext_t;
-using boost::context::jump_fcontext;
-#else
-using boost::context::detail::fcontext_t;
-using boost::context::detail::jump_fcontext;
-using boost::context::detail::transfer_t;
-#endif /* BOOST_VERSION < 106100 */
-
-static_assert(std::is_pointer<fcontext_t>::value,
-              "Boost Context has changed the fcontext_t type again :-(");
-#endif
-
-/* Boost context only provides a means of passing a single argument across a
- * jump. args_t simply provides a way to pass more by reference.
- */
-struct args_t
-{
-#if BOOST_VERSION < 106100
-  fcontext_t prev_ctx = nullptr;
-#endif
-  pdns_ucontext_t* self = nullptr;
-  std::function<void(void)>* work = nullptr;
-};
-
-extern "C"
-{
-  static void
-#if BOOST_VERSION < 106100
-  threadWrapper(intptr_t const xargs)
-  {
-#else
-  threadWrapper(transfer_t const t)
-  {
-#endif
-    /* Access the args passed from pdns_makecontext, and copy them directly from
-     * the calling stack on to ours (we're now using the MThreads stack).
-     * This saves heap allocating an args object, at the cost of an extra
-     * context switch to fashion this constructor-like init phase. The work
-     * function object is still only moved after we're (re)started, so may
-     * still be set or changed after a call to pdns_makecontext. This matches
-     * the behaviour of the System V implementation, which can inherently only
-     * be passed ints and pointers.
-     */
-    notifyStackSwitchDone();
-#if BOOST_VERSION < 106100
-    auto args = reinterpret_cast<args_t*>(xargs);
-#else
-    auto args = reinterpret_cast<args_t*>(t.data);
-#endif
-    auto ctx = args->self;
-    auto work = args->work;
-    /* we switch back to pdns_makecontext() */
-    notifyStackSwitchToKernel();
-#if BOOST_VERSION < 106100
-    jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
-                  static_cast<fcontext_t>(args->prev_ctx), 0);
-#else
-    transfer_t res = jump_fcontext(t.fctx, 0);
-    CET_ENDBR;
-    /* we got switched back from pdns_swapcontext() */
-    if (res.data) {
-      /* if res.data is not a nullptr, it holds a pointer to the context
-         we just switched from, and we need to fill it to be able to
-         switch back to it later. */
-      fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
-      *ptr = res.fctx;
-    }
-#endif
-    notifyStackSwitchDone();
-    args = nullptr;
-
-    try {
-      auto start = std::move(*work);
-      start();
-    }
-    catch (...) {
-      ctx->exception = std::current_exception();
-    }
-
-    notifyStackSwitchToKernel();
-    /* Emulate the System V uc_link feature. */
-    auto const next_ctx = ctx->uc_link->uc_mcontext;
-#if BOOST_VERSION < 106100
-    jump_fcontext(reinterpret_cast<fcontext_t*>(&ctx->uc_mcontext),
-                  static_cast<fcontext_t>(next_ctx),
-                  reinterpret_cast<intptr_t>(ctx));
-#else
-    jump_fcontext(static_cast<fcontext_t>(next_ctx), 0);
-#endif
-
-#ifdef NDEBUG
-    __builtin_unreachable();
-#endif
-  }
-}
-
-pdns_ucontext_t::pdns_ucontext_t() :
-  uc_mcontext(nullptr), uc_link(nullptr)
-{
-#ifdef PDNS_USE_VALGRIND
-  valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
-  /* There's nothing to delete here since fcontext doesn't require anything
-   * to be heap allocated.
-   */
-#ifdef PDNS_USE_VALGRIND
-  if (valgrind_id != 0) {
-    VALGRIND_STACK_DEREGISTER(valgrind_id);
-  }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
-  /* we either switch back to threadwrapper() if it's the first time,
-     or we switch back to pdns_swapcontext(),
-     in both case we will be returning from a call to jump_fcontext(). */
-#if BOOST_VERSION < 106100
-  intptr_t ptr = jump_fcontext(reinterpret_cast<fcontext_t*>(&octx.uc_mcontext),
-                               static_cast<fcontext_t>(ctx.uc_mcontext), 0);
-
-  auto origctx = reinterpret_cast<pdns_ucontext_t*>(ptr);
-  if (origctx && origctx->exception)
-    std::rethrow_exception(origctx->exception);
-#else
-  transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext), &octx.uc_mcontext);
-  CET_ENDBR;
-  if (res.data) {
-    /* if res.data is not a nullptr, it holds a pointer to the context
-       we just switched from, and we need to fill it to be able to
-       switch back to it later. */
-    fcontext_t* ptr = static_cast<fcontext_t*>(res.data);
-    *ptr = res.fctx;
-  }
-  if (ctx.exception) {
-    std::rethrow_exception(ctx.exception);
-  }
-#endif
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
-  assert(ctx.uc_link);
-  assert(ctx.uc_stack.size() >= 8192);
-  assert(!ctx.uc_mcontext);
-  ctx.uc_mcontext = make_fcontext(&ctx.uc_stack[ctx.uc_stack.size() - 1],
-                                  ctx.uc_stack.size() - 1, &threadWrapper);
-  args_t args;
-  args.self = &ctx;
-  args.work = &start;
-  /* jumping to threadwrapper */
-  notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size() - 1], ctx.uc_stack.size() - 1);
-#if BOOST_VERSION < 106100
-  jump_fcontext(reinterpret_cast<fcontext_t*>(&args.prev_ctx),
-                static_cast<fcontext_t>(ctx.uc_mcontext),
-                reinterpret_cast<intptr_t>(&args));
-#else
-  transfer_t res = jump_fcontext(static_cast<fcontext_t>(ctx.uc_mcontext),
-                                 &args);
-  CET_ENDBR;
-  /* back from threadwrapper, updating the context */
-  ctx.uc_mcontext = res.fctx;
-#endif
-  notifyStackSwitchDone();
-}
diff --git a/pdns/recursordist/mtasker_ucontext.cc b/pdns/recursordist/mtasker_ucontext.cc
deleted file mode 100644 (file)
index 9fcb3da..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "mtasker_context.hh"
-#include <system_error>
-#include <exception>
-#include <cstring>
-#include <cassert>
-#include <csignal>
-#include <cstdint>
-#include <ucontext.h>
-
-#ifdef PDNS_USE_VALGRIND
-#include <valgrind/valgrind.h>
-#endif /* PDNS_USE_VALGRIND */
-
-#ifdef HAVE_FIBER_SANITIZER
-__thread void* t_mainStack{nullptr};
-__thread size_t t_mainStackSize{0};
-#endif /* HAVE_FIBER_SANITIZER */
-
-template <typename Message>
-static __attribute__((noinline, cold, noreturn)) void
-throw_errno(Message&& msg)
-{
-  throw std::system_error(errno, std::system_category(), std::forward<Message>(msg));
-}
-
-static inline std::pair<int, int>
-splitPointer(void* const ptr) noexcept
-{
-  static_assert(sizeof(int) == 4, "splitPointer() requires an 4 byte 'int'");
-  // In theory, we need this assertion. In practice, it prevents compilation
-  // on EL6 i386. Without the assertion, everything works.
-  // If you ever run into trouble with this code, please heed the warnings at
-  // http://man7.org/linux/man-pages/man3/makecontext.3.html#NOTES
-  //    static_assert (sizeof(uintptr_t) == 8,
-  //                    "splitPointer() requires an 8 byte 'uintptr_t'");
-  std::pair<int, int> words;
-  auto rep = reinterpret_cast<uintptr_t>(ptr);
-  uint32_t const hw = rep >> 32;
-  auto const lw = static_cast<uint32_t>(rep);
-  std::memcpy(&words.first, &hw, 4);
-  std::memcpy(&words.second, &lw, 4);
-  return words;
-}
-
-template <typename T>
-static inline T*
-joinPtr(int const first, int const second) noexcept
-{
-  static_assert(sizeof(int) == 4, "joinPtr() requires an 4 byte 'int'");
-  // See above.
-  //    static_assert (sizeof(uintptr_t) == 8,
-  //                    "joinPtr() requires an 8 byte 'uintptr_t'");
-  uint32_t hw;
-  uint32_t lw;
-  std::memcpy(&hw, &first, 4);
-  std::memcpy(&lw, &second, 4);
-  return reinterpret_cast<T*>((static_cast<uintptr_t>(hw) << 32) | lw);
-}
-
-extern "C"
-{
-  static void
-  threadWrapper(int const ctx0, int const ctx1, int const fun0, int const fun1)
-  {
-    notifyStackSwitchDone();
-    auto ctx = joinPtr<pdns_ucontext_t>(ctx0, ctx1);
-    try {
-      auto start = std::move(*joinPtr<std::function<void()>>(fun0, fun1));
-      start();
-    }
-    catch (...) {
-      ctx->exception = std::current_exception();
-    }
-    notifyStackSwitchToKernel();
-  }
-} // extern "C"
-
-pdns_ucontext_t::pdns_ucontext_t()
-{
-  uc_mcontext = new ::ucontext_t();
-  uc_link = nullptr;
-#ifdef PDNS_USE_VALGRIND
-  valgrind_id = 0;
-#endif /* PDNS_USE_VALGRIND */
-}
-
-pdns_ucontext_t::~pdns_ucontext_t()
-{
-  delete static_cast<ucontext_t*>(uc_mcontext);
-#ifdef PDNS_USE_VALGRIND
-  if (valgrind_id != 0) {
-    VALGRIND_STACK_DEREGISTER(valgrind_id);
-  }
-#endif /* PDNS_USE_VALGRIND */
-}
-
-void pdns_swapcontext(pdns_ucontext_t& __restrict octx, pdns_ucontext_t const& __restrict ctx)
-{
-  if (::swapcontext(static_cast<ucontext_t*>(octx.uc_mcontext),
-                    static_cast<ucontext_t*>(ctx.uc_mcontext))) {
-    throw_errno("swapcontext() failed");
-  }
-  if (ctx.exception) {
-    std::rethrow_exception(ctx.exception);
-  }
-}
-
-void pdns_makecontext(pdns_ucontext_t& ctx, std::function<void(void)>& start)
-{
-  assert(ctx.uc_link);
-  assert(ctx.uc_stack.size());
-
-  auto const mcp = static_cast<ucontext_t*>(ctx.uc_mcontext);
-  auto const next = static_cast<ucontext_t*>(ctx.uc_link->uc_mcontext);
-  if (::getcontext(mcp)) {
-    throw_errno("getcontext() failed");
-  }
-  mcp->uc_link = next;
-  mcp->uc_stack.ss_sp = ctx.uc_stack.data();
-  mcp->uc_stack.ss_size = ctx.uc_stack.size() - 1;
-  mcp->uc_stack.ss_flags = 0;
-
-  auto ctxarg = splitPointer(&ctx);
-  auto funarg = splitPointer(&start);
-  return ::makecontext(mcp, reinterpret_cast<void (*)(void)>(&threadWrapper),
-                       4, ctxarg.first, ctxarg.second,
-                       funarg.first, funarg.second);
-}
index ad3ad7ac61430264c788a46fd3d0d441c3a691ba..d39fcd6d7d91d3fab56b555adfcbc7c1b359078a 100644 (file)
@@ -79,11 +79,7 @@ bool g_reusePort{false};
 bool g_gettagNeedsEDNSOptions{false};
 bool g_useKernelTimestamp;
 std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
 boost::container::flat_set<uint16_t> g_avoidUdpSourcePorts;
-#else
-std::set<uint16_t> g_avoidUdpSourcePorts;
-#endif
 uint16_t g_minUdpSourcePort;
 uint16_t g_maxUdpSourcePort;
 double g_balancingFactor;
@@ -251,7 +247,7 @@ PacketBuffer GenUDPQueryResponse(const ComboAddress& dest, const string& query)
   t_fdm->addReadFD(socket.getHandle(), handleGenUDPQueryResponse, pident);
 
   PacketBuffer data;
-  int ret = g_multiTasker->waitEvent(pident, &data, g_networkTimeoutMsec);
+  int ret = g_multiTasker->waitEvent(pident, &data, authWaitTimeMSec(g_multiTasker));
 
   if (ret == 0 || ret == -1) { // timeout
     t_fdm->removeReadFD(socket.getHandle());
@@ -267,9 +263,23 @@ static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& va
 
 thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
 
+// If we have plenty of mthreads slot left, use default timeout.
+// Otherwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec
+unsigned int authWaitTimeMSec(const std::unique_ptr<MT_t>& mtasker)
+{
+  const auto max = g_maxMThreads;
+  const auto current = mtasker->numProcesses();
+  const unsigned int cutoff = max / 10; // if we have less than 10% used,  do not reduce auth timeout
+  if (current < cutoff) {
+    return g_networkTimeoutMsec;
+  }
+  const auto avail = max - current;
+  return std::max(g_networkTimeoutMsec / 10, g_networkTimeoutMsec * avail / (max - cutoff));
+}
+
 /* these two functions are used by LWRes */
 LWResult::Result asendto(const void* data, size_t len, int /* flags */,
-                         const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc)
+                         const ComboAddress& toAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, bool ecs, int* fileDesc, timeval& now)
 {
 
   auto pident = std::make_shared<PacketID>();
@@ -291,8 +301,21 @@ LWResult::Result asendto(const void* data, size_t len, int /* flags */,
       assert(chain.first->key->domain == pident->domain); // NOLINT
       // don't chain onto existing chained waiter or a chain already processed
       if (chain.first->key->fd > -1 && !chain.first->key->closed) {
-        chain.first->key->chain.insert(qid); // we can chain
-        *fileDesc = -1; // gets used in waitEvent / sendEvent later on
+        auto currentChainSize = chain.first->key->authReqChain.size();
+        *fileDesc = -static_cast<int>(currentChainSize + 1); // value <= -1, gets used in waitEvent / sendEvent later on
+        if (g_maxChainLength > 0 && currentChainSize >= g_maxChainLength) {
+          return LWResult::Result::ChainLimitError;
+        }
+        assert(uSec(chain.first->key->creationTime) != 0); // NOLINT
+        auto age = now - chain.first->key->creationTime;
+        if (uSec(age) > static_cast<uint64_t>(1000) * authWaitTimeMSec(g_multiTasker) * 2 / 3) {
+          return LWResult::Result::ChainLimitError;
+        }
+        chain.first->key->authReqChain.emplace(*fileDesc, qid); // we can chain
+        auto maxLength = t_Counters.at(rec::Counter::maxChainLength);
+        if (currentChainSize + 1 > maxLength) {
+          t_Counters.at(rec::Counter::maxChainLength) = currentChainSize + 1;
+        }
         return LWResult::Result::Success;
       }
     }
@@ -331,8 +354,9 @@ LWResult::Result arecvfrom(PacketBuffer& packet, int /* flags */, const ComboAdd
   pident->domain = domain;
   pident->type = qtype;
   pident->remote = fromAddr;
+  pident->creationTime = now;
 
-  int ret = g_multiTasker->waitEvent(pident, &packet, g_networkTimeoutMsec, &now);
+  int ret = g_multiTasker->waitEvent(pident, &packet, authWaitTimeMSec(g_multiTasker), &now);
   len = 0;
 
   /* -1 means error, 0 means timeout, 1 means a result from handleUDPServerResponse() which might still be an error */
@@ -485,7 +509,7 @@ public:
   }
 
 private:
-  std::unique_ptr<DNSComboWriter>& d_dc;
+  std::unique_ptr<DNSComboWriter>& d_dc; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
   bool d_handled{false};
 };
 
@@ -597,17 +621,18 @@ static bool nodCheckNewDomain(Logr::log_t nodlogger, const DNSName& dname)
 {
   bool ret = false;
   // First check the (sub)domain isn't ignored for NOD purposes
-  if (!g_nodDomainWL.check(dname)) {
-    // Now check the NODDB (note this is probabilistic so can have FNs/FPs)
-    if (g_nodDBp && g_nodDBp->isNewDomain(dname)) {
-      if (g_nodLog) {
-        // This should probably log to a dedicated log file
-        SLOG(g_log << Logger::Notice << "Newly observed domain nod=" << dname << endl,
-             nodlogger->info(Logr::Notice, "New domain observed"));
-      }
-      t_Counters.at(rec::Counter::nodCount)++;
-      ret = true;
+  if (g_nodDomainWL.check(dname)) {
+    return ret;
+  }
+  // Now check the NODDB (note this is probabilistic so can have FNs/FPs)
+  if (g_nodDBp && g_nodDBp->isNewDomain(dname)) {
+    if (g_nodLog) {
+      // This should probably log to a dedicated log file
+      SLOG(g_log << Logger::Notice << "Newly observed domain nod=" << dname << endl,
+           nodlogger->info(Logr::Notice, "New domain observed"));
     }
+    t_Counters.at(rec::Counter::nodCount)++;
+    ret = true;
   }
   return ret;
 }
@@ -636,6 +661,10 @@ static void sendNODLookup(Logr::log_t nodlogger, const DNSName& dname)
 static bool udrCheckUniqueDNSRecord(Logr::log_t nodlogger, const DNSName& dname, uint16_t qtype, const DNSRecord& record)
 {
   bool ret = false;
+  // First check the (sub)domain isn't ignored for UDR purposes
+  if (g_udrDomainWL.check(dname)) {
+    return ret;
+  }
   if (record.d_place == DNSResourceRecord::ANSWER || record.d_place == DNSResourceRecord::ADDITIONAL) {
     // Create a string that represent a triplet of (qname, qtype and RR[type, name, content])
     std::stringstream strStream;
@@ -752,6 +781,24 @@ int getFakeAAAARecords(const DNSName& qname, ComboAddress prefix, vector<DNSReco
                 }),
               ret.end());
   }
+  else {
+    // Remove double SOA records
+    std::set<DNSName> seenSOAs;
+    ret.erase(std::remove_if(
+                ret.begin(),
+                ret.end(),
+                [&seenSOAs](DNSRecord& record) {
+                  if (record.d_type == QType::SOA) {
+                    if (seenSOAs.count(record.d_name) > 0) {
+                      // We've had this SOA before, remove it
+                      return true;
+                    }
+                    seenSOAs.insert(record.d_name);
+                  }
+                  return false;
+                }),
+              ret.end());
+  }
   t_Counters.at(rec::Counter::dns64prefixanswers)++;
   return rcode;
 }
@@ -808,9 +855,8 @@ bool isAllowNotifyForZone(DNSName qname)
     return false;
   }
 
-  notifyset_t::const_iterator ret;
   do {
-    ret = t_allowNotifyFor->find(qname);
+    auto ret = t_allowNotifyFor->find(qname);
     if (ret != t_allowNotifyFor->end()) {
       return true;
     }
@@ -1823,7 +1869,9 @@ void startDoResolve(void* arg) // NOLINT(readability-function-cognitive-complexi
       pbMessage.setDeviceName(dnsQuestion.deviceName);
       pbMessage.setToPort(comboWriter->d_destination.getPort());
       pbMessage.addPolicyTags(comboWriter->d_gettagPolicyTags);
-
+      pbMessage.setWorkerId(RecThreadInfo::id());
+      pbMessage.setPacketCacheHit(false);
+      pbMessage.setOutgoingQueries(resolver.d_outqueries);
       for (const auto& metaValue : dnsQuestion.meta) {
         pbMessage.setMeta(metaValue.first, metaValue.second.stringVal, metaValue.second.intVal);
       }
@@ -2356,7 +2404,7 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
     variable = true;
   }
 
-  if (g_multiTasker->numProcesses() > g_maxMThreads) {
+  if (g_multiTasker->numProcesses() >= g_maxMThreads) {
     if (!g_quiet) {
       SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " [" << g_multiTasker->getTid() << "/" << g_multiTasker->numProcesses() << "] DROPPED question from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << ", over capacity" << endl,
            g_slogudpin->info(Logr::Notice, "Dropped question, over capacity", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)));
@@ -2521,7 +2569,7 @@ static void handleNewUDPQuestion(int fileDesc, FDMultiplexer::funcparam_t& /* va
         }
       }
       if (t_remotes) {
-        t_remotes->push_back(fromaddr);
+        t_remotes->push_back(source);
       }
 
       if (t_allowFrom && !t_allowFrom->match(&mappedSource)) {
@@ -2834,18 +2882,36 @@ static void doResends(MT_t::waiters_t::iterator& iter, const std::shared_ptr<Pac
   // We close the chain for new entries, since they won't be processed anyway
   iter->key->closed = true;
 
-  if (iter->key->chain.empty()) {
+  if (iter->key->authReqChain.empty()) {
     return;
   }
-  for (auto i = iter->key->chain.begin(); i != iter->key->chain.end(); ++i) {
+
+  auto maxWeight = t_Counters.at(rec::Counter::maxChainWeight);
+  auto weight = iter->key->authReqChain.size() * content.size();
+  if (weight > maxWeight) {
+    t_Counters.at(rec::Counter::maxChainWeight) = weight;
+  }
+
+  for (auto [fileDesc, qid] : iter->key->authReqChain) {
     auto packetID = std::make_shared<PacketID>(*resend);
-    packetID->fd = -1;
-    packetID->id = *i;
+    packetID->fd = fileDesc;
+    packetID->id = qid;
     g_multiTasker->sendEvent(packetID, &content);
     t_Counters.at(rec::Counter::chainResends)++;
   }
 }
 
+void mthreadSleep(unsigned int jitterMsec)
+{
+  auto neverHappens = std::make_shared<PacketID>();
+  neverHappens->id = dns_random_uint16();
+  neverHappens->type = dns_random_uint16();
+  neverHappens->remote = ComboAddress("100::"); // discard-only
+  neverHappens->remote.setPort(dns_random_uint16());
+  neverHappens->fd = -1;
+  assert(g_multiTasker->waitEvent(neverHappens, nullptr, jitterMsec) != -1); // NOLINT
+}
+
 static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& var)
 {
   auto pid = boost::any_cast<std::shared_ptr<PacketID>>(var);
diff --git a/pdns/recursordist/pubsuffix.cc b/pdns/recursordist/pubsuffix.cc
deleted file mode 120000 (symlink)
index c32d99d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../pubsuffix.cc
\ No newline at end of file
index 98a8c15e886510bd6425533e5fed506d8b238211..bd838f846fbf2e4430c48690bac4ce7d67cd3c1e 100644 (file)
@@ -351,7 +351,8 @@ static void rpzPrimary(LuaConfigItems& lci, const boost::variant<string, std::ve
 class RecLuaConfigContext : public BaseLua4
 {
 public:
-  RecLuaConfigContext()
+  RecLuaConfigContext() :
+    BaseLua4("")
   {
     prepareContext();
   }
index 8a5c015d3be63d0399e6e0607a067997de11a209..6a1eb68358ba2af78b6898913d6f43b762e55310 100644 (file)
@@ -85,6 +85,7 @@ string g_pidfname;
 RecursorControlChannel g_rcc; // only active in the handler thread
 bool g_regressionTestMode;
 bool g_yamlSettings;
+string g_yamlSettingsSuffix;
 bool g_luaSettingsInYAML;
 
 #ifdef NOD_ENABLED
@@ -92,6 +93,7 @@ bool g_nodEnabled;
 DNSName g_nodLookupDomain;
 bool g_nodLog;
 SuffixMatchNode g_nodDomainWL;
+SuffixMatchNode g_udrDomainWL;
 std::string g_nod_pbtag;
 bool g_udrEnabled;
 bool g_udrLog;
@@ -107,6 +109,7 @@ NetmaskGroup g_proxyProtocolACL;
 std::set<ComboAddress> g_proxyProtocolExceptions;
 boost::optional<ComboAddress> g_dns64Prefix{boost::none};
 DNSName g_dns64PrefixReverse;
+unsigned int g_maxChainLength;
 std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
 std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
 std::shared_ptr<NetmaskGroup> g_initialAllowNotifyFrom; // new threads need this to be setup
@@ -547,6 +550,8 @@ void protobufLogQuery(LocalStateHolder<LuaConfigItems>& luaconfsLocal, const boo
   msg.setRequestorId(requestorId);
   msg.setDeviceId(deviceId);
   msg.setDeviceName(deviceName);
+  msg.setWorkerId(RecThreadInfo::id());
+  // For queries, packetCacheHit and outgoingQueries are not relevant
 
   if (!policyTags.empty()) {
     msg.addPolicyTags(policyTags);
@@ -625,6 +630,11 @@ void protobufLogResponse(const struct dnsheader* header, LocalStateHolder<LuaCon
   pbMessage.setDeviceId(deviceId);
   pbMessage.setDeviceName(deviceName);
   pbMessage.setToPort(destination.getPort());
+  pbMessage.setWorkerId(RecThreadInfo::id());
+  // this method is only used for PC cache hits
+  pbMessage.setPacketCacheHit(true);
+  // we do not set outgoingQueries, it is not relevant for PC cache hits
+
   for (const auto& metaItem : meta) {
     pbMessage.setMeta(metaItem.first, metaItem.second.stringVal, metaItem.second.intVal);
   }
@@ -850,12 +860,33 @@ static void setupNODThread(Logr::log_t log)
   }
 }
 
-static void parseNODIgnorelist(const std::string& wlist)
+static void parseIgnorelist(const std::string& wlist, SuffixMatchNode& matchNode)
 {
   vector<string> parts;
   stringtok(parts, wlist, ",; ");
   for (const auto& part : parts) {
-    g_nodDomainWL.add(DNSName(part));
+    matchNode.add(DNSName(part));
+  }
+}
+
+static void parseIgnorelistFile(const std::string& fname, SuffixMatchNode& matchNode)
+{
+  string line;
+  std::ifstream ignorelistFileStream(fname);
+  if (!ignorelistFileStream) {
+    throw ArgException(fname + " could not be opened");
+  }
+
+  while (getline(ignorelistFileStream, line)) {
+    boost::trim(line);
+
+    try {
+      matchNode.add(DNSName(line));
+    }
+    catch (const std::exception& e) {
+      SLOG(g_log << Logger::Warning << "Ignoring line of ignorelist due to an error: " << e.what() << endl,
+           g_slog->withName("config")->error(Logr::Warning, e.what(), "Ignoring line of ignorelist due to an error", "exception", Logging::Loggable("std::exception")));
+    }
   }
 }
 
@@ -865,14 +896,21 @@ static void setupNODGlobal()
   g_nodEnabled = ::arg().mustDo("new-domain-tracking");
   g_nodLookupDomain = DNSName(::arg()["new-domain-lookup"]);
   g_nodLog = ::arg().mustDo("new-domain-log");
-  parseNODIgnorelist(::arg()["new-domain-whitelist"]);
-  parseNODIgnorelist(::arg()["new-domain-ignore-list"]);
+  parseIgnorelist(::arg()["new-domain-whitelist"], g_nodDomainWL);
+  parseIgnorelist(::arg()["new-domain-ignore-list"], g_nodDomainWL);
+  if (!::arg().isEmpty("new-domain-ignore-list-file")) {
+    parseIgnorelistFile(::arg()["new-domain-ignore-list-file"], g_nodDomainWL);
+  }
 
   // Setup Unique DNS Response subsystem
   g_udrEnabled = ::arg().mustDo("unique-response-tracking");
   g_udrLog = ::arg().mustDo("unique-response-log");
   g_nod_pbtag = ::arg()["new-domain-pb-tag"];
   g_udr_pbtag = ::arg()["unique-response-pb-tag"];
+  parseIgnorelist(::arg()["unique-response-ignore-list"], g_udrDomainWL);
+  if (!::arg().isEmpty("unique-response-ignore-list-file")) {
+    parseIgnorelistFile(::arg()["unique-response-ignore-list-file"], g_udrDomainWL);
+  }
 }
 #endif /* NOD_ENABLED */
 
@@ -1345,7 +1383,7 @@ void parseACLs()
     cleanSlashes(configName);
 
     if (g_yamlSettings) {
-      configName += ".yml";
+      configName += g_yamlSettingsSuffix;
       string msg;
       pdns::rust::settings::rec::Recursorsettings settings;
       // XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line?
@@ -1742,6 +1780,7 @@ static int initSyncRes(Logr::log_t log)
   SyncRes::s_event_trace_enabled = ::arg().asNum("event-trace-enabled");
   SyncRes::s_save_parent_ns_set = ::arg().mustDo("save-parent-ns-set");
   SyncRes::s_max_busy_dot_probes = ::arg().asNum("max-busy-dot-probes");
+  SyncRes::s_max_CNAMES_followed = ::arg().asNum("max-cnames-followed");
   {
     uint64_t sse = ::arg().asNum("serve-stale-extensions");
     if (sse > std::numeric_limits<uint16_t>::max()) {
@@ -2303,11 +2342,13 @@ static int serviceMain(Logr::log_t log)
   RecThreadInfo::makeThreadPipes(log);
 
   g_tcpTimeout = ::arg().asNum("client-tcp-timeout");
+  g_maxTCPClients = ::arg().asNum("max-tcp-clients");
   g_maxTCPPerClient = ::arg().asNum("max-tcp-per-client");
   g_tcpMaxQueriesPerConn = ::arg().asNum("max-tcp-queries-per-connection");
   g_maxUDPQueriesPerRound = ::arg().asNum("max-udp-queries-per-round");
 
   g_useKernelTimestamp = ::arg().mustDo("protobuf-use-kernel-timestamp");
+  g_maxChainLength = ::arg().asNum("max-chain-length");
 
   disableStats(StatComponent::API, ::arg()["stats-api-blacklist"]);
   disableStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]);
@@ -2679,32 +2720,8 @@ static void runLuaMaintenance(RecThreadInfo& threadInfo, time_t& last_lua_mainte
   }
 }
 
-static void runTCPMaintenance(RecThreadInfo& threadInfo, bool& listenOnTCP, unsigned int maxTcpClients)
-{
-  if (threadInfo.isTCPListener()) {
-    if (listenOnTCP) {
-      if (TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections
-        for (const auto fileDesc : threadInfo.getTCPSockets()) {
-          t_fdm->removeReadFD(fileDesc);
-        }
-        listenOnTCP = false;
-      }
-    }
-    else {
-      if (TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable
-        for (const auto fileDesc : threadInfo.getTCPSockets()) {
-          t_fdm->addReadFD(fileDesc, handleNewTCPQuestion);
-        }
-        listenOnTCP = true;
-      }
-    }
-  }
-}
-
 static void recLoop()
 {
-  unsigned int maxTcpClients = ::arg().asNum("max-tcp-clients");
-  bool listenOnTCP{true};
   time_t last_stat = 0;
   time_t last_carbon = 0;
   time_t last_lua_maintenance = 0;
@@ -2763,10 +2780,9 @@ static void recLoop()
       }
       runLuaMaintenance(threadInfo, last_lua_maintenance, luaMaintenanceInterval);
 
-      t_fdm->run(&g_now);
+      auto timeoutUsec = g_multiTasker->nextWaiterDelayUsec(500000);
+      t_fdm->run(&g_now, static_cast<int>(timeoutUsec / 1000));
       // 'run' updates g_now for us
-
-      runTCPMaintenance(threadInfo, listenOnTCP, maxTcpClients);
     }
     catch (const PDNSException& pdnsException) {
       s_rateLimitedLogger.log(g_slog->withName("runtime"), "recLoop", pdnsException);
@@ -2866,6 +2882,10 @@ static void recursorThread()
       checkFrameStreamExport(luaconfsLocal, luaconfsLocal->frameStreamExportConfig, t_frameStreamServersInfo);
       checkFrameStreamExport(luaconfsLocal, luaconfsLocal->nodFrameStreamExportConfig, t_nodFrameStreamServersInfo);
 #endif
+      for (const auto& rpz : luaconfsLocal->rpzs) {
+        string name = rpz.polName.empty() ? (rpz.primaries.empty() ? "rpzFile" : rpz.name) : rpz.polName;
+        t_Counters.at(rec::PolicyNameHits::policyName).counts[name] = 0;
+      }
     }
 
     t_fdm = unique_ptr<FDMultiplexer>(getMultiplexer(log));
@@ -3112,8 +3132,8 @@ int main(int argc, char** argv)
     ::arg().laxParse(argc, argv); // do a lax parse
 
     if (::arg().mustDo("version")) {
-      showProductVersion();
-      showBuildConfiguration();
+      cout << getProductVersion();
+      cout << getBuildConfiguration();
       return 0;
     }
     if (::arg().mustDo("help")) {
@@ -3133,7 +3153,10 @@ int main(int argc, char** argv)
     }
     g_log.setLoglevel(s_logUrgency);
     g_log.toConsole(s_logUrgency);
-    showProductVersion();
+
+    for (const string& line : getProductVersionLines()) {
+      g_log << Logger::Info << line << endl;
+    }
     if (!::arg().mustDo("structured-logging")) {
       g_log << Logger::Error << "Disabling structured logging is not supported anymore" << endl;
     }
@@ -3174,11 +3197,20 @@ int main(int argc, char** argv)
 
     ::arg().setSLog(startupLog);
 
-    const string yamlconfigname = configname + ".yml";
+    string yamlconfigname;
     pdns::rust::settings::rec::Recursorsettings settings;
-    auto yamlstatus = pdns::settings::rec::tryReadYAML(yamlconfigname, true, g_yamlSettings, g_luaSettingsInYAML, settings, startupLog);
-    if (yamlstatus == pdns::settings::rec::PresentButFailed) {
-      return 1;
+    pdns::settings::rec::YamlSettingsStatus yamlstatus{};
+
+    for (const string suffix : {".yml", ".conf"}) {
+      yamlconfigname = configname + suffix;
+      yamlstatus = pdns::settings::rec::tryReadYAML(yamlconfigname, true, g_yamlSettings, g_luaSettingsInYAML, settings, startupLog);
+      if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
+        g_yamlSettingsSuffix = suffix;
+        break;
+      }
+      if (suffix == ".yml" && yamlstatus == pdns::settings::rec::PresentButFailed) {
+        return 1;
+      }
     }
 
     if (g_yamlSettings) {
@@ -3190,10 +3222,11 @@ int main(int argc, char** argv)
     }
     if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
       auto lock = g_yamlStruct.lock();
-      *lock = settings;
+      *lock = std::move(settings);
     }
-    if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::CannotOpen) {
+    else {
       configname += ".conf";
+      startupLog->info(Logr::Warning, "Trying to read YAML from .yml or .conf failed, failing back to old-style config read", "configname", Logging::Loggable(configname));
       bool mustExit = false;
       std::tie(ret, mustExit) = doConfig(startupLog, configname, argc, argv);
       if (ret != 0 || mustExit) {
@@ -3385,11 +3418,19 @@ void startLuaConfigDelayedThreads(const vector<RPZTrackerParams>& rpzs, uint64_t
   }
 }
 
+static void* pleaseInitPolCounts(const string& name)
+{
+  if (t_Counters.at(rec::PolicyNameHits::policyName).counts.count(name) == 0) {
+    t_Counters.at(rec::PolicyNameHits::policyName).counts[name] = 0;
+  }
+  return nullptr;
+}
+
 static void activateRPZFile(const RPZTrackerParams& params, LuaConfigItems& lci, shared_ptr<DNSFilterEngine::Zone>& zone)
 {
   auto log = lci.d_slog->withValues("file", Logging::Loggable(params.name));
 
-  zone->setName(params.polName);
+  zone->setName(params.polName.empty() ? "rpzFile" : params.polName);
   try {
     SLOG(g_log << Logger::Warning << "Loading RPZ from file '" << params.name << "'" << endl,
          log->info(Logr::Info, "Loading RPZ from file"));
@@ -3465,10 +3506,11 @@ static void activateRPZs(LuaConfigItems& lci)
     else {
       DNSName domain(params.name);
       zone->setDomain(domain);
-      zone->setName(params.polName);
+      zone->setName(params.polName.empty() ? params.name : params.polName);
       params.zoneIdx = lci.dfe.addZone(zone);
       activateRPZPrimary(params, lci, zone, domain);
     }
+    broadcastFunction([name = zone->getName()] { return pleaseInitPolCounts(name); });
   }
 }
 
index 74168567a31b870e19e6c66c88e67d34207f7c76..4423ffcf8b4ca38c18160891fd77d84776a5d7a7 100644 (file)
@@ -43,9 +43,7 @@
 #include "nod.hh"
 #endif /* NOD_ENABLED */
 
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
 #include <boost/container/flat_set.hpp>
-#endif
 
 extern std::shared_ptr<Logr::Logger> g_slogtcpin;
 extern std::shared_ptr<Logr::Logger> g_slogudpin;
@@ -125,7 +123,7 @@ struct DNSComboWriter
   };
   std::string d_query;
   std::unordered_set<std::string> d_policyTags;
-  const std::unordered_set<std::string> d_gettagPolicyTags;
+  std::unordered_set<std::string> d_gettagPolicyTags;
   std::string d_routingTag;
   std::vector<DNSRecord> d_records;
 
@@ -193,6 +191,7 @@ extern std::unique_ptr<RecursorPacketCache> g_packetCache;
 using RemoteLoggerStats_t = std::unordered_map<std::string, RemoteLoggerInterface::Stats>;
 
 extern bool g_yamlSettings;
+extern string g_yamlSettingsSuffix;
 extern bool g_logCommonErrors;
 extern size_t g_proxyProtocolMaximumSize;
 extern std::atomic<bool> g_quiet;
@@ -205,6 +204,7 @@ extern unsigned int g_maxMThreads;
 extern bool g_reusePort;
 extern bool g_anyToTcp;
 extern size_t g_tcpMaxQueriesPerConn;
+extern unsigned int g_maxTCPClients;
 extern unsigned int g_maxTCPPerClient;
 extern int g_tcpTimeout;
 extern uint16_t g_udpTruncationThreshold;
@@ -212,6 +212,7 @@ extern double g_balancingFactor;
 extern size_t g_maxUDPQueriesPerRound;
 extern bool g_useKernelTimestamp;
 extern bool g_allowNoRD;
+extern unsigned int g_maxChainLength;
 extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
 extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
 extern thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
@@ -244,6 +245,7 @@ extern bool g_nodEnabled;
 extern DNSName g_nodLookupDomain;
 extern bool g_nodLog;
 extern SuffixMatchNode g_nodDomainWL;
+extern SuffixMatchNode g_udrDomainWL;
 extern std::string g_nod_pbtag;
 extern bool g_udrEnabled;
 extern bool g_udrLog;
@@ -273,11 +275,7 @@ extern thread_local FrameStreamServersInfo t_frameStreamServersInfo;
 extern thread_local FrameStreamServersInfo t_nodFrameStreamServersInfo;
 #endif /* HAVE_FSTRM */
 
-#ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
 extern boost::container::flat_set<uint16_t> g_avoidUdpSourcePorts;
-#else
-extern std::set<uint16_t> g_avoidUdpSourcePorts;
-#endif
 
 /* without reuseport, all listeners share the same sockets */
 typedef vector<pair<int, std::function<void(int, boost::any&)>>> deferredAdd_t;
@@ -623,6 +621,7 @@ string doTraceRegex(FDWrapper file, vector<string>::const_iterator begin, vector
 extern bool g_luaSettingsInYAML;
 void startLuaConfigDelayedThreads(const vector<RPZTrackerParams>& rpzs, uint64_t generation);
 void activateLuaConfig(LuaConfigItems& lci);
+unsigned int authWaitTimeMSec(const std::unique_ptr<MT_t>& mtasker);
 
 #define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
 #define LOCAL_NETS_INVERSE "!127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10"
index bcabe269942b66ae4f0e8d09cb1931d3f53ae85a..fd8106f2dad97455c4a3c6f9ef29957a05ea3e2b 100644 (file)
@@ -24,7 +24,7 @@
 #include "rec-protozero.hh"
 #include <variant>
 
-void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, [[maybe_unused]] bool udr)
+void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, [[maybe_unused]] std::optional<bool> udr)
 {
   if (record.d_place != DNSResourceRecord::ANSWER || record.d_class != QClass::IN) {
     return;
@@ -150,12 +150,14 @@ void pdns::ProtoZero::RecMessage::addRR(const DNSRecord& record, const std::set<
     break;
   }
 #ifdef NOD_ENABLED
-  pbf_rr.add_bool(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::udr), udr);
-  pbf_rr.commit();
+  if (udr) {
+    pbf_rr.add_bool(static_cast<protozero::pbf_tag_type>(pdns::ProtoZero::Message::RRField::udr), *udr);
+    pbf_rr.commit();
 
-  // Save the offset of the byte containing the just added bool. We can do this since
-  // we know a bit about how protobuf's encoding works.
-  offsets.push_back(d_rspbuf.length() - 1);
+    // Save the offset of the byte containing the just added bool. We can do this since
+    // we know a bit about how protobuf's encoding works.
+    offsets.push_back(d_rspbuf.length() - 1);
+  }
 #endif
 }
 
index 926982a20c8e757f16f3233c982eaac614610901..7655b3c0c34a9d07b511d29f120bd20d71f5e7a4 100644 (file)
@@ -109,7 +109,7 @@ namespace ProtoZero
 
     // DNSResponse related fields below
 
-    void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, bool udr);
+    void addRR(const DNSRecord& record, const std::set<uint16_t>& exportTypes, std::optional<bool> udr);
 
     void setAppliedPolicyType(const DNSFilterEngine::PolicyType type)
     {
index 19b875beb5b392c66ac210da5c33109b5e28b0a7..5825defd3018b40da828b15d491543c2b1577ff2 100644 (file)
 
 #ifdef HAVE_NET_SNMP
 
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
 #define RECURSOR_OID 1, 3, 6, 1, 4, 1, 43315, 2
 #define RECURSOR_STATS_OID RECURSOR_OID, 1
 #define RECURSOR_TRAPS_OID RECURSOR_OID, 10, 0
@@ -195,6 +203,10 @@ static const oid10 packetCacheContendedOID = {RECURSOR_STATS_OID, 145};
 static const oid10 packetCacheAcquiredOID = {RECURSOR_STATS_OID, 146};
 static const oid10 nodEventsOID = {RECURSOR_STATS_OID, 147};
 static const oid10 udrEventsOID = {RECURSOR_STATS_OID, 148};
+static const oid10 maxChainLengthOID = {RECURSOR_STATS_OID, 149};
+static const oid10 maxChainWeightOID = {RECURSOR_STATS_OID, 150};
+static const oid10 chainLimitsOID = {RECURSOR_STATS_OID, 151};
+static const oid10 tcpOverflowOID = {RECURSOR_STATS_OID, 152};
 
 static std::unordered_map<oid, std::string> s_statsMap;
 
@@ -275,12 +287,9 @@ bool RecursorSNMPAgent::sendCustomTrap([[maybe_unused]] const std::string& reaso
 #ifdef HAVE_NET_SNMP
   netsnmp_variable_list* varList = nullptr;
 
-  snmp_varlist_add_variable(&varList,
-                            snmpTrapOID.data(),
-                            snmpTrapOID.size(),
-                            ASN_OBJECT_ID,
-                            customTrapOID.data(),
-                            customTrapOID.size() * sizeof(oid));
+  addSNMPTrapOID(&varList,
+                 customTrapOID.data(),
+                 customTrapOID.size() * sizeof(oid));
 
   snmp_varlist_add_variable(&varList,
                             trapReasonOID.data(),
@@ -428,6 +437,7 @@ RecursorSNMPAgent::RecursorSNMPAgent(const std::string& name, const std::string&
   registerCounter64Stat("non-resolving-nameserver-entries", nonResolvingNameserverEntriesOID);
   registerCounter64Stat("maintenance-usec", maintenanceUSecOID);
   registerCounter64Stat("maintenance-calls", maintenanceCallsOID);
+  registerCounter64Stat("chain-limits", chainLimitsOID);
 
 #define RCODE(num) registerCounter64Stat("auth-" + RCode::to_short_s(num) + "-answers", rcode##num##AnswersOID) // NOLINT(cppcoreguidelines-macro-usage)
   RCODE(0);
@@ -451,6 +461,9 @@ RecursorSNMPAgent::RecursorSNMPAgent(const std::string& name, const std::string&
   registerCounter64Stat("packetcache-acquired", packetCacheAcquiredOID);
   registerCounter64Stat("nod-events", nodEventsOID);
   registerCounter64Stat("udr-events", udrEventsOID);
+  registerCounter64Stat("max-chain-length", maxChainLengthOID);
+  registerCounter64Stat("max-chain-weight", maxChainWeightOID);
+  registerCounter64Stat("tcp-overflow", tcpOverflowOID);
 
 #endif /* HAVE_NET_SNMP */
 }
index 6f8fb1ec574094448f7d4254451b5273f605c528..b50057cf74e584fd66b06870ad92def5d4821844 100644 (file)
@@ -92,7 +92,7 @@ std::string serverID()
   if (parser.d_header.rcode != RCode::NoError || parser.d_answers.size() != 1) {
     return {};
   }
-  const auto& dnsrecord = parser.d_answers.at(0).first;
+  const auto& dnsrecord = parser.d_answers.at(0);
   if (dnsrecord.d_type == QType::TXT) {
     if (auto txt = getRR<TXTRecordContent>(dnsrecord); txt != nullptr) {
       const auto& text = txt->d_text;
index 23e17efe5667857c34025ee14c8f789544168e03..a696c90b56c065a9b7c155e95eb78161eb56c745 100644 (file)
@@ -60,6 +60,7 @@ enum class Counter : uint8_t
   sourceDisallowedNotify, // when this is increased, qcounter is also
   zoneDisallowedNotify, // when this is increased, qcounter is also
   policyDrops,
+  tcpOverflow,
   tcpClientOverflow,
   clientParseError,
   serverParseError,
@@ -96,6 +97,9 @@ enum class Counter : uint8_t
   maintenanceCalls,
   nodCount,
   udrCount,
+  maxChainLength,
+  maxChainWeight,
+  chainLimits,
 
   numberOfCounters
 };
index c68d245b496ebc6833f5e0cbbd27e07981e268df..ef44a55a77b3a4a5b3ff66ca25c7b67f2cf3603c 100644 (file)
@@ -61,6 +61,7 @@
 // worker thread(s) now no longer process TCP queries.
 
 size_t g_tcpMaxQueriesPerConn;
+unsigned int g_maxTCPClients;
 unsigned int g_maxTCPPerClient;
 int g_tcpTimeout;
 bool g_anyToTcp;
@@ -327,16 +328,23 @@ static void doProcessTCPQuestion(std::unique_ptr<DNSComboWriter>& comboWriter, s
       if (t_pdl) {
         try {
           if (t_pdl->hasGettagFFIFunc()) {
-            RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_local, comboWriter->d_remote, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_policyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
+            RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_local, comboWriter->d_remote, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_data, comboWriter->d_gettagPolicyTags, comboWriter->d_records, ednsOptions, comboWriter->d_proxyProtocolValues, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_rcode, comboWriter->d_ttlCap, comboWriter->d_variable, true, logQuery, comboWriter->d_logResponse, comboWriter->d_followCNAMERecords, comboWriter->d_extendedErrorCode, comboWriter->d_extendedErrorExtra, comboWriter->d_responsePaddingDisabled, comboWriter->d_meta);
             comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI);
             comboWriter->d_tag = t_pdl->gettag_ffi(params);
             comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI, comboWriter->d_tag, false);
           }
           else if (t_pdl->hasGettagFunc()) {
             comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag);
-            comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_policyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
+            comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.source, comboWriter->d_destination, qname, qtype, &comboWriter->d_gettagPolicyTags, comboWriter->d_data, ednsOptions, true, requestorId, deviceId, deviceName, comboWriter->d_routingTag, comboWriter->d_proxyProtocolValues);
             comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag, comboWriter->d_tag, false);
           }
+          // Copy d_gettagPolicyTags to d_policyTags, so other Lua hooks see them and can add their
+          // own. Before storing into the packetcache, the tags in d_gettagPolicyTags will be
+          // cleared by addPolicyTagsToPBMessageIfNeeded() so they do *not* end up in the PC. When an
+          // Protobuf message is constructed, one part comes from the PC (including the tags
+          // set by non-gettag hooks), and the tags in d_gettagPolicyTags will be added by the code
+          // constructing the PB message.
+          comboWriter->d_policyTags = comboWriter->d_gettagPolicyTags;
         }
         catch (const std::exception& e) {
           if (g_logCommonErrors) {
@@ -501,7 +509,7 @@ static void doProcessTCPQuestion(std::unique_ptr<DNSComboWriter>& comboWriter, s
   } // good query
 }
 
-static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& var)
+static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& var) // NOLINT(readability-function-cognitive-complexity)
 {
   auto conn = boost::any_cast<shared_ptr<TCPConnection>>(var);
 
@@ -565,6 +573,9 @@ static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& v
           ++iter->second.stats.netmaskMatches;
         }
       }
+      if (t_remotes) {
+        t_remotes->push_back(conn->d_source);
+      }
       if (t_allowFrom && !t_allowFrom->match(&conn->d_mappedSource)) {
         if (!g_quiet) {
           SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << conn->d_mappedSource.toString() << ", address not matched by allow-from" << endl,
@@ -680,86 +691,79 @@ void handleNewTCPQuestion(int fileDesc, [[maybe_unused]] FDMultiplexer::funcpara
   ComboAddress addr;
   socklen_t addrlen = sizeof(addr);
   int newsock = accept(fileDesc, reinterpret_cast<struct sockaddr*>(&addr), &addrlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
-  if (newsock >= 0) {
-    if (g_multiTasker->numProcesses() > g_maxMThreads) {
-      t_Counters.at(rec::Counter::overCapacityDrops)++;
-      try {
-        closesocket(newsock);
-      }
-      catch (const PDNSException& e) {
-        SLOG(g_log << Logger::Error << "Error closing TCP socket after an over capacity drop: " << e.reason << endl,
-             g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an over capacity drop", "exception", Logging::Loggable("PDNSException")));
-      }
-      return;
-    }
-
-    if (t_remotes) {
-      t_remotes->push_back(addr);
-    }
-
-    ComboAddress destaddr;
-    socklen_t len = sizeof(destaddr);
-    getsockname(newsock, reinterpret_cast<sockaddr*>(&destaddr), &len); // if this fails, we're ok with it NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
-    bool fromProxyProtocolSource = expectProxyProtocol(addr, destaddr);
-    ComboAddress mappedSource = addr;
-    if (!fromProxyProtocolSource && t_proxyMapping) {
-      if (const auto* iter = t_proxyMapping->lookup(addr)) {
-        mappedSource = iter->second.address;
-        ++iter->second.stats.netmaskMatches;
-      }
+  if (newsock < 0) {
+    return;
+  }
+  auto closeSock = [newsock](rec::Counter cnt, const string& msg) {
+    try {
+      closesocket(newsock);
+      t_Counters.at(cnt)++;
+      // We want this bump to percolate up without too much delay
+      t_Counters.updateSnap(false);
     }
-    if (!fromProxyProtocolSource && t_allowFrom && !t_allowFrom->match(&mappedSource)) {
-      if (!g_quiet) {
-        SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << mappedSource.toString() << ", address neither matched by allow-from nor proxy-protocol-from" << endl,
-             g_slogtcpin->info(Logr::Error, "dropping TCP query address neither matched by allow-from nor proxy-protocol-from", "source", Logging::Loggable(mappedSource)));
-      }
-      t_Counters.at(rec::Counter::unauthorizedTCP)++;
-      try {
-        closesocket(newsock);
-      }
-      catch (const PDNSException& e) {
-        SLOG(g_log << Logger::Error << "Error closing TCP socket after an ACL drop: " << e.reason << endl,
-             g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an ACL drop", "exception", Logging::Loggable("PDNSException")));
-      }
-      return;
+    catch (const PDNSException& e) {
+      g_slogtcpin->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException"));
     }
+  };
 
-    if (g_maxTCPPerClient > 0 && t_tcpClientCounts->count(addr) > 0 && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
-      t_Counters.at(rec::Counter::tcpClientOverflow)++;
-      try {
-        closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
-      }
-      catch (const PDNSException& e) {
-        SLOG(g_log << Logger::Error << "Error closing TCP socket after an overflow drop: " << e.reason << endl,
-             g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCP socket after an overflow drop", "exception", Logging::Loggable("PDNSException")));
-      }
-      return;
-    }
+  if (TCPConnection::getCurrentConnections() >= g_maxTCPClients) {
+    closeSock(rec::Counter::tcpOverflow, "Error closing TCP socket after an overflow drop");
+    return;
+  }
+  if (g_multiTasker->numProcesses() >= g_maxMThreads) {
+    closeSock(rec::Counter::overCapacityDrops, "Error closing TCP socket after an over capacity drop");
+    return;
+  }
 
-    setNonBlocking(newsock);
-    setTCPNoDelay(newsock);
-    std::shared_ptr<TCPConnection> tcpConn = std::make_shared<TCPConnection>(newsock, addr);
-    tcpConn->d_source = addr;
-    tcpConn->d_destination = destaddr;
-    tcpConn->d_mappedSource = mappedSource;
-
-    if (fromProxyProtocolSource) {
-      tcpConn->proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
-      tcpConn->data.resize(tcpConn->proxyProtocolNeed);
-      tcpConn->state = TCPConnection::PROXYPROTOCOLHEADER;
+  ComboAddress destaddr;
+  socklen_t len = sizeof(destaddr);
+  getsockname(newsock, reinterpret_cast<sockaddr*>(&destaddr), &len); // if this fails, we're ok with it NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+  bool fromProxyProtocolSource = expectProxyProtocol(addr, destaddr);
+  if (!fromProxyProtocolSource && t_remotes) {
+    t_remotes->push_back(addr);
+  }
+  ComboAddress mappedSource = addr;
+  if (!fromProxyProtocolSource && t_proxyMapping) {
+    if (const auto* iter = t_proxyMapping->lookup(addr)) {
+      mappedSource = iter->second.address;
+      ++iter->second.stats.netmaskMatches;
     }
-    else {
-      tcpConn->state = TCPConnection::BYTE0;
+  }
+  if (!fromProxyProtocolSource && t_allowFrom && !t_allowFrom->match(&mappedSource)) {
+    if (!g_quiet) {
+      SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP query from " << mappedSource.toString() << ", address neither matched by allow-from nor proxy-protocol-from" << endl,
+           g_slogtcpin->info(Logr::Error, "dropping TCP query address neither matched by allow-from nor proxy-protocol-from", "source", Logging::Loggable(mappedSource)));
     }
+    closeSock(rec::Counter::unauthorizedTCP, "Error closing TCP socket after an ACL drop");
+    return;
+  }
 
-    struct timeval ttd
-    {
-    };
-    Utility::gettimeofday(&ttd, nullptr);
-    ttd.tv_sec += g_tcpTimeout;
+  if (g_maxTCPPerClient > 0 && t_tcpClientCounts->count(addr) > 0 && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) {
+    closeSock(rec::Counter::tcpClientOverflow, "Error closing TCP socket after a client overflow drop");
+    return;
+  }
 
-    t_fdm->addReadFD(tcpConn->getFD(), handleRunningTCPQuestion, tcpConn, &ttd);
+  setNonBlocking(newsock);
+  setTCPNoDelay(newsock);
+  std::shared_ptr<TCPConnection> tcpConn = std::make_shared<TCPConnection>(newsock, addr);
+  tcpConn->d_source = addr;
+  tcpConn->d_destination = destaddr;
+  tcpConn->d_mappedSource = mappedSource;
+
+  if (fromProxyProtocolSource) {
+    tcpConn->proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
+    tcpConn->data.resize(tcpConn->proxyProtocolNeed);
+    tcpConn->state = TCPConnection::PROXYPROTOCOLHEADER;
+  }
+  else {
+    tcpConn->state = TCPConnection::BYTE0;
   }
+
+  timeval ttd{};
+  Utility::gettimeofday(&ttd, nullptr);
+  ttd.tv_sec += g_tcpTimeout;
+
+  t_fdm->addReadFD(tcpConn->getFD(), handleRunningTCPQuestion, tcpConn, &ttd);
 }
 
 static void TCPIOHandlerIO(int fileDesc, FDMultiplexer::funcparam_t& var);
@@ -1060,7 +1064,7 @@ LWResult::Result arecvtcp(PacketBuffer& data, const size_t len, shared_ptr<TCPIO
   // Will set pident->lowState
   TCPIOHandlerStateChange(IOState::Done, state, pident);
 
-  int ret = g_multiTasker->waitEvent(pident, &data, g_networkTimeoutMsec);
+  int ret = g_multiTasker->waitEvent(pident, &data, authWaitTimeMSec(g_multiTasker));
   TCPLOG(pident->tcpsock, "arecvtcp " << ret << ' ' << data.size() << ' ');
   if (ret == 0) {
     TCPLOG(pident->tcpsock, "timeout" << endl);
index 18bd991a0d87e7beee6c569c836f76447c438d93..f4eb031a91f3d1d7cb691a729c8842fa3120666b 100644 (file)
@@ -1349,6 +1349,7 @@ static void registerAllStats1()
   addGetStat("unauthorized-tcp", [] { return g_Counters.sum(rec::Counter::unauthorizedTCP); });
   addGetStat("source-disallowed-notify", [] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); });
   addGetStat("zone-disallowed-notify", [] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); });
+  addGetStat("tcp-overflow", [] { return g_Counters.sum(rec::Counter::tcpOverflow); });
   addGetStat("tcp-client-overflow", [] { return g_Counters.sum(rec::Counter::tcpClientOverflow); });
 
   addGetStat("client-parse-errors", [] { return g_Counters.sum(rec::Counter::clientParseError); });
@@ -1566,6 +1567,10 @@ static void registerAllStats1()
   addGetStat("nod-events", [] { return g_Counters.sum(rec::Counter::nodCount); });
   addGetStat("udr-events", [] { return g_Counters.sum(rec::Counter::udrCount); });
 
+  addGetStat("max-chain-length", [] { return g_Counters.max(rec::Counter::maxChainLength); });
+  addGetStat("max-chain-weight", [] { return g_Counters.max(rec::Counter::maxChainWeight); });
+  addGetStat("chain-limits", [] { return g_Counters.sum(rec::Counter::chainLimits); });
+
   /* make sure that the ECS stats are properly initialized */
   SyncRes::clearECSStats();
   for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
@@ -2204,7 +2209,7 @@ RecursorControlChannel::Answer luaconfig(bool broadcast)
     bool dummy1{};
     bool dummy2{};
     pdns::rust::settings::rec::Recursorsettings settings;
-    auto yamlstat = pdns::settings::rec::tryReadYAML(configname + ".yml", false, dummy1, dummy2, settings, g_slog);
+    auto yamlstat = pdns::settings::rec::tryReadYAML(configname + g_yamlSettingsSuffix, false, dummy1, dummy2, settings, g_slog);
     if (yamlstat != pdns::settings::rec::YamlSettingsStatus::OK) {
       return {1, "Not reloading dynamic part of YAML configuration\n"};
     }
@@ -2215,7 +2220,7 @@ RecursorControlChannel::Answer luaconfig(bool broadcast)
     lci = g_luaconfs.getCopy();
     if (broadcast) {
       startLuaConfigDelayedThreads(lci.rpzs, lci.generation);
-      broadcastFunction([=] { return pleaseSupplantProxyMapping(proxyMapping); });
+      broadcastFunction([pmap = std::move(proxyMapping)] { return pleaseSupplantProxyMapping(pmap); });
     }
     else {
       // Initial proxy mapping
index 6b2937cf44ab17a081da1cc15825d6177aa1079a..30187a11fe422b7d9105219c4cc9174c0c49c4fd 100644 (file)
@@ -74,26 +74,33 @@ static void initArguments(int argc, char** argv, Logr::log_t log)
 
   cleanSlashes(configname);
 
-  const string yamlconfigname = configname + ".yml";
   string msg;
   pdns::rust::settings::rec::Recursorsettings settings;
-
-  auto yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, "", settings, msg, g_slog);
-
-  switch (yamlstatus) {
-  case pdns::settings::rec::YamlSettingsStatus::CannotOpen:
-    break;
-  case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
-    log->error(Logr::Error, msg, "YAML config found, but error ocurred processing it", "configname", Logging::Loggable(yamlconfigname));
-    exit(1); // NOLINT(concurrency-mt-unsafe)
-    break;
-  case pdns::settings::rec::YamlSettingsStatus::OK:
-    log->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname));
-    pdns::settings::rec::bridgeStructToOldStyleSettings(settings);
-    break;
+  pdns::settings::rec::YamlSettingsStatus yamlstatus{};
+
+  for (const string suffix : {".yml", ".conf"}) {
+    const string yamlconfigname = configname + suffix;
+    yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, "", settings, msg, g_slog);
+
+    switch (yamlstatus) {
+    case pdns::settings::rec::YamlSettingsStatus::CannotOpen:
+      break;
+    case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
+      if (suffix == ".yml") {
+        log->error(Logr::Error, msg, "YAML config found, but error ocurred processing it", "configname", Logging::Loggable(yamlconfigname));
+        exit(1); // NOLINT(concurrency-mt-unsafe)
+      }
+      break;
+    case pdns::settings::rec::YamlSettingsStatus::OK:
+      log->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname));
+      pdns::settings::rec::bridgeStructToOldStyleSettings(settings);
+      break;
+    }
+    if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::OK) {
+      break;
+    }
   }
-
-  if (yamlstatus == pdns::settings::rec::YamlSettingsStatus::CannotOpen) {
+  if (yamlstatus != pdns::settings::rec::YamlSettingsStatus::OK) {
     configname += ".conf";
     arg().laxFile(configname);
   }
index f8d50bdfb9cb5aecc1c81616f81bb4d08d2592b5..747c11d83d9a4a09fb5511bf9ec2ee4e3b5e9248 100644 (file)
 #include "settings/cxxsettings.hh"
 #include "rec-system-resolve.hh"
 
+// XXX consider including rec-main.hh?
 extern int g_argc;
 extern char** g_argv;
+extern string g_yamlSettingsSuffix;
 
 bool primeHints(time_t now)
 {
@@ -147,7 +149,7 @@ string reloadZoneConfiguration(bool yaml)
          log->info(Logr::Notice, "Reloading zones, purging data from cache"));
 
     if (yaml) {
-      configname += ".yml";
+      configname += g_yamlSettingsSuffix;
       string msg;
       pdns::rust::settings::rec::Recursorsettings settings;
       // XXX Does ::arg()["include-dir"] have the right value, i.e. potentially overriden by command line?
index 486019d776ab065bd5fa4b72aaec713ade5f013e..a7471d64cabf4176939241837cdb1fdc626b381b 100644 (file)
@@ -269,10 +269,13 @@ static shared_ptr<const SOARecordContent> loadRPZFromServer(Logr::log_t plogger,
         continue;
       }
 
+      // We want the full name in the SOA record
+      if (dnsRecord.d_type == QType::SOA) {
+        zone->setSOA(dnsRecord);
+      }
       dnsRecord.d_name.makeUsRelative(zoneName);
       if (dnsRecord.d_type == QType::SOA) {
         soaRecordContent = getRR<SOARecordContent>(dnsRecord);
-        zone->setSOA(dnsRecord);
         continue;
       }
 
index 9d86c6d8271dc1137f88403f2753d006777f3e9c..29edba02d5563bfe6c1c88b62ea4c8a5943cfbb7 100644 (file)
@@ -6,10 +6,10 @@ Inside this directory, there is a `rust` subdirectory that contains the Rust cod
 The Rust code uses CXX for bridging between C++ and Rust.
 At the moment of writing, we only call Rust code from C++ and not vice versa.
 
-Additionally, the Rust Serde crate (and specifically Serde-YAML) is used to generatec code to handle YAML.
+Additionally, the Rust Serde crate (and specifically Serde-YAML) is used to generate code to handle YAML.
 
 The entry point for code generation is `generate.py`, which uses `table.py` to produce C++, Rust and .rst files.
-See `generate.sh` for some details about the generation process.
+See `generate.py` for some details about the generation process.
 This directory also contains a couple of `*-in.*` files which are included into files generated by the generation process.
 
 From the C++ point of view, several namespaces are defined:
@@ -47,7 +47,7 @@ This directory
 * `build.rs`: `The custom build file used by CXX, see CXX docs.
 * `cxx.h`: The generic types used by CXX generated code.
 * `lib.rs.h`:  The project specific C++ types generated by CXX.
-* `libsettings.a`: The actual static library procuced by this crate.
+* `libsettings.a`: The actual static library produced by this crate.
 * `src`: The actual rust code, `lib.rs` is generated, `bridge.rs` and `helpers.rs` are maintained manually.
 * `target`: The `cargo` maintained Rust build directory.
 
@@ -84,7 +84,7 @@ webservice:
 
 The generated code
 ------------------
-C++, Rust and docmentation generating is done by the `generate.py` Python script using `table.py` as input.
+C++, Rust and documentation generating is done by the `generate.py` Python script using `table.py` as input.
 After that, the C++ to Rust bridge code is generated by CXX.
 Lets take a look at the `log_bogus` setting.
 The source of its definition is in `table.py`:
@@ -104,7 +104,7 @@ Log every DNSSEC validation failure.
     },
 ```
 
-The old-style documention generated for this can be found in `../docs/settings.rst`:
+The old-style documentation generated for this can be found in `../docs/settings.rst`:
 
 ```
 .. _setting-dnssec-log-bogus:
@@ -121,7 +121,7 @@ Log every DNSSEC validation failure.
 **Note**: This is not logged per-query but every time records are validated as Bogus.
 ```
 
-The new-style documention generated for this can be found in `../docs/yamlsettings.rst`, its name includes the section and it lists a YAML default:
+The new-style documentation generated for this can be found in `../docs/yamlsettings.rst`, its name includes the section and it lists a YAML default:
 
 ```
 .. _setting-yaml-dnssec.log_bogus:
index 0edb5472d1a7c85586c8ded3bf27f33a0af6b4f2..db1053f110cfc02d7631c92c60c0bc32e58d7b3f 100644 (file)
@@ -638,7 +638,7 @@ std::string pdns::settings::rec::defaultsToYaml()
     // And for all other values below, the default is either an empty string or an empty vector.
     // Once we get more u64 values below with different default values this hack no longer works.
     rustvalue.u64_val = 24;
-    map.emplace(std::pair{std::pair{section, name}, pdns::rust::settings::rec::OldStyle{section, name, name, type, rustvalue, false}});
+    map.emplace(std::pair{std::pair{section, name}, pdns::rust::settings::rec::OldStyle{section, name, name, type, std::move(rustvalue), false}});
   };
   def("dnssec", "trustanchors", "Vec<TrustAnchor>");
   def("dnssec", "negative_trustanchors", "Vec<NegativeTrustAnchor>");
@@ -729,7 +729,7 @@ void fromLuaToRust(const LuaConfigItems& luaConfig, pdns::rust::settings::rec::D
       }
     }
     if (!dsRecords.empty()) {
-      pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), dsRecords};
+      pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), std::move(dsRecords)};
       dnssec.trustanchors.emplace_back(trustAnchor);
     }
   }
@@ -1358,7 +1358,7 @@ pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::tryReadYAML(const s
 
   case pdns::settings::rec::YamlSettingsStatus::PresentButFailed:
     SLOG(g_log << Logger::Error << "YAML config found for configname '" << yamlconfigname << "' but error ocurred processing it" << endl,
-         startupLog->error(Logr::Error, msg, "YAML config found, but error occurred processsing it", "configname", Logging::Loggable(yamlconfigname)));
+         startupLog->error(Logr::Error, msg, "YAML config found, but error occurred processing it", "configname", Logging::Loggable(yamlconfigname)));
     break;
 
   case pdns::settings::rec::YamlSettingsStatus::OK:
index 6aaba02b3a105334b1ac921a35e87d5101df56a0..df5a08ae5b685ae543dc152a34b780c177b6d012 100644 (file)
@@ -10,12 +10,13 @@ Settings on the command line are processed after the file-based settings are pro
    If both ``recursor.conf`` and ``recursor.yml`` files are found in the configuration directory the YAML file is used.
    A configuration using the old style syntax can be converted to a YAML configuration using the instructions in :doc:`appendices/yamlconversion`.
 
-   Release 5.0.0 will install a default old-style ``recursor.conf`` files only.
+   Release 5.0.0 will install a default old-style ``recursor.conf`` file.
 
-   With the release of version 5.1.0, packages will stop installing a default ``recursor.conf`` and start installing a default ``recursor.yml`` file if no existing ``recursor.conf`` is present.
-   In the absense of a ``recursor.yml`` file, an existing ``recursor.conf`` file will be accepted and used.
+   Starting with version 5.1.0, in the absence of a ``recursor.yml`` file, an existing ``recursor.conf`` will be processed as YAML,
+   if that fails, it will be processed as old-style configuration.
+   Packages will stop installing a old-style ``recursor.conf`` file and start installing a default ``recursor.conf`` file containing YAML syntax.
 
-   With the release of 5.2.0, the default will be to expect a ``recursor.yml`` file and reading of ``recursor.conf`` files will have to be enabled specifically by providing a command line option.
+   With the release of 5.2.0, the default will be to expect a YAML configuration file and reading of old-style ``recursor.conf`` files will have to be enabled specifically by providing a command line option.
 
    In a future release support for the "old-style" ``recursor.conf`` settings file will be dropped.
 
@@ -91,7 +92,7 @@ For example, with the above example ``recursor.yml`` and an include directory co
 
 After merging, ``dnssec.log_bogus`` will be ``false``, the sequence of ``recursor.forward_zones`` will contain 2 zones and the ``outgoing`` addresses used will contain one entry, as the ``extra.yml`` entry has overwritten the existing one.
 
-``outgoing.dont-query`` has a non-empty sequence as default value. The main ``recursor.yml`` did not set it, so before processing ``extra.yml`` had the default value.
+``outgoing.dont-query`` has a non-empty sequence as default value. The main ``recursor.yml`` did not set it, so before processing ``extra.yml`` it had the default value.
 After processing ``extra.yml`` the value will be set to the empty sequence, as existing default values are overwritten by new values.
 
 .. warning::
@@ -117,9 +118,12 @@ After processing ``extra.yml`` the value will be set to the empty sequence, as e
    The result will *not* be a a single forward with two IP addresses, but two entries for ``example.net``.
    It depends on the specific setting how the sequence is processed and interpreted further.
 
+Description of YAML syntax for structured types
+-----------------------------------------------
+
 Socket Address
 ^^^^^^^^^^^^^^
-A socket address is either an IP or and IP:port combination
+A socket address is a string containing either an IP address or and IP address:port combination
 For example:
 
 .. code-block:: yaml
@@ -134,7 +138,7 @@ If no prefix length is specified, ``/32`` or ``/128`` is assumed, indicating a s
 Subnets can also be prefixed with a ``!``, specifying negation.
 This can be used to deny addresses from a previously allowed range.
 
-For example, ``alow-from`` takes a sequence of subnets:
+For example, ``allow-from`` takes a sequence of subnets:
 
 .. code-block:: yaml
 
@@ -151,14 +155,14 @@ A forward zone is defined as:
 
 .. code-block:: yaml
 
-  zone: zonename
+  zone: string
   forwarders:
     - Socket Address
     - ...
   recurse: Boolean, default false
   allow_notify:  Boolean, default false
 
-An example of a ``forward_zones`` entry, which consists of a sequence of forward zone entries:
+An example of a ``forward_zones`` entry, which consists of a sequence of `Forward Zone`_ entries:
 
 .. code-block:: yaml
 
@@ -185,10 +189,10 @@ An auth zone is defined as:
 
 .. code-block:: yaml
 
-  zone: name
-  file: filename
+  zone: string
+  file: string
 
-An example of a ``auth_zones`` entry, consisting of a sequence of auth zones:
+An example of a ``auth_zones`` entry, consisting of a sequence of `Auth Zone`_:
 
 .. code-block:: yaml
 
@@ -199,10 +203,10 @@ An example of a ``auth_zones`` entry, consisting of a sequence of auth zones:
        file: zones/example.net.zone
 
 
-YAML settings corresponding to Lua config items
------------------------------------------------
+Description of YAML syntax corresponding to Lua config items
+------------------------------------------------------------
 
-The YAML settings below were introduced in verison 5.1.0 and correspond to the
+The YAML settings below were introduced in version 5.1.0 and correspond to their
 respective Lua settings. Refer to :doc:`lua-config/index`.
 
 TrustAnchor
@@ -211,10 +215,10 @@ As of version 5.1.0, a trust anchor is defined as
 
 .. code-block:: yaml
 
-   name: zonename
+   name: string
    dsrecords: sequence of DS record strings in presentation format
 
-An example of a ``trustanchors`` sequence:
+An example of a ``trustanchors`` entry, which is a sequence of `TrustAnchor`_:
 
 .. code-block:: yaml
 
@@ -229,10 +233,10 @@ As of version 5.1.0, a negative trust anchor is defined as
 
 .. code-block:: yaml
 
-   name: zonename
-   reason: text
+   name: string
+   reason: string
 
-An example of a ``negative trustanchors`` sequence:
+An example of a ``negative_trustanchors`` entry, which is a sequence of `NegativeTrustAnchor`_:
 
 .. code-block:: yaml
 
@@ -257,21 +261,17 @@ As of version 5.1.0, a protobuf server is defined as
     exportTypes: [A, AAAA, CNAME] Sequence of QType names
     logMappedFrom: false
 
-An example of a ``protobuf_servers`` entry:
+An example of a ``protobuf_servers`` entry, which is a sequence of `ProtobufServer`_:
 
 .. code-block:: yaml
 
   protobuf_servers:
-  - servers: [6.7.8.9]
-    timeout: 2
-    maxQueuedEntries: 100
-    reconnectWaitTime: 1
-    taggedOnly: false
-    asyncConnect: false
-    logQueries: true
-    logResponses: true
-    exportTypes: [A, AAAA, CNAME]
-    logMappedFrom: false
+    - servers: [127.0.0.1:4578]
+      exportTypes: [A, AAAA]
+    - servers: ['[2001:DB8::1]':7891]
+      logQueries: false
+      logResponses: true
+      exportTypes: [A]
 
 DNSTapFrameStreamServers
 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -289,6 +289,14 @@ As of version 5.1.0, a dnstap framestream server is defined as
   queueNotifyThreshold: 0
   reopenInterval: 0
 
+An example of a ``dnstap_framestream_servers`` entry, which is a sequence of `DNSTapFrameStreamServers`_:
+
+.. code-block:: yaml
+
+  dnstap_framestream_servers:
+    - servers: [127.0.0.1:2024]
+      logQueries: false
+      logResponses: true
 
 DNSTapNODFrameStreamServers
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +304,7 @@ As of version 5.1.0, an NOD dnstap framestream server is defined as
 
 .. code-block:: yaml
 
-  servers: [] Sequence of strings representing SocketAddress or a socker path
+  servers: [] Sequence of strings representing SocketAddress or a socket path
   logNODs: true
   logUDRs: false
   bufferHint: 0
@@ -306,6 +314,15 @@ As of version 5.1.0, an NOD dnstap framestream server is defined as
   queueNotifyThreshold: 0
   reopenInterval: 0
 
+An example of a ``dnstap_nod_framestream_servers`` entry, which is a sequence of `DNSTapNODFrameStreamServers`_:
+
+.. code-block:: yaml
+
+  dnstap_nop_framestream_servers:
+    - servers: [127.0.0.1:2024]
+      logNODs: false
+      logUDRs: true
+
 SortList
 ^^^^^^^^
 As of version 5.1.0, a sortlist entry is defined as
@@ -317,6 +334,22 @@ As of version 5.1.0, a sortlist entry is defined as
       - subnet: Subnet
         order: number
 
+An example of a ``sortlists`` entry, which is a sequence of `SortList`_:
+
+.. code-block:: yaml
+
+  sortlists:
+    - key: 198.18.0.0/8
+      subnets:
+       - subnet: 233.252.0.0/24
+         order: 10
+    - key: 198.18.1.0/8
+      subnets:
+        - subnet: 198.18.0.0/16
+          order: 20
+        - subnet: 203.0.113.0/24
+          order: 20
+
 RPZ
 ^^^
 As of version 5.1.0, an RPZ entry is defined as
@@ -349,7 +382,18 @@ As of version 5.1.0, an RPZ entry is defined as
     dumpFile: string
     seedFile: string
 
-If ``addresses` is empty, the ``name`` field specifies the path name of the RPZ, otherwise the ``name`` field defines the name of the RPZ.
+If ``addresses`` is empty, the ``name`` field specifies the path name of the RPZ, otherwise the ``name`` field defines the name of the RPZ.
+
+
+An example of an ``rpzs`` entry, which is a sequence of `RPZ`_:
+
+.. code-block:: yaml
+
+  rpzs:
+    - name: 'path/to/a/file'
+    - name: 'remote.rpz'
+      addresses: ['192.168.178.99']
+      policyName: mypolicy
 
 ZoneToCache
 ^^^^^^^^^^^
@@ -364,29 +408,29 @@ As of version 5.1.0, a ZoneToCache entry is defined as
    tsig:
      name: name of key
      algo: algorithm
-     secret: Base64 endcoded secret
+     secret: Base64 encoded secret
    refreshPeriod: 86400
    retryOnErrorPeriod: 60
    maxReceivedMBytes: 0 Zero mean no restrcition
-   localAddress: local IP address to  bind to. 
+   localAddress: local IP address to  bind to.
    zonemd: One of ignore, validate, require
    dnssec: One of ignore, validate, require
 
-For example, a sequence of two ZoneToCache entries:
+An example of an ``zonetocaches`` entry, which is a sequence of `ZoneToCache`_:
 
 .. code-block:: yaml
 
    zonetocaches:
-   - zone: .
-     method: url
-     sources: ['http://...']
-    - zone: example.com
-      method: file
-      sources: ['dir/example.com.zone']
+     - zone: .
+       method: url
+       sources: ['https://www.example.com/path']
+     - zone: example.com
+       method: file
+       sources: ['dir/example.com.zone']
 
 AllowedAdditionalQType
 ^^^^^^^^^^^^^^^^^^^^^^
-As of version 5.1.0, an allowed addtional qtype entry is defined as:
+As of version 5.1.0, an allowed additional qtype entry is defined as:
 
 .. code-block:: yaml
 
@@ -394,7 +438,7 @@ As of version 5.1.0, an allowed addtional qtype entry is defined as:
    targets: [] Sequence of string representing QType
    mode: One of Ignore, CacheOnly, CacheOnlyRequireAuth, ResolveImmediately, ResolveDeferred, default CacheOnlyRequireAuth
 
-For example:
+An example of an ``allowed_additional_qtypes`` entry, which is a sequence of `AllowedAdditionalQType`_:
 
 .. code-block:: yaml
 
@@ -415,15 +459,29 @@ As of version 5.1.0, a proxy mapping entry is defined as:
    address: IPAddress
    domains: [] Sequence of string
 
-For example:
+An example of an ``proxymappings`` entry, which is a sequence of `ProxyMapping`_:
 
 .. code-block:: yaml
 
    proxymappings:
-   - subnet: 192.168.178.0/24
-     address: 128.66.1.2
-
+     - subnet: 192.168.178.0/24
+       address: 128.66.1.2
+     - subnet: 192.168.179.0/24
+       address: 128.66.1.3
+       domains:
+         - example.com
+         - example.net
 
 The YAML settings
 -----------------
 
+The notation ``section.name`` means that an entry ``name`` can appear in the YAML section ``section``.
+So the entry ``recordcache.max_ttl`` will end up in settings file as follows:
+
+.. code-block:: yaml
+
+   recordcache:
+     ...
+     max_ttl: 3600
+     ...
+
index c4aabd94b581932c2050753c2a13a40f5edd01ef..297d542d72bae03cadeaa8a2938a45b0992d99e1 100644 (file)
@@ -6,7 +6,7 @@ The command line overrides the configuration file.
 .. note::
    Starting with version 5.0.0, :program:`Recursor` supports a new YAML syntax for configuration files.
    A configuration using the old style syntax can be converted to a YAML configuration using the instructions in :doc:`appendices/yamlconversion`.
-   In a future release support for the "old-style" settings decribed here will be dropped.
+   In a future release support for the "old-style" settings described here will be dropped.
    See :doc:`yamlsettings` for details.
 
 .. note::
index 454bbaf08b6d18247ccaf2cd087d2ddb97caf6db..549bfe38f4ffc14658d1d90b5d8deb2303445ebb 100644 (file)
@@ -5,7 +5,7 @@
 #
 # For Rust it generates rust/src/lib.rs, containing the structs with
 # CXX and Serde annotations and associated code. rust-preamble-in.rs is
-# included before the generated code and rus-bridge-in.rs inside the
+# included before the generated code and rust-bridge-in.rs inside the
 # bridge module in the generated lib.rs. Header files generated by CXX
 # (lib.rs.h and cxx.h) are copied from deep inside the generated code
 # hierarchy into the rust subdir as well.
@@ -377,9 +377,9 @@ def gen_cxx_brigestructtoldstylesettings(file, entries):
         file.write(f'to_arg(settings.{section}.{name});\n')
     file.write('}\n')
 
-def gen_cxx(entries):
+def gen_cxx(gendir, entries):
     """Generate the C++ code from the defs in table.py"""
-    with open('cxxsettings-generated.cc', mode='w', encoding="UTF-8") as file:
+    with open(gendir + '/cxxsettings-generated.cc', mode='w', encoding="UTF-8") as file:
         file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n\n')
         file.write('#include "arguments.hh"\n')
         file.write('#include "cxxsettings.hh"\n')
@@ -405,7 +405,8 @@ def gen_rust_vec_default_functions(name, typeName, defvalue):
     """Generate Rust code for the default handling of a vector for typeName"""
     ret = f'// DEFAULT HANDLING for {name}\n'
     ret += f'fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n'
-    ret += f'    let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).unwrap();\n'
+    ret += f'    let msg = "default value defined for `{name}\' should be valid YAML";'
+    ret += f'    let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).expect(&msg);\n'
     ret += f'    deserialized\n'
     ret += '}\n'
     ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)'
@@ -560,7 +561,7 @@ def write_rust_merge_trait_impl(file, section, entries):
         name = entry['name']
         file.write(f'            if m.contains_key("{name}") {{\n')
         if rtype in ('bool', 'u64', 'f64', 'String'):
-            file.write(f'                self.{name} = rhs.{name}.to_owned();\n')
+            file.write(f'                rhs.{name}.clone_into(&mut self.{name});\n')
         else:
             file.write(f'                if is_overriding(m, "{name}") || ')
             file.write(f'self.{name} == DEFAULT_CONFIG.{section}.{name} {{\n')
@@ -572,20 +573,20 @@ def write_rust_merge_trait_impl(file, section, entries):
     file.write('    }\n')
     file.write('}\n\n')
 
-def gen_rust(entries):
+def gen_rust(srcdir, entries):
     """Generate Rust code all entries"""
     def_functions = []
     sections = {}
-    with open('rust/src/lib.rs', mode='w', encoding='UTF-8') as file:
+    with open(srcdir + '/rust/src/lib.rs', mode='w', encoding='UTF-8') as file:
         file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
         file.write('// START INCLUDE rust-preable-in.rs\n')
-        with open('rust-preamble-in.rs', mode='r', encoding='UTF-8') as pre:
+        with open(srcdir + '/rust-preamble-in.rs', mode='r', encoding='UTF-8') as pre:
             file.write(pre.read())
             file.write('// END INCLUDE rust-preamble-in.rs\n\n')
 
         file.write('#[cxx::bridge(namespace = "pdns::rust::settings::rec")]\n')
         file.write('mod recsettings {\n')
-        with open('rust-bridge-in.rs', mode='r', encoding='UTF-8') as bridge:
+        with open(srcdir + '/rust-bridge-in.rs', mode='r', encoding='UTF-8') as bridge:
             file.write('    // START INCLUDE rust-bridge-in.rs\n')
             for line in bridge:
                 file.write('    ' + line)
@@ -657,12 +658,12 @@ def gen_docs_meta(file, entry, name, is_tuple):
             else:
                 file.write(f'.. {name}:: {vers}\n')
 
-def gen_oldstyle_docs(entries):
+def gen_oldstyle_docs(srcdir, entries):
     """Write old style docs"""
-    with open('../docs/settings.rst', mode='w', encoding='UTF-8') as file:
+    with open(srcdir + '/../docs/settings.rst', mode='w', encoding='UTF-8') as file:
         file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
         file.write('   START INCLUDE docs-old-preamble-in.rst\n\n')
-        with open('docs-old-preamble-in.rst', mode='r', encoding='UTF-8') as pre:
+        with open(srcdir + '/docs-old-preamble-in.rst', mode='r', encoding='UTF-8') as pre:
             file.write(pre.read())
             file.write('.. END INCLUDE docs-old-preamble-in.rst\n\n')
 
@@ -713,13 +714,13 @@ def fixxrefs(entries, arg):
                 arg = arg.replace(key, repl)
     return arg
 
-def gen_newstyle_docs(argentries):
+def gen_newstyle_docs(srcdir, argentries):
     """Write new style docs"""
     entries = sorted(argentries, key = lambda entry: [entry['section'], entry['name']])
-    with open('../docs/yamlsettings.rst', 'w', encoding='utf-8') as file:
+    with open(srcdir + '/../docs/yamlsettings.rst', 'w', encoding='utf-8') as file:
         file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir\n')
         file.write('   START INCLUDE docs-new-preamble-in.rst\n\n')
-        with open('docs-new-preamble-in.rst', mode='r', encoding='utf-8') as pre:
+        with open(srcdir + '/docs-new-preamble-in.rst', mode='r', encoding='utf-8') as pre:
             file.write(pre.read())
             file.write('.. END INCLUDE docs-new-preamble-in.rst\n\n')
 
@@ -763,9 +764,20 @@ def gen_newstyle_docs(argentries):
 RUNTIME = '*runtime determined*'
 
 def generate():
-    """Read table, validate and generate C++, Rst and .rst files"""
+    """Read table, validate and generate C++, Rust and .rst files"""
+    srcdir = '.'
+    gendir = '.'
+    if len(sys.argv) == 3:
+        print("Generate: using srcdir and gendir from argumens")
+        srcdir = sys.argv[1]
+        gendir = sys.argv[2]
+
+    print("Generate cwd: " + os.getcwd())
+    print("Generate srcdir: " + srcdir + " = " + os.path.realpath(srcdir))
+    print("Generate gendir: " + gendir + " = " + os.path.realpath(gendir))
+
     # read table
-    with open('table.py', mode='r', encoding="utf-8") as file:
+    with open(srcdir + '/table.py', mode='r', encoding="utf-8") as file:
         entries = eval(file.read())
 
     for entry in entries:
@@ -789,11 +801,17 @@ def generate():
         dupcheck1[entry['oldname']] = True
         dupcheck2[entry['section'] + '.' + entry['name']] = True
     # And generate C++, Rust and docs code based on table
-    gen_cxx(entries)
-    gen_rust(entries)
+    # C++ code goes int build dir
+    gen_cxx(gendir, entries)
+    # Generate Rust code into src dir, as I did not manage to figure out the Cargo stuff
+    # with mixed sources both in build and src dir
+    gen_rust(srcdir, entries)
     # Avoid generating doc files in a sdist based build
     if os.path.isdir('../docs'):
-        gen_oldstyle_docs(entries)
-        gen_newstyle_docs(entries)
-
+        gen_oldstyle_docs(srcdir, entries)
+        gen_newstyle_docs(srcdir, entries)
+    # touch pseudo output file
+    with open(gendir + '/timestamp', mode='w', encoding="utf-8") as file:
+        file.write('')
+        file.close()
 generate()
diff --git a/pdns/recursordist/settings/meson.build b/pdns/recursordist/settings/meson.build
new file mode 100644 (file)
index 0000000..1ecdf79
--- /dev/null
@@ -0,0 +1,35 @@
+sources = files(
+  'generate.py',
+  'docs-new-preamble-in.rst',
+  'docs-old-preamble-in.rst',
+  'rust-bridge-in.rs',
+  'rust-preamble-in.rs',
+  'table.py',
+)
+
+generated = [
+  'cxxsettings-generated.cc',
+]
+
+python = find_program('python3')
+
+settings = custom_target(
+  command: [python, '@INPUT0@', '@SOURCE_ROOT@/settings', '@BUILD_ROOT@/settings'],
+  input: sources,
+  output: generated,
+)
+
+# librec_common depends on this, so the sources get linked
+dep_settings_ch = declare_dependency(
+  sources: [settings, 'cxxsupport.cc'],
+  include_directories: [include_directories('.'), ]
+)
+
+# The rust parts depend on this, no sources listed, which avoid duplicates object files
+# In turn deps (defined in the main meson.build file, includes dep_rust_settings)
+dep_settings = declare_dependency(
+  include_directories: [include_directories('.'), ]
+)
+
+subdir('rust')
+
index 25fa9b107b276ba48c0ccb775c9d161ddc1652c5..76138fb84689d94af1953e81056d183db872457c 100644 (file)
@@ -10,12 +10,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
 
 [[package]]
 name = "codespan-reporting"
@@ -29,9 +26,9 @@ dependencies = [
 
 [[package]]
 name = "cxx"
-version = "1.0.115"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de00f15a6fa069c99b88c5c78c4541d0e7899a33b86f7480e23df2431fce0bc"
+checksum = "bb497fad022245b29c2a0351df572e2d67c1046bcef2260ebc022aec81efea82"
 dependencies = [
  "cc",
  "cxxbridge-flags",
@@ -41,9 +38,9 @@ dependencies = [
 
 [[package]]
 name = "cxx-build"
-version = "1.0.115"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a71e1e631fa2f2f5f92e8b0d860a00c198c6771623a6cefcc863e3554f0d8d6"
+checksum = "9327c7f9fbd6329a200a5d4aa6f674c60ab256525ff0084b52a889d4e4c60cee"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -56,15 +53,15 @@ dependencies = [
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.115"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f3fed61d56ba497c4efef9144dfdbaa25aa58f2f6b3a7cf441d4591c583745c"
+checksum = "688c799a4a846f1c0acb9f36bb9c6272d9b3d9457f3633c7753c6057270df13c"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.115"
+version = "1.0.122"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8908e380a8efd42150c017b0cfa31509fc49b6d47f7cb6b33e93ffb8f4e3661e"
+checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -79,15 +76,15 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 
 [[package]]
 name = "indexmap"
-version = "2.1.0"
+version = "2.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -101,15 +98,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
 
 [[package]]
 name = "itoa"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
-
-[[package]]
-name = "libc"
-version = "0.2.152"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "link-cplusplus"
@@ -128,27 +119,27 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "scratch"
@@ -158,18 +149,18 @@ checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
 
 [[package]]
 name = "serde"
-version = "1.0.195"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.195"
+version = "1.0.203"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -178,9 +169,9 @@ dependencies = [
 
 [[package]]
 name = "serde_yaml"
-version = "0.9.30"
+version = "0.9.34+deprecated"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
 dependencies = [
  "indexmap",
  "itoa",
@@ -191,7 +182,7 @@ dependencies = [
 
 [[package]]
 name = "settings"
-version = "0.1.0"
+version = "5.1.0"
 dependencies = [
  "base64",
  "cxx",
@@ -204,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -230,43 +221,94 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.11"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
 
 [[package]]
 name = "unsafe-libyaml"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
+name = "winapi-util"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "windows-sys",
 ]
 
 [[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
+name = "windows-sys"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
 
 [[package]]
-name = "winapi-util"
-version = "0.1.6"
+name = "windows-targets"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "winapi",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
index 6179bd863b6a058f7f7cbd17da79c343e677d3b1..73f174a8d38980033d349f8768ecf034f2b5e1c4 100644 (file)
@@ -1,6 +1,7 @@
 [package]
 name = "settings"
-version = "0.1.0"
+# Convention: major/minor is equal to rec's major/minor
+version = "5.1.0"
 edition = "2021"
 
 [lib]
diff --git a/pdns/recursordist/settings/rust/build_settings b/pdns/recursordist/settings/rust/build_settings
new file mode 100755 (executable)
index 0000000..8313238
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+
+#echo "PWD=$PWD"
+#echo "srcdir=$srcdir"
+#echo "builddir=$builddir"
+
+$CARGO build --release $RUST_TARGET --target-dir=$builddir/target --manifest-path $srcdir/Cargo.toml
+
+
+cp -p target/$RUSTC_TARGET_ARCH/release/libsettings.a $builddir/settings/rust/libsettings.a
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/settings/src/lib.rs.h $srcdir/lib.rs.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/settings/src/lib.rs.h $builddir/settings/rust/lib.rs.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $srcdir/cxx.h
+cp -p target/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $builddir/settings/rust/cxx.h
diff --git a/pdns/recursordist/settings/rust/meson.build b/pdns/recursordist/settings/rust/meson.build
new file mode 100644 (file)
index 0000000..014ca29
--- /dev/null
@@ -0,0 +1,37 @@
+
+build = find_program('build_settings')
+cargo = find_program('cargo')
+infile = 'Cargo.toml'
+outfile = 'libsettings.a'
+
+
+env = environment()
+env.append('CARGO', cargo.full_path())
+env.append('SYSCONFDIR', conf.get('SYSCONFDIR'))
+env.append('NODCACHEDIRNOD', conf.get('NODCACHEDIRNOD'))
+env.append('NODCACHEDIRUDR', conf.get('NODCACHEDIRUDR'))
+env.append('builddir', '.')
+env.append('srcdir', meson.current_source_dir())
+env.append('RUST_TARGET', '')
+env.append('RUSTC_TARGET_ARCH', '')
+
+lib_settings = custom_target('libsettings.a',
+  output: [outfile, 'cxx.h'],
+  input: infile,
+  command: [build,
+  ],
+  depend_files: [
+    'src/bridge.hh',
+    'src/bridge.rs',
+    'src/helpers.rs',
+  ],
+  depends: settings,
+  env: env,
+  console: true,
+)
+
+dep_rust_settings = declare_dependency(
+  link_with: lib_settings[0],
+  sources: lib_settings[1],
+  include_directories: [include_directories('.'), include_directories('src')],
+)
index 24998e2d1d37c20ea2d778a9504c2f924c647847..4ac678e05cd9c3cc96850e17b4dc7d91a9194ae0 100644 (file)
@@ -88,19 +88,17 @@ fn is_port_number(str: &str) -> bool {
 
 pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), ValidationError> {
     let sa = validate_socket_address(field, val);
-    if sa.is_err() {
-        if !isValidHostname(val) {
-            let parts: Vec<&str> = val.split(':').collect();
-            if parts.len() != 2
-                || !isValidHostname(parts[0])
-                || !is_port_number(parts[1])
-            {
-                let msg = format!(
-                    "{}: value `{}' is not an IP, IP:port, name or name:port combination",
-                    field, val
-                );
-                return Err(ValidationError { msg });
-            }
+    if sa.is_err() && !isValidHostname(val) {
+        let parts: Vec<&str> = val.split(':').collect();
+        if parts.len() != 2
+            || !isValidHostname(parts[0])
+            || !is_port_number(parts[1])
+        {
+            let msg = format!(
+                "{}: value `{}' is not an IP, IP:port, name or name:port combination",
+                field, val
+            );
+            return Err(ValidationError { msg });
         }
     }
     Ok(())
@@ -163,7 +161,7 @@ pub fn validate_subnet(field: &str, val: &String) -> Result<(), ValidationError>
 }
 
 fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], local_address: &String) -> Result<(), ValidationError> {
-    if vec.len() == 0 {
+    if vec.is_empty() {
         let msg = format!("{}: cannot be empty", addrfield);
         return Err(ValidationError { msg });
     }
index de4d398e9c6758e15715ddd4fe8b46220b6944aa..92caff19dc6ab5db93d07f7fd5a4e0507307ff6e 100644 (file)
@@ -701,7 +701,7 @@ This can have odd effects, depending on your network, and may even be a security
 Therefore, the PowerDNS Recursor by default does not query private space IP addresses.
 This setting can be used to expand or reduce the limitations.
 
-Queries for names in forward zones and to addresses as configured in any of the settings :ref:`setting-forward-zones`, :ref:`setting-forward-zones-file` or :ref:`setting-forward-zones-recurse` are performed regardless of these limitations.
+Queries for names in forward zones and to addresses as configured in any of the settings :ref:`setting-forward-zones`, :ref:`setting-forward-zones-file` or :ref:`setting-forward-zones-recurse` are performed regardless of these limitations. However, if NS records are learned from :ref:`setting-forward-zones` and the IP addresses of the nameservers learned in that way are included in :ref:`setting-dont-query`, lookups relying on these nameservers will fail with SERVFAIL.
  ''',
     },
     {
@@ -1034,6 +1034,9 @@ Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning
 If an ``NS`` record set for a subzone of the forwarded zone is learned, that record set will be used to determine addresses for name servers of the subzone.
 This allows e.g. a forward to a local authoritative server holding a copy of the root zone, delegations received from that server will work.
 
+**Note**: When an ``NS`` record for a subzone is learned and the IP address for that nameserver is included in the IP ranges in :ref:`setting-dont-query`,
+SERVFAIL is returned.
+
 **IMPORTANT**: When using DNSSEC validation (which is default), forwards to non-delegated (e.g. internal) zones that have a DNSSEC signed parent zone will validate as Bogus.
 To prevent this, add a Negative Trust Anchor (NTA) for this zone in the :ref:`setting-lua-config-file` with ``addNTA('your.zone', 'A comment')``.
 If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file`.
@@ -1073,6 +1076,9 @@ Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning
 If an ``NS`` record set for a subzone of the forwarded zone is learned, that record set will be used to determine addresses for name servers of the subzone.
 This allows e.g. a forward to a local authoritative server holding a copy of the root zone, delegations received from that server will work.
 
+**Note**: When an ``NS`` record for a subzone is learned and the IP address for that nameserver is included in the IP ranges in :ref:`setting-dont-query`,
+SERVFAIL is returned.
+
 **IMPORTANT**: When using DNSSEC validation (which is default), forwards to non-delegated (e.g. internal) zones that have a DNSSEC signed parent zone will validate as Bogus.
 To prevent this, add a Negative Trust Anchor (NTA) for this zone in the :ref:`setting-lua-config-file` with ``addNTA('your.zone', 'A comment')``.
 If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file`.
@@ -1187,9 +1193,12 @@ Useful during upgrade testing.
         'section' : 'recursor',
         'type' : LType.String,
         'default' : '',
-        'help' : 'Include *.conf files from this directory',
+        'help' : 'Include settings files from this directory.',
         'doc' : '''
-Directory to scan for additional config files. All files that end with .conf are loaded in order using ``POSIX`` as locale.
+Directory to scan for additional config files. All files that end with ``.conf`` are loaded in order using ``POSIX`` as locale.
+ ''',
+        'doc-new' : '''
+Directory to scan for additional config files. All files that end with ``.yml`` are loaded in order using ``POSIX`` as locale.
  ''',
     },
     {
@@ -1352,6 +1361,16 @@ Setting ``lowercase-outgoing`` to 'yes' makes the PowerDNS Recursor lowercase al
         'doc' : '''
 If set, and Lua support is compiled in, this will load an additional configuration file for newer features and more complicated setups.
 See :doc:`lua-config/index` for the options that can be set in this file.
+ ''',
+    },
+    {
+        'name' : 'lua_global_include_dir',
+        'section' : 'recursor',
+        'type' : LType.String,
+        'default' : '',
+        'help' : 'More powerful configuration options',
+        'doc' : '''
+ When creating a Lua context, all ``*.lua`` files in the directory are loaded into the Lua context.
  ''',
     },
     {
@@ -1451,6 +1470,21 @@ and also smaller than `max-mthreads`.
  ''',
     'versionadded': '4.3.0'
     },
+    {
+        'name': 'max_chain_length',
+        'section': 'recursor',
+        'type': LType.Uint64,
+        'default': '0',
+        'help': 'maximum number of queries that can be chained to an outgoing request, 0 is no limit',
+        'doc': '''
+The maximum number of queries that can be attached to an outgoing request chain. Attaching requests to a chain
+saves on outgoing queries, but the processing of a chain when the reply to the outgoing query comes in
+might result in a large outgoing traffic spike. Reducing the maximum chain length mitigates this.
+If this value is zero, no maximum is enforced, though the maximum number of mthreads (:ref:`setting-max-mthreads`)
+also limits the chain length.
+''',
+        'versionadded': '5.1.0'
+    },
     {
         'name' : 'max_include_depth',
         'section' : 'recursor',
@@ -1484,7 +1518,7 @@ means unlimited.
         'default' : '2048',
         'help' : 'Maximum number of simultaneous Mtasker threads',
         'doc' : '''
-Maximum number of simultaneous MTasker threads.
+Maximum number of simultaneous MTasker threads, per worker thread.
  ''',
     },
     {
@@ -1510,6 +1544,18 @@ This is used to avoid cycles resolving names.
  ''',
         'versionchanged': ('5.1.0', 'The default used to be 60, with an extra allowance if qname minimization was enabled. Having better algorithms allows for a lower default limit.'),
     },
+    {
+        'name' : 'max_cnames_followed',
+        'section' : 'recursor',
+        'type' : LType.Uint64,
+        'default' : '10',
+        'help' : 'Maximum number CNAME records followed',
+        'doc' : '''
+Maximum length of a CNAME chain. If a CNAME chain exceeds this length, a ``ServFail`` answer will be returned.
+Previously, this limit was fixed at 10.
+ ''',
+    'versionadded': '5.1.0'
+    },    
     {
         'name' : 'max_ns_address_qperq',
         'section' : 'outgoing',
@@ -1688,9 +1734,9 @@ recursor log file. The log line looks something like::
 If a domain is specified, then each time a newly observed domain is
 detected, the recursor will perform an A record lookup of '<newly
 observed domain>.<lookup domain>'. For example if 'new-domain-lookup'
-is configured as 'nod.powerdns.com', and a new domain 'xyz123.tv' is
+is configured as 'nod.powerdns.com', and a new domain 'example.com' is
 detected, then an A record lookup will be made for
-'xyz123.tv.nod.powerdns.com'. This feature gives a way to share the
+'example.com.nod.powerdns.com'. This feature gives a way to share the
 newly observed domain with partners, vendors or security teams. The
 result of the DNS lookup will be ignored by the recursor.
  ''',
@@ -1749,7 +1795,7 @@ from this directory.
 Interval (in seconds) to write the NOD and UDR DB snapshots.
 Set to zero to disable snapshot writing.',
  ''',
-        'versionadded': '5.1.0'
+    'versionadded': '5.1.0'
     },
     {
         'name' : 'whitelist',
@@ -1773,13 +1819,27 @@ Set to zero to disable snapshot writing.',
         'doc' : '''
 This setting is a list of all domains (and implicitly all subdomains)
 that will never be considered a new domain. For example, if the domain
-'xyz123.tv' is in the list, then 'foo.bar.xyz123.tv' will never be
+'example.com' is in the list, then 'foo.bar.example.com' will never be
 considered a new domain. One use-case for the ignore list is to never
 reveal details of internal subdomains via the new-domain-lookup
 feature.
  ''',
     'versionadded': '4.5.0'
     },
+    {
+        'name' : 'ignore_list_file',
+        'section' : 'nod',
+        'type' : LType.String,
+        'oldname' : 'new-domain-ignore-list-file',
+        'default' : '',
+        'help' : 'File with a list of domains (and implicitly all subdomains) which will never be considered a new domain',
+        'doc' : '''
+Path to a file with a list of domains. File should have one domain per line,
+with no extra characters or comments.
+See :ref:`setting-new-domain-ignore-list`.
+ ''',
+    'versionadded': '5.1.0'
+    },
     {
         'name' : 'pb_tag',
         'section' : 'nod',
@@ -1801,6 +1861,7 @@ a new domain is observed.
         'help' : 'Wait this number of milliseconds for network i/o',
         'doc' : '''
 Number of milliseconds to wait for a remote authoritative server to respond.
+If the number of concurrent requests is high, the :program:Recursor uses a lower value.
  ''',
     },
     {
@@ -2972,6 +3033,33 @@ a unique DNS response is observed.
  ''',
     'versionadded': '4.2.0'
     },
+    {
+        'name' : 'unique_response_ignore_list',
+        'section' : 'nod',
+        'type' : LType.ListStrings,
+        'default' : '',
+        'help' : 'List of domains (and implicitly all subdomains) which will never be considered for UDR',
+        'doc' : '''
+This setting is a list of all domains (and implicitly all subdomains)
+that will never be considered for new unique domain responses.
+For example, if the domain 'example.com' is in the list, then 'foo.bar.example.com'
+will never be considered for a new unique domain response.
+''',
+        'versionadded': '5.1.0'
+    },
+    {
+        'name' : 'unique_response_ignore_list_file',
+        'section' : 'nod',
+        'type' : LType.String,
+        'default' : '',
+        'help' : 'File with list of domains (and implicitly all subdomains) which will never be considered for UDR',
+        'doc' : '''
+Path to a file with a list of domains. File should have one domain per line,
+with no extra characters or comments.
+See :ref:`setting-unique-response-ignore-list`.
+''',
+        'versionadded': '5.1.0'
+    },
     {
         'name' : 'use_incoming_edns_subnet',
         'section' : 'incoming',
index 268a55d850b039dd5c6339b14aaa6d9de3640e3f..8c1ffcfe4b72c924bd2129361b7fb7825ad24d77 100644 (file)
@@ -245,26 +245,36 @@ public:
 
 static LockGuarded<nsspeeds_t> s_nsSpeeds;
 
-template <class Thing>
-class Throttle : public boost::noncopyable
+class Throttle
 {
 public:
+  Throttle() = default;
+  ~Throttle() = default;
+  Throttle(Throttle&&) = delete;
+  Throttle& operator=(const Throttle&) = default;
+  Throttle& operator=(Throttle&&) = delete;
+  Throttle(const Throttle&) = delete;
+
+  using Key = std::tuple<ComboAddress, DNSName, QType>;
+  using Reason = SyncRes::ThrottleReason;
+
   struct entry_t
   {
-    entry_t(const Thing& thing_, time_t ttd_, unsigned int count_) :
-      thing(thing_), ttd(ttd_), count(count_)
+    entry_t(Key thing_, time_t ttd_, unsigned int count_, Reason reason_) :
+      thing(std::move(thing_)), ttd(ttd_), count(count_), reason(reason_)
     {
     }
-    Thing thing;
+    Key thing;
     time_t ttd;
     mutable unsigned int count;
+    Reason reason;
   };
   using cont_t = multi_index_container<entry_t,
                                        indexed_by<
-                                         ordered_unique<tag<Thing>, member<entry_t, Thing, &entry_t::thing>>,
+                                         ordered_unique<tag<Key>, member<entry_t, Key, &entry_t::thing>>,
                                          ordered_non_unique<tag<time_t>, member<entry_t, time_t, &entry_t::ttd>>>>;
 
-  bool shouldThrottle(time_t now, const Thing& arg)
+  bool shouldThrottle(time_t now, const Key& arg)
   {
     auto iter = d_cont.find(arg);
     if (iter == d_cont.end()) {
@@ -279,18 +289,22 @@ public:
     return true; // still listed, still blocked
   }
 
-  void throttle(time_t now, const Thing& arg, time_t ttl, unsigned int count)
+  void throttle(time_t now, const Key& arg, time_t ttl, unsigned int count, Reason reason)
   {
     auto iter = d_cont.find(arg);
     time_t ttd = now + ttl;
     if (iter == d_cont.end()) {
-      d_cont.emplace(arg, ttd, count);
+      d_cont.emplace(arg, ttd, count, reason);
     }
     else if (ttd > iter->ttd || count > iter->count) {
       ttd = std::max(iter->ttd, ttd);
       count = std::max(iter->count, count);
-      auto& ind = d_cont.template get<Thing>();
-      ind.modify(iter, [ttd, count](entry_t& entry) { entry.ttd = ttd; entry.count = count; });
+      auto& ind = d_cont.template get<Key>();
+      ind.modify(iter, [ttd, count, reason](entry_t& entry) {
+        entry.ttd = ttd;
+        entry.count = count;
+        entry.reason = reason;
+      });
     }
   }
 
@@ -309,7 +323,7 @@ public:
     d_cont.clear();
   }
 
-  void clear(const Thing& thing)
+  void clear(const Key& thing)
   {
     d_cont.erase(thing);
   }
@@ -319,11 +333,31 @@ public:
     ind.erase(ind.begin(), ind.upper_bound(now));
   }
 
+  static std::string toString(Reason reason)
+  {
+    static const std::array<std::string, 10> reasons = {
+      "None",
+      "ServerDown",
+      "PermanentError",
+      "Timeout",
+      "ParseError",
+      "RCodeServFail",
+      "RCodeRefused",
+      "RCodeOther",
+      "TCPTruncate",
+      "Lame"};
+    const auto index = static_cast<unsigned int>(reason);
+    if (index >= reasons.size()) {
+      return "?";
+    }
+    return reasons.at(index);
+  }
+
 private:
   cont_t d_cont;
 };
 
-static LockGuarded<Throttle<std::tuple<ComboAddress, DNSName, QType>>> s_throttle;
+static LockGuarded<Throttle> s_throttle;
 
 struct SavedParentEntry
 {
@@ -375,7 +409,6 @@ SuffixMatchNode SyncRes::s_ednsdomains;
 EDNSSubnetOpts SyncRes::s_ecsScopeZero;
 string SyncRes::s_serverID;
 SyncRes::LogMode SyncRes::s_lm;
-const std::unordered_set<QType> SyncRes::s_redirectionQTypes = {QType::CNAME, QType::DNAME};
 static LockGuarded<fails_t<ComboAddress>> s_fails;
 static LockGuarded<fails_t<DNSName>> s_nonresolving;
 
@@ -474,7 +507,7 @@ bool SyncRes::s_dot_to_port_853;
 int SyncRes::s_event_trace_enabled;
 bool SyncRes::s_save_parent_ns_set;
 unsigned int SyncRes::s_max_busy_dot_probes;
-unsigned int SyncRes::s_max_CNAMES_followed = 10;
+unsigned int SyncRes::s_max_CNAMES_followed;
 bool SyncRes::s_addExtendedResolutionDNSErrors;
 
 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
@@ -1279,14 +1312,14 @@ void SyncRes::unThrottle(const ComboAddress& server, const DNSName& name, QType
   s_throttle.lock()->clear(std::tuple(server, name, qtype));
 }
 
-void SyncRes::doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries)
+void SyncRes::doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries, Throttle::Reason reason)
 {
-  s_throttle.lock()->throttle(now, std::tuple(server, g_rootdnsname, 0), duration, tries);
+  s_throttle.lock()->throttle(now, std::tuple(server, g_rootdnsname, 0), duration, tries, reason);
 }
 
-void SyncRes::doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries)
+void SyncRes::doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries, Throttle::Reason reason)
 {
-  s_throttle.lock()->throttle(now, std::tuple(server, name, qtype), duration, tries);
+  s_throttle.lock()->throttle(now, std::tuple(server, name, qtype), duration, tries, reason);
 }
 
 uint64_t SyncRes::doDumpThrottleMap(int fileDesc)
@@ -1301,7 +1334,7 @@ uint64_t SyncRes::doDumpThrottleMap(int fileDesc)
     return 0;
   }
   fprintf(filePtr.get(), "; throttle map dump follows\n");
-  fprintf(filePtr.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
+  fprintf(filePtr.get(), "; remote IP\tqname\tqtype\tcount\tttd\treason\n");
   uint64_t count = 0;
 
   // Get a copy to avoid holding the lock while doing I/O
@@ -1309,8 +1342,8 @@ uint64_t SyncRes::doDumpThrottleMap(int fileDesc)
   for (const auto& iter : throttleMap) {
     count++;
     timebuf_t tmp;
-    // remote IP, dns name, qtype, count, ttd
-    fprintf(filePtr.get(), "%s\t%s\t%s\t%u\t%s\n", std::get<0>(iter.thing).toString().c_str(), std::get<1>(iter.thing).toLogString().c_str(), std::get<2>(iter.thing).toString().c_str(), iter.count, timestamp(iter.ttd, tmp));
+    // remote IP, dns name, qtype, count, ttd, reason
+    fprintf(filePtr.get(), "%s\t%s\t%s\t%u\t%s\t%s\n", std::get<0>(iter.thing).toString().c_str(), std::get<1>(iter.thing).toLogString().c_str(), std::get<2>(iter.thing).toString().c_str(), iter.count, timestamp(iter.ttd, tmp), Throttle::toString(iter.reason).c_str());
   }
 
   return count;
@@ -1576,7 +1609,7 @@ LWResult::Result SyncRes::asyncresolveWrapper(const ComboAddress& address, bool
       ret = asyncresolve(address, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, d_frameStreamServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained);
     }
 
-    if (ret == LWResult::Result::PermanentError || ret == LWResult::Result::OSLimitError || ret == LWResult::Result::Spoofed) {
+    if (ret == LWResult::Result::PermanentError || LWResult::isLimitError(ret) || ret == LWResult::Result::Spoofed) {
       break; // transport error, nothing to learn here
     }
 
@@ -2312,13 +2345,22 @@ void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector
         g_recCache->doWipeCache(subdomain, false, QType::NS);
       }
       if (!missing.empty() && missing.size() < nsVector.size()) {
-        // We miss glue, but we have a chance to resolve it, since we do have address(es) for at least one NS
+        // We miss glue, but we have a chance to resolve it
+        // Pick a few and push async tasks to resolve them
+        const unsigned int max = 2;
+        unsigned int counter = 0;
+        shuffle(missing.begin(), missing.end(), pdns::dns_random_engine());
         for (const auto& name : missing) {
           if (s_doIPv4 && pushResolveIfNotInNegCache(name, QType::A, d_now)) {
             LOG(prefix << qname << ": A glue for " << subdomain << " NS " << name << " missing, pushed task to resolve" << endl);
+            counter++;
           }
           if (s_doIPv6 && pushResolveIfNotInNegCache(name, QType::AAAA, d_now)) {
             LOG(prefix << qname << ": AAAA glue for " << subdomain << " NS " << name << " missing, pushed task to resolve" << endl);
+            counter++;
+          }
+          if (counter >= max) {
+            break;
           }
         }
       }
@@ -4128,6 +4170,12 @@ void SyncRes::fixupAnswer(const std::string& prefix, LWResult& lwr, const DNSNam
 
 static void allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
 {
+  // As we only use a limited amount of NS names for resolving, limit number of additional names as
+  // well.  s_maxnsperresolve is a proper limit for the NS case and is also reasonable for other
+  // qtypes.  Allow one extra for qname itself, which is always in allowedAdditionals.
+  if (SyncRes::s_maxnsperresolve > 0 && allowedAdditionals.size() > SyncRes::s_maxnsperresolve + 1) {
+    return;
+  }
   switch (rec.d_type) {
   case QType::MX:
     if (auto mxContent = getRR<MXRecordContent>(rec)) {
@@ -4173,141 +4221,218 @@ static void allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals
   }
 }
 
+static bool isRedirection(QType qtype)
+{
+  return qtype == QType::CNAME || qtype == QType::DNAME;
+}
+
 void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
 {
   const bool wasForwardRecurse = wasForwarded && rdQuery;
   /* list of names for which we will allow A and AAAA records in the additional section
      to remain */
   std::unordered_set<DNSName> allowedAdditionals = {qname};
+  std::unordered_set<DNSName> allowedAnswerNames = {qname};
   bool haveAnswers = false;
   bool isNXDomain = false;
   bool isNXQType = false;
 
-  for (auto rec = lwr.d_records.begin(); rec != lwr.d_records.end();) {
+  std::vector<bool> skipvec(lwr.d_records.size(), false);
+  unsigned int counter = 0;
+  unsigned int skipCount = 0;
+
+  for (auto rec = lwr.d_records.cbegin(); rec != lwr.d_records.cend(); ++rec, ++counter) {
 
+    // Allow OPT record containing EDNS(0) data
     if (rec->d_type == QType::OPT) {
-      ++rec;
       continue;
     }
 
+    // Disallow QClass != IN
     if (rec->d_class != QClass::IN) {
       LOG(prefix << qname << ": Removing non internet-classed data received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+      skipvec[counter] = true;
+      ++skipCount;
       continue;
     }
 
+    // Disallow QType ANY in responses
     if (rec->d_type == QType::ANY) {
       LOG(prefix << qname << ": Removing 'ANY'-typed data received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+      skipvec[counter] = true;
+      ++skipCount;
       continue;
     }
 
+    // Disallow any name not part of auth requested (i.e. disallow x.y.z if asking a NS authoritative for x.w.z)
     if (!rec->d_name.isPartOf(auth)) {
-      LOG(prefix << qname << ": Removing record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+      LOG(prefix << qname << ": Removing record '" << rec->toString() << "' in the " << DNSResourceRecord::placeString(rec->d_place) << " section received from " << auth << endl);
+      skipvec[counter] = true;
+      ++skipCount;
       continue;
     }
 
-    /* dealing with the records in answer */
-    if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
-      /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
-         are sending such responses */
-      if (rec->d_type != QType::CNAME || qname != rec->d_name) {
-        LOG(prefix << qname << ": Removing record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the answer section without the AA bit set received from " << auth << endl);
-        rec = lwr.d_records.erase(rec);
-        continue;
-      }
-    }
-
+    // Disallow QType DNAME in non-answer section or containing an answer that is not a parent of or equal to the question name
+    // i.e. disallowed bar.example.com. DNAME bar.example.net. when asking foo.example.com
+    // But allow it when asking for foo.bar.example.com.
     if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
-      LOG(prefix << qname << ": Removing invalid DNAME record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+      LOG(prefix << qname << ": Removing invalid DNAME record '" << rec->toString() << "' in the " << DNSResourceRecord::placeString(rec->d_place) << " section received from " << auth << endl);
+      skipvec[counter] = true;
+      ++skipCount;
       continue;
     }
 
-    if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && s_redirectionQTypes.count(rec->d_type) == 0 && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
-      LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ANSWER section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
-      continue;
-    }
+    /* dealing with the records in answer */
+    if (rec->d_place == DNSResourceRecord::ANSWER) {
+      // Special case for Amazon CNAME records
+      if (!(lwr.d_aabit || wasForwardRecurse)) {
+        /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
+           are sending such responses */
+        if (rec->d_type != QType::CNAME || qname != rec->d_name) {
+          LOG(prefix << qname << ": Removing record '" << rec->toString() << "' in the ANSWER section without the AA bit set received from " << auth << endl);
+          skipvec[counter] = true;
+          ++skipCount;
+          continue;
+        }
+      }
+      // Disallow answer records not answering the QType requested. ANY, CNAME, DNAME, RRSIG complicate matters here
+      if (qtype != QType::ANY && rec->d_type != qtype.getCode() && !isRedirection(rec->d_type) && rec->d_type != QType::RRSIG) {
+        LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ANSWER section received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
+        continue;
+      }
 
-    if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
       haveAnswers = true;
-    }
-
-    if (rec->d_place == DNSResourceRecord::ANSWER) {
+      if (rec->d_type == QType::CNAME) {
+        if (auto cnametarget = getRR<CNAMERecordContent>(*rec); cnametarget != nullptr) {
+          allowedAnswerNames.insert(cnametarget->getTarget());
+        }
+      }
+      else if (rec->d_type == QType::DNAME) {
+        // We have checked the DNAME rec->d_name above, the actual answer will be synthesized in a later step
+        allowedAnswerNames.insert(rec->d_name);
+      }
       allowAdditionalEntry(allowedAdditionals, *rec);
     }
 
     /* dealing with the records in authority */
-    if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
-      LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
-      continue;
-    }
-
-    if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
-      if (!qname.isPartOf(rec->d_name)) {
-        LOG(prefix << qname << ": Removing irrelevant SOA record '" << rec->d_name << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
-        rec = lwr.d_records.erase(rec);
+    // Only allow NS, DS, SOA, RRSIG, NSEC, NSEC3 in AUTHORITY section
+    else if (rec->d_place == DNSResourceRecord::AUTHORITY) {
+      if (rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
+        LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
         continue;
       }
-
-      if (!(lwr.d_aabit || wasForwardRecurse)) {
-        LOG(prefix << qname << ": Removing irrelevant record (AA not set) '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the AUTHORITY section received from " << auth << endl);
-        rec = lwr.d_records.erase(rec);
+      if (rec->d_type == QType::NS && !d_updatingRootNS && rec->d_name == g_rootdnsname) {
+        /*
+         * We don't want to pick up root NS records in AUTHORITY and their associated ADDITIONAL sections of random queries.
+         * So remove them and don't add them to allowedAdditionals.
+         */
+        LOG(prefix << qname << ": Removing NS record '" << rec->toString() << "' in the AUTHORITY section of a response received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
         continue;
       }
 
-      if (!haveAnswers) {
-        if (lwr.d_rcode == RCode::NXDomain) {
-          isNXDomain = true;
+      if (rec->d_type == QType::SOA) {
+        // Disallow a SOA record with a name that is not a parent of or equal to the name we asked
+        if (!qname.isPartOf(rec->d_name)) {
+          LOG(prefix << qname << ": Removing irrelevant SOA record '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+          skipvec[counter] = true;
+          ++skipCount;
+          continue;
+        }
+        // Disallow SOA without AA bit (except for forward with RD=1)
+        if (!(lwr.d_aabit || wasForwardRecurse)) {
+          LOG(prefix << qname << ": Removing irrelevant record (AA not set) '" << rec->toString() << "' in the AUTHORITY section received from " << auth << endl);
+          skipvec[counter] = true;
+          ++skipCount;
+          continue;
         }
-        else if (lwr.d_rcode == RCode::NoError) {
-          isNXQType = true;
+
+        if (!haveAnswers) {
+          switch (lwr.d_rcode) {
+          case RCode::NXDomain:
+            isNXDomain = true;
+            break;
+          case RCode::NoError:
+            isNXQType = true;
+            break;
+          }
         }
       }
     }
+    /* dealing with records in additional */
+    else if (rec->d_place == DNSResourceRecord::ADDITIONAL) {
+      if (rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
+        LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ADDITIONAL section received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
+        continue;
+      }
+    }
+  } // end of first loop, handled answer and most of authority section
 
-    if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
-      /*
-       * We don't want to pick up NS records in AUTHORITY and their ADDITIONAL sections of NXDomain answers
-       * because they are somewhat easy to insert into a large, fragmented UDP response
-       * for an off-path attacker by injecting spoofed UDP fragments. So do not add these to allowedAdditionals.
-       */
-      LOG(prefix << qname << ": Removing NS record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section of a " << (isNXDomain ? "NXD" : "NXQTYPE") << " response received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+  sanitizeRecordsPass2(prefix, lwr, qname, auth, allowedAnswerNames, allowedAdditionals, isNXDomain, isNXQType, skipvec, skipCount);
+}
+
+void SyncRes::sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, std::unordered_set<DNSName>& allowedAnswerNames, std::unordered_set<DNSName>& allowedAdditionals, bool isNXDomain, bool isNXQType, std::vector<bool>& skipvec, unsigned int& skipCount)
+{
+  // Second loop, we know now if the answer was NxDomain or NoData
+  unsigned int counter = 0;
+  for (auto rec = lwr.d_records.cbegin(); rec != lwr.d_records.cend(); ++rec, ++counter) {
+
+    if (skipvec[counter]) {
       continue;
     }
-
-    if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && !d_updatingRootNS && rec->d_name == g_rootdnsname) {
-      /*
-       * We don't want to pick up root NS records in AUTHORITY and their associated ADDITIONAL sections of random queries.
-       * So don't add them to allowedAdditionals.
-       */
-      LOG(prefix << qname << ": Removing NS record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the " << (int)rec->d_place << " section of a response received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
+    // Allow OPT record containing EDNS(0) data
+    if (rec->d_type == QType::OPT) {
       continue;
     }
 
+    if (rec->d_place == DNSResourceRecord::ANSWER) {
+      if (allowedAnswerNames.count(rec->d_name) == 0) {
+        LOG(prefix << qname << ": Removing irrelevent record '" << rec->toString() << "' in the ANSWER section received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
+        continue;
+      }
+    }
     if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
+      if (isNXDomain || isNXQType) {
+        /*
+         * We don't want to pick up NS records in AUTHORITY and their ADDITIONAL sections of NXDomain answers
+         * because they are somewhat easy to insert into a large, fragmented UDP response
+         * for an off-path attacker by injecting spoofed UDP fragments. So do not add these to allowedAdditionals.
+         */
+        LOG(prefix << qname << ": Removing NS record '" << rec->toString() << "' in the AUTHORITY section of a " << (isNXDomain ? "NXD" : "NXQTYPE") << " response received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
+        continue;
+      }
       allowAdditionalEntry(allowedAdditionals, *rec);
     }
-
     /* dealing with the records in additional */
-    if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
-      LOG(prefix << qname << ": Removing irrelevant record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ADDITIONAL section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
-      continue;
+    else if (rec->d_place == DNSResourceRecord::ADDITIONAL) {
+      if (allowedAdditionals.count(rec->d_name) == 0) {
+        LOG(prefix << qname << ": Removing irrelevant record '" << rec->toString() << "' in the ADDITIONAL section received from " << auth << endl);
+        skipvec[counter] = true;
+        ++skipCount;
+        continue;
+      }
     }
-
-    if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
-      LOG(prefix << qname << ": Removing irrelevant additional record '" << rec->d_name << "|" << DNSRecordContent::NumberToType(rec->d_type) << "|" << rec->getContent()->getZoneRepresentation() << "' in the ADDITIONAL section received from " << auth << endl);
-      rec = lwr.d_records.erase(rec);
-      continue;
+  }
+  if (skipCount > 0) {
+    std::vector<DNSRecord> vec;
+    vec.reserve(lwr.d_records.size() - skipCount);
+    for (counter = 0; counter < lwr.d_records.size(); ++counter) {
+      if (!skipvec[counter]) {
+        vec.emplace_back(std::move(lwr.d_records[counter]));
+      }
     }
-
-    ++rec;
+    lwr.d_records = std::move(vec);
   }
 }
 
@@ -4952,8 +5077,8 @@ bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, co
       negIndicHasSignatures = !negEntry.authoritySOA.signatures.empty() || !negEntry.DNSSECRecords.signatures.empty();
       negindic = true;
     }
-    else if (rec.d_place == DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
-             s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
+    else if (rec.d_place == DNSResourceRecord::ANSWER && isRedirection(rec.d_type) && // CNAME or DNAME answer
+             !isRedirection(qtype.getCode())) { // But not in response to a CNAME or DNAME query
       if (rec.d_type == QType::CNAME && rec.d_name == qname) {
         if (!dnameOwner.empty()) { // We synthesize ourselves
           continue;
@@ -5317,6 +5442,23 @@ void SyncRes::updateQueryCounts(const string& prefix, const DNSName& qname, cons
   }
 }
 
+void SyncRes::incTimeoutStats(const ComboAddress& remoteIP)
+{
+  d_timeouts++;
+  t_Counters.at(rec::Counter::outgoingtimeouts)++;
+
+  if (remoteIP.sin4.sin_family == AF_INET) {
+    t_Counters.at(rec::Counter::outgoing4timeouts)++;
+  }
+  else {
+    t_Counters.at(rec::Counter::outgoing6timeouts)++;
+  }
+
+  if (t_timeouts) {
+    t_timeouts->push_back(remoteIP);
+  }
+}
+
 bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional<EDNSExtendedError>& extendedError, bool dontThrottle)
 {
   bool chained = false;
@@ -5367,28 +5509,19 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
   if (resolveret != LWResult::Result::Success) {
     /* Error while resolving */
     if (resolveret == LWResult::Result::Timeout) {
-      /* Time out */
-
       LOG(prefix << qname << ": Timeout resolving after " << lwr.d_usec / 1000.0 << " ms " << (doTCP ? "over TCP" : "") << endl);
-      d_timeouts++;
-      t_Counters.at(rec::Counter::outgoingtimeouts)++;
-
-      if (remoteIP.sin4.sin_family == AF_INET) {
-        t_Counters.at(rec::Counter::outgoing4timeouts)++;
-      }
-      else {
-        t_Counters.at(rec::Counter::outgoing6timeouts)++;
-      }
-
-      if (t_timeouts) {
-        t_timeouts->push_back(remoteIP);
-      }
+      incTimeoutStats(remoteIP);
     }
     else if (resolveret == LWResult::Result::OSLimitError) {
       /* OS resource limit reached */
       LOG(prefix << qname << ": Hit a local resource limit resolving" << (doTCP ? " over TCP" : "") << ", probable error: " << stringerror() << endl);
       t_Counters.at(rec::Counter::resourceLimits)++;
     }
+    else if (resolveret == LWResult::Result::ChainLimitError) {
+      /* Chain resource limit reached */
+      LOG(prefix << qname << ": Hit a chain limit resolving" << (doTCP ? " over TCP" : ""));
+      t_Counters.at(rec::Counter::chainLimits)++;
+    }
     else {
       /* LWResult::Result::PermanentError */
       t_Counters.at(rec::Counter::unreachables)++;
@@ -5399,22 +5532,33 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
 
     // don't account for resource limits, they are our own fault
     // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
-    if (resolveret != LWResult::Result::OSLimitError && !chained && !dontThrottle) {
-      s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec
+    if (!LWResult::isLimitError(resolveret) && !chained && !dontThrottle) {
+      uint32_t responseUsec = 1000000; // 1 sec for non-timeout cases
+      // Use the actual time if we saw a timeout
+      if (resolveret == LWResult::Result::Timeout) {
+        responseUsec = lwr.d_usec;
+      }
+
+      s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, static_cast<int>(responseUsec), d_now);
 
       // make sure we don't throttle the root
       if (s_serverdownmaxfails > 0 && auth != g_rootdnsname && s_fails.lock()->incr(remoteIP, d_now) >= s_serverdownmaxfails) {
         LOG(prefix << qname << ": Max fails reached resolving on " << remoteIP.toString() << ". Going full throttle for " << s_serverdownthrottletime << " seconds" << endl);
         // mark server as down
-        doThrottle(d_now.tv_sec, remoteIP, s_serverdownthrottletime, 10000);
+        doThrottle(d_now.tv_sec, remoteIP, s_serverdownthrottletime, 10000, Throttle::Reason::ServerDown);
       }
       else if (resolveret == LWResult::Result::PermanentError) {
         // unreachable, 1 minute or 100 queries
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 100);
+        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 100, Throttle::Reason::PermanentError);
       }
       else {
-        // timeout, 10 seconds or 5 queries
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 5);
+        // If the actual response time was more than 80% of the default timeout, we throttle. On a
+        // busy rec we reduce the time we are willing to wait for an auth, it is unfair to throttle on
+        // such a shortened timeout.
+        if (responseUsec > g_networkTimeoutMsec * 800) {
+          // timeout, 10 seconds or 5 queries
+          doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 5, Throttle::Reason::Timeout);
+        }
       }
     }
 
@@ -5430,10 +5574,10 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
 
       if (doTCP) {
         // we can be more heavy-handed over TCP
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 10);
+        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 10, Throttle::Reason::ParseError);
       }
       else {
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 2);
+        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 10, 2, Throttle::Reason::ParseError);
       }
     }
     return false;
@@ -5449,7 +5593,19 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
         s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec
       }
       else {
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3);
+        Throttle::Reason reason{};
+        switch (lwr.d_rcode) {
+        case RCode::ServFail:
+          reason = Throttle::Reason::RCodeServFail;
+          break;
+        case RCode::Refused:
+          reason = Throttle::Reason::RCodeRefused;
+          break;
+        default:
+          reason = Throttle::Reason::RCodeOther;
+          break;
+        }
+        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3, reason);
       }
     }
     return false;
@@ -5469,7 +5625,7 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
       LOG(prefix << qname << ": Truncated bit set, over TCP?" << endl);
       if (!dontThrottle) {
         /* let's treat that as a ServFail answer from this server */
-        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3);
+        doThrottle(d_now.tv_sec, remoteIP, qname, qtype, 60, 3, Throttle::Reason::TCPTruncate);
       }
       return false;
     }
@@ -5875,7 +6031,7 @@ int SyncRes::doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, con
           }
           /* was lame */
           if (!shouldNotThrottle(&tns->first, &*remoteIP)) {
-            doThrottle(d_now.tv_sec, *remoteIP, qname, qtype, 60, 100);
+            doThrottle(d_now.tv_sec, *remoteIP, qname, qtype, 60, 100, Throttle::Reason::Lame);
           }
         }
 
index 471a2d0ca18c40a66bffe288eb109870ee7b5b30..02d8ef722ff9a5dc81eca46ddadc86ef188b16b5 100644 (file)
@@ -255,8 +255,22 @@ public:
   static void clearThrottle();
   static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, QType qtype);
   static bool isThrottled(time_t now, const ComboAddress& server);
-  static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries);
-  static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries);
+
+  enum class ThrottleReason : uint8_t
+  {
+    None,
+    ServerDown,
+    PermanentError,
+    Timeout,
+    ParseError,
+    RCodeServFail,
+    RCodeRefused,
+    RCodeOther,
+    TCPTruncate,
+    Lame,
+  };
+  static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries, ThrottleReason reason);
+  static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries, ThrottleReason reason);
   static void unThrottle(const ComboAddress& server, const DNSName& qname, QType qtype);
 
   static uint64_t getFailedServersSize();
@@ -589,7 +603,6 @@ private:
   static EDNSSubnetOpts s_ecsScopeZero;
   static LogMode s_lm;
   static std::unique_ptr<NetmaskGroup> s_dontQuery;
-  const static std::unordered_set<QType> s_redirectionQTypes;
 
   struct GetBestNSAnswer
   {
@@ -620,6 +633,7 @@ private:
                   unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere, Context& context, StopAtDelegation* stopAtDelegation,
                   std::map<DNSName, std::vector<ComboAddress>>* fallback);
   void ednsStats(boost::optional<Netmask>& ednsmask, const DNSName& qname, const string& prefix);
+  void incTimeoutStats(const ComboAddress& remoteIP);
   bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, QType qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool sendRDQuery, bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional<EDNSExtendedError>& extendedError, bool dontThrottle = false);
   bool processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask>& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP);
 
@@ -649,6 +663,7 @@ private:
   vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<std::pair<DNSName, float>>::const_iterator& tns, unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, float>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly, unsigned int& nretrieveAddressesForNS);
 
   void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
+  void sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, std::unordered_set<DNSName>& allowedAnswerNames, std::unordered_set<DNSName>& allowedAdditionals, bool isNXDomain, bool isNXQType, std::vector<bool>& skipvec, unsigned int& skipCount);
   /* This function will check whether the answer should have the AA bit set, and will set if it should be set and isn't.
      This is unfortunately needed to deal with very crappy so-called DNS servers */
   void fixupAnswer(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
@@ -741,6 +756,7 @@ private:
 /* external functions, opaque to us */
 LWResult::Result asendtcp(const PacketBuffer& data, shared_ptr<TCPIOHandler>&);
 LWResult::Result arecvtcp(PacketBuffer& data, size_t len, shared_ptr<TCPIOHandler>&, bool incompleteOkay);
+void mthreadSleep(unsigned int jitterMsec);
 
 enum TCPAction : uint8_t
 {
@@ -761,9 +777,10 @@ struct PacketID
   PacketBuffer inMSG; // they'll go here
   PacketBuffer outMSG; // the outgoing message that needs to be sent
 
-  using chain_t = set<uint16_t>;
-  mutable chain_t chain;
+  using chain_t = set<std::pair<int, uint16_t>>;
+  mutable chain_t authReqChain;
   shared_ptr<TCPIOHandler> tcphandler{nullptr};
+  timeval creationTime{};
   string::size_type inPos{0}; // how far are we along in the inMSG
   size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read
   string::size_type outPos{0}; // how far we are along in the outMSG
diff --git a/pdns/recursordist/test-sholder_hh.cc b/pdns/recursordist/test-sholder_hh.cc
new file mode 120000 (symlink)
index 0000000..eb240e5
--- /dev/null
@@ -0,0 +1 @@
+../test-sholder_hh.cc
\ No newline at end of file
index 4db2c8ab7323b877c020910d0172ed98b1005731..7f253647d1183ca301ed23a7c26b77dbbc4fd9b5 100644 (file)
@@ -20,10 +20,8 @@ GlobalStateHolder<SuffixMatchNode> g_DoTToAuthNames;
 std::unique_ptr<MemRecursorCache> g_recCache;
 std::unique_ptr<NegCache> g_negCache;
 bool g_lowercaseOutgoing = false;
-#if 0
-pdns::TaskQueue g_test_tasks;
-pdns::TaskQueue g_resolve_tasks;
-#endif
+unsigned int g_networkTimeoutMsec = 1500;
+
 /* Fake some required functions we didn't want the trouble to
    link with */
 ArgvMap& arg()
@@ -188,6 +186,7 @@ void initSR(bool debug)
   SyncRes::s_locked_ttlperc = 0;
   SyncRes::s_minimize_one_label = 4;
   SyncRes::s_max_minimize_count = 10;
+  SyncRes::s_max_CNAMES_followed = 10;
 
   SyncRes::clearNSSpeeds();
   BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0U);
index 1a4e1315ffca9eac280f101d90d2f61113983cb2..86278fbe642e5153b6a61ceaeb6fe0a328fea6d5 100644 (file)
@@ -471,6 +471,7 @@ BOOST_AUTO_TEST_CASE(test_all_nss_down)
       return LWResult::Result::Success;
     }
     downServers.insert(address);
+    res->d_usec = g_networkTimeoutMsec * 1000;
     return LWResult::Result::Timeout;
   });
 
@@ -516,6 +517,7 @@ BOOST_AUTO_TEST_CASE(test_all_nss_network_error)
       return LWResult::Result::Success;
     }
     downServers.insert(address);
+    res->d_usec = g_networkTimeoutMsec * 1000;
     return LWResult::Result::Timeout;
   });
 
@@ -854,6 +856,7 @@ BOOST_AUTO_TEST_CASE(test_os_limit_errors)
       if (downServers.size() < 3) {
         /* only the last one will answer */
         downServers.insert(address);
+        res->d_usec = g_networkTimeoutMsec * 1000;
         return LWResult::Result::OSLimitError;
       }
       setLWResult(res, 0, true, false, true);
@@ -1768,6 +1771,18 @@ BOOST_AUTO_TEST_CASE(test_cname_length)
   BOOST_CHECK_EQUAL(res, RCode::ServFail);
   BOOST_CHECK_EQUAL(ret.size(), length);
   BOOST_CHECK_EQUAL(length, SyncRes::s_max_CNAMES_followed + 1);
+
+  // Currently a CNAME bounds check originating from the record cache causes an ImmediateServFail
+  // exception. This is different from the non-cached case, tested above. There a ServFail is
+  // returned with a partial CNAME chain. This should be fixed one way or another. For details, see
+  // how the result of syncres.cc:scanForCNAMELoop() is handled in the two cases.
+  ret.clear();
+  length = 0;
+  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
+                        ImmediateServFailException,
+                        [&](const ImmediateServFailException& isfe) {
+                          return isfe.reason == "max number of CNAMEs exceeded";
+                        });
 }
 
 BOOST_AUTO_TEST_CASE(test_cname_target_servfail)
index 7f57813e6b07d248426af1e5cad246fa056680cc..dc0fc76d58ae45e48f393f71d368ca427b5b2e77 100644 (file)
@@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(test_throttled_server)
 
   /* mark ns as down */
   time_t now = sr->getNow().tv_sec;
-  SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
+  SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000, SyncRes::ThrottleReason::Timeout);
 
   vector<DNSRecord> ret;
   int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
@@ -432,7 +432,7 @@ BOOST_AUTO_TEST_CASE(test_throttled_server_count)
   const size_t blocks = 10;
   /* mark ns as down for 'blocks' queries */
   time_t now = sr->getNow().tv_sec;
-  SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
+  SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks, SyncRes::ThrottleReason::Timeout);
 
   for (size_t idx = 0; idx < blocks; idx++) {
     BOOST_CHECK(SyncRes::isThrottled(now, ns));
@@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(test_throttled_server_time)
   const size_t seconds = 1;
   /* mark ns as down for 'seconds' seconds */
   time_t now = sr->getNow().tv_sec;
-  SyncRes::doThrottle(now, ns, seconds, 10000);
+  SyncRes::doThrottle(now, ns, seconds, 10000, SyncRes::ThrottleReason::Timeout);
 
   BOOST_CHECK(SyncRes::isThrottled(now, ns));
 
index 0939c12ba2855ac87e4f3903ab546e7e1be9dc80..303bf97c7ff5261ab36ad000da7ef9ca5b3a8b00 100644 (file)
@@ -158,14 +158,11 @@ BOOST_AUTO_TEST_CASE(test_extra_answers)
   BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
   BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
 
-  // The cache should also have an authoritative record for the extra in-bailiwick record
-  BOOST_REQUIRE_GT(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
-  BOOST_REQUIRE_EQUAL(cached.size(), 1U);
-  BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
-  BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.3").toString());
+  // The cache should not have an authoritative record for the extra in-bailiwick record
+  BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
 
-  // But the out-of-bailiwick record should not be there
-  BOOST_REQUIRE_LT(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
+  // And the out-of-bailiwick record should not be there
+  BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
 }
 
 BOOST_AUTO_TEST_CASE(test_dnssec_extra_answers)
@@ -229,14 +226,11 @@ BOOST_AUTO_TEST_CASE(test_dnssec_extra_answers)
   BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
   BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
 
-  // The cache should also have an authoritative record for the extra in-bailiwick record
-  BOOST_REQUIRE_GT(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
-  BOOST_REQUIRE_EQUAL(cached.size(), 1U);
-  BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
-  BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.3").toString());
+  // The cache should not have an authoritative record for the extra in-bailiwick record
+  BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
 
-  // But the out-of-bailiwick record should not be there
-  BOOST_REQUIRE_LT(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
+  // And the out-of-bailiwick record should not be there
+  BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
 }
 
 BOOST_AUTO_TEST_CASE(test_skip_opt_any)
index eae64d6d1b6e78dfeba0c37a6e5787cb32f6b2d7..88525c34d26f04bbb2a6f2a1de6298855cdef777 100644 (file)
@@ -992,13 +992,13 @@ BOOST_AUTO_TEST_CASE(test_bogus_does_not_replace_secure_in_the_cache)
       if (domain == DNSName("powerdns.com.") && type == QType::A) {
         addRecordToLW(res, domain, QType::A, "192.0.2.1");
         addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
-        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400");
+        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY);
         addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
       }
       else if (domain == DNSName("powerdns.com.") && type == QType::AAAA) {
         addRecordToLW(res, domain, QType::AAAA, "2001:db8::1");
         addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
-        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400");
+        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY);
         /* no RRSIG this time! */
       }
 
@@ -1011,7 +1011,7 @@ BOOST_AUTO_TEST_CASE(test_bogus_does_not_replace_secure_in_the_cache)
   vector<DNSRecord> ret;
   int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
   BOOST_CHECK_EQUAL(res, RCode::NoError);
-  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
+  BOOST_CHECK_EQUAL(ret.size(), 2U);
 
   const ComboAddress who;
   vector<DNSRecord> cached;
index 125cacd8314ee544e9045fe64063a6efec61d538..ee3a38eb87020a9a78db019464890576b6f1f956 100644 (file)
@@ -28,6 +28,7 @@
 #endif
 #include <boost/test/unit_test.hpp>
 
+#include <array>
 #include <iostream>
 #include <dnsrecords.hh>
 #include <iomanip>
 
 static std::string s_timestampFormat = "%s";
 
-static const char* toTimestampStringMilli(const struct timeval& tv, char* buf, size_t sz)
-
-{
-  struct tm tm;
-  size_t len = strftime(buf, sz, s_timestampFormat.c_str(), localtime_r(&tv.tv_sec, &tm));
-  if (len == 0) {
-    len = snprintf(buf, sz, "%lld", static_cast<long long>(tv.tv_sec));
-  }
-
-  snprintf(buf + len, sz - len, ".%03ld", static_cast<long>(tv.tv_usec) / 1000);
-  return buf;
-}
-
 static void loggerBackend(const Logging::Entry& entry)
 {
   static thread_local std::stringstream buf;
@@ -65,17 +53,17 @@ static void loggerBackend(const Logging::Entry& entry)
     buf << " subsystem=" << std::quoted(entry.name.get());
   }
   buf << " level=" << entry.level;
-  if (entry.d_priority) {
+  if (entry.d_priority != 0) {
     buf << " prio=" << static_cast<int>(entry.d_priority);
   }
-  char timebuf[64];
-  buf << " ts=" << std::quoted(toTimestampStringMilli(entry.d_timestamp, timebuf, sizeof(timebuf)));
-  for (auto const& v : entry.values) {
+  std::array<char, 64> timebuf{};
+  buf << " ts=" << std::quoted(Logging::toTimestampStringMilli(entry.d_timestamp, timebuf));
+  for (auto const& val : entry.values) {
     buf << " ";
-    buf << v.first << "=" << std::quoted(v.second);
+    buf << val.first << "=" << std::quoted(val.second);
   }
-  Logger::Urgency u = entry.d_priority ? Logger::Urgency(entry.d_priority) : Logger::Info;
-  g_log << u << buf.str() << endl;
+  Logger::Urgency urgency = entry.d_priority != 0 ? Logger::Urgency(entry.d_priority) : Logger::Info;
+  g_log << urgency << buf.str() << endl;
 }
 
 static bool init_unit_test()
@@ -92,5 +80,6 @@ static bool init_unit_test()
 // entry point:
 int main(int argc, char* argv[])
 {
+  setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
   return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
 }
index af2cbfee3ea25517e16594abd1100ffdb7e69f1b..54f4773ff4e5f05dc4a648c51bf217d638660617 100644 (file)
@@ -214,6 +214,7 @@ static void fillZone(const DNSName& zonename, HttpResponse* resp)
     {"kind", zone.d_servers.empty() ? "Native" : "Forwarded"},
     {"servers", servers},
     {"recursion_desired", zone.d_servers.empty() ? false : zone.d_rdForward},
+    {"notify_allowed", isAllowNotifyForZone(zonename)},
     {"records", records}};
 
   resp->setJsonBody(doc);
@@ -232,6 +233,7 @@ static void doCreateZone(const Json& document)
   string singleIPTarget = document["single_target_ip"].string_value();
   string kind = toUpper(stringFromJson(document, "kind"));
   bool rdFlag = boolFromJson(document, "recursion_desired");
+  bool notifyAllowed = boolFromJson(document, "notify_allowed", false);
   string confbasename = "zone-" + apiZoneNameToId(zone);
 
   const string yamlAPiZonesFile = ::arg()["api-config-dir"] + "/apizones";
@@ -280,7 +282,7 @@ static void doCreateZone(const Json& document)
       pdns::rust::settings::rec::ForwardZone forward;
       forward.zone = zonename;
       forward.recurse = rdFlag;
-      forward.notify_allowed = false;
+      forward.notify_allowed = notifyAllowed;
       for (const auto& value : document["servers"].array_items()) {
         forward.forwarders.emplace_back(value.string_value());
       }
@@ -308,11 +310,12 @@ static void doCreateZone(const Json& document)
         throw ApiException("Need at least one upstream server when forwarding");
       }
 
+      const string notifyAllowedConfig = notifyAllowed ? "\nallow-notify-for+=" + zonename : "";
       if (rdFlag) {
-        apiWriteConfigFile(confbasename, "forward-zones-recurse+=" + zonename + "=" + serverlist);
+        apiWriteConfigFile(confbasename, "forward-zones-recurse+=" + zonename + "=" + serverlist + notifyAllowedConfig);
       }
       else {
-        apiWriteConfigFile(confbasename, "forward-zones+=" + zonename + "=" + serverlist);
+        apiWriteConfigFile(confbasename, "forward-zones+=" + zonename + "=" + serverlist + notifyAllowedConfig);
       }
     }
   }
@@ -891,6 +894,9 @@ const std::map<std::string, MetricDefinition> MetricDefinitionStorage::d_metrics
   {"tcp-client-overflow",
    MetricDefinition(PrometheusMetricType::counter,
                     "Number of times an IP address was denied TCP access because it already had too many connections")},
+  {"tcp-overflow",
+   MetricDefinition(PrometheusMetricType::counter,
+                    "Number of times a TCP connection was denied access because too many connections")},
   {"tcp-clients",
    MetricDefinition(PrometheusMetricType::gauge,
                     "Number of currently active TCP/IP clients")},
@@ -1246,6 +1252,18 @@ const std::map<std::string, MetricDefinition> MetricDefinitionStorage::d_metrics
   {"udr-events",
    MetricDefinition(PrometheusMetricType::counter,
                     "Count of UDR events")},
+
+  {"max-chain-length",
+   MetricDefinition(PrometheusMetricType::counter,
+                    "Maximum chain length")},
+
+  {"max-chain-weight",
+   MetricDefinition(PrometheusMetricType::counter,
+                    "Maximum chain weight")},
+
+  {"chain-limits",
+   MetricDefinition(PrometheusMetricType::counter,
+                    "Chain limits reached")},
 };
 
 constexpr bool CHECK_PROMETHEUS_METRICS = false;
index 28db4e65efd088cff3ed368c4a8afcb9d3ea17f1..9d8a27c47eac10fcd57d723e6e3e9c4241504efc 100644 (file)
@@ -214,10 +214,10 @@ namespace pdns {
       result->reserve(mdp.d_answers.size());
 
       for (const auto& i: mdp.d_answers) {
-        rr.qname = i.first.d_name;
-        rr.qtype = i.first.d_type;
-        rr.ttl = i.first.d_ttl;
-        rr.content = i.first.getContent()->getZoneRepresentation(true);
+        rr.qname = i.d_name;
+        rr.qtype = i.d_type;
+        rr.ttl = i.d_ttl;
+        rr.content = i.getContent()->getZoneRepresentation(true);
         result->push_back(rr);
       }
 
@@ -286,15 +286,15 @@ bool Resolver::tryGetSOASerial(DNSName *domain, ComboAddress* remote, uint32_t *
   *theirInception = *theirExpire = 0;
   bool gotSOA=false;
   for(const MOADNSParser::answers_t::value_type& drc :  mdp.d_answers) {
-    if(drc.first.d_type == QType::SOA && drc.first.d_name == *domain) {
-      auto src = getRR<SOARecordContent>(drc.first);
+    if(drc.d_type == QType::SOA && drc.d_name == *domain) {
+      auto src = getRR<SOARecordContent>(drc);
       if (src) {
         *theirSerial = src->d_st.serial;
         gotSOA = true;
       }
     }
-    if(drc.first.d_type == QType::RRSIG && drc.first.d_name == *domain) {
-      auto rrc = getRR<RRSIGRecordContent>(drc.first);
+    if(drc.d_type == QType::RRSIG && drc.d_name == *domain) {
+      auto rrc = getRR<RRSIGRecordContent>(drc);
       if(rrc && rrc->d_type == QType::SOA) {
         *theirInception= std::max(*theirInception, rrc->d_siginception);
         *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
index f0d6e9361a6b1e2c7d5a6a906b5eb4b9bcbe6a4d..be4d78f5c12735b5469e0ccd4f9576e4b7246399 100644 (file)
@@ -768,13 +768,14 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
 
   // Check if all the records provided are within the zone
   for(const auto & answer : mdp.d_answers) {
-    const DNSRecord *rr = &answer.first;
+    const DNSRecord *dnsRecord = &answer;
     // Skip this check for other field types (like the TSIG -  which is in the additional section)
     // For a TSIG, the label is the dnskey, so it does not pass the endOn validation.
-    if (! (rr->d_place == DNSResourceRecord::ANSWER || rr->d_place == DNSResourceRecord::AUTHORITY))
+    if (dnsRecord->d_place != DNSResourceRecord::ANSWER && dnsRecord->d_place != DNSResourceRecord::AUTHORITY) {
       continue;
+    }
 
-    if (!rr->d_name.isPartOf(di.zone)) {
+    if (!dnsRecord->d_name.isPartOf(di.zone)) {
       g_log<<Logger::Error<<msgPrefix<<"Received update/record out of zone, sending NotZone."<<endl;
       return RCode::NotZone;
     }
@@ -790,11 +791,11 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
 
   // 3.2.1 and 3.2.2 - Prerequisite check
   for(const auto & answer : mdp.d_answers) {
-    const DNSRecord *rr = &answer.first;
-    if (rr->d_place == DNSResourceRecord::ANSWER) {
-      int res = checkUpdatePrerequisites(rr, &di);
+    const DNSRecord *dnsRecord = &answer;
+    if (dnsRecord->d_place == DNSResourceRecord::ANSWER) {
+      int res = checkUpdatePrerequisites(dnsRecord, &di);
       if (res>0) {
-        g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check for "<<rr->d_name<<", returning "<<RCode::to_s(res)<<endl;
+        g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check for "<<dnsRecord->d_name<<", returning "<<RCode::to_s(res)<<endl;
         di.backend->abortTransaction();
         return res;
       }
@@ -807,16 +808,17 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
   typedef std::map<rrSetKey_t, rrVector_t> RRsetMap_t;
   RRsetMap_t preReqRRsets;
   for(const auto& i: mdp.d_answers) {
-    const DNSRecord* rr = &i.first;
-    if (rr->d_place == DNSResourceRecord::ANSWER) {
+    const DNSRecord* dnsRecord = &i;
+    if (dnsRecord->d_place == DNSResourceRecord::ANSWER) {
       // Last line of 3.2.3
-      if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
+      if (dnsRecord->d_class != QClass::IN && dnsRecord->d_class != QClass::NONE && dnsRecord->d_class != QClass::ANY) {
         return RCode::FormErr;
+      }
 
-      if (rr->d_class == QClass::IN) {
-        rrSetKey_t key = {rr->d_name, QType(rr->d_type)};
+      if (dnsRecord->d_class == QClass::IN) {
+        rrSetKey_t key = {dnsRecord->d_name, QType(dnsRecord->d_type)};
         rrVector_t *vec = &preReqRRsets[key];
-        vec->push_back(DNSResourceRecord::fromWire(*rr));
+        vec->push_back(DNSResourceRecord::fromWire(*dnsRecord));
       }
     }
   }
@@ -855,9 +857,9 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
     uint changedRecords = 0;
     // 3.4.1 - Prescan section
     for(const auto & answer : mdp.d_answers) {
-      const DNSRecord *rr = &answer.first;
-      if (rr->d_place == DNSResourceRecord::AUTHORITY) {
-        int res = checkUpdatePrescan(rr);
+      const DNSRecord *dnsRecord = &answer;
+      if (dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
+        int res = checkUpdatePrescan(dnsRecord);
         if (res>0) {
           g_log<<Logger::Error<<msgPrefix<<"Failed prescan check, returning "<<res<<endl;
           di.backend->abortTransaction();
@@ -882,12 +884,12 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
     // Another special case is the addition of both a CNAME and a non-CNAME for the same name (#6270)
     set<DNSName> cn, nocn;
     for (const auto &rr : mdp.d_answers) {
-      if (rr.first.d_place == DNSResourceRecord::AUTHORITY && rr.first.d_class == QClass::IN && rr.first.d_ttl > 0) {
+      if (rr.d_place == DNSResourceRecord::AUTHORITY && rr.d_class == QClass::IN && rr.d_ttl > 0) {
         // Addition
-        if (rr.first.d_type == QType::CNAME) {
-          cn.insert(rr.first.d_name);
-        } else if (rr.first.d_type != QType::RRSIG) {
-          nocn.insert(rr.first.d_name);
+        if (rr.d_type == QType::CNAME) {
+          cn.insert(rr.d_name);
+        } else if (rr.d_type != QType::RRSIG) {
+          nocn.insert(rr.d_name);
         }
       }
     }
@@ -901,29 +903,30 @@ int PacketHandler::processUpdate(DNSPacket& packet) { // NOLINT(readability-func
 
     vector<const DNSRecord *> cnamesToAdd, nonCnamesToAdd;
     for(const auto & answer : mdp.d_answers) {
-      const DNSRecord *rr = &answer.first;
-      if (rr->d_place == DNSResourceRecord::AUTHORITY) {
+      const DNSRecord *dnsRecord = &answer;
+      if (dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
         /* see if it's permitted by policy */
         if (this->d_update_policy_lua != nullptr) {
-          if (!this->d_update_policy_lua->updatePolicy(rr->d_name, QType(rr->d_type), di.zone, packet)) {
-            g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).toString() << ": Not permitted by policy"<<endl;
+          if (!this->d_update_policy_lua->updatePolicy(dnsRecord->d_name, QType(dnsRecord->d_type), di.zone, packet)) {
+            g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << dnsRecord->d_name << "/" << QType(dnsRecord->d_type).toString() << ": Not permitted by policy"<<endl;
             continue;
           } else {
-            g_log<<Logger::Debug<<msgPrefix<<"Accepting update for " << rr->d_name << "/" << QType(rr->d_type).toString() << ": Permitted by policy"<<endl;
+            g_log<<Logger::Debug<<msgPrefix<<"Accepting update for " << dnsRecord->d_name << "/" << QType(dnsRecord->d_type).toString() << ": Permitted by policy"<<endl;
           }
         }
 
-        if (rr->d_class == QClass::NONE  && rr->d_type == QType::NS && rr->d_name == di.zone)
-          nsRRtoDelete.push_back(rr);
-        else if (rr->d_class == QClass::IN &&  rr->d_ttl > 0) {
-          if (rr->d_type == QType::CNAME) {
-            cnamesToAdd.push_back(rr);
+        if (dnsRecord->d_class == QClass::NONE  && dnsRecord->d_type == QType::NS && dnsRecord->d_name == di.zone) {
+          nsRRtoDelete.push_back(dnsRecord);
+        }
+        else if (dnsRecord->d_class == QClass::IN &&  dnsRecord->d_ttl > 0) {
+          if (dnsRecord->d_type == QType::CNAME) {
+            cnamesToAdd.push_back(dnsRecord);
           } else {
-            nonCnamesToAdd.push_back(rr);
+            nonCnamesToAdd.push_back(dnsRecord);
           }
         }
         else
-          changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+          changedRecords += performUpdate(msgPrefix, dnsRecord, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
       }
     }
     for (const auto &rr : cnamesToAdd) {
index bd333095e955e96860dd4cc64e9ee1b21ccfaf82..8e733568e96cbc8afc1ee95ff18497c8ff0c49e3 100644 (file)
@@ -16,6 +16,7 @@
 
 StatBag S;
 
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
 int main(int argc, char** argv)
 try
 {
@@ -144,9 +145,11 @@ try
          throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
        }
        for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
-         if(i->first.d_type != QType::TKEY) continue;
+         if (i->d_type != QType::TKEY) {
+           continue;
+         }
          // recover TKEY record
-         tkrc = TKEYRecordContent(i->first.getContent()->getZoneRepresentation());
+         tkrc = TKEYRecordContent(i->getContent()->getZoneRepresentation());
          input = tkrc.d_key;
        }
     }
@@ -209,39 +212,39 @@ try
       throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
     }
     for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
-      if (i->first.d_type == QType::TSIG) {
+      if (i->d_type == QType::TSIG) {
         string message;
         if (!tsig) {
           std::cerr<<"Unexpected TSIG signature in data"<<endl;
         }
-        trc = TSIGRecordContent(i->first.getContent()->getZoneRepresentation());
+        trc = TSIGRecordContent(i->getContent()->getZoneRepresentation());
         continue;
       }
-      if(i->first.d_type == QType::SOA)
+      if(i->d_type == QType::SOA)
       {
         ++soacount;
       }
-      else if (i->first.d_type == QType::NSEC3PARAM) {
-        ns3pr = NSEC3PARAMRecordContent(i->first.getContent()->getZoneRepresentation());
+      else if (i->d_type == QType::NSEC3PARAM) {
+        ns3pr = NSEC3PARAMRecordContent(i->getContent()->getZoneRepresentation());
         isNSEC3 = true;
       }
 
       ostringstream o;
-      o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+      o<<"\t"<<i->d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->d_type);
       if(showdetails)
       {
-        o<<"\t"<<i->first.getContent()->getZoneRepresentation();
+        o<<"\t"<<i->getContent()->getZoneRepresentation();
       }
-      else if(i->first.d_type == QType::RRSIG)
+      else if(i->d_type == QType::RRSIG)
       {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
       }
-      else if(i->first.d_type == QType::NSEC3)
+      else if(i->d_type == QType::NSEC3)
       {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         o<<"\t"<<parts[0]<<" ";
@@ -253,21 +256,21 @@ try
         for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
           o<<" "<<*iter;
       }
-      else if(i->first.d_type == QType::DNSKEY)
+      else if(i->d_type == QType::DNSKEY)
       {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
       }
       else
       {
-        o<<"\t"<<i->first.getContent()->getZoneRepresentation();
+        o<<"\t"<<i->getContent()->getZoneRepresentation();
       }
 
-      records.emplace_back(i->first.d_name, o.str());
+      records.emplace_back(i->d_name, o.str());
 
-      DNSName shorter(i->first.d_name);
+      DNSName shorter(i->d_name);
       do {
         labels.insert(shorter);
         if (shorter == DNSName(argv[3]))
index 7362cc8164e0d5e3ff69bd6e5c2bcec5f748851c..66fc26603e7ceeea06721f6a25e086f85d63cff0 100644 (file)
@@ -104,16 +104,16 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
 
   for (MOADNSParser::answers_t::const_iterator i = mdp.d_answers.begin();
        i != mdp.d_answers.end(); ++i) {
-    cout << i->first.d_place - 1 << "\t" << i->first.d_name.toString() << "\t"
-         << ttl(i->first.d_ttl) << "\t" << nameForClass(i->first.d_class, i->first.d_type) << "\t"
-         << DNSRecordContent::NumberToType(i->first.d_type);
+    cout << i->d_place - 1 << "\t" << i->d_name.toString() << "\t"
+         << ttl(i->d_ttl) << "\t" << nameForClass(i->d_class, i->d_type) << "\t"
+         << DNSRecordContent::NumberToType(i->d_type);
     if (dumpluaraw) {
-      cout<<"\t"<< makeLuaString(i->first.getContent()->serialize(DNSName(), true))<<endl;
+      cout<<"\t"<< makeLuaString(i->getContent()->serialize(DNSName(), true))<<endl;
       continue;
     }
-    if (i->first.d_class == QClass::IN) {
-      if (i->first.d_type == QType::RRSIG) {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+    if (i->d_class == QClass::IN) {
+      if (i->d_type == QType::RRSIG) {
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         cout << "\t" << parts[0] << " "
@@ -121,8 +121,8 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
              << " [expiry] [inception] [keytag] " << parts[7] << " ...\n";
         continue;
       }
-      if (!showflags && i->first.d_type == QType::NSEC3) {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+      if (!showflags && i->d_type == QType::NSEC3) {
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         cout << "\t" << parts[0] << " [flags] "
@@ -133,16 +133,16 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
         cout << "\n";
         continue;
       }
-      if (i->first.d_type == QType::DNSKEY) {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+      if (i->d_type == QType::DNSKEY) {
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         cout << "\t" << parts[0] << " "
              << parts[1] << " " << parts[2] << " ...\n";
         continue;
       }
-      if (i->first.d_type == QType::SOA && hidesoadetails) {
-        string zoneRep = i->first.getContent()->getZoneRepresentation();
+      if (i->d_type == QType::SOA && hidesoadetails) {
+        string zoneRep = i->getContent()->getZoneRepresentation();
         vector<string> parts;
         stringtok(parts, zoneRep);
         cout << "\t" << parts[0] << " "
@@ -151,7 +151,7 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
         continue;
       }
     }
-    cout << "\t" << i->first.getContent()->getZoneRepresentation() << "\n";
+    cout << "\t" << i->getContent()->getZoneRepresentation() << "\n";
   }
 
   EDNSOpts edo;
index 2a4f758c08052fa1447cda45994fb80b5998ce69..f26dd250bdff2e67822064dff1c791b55ab57974 100644 (file)
 
 #include "lock.hh"
 
-/** This is sort of a light-weight RCU idea. 
+/** This is sort of a light-weight RCU idea.
     Suitable for when you frequently consult some "readonly" state, which infrequently
-    gets changed. One way of dealing with this is fully locking access to the state, but 
+    gets changed. One way of dealing with this is fully locking access to the state, but
     this is rather wasteful.
 
-    Instead, in the code below, the frequent users of the state get a "readonly" copy of it, 
-    which they can consult.  On access, we atomically compare if the local copy is still current 
+    Instead, in the code below, the frequent users of the state get a "readonly" copy of it,
+    which they can consult.  On access, we atomically compare if the local copy is still current
     with the global one.  If it isn't we do the lock thing, and create a new local copy.
 
-    Meanwhile, to upgrade the global state, methods are offered that do appropriate locking 
+    Meanwhile, to upgrade the global state, methods are offered that do appropriate locking
     and upgrade the 'generation' counter, signaling to the local copies that they need to be
     refreshed on the next access.
 
     Two ways to change the global copy are available:
         getCopy(), which delivers a deep copy of the current state, followed by setState()
-       modify(), which accepts a (lambda)function that modifies the state
+        modify(), which accepts a (lambda)function that modifies the state
 
-    NOTE: The actual destruction of the 'old' state happens when the last local state 
+    NOTE: The actual destruction of the 'old' state happens when the last local state
     relinquishes its access to the state.
 
     "read-only"
-    Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for 
+    Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for
     example, atomic counters. In such cases, it may be useful to explicitly declare such counters
     as mutable.  */
 
-template<typename T> class GlobalStateHolder;
+template <typename T>
+class GlobalStateHolder;
 
-template<typename T>
+template <typename T>
 class LocalStateHolder
 {
 public:
-  explicit LocalStateHolder(GlobalStateHolder<T>* source) : d_source(source)
+  explicit LocalStateHolder(GlobalStateHolder<T>* source) :
+    d_source(source)
   {}
 
-  const T* operator->()  // fast const-only access, but see "read-only" above
+  const T* operator->() // fast const-only access, but see "read-only" above
   {
-    if(d_source->getGeneration() != d_generation) {
-      d_source->getState(&d_state, & d_generation);
+    if (d_source->getGeneration() != d_generation) {
+      d_source->getState(&d_state, &d_generation);
     }
 
     return d_state.get();
   }
-  const T& operator*()  // fast const-only access, but see "read-only" above
+  const T& operator*() // fast const-only access, but see "read-only" above
   {
     return *operator->();
   }
 
   void reset()
   {
-    d_generation=0;
+    d_generation = 0;
     d_state.reset();
   }
+
 private:
   std::shared_ptr<T> d_state;
   unsigned int d_generation{0};
   const GlobalStateHolder<T>* d_source;
 };
 
-template<typename T>
+template <typename T>
 class GlobalStateHolder
 {
 public:
-  GlobalStateHolder() : d_state(std::make_shared<T>())
+  GlobalStateHolder() :
+    d_state(std::make_shared<T>())
   {}
   LocalStateHolder<T> getLocal()
   {
@@ -112,14 +116,15 @@ public:
     }
   }
 
-  T getCopy() const  //!< Safely & slowly get a copy of the global state
+  T getCopy() const //!< Safely & slowly get a copy of the global state
   {
     return *(*(d_state.lock()));
   }
-  
+
   //! Safely & slowly modify the global state
-  template<typename F>
-  void modify(F act) {
+  template <typename F>
+  void modify(F act)
+  {
     auto state = d_state.lock();
     auto newState = *(*state); // and yes, these three steps are necessary, can't ever modify state in place, even when locked!
     act(newState);
@@ -127,7 +132,8 @@ public:
     ++d_generation;
   }
 
-  typedef T value_type;
+  using value_type = T;
+
 private:
   unsigned int getGeneration() const
   {
index 5f96fcd39bac5bde57e1ca03f1884aba8c782361..0e507a76d54d3fb101f94dde0d4f527d8b019cc1 100644 (file)
@@ -32,7 +32,8 @@
 // shuffle, maintaining some semblance of order
 void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
 {
-  std::vector<DNSZoneRecord>::iterator first, second;
+  std::vector<DNSZoneRecord>::iterator first;
+  std::vector<DNSZoneRecord>::iterator second;
 
   // We assume the CNAMES are listed first in the ANSWER section and the the other records
   // and we want to shuffle the other records only
@@ -44,14 +45,16 @@ void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
     }
   }
   // And then for one past the last ANSWER record
-  for (second = first; second != rrs.end(); ++second)
-    if (second->dr.d_place != DNSResourceRecord::ANSWER)
+  for (second = first; second != rrs.end(); ++second) {
+    if (second->dr.d_place != DNSResourceRecord::ANSWER) {
       break;
+    }
+  }
 
   // Now shuffle the non-CNAME ANSWER records
-  dns_random_engine r;
+  dns_random_engine randomEngine;
   if (second - first > 1) {
-    shuffle(first, second, r);
+    shuffle(first, second, randomEngine);
   }
 
   // now shuffle the ADDITIONAL records in the same manner as the ANSWER records
@@ -67,7 +70,7 @@ void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
   }
 
   if (second - first > 1) {
-    shuffle(first, second, r);
+    shuffle(first, second, randomEngine);
   }
   // we don't shuffle the rest
 }
@@ -76,7 +79,9 @@ void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
 static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
 {
   // This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
-  std::vector<DNSRecord>::iterator first, second;
+  std::vector<DNSRecord>::iterator first;
+  std::vector<DNSRecord>::iterator second;
+
   for (first = rrs.begin(); first != rrs.end(); ++first) {
     if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
       break;
@@ -88,9 +93,9 @@ static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
     }
   }
 
-  pdns::dns_random_engine r;
+  pdns::dns_random_engine randomEngine;
   if (second - first > 1) {
-    shuffle(first, second, r);
+    shuffle(first, second, randomEngine);
   }
 
   if (!includingAdditionals) {
@@ -110,27 +115,28 @@ static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
   }
 
   if (second - first > 1) {
-    shuffle(first, second, r);
+    shuffle(first, second, randomEngine);
   }
   // we don't shuffle the rest
 }
 
 static uint16_t mapTypesToOrder(uint16_t type)
 {
-  if (type == QType::CNAME)
+  if (type == QType::CNAME) {
     return 0;
-  if (type == QType::RRSIG)
+  }
+  if (type == QType::RRSIG) {
     return 65535;
-  else
-    return 1;
+  }
+  return 1;
 }
 
 // make sure rrs is sorted in d_place order to avoid surprises later
 // then shuffle the parts that desire shuffling
 void pdns::orderAndShuffle(vector<DNSRecord>& rrs, bool includingAdditionals)
 {
-  std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
-    return std::tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::tuple(b.d_place, mapTypesToOrder(b.d_type));
+  std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& lhs, const DNSRecord& rhs) {
+    return std::tuple(lhs.d_place, mapTypesToOrder(lhs.d_type)) < std::tuple(rhs.d_place, mapTypesToOrder(rhs.d_type));
   });
   shuffle(rrs, includingAdditionals);
 }
index 0e0556056427a2b963fde1c3d892e02a99cfef2e..25f3d59b9f9783c02e31eb21db95cc994966f9b7 100644 (file)
@@ -1,3 +1,4 @@
+#include "threadname.hh"
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -49,6 +50,7 @@ int readn(int fd, void* buffer, unsigned int len)
 
 void* ChunkedSigningPipe::helperWorker(ChunkedSigningPipe* csp, int fd)
 try {
+  setThreadName("pdns/signer");
   csp->worker(fd);
   return nullptr;
 }
index a335f31d0c0d38bbff0e2f86faf256cb3b832853..0e7ca82d65e8c1ca6c9b7d4518423a4738e9d7a5 100644 (file)
@@ -9,6 +9,14 @@
 
 #ifdef HAVE_NET_SNMP
 
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/definitions.h>
+#include <net-snmp/types.h>
+#include <net-snmp/utilities.h>
+#include <net-snmp/config_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#undef INET6 /* SRSLY? */
+
 #ifndef HAVE_SNMP_SELECT_INFO2
 /* that's terrible, because it means we are going to have trouble with large
    FD numbers at some point.. */
@@ -25,7 +33,7 @@
 # include <net-snmp/library/large_fd_set.h>
 #endif
 
-const std::array<oid, 11> SNMPAgent::snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
+static const std::array<oid, 11> s_snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
 
 int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
                                  uint64_t value)
@@ -40,6 +48,16 @@ int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
   return SNMP_ERR_NOERROR;
 }
 
+void SNMPAgent::addSNMPTrapOID(netsnmp_variable_list** varList, const void* value, size_t len)
+{
+  snmp_varlist_add_variable(varList,
+                            s_snmpTrapOID.data(),
+                            s_snmpTrapOID.size(),
+                            ASN_OBJECT_ID,
+                            value,
+                            len);
+}
+
 bool SNMPAgent::sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
                          netsnmp_variable_list* varList)
 {
index c75db08616051209d1936c2ab73f893cf96a1c9d..06989afc21efb0de5fd0e3068799a3ef668bba21 100644 (file)
@@ -5,19 +5,12 @@
 #include <thread>
 #include <unistd.h>
 
-#ifdef HAVE_NET_SNMP
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/definitions.h>
-#include <net-snmp/types.h>
-#include <net-snmp/utilities.h>
-#include <net-snmp/config_api.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#undef INET6 /* SRSLY? */
-#endif /* HAVE_NET_SNMP */
-
 #include "mplexer.hh"
 #include "channel.hh"
 
+typedef struct netsnmp_request_info_s netsnmp_request_info;
+typedef struct variable_list netsnmp_variable_list;
+
 class SNMPAgent
 {
 public:
@@ -40,8 +33,7 @@ public:
 #endif /* HAVE_NET_SNMP */
 protected:
 #ifdef HAVE_NET_SNMP
-  /* OID for snmpTrapOID.0 */
-  static const std::array<oid, 11> snmpTrapOID;
+  static void addSNMPTrapOID(netsnmp_variable_list** varList, const void* value, size_t len);
 
   static bool sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
                        netsnmp_variable_list* varList);
index f8188b0ab2aee6208c9c9c7028c16320020f81dc..976275c3a1a1ce56d434189e5b772cba23e309d9 100644 (file)
@@ -669,11 +669,11 @@ struct ParsePacketTest
     } lwr;
     for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
       DNSResourceRecord rr;
-      rr.qtype=i->first.d_type;
-      rr.qname=i->first.d_name;
+      rr.qtype=i->d_type;
+      rr.qname=i->d_name;
 
-      rr.ttl=i->first.d_ttl;
-      rr.content=i->first.getContent()->getZoneRepresentation();  // this should be the serialised form
+      rr.ttl=i->d_ttl;
+      rr.content=i->getContent()->getZoneRepresentation();  // this should be the serialised form
       lwr.d_result.push_back(rr);
     }
 
index ec28058ea85e5bf171b77e9ed8166a9514ef4040..cd7d361e6cb02d5c252a773750ad1f6e242887f9 100644 (file)
@@ -377,7 +377,7 @@ int SSQLite3::busyHandler([[maybe_unused]] void* userData, [[maybe_unused]] int
 
 void SSQLite3::startTransaction()
 {
-  execute("begin");
+  execute("begin immediate");
   m_in_transaction = true;
 }
 
index 88f680929934dd1363d6ce5dc577cee4b74836c3..e673c320dde6dde394ebd9f8af10066e489149bb 100644 (file)
@@ -35,7 +35,6 @@
 #include <fcntl.h>
 #include <stdexcept>
 
-#include <boost/utility.hpp>
 #include <csignal>
 #include "namespaces.hh"
 #include "noinitvector.hh"
 using ProtocolType = int; //!< Supported protocol types
 
 //! Representation of a Socket and many of the Berkeley functions available
-class Socket : public boost::noncopyable
+class Socket
 {
 public:
-  Socket(int fd): d_socket(fd)
+  Socket(const Socket&) = delete;
+  Socket& operator=(const Socket&) = delete;
+
+  Socket(int socketDesc) :
+    d_socket(socketDesc)
   {
   }
 
   //! Construct a socket of specified address family and socket type.
-  Socket(int af, int st, ProtocolType pt=0)
+  Socket(int addressFamily, int socketType, ProtocolType protocolType = 0) :
+    d_socket(socket(addressFamily, socketType, protocolType))
   {
-    if((d_socket=socket(af, st, pt))<0)
+    if (d_socket < 0) {
       throw NetworkError(stringerror());
+    }
     setCloseOnExec(d_socket);
   }
 
@@ -82,60 +87,64 @@ public:
         closesocket(d_socket);
       }
     }
-    catch(const PDNSException& e) {
+    catch (const PDNSException& e) {
     }
   }
 
   //! If the socket is capable of doing so, this function will wait for a connection
-  std::unique_ptr<Socket> accept()
+  [[nodiscard]] std::unique_ptr<Socket> accept() const
   {
-    struct sockaddr_in remote;
-    socklen_t remlen=sizeof(remote);
+    sockaddr_in remote{};
+    socklen_t remlen = sizeof(remote);
     memset(&remote, 0, sizeof(remote));
-    int s=::accept(d_socket, reinterpret_cast<sockaddr *>(&remote), &remlen);
-    if(s<0) {
-      if(errno==EAGAIN)
+    int sock = ::accept(d_socket, reinterpret_cast<sockaddr*>(&remote), &remlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+    if (sock < 0) {
+      if (errno == EAGAIN) {
         return nullptr;
+      }
 
-      throw NetworkError("Accepting a connection: "+stringerror());
+      throw NetworkError("Accepting a connection: " + stringerror());
     }
 
-    return std::make_unique<Socket>(s);
+    return std::make_unique<Socket>(sock);
   }
 
   //! Get remote address
-  bool getRemote(ComboAddress &remote) {
-    socklen_t remotelen=sizeof(remote);
-    return (getpeername(d_socket, reinterpret_cast<struct sockaddr *>(&remote), &remotelen) >= 0);
+  bool getRemote(ComboAddress& remote) const
+  {
+    socklen_t remotelen = sizeof(remote);
+    return getpeername(d_socket, reinterpret_cast<struct sockaddr*>(&remote), &remotelen) >= 0; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
   }
 
   //! Check remote address against netmaskgroup ng
-  bool acl(const NetmaskGroup &ng)
+  [[nodiscard]] bool acl(const NetmaskGroup& netmaskGroup) const
   {
     ComboAddress remote;
-    if (getRemote(remote))
-      return ng.match(remote);
+    if (getRemote(remote)) {
+      return netmaskGroup.match(remote);
+    }
 
     return false;
   }
 
   //! Set the socket to non-blocking
-  void setNonBlocking()
+  void setNonBlocking() const
   {
     ::setNonBlocking(d_socket);
   }
 
   //! Set the socket to blocking
-  void setBlocking()
+  void setBlocking() const
   {
     ::setBlocking(d_socket);
   }
 
-  void setReuseAddr()
+  void setReuseAddr() const
   {
     try {
       ::setReuseAddr(d_socket);
-    } catch (const PDNSException &e) {
+    }
+    catch (const PDNSException& e) {
       throw NetworkError(e.reason);
     }
   }
@@ -148,113 +157,112 @@ public:
       throw NetworkError("While setting TCP_FASTOPEN_CONNECT: " + stringerror());
     }
 #else
-   throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
+    throw NetworkError("While setting TCP_FASTOPEN_CONNECT: not compiled in");
 #endif
   }
 
   //! Bind the socket to a specified endpoint
-  void bind(const ComboAddress &local, bool reuseaddr=true)
+  void bind(const ComboAddress& local, bool reuseaddr = true) const
   {
-    int tmp=1;
-    if(reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp)<0)
-      throw NetworkError("Setsockopt failed: "+stringerror());
-
-    if(::bind(d_socket, reinterpret_cast<const struct sockaddr *>(&local), local.getSocklen())<0)
-      throw NetworkError("While binding: "+stringerror());
+    int tmp = 1;
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    if (reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp) < 0) {
+      throw NetworkError("Setsockopt failed: " + stringerror());
+    }
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    if (::bind(d_socket, reinterpret_cast<const struct sockaddr*>(&local), local.getSocklen()) < 0) {
+      throw NetworkError("While binding: " + stringerror());
+    }
   }
 
   //! Connect the socket to a specified endpoint
-  void connect(const ComboAddress &ep, int timeout=0)
+  void connect(const ComboAddress& address, int timeout = 0) const
   {
-    SConnectWithTimeout(d_socket, ep, timeval{timeout,0});
+    SConnectWithTimeout(d_socket, address, timeval{timeout, 0});
   }
 
-
   //! For datagram sockets, receive a datagram and learn where it came from
   /** For datagram sockets, receive a datagram and learn where it came from
       \param dgram Will be filled with the datagram
       \param ep Will be filled with the origin of the datagram */
-  void recvFrom(string &dgram, ComboAddress& remote)
+  void recvFrom(string& dgram, ComboAddress& remote) const
   {
     socklen_t remlen = sizeof(remote);
     if (dgram.size() < s_buflen) {
       dgram.resize(s_buflen);
     }
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote) , &remlen);
+    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr*>(&remote), &remlen);
     if (bytes < 0) {
       throw NetworkError("After recvfrom: " + stringerror());
     }
     dgram.resize(static_cast<size_t>(bytes));
   }
 
-  bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote)
+  bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote) const
   {
     socklen_t remlen = sizeof(remote);
     if (dgram.size() < s_buflen) {
       dgram.resize(s_buflen);
     }
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote), &remlen);
+    auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr*>(&remote), &remlen);
     if (bytes < 0) {
       if (errno != EAGAIN) {
         throw NetworkError("After async recvfrom: " + stringerror());
       }
-      else {
-        return false;
-      }
+      return false;
     }
     dgram.resize(static_cast<size_t>(bytes));
     return true;
   }
 
   //! For datagram sockets, send a datagram to a destination
-  void sendTo(const char* msg, size_t len, const ComboAddress& remote)
+  void sendTo(const char* msg, size_t len, const ComboAddress& remote) const
   {
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&remote), remote.getSocklen()) < 0) {
+    if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr*>(&remote), remote.getSocklen()) < 0) {
       throw NetworkError("After sendto: " + stringerror());
     }
   }
 
   //! For connected datagram sockets, send a datagram
-  void send(const std::string& msg)
+  void send(const std::string& msg) const
   {
     if (::send(d_socket, msg.data(), msg.size(), 0) < 0) {
-      throw NetworkError("After send: "+stringerror());
+      throw NetworkError("After send: " + stringerror());
     }
   }
 
-
   /** For datagram sockets, send a datagram to a destination
       \param dgram The datagram
       \param remote The intended destination of the datagram */
-  void sendTo(const string& dgram, const ComboAddress& remote)
+  void sendTo(const string& dgram, const ComboAddress& remote) const
   {
     sendTo(dgram.data(), dgram.length(), remote);
   }
 
-
   //! Write this data to the socket, taking care that all bytes are written out
-  void writen(const string &data)
+  void writen(const string& data) const
   {
-    if(data.empty())
+    if (data.empty()) {
       return;
+    }
 
-    size_t toWrite=data.length();
-    ssize_t res;
-    const char *ptr=data.c_str();
+    size_t toWrite = data.length();
+    const char* ptr = data.data();
 
     do {
-      res=::send(d_socket, ptr, toWrite, 0);
-      if(res<0)
-        throw NetworkError("Writing to a socket: "+stringerror());
-      if(!res)
+      auto res = ::send(d_socket, ptr, toWrite, 0);
+      if (res < 0) {
+        throw NetworkError("Writing to a socket: " + stringerror());
+      }
+      if (res == 0) {
         throw NetworkError("EOF on socket");
+      }
       toWrite -= static_cast<size_t>(res);
-      ptr += static_cast<size_t>(res);
-    } while(toWrite);
-
+      ptr += static_cast<size_t>(res); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    } while (toWrite > 0);
   }
 
   //! tries to write toWrite bytes from ptr to the socket
@@ -262,129 +270,140 @@ public:
       \param ptr Location to write from
       \param toWrite number of bytes to try
   */
-  size_t tryWrite(const char *ptr, size_t toWrite)
+  size_t tryWrite(const char* ptr, size_t toWrite) const
   {
-    ssize_t res;
-    res=::send(d_socket,ptr,toWrite,0);
-    if(res==0)
+    auto res = ::send(d_socket, ptr, toWrite, 0);
+    if (res == 0) {
       throw NetworkError("EOF on writing to a socket");
-
-    if(res>0)
+    }
+    if (res > 0) {
       return res;
+    }
 
-    if(errno==EAGAIN)
+    if (errno == EAGAIN) {
       return 0;
+    }
 
-    throw NetworkError("Writing to a socket: "+stringerror());
+    throw NetworkError("Writing to a socket: " + stringerror());
   }
 
   //! Writes toWrite bytes from ptr to the socket
   /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
-  size_t write(const char *ptr, size_t toWrite)
+  size_t write(const char* ptr, size_t toWrite) const
   {
-    ssize_t res;
-    res=::send(d_socket,ptr,toWrite,0);
-    if(res<0) {
-      throw NetworkError("Writing to a socket: "+stringerror());
+    auto res = ::send(d_socket, ptr, toWrite, 0);
+    if (res < 0) {
+      throw NetworkError("Writing to a socket: " + stringerror());
     }
     return res;
   }
 
-  void writenWithTimeout(const void *buffer, size_t n, int timeout)
+  void writenWithTimeout(const void* buffer, size_t n, int timeout) const
   {
-    size_t bytes=n;
-    const char *ptr = reinterpret_cast<const char*>(buffer);
-    ssize_t ret;
-    while(bytes) {
-      ret=::write(d_socket, ptr, bytes);
-      if(ret < 0) {
-        if(errno == EAGAIN) {
-          ret=waitForRWData(d_socket, false, timeout, 0);
-          if(ret < 0)
+    size_t bytes = n;
+    const char* ptr = static_cast<const char*>(buffer);
+
+    while (bytes > 0) {
+      auto ret = ::write(d_socket, ptr, bytes);
+      if (ret < 0) {
+        if (errno == EAGAIN) {
+          ret = waitForRWData(d_socket, false, timeout, 0);
+          if (ret < 0) {
             throw NetworkError("Waiting for data write");
-          if(!ret)
+          }
+          if (ret == 0) {
             throw NetworkError("Timeout writing data");
+          }
           continue;
         }
-        else
-          throw NetworkError("Writing data: "+stringerror());
+        throw NetworkError("Writing data: " + stringerror());
       }
-      if(!ret) {
+      if (ret == 0) {
         throw NetworkError("Did not fulfill TCP write due to EOF");
       }
 
-      ptr += static_cast<size_t>(ret);
+      ptr += static_cast<size_t>(ret); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
       bytes -= static_cast<size_t>(ret);
     }
   }
 
   //! reads one character from the socket
-  int getChar()
+  [[nodiscard]] int getChar() const
   {
-    char c;
+    char character{};
 
-    ssize_t res=::recv(d_socket,&c,1,0);
-    if(res)
-      return c;
+    ssize_t res = ::recv(d_socket, &character, 1, 0);
+    if (res == 0) {
+      return character;
+    }
     return -1;
   }
 
-  void getline(string &data)
+  void getline(string& data) const
   {
-    data="";
-    int c;
-    while((c=getChar())!=-1) {
-      data+=(char)c;
-      if(c=='\n')
+    data.clear();
+    while (true) {
+      int character = getChar();
+      if (character == -1) {
         break;
+      }
+      data += (char)character;
+      if (character == '\n') {
+        break;
+      }
     }
   }
 
   //! Reads a block of data from the socket to a string
-  void read(string &data)
+  void read(stringdata)
   {
     d_buffer.resize(s_buflen);
-    ssize_t res=::recv(d_socket, &d_buffer[0], s_buflen, 0);
-    if(res<0)
-      throw NetworkError("Reading from a socket: "+stringerror());
+    ssize_t res = ::recv(d_socket, d_buffer.data(), s_buflen, 0);
+    if (res < 0) {
+      throw NetworkError("Reading from a socket: " + stringerror());
+    }
     data.assign(d_buffer, 0, static_cast<size_t>(res));
   }
 
   //! Reads a block of data from the socket to a block of memory
-  size_t read(char *buffer, size_t bytes)
+  size_t read(char* buffer, size_t bytes) const
   {
-    ssize_t res=::recv(d_socket, buffer, bytes, 0);
-    if(res<0)
-      throw NetworkError("Reading from a socket: "+stringerror());
+    auto res = ::recv(d_socket, buffer, bytes, 0);
+    if (res < 0) {
+      throw NetworkError("Reading from a socket: " + stringerror());
+    }
     return static_cast<size_t>(res);
   }
 
   /** Read a bock of data from the socket to a block of memory,
-  *   waiting at most 'timeout' seconds for the data to become
-  *   available. Be aware that this does _NOT_ handle partial reads
-  *   for you.
-  */
-  ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
+   *   waiting at most 'timeout' seconds for the data to become
+   *   available. Be aware that this does _NOT_ handle partial reads
+   *   for you.
+   */
+  size_t readWithTimeout(char* buffer, size_t n, int timeout) const
   {
     int err = waitForRWData(d_socket, true, timeout, 0);
 
-    if(err == 0)
+    if (err == 0) {
       throw NetworkError("timeout reading");
-    if(err < 0)
-      throw NetworkError("nonblocking read failed: "+stringerror());
+    }
+    if (err < 0) {
+      throw NetworkError("nonblocking read failed: " + stringerror());
+    }
 
     return read(buffer, n);
   }
 
   //! Sets the socket to listen with a default listen backlog of 10 pending connections
-  void listen(unsigned int length=10)
+  void listen(int length = 10) const
   {
-    if(::listen(d_socket,length)<0)
-      throw NetworkError("Setting socket to listen: "+stringerror());
+    if (::listen(d_socket, length) < 0) {
+      throw NetworkError("Setting socket to listen: " + stringerror());
+    }
   }
 
   //! Returns the internal file descriptor of the socket
-  int getHandle() const
+  [[nodiscard]] int getHandle() const
   {
     return d_socket;
   }
@@ -397,7 +416,7 @@ public:
   }
 
 private:
-  static const size_t s_buflen{4096};
+  static constexpr size_t s_buflen{4096};
   std::string d_buffer;
   int d_socket;
 };
index 96c7433514de3bca2e5748c9e954379ece5c0c76..4fa00d2a29a1eee2d400c20c7382acbba44704c0 100644 (file)
@@ -87,17 +87,17 @@ namespace pdns {
     }
     typename std::aligned_storage_t<sizeof(atomic_t), CPU_LEVEL1_DCACHE_LINESIZE> counter;
   };
-
-  using stat_t = stat_t_trait<uint64_t>;
-  using stat32_t = stat_t_trait<uint32_t>;
-  using stat16_t = stat_t_trait<uint16_t>;
 }
 #else
 namespace pdns {
-  using stat_t = std::atomic<uint64_t>;
-  using stat32_t = std::atomic<uint32_t>;
-  using stat16_t = std::atomic<uint16_t>;
   template <class T>
   using stat_t_trait = std::atomic<T>;
 }
 #endif
+
+namespace pdns {
+  using stat_t = stat_t_trait<uint64_t>;
+  using stat32_t = stat_t_trait<uint32_t>;
+  using stat16_t = stat_t_trait<uint16_t>;
+  using stat_double_t = stat_t_trait<double>;
+}
index 84cdca32058089a3f6a380d0ca15f7c1cb9b4886..5c8df331111497d7177208b3ab23029035192f80 100644 (file)
@@ -177,9 +177,9 @@ int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& r
     }
 
     for (const auto& answer : mdp.d_answers) {
-      if (answer.first.d_place == 1 && answer.first.d_type == qtype) {
+      if (answer.d_place == 1 && answer.d_type == qtype) {
         DNSZoneRecord zrr;
-        zrr.dr = answer.first;
+        zrr.dr = answer;
         zrr.auth = true;
         ret.push_back(zrr);
       }
index cf82471ba84dfc36fde17bb78af544533769a952..59382083f7ee0e735b02f3cac0de2b4ccee37169 100644 (file)
@@ -7,10 +7,45 @@
 
 const bool TCPIOHandler::s_disableConnectForUnitTests = false;
 
+namespace {
+bool shouldDoVerboseLogging()
+{
+#ifdef DNSDIST
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+#elif defined(RECURSOR)
+  return false;
+#else
+  return true;
+#endif
+}
+}
+
 #ifdef HAVE_LIBSODIUM
 #include <sodium.h>
 #endif /* HAVE_LIBSODIUM */
 
+TLSCtx::tickets_key_added_hook TLSCtx::s_ticketsKeyAddedHook{nullptr};
+
+static std::vector<std::vector<uint8_t>> getALPNVector(TLSFrontend::ALPN alpn, bool client)
+{
+  if (alpn == TLSFrontend::ALPN::DoT) {
+    /* we want to set the ALPN to dot (RFC7858), if only to mitigate the ALPACA attack */
+    return std::vector<std::vector<uint8_t>>{{'d', 'o', 't'}};
+  }
+  if (alpn == TLSFrontend::ALPN::DoH) {
+    if (client) {
+      /* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */
+      return std::vector<std::vector<uint8_t>>{{'h', '2'}};
+    }
+    /* For server contexts, we want to set the ALPN for DoH (note that h2o sets it own ALPN values):
+       - HTTP/1.1 so that the OpenSSL callback ALPN accepts it, letting us later return a static response
+       - HTTP/2
+    */
+    return std::vector<std::vector<uint8_t>>{{'h', '2'},{'h', 't', 't', 'p', '/', '1', '.', '1'}};
+  }
+  return {};
+}
+
 #if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
 #ifdef HAVE_LIBSSL
 
@@ -71,17 +106,19 @@ private:
   std::unique_ptr<SSL_SESSION, void(*)(SSL_SESSION*)> d_sess;
 };
 
+class OpenSSLTLSIOCtx;
+
 class OpenSSLTLSConnection: public TLSConnection
 {
 public:
   /* server side connection */
-  OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<OpenSSLFrontendContext> feContext): d_feContext(std::move(feContext)), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(d_feContext->d_tlsCtx.get()), SSL_free)), d_timeout(timeout)
+  OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<const OpenSSLTLSIOCtx> tlsCtx, std::unique_ptr<SSL, void(*)(SSL*)>&& conn): d_tlsCtx(std::move(tlsCtx)), d_conn(std::move(conn)), d_timeout(timeout)
   {
     d_socket = socket;
 
     if (!d_conn) {
       vinfolog("Error creating TLS object");
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         ERR_print_errors_fp(stderr);
       }
       throw std::runtime_error("Error creating TLS object");
@@ -95,13 +132,13 @@ public:
   }
 
   /* client-side connection */
-  OpenSSLTLSConnection(const std::string& hostname, bool hostIsAddr, int socket, const struct timeval& timeout, std::shared_ptr<SSL_CTX>& tlsCtx): d_tlsCtx(tlsCtx), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(tlsCtx.get()), SSL_free)), d_hostname(hostname), d_timeout(timeout)
+  OpenSSLTLSConnection(std::string hostname, bool hostIsAddr, int socket, const struct timeval& timeout, std::shared_ptr<const OpenSSLTLSIOCtx> tlsCtx, std::unique_ptr<SSL, void(*)(SSL*)>&& conn): d_tlsCtx(std::move(tlsCtx)), d_conn(std::move(conn)), d_hostname(std::move(hostname)), d_timeout(timeout), d_isClient(true)
   {
     d_socket = socket;
 
     if (!d_conn) {
       vinfolog("Error creating TLS object");
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         ERR_print_errors_fp(stderr);
       }
       throw std::runtime_error("Error creating TLS object");
@@ -199,7 +236,7 @@ public:
     }
 #endif
     else {
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         throw std::runtime_error("Error while processing TLS connection: (" + std::to_string(error) + ") " + libssl_get_error_string());
       } else {
         throw std::runtime_error("Error while processing TLS connection: " + std::to_string(error));
@@ -282,7 +319,7 @@ public:
 
   IOState tryHandshake() override
   {
-    if (!d_feContext) {
+    if (isClient()) {
       /* In client mode, the handshake is initiated by the call to SSL_connect()
          done from connect()/tryConnect().
          In blocking mode it does not return before the handshake has been finished,
@@ -310,7 +347,7 @@ public:
 
   void doHandshake() override
   {
-    if (!d_feContext) {
+    if (isClient()) {
       /* we are a client, nothing to do, see the non-blocking version */
       return;
     }
@@ -331,7 +368,7 @@ public:
 
   IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) override
   {
-    if (!d_feContext && !d_connected) {
+    if (isClient() && !d_connected) {
       if (d_ktls) {
         /* work-around to get kTLS to be started, as we cannot do that until after the socket has been connected */
         SSL_set_fd(d_conn.get(), SSL_get_fd(d_conn.get()));
@@ -477,11 +514,6 @@ public:
 
     const unsigned char* alpn = nullptr;
     unsigned int alpnLen  = 0;
-#ifndef DISABLE_NPN
-#ifdef HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED
-    SSL_get0_next_proto_negotiated(d_conn.get(), &alpn, &alpnLen);
-#endif /* HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED */
-#endif /* DISABLE_NPN */
 #ifdef HAVE_SSL_GET0_ALPN_SELECTED
     if (alpn == nullptr) {
       SSL_get0_alpn_selected(d_conn.get(), &alpn, &alpnLen);
@@ -550,6 +582,11 @@ public:
     d_ktls = true;
   }
 
+  [[nodiscard]] bool isClient() const
+  {
+    return d_isClient;
+  }
+
   static void generateConnectionIndexIfNeeded()
   {
     auto init = s_initTLSConnIndex.lock();
@@ -575,31 +612,44 @@ private:
   static LockGuarded<bool> s_initTLSConnIndex;
   static int s_tlsConnIndex;
   std::vector<std::unique_ptr<TLSSession>> d_tlsSessions;
-  /* server context */
-  std::shared_ptr<OpenSSLFrontendContext> d_feContext;
-  /* client context */
-  std::shared_ptr<SSL_CTX> d_tlsCtx;
+  const std::shared_ptr<const OpenSSLTLSIOCtx> d_tlsCtx; // we need to hold a reference to this to make sure that the context exists for as long as the connection, even if a reload happens in the meantime
   std::unique_ptr<SSL, void(*)(SSL*)> d_conn;
-  std::string d_hostname;
-  struct timeval d_timeout;
+  const std::string d_hostname;
+  const timeval d_timeout;
   bool d_connected{false};
   bool d_ktls{false};
+  const bool d_isClient{false};
 };
 
 LockGuarded<bool> OpenSSLTLSConnection::s_initTLSConnIndex{false};
 int OpenSSLTLSConnection::s_tlsConnIndex{-1};
 
-class OpenSSLTLSIOCtx: public TLSCtx
+class OpenSSLTLSIOCtx: public TLSCtx, public std::enable_shared_from_this<OpenSSLTLSIOCtx>
 {
+  struct Private
+  {
+    explicit Private() = default;
+  };
+
 public:
+  static std::shared_ptr<OpenSSLTLSIOCtx> createServerSideContext(TLSFrontend& frontend)
+  {
+    return std::make_shared<OpenSSLTLSIOCtx>(frontend, Private());
+  }
+
+  static std::shared_ptr<OpenSSLTLSIOCtx> createClientSideContext(const TLSContextParameters& params)
+  {
+    return std::make_shared<OpenSSLTLSIOCtx>(params, Private());
+  }
+
   /* server side context */
-  OpenSSLTLSIOCtx(TLSFrontend& fe): d_feContext(std::make_shared<OpenSSLFrontendContext>(fe.d_addr, fe.d_tlsConfig))
+  OpenSSLTLSIOCtx(TLSFrontend& frontend, [[maybe_unused]] Private priv): d_alpnProtos(getALPNVector(frontend.d_alpn, false)), d_feContext(std::make_unique<OpenSSLFrontendContext>(frontend.d_addr, frontend.d_tlsConfig))
   {
     OpenSSLTLSConnection::generateConnectionIndexIfNeeded();
 
-    d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
+    d_ticketsKeyRotationDelay = frontend.d_tlsConfig.d_ticketsKeyRotationDelay;
 
-    if (fe.d_tlsConfig.d_enableTickets && fe.d_tlsConfig.d_numberOfTicketsKeys > 0) {
+    if (frontend.d_tlsConfig.d_enableTickets && frontend.d_tlsConfig.d_numberOfTicketsKeys > 0) {
       /* use our own ticket keys handler so we can rotate them */
 #if OPENSSL_VERSION_MAJOR >= 3
       SSL_CTX_set_tlsext_ticket_key_evp_cb(d_feContext->d_tlsCtx.get(), &OpenSSLTLSIOCtx::ticketKeyCb);
@@ -616,22 +666,24 @@ public:
     }
 #endif /* DISABLE_OCSP_STAPLING */
 
-    if (fe.d_tlsConfig.d_readAhead) {
+    if (frontend.d_tlsConfig.d_readAhead) {
       SSL_CTX_set_read_ahead(d_feContext->d_tlsCtx.get(), 1);
     }
 
-    libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &fe.d_tlsCounters);
+    libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &frontend.d_tlsCounters);
+
+    libssl_set_alpn_select_callback(d_feContext->d_tlsCtx.get(), alpnServerSelectCallback, this);
 
-    if (!fe.d_tlsConfig.d_keyLogFile.empty()) {
-      d_feContext->d_keyLogFile = libssl_set_key_log_file(d_feContext->d_tlsCtx, fe.d_tlsConfig.d_keyLogFile);
+    if (!frontend.d_tlsConfig.d_keyLogFile.empty()) {
+      d_feContext->d_keyLogFile = libssl_set_key_log_file(d_feContext->d_tlsCtx, frontend.d_tlsConfig.d_keyLogFile);
     }
 
     try {
-      if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
+      if (frontend.d_tlsConfig.d_ticketKeyFile.empty()) {
         handleTicketsKeyRotation(time(nullptr));
       }
       else {
-        OpenSSLTLSIOCtx::loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
+        OpenSSLTLSIOCtx::loadTicketsKeys(frontend.d_tlsConfig.d_ticketKeyFile);
       }
     }
     catch (const std::exception& e) {
@@ -640,7 +692,7 @@ public:
   }
 
   /* client side context */
-  OpenSSLTLSIOCtx(const TLSContextParameters& params)
+  OpenSSLTLSIOCtx(const TLSContextParameters& params, [[maybe_unused]] Private priv)
   {
     int sslOptions =
       SSL_OP_NO_SSLv2 |
@@ -724,6 +776,8 @@ public:
     SSL_CTX_set_session_cache_mode(d_tlsCtx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
     SSL_CTX_sess_set_new_cb(d_tlsCtx.get(), &OpenSSLTLSIOCtx::newTicketFromServerCb);
 
+    libssl_set_alpn_protos(d_tlsCtx.get(), getALPNVector(params.d_alpn, true));
+
 #ifdef SSL_MODE_RELEASE_BUFFERS
     if (params.d_releaseBuffers) {
       SSL_CTX_set_mode(d_tlsCtx.get(), SSL_MODE_RELEASE_BUFFERS);
@@ -731,6 +785,11 @@ public:
 #endif
   }
 
+  OpenSSLTLSIOCtx(const OpenSSLTLSIOCtx&) = delete;
+  OpenSSLTLSIOCtx(OpenSSLTLSIOCtx&&) = delete;
+  OpenSSLTLSIOCtx& operator=(const OpenSSLTLSIOCtx&) = delete;
+  OpenSSLTLSIOCtx& operator=(OpenSSLTLSIOCtx&&) = delete;
+
   ~OpenSSLTLSIOCtx() override
   {
     d_tlsCtx.reset();
@@ -788,16 +847,24 @@ public:
     return 1;
   }
 
+  SSL_CTX* getOpenSSLContext() const
+  {
+    if (d_feContext) {
+      return d_feContext->d_tlsCtx.get();
+    }
+    return d_tlsCtx.get();
+  }
+
   std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) override
   {
     handleTicketsKeyRotation(now);
 
-    return std::make_unique<OpenSSLTLSConnection>(socket, timeout, d_feContext);
+    return std::make_unique<OpenSSLTLSConnection>(socket, timeout, shared_from_this(), std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(getOpenSSLContext()), SSL_free));
   }
 
   std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) override
   {
-    auto conn = std::make_unique<OpenSSLTLSConnection>(host, hostIsAddr, socket, timeout, d_tlsCtx);
+    auto conn = std::make_unique<OpenSSLTLSConnection>(host, hostIsAddr, socket, timeout, shared_from_this(), std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(getOpenSSLContext()), SSL_free));
     if (d_ktls) {
       conn->enableKTLS();
     }
@@ -832,45 +899,13 @@ public:
     return "openssl";
   }
 
-  bool setALPNProtos(const std::vector<std::vector<uint8_t>>& protos) override
-  {
-    if (d_feContext && d_feContext->d_tlsCtx) {
-      d_alpnProtos = protos;
-      libssl_set_alpn_select_callback(d_feContext->d_tlsCtx.get(), alpnServerSelectCallback, this);
-      return true;
-    }
-    if (d_tlsCtx) {
-      return libssl_set_alpn_protos(d_tlsCtx.get(), protos);
-    }
-    return false;
-  }
-
-#ifndef DISABLE_NPN
-  bool setNextProtocolSelectCallback(bool(*cb)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen)) override
+  bool isServerContext() const
   {
-    d_nextProtocolSelectCallback = cb;
-    libssl_set_npn_select_callback(d_tlsCtx.get(), npnSelectCallback, this);
-    return true;
+    return d_feContext != nullptr;
   }
-#endif /* DISABLE_NPN */
 
 private:
-  /* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-#ifndef DISABLE_NPN
-  static int npnSelectCallback(SSL* /* s */, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
-  {
-    if (!arg) {
-      return SSL_TLSEXT_ERR_ALERT_WARNING;
-    }
-    OpenSSLTLSIOCtx* obj = reinterpret_cast<OpenSSLTLSIOCtx*>(arg);
-    if (obj->d_nextProtocolSelectCallback) {
-      return (*obj->d_nextProtocolSelectCallback)(out, outlen, in, inlen) ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_WARNING;
-    }
-
-    return SSL_TLSEXT_ERR_OK;
-  }
-#endif /* NPN */
-
+  /* called in a client context, if the client advertised more than one ALPN value and the server returned more than one as well, to select the one to use. */
   static int alpnServerSelectCallback(SSL*, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
   {
     if (!arg) {
@@ -903,10 +938,9 @@ private:
     return SSL_TLSEXT_ERR_NOACK;
   }
 
-  std::vector<std::vector<uint8_t>> d_alpnProtos; // store the supported ALPN protocols, so that the server can select based on what the client sent
-  std::shared_ptr<OpenSSLFrontendContext> d_feContext{nullptr};
+  const std::vector<std::vector<uint8_t>> d_alpnProtos; // store the supported ALPN protocols, so that the server can select based on what the client sent
   std::shared_ptr<SSL_CTX> d_tlsCtx{nullptr}; // client context, on a server-side the context is stored in d_feContext->d_tlsCtx
-  bool (*d_nextProtocolSelectCallback)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen){nullptr};
+  std::unique_ptr<OpenSSLFrontendContext> d_feContext{nullptr};
   bool d_ktls{false};
 };
 
@@ -987,6 +1021,16 @@ public:
       throw;
     }
   }
+  [[nodiscard]] std::string content() const
+  {
+    std::string result{};
+    if (d_key.data != nullptr && d_key.size > 0) {
+      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+      result.append(reinterpret_cast<const char*>(d_key.data), d_key.size);
+      safe_memory_lock(result.data(), result.size());
+    }
+    return result;
+  }
 
   ~GnuTLSTicketsKey()
   {
@@ -1559,7 +1603,7 @@ private:
   std::unique_ptr<gnutls_session_int, void(*)(gnutls_session_t)> d_conn;
   std::vector<std::unique_ptr<TLSSession>> d_tlsSessions;
   std::string d_host;
-  bool d_client{false};
+  const bool d_client{false};
   bool d_handshakeDone{false};
 };
 
@@ -1567,33 +1611,33 @@ class GnuTLSIOCtx: public TLSCtx
 {
 public:
   /* server side context */
-  GnuTLSIOCtx(TLSFrontend& fe): d_enableTickets(fe.d_tlsConfig.d_enableTickets)
+  GnuTLSIOCtx(TLSFrontend& frontend): d_protos(getALPNVector(frontend.d_alpn, false)), d_enableTickets(frontend.d_tlsConfig.d_enableTickets)
   {
     int rc = 0;
-    d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
+    d_ticketsKeyRotationDelay = frontend.d_tlsConfig.d_ticketsKeyRotationDelay;
 
     gnutls_certificate_credentials_t creds;
     rc = gnutls_certificate_allocate_credentials(&creds);
     if (rc != GNUTLS_E_SUCCESS) {
-      throw std::runtime_error("Error allocating credentials for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+      throw std::runtime_error("Error allocating credentials for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
     }
 
     d_creds = std::shared_ptr<gnutls_certificate_credentials_st>(creds, gnutls_certificate_free_credentials);
     creds = nullptr;
 
-    for (const auto& pair : fe.d_tlsConfig.d_certKeyPairs) {
+    for (const auto& pair : frontend.d_tlsConfig.d_certKeyPairs) {
       rc = gnutls_certificate_set_x509_key_file(d_creds.get(), pair.d_cert.c_str(), pair.d_key->c_str(), GNUTLS_X509_FMT_PEM);
       if (rc != GNUTLS_E_SUCCESS) {
-        throw std::runtime_error("Error loading certificate ('" + pair.d_cert + "') and key ('" + pair.d_key.value() + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+        throw std::runtime_error("Error loading certificate ('" + pair.d_cert + "') and key ('" + pair.d_key.value() + "') for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
       }
     }
 
 #ifndef DISABLE_OCSP_STAPLING
     size_t count = 0;
-    for (const auto& file : fe.d_tlsConfig.d_ocspFiles) {
+    for (const auto& file : frontend.d_tlsConfig.d_ocspFiles) {
       rc = gnutls_certificate_set_ocsp_status_request_file(d_creds.get(), file.c_str(), count);
       if (rc != GNUTLS_E_SUCCESS) {
-        warnlog("Error loading OCSP response from file '%s' for certificate ('%s') and key ('%s') for TLS context on %s: %s", file, fe.d_tlsConfig.d_certKeyPairs.at(count).d_cert, fe.d_tlsConfig.d_certKeyPairs.at(count).d_key.value(), fe.d_addr.toStringWithPort(), gnutls_strerror(rc));
+        warnlog("Error loading OCSP response from file '%s' for certificate ('%s') and key ('%s') for TLS context on %s: %s", file, frontend.d_tlsConfig.d_certKeyPairs.at(count).d_cert, frontend.d_tlsConfig.d_certKeyPairs.at(count).d_key.value(), frontend.d_addr.toStringWithPort(), gnutls_strerror(rc));
       }
       ++count;
     }
@@ -1602,30 +1646,30 @@ public:
 #if GNUTLS_VERSION_NUMBER >= 0x030600
     rc = gnutls_certificate_set_known_dh_params(d_creds.get(), GNUTLS_SEC_PARAM_HIGH);
     if (rc != GNUTLS_E_SUCCESS) {
-      throw std::runtime_error("Error setting DH params for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+      throw std::runtime_error("Error setting DH params for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
     }
 #endif
 
-    rc = gnutls_priority_init(&d_priorityCache, fe.d_tlsConfig.d_ciphers.empty() ? "NORMAL" : fe.d_tlsConfig.d_ciphers.c_str(), nullptr);
+    rc = gnutls_priority_init(&d_priorityCache, frontend.d_tlsConfig.d_ciphers.empty() ? "NORMAL" : frontend.d_tlsConfig.d_ciphers.c_str(), nullptr);
     if (rc != GNUTLS_E_SUCCESS) {
-      throw std::runtime_error("Error setting up TLS cipher preferences to '" + fe.d_tlsConfig.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + fe.d_addr.toStringWithPort());
+      throw std::runtime_error("Error setting up TLS cipher preferences to '" + frontend.d_tlsConfig.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + frontend.d_addr.toStringWithPort());
     }
 
     try {
-      if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
+      if (frontend.d_tlsConfig.d_ticketKeyFile.empty()) {
         handleTicketsKeyRotation(time(nullptr));
       }
       else {
-        GnuTLSIOCtx::loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
+        GnuTLSIOCtx::loadTicketsKeys(frontend.d_tlsConfig.d_ticketKeyFile);
       }
     }
     catch(const std::runtime_error& e) {
-      throw std::runtime_error("Error generating tickets key for TLS context on " + fe.d_addr.toStringWithPort() + ": " + e.what());
+      throw std::runtime_error("Error generating tickets key for TLS context on " + frontend.d_addr.toStringWithPort() + ": " + e.what());
     }
   }
 
   /* client side context */
-  GnuTLSIOCtx(const TLSContextParameters& params): d_contextParameters(std::make_unique<TLSContextParameters>(params)), d_enableTickets(true), d_validateCerts(params.d_validateCertificates)
+  GnuTLSIOCtx(const TLSContextParameters& params): d_protos(getALPNVector(params.d_alpn, true)), d_contextParameters(std::make_unique<TLSContextParameters>(params)), d_validateCerts(params.d_validateCertificates)
   {
     int rc = 0;
 
@@ -1730,14 +1774,12 @@ public:
     return connection;
   }
 
-  void rotateTicketsKey(time_t now) override
+  void addTicketsKey(time_t now, std::shared_ptr<GnuTLSTicketsKey>&& newKey)
   {
     if (!d_enableTickets) {
       return;
     }
 
-    auto newKey = std::make_shared<GnuTLSTicketsKey>();
-
     {
       *(d_ticketsKey.write_lock()) = std::move(newKey);
     }
@@ -1745,8 +1787,23 @@ public:
     if (d_ticketsKeyRotationDelay > 0) {
       d_ticketsKeyNextRotation = now + d_ticketsKeyRotationDelay;
     }
+
+    if (TLSCtx::hasTicketsKeyAddedHook()) {
+      auto ticketsKey = *(d_ticketsKey.read_lock());
+      auto content = ticketsKey->content();
+      TLSCtx::getTicketsKeyAddedHook()(content);
+      safe_memory_release(content.data(), content.size());
+    }
   }
+  void rotateTicketsKey(time_t now) override
+  {
+    if (!d_enableTickets) {
+      return;
+    }
 
+    auto newKey = std::make_shared<GnuTLSTicketsKey>();
+    addTicketsKey(now, std::move(newKey));
+  }
   void loadTicketsKeys(const std::string& file) final
   {
     if (!d_enableTickets) {
@@ -1754,13 +1811,7 @@ public:
     }
 
     auto newKey = std::make_shared<GnuTLSTicketsKey>(file);
-    {
-      *(d_ticketsKey.write_lock()) = std::move(newKey);
-    }
-
-    if (d_ticketsKeyRotationDelay > 0) {
-      d_ticketsKeyNextRotation = time(nullptr) + d_ticketsKeyRotationDelay;
-    }
+    addTicketsKey(time(nullptr), std::move(newKey));
   }
 
   size_t getTicketsKeysCount() override
@@ -1773,21 +1824,11 @@ public:
     return "gnutls";
   }
 
-  bool setALPNProtos(const std::vector<std::vector<uint8_t>>& protos) override
-  {
-#ifdef HAVE_GNUTLS_ALPN_SET_PROTOCOLS
-    d_protos = protos;
-    return true;
-#else
-    return false;
-#endif
-  }
-
 private:
   /* client context parameters */
-  std::unique_ptr<TLSContextParameters> d_contextParameters{nullptr};
   std::shared_ptr<gnutls_certificate_credentials_st> d_creds;
-  std::vector<std::vector<uint8_t>> d_protos;
+  const std::vector<std::vector<uint8_t>> d_protos;
+  std::unique_ptr<TLSContextParameters> d_contextParameters{nullptr};
   gnutls_priority_t d_priorityCache{nullptr};
   SharedLockGuarded<std::shared_ptr<GnuTLSTicketsKey>> d_ticketsKey{nullptr};
   bool d_enableTickets{true};
@@ -1798,34 +1839,6 @@ private:
 
 #endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
 
-bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
-  if (ctx == nullptr) {
-    return false;
-  }
-  /* we want to set the ALPN to dot (RFC7858), if only to mitigate the ALPACA attack */
-  const std::vector<std::vector<uint8_t>> dotAlpns = {{'d', 'o', 't'}};
-  ctx->setALPNProtos(dotAlpns);
-  return true;
-}
-
-bool setupDoHProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
-{
-  if (ctx == nullptr) {
-    return false;
-  }
-  /* This code is only called for incoming/server TLS contexts (not outgoing/client),
-     and h2o sets it own ALPN values.
-     We want to set the ALPN for DoH:
-     - HTTP/1.1 so that the OpenSSL callback ALPN accepts it, letting us later return a static response
-     - HTTP/2
-  */
-  const std::vector<std::vector<uint8_t>> dohAlpns{{'h', '2'},{'h', 't', 't', 'p', '/', '1', '.', '1'}};
-  ctx->setALPNProtos(dohAlpns);
-
-  return true;
-}
-
 bool TLSFrontend::setupTLS()
 {
 #if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
@@ -1838,13 +1851,13 @@ bool TLSFrontend::setupTLS()
 #endif /* HAVE_GNUTLS */
 #if defined(HAVE_LIBSSL)
   if (d_provider == "openssl") {
-    newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+    newCtx = OpenSSLTLSIOCtx::createServerSideContext(*this);
   }
 #endif /* HAVE_LIBSSL */
 
   if (!newCtx) {
 #if defined(HAVE_LIBSSL)
-    newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+    newCtx = OpenSSLTLSIOCtx::createServerSideContext(*this);
 #elif defined(HAVE_GNUTLS)
     newCtx = std::make_shared<GnuTLSIOCtx>(*this);
 #else
@@ -1852,13 +1865,6 @@ bool TLSFrontend::setupTLS()
 #endif
   }
 
-  if (d_alpn == ALPN::DoT) {
-    setupDoTProtocolNegotiation(newCtx);
-  }
-  else if (d_alpn == ALPN::DoH) {
-    setupDoHProtocolNegotiation(newCtx);
-  }
-
   std::atomic_store_explicit(&d_ctx, std::move(newCtx), std::memory_order_release);
 #endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
   return true;
@@ -1876,13 +1882,13 @@ std::shared_ptr<TLSCtx> getTLSContext([[maybe_unused]] const TLSContextParameter
 #endif /* HAVE_GNUTLS */
 #if defined(HAVE_LIBSSL)
     if (params.d_provider == "openssl") {
-      return std::make_shared<OpenSSLTLSIOCtx>(params);
+      return OpenSSLTLSIOCtx::createClientSideContext(params);
     }
 #endif /* HAVE_LIBSSL */
   }
 
 #if defined(HAVE_LIBSSL)
-  return std::make_shared<OpenSSLTLSIOCtx>(params);
+  return OpenSSLTLSIOCtx::createClientSideContext(params);
 #elif defined(HAVE_GNUTLS)
   return std::make_shared<GnuTLSIOCtx>(params);
 #else
index 058d10443b713840304a24e37b87c05f9f5004e7..f24735cc88d7b25362d656654f5a73288845b7a3 100644 (file)
@@ -81,7 +81,6 @@ public:
   {
     throw std::runtime_error("This TLS backend does not have the capability to load a tickets key from a file");
   }
-
   void handleTicketsKeyRotation(time_t now)
   {
     if (d_ticketsKeyRotationDelay != 0 && now > d_ticketsKeyNextRotation) {
@@ -112,22 +111,27 @@ public:
   virtual size_t getTicketsKeysCount() = 0;
   virtual std::string getName() const = 0;
 
-  /* set the advertised ALPN protocols, in client or server context */
-  virtual bool setALPNProtos(const std::vector<std::vector<uint8_t>>& /* protos */)
+  using tickets_key_added_hook = std::function<void(const std::string& key)>;
+
+  static void setTicketsKeyAddedHook(const tickets_key_added_hook& hook)
   {
-    return false;
+    TLSCtx::s_ticketsKeyAddedHook = hook;
   }
-
-  /* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
-  virtual bool setNextProtocolSelectCallback(bool(*)(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen))
+  static const tickets_key_added_hook& getTicketsKeyAddedHook()
   {
-    return false;
+    return TLSCtx::s_ticketsKeyAddedHook;
+  }
+  static bool hasTicketsKeyAddedHook()
+  {
+    return TLSCtx::s_ticketsKeyAddedHook != nullptr;
   }
-
 protected:
   std::atomic_flag d_rotatingTicketsKey;
   std::atomic<time_t> d_ticketsKeyNextRotation{0};
   time_t d_ticketsKeyRotationDelay{0};
+
+private:
+  static tickets_key_added_hook s_ticketsKeyAddedHook;
 };
 
 class TLSFrontend
@@ -550,7 +554,7 @@ public:
     return d_conn->getAsyncFDs();
   }
 
-  const static bool s_disableConnectForUnitTests;
+  static const bool s_disableConnectForUnitTests;
 
 private:
   std::unique_ptr<TLSConnection> d_conn{nullptr};
@@ -567,6 +571,7 @@ struct TLSContextParameters
   std::string d_ciphers;
   std::string d_ciphers13;
   std::string d_caStore;
+  TLSFrontend::ALPN d_alpn{TLSFrontend::ALPN::Unset};
   bool d_validateCertificates{true};
   bool d_releaseBuffers{true};
   bool d_enableRenegotiation{false};
index e290571458f7338fd17a3fc75bb0a360572f9c77..8dfa9573158846c888f277b22611fe236c7d2b6a 100644 (file)
@@ -1189,10 +1189,10 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
   uint32_t serial = 0;
   MOADNSParser mdp(false, q->getString());
   for(const auto & answer : mdp.d_answers) {
-    const DNSRecord *rr = &answer.first;
-    if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
+    const DNSRecord *dnsRecord = &answer;
+    if (dnsRecord->d_type == QType::SOA && dnsRecord->d_place == DNSResourceRecord::AUTHORITY) {
       vector<string>parts;
-      stringtok(parts, rr->getContent()->getZoneRepresentation());
+      stringtok(parts, dnsRecord->getContent()->getZoneRepresentation());
       if (parts.size() >= 3) {
         try {
           pdns::checked_stoi_into(serial, parts[2]);
@@ -1209,8 +1209,8 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
         sendPacket(outpacket,outsock);
         return 0;
       }
-    } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
-      g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(rr->d_type).toString()<<endl;
+    } else if (dnsRecord->d_type != QType::TSIG && dnsRecord->d_type != QType::OPT) {
+      g_log<<Logger::Warning<<logPrefix<<"additional records in IXFR query, type: "<<QType(dnsRecord->d_type).toString()<<endl;
       outpacket->setRcode(RCode::FormErr);
       sendPacket(outpacket,outsock);
       return 0;
index 4f1dc4bdb49640fcf8c3203c121197a629219fab..1d1273de73fe30c9ce94b32154cd0354dfd7fb38 100644 (file)
@@ -6,7 +6,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-#include <stdlib.h>
+#include <cstdlib>
 #include <unistd.h>
 #include <boost/test/unit_test.hpp>
 #include "distributor.hh"
@@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(test_distributor_basic) {
 
 struct BackendSlow
 {
-  std::unique_ptr<DNSPacket> question(Question&)
+  std::unique_ptr<DNSPacket> question([[maybe_unused]] Question& query)
   {
     if (d_shouldSleep) {
       /* only sleep once per distributor thread, otherwise
@@ -80,10 +80,10 @@ private:
   bool d_shouldSleep{true};
 };
 
-static std::atomic<int> g_receivedAnswers1;
+static std::atomic<size_t> s_receivedAnswers;
 static void report1(std::unique_ptr<DNSPacket>& /* A */, int /* B */)
 {
-  g_receivedAnswers1++;
+  s_receivedAnswers++;
 }
 
 BOOST_AUTO_TEST_CASE(test_distributor_queue) {
@@ -93,17 +93,31 @@ BOOST_AUTO_TEST_CASE(test_distributor_queue) {
   S.declare("servfail-packets","Number of times a server-failed packet was sent out");
   S.declare("timedout-packets", "timedout-packets");
 
-  auto d=Distributor<DNSPacket, Question, BackendSlow>::Create(2);
+  s_receivedAnswers.store(0);
+  auto* distributor = Distributor<DNSPacket, Question, BackendSlow>::Create(2);
 
+  size_t queued = 0;
   BOOST_CHECK_EXCEPTION( {
-    int n;
     // bound should be higher than max-queue-length
-    for(n=0; n < 2000; ++n)  {
-      Question q;
-      q.d_dt.set();
-      d->question(q, report1);
+    const size_t bound = 2000;
+    for (size_t idx = 0; idx < bound; ++idx)  {
+      Question query;
+      query.d_dt.set();
+      ++queued;
+      distributor->question(query, report1);
     }
     }, DistributorFatal, [](DistributorFatal) { return true; });
+
+  BOOST_CHECK_GT(queued, 1000U);
+
+  // now we want to make sure that all queued queries have been processed
+  // otherwise LeakSanitizer will report a leak, but we are only willing to
+  // wait up to 3 seconds (3000 milliseconds)
+  size_t remainingMs = 3000;
+  while (s_receivedAnswers.load() < queued && remainingMs > 0) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    remainingMs -= 10;
+  }
 };
 
 struct BackendDies
index c790b89a9134ce084a119f363fa6ee9f557f3f19..48b8c502558780e292f79572eb292acb8588be3d 100644 (file)
@@ -701,7 +701,7 @@ BOOST_AUTO_TEST_CASE(test_nsec3_records_types) {
 
     MOADNSParser parser(false, reinterpret_cast<const char*>(packet.data()), packet.size());
     BOOST_REQUIRE_EQUAL(parser.d_answers.size(), 1U);
-    const auto& record = parser.d_answers.at(0).first;
+    const auto& record = parser.d_answers.at(0);
     BOOST_REQUIRE(record.d_type == QType::NSEC3);
     BOOST_REQUIRE(record.d_class == QClass::IN);
     auto content = getRR<NSEC3RecordContent>(record);
index 3ca40e462543f99f2a4f318b9d3cbfda61a2c6b1..71a42ada8aafc34dbf3c056f8a82a62e69c914d1 100644 (file)
@@ -13,38 +13,37 @@ using std::string;
 struct TestObject
 {
   string name;
-  uint64_t number;
+  uint64_t number{0};
 };
 
-static GlobalStateHolder<TestObject> g_to; 
-std::atomic<bool> g_failed;
+static GlobalStateHolder<TestObject> s_to;
+static std::atomic<bool> s_failed;
 
 BOOST_AUTO_TEST_SUITE(test_sholder_hh)
 
-void treader()
+static void treader()
 {
-  auto local = g_to.getLocal();
-  for(int n=0; n < 10000000; ++n) {
-    auto g = *local;
-    if(g.name != std::to_string(g.number)) {
-      g_failed=1;
+  auto local = s_to.getLocal();
+  for (uint64_t counter = 0; counter < 10000000U; ++counter) {
+    auto copy = *local;
+    if (copy.name != std::to_string(copy.number)) {
+      s_failed.store(true);
       break;
     }
   }
 }
 
-BOOST_AUTO_TEST_CASE(test_sholder) {
-  g_to.setState({"1", 1});
+BOOST_AUTO_TEST_CASE(test_sholder)
+{
+  s_to.setState({"1", 1});
 
-  std::thread t1(treader);
-  for(unsigned int n=0; n < 1000000; ++n) {
-    g_to.setState({std::to_string(n), n});
-    g_to.modify([n](TestObject& to) { to.number = 2*n; to.name=std::to_string(to.number);} );
+  std::thread thread1(treader);
+  for (uint64_t counter = 0; counter < 1000000U; ++counter) {
+    s_to.setState({std::to_string(counter), counter});
+    s_to.modify([counter](TestObject& toValue) { toValue.number = 2*counter; toValue.name = std::to_string(toValue.number); });
   }
-  t1.join();
-  BOOST_CHECK_EQUAL(g_failed, 0);
+  thread1.join();
+  BOOST_CHECK_EQUAL(s_failed, 0);
 }
 
-
 BOOST_AUTO_TEST_SUITE_END()
-
index 08c90828dea95fc74d4b6700d92ca1fbbd222e44..55e92936d01da050c55c96e7a2bd4836dfe55de7 100644 (file)
@@ -82,17 +82,17 @@ static void checkTSIG(const DNSName& tsigName, const DNSName& tsigAlgo, const st
   TSIGRecordContent trc;
 
   for(const auto& answer: mdp.d_answers) {
-    if(answer.first.d_type == QType::TSIG) {
-      BOOST_CHECK_EQUAL(answer.first.d_place, DNSResourceRecord::ADDITIONAL);
-      BOOST_CHECK_EQUAL(answer.first.d_class, QClass::ANY);
-      BOOST_CHECK_EQUAL(answer.first.d_ttl, 0U);
+    if(answer.d_type == QType::TSIG) {
+      BOOST_CHECK_EQUAL(answer.d_place, DNSResourceRecord::ADDITIONAL);
+      BOOST_CHECK_EQUAL(answer.d_class, QClass::ANY);
+      BOOST_CHECK_EQUAL(answer.d_ttl, 0U);
       BOOST_CHECK_EQUAL(tsigFound, false);
 
-      auto rectrc = getRR<TSIGRecordContent>(answer.first);
+      auto rectrc = getRR<TSIGRecordContent>(answer);
       if (rectrc) {
         trc = *rectrc;
         theirMac = rectrc->d_mac;
-        keyName = answer.first.d_name;
+        keyName = answer.d_name;
         tsigFound = true;
       }
     }
index ef4f16a014e7b012ebf2024a4e27bcbc3b188f24..e4838514b52e1d267ab48c75525edb9710ec0f97 100644 (file)
@@ -34,6 +34,7 @@ static bool init_unit_test()
 // entry point:
 int main(int argc, char* argv[])
 {
+  setenv("BOOST_TEST_RANDOM", "1", 1); // NOLINT(concurrency-mt-unsafe)
   S.d_allowRedeclare = true;
   return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
 }
index b5300179751730f8d4bfbc2e6a44b2b2395eaf81..603a69b5d171e0818a849e6695ed3f413a2ea2b0 100644 (file)
@@ -22,13 +22,13 @@ bool TSIGTCPVerifier::check(const string& data, const MOADNSParser& mdp)
   }
 
   for(const auto& answer :  mdp.d_answers) {
-    if (answer.first.d_type == QType::SOA) {
+    if (answer.d_type == QType::SOA) {
       // A SOA is either the first or the last record. We need to check TSIG if that's the case.
       checkTSIG = true;
     }
 
-    if(answer.first.d_type == QType::TSIG) {
-      auto trc = getRR<TSIGRecordContent>(answer.first);
+    if(answer.d_type == QType::TSIG) {
+      auto trc = getRR<TSIGRecordContent>(answer);
       if(trc) {
         theirMac = trc->d_mac;
         d_trc.d_time = trc->d_time;
index 79f2b7e47ec678d1f090fc14161ebcdb65f0a96a..a0e986115a56fd18b059178df487eed8da03f18b 100644 (file)
@@ -801,6 +801,20 @@ bool UeberBackend::get(DNSZoneRecord& resourceRecord)
   return false;
 }
 
+void UeberBackend::lookupEnd()
+{
+  if (!d_negcached && !d_cached) {
+    DNSZoneRecord zoneRecord;
+    while (d_handle.get(zoneRecord)) {
+      // Read all answers so the backends will close any database handles they might have allocated.
+      // One day this could be optimized.
+    }
+  }
+
+  d_answers.clear();
+  d_cached = d_negcached = false;
+}
+
 // TSIG
 //
 bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
index be5859c9d47f2aafb26324fa03deaddb7fdde2af..0565abfaea0b2e147d92c9e91b63539497493607 100644 (file)
@@ -94,12 +94,15 @@ public:
   };
 
   void lookup(const QType& qtype, const DNSName& qname, int zoneId, DNSPacket* pkt_p = nullptr);
+  /** Read a single record from a lookup(...) result. */
+  bool get(DNSZoneRecord& resourceRecord);
+  /** Close state created by lookup(...). */
+  void lookupEnd();
 
   /** Determines if we are authoritative for a zone, and at what level */
   bool getAuth(const DNSName& target, const QType& qtype, SOAData* soaData, bool cachedOk = true);
   /** Load SOA info from backends, ignoring the cache.*/
   bool getSOAUncached(const DNSName& domain, SOAData& soaData);
-  bool get(DNSZoneRecord& resourceRecord);
   void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled);
 
   void getUnfreshSecondaryInfos(vector<DomainInfo>* domains);
index c59e0a0d0daae040c81bbfbb29357017690e5814..301daff0bb1ee1e9390cee1708c8e6e7eb7bf031 100644 (file)
@@ -30,6 +30,7 @@
 #endif /* BOOST_PENDING_INTEGER_LOG2_HPP */
 #endif /* BOOST_VERSION */
 
+#include <boost/random/mersenne_twister.hpp>
 #include <boost/uuid/uuid_generators.hpp>
 
 // The default of:
index 7f608572b30231e57ca5e48701623249bc22b317..9e7b8bc6d1e0bbdf8b951276aea14484070bf68f 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#ifdef HAVE_CONFIG_H
+
 #include "config.h"
-#endif
-#include "logger.hh"
 #include "version.hh"
+#include "namespaces.hh"
+
+#ifdef PDNS_MODULES
 #include "dnsbackend.hh"
+#endif
 
+#include <sstream>
 #include <boost/algorithm/string/join.hpp>
 
 static ProductType productType;
@@ -33,16 +36,17 @@ static ProductType productType;
 string compilerVersion()
 {
 #if defined(__clang__)
-  return string("clang " __clang_version__ );
+  return "clang " __clang_version__;
 #elif defined(__GNUC__)
-  return string("gcc " __VERSION__ );
-#else  // add other compilers here
-  return string("Unknown compiler");
+  return "gcc " __VERSION__;
+#else // add other compilers here
+  return "Unknown compiler";
 #endif
 }
 
 // Human-readable product name
-string productName() {
+string productName()
+{
   switch (productType) {
   case ProductAuthoritative:
     return "PowerDNS Authoritative Server";
@@ -58,7 +62,8 @@ string getPDNSVersion()
 }
 
 // REST API product type
-string productTypeApiType() {
+string productTypeApiType()
+{
   switch (productType) {
   case ProductAuthoritative:
     return "authoritative";
@@ -68,120 +73,136 @@ string productTypeApiType() {
   return "unknown";
 }
 
-void showProductVersion()
+vector<string> getProductVersionLines()
+{
+  vector<string> ret;
+  std::istringstream istr(getProductVersion());
+  for (string line; std::getline(istr, line);) {
+    ret.emplace_back(line);
+  }
+  return ret;
+}
+
+string getProductVersion()
 {
-  g_log<<Logger::Warning<<productName()<<" "<< VERSION << " (C) "
-    "PowerDNS.COM BV" << endl;
-  g_log<<Logger::Warning<<"Using "<<(sizeof(unsigned long)*8)<<"-bits mode. "
-    "Built using " << compilerVersion()
+  ostringstream ret;
+  ret << productName() << " " << VERSION << " (C) "
+                                            "PowerDNS.COM BV"
+      << endl;
+  ret << "Using " << (sizeof(unsigned long) * 8) << "-bits mode. "
+                                                    "Built using "
+      << compilerVersion()
 #ifndef REPRODUCIBLE
-    <<" on " __DATE__ " " __TIME__ " by " BUILD_HOST
-#endif
-    <<"."<< endl;
-  g_log<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
-    "This is free software, and you are welcome to redistribute it "
-    "according to the terms of the GPL version 2." << endl;
+      << " on " __DATE__ " " __TIME__ " by " BUILD_HOST
+#endif
+      << "." << endl;
+  ret << "PowerDNS comes with ABSOLUTELY NO WARRANTY. "
+         "This is free software, and you are welcome to redistribute it "
+         "according to the terms of the GPL version 2."
+      << endl;
+  return ret.str();
 }
 
-void showBuildConfiguration()
+string getBuildConfiguration()
 {
-  g_log<<Logger::Warning<<"Features: "<<
+  ostringstream ret;
+  ret << "Features:"
 #ifdef HAVE_LIBDECAF
-    "decaf " <<
-#endif
-#ifdef HAVE_BOOST_CONTEXT
-    "fcontext " <<
+      << " decaf"
 #endif
 #ifdef HAVE_LIBCRYPTO_ECDSA
-    "libcrypto-ecdsa " <<
+      << " libcrypto-ecdsa"
 #endif
 #ifdef HAVE_LIBCRYPTO_ED25519
-    "libcrypto-ed25519 " <<
+      << " libcrypto-ed25519"
 #endif
 #ifdef HAVE_LIBCRYPTO_ED448
-    "libcrypto-ed448 " <<
+      << " libcrypto-ed448"
 #endif
 #ifdef HAVE_LIBCRYPTO_EDDSA
-    "libcrypto-eddsa " <<
+      << " libcrypto-eddsa"
 #endif
 #ifdef HAVE_LIBDL
-    "libdl " <<
+      << " libdl"
 #endif
 #ifdef HAVE_GEOIP
-    "libgeoip " <<
+      << " libgeoip"
 #endif
 #ifdef HAVE_MMDB
-    "libmaxminddb " <<
+      << " libmaxminddb"
 #endif
 #ifdef HAVE_LUA
-    "lua " <<
+      << " lua"
 #endif
 #ifdef HAVE_LUA_RECORDS
-    "lua-records " <<
+      << " lua-records"
 #endif
 #ifdef NOD_ENABLED
-    "nod " <<
+      << " nod"
 #endif
 #ifdef HAVE_P11KIT1
-    "PKCS#11 " <<
+      << " PKCS#11"
 #endif
-"protobuf " <<
+      << " protobuf"
 #ifdef HAVE_FSTRM
-"dnstap-framestream " <<
+      << " dnstap-framestream"
 #endif
 #ifdef REMOTEBACKEND_ZEROMQ
-    "remotebackend-zeromq " <<
+      << " remotebackend-zeromq"
 #endif
 #ifdef HAVE_NET_SNMP
-    "snmp " <<
+      << " snmp"
 #endif
 #ifdef HAVE_LIBSODIUM
-    "sodium " <<
+      << " sodium"
 #endif
 #ifdef HAVE_LIBCURL
-    "curl " <<
+      << " curl"
 #endif
 #ifdef HAVE_DNS_OVER_TLS
-    "DoT " <<
+      << " DoT"
 #endif
 #ifdef HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT
-    "scrypt " <<
+      << " scrypt"
 #endif
 #ifdef ENABLE_GSS_TSIG
-    "gss-tsig " <<
+      << " gss-tsig"
 #endif
 #ifdef VERBOSELOG
-    "verboselog" <<
+      << " verboselog"
 #endif
-    endl;
+      << endl;
 #ifdef PDNS_MODULES
   // Auth only
-  g_log << Logger::Warning << "Built-in modules: " << PDNS_MODULES << endl;
+  ret << "Built-in modules: " << PDNS_MODULES << endl;
   const auto& modules = BackendMakers().getModules();
-  g_log << Logger::Warning << "Loaded modules: " << boost::join(modules, " ") << endl;
+  ret << "Loaded modules: " << boost::join(modules, " ") << endl;
 #endif
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
 #ifdef PDNS_CONFIG_ARGS
 #define double_escape(s) #s
 #define escape_quotes(s) double_escape(s)
-  g_log<<Logger::Warning<<"Configured with: "<<escape_quotes(PDNS_CONFIG_ARGS)<<endl;
+  // NOLINTEND(cppcoreguidelines-macro-usage)
+  ret << "Configured with: " << escape_quotes(PDNS_CONFIG_ARGS) << endl;
 #undef escape_quotes
 #undef double_escape
 #endif
+  return ret.str();
 }
 
 string fullVersionString()
 {
-  ostringstream s;
-  s<<productName()<<" " VERSION;
+  ostringstream ret;
+  ret << productName() << " " VERSION;
 #ifndef REPRODUCIBLE
-  s<<" (built " __DATE__ " " __TIME__ " by " BUILD_HOST ")";
+  ret << " (built " __DATE__ " " __TIME__ " by " BUILD_HOST ")";
 #endif
-  return s.str();
+  return ret.str();
 }
 
-void versionSetProduct(ProductType pt)
+void versionSetProduct(ProductType productType_)
 {
-  productType = pt;
+  productType = productType_;
 }
 
 ProductType versionGetProduct()
index 66944da9153a509bd97fc60bfb45d8a40820fe39..c0b63c0a5d1bbc0df789412b43af697141515e7f 100644 (file)
 #pragma once
 #include "namespaces.hh"
 
-enum ProductType { ProductAuthoritative, ProductRecursor };
+enum ProductType
+{
+  ProductAuthoritative,
+  ProductRecursor
+};
 
-string compilerVersion();
-void showProductVersion();
-void showBuildConfiguration();
-string fullVersionString();
-string getPDNSVersion();
-string productName();
-string productTypeApiType();
-void versionSetProduct(ProductType pt);
-ProductType versionGetProduct();
+[[nodiscard]] std::string compilerVersion();
+[[nodiscard]] std::vector<std::string> getProductVersionLines();
+[[nodiscard]] std::string getProductVersion();
+[[nodiscard]] std::string getBuildConfiguration();
+[[nodiscard]] std::string fullVersionString();
+[[nodiscard]] std::string getPDNSVersion();
+[[nodiscard]] std::string productName();
+[[nodiscard]] std::string productTypeApiType();
+void versionSetProduct(ProductType productType_);
+[[nodiscard]] ProductType versionGetProduct();
index c3c8c898b3fea6787469a06701f72671eaba6ec2..b6be93019c1c119e87096156d8c740b0acf5c963 100644 (file)
@@ -33,21 +33,39 @@ public:
     view(data_, size_)
   {
   }
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
+  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
   UnsignedCharView(const unsigned char* data_, size_t size_) :
     view(reinterpret_cast<const char*>(data_), size_)
   {
   }
-  const unsigned char& at(std::string_view::size_type pos) const
+  using size_type = std::string_view::size_type;
+
+  [[nodiscard]] const unsigned char& at(size_type pos) const
   {
     return reinterpret_cast<const unsigned char&>(view.at(pos));
   }
 
-  size_t size() const
+  [[nodiscard]] const unsigned char& operator[](size_type pos) const
+  {
+    return reinterpret_cast<const unsigned char&>(view[pos]);
+  }
+
+  [[nodiscard]] const unsigned char* data() const
+  {
+    return reinterpret_cast<const unsigned char*>(view.data());
+  }
+  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
+
+  [[nodiscard]] size_t size() const
   {
     return view.size();
   }
 
+  [[nodiscard]] size_t length() const
+  {
+    return view.length();
+  }
+
 private:
   std::string_view view;
 };
index ec4b09f5f94a37eb8d61c1c159f79cfe05de1aa1..58fb65c0ff1651ceea224a20e9a90c498044fab6 100644 (file)
@@ -301,12 +301,12 @@ void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp) const
     catch(PDNSException &e) {
       SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Exception: " << e.reason << endl,
            log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException")));
-      throw HttpInternalServerErrorException();
+      throw HttpInternalServerErrorException(e.reason);
     }
     catch(std::exception &e) {
       SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": STL Exception: " << e.what() << endl,
            log->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception")));
-      throw HttpInternalServerErrorException();
+      throw HttpInternalServerErrorException(e.what());
     }
     catch(...) {
       SLOG(g_log<<Logger::Error<<req.logprefix<<"HTTP ISE for \""<< req.url.path << "\": Unknown Exception" << endl,
@@ -520,16 +520,15 @@ void WebServer::serveConnection(const std::shared_ptr<Socket>& client) const {
     YaHTTP::AsyncRequestLoader yarl;
     yarl.initialize(&req);
     req.max_request_size=d_maxbodysize;
-    int timeout = 5;
+    int timeout = d_connectiontimeout;
     client->setNonBlocking();
 
     try {
       while(!req.complete) {
-        int bytes;
-        char buf[16000];
-        bytes = client->readWithTimeout(buf, sizeof(buf), timeout);
+        std::array<char, 16000> buf{};
+        auto bytes = client->readWithTimeout(buf.data(), buf.size(), timeout);
         if (bytes > 0) {
-          string data = string(buf, bytes);
+          string data = string(buf.data(), bytes);
           req.complete = yarl.feed(data);
         } else {
           // read error OR EOF
@@ -588,7 +587,8 @@ WebServer::WebServer(string listenaddress, int port) :
   d_listenaddress(std::move(listenaddress)),
   d_port(port),
   d_server(nullptr),
-  d_maxbodysize(2*1024*1024)
+  d_maxbodysize(2*1024*1024),
+  d_connectiontimeout(5)
 {
     YaHTTP::Router::Map("OPTIONS", "/<*url>", [](YaHTTP::Request *req, YaHTTP::Response *resp) {
       // look for url in routes
index 49f38b9ab319ef605851bf1fc6fdc41d8ca2f921..5b83d70712e9251637dde47258b501da94a4ae39 100644 (file)
@@ -212,6 +212,10 @@ public:
     d_maxbodysize = s * 1024 * 1024;
   }
 
+  void setConnectionTimeout(int t) { // in seconds
+    d_connectiontimeout = t;
+  }
+
   void setACL(const NetmaskGroup &nmg) {
     d_acl = nmg;
   }
@@ -285,6 +289,7 @@ protected:
   std::unique_ptr<CredentialsHolder> d_webserverPassword{nullptr};
 
   ssize_t d_maxbodysize; // in bytes
+  int d_connectiontimeout; // in seconds
 
   NetmaskGroup d_acl;
 
index 460734c4dc621335a3f85188beff48d082b9c049..8dc0f3f7e3cad2e9c1ba15806327b882b3204dbd 100644 (file)
@@ -117,6 +117,7 @@ AuthWebServer::AuthWebServer() :
     d_ws->setACL(acl);
 
     d_ws->setMaxBodySize(::arg().asNum("webserver-max-bodysize"));
+    d_ws->setConnectionTimeout(::arg().asNum("webserver-connection-timeout"));
 
     d_ws->bind();
   }
@@ -444,6 +445,9 @@ static void fillZone(UeberBackend& backend, const DNSName& zonename, HttpRespons
     vector<DNSResourceRecord> records;
     vector<Comment> comments;
 
+    QType qType = QType::ANY;
+    DNSName qName;
+
     // load all records + sort
     {
       DNSResourceRecord resourceRecord;
@@ -451,14 +455,11 @@ static void fillZone(UeberBackend& backend, const DNSName& zonename, HttpRespons
         domainInfo.backend->list(zonename, static_cast<int>(domainInfo.id), true); // incl. disabled
       }
       else {
-        QType qType;
-        if (req->getvars.count("rrset_type") == 0) {
-          qType = QType::ANY;
-        }
-        else {
+        qName = DNSName(req->getvars["rrset_name"]);
+        if (req->getvars.count("rrset_type") != 0) {
           qType = req->getvars["rrset_type"];
         }
-        domainInfo.backend->lookup(qType, DNSName(req->getvars["rrset_name"]), static_cast<int>(domainInfo.id));
+        domainInfo.backend->lookup(qType, qName, static_cast<int>(domainInfo.id));
       }
       while (domainInfo.backend->get(resourceRecord)) {
         if (resourceRecord.qtype.getCode() == 0) {
@@ -482,7 +483,9 @@ static void fillZone(UeberBackend& backend, const DNSName& zonename, HttpRespons
       Comment comment;
       domainInfo.backend->listComments(domainInfo.id);
       while (domainInfo.backend->getComment(comment)) {
-        comments.push_back(comment);
+        if ((qName.empty() || comment.qname == qName) && (qType == QType::ANY || comment.qtype == qType)) {
+          comments.push_back(comment);
+        }
       }
       sort(comments.begin(), comments.end(), [](const Comment& rrA, const Comment& rrB) {
         /* if you ever want to update this comparison function,
diff --git a/pdns/xsk.cc b/pdns/xsk.cc
deleted file mode 100644 (file)
index e507c0f..0000000
+++ /dev/null
@@ -1,1268 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#ifdef HAVE_XSK
-
-#include <algorithm>
-#include <cstdint>
-#include <cstring>
-#include <fcntl.h>
-#include <iterator>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <poll.h>
-#include <stdexcept>
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <vector>
-
-#include <bpf/bpf.h>
-#include <bpf/libbpf.h>
-extern "C"
-{
-#include <xdp/libxdp.h>
-}
-
-#include "gettime.hh"
-#include "xsk.hh"
-
-/* we need to include the linux specific headers AFTER the regular
-   ones, because it then detects that some types have already been
-   defined (sockaddr_in6 for example) and does not attempt to
-   re-define them, which otherwise breaks the C++ One Definition Rule
-*/
-#include <linux/bpf.h>
-#include <linux/if_ether.h>
-#include <linux/if_link.h>
-#include <linux/if_xdp.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/udp.h>
-
-#ifdef DEBUG_UMEM
-namespace
-{
-struct UmemEntryStatus
-{
-  enum class Status : uint8_t
-  {
-    Free,
-    FillQueue,
-    Received,
-    TXQueue
-  };
-  Status status{Status::Free};
-};
-
-LockGuarded<std::unordered_map<uint64_t, UmemEntryStatus>> s_umems;
-
-void checkUmemIntegrity(const char* function, int line, uint64_t offset, const std::set<UmemEntryStatus::Status>& validStatuses, UmemEntryStatus::Status newStatus)
-{
-  auto umems = s_umems.lock();
-  if (validStatuses.count(umems->at(offset).status) == 0) {
-    std::cerr << "UMEM integrity check failed at " << function << ": " << line << ": status is " << static_cast<int>(umems->at(offset).status) << ", expected: ";
-    for (const auto status : validStatuses) {
-      std::cerr << static_cast<int>(status) << " ";
-    }
-    std::cerr << std::endl;
-    abort();
-  }
-  (*umems)[offset].status = newStatus;
-}
-}
-#endif /* DEBUG_UMEM */
-
-constexpr bool XskSocket::isPowOfTwo(uint32_t value) noexcept
-{
-  return value != 0 && (value & (value - 1)) == 0;
-}
-
-int XskSocket::firstTimeout()
-{
-  if (waitForDelay.empty()) {
-    return -1;
-  }
-  timespec now{};
-  gettime(&now);
-  const auto& firstTime = waitForDelay.top().getSendTime();
-  const auto res = timeDifference(now, firstTime);
-  if (res <= 0) {
-    return 0;
-  }
-  return res;
-}
-
-XskSocket::XskSocket(size_t frameNum_, std::string ifName_, uint32_t queue_id, const std::string& xskMapPath) :
-  frameNum(frameNum_), ifName(std::move(ifName_)), socket(nullptr, xsk_socket__delete), sharedEmptyFrameOffset(std::make_shared<LockGuarded<vector<uint64_t>>>())
-{
-  if (!isPowOfTwo(frameNum_) || !isPowOfTwo(frameSize)
-      || !isPowOfTwo(fqCapacity) || !isPowOfTwo(cqCapacity) || !isPowOfTwo(rxCapacity) || !isPowOfTwo(txCapacity)) {
-    throw std::runtime_error("The number of frame , the size of frame and the capacity of rings must is a pow of 2");
-  }
-  getMACFromIfName();
-
-  memset(&cq, 0, sizeof(cq));
-  memset(&fq, 0, sizeof(fq));
-  memset(&tx, 0, sizeof(tx));
-  memset(&rx, 0, sizeof(rx));
-
-  xsk_umem_config umemCfg{};
-  umemCfg.fill_size = fqCapacity;
-  umemCfg.comp_size = cqCapacity;
-  umemCfg.frame_size = frameSize;
-  umemCfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
-  umemCfg.flags = 0;
-  umem.umemInit(frameNum_ * frameSize, &cq, &fq, &umemCfg);
-
-  {
-    xsk_socket_config socketCfg{};
-    socketCfg.rx_size = rxCapacity;
-    socketCfg.tx_size = txCapacity;
-    socketCfg.bind_flags = XDP_USE_NEED_WAKEUP;
-    socketCfg.xdp_flags = XDP_FLAGS_SKB_MODE;
-    socketCfg.libxdp_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
-    xsk_socket* tmp = nullptr;
-    auto ret = xsk_socket__create(&tmp, ifName.c_str(), queue_id, umem.umem, &rx, &tx, &socketCfg);
-    if (ret != 0) {
-      throw std::runtime_error("Error creating a xsk socket of if_name " + ifName + ": " + stringerror(ret));
-    }
-    socket = std::unique_ptr<xsk_socket, decltype(&xsk_socket__delete)>(tmp, xsk_socket__delete);
-  }
-
-  uniqueEmptyFrameOffset.reserve(frameNum);
-  {
-    for (uint64_t idx = 0; idx < frameNum; idx++) {
-      uniqueEmptyFrameOffset.push_back(idx * frameSize + XDP_PACKET_HEADROOM);
-#ifdef DEBUG_UMEM
-      {
-        auto umems = s_umems.lock();
-        (*umems)[idx * frameSize + XDP_PACKET_HEADROOM] = UmemEntryStatus();
-      }
-#endif /* DEBUG_UMEM */
-    }
-  }
-
-  fillFq(fqCapacity);
-
-  const auto xskfd = xskFd();
-  fds.push_back(pollfd{
-    .fd = xskfd,
-    .events = POLLIN,
-    .revents = 0});
-
-  const auto xskMapFd = FDWrapper(bpf_obj_get(xskMapPath.c_str()));
-
-  if (xskMapFd.getHandle() < 0) {
-    throw std::runtime_error("Error getting BPF map from path '" + xskMapPath + "'");
-  }
-
-  auto ret = bpf_map_update_elem(xskMapFd.getHandle(), &queue_id, &xskfd, 0);
-  if (ret != 0) {
-    throw std::runtime_error("Error inserting into xsk_map '" + xskMapPath + "': " + std::to_string(ret));
-  }
-}
-
-// see xdp.h in contrib/
-struct IPv4AndPort
-{
-  uint32_t addr;
-  uint16_t port;
-};
-struct IPv6AndPort
-{
-  struct in6_addr addr;
-  uint16_t port;
-};
-
-static FDWrapper getDestinationMap(const std::string& mapPath)
-{
-  auto destMapFd = FDWrapper(bpf_obj_get(mapPath.c_str()));
-  if (destMapFd.getHandle() < 0) {
-    throw std::runtime_error("Error getting the XSK destination addresses map path '" + mapPath + "'");
-  }
-  return destMapFd;
-}
-
-void XskSocket::clearDestinationMap(const std::string& mapPath, bool isV6)
-{
-  auto destMapFd = getDestinationMap(mapPath);
-  if (!isV6) {
-    IPv4AndPort prevKey{};
-    IPv4AndPort key{};
-    while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
-      bpf_map_delete_elem(destMapFd.getHandle(), &key);
-      prevKey = key;
-    }
-  }
-  else {
-    IPv6AndPort prevKey{};
-    IPv6AndPort key{};
-    while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
-      bpf_map_delete_elem(destMapFd.getHandle(), &key);
-      prevKey = key;
-    }
-  }
-}
-
-void XskSocket::addDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
-{
-  auto destMapFd = getDestinationMap(mapPath);
-  bool value = true;
-  if (destination.isIPv4()) {
-    IPv4AndPort key{};
-    key.addr = destination.sin4.sin_addr.s_addr;
-    key.port = destination.sin4.sin_port;
-    auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
-    if (ret != 0) {
-      throw std::runtime_error("Error inserting into xsk_map '" + mapPath + "': " + std::to_string(ret));
-    }
-  }
-  else {
-    IPv6AndPort key{};
-    key.addr = destination.sin6.sin6_addr;
-    key.port = destination.sin6.sin6_port;
-    auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
-    if (ret != 0) {
-      throw std::runtime_error("Error inserting into XSK destination addresses map '" + mapPath + "': " + std::to_string(ret));
-    }
-  }
-}
-
-void XskSocket::removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
-{
-  auto destMapFd = getDestinationMap(mapPath);
-  if (destination.isIPv4()) {
-    IPv4AndPort key{};
-    key.addr = destination.sin4.sin_addr.s_addr;
-    key.port = destination.sin4.sin_port;
-    bpf_map_delete_elem(destMapFd.getHandle(), &key);
-  }
-  else {
-    IPv6AndPort key{};
-    key.addr = destination.sin6.sin6_addr;
-    key.port = destination.sin6.sin6_port;
-    bpf_map_delete_elem(destMapFd.getHandle(), &key);
-  }
-}
-
-void XskSocket::fillFq(uint32_t fillSize) noexcept
-{
-  {
-    // if we have less than holdThreshold frames in the shared queue (which might be an issue
-    // when the XskWorker needs empty frames), move frames from the unique container into the
-    // shared one. This might not be optimal right now.
-    auto frames = sharedEmptyFrameOffset->lock();
-    if (frames->size() < holdThreshold) {
-      const auto moveSize = std::min(holdThreshold - frames->size(), uniqueEmptyFrameOffset.size());
-      if (moveSize > 0) {
-        // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-        frames->insert(frames->end(), std::make_move_iterator(uniqueEmptyFrameOffset.end() - moveSize), std::make_move_iterator(uniqueEmptyFrameOffset.end()));
-        uniqueEmptyFrameOffset.resize(uniqueEmptyFrameOffset.size() - moveSize);
-      }
-    }
-  }
-
-  if (uniqueEmptyFrameOffset.size() < fillSize) {
-    return;
-  }
-
-  uint32_t idx{0};
-  auto toFill = xsk_ring_prod__reserve(&fq, fillSize, &idx);
-  if (toFill == 0) {
-    return;
-  }
-  uint32_t processed = 0;
-  for (; processed < toFill; processed++) {
-    *xsk_ring_prod__fill_addr(&fq, idx++) = uniqueEmptyFrameOffset.back();
-#ifdef DEBUG_UMEM
-    checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Free}, UmemEntryStatus::Status::FillQueue);
-#endif /* DEBUG_UMEM */
-    uniqueEmptyFrameOffset.pop_back();
-  }
-
-  xsk_ring_prod__submit(&fq, processed);
-}
-
-int XskSocket::wait(int timeout)
-{
-  auto waitAtMost = std::min(timeout, firstTimeout());
-  return poll(fds.data(), fds.size(), waitAtMost);
-}
-
-[[nodiscard]] uint64_t XskSocket::frameOffset(const XskPacket& packet) const noexcept
-{
-  return packet.getFrameOffsetFrom(umem.bufBase);
-}
-
-[[nodiscard]] int XskSocket::xskFd() const noexcept
-{
-  return xsk_socket__fd(socket.get());
-}
-
-void XskSocket::send(std::vector<XskPacket>& packets)
-{
-  while (!packets.empty()) {
-    auto packetSize = packets.size();
-    if (packetSize > std::numeric_limits<uint32_t>::max()) {
-      packetSize = std::numeric_limits<uint32_t>::max();
-    }
-    size_t toSend = std::min(static_cast<uint32_t>(packetSize), txCapacity);
-    uint32_t idx{0};
-    auto toFill = xsk_ring_prod__reserve(&tx, toSend, &idx);
-    if (toFill == 0) {
-      return;
-    }
-
-    size_t queued = 0;
-    for (const auto& packet : packets) {
-      if (queued == toFill) {
-        break;
-      }
-      *xsk_ring_prod__tx_desc(&tx, idx++) = {
-        .addr = frameOffset(packet),
-        .len = packet.getFrameLen(),
-        .options = 0};
-#ifdef DEBUG_UMEM
-      checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::Received}, UmemEntryStatus::Status::TXQueue);
-#endif /* DEBUG_UMEM */
-      queued++;
-    }
-    xsk_ring_prod__submit(&tx, toFill);
-    packets.erase(packets.begin(), packets.begin() + toFill);
-  }
-}
-
-std::vector<XskPacket> XskSocket::recv(uint32_t recvSizeMax, uint32_t* failedCount)
-{
-  uint32_t idx{0};
-  std::vector<XskPacket> res;
-  // how many descriptors to packets have been filled
-  const auto recvSize = xsk_ring_cons__peek(&rx, recvSizeMax, &idx);
-  if (recvSize == 0) {
-    return res;
-  }
-
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-  const auto baseAddr = reinterpret_cast<uint64_t>(umem.bufBase);
-  uint32_t failed = 0;
-  uint32_t processed = 0;
-  res.reserve(recvSize);
-  for (; processed < recvSize; processed++) {
-    try {
-      const auto* desc = xsk_ring_cons__rx_desc(&rx, idx++);
-      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr)
-      XskPacket packet = XskPacket(reinterpret_cast<uint8_t*>(desc->addr + baseAddr), desc->len, frameSize);
-#ifdef DEBUG_UMEM
-      checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::FillQueue}, UmemEntryStatus::Status::Received);
-#endif /* DEBUG_UMEM */
-
-      if (!packet.parse(false)) {
-        ++failed;
-        markAsFree(packet);
-      }
-      else {
-        res.push_back(packet);
-      }
-    }
-    catch (const std::exception& exp) {
-      std::cerr << "Exception while processing the XSK RX queue: " << exp.what() << std::endl;
-      break;
-    }
-    catch (...) {
-      std::cerr << "Exception while processing the XSK RX queue" << std::endl;
-      break;
-    }
-  }
-
-  // this releases the descriptor, but not the packet (umem entries)
-  // which will only be made available again when pushed into the fill
-  // queue
-  xsk_ring_cons__release(&rx, processed);
-  if (failedCount != nullptr) {
-    *failedCount = failed;
-  }
-
-  return res;
-}
-
-void XskSocket::pickUpReadyPacket(std::vector<XskPacket>& packets)
-{
-  timespec now{};
-  gettime(&now);
-  while (!waitForDelay.empty() && timeDifference(now, waitForDelay.top().getSendTime()) <= 0) {
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
-    auto& top = const_cast<XskPacket&>(waitForDelay.top());
-    packets.push_back(top);
-    waitForDelay.pop();
-  }
-}
-
-void XskSocket::recycle(size_t size) noexcept
-{
-  uint32_t idx{0};
-  const auto completeSize = xsk_ring_cons__peek(&cq, size, &idx);
-  if (completeSize == 0) {
-    return;
-  }
-  uniqueEmptyFrameOffset.reserve(uniqueEmptyFrameOffset.size() + completeSize);
-  uint32_t processed = 0;
-  for (; processed < completeSize; ++processed) {
-    uniqueEmptyFrameOffset.push_back(*xsk_ring_cons__comp_addr(&cq, idx++));
-#ifdef DEBUG_UMEM
-    checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
-  }
-  xsk_ring_cons__release(&cq, processed);
-}
-
-void XskSocket::XskUmem::umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config)
-{
-  size = memSize;
-  bufBase = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
-  if (bufBase == MAP_FAILED) {
-    throw std::runtime_error("mmap failed");
-  }
-  auto ret = xsk_umem__create(&umem, bufBase, size, fillQueue, completionQueue, config);
-  if (ret != 0) {
-    munmap(bufBase, size);
-    throw std::runtime_error("Error creating a umem of size " + std::to_string(size) + ": " + stringerror(ret));
-  }
-}
-
-std::string XskSocket::getMetrics() const
-{
-  xdp_statistics stats{};
-  socklen_t optlen = sizeof(stats);
-  int err = getsockopt(xskFd(), SOL_XDP, XDP_STATISTICS, &stats, &optlen);
-  if (err != 0) {
-    return "";
-  }
-  if (optlen != sizeof(struct xdp_statistics)) {
-    return "";
-  }
-
-  ostringstream ret;
-  ret << "RX dropped: " << std::to_string(stats.rx_dropped) << std::endl;
-  ret << "RX invalid descs: " << std::to_string(stats.rx_invalid_descs) << std::endl;
-  ret << "TX invalid descs: " << std::to_string(stats.tx_invalid_descs) << std::endl;
-  ret << "RX ring full: " << std::to_string(stats.rx_ring_full) << std::endl;
-  ret << "RX fill ring empty descs: " << std::to_string(stats.rx_fill_ring_empty_descs) << std::endl;
-  ret << "TX ring empty descs: " << std::to_string(stats.tx_ring_empty_descs) << std::endl;
-  return ret.str();
-}
-
-[[nodiscard]] std::string XskSocket::getXDPMode() const
-{
-#ifdef HAVE_BPF_XDP_QUERY
-  unsigned int itfIdx = if_nametoindex(ifName.c_str());
-  if (itfIdx == 0) {
-    return "unable to get interface index";
-  }
-  bpf_xdp_query_opts info{};
-  info.sz = sizeof(info);
-  int ret = bpf_xdp_query(static_cast<int>(itfIdx), 0, &info);
-  if (ret != 0) {
-    return {};
-  }
-  switch (info.attach_mode) {
-  case XDP_ATTACHED_DRV:
-  case XDP_ATTACHED_HW:
-    return "native";
-  case XDP_ATTACHED_SKB:
-    return "emulated";
-  default:
-    return "unknown";
-  }
-#else /* HAVE_BPF_XDP_QUERY */
-  return "undetected";
-#endif /* HAVE_BPF_XDP_QUERY */
-}
-
-void XskSocket::markAsFree(const XskPacket& packet)
-{
-  auto offset = frameOffset(packet);
-#ifdef DEBUG_UMEM
-  checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
-
-  uniqueEmptyFrameOffset.push_back(offset);
-}
-
-XskSocket::XskUmem::~XskUmem()
-{
-  if (umem != nullptr) {
-    xsk_umem__delete(umem);
-  }
-  if (bufBase != nullptr) {
-    munmap(bufBase, size);
-  }
-}
-
-[[nodiscard]] size_t XskPacket::getL4HeaderOffset() const noexcept
-{
-  return sizeof(ethhdr) + (v6 ? (sizeof(ipv6hdr)) : sizeof(iphdr));
-}
-
-[[nodiscard]] size_t XskPacket::getDataOffset() const noexcept
-{
-  return getL4HeaderOffset() + sizeof(udphdr);
-}
-
-[[nodiscard]] size_t XskPacket::getDataSize() const noexcept
-{
-  return frameLength - getDataOffset();
-}
-
-[[nodiscard]] ethhdr XskPacket::getEthernetHeader() const noexcept
-{
-  ethhdr ethHeader{};
-  if (frameLength >= sizeof(ethHeader)) {
-    memcpy(&ethHeader, frame, sizeof(ethHeader));
-  }
-  return ethHeader;
-}
-
-void XskPacket::setEthernetHeader(const ethhdr& ethHeader) noexcept
-{
-  if (frameLength < sizeof(ethHeader)) {
-    frameLength = sizeof(ethHeader);
-  }
-  memcpy(frame, &ethHeader, sizeof(ethHeader));
-}
-
-[[nodiscard]] iphdr XskPacket::getIPv4Header() const noexcept
-{
-  iphdr ipv4Header{};
-  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv4Header)));
-  assert(!v6);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(&ipv4Header, frame + sizeof(ethhdr), sizeof(ipv4Header));
-  return ipv4Header;
-}
-
-void XskPacket::setIPv4Header(const iphdr& ipv4Header) noexcept
-{
-  assert(frameLength >= (sizeof(ethhdr) + sizeof(iphdr)));
-  assert(!v6);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(frame + sizeof(ethhdr), &ipv4Header, sizeof(ipv4Header));
-}
-
-[[nodiscard]] ipv6hdr XskPacket::getIPv6Header() const noexcept
-{
-  ipv6hdr ipv6Header{};
-  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
-  assert(v6);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(&ipv6Header, frame + sizeof(ethhdr), sizeof(ipv6Header));
-  return ipv6Header;
-}
-
-void XskPacket::setIPv6Header(const ipv6hdr& ipv6Header) noexcept
-{
-  assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
-  assert(v6);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(frame + sizeof(ethhdr), &ipv6Header, sizeof(ipv6Header));
-}
-
-[[nodiscard]] udphdr XskPacket::getUDPHeader() const noexcept
-{
-  udphdr udpHeader{};
-  assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(&udpHeader, frame + getL4HeaderOffset(), sizeof(udpHeader));
-  return udpHeader;
-}
-
-void XskPacket::setUDPHeader(const udphdr& udpHeader) noexcept
-{
-  assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(frame + getL4HeaderOffset(), &udpHeader, sizeof(udpHeader));
-}
-
-bool XskPacket::parse(bool fromSetHeader)
-{
-  if (frameLength <= sizeof(ethhdr)) {
-    return false;
-  }
-
-  auto ethHeader = getEthernetHeader();
-  uint8_t l4Protocol{0};
-  if (ethHeader.h_proto == htons(ETH_P_IP)) {
-    if (frameLength < (sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr))) {
-      return false;
-    }
-    v6 = false;
-    auto ipHeader = getIPv4Header();
-    if (ipHeader.ihl != (static_cast<uint8_t>(sizeof(iphdr) / 4))) {
-      // ip options is not supported now!
-      return false;
-    }
-    // check ip.check == ipv4Checksum() is not needed!
-    // We check it in BPF program
-    // we don't, actually.
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    from = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    to = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
-    l4Protocol = ipHeader.protocol;
-    if (!fromSetHeader && (frameLength - sizeof(ethhdr)) != ntohs(ipHeader.tot_len)) {
-      // too small, or too large (trailing data), go away
-      return false;
-    }
-  }
-  else if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
-    if (frameLength < (sizeof(ethhdr) + sizeof(ipv6hdr) + sizeof(udphdr))) {
-      return false;
-    }
-    v6 = true;
-    auto ipHeader = getIPv6Header();
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    from = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-    to = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
-    l4Protocol = ipHeader.nexthdr;
-    if (!fromSetHeader && (frameLength - (sizeof(ethhdr) + sizeof(ipv6hdr))) != ntohs(ipHeader.payload_len)) {
-      return false;
-    }
-  }
-  else {
-    return false;
-  }
-
-  if (l4Protocol != IPPROTO_UDP) {
-    return false;
-  }
-
-  // check udp.check == ipv4Checksum() is not needed!
-  // We check it in BPF program
-  // we don't, actually.
-  auto udpHeader = getUDPHeader();
-  if (!fromSetHeader) {
-    // Because of XskPacket::setHeader
-    if (getDataOffset() > frameLength) {
-      return false;
-    }
-
-    if (getDataSize() + sizeof(udphdr) != ntohs(udpHeader.len)) {
-      return false;
-    }
-  }
-
-  from.setPort(ntohs(udpHeader.source));
-  to.setPort(ntohs(udpHeader.dest));
-  return true;
-}
-
-uint32_t XskPacket::getDataLen() const noexcept
-{
-  return getDataSize();
-}
-
-uint32_t XskPacket::getFrameLen() const noexcept
-{
-  return frameLength;
-}
-
-size_t XskPacket::getCapacity() const noexcept
-{
-  return frameSize;
-}
-
-void XskPacket::changeDirectAndUpdateChecksum() noexcept
-{
-  auto ethHeader = getEthernetHeader();
-  {
-    std::array<uint8_t, ETH_ALEN> tmp{};
-    static_assert(tmp.size() == sizeof(ethHeader.h_dest), "Size Error");
-    static_assert(tmp.size() == sizeof(ethHeader.h_source), "Size Error");
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-    memcpy(tmp.data(), ethHeader.h_dest, tmp.size());
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-    memcpy(ethHeader.h_dest, ethHeader.h_source, tmp.size());
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-    memcpy(ethHeader.h_source, tmp.data(), tmp.size());
-  }
-  if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
-    // IPV6
-    auto ipv6 = getIPv6Header();
-    std::swap(ipv6.daddr, ipv6.saddr);
-    assert(ipv6.nexthdr == IPPROTO_UDP);
-
-    auto udp = getUDPHeader();
-    std::swap(udp.dest, udp.source);
-    udp.len = htons(getDataSize() + sizeof(udp));
-    udp.check = 0;
-    /* needed to get the correct checksum */
-    setIPv6Header(ipv6);
-    setUDPHeader(udp);
-    udp.check = tcp_udp_v6_checksum(&ipv6);
-    rewriteIpv6Header(&ipv6, getFrameLen());
-    setIPv6Header(ipv6);
-    setUDPHeader(udp);
-  }
-  else {
-    // IPV4
-    auto ipv4 = getIPv4Header();
-    std::swap(ipv4.daddr, ipv4.saddr);
-    assert(ipv4.protocol == IPPROTO_UDP);
-
-    auto udp = getUDPHeader();
-    std::swap(udp.dest, udp.source);
-    udp.len = htons(getDataSize() + sizeof(udp));
-    udp.check = 0;
-    /* needed to get the correct checksum */
-    setIPv4Header(ipv4);
-    setUDPHeader(udp);
-    udp.check = tcp_udp_v4_checksum(&ipv4);
-    rewriteIpv4Header(&ipv4, getFrameLen());
-    setIPv4Header(ipv4);
-    setUDPHeader(udp);
-  }
-  setEthernetHeader(ethHeader);
-}
-
-void XskPacket::rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept
-{
-  ipv4header->version = 4;
-  ipv4header->ihl = sizeof(iphdr) / 4;
-  ipv4header->tos = 0;
-  ipv4header->tot_len = htons(frameLen - sizeof(ethhdr));
-  ipv4header->id = 0;
-  ipv4header->frag_off = 0;
-  ipv4header->ttl = DefaultTTL;
-  ipv4header->check = 0;
-  ipv4header->check = ipv4Checksum(ipv4header);
-}
-
-void XskPacket::rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept
-{
-  ipv6header->version = 6;
-  ipv6header->priority = 0;
-  ipv6header->payload_len = htons(frameLen - sizeof(ethhdr) - sizeof(ipv6hdr));
-  ipv6header->hop_limit = DefaultTTL;
-  memset(&ipv6header->flow_lbl, 0, sizeof(ipv6header->flow_lbl));
-}
-
-bool XskPacket::isIPV6() const noexcept
-{
-  return v6;
-}
-
-XskPacket::XskPacket(uint8_t* frame_, size_t dataSize, size_t frameSize_) :
-  frame(frame_), frameLength(dataSize), frameSize(frameSize_ - XDP_PACKET_HEADROOM)
-{
-}
-
-PacketBuffer XskPacket::clonePacketBuffer() const
-{
-  const auto size = getDataSize();
-  PacketBuffer tmp(size);
-  if (size > 0) {
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    memcpy(tmp.data(), frame + getDataOffset(), size);
-  }
-  return tmp;
-}
-
-bool XskPacket::setPayload(const PacketBuffer& buf)
-{
-  const auto bufSize = buf.size();
-  const auto currentCapacity = getCapacity();
-  if (bufSize == 0 || bufSize > currentCapacity) {
-    return false;
-  }
-  flags |= UPDATE;
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  memcpy(frame + getDataOffset(), buf.data(), bufSize);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  frameLength = getDataOffset() + bufSize;
-  return true;
-}
-
-void XskPacket::addDelay(const int relativeMilliseconds) noexcept
-{
-  gettime(&sendTime);
-  sendTime.tv_nsec += static_cast<int64_t>(relativeMilliseconds) * 1000000L;
-  sendTime.tv_sec += sendTime.tv_nsec / 1000000000L;
-  sendTime.tv_nsec %= 1000000000L;
-}
-
-bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept
-{
-  return lhs.getSendTime() < rhs.getSendTime();
-}
-
-const ComboAddress& XskPacket::getFromAddr() const noexcept
-{
-  return from;
-}
-
-const ComboAddress& XskPacket::getToAddr() const noexcept
-{
-  return to;
-}
-
-void XskWorker::notify(int desc)
-{
-  uint64_t value = 1;
-  ssize_t res = 0;
-  while ((res = write(desc, &value, sizeof(value))) == EINTR) {
-  }
-  if (res != sizeof(value)) {
-    throw runtime_error("Unable Wake Up XskSocket Failed");
-  }
-}
-
-XskWorker::XskWorker() :
-  workerWaker(createEventfd()), xskSocketWaker(createEventfd())
-{
-}
-
-void XskWorker::pushToProcessingQueue(XskPacket& packet)
-{
-#if defined(__SANITIZE_THREAD__)
-  if (!incomingPacketsQueue.lock()->push(packet)) {
-#else
-  if (!incomingPacketsQueue.push(packet)) {
-#endif
-    markAsFree(packet);
-  }
-}
-
-void XskWorker::pushToSendQueue(XskPacket& packet)
-{
-#if defined(__SANITIZE_THREAD__)
-  if (!outgoingPacketsQueue.lock()->push(packet)) {
-#else
-  if (!outgoingPacketsQueue.push(packet)) {
-#endif
-    markAsFree(packet);
-  }
-}
-
-const void* XskPacket::getPayloadData() const
-{
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  return frame + getDataOffset();
-}
-
-void XskPacket::setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept
-{
-  auto ethHeader = getEthernetHeader();
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-  memcpy(ethHeader.h_dest, toMAC.data(), toMAC.size());
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-  memcpy(ethHeader.h_source, fromMAC.data(), fromMAC.size());
-  setEthernetHeader(ethHeader);
-  to = to_;
-  from = from_;
-  v6 = !to.isIPv4();
-  flags = 0;
-}
-
-void XskPacket::rewrite() noexcept
-{
-  flags |= REWRITE;
-  auto ethHeader = getEthernetHeader();
-  if (!v6) {
-    ethHeader.h_proto = htons(ETH_P_IP);
-
-    auto ipHeader = getIPv4Header();
-    ipHeader.daddr = to.sin4.sin_addr.s_addr;
-    ipHeader.saddr = from.sin4.sin_addr.s_addr;
-
-    auto udpHeader = getUDPHeader();
-    ipHeader.protocol = IPPROTO_UDP;
-    udpHeader.source = from.sin4.sin_port;
-    udpHeader.dest = to.sin4.sin_port;
-    udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
-    udpHeader.check = 0;
-    /* needed to get the correct checksum */
-    setIPv4Header(ipHeader);
-    setUDPHeader(udpHeader);
-    udpHeader.check = tcp_udp_v4_checksum(&ipHeader);
-    rewriteIpv4Header(&ipHeader, getFrameLen());
-    setIPv4Header(ipHeader);
-    setUDPHeader(udpHeader);
-  }
-  else {
-    ethHeader.h_proto = htons(ETH_P_IPV6);
-
-    auto ipHeader = getIPv6Header();
-    memcpy(&ipHeader.daddr, &to.sin6.sin6_addr, sizeof(ipHeader.daddr));
-    memcpy(&ipHeader.saddr, &from.sin6.sin6_addr, sizeof(ipHeader.saddr));
-
-    auto udpHeader = getUDPHeader();
-    ipHeader.nexthdr = IPPROTO_UDP;
-    udpHeader.source = from.sin6.sin6_port;
-    udpHeader.dest = to.sin6.sin6_port;
-    udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
-    udpHeader.check = 0;
-    /* needed to get the correct checksum */
-    setIPv6Header(ipHeader);
-    setUDPHeader(udpHeader);
-    udpHeader.check = tcp_udp_v6_checksum(&ipHeader);
-    setIPv6Header(ipHeader);
-    setUDPHeader(udpHeader);
-  }
-
-  setEthernetHeader(ethHeader);
-}
-
-[[nodiscard]] __be16 XskPacket::ipv4Checksum(const struct iphdr* ipHeader) noexcept
-{
-  auto partial = ip_checksum_partial(ipHeader, sizeof(iphdr), 0);
-  return ip_checksum_fold(partial);
-}
-
-[[nodiscard]] __be16 XskPacket::tcp_udp_v4_checksum(const struct iphdr* ipHeader) const noexcept
-{
-  // ip options is not supported !!!
-  const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
-  auto sum = tcp_udp_v4_header_checksum_partial(ipHeader->saddr, ipHeader->daddr, ipHeader->protocol, l4Length);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
-  return ip_checksum_fold(sum);
-}
-
-[[nodiscard]] __be16 XskPacket::tcp_udp_v6_checksum(const struct ipv6hdr* ipv6) const noexcept
-{
-  const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
-  uint64_t sum = tcp_udp_v6_header_checksum_partial(&ipv6->saddr, &ipv6->daddr, ipv6->nexthdr, l4Length);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-  sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
-  return ip_checksum_fold(sum);
-}
-
-[[nodiscard]] uint64_t XskPacket::ip_checksum_partial(const void* ptr, const size_t len, uint64_t sum) noexcept
-{
-  size_t position{0};
-  /* Main loop: 32 bits at a time */
-  for (position = 0; position < len; position += sizeof(uint32_t)) {
-    uint32_t value{};
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
-    sum += value;
-  }
-
-  /* Handle un-32bit-aligned trailing bytes */
-  if ((len - position) >= 2) {
-    uint16_t value{};
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
-    sum += value;
-    position += sizeof(value);
-  }
-
-  if ((len - position) > 0) {
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    const auto* ptr8 = static_cast<const uint8_t*>(ptr) + position;
-    sum += ntohs(*ptr8 << 8); /* RFC says pad last byte */
-  }
-
-  return sum;
-}
-
-[[nodiscard]] __be16 XskPacket::ip_checksum_fold(uint64_t sum) noexcept
-{
-  while ((sum & ~0xffffffffULL) != 0U) {
-    sum = (sum >> 32) + (sum & 0xffffffffULL);
-  }
-  while ((sum & 0xffff0000ULL) != 0U) {
-    sum = (sum >> 16) + (sum & 0xffffULL);
-  }
-
-  return static_cast<__be16>(~sum);
-}
-
-#ifndef __packed
-#define packed_attribute __attribute__((packed))
-#else
-#define packed_attribute __packed
-#endif
-
-// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
-[[nodiscard]] uint64_t XskPacket::tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept
-{
-  struct header
-  {
-    __be32 src_ip;
-    __be32 dst_ip;
-    __uint8_t mbz;
-    __uint8_t protocol;
-    __be16 length;
-  };
-  /* The IPv4 pseudo-header is defined in RFC 793, Section 3.1. */
-  struct ipv4_pseudo_header_t
-  {
-    /* We use a union here to avoid aliasing issues with gcc -O2 */
-    union
-    {
-      header packed_attribute fields;
-      // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
-      uint32_t words[3];
-    };
-  };
-  ipv4_pseudo_header_t pseudo_header{};
-  static_assert(sizeof(pseudo_header) == 12, "IPv4 pseudo-header size is incorrect");
-
-  /* Fill in the pseudo-header. */
-  pseudo_header.fields.src_ip = src_ip;
-  pseudo_header.fields.dst_ip = dst_ip;
-  pseudo_header.fields.mbz = 0;
-  pseudo_header.fields.protocol = protocol;
-  pseudo_header.fields.length = htons(len);
-  return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
-}
-
-[[nodiscard]] uint64_t XskPacket::tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept
-{
-  struct header
-  {
-    struct in6_addr src_ip;
-    struct in6_addr dst_ip;
-    __be32 length;
-    // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
-    __uint8_t mbz[3];
-    __uint8_t next_header;
-  };
-  /* The IPv6 pseudo-header is defined in RFC 2460, Section 8.1. */
-  struct ipv6_pseudo_header_t
-  {
-    /* We use a union here to avoid aliasing issues with gcc -O2 */
-    union
-    {
-      header packed_attribute fields;
-      // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
-      uint32_t words[10];
-    };
-  };
-  ipv6_pseudo_header_t pseudo_header{};
-  static_assert(sizeof(pseudo_header) == 40, "IPv6 pseudo-header size is incorrect");
-
-  /* Fill in the pseudo-header. */
-  pseudo_header.fields.src_ip = *src_ip;
-  pseudo_header.fields.dst_ip = *dst_ip;
-  pseudo_header.fields.length = htonl(len);
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-  memset(pseudo_header.fields.mbz, 0, sizeof(pseudo_header.fields.mbz));
-  pseudo_header.fields.next_header = protocol;
-  return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
-}
-
-void XskPacket::setHeader(PacketBuffer& buf)
-{
-  memcpy(frame, buf.data(), buf.size());
-  frameLength = buf.size();
-  buf.clear();
-  flags = 0;
-  if (!parse(true)) {
-    throw std::runtime_error("Error setting the XSK frame header");
-  }
-}
-
-PacketBuffer XskPacket::cloneHeaderToPacketBuffer() const
-{
-  const auto size = getFrameLen() - getDataSize();
-  PacketBuffer tmp(size);
-  memcpy(tmp.data(), frame, size);
-  return tmp;
-}
-
-int XskWorker::createEventfd()
-{
-  auto desc = ::eventfd(0, EFD_CLOEXEC);
-  if (desc < 0) {
-    throw runtime_error("Unable create eventfd");
-  }
-  return desc;
-}
-
-void XskWorker::waitForXskSocket() const noexcept
-{
-  uint64_t value = read(workerWaker, &value, sizeof(value));
-}
-
-void XskWorker::notifyXskSocket() const
-{
-  notify(xskSocketWaker);
-}
-
-std::shared_ptr<XskWorker> XskWorker::create()
-{
-  return std::make_shared<XskWorker>();
-}
-
-void XskSocket::addWorker(std::shared_ptr<XskWorker> worker)
-{
-  const auto socketWaker = worker->xskSocketWaker.getHandle();
-  worker->umemBufBase = umem.bufBase;
-  d_workers.insert({socketWaker, std::move(worker)});
-  fds.push_back(pollfd{
-    .fd = socketWaker,
-    .events = POLLIN,
-    .revents = 0});
-};
-
-void XskSocket::addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest)
-{
-  d_workerRoutes.lock()->insert({dest, worker});
-}
-
-void XskSocket::removeWorkerRoute(const ComboAddress& dest)
-{
-  d_workerRoutes.lock()->erase(dest);
-}
-
-uint64_t XskWorker::frameOffset(const XskPacket& packet) const noexcept
-{
-  return packet.getFrameOffsetFrom(umemBufBase);
-}
-
-void XskWorker::notifyWorker() const
-{
-  notify(workerWaker);
-}
-
-void XskSocket::getMACFromIfName()
-{
-  ifreq ifr{};
-  auto desc = FDWrapper(::socket(AF_INET, SOCK_DGRAM, 0));
-  if (desc < 0) {
-    throw std::runtime_error("Error creating a socket to get the MAC address of interface " + ifName);
-  }
-
-  if (ifName.size() >= IFNAMSIZ) {
-    throw std::runtime_error("Unable to get MAC address for interface " + ifName + ": name too long");
-  }
-
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-  strncpy(ifr.ifr_name, ifName.c_str(), ifName.length() + 1);
-  if (ioctl(desc.getHandle(), SIOCGIFHWADDR, &ifr) < 0 || ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-    throw std::runtime_error("Error getting MAC address for interface " + ifName);
-  }
-  static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= std::tuple_size<decltype(source)>{}, "The size of an ARPHRD_ETHER MAC address is smaller than expected");
-  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
-  memcpy(source.data(), ifr.ifr_hwaddr.sa_data, source.size());
-}
-
-[[nodiscard]] int XskSocket::timeDifference(const timespec& lhs, const timespec& rhs) noexcept
-{
-  const auto res = lhs.tv_sec * 1000 + lhs.tv_nsec / 1000000L - (rhs.tv_sec * 1000 + rhs.tv_nsec / 1000000L);
-  return static_cast<int>(res);
-}
-
-void XskWorker::cleanWorkerNotification() const noexcept
-{
-  uint64_t value = read(xskSocketWaker, &value, sizeof(value));
-}
-
-void XskWorker::cleanSocketNotification() const noexcept
-{
-  uint64_t value = read(workerWaker, &value, sizeof(value));
-}
-
-std::vector<pollfd> getPollFdsForWorker(XskWorker& info)
-{
-  std::vector<pollfd> fds;
-  int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
-  if (timerfd < 0) {
-    throw std::runtime_error("create_timerfd failed");
-  }
-  fds.push_back(pollfd{
-    .fd = info.workerWaker,
-    .events = POLLIN,
-    .revents = 0,
-  });
-  fds.push_back(pollfd{
-    .fd = timerfd,
-    .events = POLLIN,
-    .revents = 0,
-  });
-  return fds;
-}
-
-void XskWorker::fillUniqueEmptyOffset()
-{
-  auto frames = sharedEmptyFrameOffset->lock();
-  const auto moveSize = std::min(static_cast<size_t>(32), frames->size());
-  if (moveSize > 0) {
-    // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
-    uniqueEmptyFrameOffset.insert(uniqueEmptyFrameOffset.end(), std::make_move_iterator(frames->end() - moveSize), std::make_move_iterator(frames->end()));
-    frames->resize(frames->size() - moveSize);
-  }
-}
-
-std::optional<XskPacket> XskWorker::getEmptyFrame()
-{
-  if (!uniqueEmptyFrameOffset.empty()) {
-    auto offset = uniqueEmptyFrameOffset.back();
-    uniqueEmptyFrameOffset.pop_back();
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    return XskPacket(offset + umemBufBase, 0, frameSize);
-  }
-  fillUniqueEmptyOffset();
-  if (!uniqueEmptyFrameOffset.empty()) {
-    auto offset = uniqueEmptyFrameOffset.back();
-    uniqueEmptyFrameOffset.pop_back();
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
-    return XskPacket(offset + umemBufBase, 0, frameSize);
-  }
-  return std::nullopt;
-}
-
-void XskWorker::markAsFree(const XskPacket& packet)
-{
-  auto offset = frameOffset(packet);
-#ifdef DEBUG_UMEM
-  checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
-#endif /* DEBUG_UMEM */
-  uniqueEmptyFrameOffset.push_back(offset);
-}
-
-uint32_t XskPacket::getFlags() const noexcept
-{
-  return flags;
-}
-
-void XskPacket::updatePacket() noexcept
-{
-  if ((flags & UPDATE) == 0U) {
-    return;
-  }
-  if ((flags & REWRITE) == 0U) {
-    changeDirectAndUpdateChecksum();
-  }
-}
-#endif /* HAVE_XSK */
diff --git a/pdns/xsk.hh b/pdns/xsk.hh
deleted file mode 100644 (file)
index 8d2b57d..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#pragma once
-#include "config.h"
-
-#ifdef HAVE_XSK
-#include <array>
-#include <bits/types/struct_timespec.h>
-#include <boost/lockfree/spsc_queue.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/member.hpp>
-#include <cstdint>
-#include <memory>
-#include <poll.h>
-#include <queue>
-#include <stdexcept>
-#include <string>
-#include <unistd.h>
-#include <unordered_map>
-#include <vector>
-
-#include <xdp/xsk.h>
-
-#include "iputils.hh"
-#include "lock.hh"
-#include "misc.hh"
-#include "noinitvector.hh"
-
-class XskPacket;
-class XskWorker;
-class XskSocket;
-
-using MACAddr = std::array<uint8_t, 6>;
-
-// We use an XskSocket to manage an AF_XDP Socket corresponding to a NIC queue.
-// The XDP program running in the kernel redirects the data to the XskSocket in userspace.
-// We allocate frames that are placed into the descriptors in the fill queue, allowing the kernel to put incoming packets into the frames and place descriptors into the rx queue.
-// Once we have read the descriptors from the rx queue we release them, but we own the frames.
-// After we are done with the frame, we place them into descriptors of either the fill queue (empty frames) or tx queues (packets to be sent).
-// Once the kernel is done, it places descriptors referencing these frames into the cq where we can recycle them (packets destined to the tx queue or empty frame to the fill queue queue).
-
-// XskSocket routes packets to multiple worker threads registered on XskSocket via XskSocket::addWorker based on the destination port number of the packet.
-// The kernel and the worker thread holding XskWorker will wake up the XskSocket through XskFd and the Eventfd corresponding to each worker thread, respectively.
-
-class XskSocket
-{
-  struct XskUmem
-  {
-    xsk_umem* umem{nullptr};
-    uint8_t* bufBase{nullptr};
-    size_t size{0};
-    void umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config);
-    ~XskUmem();
-    XskUmem() = default;
-  };
-  using WorkerContainer = std::unordered_map<int, std::shared_ptr<XskWorker>>;
-  WorkerContainer d_workers;
-  using WorkerRoutesMap = std::unordered_map<ComboAddress, std::shared_ptr<XskWorker>, ComboAddress::addressPortOnlyHash>;
-  // it might be better to move to a StateHolder for performance
-  LockGuarded<WorkerRoutesMap> d_workerRoutes;
-  // number of frames to keep in sharedEmptyFrameOffset
-  static constexpr size_t holdThreshold = 256;
-  // number of frames to insert into the fill queue
-  static constexpr size_t fillThreshold = 128;
-  static constexpr size_t frameSize = 2048;
-  // number of entries (frames) in the umem
-  const size_t frameNum;
-  // responses that have been delayed
-  std::priority_queue<XskPacket> waitForDelay;
-  MACAddr source{};
-  const std::string ifName;
-  // AF_XDP socket then worker waker sockets
-  vector<pollfd> fds;
-  // list of frames, aka (indexes of) umem entries that can be reused to fill fq,
-  // collected from packets that we could not route (unknown destination),
-  // could not parse, were dropped during processing (!UPDATE), or
-  // simply recycled from cq after being processed by the kernel
-  vector<uint64_t> uniqueEmptyFrameOffset;
-  // completion ring: queue where sent packets are stored by the kernel
-  xsk_ring_cons cq{};
-  // rx ring: queue where the incoming packets are stored, read by XskRouter
-  xsk_ring_cons rx{};
-  // fill ring: queue where umem entries available to be filled (put into rx) are stored
-  xsk_ring_prod fq{};
-  // tx ring: queue where outgoing packets are stored
-  xsk_ring_prod tx{};
-  std::unique_ptr<xsk_socket, void (*)(xsk_socket*)> socket;
-  XskUmem umem;
-
-  static constexpr uint32_t fqCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4;
-  static constexpr uint32_t cqCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 4;
-  static constexpr uint32_t rxCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 2;
-  static constexpr uint32_t txCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2;
-
-  constexpr static bool isPowOfTwo(uint32_t value) noexcept;
-  [[nodiscard]] static int timeDifference(const timespec& lhs, const timespec& rhs) noexcept;
-
-  [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
-  [[nodiscard]] int firstTimeout();
-  void getMACFromIfName();
-
-public:
-  static void clearDestinationMap(const std::string& mapPath, bool isV6);
-  static void addDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
-  static void removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
-  static constexpr size_t getFrameSize()
-  {
-    return frameSize;
-  }
-  // list of free umem entries that can be reused
-  std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
-  XskSocket(size_t frameNum, std::string ifName, uint32_t queue_id, const std::string& xskMapPath);
-  [[nodiscard]] int xskFd() const noexcept;
-  // wait until one event has occurred
-  [[nodiscard]] int wait(int timeout);
-  // add as many packets as possible to the rx queue for sending */
-  void send(std::vector<XskPacket>& packets);
-  // look at incoming packets in rx, return them if parsing succeeeded
-  [[nodiscard]] std::vector<XskPacket> recv(uint32_t recvSizeMax, uint32_t* failedCount);
-  void addWorker(std::shared_ptr<XskWorker> worker);
-  void addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest);
-  void removeWorkerRoute(const ComboAddress& dest);
-  [[nodiscard]] std::string getMetrics() const;
-  [[nodiscard]] std::string getXDPMode() const;
-  void markAsFree(const XskPacket& packet);
-  [[nodiscard]] const std::shared_ptr<XskWorker>& getWorkerByDescriptor(int desc) const
-  {
-    return d_workers.at(desc);
-  }
-  [[nodiscard]] std::shared_ptr<XskWorker> getWorkerByDestination(const ComboAddress& destination)
-  {
-    auto routes = d_workerRoutes.lock();
-    auto workerIt = routes->find(destination);
-    if (workerIt == routes->end()) {
-      return nullptr;
-    }
-    return workerIt->second;
-  }
-  [[nodiscard]] const std::vector<pollfd>& getDescriptors() const
-  {
-    return fds;
-  }
-  [[nodiscard]] MACAddr getSourceMACAddress() const
-  {
-    return source;
-  }
-  [[nodiscard]] const std::string& getInterfaceName() const
-  {
-    return ifName;
-  }
-  // pick ups available frames from uniqueEmptyFrameOffset
-  // insert entries from uniqueEmptyFrameOffset into fq
-  void fillFq(uint32_t fillSize = fillThreshold) noexcept;
-  // picks up entries that have been processed (sent) from cq and push them into uniqueEmptyFrameOffset
-  void recycle(size_t size) noexcept;
-  // look at delayed packets, and send the ones that are ready
-  void pickUpReadyPacket(std::vector<XskPacket>& packets);
-  void pushDelayed(XskPacket& packet)
-  {
-    waitForDelay.push(packet);
-  }
-};
-
-struct ethhdr;
-struct iphdr;
-struct ipv6hdr;
-struct udphdr;
-
-class XskPacket
-{
-public:
-  enum Flags : uint32_t
-  {
-    UPDATE = 1 << 0,
-    DELAY = 1 << 1,
-    REWRITE = 1 << 2
-  };
-
-private:
-  ComboAddress from;
-  ComboAddress to;
-  timespec sendTime{};
-  uint8_t* frame{nullptr};
-  size_t frameLength{0};
-  size_t frameSize{0};
-  uint32_t flags{0};
-  bool v6{false};
-
-  // You must set ipHeader.check = 0 before calling this method
-  [[nodiscard]] static __be16 ipv4Checksum(const struct iphdr*) noexcept;
-  [[nodiscard]] static uint64_t ip_checksum_partial(const void* p, size_t len, uint64_t sum) noexcept;
-  [[nodiscard]] static __be16 ip_checksum_fold(uint64_t sum) noexcept;
-  [[nodiscard]] static uint64_t tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept;
-  [[nodiscard]] static uint64_t tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept;
-  static void rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept;
-  static void rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept;
-
-  // You must set l4Header.check = 0 before calling this method
-  // ip options is not supported
-  [[nodiscard]] __be16 tcp_udp_v4_checksum(const struct iphdr*) const noexcept;
-  // You must set l4Header.check = 0 before calling this method
-  [[nodiscard]] __be16 tcp_udp_v6_checksum(const struct ipv6hdr*) const noexcept;
-  /* offset of the L4 (udphdr) header (after ethhdr and iphdr/ipv6hdr) */
-  [[nodiscard]] size_t getL4HeaderOffset() const noexcept;
-  /* offset of the data after the UDP header */
-  [[nodiscard]] size_t getDataOffset() const noexcept;
-  [[nodiscard]] size_t getDataSize() const noexcept;
-  [[nodiscard]] ethhdr getEthernetHeader() const noexcept;
-  void setEthernetHeader(const ethhdr& ethHeader) noexcept;
-  [[nodiscard]] iphdr getIPv4Header() const noexcept;
-  void setIPv4Header(const iphdr& ipv4Header) noexcept;
-  [[nodiscard]] ipv6hdr getIPv6Header() const noexcept;
-  void setIPv6Header(const ipv6hdr& ipv6Header) noexcept;
-  [[nodiscard]] udphdr getUDPHeader() const noexcept;
-  void setUDPHeader(const udphdr& udpHeader) noexcept;
-  void changeDirectAndUpdateChecksum() noexcept;
-
-  constexpr static uint8_t DefaultTTL = 64;
-
-public:
-  [[nodiscard]] const ComboAddress& getFromAddr() const noexcept;
-  [[nodiscard]] const ComboAddress& getToAddr() const noexcept;
-  [[nodiscard]] const void* getPayloadData() const;
-  [[nodiscard]] bool isIPV6() const noexcept;
-  [[nodiscard]] size_t getCapacity() const noexcept;
-  [[nodiscard]] uint32_t getDataLen() const noexcept;
-  [[nodiscard]] uint32_t getFrameLen() const noexcept;
-  [[nodiscard]] PacketBuffer clonePacketBuffer() const;
-  [[nodiscard]] PacketBuffer cloneHeaderToPacketBuffer() const;
-  void setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept;
-  bool setPayload(const PacketBuffer& buf);
-  void rewrite() noexcept;
-  void setHeader(PacketBuffer& buf);
-  XskPacket(uint8_t* frame, size_t dataSize, size_t frameSize);
-  void addDelay(int relativeMilliseconds) noexcept;
-  void updatePacket() noexcept;
-  // parse IP and UDP payloads
-  bool parse(bool fromSetHeader);
-  [[nodiscard]] uint32_t getFlags() const noexcept;
-  [[nodiscard]] timespec getSendTime() const noexcept
-  {
-    return sendTime;
-  }
-  [[nodiscard]] uint64_t getFrameOffsetFrom(const uint8_t* base) const noexcept
-  {
-    return frame - base;
-  }
-};
-bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept;
-
-/* g++ defines __SANITIZE_THREAD__
-   clang++ supports the nice __has_feature(thread_sanitizer),
-   let's merge them */
-#if defined(__has_feature)
-#if __has_feature(thread_sanitizer)
-#define __SANITIZE_THREAD__ 1
-#endif
-#endif
-
-// XskWorker obtains XskPackets of specific ports in the NIC from XskSocket through cq.
-// After finishing processing the packet, XskWorker puts the packet into sq so that XskSocket decides whether to send it through the network card according to XskPacket::flags.
-// XskWorker wakes up XskSocket via xskSocketWaker after putting the packets in sq.
-class XskWorker
-{
-#if defined(__SANITIZE_THREAD__)
-  using XskPacketRing = LockGuarded<boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>>;
-#else
-  using XskPacketRing = boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>;
-#endif
-
-public:
-  // queue of packets to be processed by this worker
-  XskPacketRing incomingPacketsQueue;
-  // queue of packets processed by this worker (to be sent, or discarded)
-  XskPacketRing outgoingPacketsQueue;
-
-  uint8_t* umemBufBase{nullptr};
-  // list of frames that are shared with the XskRouter
-  std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
-  // list of frames that we own, used to generate new packets (health-check)
-  vector<uint64_t> uniqueEmptyFrameOffset;
-  const size_t frameSize{XskSocket::getFrameSize()};
-  FDWrapper workerWaker;
-  FDWrapper xskSocketWaker;
-
-  XskWorker();
-  static int createEventfd();
-  static void notify(int desc);
-  static std::shared_ptr<XskWorker> create();
-  void pushToProcessingQueue(XskPacket& packet);
-  void pushToSendQueue(XskPacket& packet);
-  void markAsFree(const XskPacket& packet);
-  // notify worker that at least one packet is available for processing
-  void notifyWorker() const;
-  // notify the router that packets are ready to be sent
-  void notifyXskSocket() const;
-  void waitForXskSocket() const noexcept;
-  void cleanWorkerNotification() const noexcept;
-  void cleanSocketNotification() const noexcept;
-  [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
-  // reap empty umem entry from sharedEmptyFrameOffset into uniqueEmptyFrameOffset
-  void fillUniqueEmptyOffset();
-  // look for an empty umem entry in uniqueEmptyFrameOffset
-  // then sharedEmptyFrameOffset if needed
-  std::optional<XskPacket> getEmptyFrame();
-};
-std::vector<pollfd> getPollFdsForWorker(XskWorker& info);
-#else
-class XskSocket
-{
-};
-class XskPacket
-{
-};
-class XskWorker
-{
-};
-
-#endif /* HAVE_XSK */
index d769859896f4e9d4540a965be522aba6074160c2..2876b5e268d4b45f27866f7b00d7d8e7733d7bad 100644 (file)
@@ -1935,7 +1935,7 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
 
     def test_zone_comment_create(self):
         name, payload, zone = self.create_zone()
-        rrset = {
+        rrset1 = {
             'changetype': 'replace',
             'name': name,
             'type': 'NS',
@@ -1951,7 +1951,19 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
                 }
             ]
         }
-        payload = {'rrsets': [rrset]}
+        rrset2 = {
+            'changetype': 'replace',
+            'name': name,
+            'type': 'SOA',
+            'ttl': 3600,
+            'comments': [
+                {
+                    'account': 'test3',
+                    'content': 'this should not show up later'
+                }
+            ]
+        }
+        payload = {'rrsets': [rrset1, rrset2]}
         r = self.session.patch(
             self.url("/api/v1/servers/localhost/zones/" + name),
             data=json.dumps(payload),
@@ -1963,13 +1975,15 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
             self.assert_success(r)
         # make sure the comments have been set, and that the NS
         # records are still present
-        data = self.get_zone(name)
+        data = self.get_zone(name, rrset_name=name, rrset_type="NS")
         serverset = get_rrset(data, name, 'NS')
         print(serverset)
         self.assertNotEqual(serverset['records'], [])
         self.assertNotEqual(serverset['comments'], [])
         # verify that modified_at has been set by pdns
         self.assertNotEqual([c for c in serverset['comments']][0]['modified_at'], 0)
+        # verify that unrelated comments do not leak into the result
+        self.assertEqual(get_rrset(data, name, 'SOA'), None)
         # verify that TTL is correct (regression test)
         self.assertEqual(serverset['ttl'], 3600)
 
@@ -1997,7 +2011,7 @@ $NAME$  1D  IN  SOA ns1.example.org. hostmaster.example.org. (
 
     @unittest.skipIf(is_auth_lmdb(), "No comments in LMDB")
     def test_zone_comment_out_of_range_modified_at(self):
-        # Test if comments on an rrset stay intact if the rrset is replaced
+        # Test if a modified_at outside of the 32 bit range throws an error
         name, payload, zone = self.create_zone()
         rrset = {
             'changetype': 'replace',
@@ -2555,7 +2569,7 @@ class AuthRootZone(ApiTestCase, AuthZonesHelperMixin):
 @unittest.skipIf(not is_recursor(), "Not applicable")
 class RecursorZones(ApiTestCase):
 
-    def create_zone(self, name=None, kind=None, rd=False, servers=None):
+    def create_zone(self, name=None, kind=None, rd=False, servers=None, notify_allowed=False):
         if name is None:
             name = unique_zone_name()
         if servers is None:
@@ -2564,7 +2578,8 @@ class RecursorZones(ApiTestCase):
             'name': name,
             'kind': kind,
             'servers': servers,
-            'recursion_desired': rd
+            'recursion_desired': rd,
+            'notify_allowed': notify_allowed
         }
         r = self.session.post(
             self.url("/api/v1/servers/localhost/zones"),
@@ -2600,6 +2615,13 @@ class RecursorZones(ApiTestCase):
         for k in payload.keys():
             self.assertEqual(data[k], payload[k])
 
+    def test_create_forwarded_zone_notify_allowed(self):
+        payload, data = self.create_zone(kind='Forwarded', rd=False, servers=['8.8.8.8'], notify_allowed=True)
+        # return values are normalized
+        payload['servers'][0] += ':53'
+        for k in payload.keys():
+            self.assertEqual(data[k], payload[k])
+
     def test_create_forwarded_rd_zone(self):
         payload, data = self.create_zone(name='google.com.', kind='Forwarded', rd=True, servers=['8.8.8.8'])
         # return values are normalized
index ef2bbe8132cde099b266818d48d2755f3cc80575..5eb6534df8fef6ec87713ba4d9c7acd8478f8270 100644 (file)
@@ -27,7 +27,7 @@ class AuthTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     _config_params = []
 
     _config_template_default = """
-module-dir=../regression-tests/modules
+module-dir={PDNS_MODULE_DIR}
 daemon=no
 bind-config={confdir}/named.conf
 bind-dnssec-db={bind_dnssec_db}
@@ -69,12 +69,15 @@ PrivateKey: Lt0v0Gol3pRUFM7fDdcy0IWN0O/MnEmVPA+VylL8Y4U=
         """,
     }
 
-    _auth_cmd = ['authbind',
-                 os.environ['PDNS']]
+    _auth_cmd = [os.environ['PDNS']]
+    if sys.platform != 'darwin':
+        _auth_cmd = ['authbind'] + _auth_cmd
+
     _auth_env = {}
     _auths = {}
 
     _PREFIX = os.environ['PREFIX']
+    _PDNS_MODULE_DIR = os.environ['PDNS_MODULE_DIR']
 
 
     @classmethod
@@ -116,7 +119,9 @@ options {
         with open(os.path.join(confdir, 'pdns.conf'), 'w') as pdnsconf:
             pdnsconf.write(cls._config_template_default.format(
                 confdir=confdir, prefix=cls._PREFIX,
-                bind_dnssec_db=bind_dnssec_db))
+                bind_dnssec_db=bind_dnssec_db,
+                PDNS_MODULE_DIR=cls._PDNS_MODULE_DIR,
+            ))
             pdnsconf.write(cls._config_template % params)
 
         os.system("sqlite3 ./configs/auth/powerdns.sqlite < ../modules/gsqlite3backend/schema.sqlite3.sql")
index 22f0b14639c339f9f5e01ed1dc98a027f9644c7b..eb47cb0bec165faf92ceb58a0ad95f4ca35050a4 100755 (executable)
@@ -14,9 +14,20 @@ mkdir -p configs
 
 [ -f ./vars ] && . ./vars
 
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+  # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+  PDNS_BUILD_PATH=.
+
+  export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+  export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+  export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+  export PDNS_MODULE_DIR=${PDNS_MODULE_DIR:-${PWD}/modules}
+else
+  export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+  export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+  export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+  export PDNS_MODULE_DIR=${PDNS_MODULE_DIR:-$PDNS_BUILD_PATH/modules}
+fi
 
 export PREFIX=127.0.0
 
index 3016053a20f5ff62243b067352d72dc47a3b9de3..8cd7f4f3deb7e67c96bb57fb52c8d6c56dbf9bfc 100644 (file)
@@ -194,10 +194,10 @@ subnetwrong.example.org.     3600 IN ALIAS subnetwrong.example.com.
 
         ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
         ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
-        query = dns.message.make_query('subnet.example.org', 'A', use_edns=True, options=[ecso])
+        query = dns.message.make_query('subnet.example.org', 'AAAA', use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertAnyRRsetInAnswer(res, expected_a)
+        self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
     def testECSWrong(self):
@@ -218,10 +218,10 @@ subnetwrong.example.org.     3600 IN ALIAS subnetwrong.example.com.
 
         ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
         ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 48)
-        query = dns.message.make_query('subnetwrong.example.org', 'A', use_edns=True, options=[ecso])
+        query = dns.message.make_query('subnetwrong.example.org', 'AAAA', use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertAnyRRsetInAnswer(res, expected_a)
+        self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
     def testECSNone(self):
@@ -242,10 +242,10 @@ subnetwrong.example.org.     3600 IN ALIAS subnetwrong.example.com.
 
         ecso = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64)
         ecso2 = clientsubnetoption.ClientSubnetOption('2001:db8:db6:db5::', 64, 0)
-        query = dns.message.make_query('noerror.example.org', 'A', use_edns=True, options=[ecso])
+        query = dns.message.make_query('noerror.example.org', 'AAAA', use_edns=True, options=[ecso])
         res = self.sendUDPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
-        self.assertAnyRRsetInAnswer(res, expected_a)
+        self.assertAnyRRsetInAnswer(res, expected_aaaa)
         self.assertEqual(res.options[0], ecso2)
 
 class AliasUDPResponder(DatagramProtocol):
index 8ef7c5b717193a9d26ac10c117d4322c2657eda5..2297f46c2a983ee5028f1c16f8617071cd40be97 100644 (file)
@@ -8,7 +8,7 @@ from authtests import AuthTest
 
 class GSSTSIGBase(AuthTest):
     _config_template_default = """
-module-dir=../regression-tests/modules
+module-dir={PDNS_MODULE_DIR}
 daemon=no
 socket-dir={confdir}
 cache-ttl=0
index 889d40a54fa54744588862ed544f5b2424b2660c..94648db48756c42284ce2e54ce3b09935d473b64 100644 (file)
@@ -864,11 +864,13 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     def checkMessageEDNSWithoutOptions(self, expected, received):
         self.assertEqual(expected, received)
         self.assertEqual(received.edns, 0)
+        self.assertEqual(expected.ednsflags, received.ednsflags)
         self.assertEqual(expected.payload, received.payload)
 
     def checkMessageEDNSWithoutECS(self, expected, received, withCookies=0):
         self.assertEqual(expected, received)
         self.assertEqual(received.edns, 0)
+        self.assertEqual(expected.ednsflags, received.ednsflags)
         self.assertEqual(expected.payload, received.payload)
         self.assertEqual(len(received.options), withCookies)
         if withCookies:
@@ -881,6 +883,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     def checkMessageEDNSWithECS(self, expected, received, additionalOptions=0):
         self.assertEqual(expected, received)
         self.assertEqual(received.edns, 0)
+        self.assertEqual(expected.ednsflags, received.ednsflags)
         self.assertEqual(expected.payload, received.payload)
         self.assertEqual(len(received.options), 1 + additionalOptions)
         hasECS = False
@@ -896,6 +899,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     def checkMessageEDNS(self, expected, received):
         self.assertEqual(expected, received)
         self.assertEqual(received.edns, 0)
+        self.assertEqual(expected.ednsflags, received.ednsflags)
         self.assertEqual(expected.payload, received.payload)
         self.assertEqual(len(expected.options), len(received.options))
         self.compareOptions(expected.options, received.options)
index 13ce6de1840cb2b70a864b7be811c6a5bc446cea..72ee0cac007dc6d027d38717d75f27e3eb9a111e 100644 (file)
@@ -5,7 +5,7 @@ libnacl>=1.4.3,<1.7
 requests>=2.1.0
 protobuf>=3.0
 pyasn1==0.4.8
-pysnmp>=4.3.4
+pysnmp>=5,<6
 future>=0.17.1
 pycurl>=7.43.0
 lmdb>=0.95
index 23e6e54e3354865e1c19fdb0db7eb13a66f2fac8..40e65aaa7f269ea64e368388f3060e9bf8f5d0e2 100755 (executable)
@@ -11,14 +11,16 @@ python -V
 
 if [ `uname -s` == Darwin ]
 then
-  if [ ! -e /usr/local/opt/curl-openssl ]
+  BREW_CURL_PREFIX=$(brew --prefix curl)
+  if [ ! -e "${BREW_CURL_PREFIX}" ]
   then
-    echo Please run: brew install curl-openssl, and try again
+    echo Please run: brew install curl, and try again
     exit 1
   else
-    export PYCURL_CURL_CONFIG=/usr/local/opt/curl-openssl/bin/curl-config
-    export LDFLAGS=-L/usr/local/opt/openssl/lib
-    export CPPFLAGS=-I/usr/local/opt/openssl/include
+    export PYCURL_CURL_CONFIG="${BREW_CURL_PREFIX}/bin/curl-config"
+    export LDFLAGS="-L${BREW_CURL_PREFIX}/lib${LDFLAGS+ $LDFLAGS}"
+    export CPPFLAGS="-I${BREW_CURL_PREFIX}/include${CPPFLAGS+ $CPPFLAGS}"
+    export PKG_CONFIG_PATH="${BREW_CURL_PREFIX}/lib/pkgconfig"
   fi
 fi
 pip install -U pip wheel | cat
index 562795402d40e5da7c70fa881fa54df0a05090eb..c9554846ea86f52ea6140720d7b03de1c5249f2f 100644 (file)
@@ -184,6 +184,7 @@ class DOHTests(object):
         query.id = 0
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
+        response.want_dnssec(True)
         rrset = dns.rrset.from_text(name,
                                     3600,
                                     dns.rdataclass.IN,
@@ -899,9 +900,10 @@ class DOHAddingECSTests(object):
         rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
         query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True)
         query.id = 0
-        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso])
+        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso], want_dnssec=True)
         response = dns.message.make_response(query)
         response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
+        response.want_dnssec(True)
         rrset = dns.rrset.from_text(name,
                                     3600,
                                     dns.rdataclass.IN,
index e45ded5e17509ed52350e1c3533dece5c2a8c38c..675f70c6bec5cec4700df2d97a2457ff388fbd9d 100644 (file)
@@ -90,6 +90,47 @@ class TestBasics(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.checkMessageEDNS(expectedResponse, receivedResponse)
 
+    def testExtendedErrorBackendResponse(self):
+        """
+        EDE: Backend response (DO)
+        """
+        name = 'backend-response-do.ede.tests.powerdns.com.'
+        ede = extendederrors.ExtendedErrorOption(16, b'my extended error status')
+        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, want_dnssec=True)
+
+        backendResponse = dns.message.make_response(query)
+        backendResponse.use_edns(edns=True, payload=4096, options=[])
+        backendResponse.want_dnssec(True)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+
+        backendResponse.answer.append(rrset)
+        expectedResponse = dns.message.make_response(query)
+        expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
+        expectedResponse.want_dnssec(True)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        expectedResponse.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, backendResponse)
+            receivedQuery.id = query.id
+            self.assertEqual(query, receivedQuery)
+            self.checkMessageEDNS(expectedResponse, receivedResponse)
+
+        # testing the cache
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageEDNS(expectedResponse, receivedResponse)
+
     def testExtendedErrorBackendResponseWithExistingEDE(self):
         """
         EDE: Backend response with existing EDE
index f1ee0aec1ddcb87aed5a9b5208b149f7beff7407..6186841b52335e0290dcd20210a7434ea61e661c 100644 (file)
@@ -145,6 +145,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -159,6 +160,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.flags |= dns.flags.TC
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -169,6 +171,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         name = 'edns-do.lua.edns-self.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, want_dnssec=True)
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -183,6 +186,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.answer.append(dns.rrset.from_text(name,
                                                            60,
                                                            dns.rdataclass.IN,
@@ -206,6 +210,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
         expectedResponse.set_rcode(dns.rcode.REFUSED)
+        expectedResponse.want_dnssec(True)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
             sender = getattr(self, method)
@@ -219,6 +224,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         # dnsdist sets RA = RD for TC responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.flags |= dns.flags.TC
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -229,6 +235,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         name = 'edns-options.lua.edns-self.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512, want_dnssec=True)
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
 
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -243,6 +250,7 @@ class TestEDNSSelfGenerated(DNSDistTest):
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
         expectedResponse = dns.message.make_response(query, our_payload=1042)
+        expectedResponse.want_dnssec(True)
         expectedResponse.answer.append(dns.rrset.from_text(name,
                                                            60,
                                                            dns.rdataclass.IN,
index 517db15c3265ff1f6121b143ee7318b908d5a5ab..f298d2a3cece94a09b5d970cc8f070bdfa1b4826 100644 (file)
@@ -70,6 +70,18 @@ class TestAdvancedLuaFFI(DNSDistTest):
         return false
       end
 
+      local ednsVersion = ffi.C.dnsdist_ffi_dnsquestion_get_edns_version(dq)
+      if ednsVersion ~= 0 then
+        print('invalid EDNS version')
+        return false
+      end
+
+      local ednsExtendedRCode = ffi.C.dnsdist_ffi_dnsquestion_get_edns_extended_rcode(dq)
+      if ednsExtendedRCode ~= 0 then
+        print('invalid EDNS Extended RCode')
+        return false
+      end
+
       local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
       if len ~= 52 then
         print('invalid length')
@@ -226,7 +238,19 @@ class TestAdvancedLuaFFIPerThread(DNSDistTest):
           return false
         end
 
-        local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
+        local ednsVersion = ffi.C.dnsdist_ffi_dnsquestion_get_edns_version(dq)
+        if ednsVersion ~= 0 then
+          print('invalid EDNS version')
+          return false
+        end
+
+        local ednsExtendedRCode = ffi.C.dnsdist_ffi_dnsquestion_get_edns_extended_rcode(dq)
+        if ednsExtendedRCode ~= 0 then
+          print('invalid EDNS Extended RCode')
+          return false
+        end
+
+      local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
         if len ~= 61 then
           print('invalid length')
           print(len)
index cccf04bfb66e338331766bd73cd25a36f3723b5d..f6d334038b0fae8f564d690d133528797d31bb8c 100644 (file)
@@ -28,6 +28,10 @@ class TestPrometheus(DNSDistTest):
     declareMetric('custom-metric2', 'gauge', 'Custom gauge')
     -- and custom names
     declareMetric('custom-metric3', 'counter', 'Custom counter', 'custom_prometheus_name')
+
+    -- test prometheus labels in custom metrics
+    declareMetric('custom-metric-foo-x-bar-y-xyz', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="bar",y="xyz"}')
+    declareMetric('custom-metric-foo-x-baz-y-abc', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="baz",y="abc"}')
     """
 
     def checkPrometheusContentBasic(self, content):
@@ -42,7 +46,7 @@ class TestPrometheus(DNSDistTest):
             elif not line.startswith('#'):
                 tokens = line.split(' ')
                 self.assertEqual(len(tokens), 2)
-                if not line.startswith('dnsdist_') and not line.startswith('custom_prometheus_name'):
+                if not line.startswith('dnsdist_') and not line.startswith('custom_'):
                     raise AssertionError('Expecting prometheus metric to be prefixed by \'dnsdist_\', got: "%s"' % (line))
 
     def checkMetric(self, content, name, expectedType, expectedValue):
index 2ed60e08bc9f4351b7a59da384030f4b3f7691a6..78677b3a7149f7e9a4775e6264b78f36947717ba 100644 (file)
@@ -142,7 +142,6 @@ class TestProxyProtocol(ProxyProtocolTest):
     addAction("values-action.proxy.tests.powerdns.com.", SetProxyProtocolValuesAction({ ["1"]="dnsdist", ["255"]="proxy-protocol"}))
     """
     _config_params = ['_proxyResponderPort']
-    _verboseMode = True
 
     def testProxyUDP(self):
         """
@@ -379,6 +378,8 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
     _config_template = """
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=true})
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=false})
+    addTLSLocal("127.0.0.1:%d", "%s", "%s", {proxyProtocolOutsideTLS=true})
+    addTLSLocal("127.0.0.1:%d", "%s", "%s", {proxyProtocolOutsideTLS=false})
     setProxyProtocolACL( { "127.0.0.1/32" } )
     newServer{address="127.0.0.1:%d", useProxyProtocol=true, proxyProtocolAdvertiseTLS=true}
 
@@ -421,7 +422,9 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
     _caCert = 'ca.pem'
     _dohServerPPOutsidePort = pickAvailablePort()
     _dohServerPPInsidePort = pickAvailablePort()
-    _config_params = ['_dohServerPPOutsidePort', '_serverCert', '_serverKey', '_dohServerPPInsidePort', '_serverCert', '_serverKey', '_proxyResponderPort']
+    _dotServerPPOutsidePort = pickAvailablePort()
+    _dotServerPPInsidePort = pickAvailablePort()
+    _config_params = ['_dohServerPPOutsidePort', '_serverCert', '_serverKey', '_dohServerPPInsidePort', '_serverCert', '_serverKey', '_dotServerPPOutsidePort', '_serverCert', '_serverKey', '_dotServerPPInsidePort', '_serverCert', '_serverKey', '_proxyResponderPort']
 
     def testNoHeader(self):
         """
@@ -666,7 +669,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
 
         reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
         self.assertTrue(receivedDNSData)
@@ -682,7 +685,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         for idx in range(5):
           receivedResponse = None
           toProxyQueue.put(response, True, 2.0)
-          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
           (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
           self.assertTrue(receivedProxyPayload)
           self.assertTrue(receivedDNSData)
@@ -719,7 +722,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         conn = self.openDOHConnection(reverseProxyPort, self._caCert, timeout=2.0)
 
         reverseProxyBaseURL = ("https://%s:%d/" % (self._serverName, reverseProxyPort))
-        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+        (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
         (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
         self.assertTrue(receivedProxyPayload)
         self.assertTrue(receivedDNSData)
@@ -735,7 +738,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         for idx in range(5):
           receivedResponse = None
           toProxyQueue.put(response, True, 2.0)
-          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, useQueue=True, conn=conn)
+          (receivedQuery, receivedResponse) = self.sendDOHQuery(reverseProxyPort, self._serverName, reverseProxyBaseURL, query, response=response, caFile=self._caCert, conn=conn)
           (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
           self.assertTrue(receivedProxyPayload)
           self.assertTrue(receivedDNSData)
@@ -748,6 +751,108 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
           self.assertEqual(receivedResponse, response)
           self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
 
+    def testProxyDoTSeveralQueriesOverConnectionPPOutside(self):
+        """
+        Incoming Proxy Protocol: Several queries over the same connection (DoT, PP outside TLS)
+        """
+        name = 'several-queries.dot-outside.proxy-protocol-incoming.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+
+        toProxyQueue.put(response, True, 2.0)
+
+        wire = query.to_wire()
+
+        reverseProxyPort = pickAvailablePort()
+        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPOutsidePort])
+        reverseProxy.start()
+        time.sleep(1)
+
+        receivedResponse = None
+        conn = self.openTLSConnection(reverseProxyPort, self._serverName, self._caCert, timeout=2.0)
+        self.sendTCPQueryOverConnection(conn, query, response=response)
+        receivedResponse = self.recvTCPResponseOverConnection(conn)
+        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+        self.assertTrue(receivedProxyPayload)
+        self.assertTrue(receivedDNSData)
+        self.assertTrue(receivedResponse)
+
+        receivedQuery = dns.message.from_wire(receivedDNSData)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+
+        for idx in range(5):
+          receivedResponse = None
+          toProxyQueue.put(response, True, 2.0)
+          self.sendTCPQueryOverConnection(conn, query, response=response)
+          receivedResponse = self.recvTCPResponseOverConnection(conn)
+          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+          self.assertTrue(receivedProxyPayload)
+          self.assertTrue(receivedDNSData)
+          self.assertTrue(receivedResponse)
+
+          receivedQuery = dns.message.from_wire(receivedDNSData)
+          receivedQuery.id = query.id
+          receivedResponse.id = response.id
+          self.assertEqual(receivedQuery, query)
+          self.assertEqual(receivedResponse, response)
+          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+
+    def testProxyDoTSeveralQueriesOverConnectionPPInside(self):
+        """
+        Incoming Proxy Protocol: Several queries over the same connection (DoT, PP inside TLS)
+        """
+        name = 'several-queries.dot-inside.proxy-protocol-incoming.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+
+        toProxyQueue.put(response, True, 2.0)
+
+        wire = query.to_wire()
+
+        reverseProxyPort = pickAvailablePort()
+        tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+        tlsContext.load_cert_chain(self._serverCert, self._serverKey)
+        tlsContext.set_alpn_protocols(['dot'])
+        reverseProxy = threading.Thread(name='Mock Proxy Protocol Reverse Proxy', target=MockTCPReverseProxyAddingProxyProtocol, args=[reverseProxyPort, self._dotServerPPInsidePort, tlsContext, self._caCert, self._serverName])
+        reverseProxy.start()
+
+        receivedResponse = None
+        time.sleep(1)
+        conn = self.openTLSConnection(reverseProxyPort, self._serverName, self._caCert, timeout=2.0)
+
+        self.sendTCPQueryOverConnection(conn, query, response=response)
+        receivedResponse = self.recvTCPResponseOverConnection(conn)
+        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+        self.assertTrue(receivedProxyPayload)
+        self.assertTrue(receivedDNSData)
+        self.assertTrue(receivedResponse)
+
+        receivedQuery = dns.message.from_wire(receivedDNSData)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+
+        for idx in range(5):
+          receivedResponse = None
+          toProxyQueue.put(response, True, 2.0)
+          self.sendTCPQueryOverConnection(conn, query, response=response)
+          receivedResponse = self.recvTCPResponseOverConnection(conn)
+          (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
+          self.assertTrue(receivedProxyPayload)
+          self.assertTrue(receivedDNSData)
+          self.assertTrue(receivedResponse)
+
+          receivedQuery = dns.message.from_wire(receivedDNSData)
+          receivedQuery.id = query.id
+          receivedResponse.id = response.id
+          self.assertEqual(receivedQuery, query)
+          self.assertEqual(receivedResponse, response)
+
     @classmethod
     def tearDownClass(cls):
         cls._sock.close()
@@ -768,7 +873,6 @@ class TestProxyProtocolNotExpected(DNSDistTest):
     """
     # NORMAL responder, does not expect a proxy protocol payload!
     _config_params = ['_testServerPort']
-    _verboseMode = True
 
     def testNoHeader(self):
         """
@@ -910,7 +1014,6 @@ class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
     setACL( { "::1/128", "127.0.0.0/8" } )
     """
     _config_params = ['_proxyResponderPort', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_dohWithH2OServerPort', '_serverCert', '_serverKey']
-    _verboseMode = True
 
     def testTruncation(self):
         """
index 9056924231a6f53865801a359074f2d58941df25..12c92809144e1b7973696c9e00860d749eb6a5e3 100644 (file)
@@ -101,3 +101,166 @@ class TestSVCB(DNSDistTest):
             self.assertEqual(len(receivedResponse.additional), 2)
             self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
             self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+
+class TestSVCBViaFFI(DNSDistTest):
+
+    _config_template = """
+    local ffi = require("ffi")
+
+    function setSVC(record, port, mandatoryParam, alpn, v4Hint, v6Hint)
+      ffi.C.dnsdist_ffi_svc_record_parameters_set_port(record, port)
+      ffi.C.dnsdist_ffi_svc_record_parameters_add_mandatory_param(record, mandatoryParam)
+      ffi.C.dnsdist_ffi_svc_record_parameters_add_alpn(record, alpn, #alpn)
+      if v4Hint then
+        ffi.C.dnsdist_ffi_svc_record_parameters_add_ipv4_hint(record, v4Hint, #v4Hint)
+      end
+      if v6Hint then
+        ffi.C.dnsdist_ffi_svc_record_parameters_add_ipv6_hint(record, v6Hint, #v6Hint)
+      end
+    end
+
+    function generateSVC(target, priority, port, alpn, noDefaultALPN, v4Hint, v6Hint)
+      local recordPtr = ffi.new("dnsdist_ffi_svc_record_parameters* [1]")
+      local recordPtrOut = ffi.cast("dnsdist_ffi_svc_record_parameters**", recordPtr)
+      ffi.C.dnsdist_ffi_svc_record_parameters_new(target, priority, noDefaultALPN, recordPtrOut)
+      ffi.gc(recordPtrOut[0], ffi.C.dnsdist_ffi_svc_record_parameters_free)
+      -- 3 is the port parameter
+      setSVC(recordPtrOut[0], port, 3, alpn, v4Hint, v6Hint)
+      return recordPtrOut[0]
+    end
+
+    function basicSVC(dq)
+      local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+      SVCrecords[0] = generateSVC("dot.powerdns.com.", 1, 853, "dot", true, "192.0.2.1", "2001:db8::1")
+      SVCrecords[1] = generateSVC("doh.powerdns.com.", 2, 443, "h2", false, "192.0.2.2", "2001:db8::2")
+      local path = "/dns-query{?dns}"
+      ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+      local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+      if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+        return DNSAction.ServFail
+      end
+      return DNSAction.HeaderModify
+    end
+
+    addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("basic.svcb.tests.powerdns.com.")}, LuaFFIAction(basicSVC))
+
+    function noHintsSVC(dq)
+      local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+      SVCrecords[0] = generateSVC("dot.powerdns.com.", 1, 853, "dot", true, nil, nil)
+      SVCrecords[1] = generateSVC("doh.powerdns.com.", 2, 443, "h2", false, nil, nil)
+      local path = "/dns-query{?dns}"
+      ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+      local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+      if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+        return DNSAction.ServFail
+      end
+      return DNSAction.HeaderModify
+    end
+
+    addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("no-hints.svcb.tests.powerdns.com.")}, LuaFFIAction(noHintsSVC))
+
+    function effectiveTargetSVC(dq)
+      local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [2]")
+      SVCrecords[0] = generateSVC(".", 1, 853, "dot", true, "192.0.2.1", "2001:db8::1")
+      SVCrecords[1] = generateSVC(".", 2, 443, "h2", false, "192.0.2.1", "2001:db8::1")
+      local path = "/dns-query{?dns}"
+      ffi.C.dnsdist_ffi_svc_record_parameters_set_additional_param(SVCrecords[1], 7, path, #path)
+      local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+      if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 2, 60) then
+        return DNSAction.ServFail
+      end
+      return DNSAction.HeaderModify
+    end
+
+    addAction(AndRule{QTypeRule(64), SuffixMatchNodeRule("effective-target.svcb.tests.powerdns.com.")}, LuaFFIAction(effectiveTargetSVC))
+
+    function httpsSVC(dq)
+      local SVCrecords = ffi.new("dnsdist_ffi_svc_record_parameters* [1]")
+      SVCrecords[0] = generateSVC(".", 1, 8002, "h2", false, "192.0.2.2", "2001:db8::2")
+      local SVCrecordsPtr = ffi.cast("const dnsdist_ffi_svc_record_parameters**", SVCrecords)
+      if not ffi.C.dnsdist_ffi_dnsquestion_generate_svc_response(dq, SVCrecordsPtr, 1, 60) then
+        return DNSAction.ServFail
+      end
+      return DNSAction.HeaderModify
+    end
+
+    addAction(AndRule{QTypeRule(65), SuffixMatchNodeRule("https.svcb.tests.powerdns.com.")}, LuaFFIAction(httpsSVC))
+
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testBasic(self):
+        """
+        SVCB: Basic service binding
+        """
+        name = 'basic.svcb.tests.powerdns.com.'
+        query = dns.message.make_query(name, 64, 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertTrue(receivedResponse)
+            self.assertEqual(len(receivedResponse.answer), 1)
+            self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+            self.assertEqual(len(receivedResponse.additional), 4)
+            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
+            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
+            self.assertEqual(receivedResponse.additional[2], dns.rrset.from_text("doh.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
+            self.assertEqual(receivedResponse.additional[3], dns.rrset.from_text("dot.powerdns.com.", 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+
+    def testNoHints(self):
+        """
+        SVCB: No hints
+        """
+        name = 'no-hints.svcb.tests.powerdns.com.'
+        query = dns.message.make_query(name, 64, 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertTrue(receivedResponse)
+            self.assertEqual(len(receivedResponse.answer), 1)
+            self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+            self.assertEqual(len(receivedResponse.additional), 0)
+
+    def testEffectiveTarget(self):
+        """
+        SVCB: Effective target
+        """
+        name = 'effective-target.svcb.tests.powerdns.com.'
+        query = dns.message.make_query(name, 64, 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertTrue(receivedResponse)
+            self.assertEqual(len(receivedResponse.answer), 1)
+            self.assertEqual(receivedResponse.answer[0].rdtype, 64)
+            self.assertEqual(len(receivedResponse.additional), 2)
+            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1'))
+            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::1'))
+
+    def testHTTPS(self):
+        """
+        SVCB: HTTPS
+        """
+        name = 'https.svcb.tests.powerdns.com.'
+        query = dns.message.make_query(name, 65, 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertTrue(receivedResponse)
+            self.assertEqual(len(receivedResponse.answer), 1)
+            self.assertEqual(receivedResponse.answer[0].rdtype, 65)
+            self.assertEqual(len(receivedResponse.additional), 2)
+            self.assertEqual(receivedResponse.additional[0], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.2'))
+            self.assertEqual(receivedResponse.additional[1], dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:db8::2'))
index 9803ed550f961300ecfb656ede0eddd6edaa9a65..27c2de52fe19b6ac343eb6da5f0f30830217678f 100644 (file)
@@ -516,3 +516,40 @@ class TestPKCSTLSCertificate(DNSDistTest, TLSTests):
         cls.startResponders()
         cls.startDNSDist()
         cls.setUpSockets()
+
+class TestTLSTicketsKeyAddedCallback(DNSDistTest):
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+
+    _serverKey = 'server.key'
+    _serverCert = 'server.chain'
+    _serverName = 'tls.tests.dnsdist.org'
+    _caCert = 'ca.pem'
+    _tlsServerPort = pickAvailablePort()
+    _numberOfKeys = 5
+
+    _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+    _config_template = """
+    setKey("%s")
+    controlSocket("127.0.0.1:%s")
+
+    newServer{address="127.0.0.1:%s"}
+    addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl" })
+
+    callbackCalled = 0
+    function keyAddedCallback(key, keyLen)
+      callbackCalled = keyLen
+    end
+
+    """
+
+    def testLuaThreadCounter(self):
+        """
+        LuaThread: Test the lua newThread interface
+        """
+        self.sendConsoleCommand('setTicketsKeyAddedHook(keyAddedCallback)');
+        called = self.sendConsoleCommand('callbackCalled')
+        self.assertEqual(int(called), 0)
+        self.sendConsoleCommand("getTLSFrontend(0):rotateTicketsKey()")
+        called = self.sendConsoleCommand('callbackCalled')
+        self.assertGreater(int(called), 0)
index 3058cd7ff8d2acab7db00c6b7c52e0f3c701c6b6..8533744504bbe90d97f54f4db35c02daba67e519 100755 (executable)
@@ -6,36 +6,41 @@ import os.path
 import glob
 
 e = xml.etree.ElementTree.parse('pytest.xml')
-root = e.getroot()
+testsuites = e.getroot()
 
-for child in root:
-    if len(child):
+for testsuite in testsuites:
+    if len(testsuite):
         getstdout = False
-        for elem in child:
-            if elem.tag in ["failure", "error"]:
-                cls = child.get("classname")
-                name = child.get("name")
-                if '_' not in cls or '.' not in cls:
-                    print('Unexpected classname %s; name %s' % (cls, name))
-                    getstdout = True
-                    continue
+        for testcase in testsuite:
+            cls = testcase.get("classname")
+            name = testcase.get("name")
+            if '_' not in cls or '.' not in cls:
+                print('Unexpected classname %s; name %s' % (cls, name))
+                getstdout = True
+                continue
 
-                confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]]
-                for confdirname in confdirnames:
-                    confdir = os.path.join("configs", confdirname)
-                    recursorlog = os.path.join(confdir, "recursor.log")
-                    if os.path.exists(recursorlog):
-                        print("==============> %s <==============" % recursorlog)
-                        with open(recursorlog) as f:
-                            print(''.join(f.readlines()))
-                            authdirs = glob.glob(os.path.join(confdir, "auth-*"))
-                            for authdir in authdirs:
-                                authlog = os.path.join(authdir, "pdns.log")
-                                if os.path.exists(recursorlog):
-                                    print("==============> %s <==============" % authlog)
-                                    with open(authlog) as f:
-                                        print(''.join(f.readlines()))
-            if getstdout and elem.tag == 'system-out':
-                print("==============> STDOUT LOG FROM XML <==============")
-                print(elem.text)
-                print("==============> END STDOUT LOG FROM XML <==============")
+            confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]]
+            found = False
+            for confdirname in confdirnames:
+                confdir = os.path.join("configs", confdirname)
+                recursorlog = os.path.join(confdir, "recursor.log")
+                if os.path.exists(recursorlog):
+                    found = True
+                    for elem in testcase:
+                        if elem.tag in ["failure", "error"]:
+                            print("==============> %s <==============" % recursorlog)
+                            with open(recursorlog) as f:
+                                print(''.join(f.readlines()))
+                                authdirs = glob.glob(os.path.join(confdir, "auth-*"))
+                                for authdir in authdirs:
+                                    authlog = os.path.join(authdir, "pdns.log")
+                                    if os.path.exists(recursorlog):
+                                        print("==============> %s <==============" % authlog)
+                                        with open(authlog) as f:
+                                            print(''.join(f.readlines()))
+            if not found and confdirnames[0] != 'Flags': 
+                print("%s not found, configdir does not mach expected pattern" % confdirnames)
+        if getstdout and elem.tag == 'system-out':
+            print("==============> STDOUT LOG FROM XML <==============")
+            print(elem.text)
+            print("==============> END STDOUT LOG FROM XML <==============")
index 9ad7dfeca730e1786a7948463a6920407d11a36f..bb97883624fce73549da1d5123ef57f7899d6343 100644 (file)
@@ -12,6 +12,7 @@ import time
 import unittest
 import dns
 import dns.message
+import requests
 
 from proxyprotocol import ProxyProtocol
 
@@ -610,8 +611,14 @@ distributor-threads={threads}""".format(confdir=confdir,
             print(f"*** End startAuth log for {logFile} ***")
             raise AssertionError('%s failed (%d)' % (authcmd, cls._auths[ipaddress].returncode))
 
+    @classmethod
+    def checkConfdir(cls, confdir):
+        if cls.__name__ != 'FlagsTest' and os.path.basename(confdir) + 'Test' != cls.__name__:
+            raise AssertionError('conf dir ' + confdir + ' and ' + cls.__name__ + ' inconsistent with convention')
+
     @classmethod
     def generateRecursorConfig(cls, confdir):
+        cls.checkConfdir(confdir)
         params = tuple([getattr(cls, param) for param in cls._config_params])
         if len(params):
             print(params)
@@ -645,6 +652,7 @@ distributor-threads={threads}""".format(confdir=confdir,
 
     @classmethod
     def generateRecursorYamlConfig(cls, confdir, luaConfig=True):
+        cls.checkConfdir(confdir)
         params = tuple([getattr(cls, param) for param in cls._config_params])
         if len(params):
             print(params)
@@ -809,7 +817,7 @@ distributor-threads={threads}""".format(confdir=confdir,
         return message
 
     @classmethod
-    def sendTCPQuery(cls, query, timeout=2.0):
+    def sendTCPQuery(cls, query, timeout=2.0, decode=True, fwparams=dict()):
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         if timeout:
             sock.settimeout(timeout)
@@ -835,7 +843,9 @@ distributor-threads={threads}""".format(confdir=confdir,
 
         message = None
         if data:
-            message = dns.message.from_wire(data)
+            if not decode:
+                return data
+            message = dns.message.from_wire(data, **fwparams)
         return message
 
     @classmethod
@@ -1188,3 +1198,23 @@ distributor-threads={threads}""".format(confdir=confdir,
         if data:
             message = dns.message.from_wire(data)
         return message
+
+    def checkMetrics(self, map):
+        self.waitForTCPSocket("127.0.0.1", self._wsPort)
+        headers = {'x-api-key': self._apiKey}
+        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        count = 0
+        for entry in content:
+            for key, expected in map.items():
+                if entry['name'] == key:
+                    value = int(entry['value'])
+                    if callable(expected):
+                        self.assertTrue(expected(value))
+                    else:
+                        self.assertEqual(value, expected)
+                    count += 1
+        self.assertEqual(count, len(map))
index 1ec32b533fc0eb64d6e3c67d56aa4aca6c58a2f0..6123ed7b4e21924b9a16e2515afc420da9c2d83a 100644 (file)
@@ -3,6 +3,6 @@ pytest
 protobuf>=2.5; sys_platform != 'darwin'
 protobuf>=3.0; sys_platform == 'darwin'
 pyasn1==0.4.8
-pysnmp>=4.3.4
+pysnmp>=5,<6
 requests>=2.1.0
 Twisted>0.15.0
index b4ded3d9b24585e72f7cd46d8b36635b3823c566..adee05c4617320de7d1bdc9b02b8fb9315c9446b 100755 (executable)
@@ -27,7 +27,7 @@ export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
 export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
 export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
 
-LIBFAKETIME_DEFAULT=/usr/lib/x86_64-linux-gnu/faketime/libfaketimeMT.so.1 # ubuntu default
+LIBFAKETIME_DEFAULT=/usr/lib/$(arch)-linux-gnu/faketime/libfaketimeMT.so.1 # ubuntu default
 LIBAUTHBIND_DEFAULT=/usr/lib/authbind/libauthbind.so.1
 if [ $(uname -s) = "Darwin" ]; then
   # macOS is not /really/ supported here; it works for some tests, and then you might need sudo.
index 07fc05aa154aa6827d47654f4312b0d2fcaf670d..90a6fc08ce08db0c21ae386210e4570ced684556 100644 (file)
@@ -23,7 +23,7 @@ class APIRecursorTest(RecursorTest):
         cls.tearDownRecursor()
 
 class APIAllowedRecursorTest(APIRecursorTest):
-    _confdir = 'API'
+    _confdir = 'APIAllowedRecursor'
     _wsPort = 8042
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
@@ -48,7 +48,7 @@ api-key=%s
         self.assertTrue(r.json())
 
 class APIDeniedRecursorTest(APIRecursorTest):
-    _confdir = 'API'
+    _confdir = 'APIDeniedRecursor'
     _wsPort = 8042
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
index 49a14d081b91a8aace492aceb833e4cb7bf81d98..b09bf3e21d99873fea23cc9f678f6c2b9bb1473c 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testAdditionalsDefault(RecursorTest):
+class AdditionalsDefaultTest(RecursorTest):
     _confdir = 'AdditionalsDefault'
 
     _config_template = """
@@ -40,7 +40,7 @@ class testAdditionalsDefault(RecursorTest):
         self.assertRRsetInAdditional(res, adds1)
         self.assertRRsetInAdditional(res, adds2)
 
-class testAdditionalsResolveImmediately(RecursorTest):
+class AdditionalsResolveImmediatelyTest(RecursorTest):
     _confdir = 'AdditionalsResolveImmediately'
     _config_template = """
     dnssec=validate
@@ -102,7 +102,7 @@ class testAdditionalsResolveImmediately(RecursorTest):
         self.assertRRsetInAdditional(res, adds7)
         self.assertMatchingRRSIGInAdditional(res, adds7)
 
-class testAdditionalsResolveCacheOnly(RecursorTest):
+class AdditionalsResolveCacheOnlyTest(RecursorTest):
     _confdir = 'AdditionalsResolveCacheOnly'
     _config_template = """
     dnssec=validate
index 88be1855002ef54d3e294fc7cf692df3a3c45847..fb1f046e932bae38b705a81f96eb4a7aa8b3ba41 100644 (file)
@@ -97,7 +97,7 @@ class AggressiveNSECCacheBase(RecursorTest):
         self.assertEqual(res.options[0].otype, 15)
         self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
-class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
+class AggressiveNSECCacheNSECTest(AggressiveNSECCacheBase):
     _confdir = 'AggressiveNSECCacheNSEC'
     __test__ = True
 
@@ -235,7 +235,7 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
         self.assertEqual(res.options[0].otype, 15)
         self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(9, b''))
 
-class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
+class AggressiveNSECCacheNSEC3Test(AggressiveNSECCacheBase):
     _confdir = 'AggressiveNSECCacheNSEC3'
     __test__ = True
 
index f1e9ab6b07009772507dfaedfd857733a4be2fce..1dcae1f376bbec6b98d37c9934b4b4f36a1d1b15 100644 (file)
@@ -3,7 +3,7 @@ import os
 import socket
 from recursortests import RecursorTest
 
-class testAnyBind(RecursorTest):
+class AnyBindTest(RecursorTest):
     _confdir = 'AnyBind'
 
     _config_template = """dnssec=validate
@@ -18,7 +18,7 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testAnyBind, cls).generateRecursorConfig(confdir)
+        super(AnyBindTest, cls).generateRecursorConfig(confdir)
 
     @classmethod
     def setUpSockets(cls):
index f9ed9450cd0b99058a66bd45c8c21e29340aa3ca..71d0365c33a7416881408220663a0bd0d2d7d7fb 100644 (file)
@@ -8,7 +8,7 @@ from queue import Queue
 
 from recursortests import RecursorTest
 
-class TestCarbon(RecursorTest):
+class CarbonTest(RecursorTest):
     _confdir = 'Carbon'
     _carbonNamespace = 'NS'
     _carbonInstance = 'Instance'
diff --git a/regression-tests.recursor-dnssec/test_Chain.py b/regression-tests.recursor-dnssec/test_Chain.py
new file mode 100644 (file)
index 0000000..6c20937
--- /dev/null
@@ -0,0 +1,54 @@
+import dns
+import os
+import time
+from recursortests import RecursorTest
+
+class ChainTest(RecursorTest):
+    """
+    These regression tests test the chaining of outgoing requests.
+    """
+    _confdir = 'Chain'
+    _wsPort = 8042
+    _wsTimeout = 2
+    _wsPassword = 'secretpassword'
+    _apiKey = 'secretapikey'
+
+    _config_template = """dnssec=validate
+    trace=no
+    devonly-regression-test-mode
+    webserver=yes
+    webserver-port=%d
+    webserver-address=127.0.0.1
+    webserver-password=%s
+    api-key=%s
+""" % (_wsPort, _wsPassword, _apiKey)
+
+    def testBasic(self):
+        """
+        Tests the case of #14624. Sending many equal requests could lead to ServFail because of clashing
+        waiter ids.
+        """
+        # We actually do not check all responses, as experience show that packets may be dropped by the OS
+        # Instead, we check if a few counters in rec have the expected values.
+        count = 200
+        name = '9.delay1.example.'
+        exp = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', 'a')
+        for i in range(count):
+            query = dns.message.make_query(name, 'TXT', want_dnssec=True)
+            query.flags |= dns.flags.AD
+            self._sock.send(query.to_wire())
+
+        # Just check one, as OS emptying of socket buffers can work against us
+        data = self._sock.recv(4096)
+        res = dns.message.from_wire(data)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageIsAuthenticated(res)
+        self.assertRRsetInAnswer(res, exp)
+        self.assertMatchingRRSIGInAnswer(res, exp)
+        time.sleep(1)
+
+        self.checkMetrics({
+            'max-chain-length': (lambda x: x <= count-1), # first request has count - 1 requests chained to it
+            'servfail-answers': 0,
+            'noerror-answers': (lambda x: x <= count),
+        })
index abf6fdb23ac20f726ab1a04693af5514869bbadc..c6b70d5c0062735ae4be9b604c8c23c7191ce733 100644 (file)
@@ -3,7 +3,7 @@ import os
 
 from recursortests import RecursorTest
 
-class DNS64RecursorTest(RecursorTest):
+class DNS64Test(RecursorTest):
 
     _confdir = 'DNS64'
     _config_template = """
@@ -32,9 +32,11 @@ class DNS64RecursorTest(RecursorTest):
 @ 3600 IN SOA {soa}
 www 3600 IN A 192.0.2.42
 www 3600 IN TXT "does exist"
+txt 3600 IN TXT "a and aaaa do not exist"
 aaaa 3600 IN AAAA 2001:db8::1
 cname 3600 IN CNAME cname2.example.dns64.
 cname2 3600 IN CNAME www.example.dns64.
+cname3 3600 IN CNAME txt.example.dns64.
 formerr 3600 IN A 192.0.2.43
 """.format(soa=cls._SOA))
 
@@ -52,7 +54,7 @@ formerr 3600 IN A 192.0.2.43
 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2 IN PTR aaaa.example.dns64.
 """.format(soa=cls._SOA))
 
-        super(DNS64RecursorTest, cls).generateRecursorConfig(confdir)
+        super(DNS64Test, cls).generateRecursorConfig(confdir)
 
     # this type (A) exists for this name
     def testExistingA(self):
@@ -107,6 +109,22 @@ formerr 3600 IN A 192.0.2.43
             for expected in expectedResults:
                 self.assertRRsetInAnswer(res, expected)
 
+    # there is a CNAME from the name to a name that is NODATA for both A and AAAA
+    # so we should get a NODATA with a single SOA record (#14362)
+    def testCNAMEToNoData(self):
+        qname = 'cname3.example.dns64.'
+
+        expectedAnswer = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'CNAME', 'txt.example.dns64.')
+        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertEqual(len(res.answer), 1)
+            self.assertEqual(len(res.authority), 1)
+            self.assertRRsetInAnswer(res, expectedAnswer)
+            self.assertAuthorityHasSOA(res)
+
     # this type (AAAA) does not exist for this name and there is no A record either, we should get a NXDomain
     def testNXD(self):
         qname = 'nxd.example.dns64.'
@@ -117,6 +135,18 @@ formerr 3600 IN A 192.0.2.43
             res = sender(query)
             self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
 
+    # this type (AAAA) does not exist for this name and there is no A record either, we should get a NODATA as TXT does exist
+    def testNoData(self):
+        qname = 'txt.example.dns64.'
+
+        query = dns.message.make_query(qname, 'AAAA', want_dnssec=True)
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query, 2.0, True, {"one_rr_per_rrset": True}) # we want to detect dups
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertEqual(len(res.answer), 0)
+            self.assertEqual(len(res.authority), 1)
+
     # there is an AAAA record, we should get it
     def testExistingAAAA(self):
         qname = 'aaaa.example.dns64.'
index 29a75cf1e24c6a1efba166bc784be7e2458bd161..77710243ee223098565c63c26c61347e65434fc1 100644 (file)
@@ -116,7 +116,7 @@ ecs-add-for=0.0.0.0/0
     def tearDownClass(cls):
         cls.tearDownRecursor()
 
-class testNoECS(ECSTest):
+class NoECSTest(ECSTest):
     _confdir = 'NoECS'
 
     _config_template = """edns-subnet-allow-list=
@@ -141,7 +141,7 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testIncomingNoECS(ECSTest):
+class IncomingNoECSTest(ECSTest):
     _confdir = 'IncomingNoECS'
 
     _config_template = """edns-subnet-allow-list=
@@ -169,7 +169,7 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, scopeZeroResponse=True)
 
-class testECSByName(ECSTest):
+class ECSByNameTest(ECSTest):
     _confdir = 'ECSByName'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
@@ -200,7 +200,7 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testECSByNameLarger(ECSTest):
+class ECSByNameLargerTest(ECSTest):
     _confdir = 'ECSByNameLarger'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
@@ -234,8 +234,8 @@ ecs-ipv6-cache-bits=128
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testECSByNameSmaller(ECSTest):
-    _confdir = 'ECSByNameLarger'
+class ECSByNameSmallerTest(ECSTest):
+    _confdir = 'ECSByNameSmaller'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 ecs-ipv4-bits=16
@@ -261,8 +261,8 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testIncomingECSByName(ECSTest):
-    _confdir = 'ECSIncomingByName'
+class IncomingECSByNameTest(ECSTest):
+    _confdir = 'IncomingECSByName'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -301,8 +301,8 @@ ecs-ipv6-cache-bits=128
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
-class testIncomingECSByNameLarger(ECSTest):
-    _confdir = 'ECSIncomingByNameLarger'
+class IncomingECSByNameLargerTest(ECSTest):
+    _confdir = 'IncomingECSByNameLarger'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -333,8 +333,8 @@ ecs-ipv6-cache-bits=128
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
-class testIncomingECSByNameSmaller(ECSTest):
-    _confdir = 'ECSIncomingByNameSmaller'
+class IncomingECSByNameSmallerTest(ECSTest):
+    _confdir = 'IncomingECSByNameSmaller'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -364,8 +364,8 @@ ecs-ipv6-cache-bits=128
         self.sendECSQuery(query, expected, ttlECS)
 
 @unittest.skipIf(not have_ipv6(), "No IPv6")
-class testIncomingECSByNameV6(ECSTest):
-    _confdir = 'ECSIncomingByNameV6'
+class IncomingECSByNameV6Test(ECSTest):
+    _confdir = 'IncomingECSByNameV6'
 
     _config_template = """edns-subnet-allow-list=ecs-echo.example.
 use-incoming-edns-subnet=yes
@@ -397,7 +397,7 @@ forward-zones=ecs-echo.example=[::1]:53000
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected, ttlECS)
 
-class testECSNameMismatch(ECSTest):
+class ECSNameMismatchTest(ECSTest):
     _confdir = 'ECSNameMismatch'
 
     _config_template = """edns-subnet-allow-list=not-the-right-name.example.
@@ -422,7 +422,7 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testECSByIP(ECSTest):
+class ECSByIPTest(ECSTest):
     _confdir = 'ECSByIP'
 
     _config_template = """edns-subnet-allow-list=%s.21
@@ -448,8 +448,8 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testIncomingECSByIP(ECSTest):
-    _confdir = 'ECSIncomingByIP'
+class IncomingECSByIPTest(ECSTest):
+    _confdir = 'IncomingECSByIP'
 
     _config_template = """edns-subnet-allow-list=%s.21
 use-incoming-edns-subnet=yes
@@ -488,7 +488,7 @@ ecs-ipv6-cache-bits=128
 
         self.sendECSQuery(query, expected)
 
-class testECSIPMismatch(ECSTest):
+class ECSIPMismatchTest(ECSTest):
     _confdir = 'ECSIPMismatch'
 
     _config_template = """edns-subnet-allow-list=192.0.2.1
@@ -514,8 +514,8 @@ forward-zones=ecs-echo.example=%s.21
         query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512)
         self.sendECSQuery(query, expected)
 
-class testECSWithProxyProtocoldRecursorTest(ECSTest):
-    _confdir = 'ECSWithProxyProtocol'
+class ECSWithProxyProtocolRecursorTest(ECSTest):
+    _confdir = 'ECSWithProxyProtocolRecursor'
     _config_template = """
     ecs-add-for=2001:db8::1/128
     edns-subnet-allow-list=ecs-echo.example.
@@ -535,7 +535,7 @@ class testECSWithProxyProtocoldRecursorTest(ECSTest):
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
 
-class testTooLargeToAddZeroScope(RecursorTest):
+class TooLargeToAddZeroScopeTest(RecursorTest):
 
     _confdir = 'TooLargeToAddZeroScope'
     _config_template = """
@@ -573,7 +573,7 @@ dnssec=validate
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        super(testTooLargeToAddZeroScope, cls).generateRecursorConfig(confdir)
+        super(TooLargeToAddZeroScopeTest, cls).generateRecursorConfig(confdir)
 
     def testTooLarge(self):
         qname = 'toolarge.ecs.'
index 01ac82462fcff46cd74e523ed4bada569b2d5076..e9b4ccb4aa4f00e42ed5c197506c16e61bd95bd7 100644 (file)
@@ -111,10 +111,11 @@ edns-outgoing-bufsize=%d
             self.assertEqual(message.edns, -1)
 
 
-class EDNSBufferTest16801680(EDNSBufferTest):
+class EDNSBuffer16801680Test(EDNSBufferTest):
     """
     Runs test cases 1, 2, 5, 6, 7, 8
     """
+    _confdir = 'EDNSBuffer16801680'
 
     def testEdnsBufferTestCase01(self):
         query = self.getMessage('01', 4096)
@@ -164,7 +165,7 @@ class EDNSBufferTest16801680(EDNSBufferTest):
             message = dns.message.from_wire(raw)
             self.checkEDNS(message, 512)
 
-class EDNSBufferTest16801681(EDNSBufferTest):
+class EDNSBuffer16801681Test(EDNSBufferTest):
     """
     Runs test case 3
     """
@@ -188,7 +189,7 @@ edns-outgoing-bufsize=%d
             self.checkEDNS(message, 512)
 
 
-class EDNSBufferTest16801679(EDNSBufferTest):
+class EDNSBuffer16801679Test(EDNSBufferTest):
     """
     Runs test case 4
     """
index e9645aaf7aea502e9451aa3d2757f5dcdb5fc1bc..55de943a1ad65e688dda0aa6cc52a8e26d032d39 100644 (file)
@@ -9,6 +9,8 @@ from recursortests import RecursorTest
 
 class RecursorEDNSPaddingTest(RecursorTest):
 
+    _confdir = 'RecursorEDNSPadding'
+
     @classmethod
     def setUpClass(cls):
         cls.setUpSockets()
@@ -209,7 +211,7 @@ packetcache-ttl=60
 
 class PaddingNotAllowedAlwaysTest(RecursorEDNSPaddingTest):
 
-    _confdir = 'PaddingAlwaysNotAllowed'
+    _confdir = 'PaddingNotAllowedAlways'
     _config_template = """edns-padding-from=127.0.0.2
 edns-padding-mode=always
 edns-padding-tag=7830
@@ -299,7 +301,7 @@ class PaddingAllowedAlwaysSameTagTest(RecursorEDNSPaddingTest):
     # we use the default tag (0) for padded responses, which will cause
     # the same packet cache entry (with padding ) to be returned to a client
     # not allowed by the edns-padding-from list
-    _confdir = 'PaddingAlwaysSameTag'
+    _confdir = 'PaddingAllowedAlwaysSameTag'
     _config_template = """edns-padding-from=127.0.0.1
 edns-padding-mode=always
 edns-padding-tag=0
index 14c4948ecdc1e0fbdee469a82abc43bdc116c59f..06be8af03a8c2464e31672158a8d7e71e5f566b1 100644 (file)
@@ -8,7 +8,7 @@ import extendederrors
 from recursortests import RecursorTest
 
 
-class testExpired(RecursorTest):
+class ExpiredTest(RecursorTest):
     """This regression test starts the authoritative servers with a clock that is
     set 15 days into the past. Hence, the recursor must reject the signatures
     because they are expired.
@@ -26,7 +26,7 @@ class testExpired(RecursorTest):
 
         self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
 
-class testExpiredWithEDE(RecursorTest):
+class ExpiredWithEDETest(RecursorTest):
     """This regression test starts the authoritative servers with a clock that is
     set 15 days into the past. Hence, the recursor must reject the signatures
     because they are expired.
index d2625137f37063d647526d6a04696c0a102673d4..635c2c579c4c4e5c53a54da5b6d7946ac3c7697a 100644 (file)
@@ -5,7 +5,7 @@ import pytest
 
 from recursortests import RecursorTest
 
-class ExtendedErrorsRecursorTest(RecursorTest):
+class ExtendedErrorsTest(RecursorTest):
 
     _confdir = 'ExtendedErrors'
     _config_template = """
@@ -81,9 +81,8 @@ extended-resolution-errors=yes
 *.rpz.extended.zone.rpz. 60 IN CNAME .
 """.format(soa=cls._SOA))
 
-        super(ExtendedErrorsRecursorTest, cls).generateRecursorConfig(confdir)
+        super(ExtendedErrorsTest, cls).generateRecursorConfig(confdir)
 
-    @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
     def testNotIncepted(self):
         qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
         query = dns.message.make_query(qname, 'A', want_dnssec=True)
@@ -97,7 +96,6 @@ extended-resolution-errors=yes
             self.assertEqual(res.options[0].otype, 15)
             self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(8, b''))
 
-    @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
     def testExpired(self):
         qname = 'sigexpired.bad-dnssec.wb.sidnlabs.nl.'
         query = dns.message.make_query(qname, 'A', want_dnssec=True)
@@ -124,7 +122,6 @@ extended-resolution-errors=yes
             self.assertEqual(res.options[0].otype, 15)
             self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(6, b''))
 
-    @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
     def testBogus(self):
         qname = 'bogussig.ok.bad-dnssec.wb.sidnlabs.nl.'
         query = dns.message.make_query(qname, 'A', want_dnssec=True)
@@ -209,9 +206,9 @@ extended-resolution-errors=yes
         self.assertEqual(res.options[0].otype, 15)
         self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(10, b'Extra text from Lua!'))
 
-class NoExtendedErrorsRecursorTest(RecursorTest):
+class NoExtendedErrorsTest(RecursorTest):
 
-    _confdir = 'ExtendedErrorsDisabled'
+    _confdir = 'NoExtendedErrors'
     _config_template = """
 dnssec=validate
 extended-resolution-errors=no
@@ -237,9 +234,8 @@ extended-resolution-errors=no
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        super(NoExtendedErrorsRecursorTest, cls).generateRecursorConfig(confdir)
+        super(NoExtendedErrorsTest, cls).generateRecursorConfig(confdir)
 
-    @pytest.mark.skip(reason="sidnlabs no longer serves thiss until further notice")
     def testNotIncepted(self):
         qname = 'signotincepted.bad-dnssec.wb.sidnlabs.nl.'
         query = dns.message.make_query(qname, 'A', want_dnssec=True)
index a550b9001d52aa13d16c59605779120b6da1938f..702d44de1d970bf46edc2db0c9cf5c61291a3409 100644 (file)
@@ -5,7 +5,7 @@ import dns
 from recursortests import RecursorTest
 
 
-class TestFlags(RecursorTest):
+class FlagsTest(RecursorTest):
     _confdir = 'Flags'
     _config_template = """dnssec=%s"""
     _config_params = ['_dnssec_setting']
index 4b61759d712ddf6c68398d26c256fa680d566ed5..772f72ec60ef8eee0f4bded0f138304726d67953 100644 (file)
@@ -7,7 +7,7 @@ from twisted.internet.protocol import DatagramProtocol
 from twisted.internet import reactor
 import threading
 
-class testInterop(RecursorTest):
+class InteropTest(RecursorTest):
     _confdir = 'Interop'
 
     _config_template = """dnssec=validate
@@ -151,7 +151,7 @@ forward-zones+=undelegated.insecure.example=%s.12
             cls._UDPResponder.setDaemon(True)
             cls._UDPResponder.start()
 
-class testInteropProcess(RecursorTest):
+class InteropProcessTest(RecursorTest):
     _confdir = 'InteropProcess'
 
     _config_template = """dnssec=process
index 571d0746624de762a9bbab96eed20316e1167cbe..7c8630e14212121fa30ac455b33ef0a753d857ca 100644 (file)
@@ -5,7 +5,7 @@ import struct
 
 from recursortests import RecursorTest
 
-class testKeepOpenTCP(RecursorTest):
+class KeepOpenTCPTest(RecursorTest):
     _confdir = 'KeepOpenTCP'
 
     _config_template = """dnssec=validate
@@ -21,7 +21,7 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testKeepOpenTCP, cls).generateRecursorConfig(confdir)
+        super(KeepOpenTCPTest, cls).generateRecursorConfig(confdir)
 
     def sendTCPQueryKeepOpen(cls, sock, query, timeout=2.0):
         try:
index 9a58d97752f9bbd1bd2acc03f85f9e3e5b7e4be3..c53e31238d1cc6cd50e1d5f7dfcfe10d29aca35a 100644 (file)
@@ -5,7 +5,7 @@ import time
 
 from recursortests import RecursorTest
 
-class testLockedCache(RecursorTest):
+class LockedCacheTest(RecursorTest):
     """
     Test that a locked cached entry is *not* updated by the same additional encountered in a second query
     """
@@ -55,7 +55,7 @@ class testLockedCache(RecursorTest):
         ttl2 = self.getCacheTTL()
         self.assertGreater(ttl1, ttl2)
 
-class testNotLockedCache(RecursorTest):
+class NotLockedCacheTest(RecursorTest):
     """
     Test that a not locked cached entry *is* updated by the same additional encountered in a second query
     """
index dad74051f5d687abc1ccdbefa5e2be0fc2bab903..23750b4caa7263ddbad95953ba2bc465e0c66eb2 100644 (file)
@@ -11,7 +11,7 @@ from twisted.internet import reactor
 from recursortests import RecursorTest
 
 class GettagRecursorTest(RecursorTest):
-    _confdir = 'LuaGettag'
+    _confdir = 'GettagRecursor'
     _config_template = """
     log-common-errors=yes
     gettag-needs-edns-options=yes
@@ -209,7 +209,7 @@ class GettagRecursorTest(RecursorTest):
         self.assertResponseMatches(query, expected, res)
 
 class GettagRecursorDistributesQueriesTest(GettagRecursorTest):
-    _confdir = 'LuaGettagDistributes'
+    _confdir = 'GettagRecursorDistributesQueries'
     _config_template = """
     log-common-errors=yes
     gettag-needs-edns-options=yes
@@ -247,7 +247,7 @@ class UDPHooksResponder(DatagramProtocol):
         self.transport.write(response.to_wire(), address)
 
 class LuaHooksRecursorTest(RecursorTest):
-    _confdir = 'LuaHooks'
+    _confdir = 'LuaHooksRecursor'
     _config_template = """
 forward-zones=luahooks.example=%s.23
 log-common-errors=yes
@@ -446,7 +446,7 @@ quiet=no
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
 
 class LuaHooksRecursorDistributesTest(LuaHooksRecursorTest):
-    _confdir = 'LuaHooksDistributes'
+    _confdir = 'LuaHooksRecursorDistributes'
     _config_template = """
 forward-zones=luahooks.example=%s.23
 log-common-errors=yes
@@ -458,7 +458,7 @@ quiet=no
 class LuaDNS64Test(RecursorTest):
     """Tests the dq.followupAction("getFakeAAAARecords")"""
 
-    _confdir = 'lua-dns64'
+    _confdir = 'LuaDNS64'
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -519,7 +519,7 @@ class GettagFFIDNS64Test(RecursorTest):
        - DNS64 should kick in, generating an AAAA
     """
 
-    _confdir = 'gettagffi-rpz-dns64'
+    _confdir = 'GettagFFIDNS64'
     _config_template = """
     dns64-prefix=64:ff9b::/96
     """
@@ -572,7 +572,7 @@ dns64.test.powerdns.com.zone.rpz. 60 IN A 192.0.2.42
 class PDNSRandomTest(RecursorTest):
     """Tests if pdnsrandom works"""
 
-    _confdir = 'pdnsrandom'
+    _confdir = 'PDNSRandom'
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -600,7 +600,7 @@ class PDNSRandomTest(RecursorTest):
 class PDNSFeaturesTest(RecursorTest):
     """Tests if pdns_features works"""
 
-    _confdir = 'pdnsfeatures'
+    _confdir = 'PDNSFeatures'
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -628,7 +628,7 @@ class PDNSFeaturesTest(RecursorTest):
 class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
     """Tests that we can generate answers from gettag"""
 
-    _confdir = 'gettaganswers'
+    _confdir = 'PDNSGeneratingAnswerFromGettag'
     _config_template = """
     """
     _lua_dns_script_file = """
@@ -685,7 +685,7 @@ class PDNSGeneratingAnswerFromGettagTest(RecursorTest):
 class PDNSValidationStatesTest(RecursorTest):
     """Tests that we have access to the validation states from Lua"""
 
-    _confdir = 'validation-states-from-lua'
+    _confdir = 'PDNSValidationStates'
     _config_template = """
 dnssec=validate
 """
@@ -751,7 +751,7 @@ class PolicyEventFilterOnFollowUpTest(RecursorTest):
     """Tests the interaction between RPZ and followup queries (dns64, followCNAME)
     """
 
-    _confdir = 'policyeventfilter-followup'
+    _confdir = 'PolicyEventFilterOnFollowUp'
     _config_template = """
     """
     _lua_config_file = """
@@ -802,7 +802,7 @@ class PolicyEventFilterOnFollowUpWithNativeDNS64Test(RecursorTest):
     """Tests the interaction between followup queries and native dns64
     """
 
-    _confdir = 'policyeventfilter-followup-dns64'
+    _confdir = 'PolicyEventFilterOnFollowUpWithNativeDNS64'
     _config_template = """
     dns64-prefix=1234::/96
     """
@@ -838,7 +838,7 @@ class PolicyEventFilterOnFollowUpWithNativeDNS64Test(RecursorTest):
 class LuaPostResolveFFITest(RecursorTest):
     """Tests postresolve_ffi interface"""
 
-    _confdir = 'LuaPostResolveFFITest'
+    _confdir = 'LuaPostResolveFFI'
     _config_template = """
     """
     _lua_dns_script_file = """
index f2268d7f32dbbcfde0b2af8ffa0cd985ff0eb5db..44b1672d856344c22dd9e262e62dd37040542240 100644 (file)
@@ -1,7 +1,7 @@
 import dns
 from recursortests import RecursorTest
 
-class testNTA(RecursorTest):
+class NTATest(RecursorTest):
     _confdir = 'NTA'
 
     _config_template = """dnssec=validate"""
index 018990b71b654dc8d43ec88b57a3f285edecbf14..a4b2525d8f551755aaa7ed0ab5112a1227bf34c0 100644 (file)
@@ -5,7 +5,7 @@ import subprocess
 import time
 from recursortests import RecursorTest
 
-class testNamedForward(RecursorTest):
+class NamedForwardTest(RecursorTest):
     """
     This is forwarding test using a name as target
     """
@@ -13,7 +13,7 @@ class testNamedForward(RecursorTest):
     _confdir = 'NamedForward'
     _config_template = """
 dnssec=validate
-forward-zones-recurse=.=dns.quad9.net
+forward-zones-recurse=.=dns.quad9.net;dns.google;one.one.one.one
 system-resolver-ttl=10
     """
 
@@ -41,7 +41,7 @@ system-resolver-ttl=10
         self.assertMatchingRRSIGInAnswer(res, expected)
 
 @unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
-class testNamedForwardWithChange(RecursorTest):
+class NamedForwardWithChangeTest(RecursorTest):
     """
     This is forwarding test using a name as target and a changing resolve
     """
index 5e9e9131e1fc7e9e8c24bd995359de5049d6c110..630b717bc666f42c078db226c1214b5336cabde8 100644 (file)
@@ -2,7 +2,7 @@ import dns
 from recursortests import RecursorTest
 
 
-class testNoDS(RecursorTest):
+class NoDSTest(RecursorTest):
     _confdir = 'NoDS'
 
     _config_template = """dnssec=validate"""
index 17b36e5ec6cd76d345ec974dd95f2f2cbef6b6d2..b944d8cfe648acfaa31ad55ec42d0335eb0ac8eb 100644 (file)
@@ -1,7 +1,7 @@
 import dns
 from recursortests import RecursorTest
 
-class testNoDSYAML(RecursorTest):
+class NoDSYAMLTest(RecursorTest):
     _confdir = 'NoDSYAML'
 
     _config_template = """
@@ -11,7 +11,7 @@ dnssec:
 """
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        super(testNoDSYAML, cls).generateRecursorYamlConfig(confdir, False)
+        super(NoDSYAMLTest, cls).generateRecursorYamlConfig(confdir, False)
 
     def testNoDSInsecure(self):
         """#4430 When the root DS is removed, the result must be Insecure"""
index b2164cf3409b92a77b26e1fe2861dcbe5aa9c9ff..a6b41b1a47173ed1685f29a10e0019d43e2b275d 100644 (file)
@@ -7,7 +7,7 @@ import dns
 from recursortests import RecursorTest
 
 
-class testNotYetValid(RecursorTest):
+class NotYetValidTest(RecursorTest):
     """This regression test starts the authoritative servers with a clock that is
     set 15 days into the future. Hence, the recursor must reject the signatures
     because they are not yet valid.
index 622ad37ec6c2e469caa0e8040f65b7ccfa6fdf8b..7b65e1dda432187ae703d0d690ea756f0c9c11cc 100644 (file)
@@ -7,7 +7,7 @@ import subprocess
 
 from recursortests import RecursorTest
 
-class NotifyRecursorTest(RecursorTest):
+class NotifyTest(RecursorTest):
 
     _auth_zones = {
         '8': {'threads': 1,
@@ -46,7 +46,7 @@ d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
 """.format(soa=cls._SOA))
-        super(NotifyRecursorTest, cls).generateRecursorConfig(confdir)
+        super(NotifyTest, cls).generateRecursorConfig(confdir)
 
     def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
         headers = {'x-api-key': self._apiKey}
index 9c18017011a0475182288e56e5ae7cc060ba255c..24d225e503c090aa3e7f660d17e96f797c581693 100644 (file)
@@ -3,7 +3,7 @@ import os
 import time
 from recursortests import RecursorTest
 
-class testOOOTCP(RecursorTest):
+class OOOTCPTest(RecursorTest):
     _confdir = 'OOOTCP'
 
     _config_template = """dnssec=validate
@@ -11,7 +11,7 @@ class testOOOTCP(RecursorTest):
 
     @classmethod
     def generateRecursorConfig(cls, confdir):
-        super(testOOOTCP, cls).generateRecursorConfig(confdir)
+        super(OOOTCPTest, cls).generateRecursorConfig(confdir)
 
     def testOOOVeryBasic(self):
         expected = {}
index ba8c102ddde4b97e407817d65d22cdcc976817c4..61472d014b446c83040e1df0e384bc0b844c74cf 100644 (file)
@@ -7,7 +7,7 @@ import subprocess
 
 from recursortests import RecursorTest
 
-class PacketCacheRecursorTest(RecursorTest):
+class PacketCacheTest(RecursorTest):
 
     _auth_zones = {
         '8': {'threads': 1,
@@ -44,7 +44,7 @@ d 3600 IN A 192.0.2.42
 e 3600 IN A 192.0.2.42
 f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
 """.format(soa=cls._SOA))
-        super(PacketCacheRecursorTest, cls).generateRecursorConfig(confdir)
+        super(PacketCacheTest, cls).generateRecursorConfig(confdir)
 
     def checkPacketCacheMetrics(self, expectedHits, expectedMisses):
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
index dc82f80fd7e54bb45938add3c9a498b2f63ed764..c734b27f63f0f9a0c82bfdfc39107e71085b26db 100644 (file)
@@ -58,7 +58,7 @@ class RecPrometheusTest(RecursorTest):
             raise AssertionError('%s returned an unexpected output. Faulty line is "%s", complete content is "%s"' % (testcmd, line, output))
 
 class BasicPrometheusTest(RecPrometheusTest):
-    _confdir = 'Prometheus'
+    _confdir = 'BasicPrometheus'
     _wsPort = 8042
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
index 4a5007488bb5ef6c5c392bfbae4ca3e0a3ceb8cf..db6828dfb3d1780894c50c984a417123ed5bf95b 100644 (file)
@@ -190,6 +190,7 @@ class TestRecursorProtobuf(RecursorTest):
         # because it doesn't keep the information around.
         self.assertTrue(msg.HasField('to'))
         self.assertEqual(socket.inet_ntop(socket.AF_INET, msg.to), to)
+        self.assertTrue(msg.HasField('workerId'))
         self.assertTrue(msg.HasField('question'))
         self.assertTrue(msg.question.HasField('qClass'))
         self.assertEqual(msg.question.qClass, qclass)
@@ -201,6 +202,8 @@ class TestRecursorProtobuf(RecursorTest):
     def checkProtobufResponse(self, msg, protocol, response, initiator='127.0.0.1', receivedSize=None, vstate=dnsmessage_pb2.PBDNSMessage.VState.Indeterminate):
         self.assertEqual(msg.type, dnsmessage_pb2.PBDNSMessage.DNSResponseType)
         self.checkProtobufBase(msg, protocol, response, initiator, receivedSize=receivedSize)
+        self.assertTrue(msg.HasField('workerId'))
+        self.assertTrue(msg.HasField('packetCacheHit'))
         self.assertTrue(msg.HasField('response'))
         self.assertTrue(msg.response.HasField('queryTimeSec'))
         self.assertTrue(msg.response.HasField('validationState'))
@@ -302,6 +305,7 @@ class TestRecursorProtobuf(RecursorTest):
 @ 3600 IN SOA {soa}
 a 3600 IN A 192.0.2.42
 tagged 3600 IN A 192.0.2.84
+taggedtcp 3600 IN A 192.0.2.87
 meta 3600 IN A 192.0.2.85
 query-selected 3600 IN A 192.0.2.84
 answer-selected 3600 IN A 192.0.2.84
@@ -382,7 +386,7 @@ class ProtobufProxyMappingTest(TestRecursorProtobuf):
     This test makes sure that we correctly export queries and response over protobuf with a proxyMapping
     """
 
-    _confdir = 'ProtobufProxyMappingTest'
+    _confdir = 'ProtobufProxyMapping'
     _config_template = """
     auth-zones=example=configs/%s/example.zone
     allow-from=3.4.5.0/24
@@ -420,7 +424,7 @@ class ProtobufProxyMappingLogMappedTest(TestRecursorProtobuf):
     This test makes sure that we correctly export queries and response over protobuf.
     """
 
-    _confdir = 'ProtobufProxyMappingLogMappedTest'
+    _confdir = 'ProtobufProxyMappingLogMapped'
     _config_template = """
     auth-zones=example=configs/%s/example.zone
     allow-from=3.4.5.0/0"
@@ -639,7 +643,7 @@ class OutgoingProtobufWithECSMappingTest(TestRecursorProtobuf):
     that the recursor at least connects to the protobuf server.
     """
 
-    _confdir = 'OutgoingProtobuffWithECSMapping'
+    _confdir = 'OutgoingProtobufWithECSMapping'
     _config_template = """
     # Switch off QName Minimization, it generates much more protobuf messages
     # (or make the test much more smart!)
@@ -981,25 +985,8 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         self.checkProtobufTags(msg, tags)
         self.checkNoRemainingMessage()
 
-class ProtobufTagCacheTest(TestRecursorProtobuf):
-    """
-    This test makes sure that we correctly cache tags (actually not cache them)
-    """
-
-    _confdir = 'ProtobufTagCache'
-    _config_template = """
-auth-zones=example=configs/%s/example.zone""" % _confdir
-    _lua_config_file = """
-    protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
-    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
-    _lua_dns_script_file = """
-    function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
-      if qname:equal('tagged.example.') then
-        return 0, { '' .. math.random() }
-      end
-      return 0
-    end
-    """
+class ProtobufTagCacheBase(TestRecursorProtobuf):
+    __test__ = False
 
     def testTagged(self):
         name = 'tagged.example.'
@@ -1036,6 +1023,95 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         ts2 = msg.response.tags[0]
         self.assertNotEqual(ts1, ts2)
 
+    def testTaggedTCP(self):
+        name = 'taggedtcp.example.'
+        expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.87')
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.CD
+        res = self.sendTCPQuery(query)
+        self.assertRRsetInAnswer(res, expected)
+
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res)
+        self.assertEqual(len(msg.response.rrs), 1)
+        rr = msg.response.rrs[0]
+        # we have max-cache-ttl set to 15
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+        self.checkNoRemainingMessage()
+        print(msg.response)
+        self.assertEqual(len(msg.response.tags), 1)
+        ts1 = msg.response.tags[0]
+
+        # Again to check PC case
+        res = self.sendTCPQuery(query)
+        self.assertRRsetInAnswer(res, expected)
+
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.TCP, res)
+        print(msg.response)
+        self.assertEqual(len(msg.response.rrs), 1)
+        rr = msg.response.rrs[0]
+        # time may have passed, so do not check TTL
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15, checkTTL=False)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.87')
+        self.checkNoRemainingMessage()
+        self.assertEqual(len(msg.response.tags), 1)
+        ts2 = msg.response.tags[0]
+        self.assertNotEqual(ts1, ts2)
+
+class ProtobufTagCacheTest(ProtobufTagCacheBase):
+    """
+    This test makes sure that we correctly cache tags (actually not cache them)
+    """
+
+    __test__ = True
+    _confdir = 'ProtobufTagCache'
+    _config_template = """
+auth-zones=example=configs/%s/example.zone""" % _confdir
+    _lua_config_file = """
+    protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
+    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+    _lua_dns_script_file = """
+    function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
+      if qname:equal('tagged.example.') or qname:equal('taggedtcp.example.') then
+        return 0, { '' .. math.random() }
+      end
+      return 0
+    end
+    """
+
+class ProtobufTagCacheFFITest(ProtobufTagCacheBase):
+    """
+    This test makes sure that we correctly cache tags (actually not cache them) for the FFI case
+    """
+
+    __test__ = True
+    _confdir = 'ProtobufTagCacheFFI'
+    _config_template = """
+auth-zones=example=configs/%s/example.zone""" % _confdir
+    _lua_config_file = """
+    protobufServer({"127.0.0.1:%d", "127.0.0.1:%d"}, { logQueries=false, logResponses=true } )
+    """ % (protobufServersParameters[0].port, protobufServersParameters[1].port)
+    _lua_dns_script_file = """
+    local ffi = require("ffi")
+
+    ffi.cdef[[
+      typedef struct pdns_ffi_param pdns_ffi_param_t;
+
+      const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref);
+      void pdns_ffi_param_add_policytag(pdns_ffi_param_t* ref, const char* name);
+    ]]
+
+    function gettag_ffi(obj)
+      qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
+      if qname == 'tagged.example' or qname == 'taggedtcp.example' then
+        ffi.C.pdns_ffi_param_add_policytag(obj, '' .. math.random())
+      end
+      return 0
+    end
+    """
+
 class ProtobufSelectedFromLuaTest(TestRecursorProtobuf):
     """
     This test makes sure that we correctly export queries and responses but only if they have been selected from Lua.
@@ -1192,7 +1268,7 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp)
       if qname:equal('tagged.example.') then
         -- tag number, policy tags, data, requestorId, deviceId, deviceName
-        return 0, {}, {}, '%s', '%s', '%s'
+        return 0, {}, {}, '%s:'..remote:getPort(), '%s:'..remote:getPort(), '%s:'..remote:getPort()
       end
       return 0
     end
@@ -1235,7 +1311,30 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # check the protobuf messages corresponding to the UDP query and answer
         msg = self.getFirstProtobufMessage()
         self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
-        self.checkProtobufIdentity(msg, self._requestorId, self._deviceId.encode('ascii'), self._deviceName)
+        port = ':' + str(msg.fromPort)
+        self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+
+        # then the response
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, res)
+        self.assertEqual(len(msg.response.rrs), 1)
+        rr = msg.response.rrs[0]
+        # we have max-cache-ttl set to 15
+        self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
+        self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
+        self.checkProtobufIdentity(msg, self._requestorId + port, (self._deviceId + port).encode('ascii'), self._deviceName + port)
+        self.checkNoRemainingMessage()
+
+        # Again, but now the PC is involved
+        # check the protobuf messages corresponding to the UDP query and answer
+        # Re-init socket so we get a different port
+        self.setUpSockets();
+        res = self.sendUDPQuery(query)
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+        port2 = ':' + str(msg.fromPort)
+        self.assertNotEqual(port, port2)
+        self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
 
         # then the response
         msg = self.getFirstProtobufMessage()
@@ -1245,7 +1344,7 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
         # we have max-cache-ttl set to 15
         self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, name, 15)
         self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '192.0.2.84')
-        self.checkProtobufIdentity(msg, self._requestorId, self._deviceId.encode('ascii'), self._deviceName)
+        self.checkProtobufIdentity(msg, self._requestorId + port2, (self._deviceId + port2).encode('ascii'), self._deviceName + port2)
         self.checkNoRemainingMessage()
 
 class ProtobufTaggedExtraFieldsFFITest(ProtobufTaggedExtraFieldsTest):
@@ -1265,6 +1364,7 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
       typedef struct pdns_ffi_param pdns_ffi_param_t;
 
       const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref);
+      uint16_t pdns_ffi_param_get_remote_port(pdns_ffi_param_t* ref);
       void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag);
       void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name);
       void pdns_ffi_param_set_devicename(pdns_ffi_param_t* ref, const char* name);
@@ -1274,10 +1374,11 @@ auth-zones=example=configs/%s/example.zone""" % _confdir
     function gettag_ffi(obj)
       qname = ffi.string(ffi.C.pdns_ffi_param_get_qname(obj))
       if qname == 'tagged.example' then
-        ffi.C.pdns_ffi_param_set_requestorid(obj, "%s")
-        deviceid = "%s"
+        port = ':'..tostring(ffi.C.pdns_ffi_param_get_remote_port(obj))
+        ffi.C.pdns_ffi_param_set_requestorid(obj, "%s"..port)
+        deviceid = "%s"..port
         ffi.C.pdns_ffi_param_set_deviceid(obj, string.len(deviceid), deviceid)
-        ffi.C.pdns_ffi_param_set_devicename(obj, "%s")
+        ffi.C.pdns_ffi_param_set_devicename(obj, "%s"..port)
       end
       return 0
     end
@@ -1431,7 +1532,7 @@ class ProtobufMetaFFITest(TestRecursorProtobuf):
     """
     This test makes sure that we can correctly add extra meta fields (FFI version).
     """
-    _confdir = 'ProtobufMetaFFITest'
+    _confdir = 'ProtobufMetaFFI'
     _config_template = """
 auth-zones=example=configs/%s/example.zone""" % _confdir
     _lua_config_file = """
index b804001fb2f1d906a20f01e4ee47c949c0511016..7f631d4dc539a636d504174cc2f38989652282d7 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testProxyByTable(RecursorTest):
+class ProxyByTableTest(RecursorTest):
     """
     This test makes sure that we correctly use the proxy-mapped address during the ACL check
     """
@@ -25,7 +25,7 @@ class testProxyByTable(RecursorTest):
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testProxyByTable, cls).generateRecursorConfig(confdir)
+        super(ProxyByTableTest, cls).generateRecursorConfig(confdir)
 
 
     def testA(self):
index 5f100fe13eba3b6dd545dd081c1911f05a6995ad..43cd775123a971931ae6a06778b954bbbdecfc98 100644 (file)
@@ -4,6 +4,7 @@ import socket
 import struct
 import sys
 import time
+import requests
 
 try:
     range = xrange
@@ -13,7 +14,7 @@ except NameError:
 from recursortests import RecursorTest
 from proxyprotocol import ProxyProtocol
 
-class ProxyProtocolRecursorTest(RecursorTest):
+class ProxyProtocolTest(RecursorTest):
 
     @classmethod
     def setUpClass(cls):
@@ -32,8 +33,12 @@ class ProxyProtocolRecursorTest(RecursorTest):
     def tearDownClass(cls):
         cls.tearDownRecursor()
 
-class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
-    _confdir = 'ProxyProtocol'
+class ProxyProtocolAllowedTest(ProxyProtocolTest):
+    _confdir = 'ProxyProtocolAllowed'
+    _wsPort = 8042
+    _wsTimeout = 2
+    _wsPassword = 'secretpassword'
+    _apiKey = 'secretapikey'
     _lua_dns_script_file = """
 
     function gettag(remote, ednssubnet, localip, qname, qtype, ednsoptions, tcp, proxyProtocolValues)
@@ -128,13 +133,35 @@ class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
       dq:addAnswer(pdns.A, '192.0.2.1', 60)
       return true
     end
-    """ % (ProxyProtocolRecursorTest._recursorPort, ProxyProtocolRecursorTest._recursorPort)
+    """ % (ProxyProtocolTest._recursorPort, ProxyProtocolTest._recursorPort)
 
     _config_template = """
     proxy-protocol-from=127.0.0.1
     proxy-protocol-maximum-size=512
     allow-from=127.0.0.0/24, ::1/128, ::42/128
-""" % ()
+    webserver=yes
+    webserver-port=%d
+    webserver-address=127.0.0.1
+    webserver-password=%s
+api-key=%s
+
+""" % (_wsPort, _wsPassword, _apiKey)
+
+    def checkStats(self, expected127001):
+        headers = {'x-api-key': self._apiKey}
+        url = 'http://127.0.0.1:' + str(self._wsPort) + '/jsonstat?command=get-remote-ring&name=remotes'
+        r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+        self.assertTrue(r)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        # We allow all kind of entries, but 127.0.0.1 must have the given value, due to the
+        # testLocalProxyProtocol test, which actually does not set a source address.  If we see a
+        # higher value than expected, some ProxyProtocol clients were accounted as 127.0.0.1, which
+        # is not right as all other tests set a source addres other than 127.0.0.1
+        for entry in content['entries']:
+            if entry[1] == '127.0.0.1':
+                self.assertEqual(entry[0], expected127001)
 
     def testLocalProxyProtocol(self):
         qname = 'local.proxy-protocol.recursor-tests.powerdns.com.'
@@ -161,6 +188,7 @@ class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
             res = dns.message.from_wire(data)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
+        self.checkStats(1)
 
         # TCP
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -189,6 +217,7 @@ class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
             res = dns.message.from_wire(data)
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
         self.assertRRsetInAnswer(res, expected)
+        self.checkStats(2)
 
     def testInvalidMagicProxyProtocol(self):
         qname = 'invalid-magic.proxy-protocol.recursor-tests.powerdns.com.'
@@ -457,9 +486,9 @@ class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest):
         self.assertEqual(count, 5)
         sock.close()
 
-class ProxyProtocolAllowedFFIRecursorTest(ProxyProtocolAllowedRecursorTest):
-    # same tests than ProxyProtocolAllowedRecursorTest but with the Lua FFI interface instead of the regular one
-    _confdir = 'ProxyProtocolFFI'
+class ProxyProtocolAllowedFFITest(ProxyProtocolAllowedTest):
+    # same tests than ProxyProtocolAllowedTest but with the Lua FFI interface instead of the regular one
+    _confdir = 'ProxyProtocolAllowedFFI'
     _lua_dns_script_file = """
     local ffi = require("ffi")
 
@@ -605,9 +634,9 @@ class ProxyProtocolAllowedFFIRecursorTest(ProxyProtocolAllowedRecursorTest):
       dq:addAnswer(pdns.A, '192.0.2.1', 60)
       return true
     end
-    """ % (ProxyProtocolAllowedRecursorTest._recursorPort)
+    """ % (ProxyProtocolAllowedTest._recursorPort)
 
-class ProxyProtocolNotAllowedRecursorTest(ProxyProtocolRecursorTest):
+class ProxyProtocolNotAllowedTest(ProxyProtocolTest):
     _confdir = 'ProxyProtocolNotAllowed'
     _lua_dns_script_file = """
 
@@ -643,7 +672,7 @@ class ProxyProtocolNotAllowedRecursorTest(ProxyProtocolRecursorTest):
             res = sender(query, False, '127.0.0.42', '255.255.255.255', 0, 65535, [ [0, b'foo' ], [ 255, b'bar'] ])
             self.assertEqual(res, None)
 
-class ProxyProtocolExceptionRecursorTest(ProxyProtocolRecursorTest):
+class ProxyProtocolExceptionTest(ProxyProtocolTest):
     _confdir = 'ProxyProtocolException'
     _lua_dns_script_file = """
 
@@ -657,7 +686,7 @@ class ProxyProtocolExceptionRecursorTest(ProxyProtocolRecursorTest):
     proxy-protocol-from=127.0.0.1/32
     proxy-protocol-exceptions=127.0.0.1:%d
     allow-from=127.0.0.0/24, ::1/128
-""" % (ProxyProtocolRecursorTest._recursorPort)
+""" % (ProxyProtocolTest._recursorPort)
 
     def testNoHeaderProxyProtocol(self):
         qname = 'no-header.proxy-protocol-not-allowed.recursor-tests.powerdns.com.'
index 16f50d2afe84c0bc7853256e5535de2df7418cdd..85ce958b1d240caed9ddc4dc2aa3a79498c32cab 100644 (file)
@@ -2,8 +2,8 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testRDNotAllowed(RecursorTest):
-    _confdir = 'RDFlagNotAllowed'
+class RDNotAllowedTest(RecursorTest):
+    _confdir = 'RDNotAllowed'
 
     _config_template = """
 """
@@ -17,8 +17,8 @@ class testRDNotAllowed(RecursorTest):
         self.assertRcodeEqual(res, dns.rcode.REFUSED)
         self.assertAnswerEmpty(res)
 
-class testRDAllowed(RecursorTest):
-    _confdir = 'RDFlagAllowed'
+class RDAllowedTest(RecursorTest):
+    _confdir = 'RDAllowed'
 
     _config_template = """
     disable-packetcache=yes
index ca7292d39c750292665df1216081247b490ce307..832989b1a5f939ff8e125cf133b83744e5bca627 100644 (file)
@@ -261,20 +261,20 @@ log-rpz-changes=yes
         self.assertEqual(res.opcode(), 4)
         self.assertEqual(res.question[0].to_text(), 'zone.rpz. IN SOA')
 
-    def assertAdditionalHasSOA(self, msg):
+    def assertAdditionalHasSOA(self, msg, name):
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))
 
         found = False
         for rrset in msg.additional:
-            if rrset.rdtype == dns.rdatatype.SOA:
+            if rrset.rdtype == dns.rdatatype.SOA and str(rrset.name) == name:
                 found = True
                 break
 
         if not found:
-            raise AssertionError("No SOA record found in the authority section:\n%s" % msg.to_text())
+            raise AssertionError("No %s SOA record found in the additional section:\n%s" % (name, msg.to_text()))
 
-    def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=False):
+    def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=None):
         query = dns.message.make_query(name, 'A', want_dnssec=True)
         query.flags |= dns.flags.CD
         if adQuery:
@@ -291,14 +291,14 @@ log-rpz-changes=yes
 
             self.assertRRsetInAnswer(res, expected)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
             if singleCheck:
                 break
 
     def checkNotBlocked(self, name, adQuery=False, singleCheck=False):
         self.checkBlocked(name, False, adQuery, singleCheck)
 
-    def checkCustom(self, qname, qtype, expected, soa=False):
+    def checkCustom(self, qname, qtype, expected, soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -307,9 +307,9 @@ log-rpz-changes=yes
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
 
-    def checkNoData(self, qname, qtype, soa=False):
+    def checkNoData(self, qname, qtype, soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -318,7 +318,7 @@ log-rpz-changes=yes
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(len(res.answer), 0)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
 
     def checkNXD(self, qname, qtype='A'):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
@@ -330,7 +330,7 @@ log-rpz-changes=yes
             self.assertEqual(len(res.answer), 0)
             self.assertEqual(len(res.authority), 1)
 
-    def checkTruncated(self, qname, qtype='A', soa=False):
+    def checkTruncated(self, qname, qtype='A', soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
@@ -339,7 +339,7 @@ log-rpz-changes=yes
         self.assertEqual(len(res.answer), 0)
         self.assertEqual(len(res.authority), 0)
         if soa:
-            self.assertAdditionalHasSOA(res)
+            self.assertAdditionalHasSOA(res, soa)
 
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -387,7 +387,7 @@ class RPZXFRRecursorTest(RPZRecursorTest):
     -- The first server is a bogus one, to test that we correctly fail over to the second one
     rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1, includeSOA=true})
     """ % (rpzServerPort)
-    _confdir = 'RPZXFR'
+    _confdir = 'RPZXFRRecursor'
     _wsPort = 8042
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
@@ -444,7 +444,7 @@ e 3600 IN A 192.0.2.42
         # first zone, only a should be blocked
         self.waitUntilCorrectSerialIsLoaded(1)
         self.checkRPZStats(1, 1, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa=True)
+        self.checkBlocked('a.example.', soa='zone.rpz.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
 
@@ -452,8 +452,8 @@ e 3600 IN A 192.0.2.42
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(2)
         self.checkRPZStats(2, 2, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa=True)
-        self.checkBlocked('b.example.', soa=True)
+        self.checkBlocked('a.example.', soa='zone.rpz.')
+        self.checkBlocked('b.example.', soa='zone.rpz.')
         self.checkNotBlocked('c.example.')
 
         # third zone, only b should be blocked
@@ -461,7 +461,7 @@ e 3600 IN A 192.0.2.42
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkRPZStats(3, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
-        self.checkBlocked('b.example.', soa=True)
+        self.checkBlocked('b.example.', soa='zone.rpz.')
         self.checkNotBlocked('c.example.')
 
         # fourth zone, only c should be blocked
@@ -470,7 +470,7 @@ e 3600 IN A 192.0.2.42
         self.checkRPZStats(4, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
         self.checkNotBlocked('b.example.')
-        self.checkBlocked('c.example.', soa=True)
+        self.checkBlocked('c.example.', soa='zone.rpz.')
 
         # fifth zone, we should get a full AXFR this time, and only d should be blocked
         self.sendNotify()
@@ -479,7 +479,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('a.example.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
-        self.checkBlocked('d.example.', soa=True)
+        self.checkBlocked('d.example.', soa='zone.rpz.')
 
         # sixth zone, only e should be blocked, f is a local data record
         self.sendNotify()
@@ -489,10 +489,10 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa=True)
+        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa='zone.rpz.')
         self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
-        self.checkNoData('e.example.', 'AAAA', soa=True)
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
 
         # seventh zone, e should only have one A
         self.sendNotify()
@@ -502,14 +502,14 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa=True)
-        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa=True)
-        self.checkNoData('e.example.', 'AAAA', soa=True)
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa='zone.rpz.')
+        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa='zone.rpz.')
+        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
         # check that the policy is disabled for AD=1 queries
         self.checkNotBlocked('e.example.', True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa=True)
+        self.checkTruncated('tc.example.', soa='zone.rpz.')
         self.checkDropped('drop.example.')
 
         # eighth zone, all entries should be gone
@@ -538,7 +538,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
         self.checkNotBlocked('e.example.')
-        self.checkBlocked('f.example.', soa=True)
+        self.checkBlocked('f.example.', soa='zone.rpz.')
         self.checkNXD('tc.example.')
         self.checkNXD('drop.example.')
 
@@ -555,7 +555,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('d.example.')
         self.checkNotBlocked('e.example.')
         self.checkNXD('f.example.')
-        self.checkBlocked('g.example.', soa=True)
+        self.checkBlocked('g.example.', soa='zone.rpz.')
         self.checkNXD('tc.example.')
         self.checkNXD('drop.example.')
 
@@ -564,7 +564,7 @@ class RPZFileRecursorTest(RPZRecursorTest):
     This test makes sure that we correctly load RPZ zones from a file
     """
 
-    _confdir = 'RPZFile'
+    _confdir = 'RPZFileRecursor'
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", includeSOA=true })
     """ % (_confdir)
@@ -602,7 +602,7 @@ tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
     def testRPZ(self):
         self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
         self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
-        self.checkBlocked('z.example.', soa=True)
+        self.checkBlocked('z.example.', soa='zone.rpz.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
@@ -610,7 +610,7 @@ tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
         # check that the policy is disabled for AD=1 queries
         self.checkNotBlocked('z.example.', True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa=True)
+        self.checkTruncated('tc.example.', soa='zone.rpz.')
         self.checkDropped('drop.example.')
 
 class RPZFileDefaultPolRecursorTest(RPZRecursorTest):
@@ -618,7 +618,7 @@ class RPZFileDefaultPolRecursorTest(RPZRecursorTest):
     This test makes sure that we correctly load RPZ zones from a file with a default policy
     """
 
-    _confdir = 'RPZFileDefaultPolicy'
+    _confdir = 'RPZFileDefaultPolRecursor'
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction })
     """ % (_confdir)
@@ -671,7 +671,7 @@ class RPZFileDefaultPolNotOverrideLocalRecursorTest(RPZRecursorTest):
     This test makes sure that we correctly load RPZ zones from a file with a default policy, not overriding local data entries
     """
 
-    _confdir = 'RPZFileDefaultPolicyNotOverrideLocal'
+    _confdir = 'RPZFileDefaultPolNotOverrideLocalRecursor'
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz.", defpol=Policy.NoAction, defpolOverrideLocalData=false })
     """ % (_confdir)
@@ -775,7 +775,7 @@ class RPZOrderingPrecedenceRecursorTest(RPZRecursorTest):
     This test makes sure that the recursor respects the RPZ ordering precedence rules
     """
 
-    _confdir = 'RPZOrderingPrecedence'
+    _confdir = 'RPZOrderingPrecedenceRecursor'
     _lua_config_file = """
     rpzFile('configs/%s/zone.rpz', { policyName="zone.rpz."})
     rpzFile('configs/%s/zone2.rpz', { policyName="zone2.rpz."})
@@ -1040,7 +1040,7 @@ class RPZFileModByLuaRecursorTest(RPZRecursorTest):
     This test makes sure that we correctly load RPZ zones from a file while being modified by Lua callbacks
     """
 
-    _confdir = 'RPZFileModByLua'
+    _confdir = 'RPZFileModByLuaRecursor'
     _lua_dns_script_file = """
     function preresolve(dq)
       if dq.qname:equal('zmod.example.') then
index baeb2db053d0dfd87df54487b36ea21fcd41f076..647a7ab090b3c4d0d90858357306b1e355e2e469 100644 (file)
@@ -129,7 +129,7 @@ class RPZIncompleteRecursorTest(RecursorTest):
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
     _apiKey = 'secretapikey'
-    _confdir = 'RPZIncomplete'
+    _confdir = 'RPZIncompleteRecursor'
     _auth_zones = {
         '8': {'threads': 1,
               'zones': ['ROOT']},
@@ -179,7 +179,7 @@ class RPZXFRIncompleteRecursorTest(RPZIncompleteRecursorTest):
     -- The first server is a bogus one, to test that we correctly fail over to the second one
     rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1 })
     """ % (badrpzServerPort)
-    _confdir = 'RPZXFRIncomplete'
+    _confdir = 'RPZXFRIncompleteRecursor'
     _wsPort = 8042
     _wsTimeout = 2
     _wsPassword = 'secretpassword'
index c1a25747c1eb961b370cc00fdbc2756758a2cdb8..16bca4e83e2e5b5e77fcd46a979b2a6342738cfb 100644 (file)
@@ -4,8 +4,8 @@ import subprocess
 from recursortests import RecursorTest
 
 
-class testReadTrustAnchorsFromFile(RecursorTest):
-    _confdir = 'ReadTAsFromFile'
+class ReadTrustAnchorsFromFileTest(RecursorTest):
+    _confdir = 'ReadTrustAnchorsFromFile'
 
     _config_template = """dnssec=validate"""
     _lua_config_file = """clearTA()
index b975483d7d76e3367b0783368216d1ef3d45278c..6e50f9ff888ccc6b47e53f1dd31b2a8d8af1ffbe 100644 (file)
@@ -4,6 +4,7 @@ import socket
 import struct
 import sys
 import threading
+import time
 import dns
 import dnstap_pb2
 from unittest import SkipTest
@@ -330,6 +331,7 @@ dnstapFrameStreamServer({"%s"}, {logQueries=false})
         self.assertNotEqual(res, None)
 
         # We don't expect anything
+        time.sleep(1)
         self.assertTrue(DNSTapServerParameters.queue.empty())
 
 class DNSTapLogNODTest(TestRecursorDNSTap):
@@ -339,7 +341,7 @@ class DNSTapLogNODTest(TestRecursorDNSTap):
     that the recursor at least connects to the DNSTap server.
     """
 
-    _confdir = 'DNSTapLogNODQueries'
+    _confdir = 'DNSTapLogNOD'
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
@@ -368,7 +370,7 @@ dnstapNODFrameStreamServer({"%s"})
         return dnstap
 
     def testA(self):
-        name = 'www.example.org.'
+        name = 'types.example.'
         query = dns.message.make_query(name, 'A', want_dnssec=True)
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
@@ -383,7 +385,7 @@ dnstapNODFrameStreamServer({"%s"})
 
 class DNSTapLogUDRTest(TestRecursorDNSTap):
 
-    _confdir = 'DNSTapLogUDRResponses'
+    _confdir = 'DNSTapLogUDR'
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
@@ -427,7 +429,7 @@ dnstapNODFrameStreamServer({"%s"}, {logNODs=false, logUDRs=true})
 
 class DNSTapLogNODUDRTest(TestRecursorDNSTap):
 
-    _confdir = 'DNSTapLogNODUDRs'
+    _confdir = 'DNSTapLogNODUDR'
     _config_template = """
 new-domain-tracking=yes
 new-domain-history-dir=configs/%s/nod
index cb1133641b3e8114101e74931a407c23fd6a929c..2925c2a6fe83a151a5e5e95b78d79213226861f6 100644 (file)
@@ -33,7 +33,7 @@ class RootNXTrustRecursorTest(RecursorTest):
             if outgoing1 == outgoing2:
                 break
 
-class testRootNXTrustDisabled(RootNXTrustRecursorTest):
+class RootNXTrustDisabledTest(RootNXTrustRecursorTest):
     _confdir = 'RootNXTrustDisabled'
     _wsPort = 8042
     _wsTimeout = 2
@@ -86,7 +86,7 @@ extended-resolution-errors
         self.assertEqual(res.edns, 0)
         self.assertEqual(len(res.options), 0)
 
-class testRootNXTrustEnabled(RootNXTrustRecursorTest):
+class RootNXTrustEnabledTest(RootNXTrustRecursorTest):
     _confdir = 'RootNXTrustEnabled'
     _wsPort = 8042
     _wsTimeout = 2
index 6d54618ae641f7aa1465d00bf2c13b025072a56e..a1cec5d0cae9b031345131a2d582b6f1ae8f5baf 100644 (file)
@@ -105,7 +105,7 @@ ecs-add-for=0.0.0.0/0
         cls.tearDownRecursor()
         os.unlink('tagfile')
 
-class testRoutingTag(RoutingTagTest):
+class RoutingTagTest(RoutingTagTest):
     _confdir = 'RoutingTag'
 
     _config_template = """
@@ -179,7 +179,7 @@ end
             print(e.output)
             raise
 
-class testRoutingTagFFI(RoutingTagTest):
+class RoutingTagFFITest(RoutingTagTest):
     _confdir = 'RoutingTagFFI'
 
     _config_template = """
index 4ad78640cbcc442e8edabbb80d79e3d70c98533b..40907ad3aba14fa21e4c8cd8a52ba029feebeaea 100644 (file)
@@ -4,7 +4,7 @@ from pysnmp.hlapi import *
 
 from recursortests import RecursorTest
 
-class TestSNMP(RecursorTest):
+class SNMPTest(RecursorTest):
 
     _snmpTimeout = 2.0
     _snmpServer = '127.0.0.1'
@@ -21,7 +21,7 @@ class TestSNMP(RecursorTest):
     """
 
     def _checkStatsValues(self, results):
-        count = 148
+        count = 152
         for i in list(range(1, count)):
             oid = self._snmpOID + '.1.' + str(i) + '.0'
             self.assertTrue(oid in results)
index 79dfd0060ee9da046ec27fa0bab0b9645a2196ec..1611f625d7b12c83cf1d4b7eea37689975d3bdb4 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testServerNames(RecursorTest):
+class ServerNamesTest(RecursorTest):
     """
     This tests all kinds naming things
     """
index e6c4e97455ad237a2275424a39e1c3195c5dd4b9..7a247bce40a44463d1470ef485ac7d9a5c54f0d4 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testSimple(RecursorTest):
+class SimpleTest(RecursorTest):
     _confdir = 'Simple'
 
     _config_template = """dnssec=validate
@@ -16,7 +16,7 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testSimple, cls).generateRecursorConfig(confdir)
+        super(SimpleTest, cls).generateRecursorConfig(confdir)
 
     def testSOAs(self):
         for zone in ['.', 'example.', 'secure.example.']:
index fcc915ab53d1abcb8dcc6bfd723ecc325075b787..0c22b87f34660d3a3554f53562c5141be19c1eb9 100644 (file)
@@ -3,7 +3,7 @@ import os
 import subprocess
 from recursortests import RecursorTest
 
-class testSimpleDoT(RecursorTest):
+class SimpleDoTTest(RecursorTest):
     """
     This tests DoT to auth server in a very basic way and is dependent on powerdns.com nameservers having DoT enabled.
     """
index d839d43084ecec58e43d1ff642611ced797c72ed..d7b85e648c21e295bd76b2c123ed9837cbfeb50b 100644 (file)
@@ -3,15 +3,15 @@ import os
 import subprocess
 from recursortests import RecursorTest
 
-class testSimpleForwardOverDoT(RecursorTest):
+class SimpleForwardOverDoTTest(RecursorTest):
     """
-    This is forwarding to a DoT server in a very basic way and is dependent on Quad9 working
+    This is forwarding to DoT servers in a very basic way and is dependent on the forwards working for DoT
     """
 
     _confdir = 'SimpleForwardOverDoT'
     _config_template = """
 dnssec=validate
-forward-zones-recurse=.=9.9.9.9:853
+forward-zones-recurse=.=1.1.1.1:853;8.8.8.8:853;9.9.9.9:853
 devonly-regression-test-mode
     """
 
index b70900f7592b1f3e2ba65f982f89daf713450668..4fb7733c41ae9295e2a282acbc796f2f5aefe169 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testSimpleTCP(RecursorTest):
+class SimpleTCPTest(RecursorTest):
     _confdir = 'SimpleTCP'
 
     _config_template = """dnssec=validate
@@ -16,7 +16,7 @@ auth-zones=authzone.example=configs/%s/authzone.zone""" % _confdir
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testSimpleTCP, cls).generateRecursorConfig(confdir)
+        super(SimpleTCPTest, cls).generateRecursorConfig(confdir)
 
     def testSOAs(self):
         for zone in ['.', 'example.', 'secure.example.']:
index e4713401f4209869ee428a8cf3aa7dda35a532de..9d742162f4b1dfa98a6a2ae29d07bace4907e4f5 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testSimpleYAML(RecursorTest):
+class SimpleYAMLTest(RecursorTest):
     _confdir = 'SimpleYAML'
 
     _config_template = """
@@ -21,7 +21,7 @@ dnssec:
 @ 3600 IN SOA {soa}
 @ 3600 IN A 192.0.2.88
 """.format(soa=cls._SOA))
-        super(testSimpleYAML, cls).generateRecursorYamlConfig(confdir)
+        super(SimpleYAMLTest, cls).generateRecursorYamlConfig(confdir)
 
     def testSOAs(self):
         for zone in ['.', 'example.', 'secure.example.']:
index 7665602bd0a67a426b435df2a9936b685f1d3ae1..fdf8e29645edf13a7826086cc624fe9b9e1943be 100644 (file)
@@ -2,7 +2,7 @@ import dns
 from recursortests import RecursorTest
 
 
-class testSortlist(RecursorTest):
+class SortlistTest(RecursorTest):
     _confdir = 'Sortlist'
 
     _config_template = """dnssec=off"""
@@ -38,4 +38,4 @@ class testSortlist(RecursorTest):
         self.assertEqual(indexCNAME, 0)
         self.assertGreater(indexMX, 0)
 
-        self.assertEqual(recordsA, ['17.238.240.5', '17.38.42.80', '192.168.0.1'])
\ No newline at end of file
+        self.assertEqual(recordsA, ['17.238.240.5', '17.38.42.80', '192.168.0.1'])
index 3c1d78f51768f21e11c27d810ca20f3342c9e954..7e30c1a657d05decaed0c35e1c83cded457c5726 100644 (file)
@@ -2,7 +2,7 @@ import dns
 import os
 from recursortests import RecursorTest
 
-class testBogusMaxTTL(RecursorTest):
+class BogusMaxTTLTest(RecursorTest):
     _confdir = 'BogusMaxTTL'
 
     _config_template = """dnssec=validate
index 52e8c29781c671802108cbdf4cdf37cb1df1da1f..6f7e7b05872ab801747284ca3daeda3349c32804 100644 (file)
@@ -4,7 +4,7 @@ import time
 import subprocess
 from recursortests import RecursorTest
 
-class testTraceFail(RecursorTest):
+class TraceFailTest(RecursorTest):
     _confdir = 'TraceFail'
 
     _config_template = """
index f44497881aba4f1fc17ea98dc8891848521dd010..4d3211873d5f0b6725bcd7939ef5e35e4beb97eb 100644 (file)
@@ -2,7 +2,7 @@ import dns
 from recursortests import RecursorTest
 
 
-class testTrustAnchorsEnabled(RecursorTest):
+class TrustAnchorsEnabledTest(RecursorTest):
     """This test will do a query for "trustanchor.server CH TXT" and hopes to get
     a proper answer"""
 
@@ -42,7 +42,7 @@ addNTA("example.com", "some reason")
         self.assertRRsetInAnswer(result, expected)
 
 
-class testTrustAnchorsDisabled(RecursorTest):
+class TrustAnchorsDisabledTest(RecursorTest):
     """This test will do a query for "trustanchor.server CH TXT" and hopes to get
     a proper answer"""
 
index f880692364d4e85f83147c6f343049b73c5f681b..c8b1667cd2cd5c13feccb6bcec3541d22296ae22 100644 (file)
@@ -5,7 +5,7 @@ import subprocess
 
 from recursortests import RecursorTest
 
-class testZTC(RecursorTest):
+class ZTCTest(RecursorTest):
 
     _confdir = 'ZTC'
     _config_template = """
index 9987776d8b4819ce608fb89b4bc734252e569a09..09227caf8ecf4b911315e98915f7dc48401107f9 100644 (file)
@@ -1,6 +1,6 @@
 from basicDNSSEC import BasicDNSSEC
 import unittest
 
-class basicNSEC(BasicDNSSEC):
+class basicNSECTest(BasicDNSSEC):
     __test__ = True
     _confdir = 'basicNSEC'
index 34ef04f93392230467aa754a936c541da7dfa3bc..d82d7cd9304de1f21129e19353df3188640a0ae8 100644 (file)
@@ -3,7 +3,7 @@ from basicDNSSEC import BasicDNSSEC
 import os
 import subprocess
 
-class basicNSEC3(BasicDNSSEC):
+class basicNSEC3Test(BasicDNSSEC):
     __test__ = True
     _confdir = 'basicNSEC3'
 
diff --git a/regression-tests.rootzone/tests/direct-ns/skip-unboundhost b/regression-tests.rootzone/tests/direct-ns/skip-unboundhost
new file mode 100644 (file)
index 0000000..e69de29
index 6fb6e5a1ff8682e641ea9075567cae0fd80272fd..b91b83fc56c4e883c12bbcb22bb52eb06f95d066 100644 (file)
@@ -1,13 +1,13 @@
 case $context in
     bind)
         cat > pdns-bind.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=bind
 bind-config=./named.conf
 bind-ignore-broken-records=yes
 __EOF__
 
-        $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+        $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
             --config-name=bind --socket-dir=./ --no-shuffle \
             --cache-ttl=$cachettl --dname-processing \
             --disable-axfr-rectify=yes &
@@ -18,7 +18,7 @@ __EOF__
     bind-dnssec | bind-dnssec-nsec3 | bind-hybrid-nsec3 | bind-dnssec-nsec3-optout | bind-dnssec-nsec3-narrow)
         rm -f dnssec.sqlite3
         cat > pdns-bind.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=bind
 bind-config=./named.conf
 bind-ignore-broken-records=yes
@@ -103,7 +103,7 @@ __EOF__
             skipreasons="nodyndns noalias nsec"
         fi
 
-        $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+        $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
             --config-name=bind --socket-dir=./ --no-shuffle \
             --cache-ttl=$cachettl --dname-processing \
             --disable-axfr-rectify=yes $lua_prequery &
index 36c1b595cf04b812599ab4726dce787477c760e7..1c6681a48f47f5525c010b821516a6e113766cdb 100644 (file)
 start_master ()
 {
-       case $context in
-                       bind*)
-                               source ./backends/bind-master
-                               ;;
-                       geoip*)
-                               source ./backends/geoip-master
-                               ;;
-                       gmysql*)
-                               source ./backends/gmysql-master
-                               ;;
-
-                       godbc_mssql*)
-                               [ -z $GODBC_MSSQL_DSN ] && echo '$GODBC_MSSQL_DSN must be set' >&2 && exit 1
-                               [ -z $GODBC_MSSQL_USERNAME ] && echo '$GODBC_MSSQL_USERNAME must be set' >&2 && exit 1
-                               [ -z $GODBC_MSSQL_PASSWORD ] && echo '$GODBC_MSSQL_PASSWORD must be set' >&2 && exit 1
-                               source ./backends/godbc_mssql-master
-                               ;;
-
-                       godbc_sqlite3*)
-                               [ -z $GODBC_SQLITE3_DSN ] && echo '$GODBC_SQLITE3_DSN must be set' >&2 && exit 1
-                               source ./backends/godbc_sqlite3-master
-                               ;;
-
-                       gpgsql*)
-                               source ./backends/gpgsql-master
-                               ;;
-
-                       gsqlite3*)
-                               source ./backends/gsqlite3-master
-                               ;;
-
-                       lmdb*)
-                               source ./backends/lmdb-master
-                               ;;
-
-                       remote*)
-                               source ./backends/remote-master
-                               ;;
-
-                       tinydns*)
-                               source ./backends/tinydns-master
-                               ;;
-
-                       ldap*)
-                               source ./backends/ldap-master
-                               ;;
-
-                       lua2*)
-                               source ./backends/lua2-master
-                               ;;
-
-                       ext-nsd*)
-                               source ./ext/nsd-master
-                               ;;
-
-                       ext-bind*)
-                               source ./ext/bind-master
-                               ;;
-
-                       *)
-                               nocontext=yes
-       esac
-
-       if [ "$nocontext" == "yes" ]
-       then
-               echo unknown context $context
-               : > passed_tests
-               echo 'unknown-context-'"$context" > failed_tests
-               ./toxml $context
-               exit
-       fi
+        case $context in
+                        bind*)
+                                source ./backends/bind-master
+                                ;;
+                        geoip*)
+                                source ./backends/geoip-master
+                                ;;
+                        gmysql*)
+                                source ./backends/gmysql-master
+                                ;;
+
+                        godbc_mssql*)
+                                [ -z $GODBC_MSSQL_DSN ] && echo '$GODBC_MSSQL_DSN must be set' >&2 && exit 1
+                                [ -z $GODBC_MSSQL_USERNAME ] && echo '$GODBC_MSSQL_USERNAME must be set' >&2 && exit 1
+                                [ -z $GODBC_MSSQL_PASSWORD ] && echo '$GODBC_MSSQL_PASSWORD must be set' >&2 && exit 1
+                                source ./backends/godbc_mssql-master
+                                ;;
+
+                        godbc_sqlite3*)
+                                [ -z $GODBC_SQLITE3_DSN ] && echo '$GODBC_SQLITE3_DSN must be set' >&2 && exit 1
+                                source ./backends/godbc_sqlite3-master
+                                ;;
+
+                        gpgsql*)
+                                source ./backends/gpgsql-master
+                                ;;
+
+                        gsqlite3*)
+                                source ./backends/gsqlite3-master
+                                ;;
+
+                        lmdb*)
+                                source ./backends/lmdb-master
+                                ;;
+
+                        remote*)
+                                source ./backends/remote-master
+                                ;;
+
+                        tinydns*)
+                                source ./backends/tinydns-master
+                                ;;
+
+                        ldap*)
+                                source ./backends/ldap-master
+                                ;;
+
+                        lua2*)
+                                source ./backends/lua2-master
+                                ;;
+
+                        ext-nsd*)
+                                source ./ext/nsd-master
+                                ;;
+
+                        ext-bind*)
+                                source ./ext/bind-master
+                                ;;
+
+                        *)
+                                nocontext=yes
+        esac
+
+        if [ "$nocontext" == "yes" ]
+        then
+                echo unknown context $context
+                : > passed_tests
+                echo 'unknown-context-'"$context" > failed_tests
+                ./toxml $context
+                exit
+        fi
 }
 
 start_slave ()
 {
-       skipreasons="$skipreasons presigned nodyndns"
-
-       case $presignedcontext in
-               bind*)
-                       source ./backends/bind-slave
-                       ;;
-
-               gmysql*)
-                       source ./backends/gmysql-slave
-                       ;;
-
-               godbc_mssql*)
-                       [ -z $GODBC_MSSQL2_DSN ] && echo '$GODBC_MSSQL2_DSN must be set' >&2 && exit 1
-                       [ -z $GODBC_MSSQL2_USERNAME ] && echo '$GODBC_MSSQL2_USERNAME must be set' >&2 && exit 1
-                       [ -z $GODBC_MSSQL2_PASSWORD ] && echo '$GODBC_MSSQL2_PASSWORD must be set' >&2 && exit 1
-                       source ./backends/godbc_mssql-slave
-                       ;;
-
-               gpgsql*)
-               source ./backends/gpgsql-slave
-                       ;;
-
-               gsqlite3*)
-                       source ./backends/gsqlite3-slave
-                       ;;
-
-               lmdb*)
-                       source ./backends/lmdb-slave
-                       ;;
-
-               ext-bind*)
-                       source ./ext/bind-slave
-                       ;;
-
-               ext-nsd*)
-                       source ./ext/nsd-slave
-                       ;;
-
-               *)
-                       nocontext=yes
-       esac
-
-       if [ "$nocontext" == "yes" ]
-       then
-               echo unknown presigned context $presignedcontext
-               : > passed_tests
-               echo 'unknown-presigned-context-'"$presignedcontext" > failed_tests
-               ./toxml $context
-               exit
-       fi
+        skipreasons="$skipreasons presigned nodyndns"
+
+        case $presignedcontext in
+                bind*)
+                        source ./backends/bind-slave
+                        ;;
+
+                gmysql*)
+                        source ./backends/gmysql-slave
+                        ;;
+
+                godbc_mssql*)
+                        [ -z $GODBC_MSSQL2_DSN ] && echo '$GODBC_MSSQL2_DSN must be set' >&2 && exit 1
+                        [ -z $GODBC_MSSQL2_USERNAME ] && echo '$GODBC_MSSQL2_USERNAME must be set' >&2 && exit 1
+                        [ -z $GODBC_MSSQL2_PASSWORD ] && echo '$GODBC_MSSQL2_PASSWORD must be set' >&2 && exit 1
+                        source ./backends/godbc_mssql-slave
+                        ;;
+
+                gpgsql*)
+                source ./backends/gpgsql-slave
+                        ;;
+
+                gsqlite3*)
+                        source ./backends/gsqlite3-slave
+                        ;;
+
+                lmdb*)
+                        source ./backends/lmdb-slave
+                        ;;
+
+                ext-bind*)
+                        source ./ext/bind-slave
+                        ;;
+
+                ext-nsd*)
+                        source ./ext/nsd-slave
+                        ;;
+
+                *)
+                        nocontext=yes
+        esac
+
+        if [ "$nocontext" == "yes" ]
+        then
+                echo unknown presigned context $presignedcontext
+                : > passed_tests
+                echo 'unknown-presigned-context-'"$presignedcontext" > failed_tests
+                ./toxml $context
+                exit
+        fi
 }
index 2018929324075cb97c80557617d88374161b1409..c3e3ef1757966052ec5579b4d041f491b82178d6 100644 (file)
@@ -132,12 +132,12 @@ EOF
 
                geoipdatabase=${geoipdatabase:-$testsdir/GeoLiteCity.dat}
 
-               $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+               $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
                        --no-shuffle --launch=geoip \
                        --cache-ttl=$cachettl --dname-processing --no-config \
                        --distributor-threads=1 \
                         --geoip-zones-file=$testsdir/geo.yaml --geoip-database-files="$geoipdatabase" \
-                        --module-dir=./modules --edns-subnet-processing=yes \
+                        --module-dir="$PDNS_BUILD_PATH/modules" --edns-subnet-processing=yes \
                        $geoipkeydir &
                ;;
 
index 5b2ed60fc252afad205864b4b1497d056a6b0611..e90f95e1523638cd35c2c7961f3faa9bbbb9eeef 100644 (file)
@@ -17,7 +17,7 @@ case $context in
                        "$GMYSQLDB"
 
                cat > pdns-gmysql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=gmysql
 gmysql-dbname=$GMYSQLDB
 gmysql-user=$GMYSQLUSER
index 6ece162d9729c97002f0f8f0598f303455f4eb7a..739fad50c169edbb3bf7b4e36b91ce8d8050e9cd 100644 (file)
@@ -17,7 +17,7 @@ case $context in
                # actually terminates
                tosql gsqlite | grep -v -E '(COMMIT|TRANSACTION)' | awk '1;!(NR%98){print "go"}' | cat - <(echo go) /dev/null | $BSQLODBC
                cat > pdns-godbc_mssql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=godbc
 godbc-datasource=$GODBC_MSSQL_DSN
 godbc-username=$GODBC_MSSQL_USERNAME
index 0c6f3eab8af7a1b2340d7ecc7621052b274c0b67..aef648d120050cb2abf98285dae9a16a080742cd 100644 (file)
@@ -7,7 +7,7 @@ case $context in
                echo 'ANALYZE; PRAGMA journal_mode=WAL;' | sqlite3 pdns.sqlite3
 
                cat > pdns-godbc_sqlite3.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=godbc
 godbc-datasource=$GODBC_SQLITE3_DSN
 
@@ -41,7 +41,7 @@ godbc-get-tsig-key-query=select algorithm, secret from tsigkeys where name=?
 godbc-get-tsig-keys-query=select name,algorithm, secret from tsigkeys
 godbc-publish-domain-key-query=update cryptokeys set published=1 where domain_id=(select id from domains where name=?) and  cryptokeys.id=?
 godbc-id-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=? and domain_id=?
-godbc-info-all-primary-query=select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')
+godbc-info-all-primary-query=select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER') order by domains.id
 godbc-info-all-secondaries-query=select domains.id, domains.name, domains.type, domains.master, domains.last_check, records.content from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name where domains.type in ('SLAVE', 'CONSUMER')
 godbc-info-zone-query=select id,name,master,last_check,notified_serial,type,options,catalog,account from domains where name=?
 godbc-info-producer-members-query=select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.type='MASTER' and domains.catalog=? and records.type='SOA' and records.disabled=0
index 4f2fa3ef05056fbc17d8b5b67b7d8bb61fe78faa..9741599c211daef34071ab58ed7a2e6a2f36405d 100644 (file)
@@ -12,7 +12,7 @@ case $context in
                 psql --user="$GPGSQLUSER" -c "ANALYZE" "$GPGSQLDB"
 
                cat > pdns-gpgsql.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=gpgsql
 gpgsql-dbname=$GPGSQLDB
 gpgsql-user=$GPGSQLUSER
index a1134d23118c6dc1f41ad7f9ec84103d1b2960d1..c6aeff8fab972dbfadf55d49f9d3b97f5472072f 100644 (file)
@@ -46,10 +46,11 @@ gsql_master()
     done
 
 
-    $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+    $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
         --config-name=$backend --socket-dir=./ --no-shuffle \
         --dnsupdate=yes --resolver=$RESOLVERIP --outgoing-axfr-expand-alias=yes \
         --expand-alias=yes \
+        --primary=yes --only-notify="" \
         --cache-ttl=$cachettl --dname-processing \
         --disable-axfr-rectify=yes $lua_prequery &
 
index b465e23a8835580c32c82e32b8521306e30de1a1..4f3b532e130ac2b92fc1b8bf697d1d7e68f1be79 100644 (file)
@@ -8,7 +8,7 @@ case $context in
                echo ANALYZE\; | sqlite3 pdns.sqlite3
 
                cat > pdns-gsqlite3.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=gsqlite3
 gsqlite3-database=pdns.sqlite3
 consistent-backends
index cb7047e2d492c757541f9c0fd422999acd7e131d..cbb0d62c9147e4f4d2af9f4f3b8bf8d958d2fa92 100644 (file)
@@ -17,7 +17,7 @@ __EOF__
                $ZONE2LDAP --dnsttl=yes --basedn=$LDAPBASEDN --layout=$layout --named-conf=named.conf | ldapmodify -D $LDAPUSER -w $LDAPPASSWD -H $LDAPHOST -c > /dev/null || true
 
                cat > pdns-ldap.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=ldap
 ldap-basedn=$LDAPBASEDN
 ldap-binddn=$LDAPUSER
@@ -26,7 +26,7 @@ ldap-method=$layout
 ldap-host=$LDAPHOST
 __EOF__
 
-               $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+               $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
                        --config-name=ldap --socket-dir=./ --no-shuffle \
                        --query-logging --dnsupdate=yes \
                        --expand-alias=yes --outgoing-axfr-expand-alias=yes \
index c1bf9346b205b1cd6517b965c24947e4816eedda..cdeb418df05aa38de8413e7c530d3ace08ac4c96 100644 (file)
@@ -1,7 +1,7 @@
 case $context in
     lmdb | lmdb-nodnssec | lmdb-nsec3 | lmdb-nsec3-optout | lmdb-nsec3-narrow)
         cat > pdns-lmdb.conf << __EOF__
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=lmdb
 lmdb-filename=./pdns.lmdb
 lmdb-random-ids=yes
@@ -11,9 +11,9 @@ __EOF__
         for zone in $(grep 'zone ' named.conf  | cut -f2 -d\" | grep -v '^nztest.com$')
         do
             if [ "$zone" = "." ]; then
-                        $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/ROOT
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/ROOT
             else
-                        $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/$zone
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone $zone zones/$zone
             fi
             if [ $context != lmdb-nodnssec ]
             then
@@ -21,54 +21,54 @@ __EOF__
                 then
                     if [ $context = lmdb-nsec3 ]
                     then
-                        $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 0 1 abcd" 2>&1
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 0 1 abcd" 2>&1
                     elif [ $context =  lmdb-nsec3-optout ]
                     then
-                        $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 1 1 abcd" 2>&1
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone "1 1 1 abcd" 2>&1
                     elif [ $context = lmdb-nsec3-narrow ]
                     then
-                        $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-nsec3 $zone '1 1 1 abcd' narrow 2>&1
                     fi
                     securezone $zone lmdb
                     if [ $zone = hiddencryptokeys.org ]
                     then
-                        keyid=$($PDNSUTIL --config-dir=. --config-name=lmdb list-keys $zone | grep hiddencryptokeys.org | awk '{ print $7 }')
-                        $PDNSUTIL --config-dir=. --config-name=lmdb unpublish-zone-key $zone $keyid
+                        keyid=$($RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb list-keys $zone | grep hiddencryptokeys.org | awk '{ print $7 }')
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb unpublish-zone-key $zone $keyid
                     fi
                     if [ $zone = cryptokeys.org ]
                     then
-                        $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 384 active unpublished ecdsa384
-                        $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive published rsasha512
-                        $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive unpublished rsasha256
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 384 active unpublished ecdsa384
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive published rsasha512
+                        $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb add-zone-key $zone zsk 2048 inactive unpublished rsasha256
                     fi
                 fi
             else
-                $PDNSUTIL --config-dir=. --config-name=lmdb rectify-zone $zone 2>&1
+                $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb rectify-zone $zone 2>&1
             fi
             if [ "$zone" = "tsig.com" ]; then
-                $PDNSUTIL --config-dir=. --config-name=lmdb import-tsig-key test $ALGORITHM $KEY
-                $PDNSUTIL --config-dir=. --config-name=lmdb activate-tsig-key tsig.com test primary
+                $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb import-tsig-key test $ALGORITHM $KEY
+                $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb activate-tsig-key tsig.com test primary
             fi
         done
 
         # setup catalog zone
 
-        if ! $PDNSUTIL --config-dir=. --config-name=lmdb list-all-zones | grep '^.$' # detect root tests
+        if ! $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb list-all-zones | grep '^.$' # detect root tests
         then
             for zone in $(grep 'zone ' named.conf  | cut -f2 -d\" | grep -v '^nztest.com$')
             do
-                $PDNSUTIL --config-dir=. --config-name=lmdb set-kind $zone master
-                $PDNSUTIL --config-dir=. --config-name=lmdb set-catalog $zone catalog.invalid
+                $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-kind $zone master
+                $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-catalog $zone catalog.invalid
             done
 
-            $PDNSUTIL --config-dir=. --config-name=lmdb load-zone catalog.invalid zones/catalog.invalid
-            $PDNSUTIL --config-dir=. --config-name=lmdb set-kind catalog.invalid producer
+            $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb load-zone catalog.invalid zones/catalog.invalid
+            $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-kind catalog.invalid producer
 
-            $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json test.com '{"producer":{"coo":"other-catalog.invalid","unique":"123"}}'
-            $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json tsig.com '{"producer":{"group":["pdns-group-x","pdns-group-y"]}}'
+            $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json test.com '{"producer":{"coo":"other-catalog.invalid","unique":"123"}}'
+            $RUNWRAPPER_PDNSUTIL $PDNSUTIL --config-dir=. --config-name=lmdb set-options-json tsig.com '{"producer":{"group":["pdns-group-x","pdns-group-y"]}}'
         fi
 
-        $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --config-dir=. \
+        $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --config-dir=. \
             --config-name=lmdb --socket-dir=./ --no-shuffle \
             --dnsupdate=no \
             --expand-alias=yes --resolver=$RESOLVERIP \
index 785a71c9de697cd3aa980c87a98a52a53fb56b50..f636250eb19c163a94ec420adec506177da0b2ef 100644 (file)
@@ -23,14 +23,14 @@ case $context in
 
                # generate pdns.conf for pdnsutil
                cat > pdns-lua2.conf <<EOF
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=lua2
 lua2-filename=$testsdir/$luascript
 lua2-api=2
 allow-axfr-ips=0.0.0.0/0,::/0
 EOF
 
-               $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+               $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
                        --no-shuffle --launch=lua2 \
                        --cache-ttl=$cachettl --dname-processing --no-config \
                        --distributor-threads=1 --zone-cache-refresh-interval=$interval \
index 8aca1fafb026e7d93aee2d2aab2096920ce55e32..7abb1b4502da3aa4079c73b83c4df83d6aec445e 100644 (file)
@@ -77,7 +77,7 @@ case $context in
                                extracontexts="dnssec nsec3"
                                skipreasons="nsec3 nodyndns"
                        fi
-                       
+
                        remote_add_param="--remote-dnssec=yes"
                elif [ "$remotesec" = "dnssec" ]
                then
@@ -90,7 +90,7 @@ case $context in
 
                # generate pdns.conf for pdnsutil
                cat > pdns-remote.conf <<EOF
-module-dir=./modules
+module-dir=$PDNS_BUILD_PATH/modules
 launch=remote
 remote-connection-string=$connstr,timeout=10000
 EOF
@@ -114,16 +114,16 @@ EOF
 
                        # add DS records into list-all-records
                         $PDNSUTIL --config-dir=. --config-name=remote show-zone -v up.example.com | gawk '{ if ($1=="DS") { printf "up.example.com.            120     IN      DS      " $6 " " $7 " " $8 " " substr(toupper($9),0,56); if (length($9)>56) { print " " substr(toupper($9),57) } else { print "" } } }' > $testsdir/list-all-records/expected_dnssec_part2
-                       cat $testsdir/list-all-records/expected_dnssec_part1 $testsdir/list-all-records/expected_dnssec_part2 $testsdir/list-all-records/expected_dnssec_part3 > $testsdir/list-all-records/expected_result.dnssec 
+                       cat $testsdir/list-all-records/expected_dnssec_part1 $testsdir/list-all-records/expected_dnssec_part2 $testsdir/list-all-records/expected_dnssec_part3 > $testsdir/list-all-records/expected_result.dnssec
                        cp -f $testsdir/list-all-records/expected_result.dnssec $testsdir/list-all-records/expected_result.nsec3
                fi
 
-               $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+               $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
                        --no-shuffle --launch=remote \
                        --cache-ttl=$cachettl --dname-processing --no-config \
                        --distributor-threads=1 \
                        --dnsupdate=yes --zone-cache-refresh-interval=0 \
-                       --remote-connection-string="$connstr" $remote_add_param --module-dir=./modules &
+                       --remote-connection-string="$connstr" $remote_add_param --module-dir="$PDNS_BUILD_PATH/modules" &
                ;;
 
        *)
index 3ebafbf74ed82dc86751e8569cdb18615fd233be..dd35a3dce55fb6c24a6a425025d967b2ddc528ad 100644 (file)
@@ -1,10 +1,10 @@
 case $context in
        tinydns)
-               $RUNWRAPPER $PDNS --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
+               $RUNWRAPPER $PDNS --loglevel=7 --daemon=no --local-address=$address --local-port=$port --socket-dir=./ \
                        --no-shuffle --launch=tinydns \
                 --cache-ttl=$cachettl --dname-processing --no-config \
                        --dnsupdate=yes \
-                       --tinydns-dbfile=../modules/tinydnsbackend/data.cdb --module-dir=./modules &
+                       --tinydns-dbfile=../modules/tinydnsbackend/data.cdb --module-dir="$PDNS_BUILD_PATH/modules" &
                skipreasons="nodnssec noent nodyndns nometa noaxfr noalias"
                ;;
 
index 60c8844c0c3578dd8bb165cb5c743d255b3314f1..d1ced13730f8718ccdb5d85aa3148f63764e204f 100755 (executable)
@@ -7,19 +7,38 @@ fi
 PATH=.:$PATH:/usr/sbin
 MAKE=${MAKE:-make}
 
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
-export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
-export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
-export SDIG=${SDIG:-${PWD}/../pdns/sdig}
-export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
-export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
-export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
-export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
-export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
-export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+  # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+  PDNS_BUILD_PATH=.
+
+  export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+  export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
+  export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
+  export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
+  export SDIG=${SDIG:-${PWD}/../pdns/sdig}
+  export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
+  export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
+  export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
+  export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
+  export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
+  export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
+  export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+  export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+else
+  export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+  export PDNS2=${PDNS2:-$PDNS_BUILD_PATH/pdns-auth}
+  export PDNSRECURSOR=${PDNSRECURSOR:-$PDNS_BUILD_PATH/pdns/recursordist/pdns_recursor}
+  export RECCONTROL=${RECCONTROL:-$PDNS_BUILD_PATH/pdns/recursordist/rec_control}
+  export SDIG=${SDIG:-$PDNS_BUILD_PATH/sdig}
+  export NOTIFY=${NOTIFY:-$PDNS_BUILD_PATH/pdns-auth-notify}
+  export NSEC3DIG=${NSEC3DIG:-$PDNS_BUILD_PATH/nsec3dig}
+  export SAXFR=${SAXFR:-$PDNS_BUILD_PATH/saxfr}
+  export ZONE2SQL=${ZONE2SQL:-$PDNS_BUILD_PATH/pdns-zone2sql}
+  export ZONE2JSON=${ZONE2JSON:-$PDNS_BUILD_PATH/pdns-zone2json}
+  export ZONE2LDAP=${ZONE2LDAP:-$PDNS_BUILD_PATH/pdns-zone2ldap}
+  export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+  export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+fi
 
 unset _JAVA_OPTIONS
 
@@ -45,7 +64,7 @@ skipped=0
 
 touch passed_tests failed_tests skipped_tests
 
-for a in $(find $testsdir -type d | grep -v ^.$ | grep -v .svn | grep -v ^confdir | LC_ALL=C sort) 
+for a in $(find $testsdir -type d | grep -v ^.$ | grep -v .svn | grep -v ^confdir | LC_ALL=C sort)
 do
        if [ ! -x $a/command ]
        then
@@ -60,9 +79,9 @@ do
 
        echo  "$testname: " >> test-results
        cat $a/description >> test-results
-       
+
        SKIPIT=0
-       if [ -e $a/skip ] 
+       if [ -e $a/skip ]
        then
                SKIPIT=1
                result="        Skipped test $a"
@@ -94,7 +113,7 @@ do
                result="        Skipped test $a because it's not the specified single test"
        fi
 
-                               
+
        if [ $SKIPIT = 1 ]
        then
                echo $testname >> skipped_tests
@@ -115,7 +134,7 @@ do
                done
                [ -n "$context" ] && [ -e "$a/expected_result.$context" ] && expected=$a/expected_result.$context
                diff ${diffopts} $expected $a/real_result > $a/diff 2>&1
-               if [ -s $a/diff ] 
+               if [ -s $a/diff ]
                then
                        if [ $FAIL = 0 ]
                        then
@@ -144,7 +163,7 @@ do
                                failed=$[$failed+1]
                        fi
                fi
-       fi      
+       fi
        echo "$result"
        echo
        echo "$result" >> test-results
index fa7f16e41934d4bb3b3d2ec52b962b8fbe97bbc5..9c23ae869ac3db1593f505aa7e4605e5347199ef 100755 (executable)
@@ -4,22 +4,42 @@ if [ "${PDNS_DEBUG}" = "YES" ]; then
   set -x
 fi
 
-export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
-export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
-export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
-export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
-export SDIG=${SDIG:-${PWD}/../pdns/sdig}
-export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
-export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
-export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
-export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
-export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
-export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
-export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+if [ -z "$PDNS_BUILD_PATH" ]; then
+  # PDNS_BUILD_PATH is unset or empty. Assume an autotools build.
+  PDNS_BUILD_PATH=.
+
+  export PDNS=${PDNS:-${PWD}/../pdns/pdns_server}
+  export PDNS2=${PDNS2:-${PWD}/../pdns/pdns_server}
+  export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
+  export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
+  export SDIG=${SDIG:-${PWD}/../pdns/sdig}
+  export NOTIFY=${NOTIFY:-${PWD}/../pdns/pdns_notify}
+  export NSEC3DIG=${NSEC3DIG:-${PWD}/../pdns/nsec3dig}
+  export SAXFR=${SAXFR:-${PWD}/../pdns/saxfr}
+  export ZONE2SQL=${ZONE2SQL:-${PWD}/../pdns/zone2sql}
+  export ZONE2LDAP=${ZONE2LDAP:-${PWD}/../pdns/zone2ldap}
+  export ZONE2JSON=${ZONE2JSON:-${PWD}/../pdns/zone2json}
+  export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
+  export PDNSCONTROL=${PDNSCONTROL:-${PWD}/../pdns/pdns_control}
+else
+  export PDNS=${PDNS:-$PDNS_BUILD_PATH/pdns-auth}
+  export PDNS2=${PDNS2:-$PDNS_BUILD_PATH/pdns-auth}
+  export PDNSRECURSOR=${PDNSRECURSOR:-$PDNS_BUILD_PATH/pdns/recursordist/pdns_recursor}
+  export RECCONTROL=${RECCONTROL:-$PDNS_BUILD_PATH/pdns/recursordist/rec_control}
+  export SDIG=${SDIG:-$PDNS_BUILD_PATH/sdig}
+  export NOTIFY=${NOTIFY:-$PDNS_BUILD_PATH/pdns-auth-notify}
+  export NSEC3DIG=${NSEC3DIG:-$PDNS_BUILD_PATH/nsec3dig}
+  export SAXFR=${SAXFR:-$PDNS_BUILD_PATH/saxfr}
+  export ZONE2SQL=${ZONE2SQL:-$PDNS_BUILD_PATH/pdns-zone2sql}
+  export ZONE2JSON=${ZONE2JSON:-$PDNS_BUILD_PATH/pdns-zone2json}
+  export ZONE2LDAP=${ZONE2LDAP:-$PDNS_BUILD_PATH/pdns-zone2ldap}
+  export PDNSUTIL=${PDNSUTIL:-$PDNS_BUILD_PATH/pdns-auth-util}
+  export PDNSCONTROL=${PDNSCONTROL:-$PDNS_BUILD_PATH/pdns-auth-control}
+fi
+
 export RESOLVERIP=${RESOLVERIP:-8.8.8.8}
 export FIX_TESTS=${FIX_TESTS:-NO}
 
-
 ALGORITHM=${ALGORITHM:="hmac-md5"}
 KEY=${KEY:="kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}
 
@@ -37,7 +57,7 @@ for arg; do
     esac
 done; unset -v arg
 if [ "$_show_help" -eq 1 ]; then
-       grep -v '^#' << '__EOF__'
+        grep -v '^#' << '__EOF__'
 
 Usage: ./start-test-stop <port> [<context>] [wait|nowait] [<cachettl>] [<specifictest>]
 
@@ -73,7 +93,7 @@ lua2 lua2-dnssec lua2-nsec3 lua2-nsec3-narrow
 
 * Specifictest can be used to run only one single test.
 __EOF__
-       exit
+        exit
 fi
 unset -v _show_help
 
@@ -83,129 +103,129 @@ source ../regression-tests/common
 
 bindwait ()
 {
-       check_process
-       configname=$1
-       domcount=$(grep -c ^zone named.conf)
-       if [ ! -x $PDNSCONTROL ]
-       then
-               echo "No pdns_control found"
-               exit
-       fi
-       loopcount=0
-
-       while [ $loopcount -lt 20 ]
-       do
-               sleep 5
-               done=$( ($PDNSCONTROL --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
-               if [ $done = $domcount ]
-               then
-                       return
-               fi
-               let loopcount=loopcount+1
-       done
-
-       if [ $done != $domcount ]
-       then
-               echo "Domain parsing failed" >> failed_tests
-       fi
+        check_process
+        configname=$1
+        domcount=$(grep -c ^zone named.conf)
+        if [ ! -x $PDNSCONTROL ]
+        then
+                echo "No pdns_control found"
+                exit
+        fi
+        loopcount=0
+
+        while [ $loopcount -lt 20 ]
+        do
+                sleep 5
+                done=$( ($PDNSCONTROL --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
+                if [ $done = $domcount ]
+                then
+                        return
+                fi
+                let loopcount=loopcount+1
+        done
+
+        if [ $done != $domcount ]
+        then
+                echo "Domain parsing failed" >> failed_tests
+        fi
 }
 
 securezone ()
 {
-       local zone=$1
-       local configname=$2
-
-       if [ -n "$configname" ]
-       then
-               configname="--config-name=$configname"
-       fi
-       if [ "${zone: 0:16}" = "secure-delegated" ]
-       then
-               $PDNSUTIL --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
-               $PDNSUTIL --config-dir=. $configname add-zone-key $zone rsasha256 1024 zsk active 2>&1
-               $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
-               $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
-               $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
-       else
-               # check if PKCS#11 should be used
-               if [ "$pkcs11" -eq 1 ]; then
-                       if [ "$slot" == "" ]; then
-                               slot=0
-                       else
-                               slot=$((slot+1))
-                       fi
-                       label=pdnstest-${EPOCHSECONDS}-${slot}
-                       softhsm2-util --delete-token --label $label 2> /dev/null || true
-                       softhsm2-util --init-token --label $label --free --pin 1234 --so-pin 1234
-                       kid=`$PDNSUTIL --config-dir=. $configname hsm assign $zone ecdsa256 ksk softhsm2 $label 1234 $label 2>&1 | grep softhsm | awk '{ print $NF }'`
-                       $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
-                       $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
-               else
-                       $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
-               fi
-               if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
-                       $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
-                       $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
-               fi
-               if [ "$zone" = "dnssec-parent.com" ]; then
-                       $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 0 2>&1
-                       $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone delete 2>&1
-               fi
-       fi
+        local zone=$1
+        local configname=$2
+
+        if [ -n "$configname" ]
+        then
+                configname="--config-name=$configname"
+        fi
+        if [ "${zone: 0:16}" = "secure-delegated" ]
+        then
+                $PDNSUTIL --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
+                $PDNSUTIL --config-dir=. $configname add-zone-key $zone rsasha256 1024 zsk active 2>&1
+                $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
+                $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
+                $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
+        else
+                # check if PKCS#11 should be used
+                if [ "$pkcs11" -eq 1 ]; then
+                        if [ "$slot" == "" ]; then
+                                slot=0
+                        else
+                                slot=$((slot+1))
+                        fi
+                        label=pdnstest-${EPOCHSECONDS}-${slot}
+                        softhsm2-util --delete-token --label $label 2> /dev/null || true
+                        softhsm2-util --init-token --label $label --free --pin 1234 --so-pin 1234
+                        kid=`$PDNSUTIL --config-dir=. $configname hsm assign $zone ecdsa256 ksk softhsm2 $label 1234 $label 2>&1 | grep softhsm | awk '{ print $NF }'`
+                        $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
+                        $PDNSUTIL --config-dir=. $configname rectify-zone $zone 2>&1
+                else
+                        $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
+                fi
+                if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
+                        $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
+                        $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
+                fi
+                if [ "$zone" = "dnssec-parent.com" ]; then
+                        $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 0 2>&1
+                        $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone delete 2>&1
+                fi
+        fi
 }
 
 kill_process ()
 {
-       set +e
-       trap - EXIT INT TERM
-
-       if [ $1 -gt 1 ]
-       then
-               echo "exitvalue$1" >> failed_tests
-               ./toxml
-               ./totar
-       fi
-
-       pids=$(cat pdns*.pid)
-
-       if [ -n "$pids" ]
-       then
-               kill $pids
-               # make sure they die.
-               loopcount=0
-               done=0
-               while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
-               do
-                       done=1
-                       for pid in $pids
-                       do
-                               kill -0 $pid > /dev/null 2>&1
-                               if [ $? -eq 0 ];
-                               then
-                                       done=0
-                               fi
-                       done
-                       let loopcount=loopcount+1
-                       sleep 1
-               done
-
-               kill -9 $pids
-       fi
-
-       rm pdns*.pid
-       exit $1
+        set +e
+        trap - EXIT INT TERM
+
+        if [ $1 -gt 1 ]
+        then
+                echo "exitvalue$1" >> failed_tests
+                ./toxml
+                ./totar
+        fi
+
+        pids=$(cat pdns*.pid)
+
+        if [ -n "$pids" ]
+        then
+                kill $pids
+                # make sure they die.
+                loopcount=0
+                done=0
+                while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
+                do
+                        done=1
+                        for pid in $pids
+                        do
+                                kill -0 $pid > /dev/null 2>&1
+                                if [ $? -eq 0 ];
+                                then
+                                        done=0
+                                fi
+                        done
+                        let loopcount=loopcount+1
+                        sleep 1
+                done
+
+                kill -9 $pids
+        fi
+
+        rm pdns*.pid
+        exit $1
 }
 
 if [ ! -x $PDNS ]
  then
-       echo "$PDNS is not executable binary"
-       exit
+        echo "$PDNS is not executable binary"
+        exit
 fi
 
 if [ ! -x $PDNS2 ]
 then
-       echo "$PDNS2 is not executable binary"
-       exit
+        echo "$PDNS2 is not executable binary"
+        exit
 fi
 
 address="${PDNS_LISTEN_ADDR:-127.0.0.1}"
@@ -230,10 +250,10 @@ done
 # Copy original zones because the test might modify them (well only the dyndns stuff, but let's make this work for others as well)
 for zone in $(grep 'zone ' named.conf  | cut -f2 -d\")
 do
-       if [ -f zones/$zone.orig ]
-       then
-               cp -f zones/$zone.orig zones/$zone
-       fi
+        if [ -f zones/$zone.orig ]
+        then
+                cp -f zones/$zone.orig zones/$zone
+        fi
 done
 
 rm -f pdns*.pid
@@ -245,21 +265,21 @@ both=no
 
 if [[ "$context" =~ .+-presigned.* ]]
 then
-       presigned=yes
-       port=$((port-100))
-       eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
-       if [ -z "$presignedcontext" ]
-       then
-               presignedcontext=$context
-       fi
+        presigned=yes
+        port=$((port-100))
+        eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
+        if [ -z "$presignedcontext" ]
+        then
+                presignedcontext=$context
+        fi
 fi
 
 if [ "${context: -5}" = "-both" ]
 then
-       both=yes
-       port=$((port-100))
-       context=${context%-both}
-       presignedcontext=$context
+        both=yes
+        port=$((port-100))
+        context=${context%-both}
+        presignedcontext=$context
 fi
 
 optout=0
@@ -267,7 +287,7 @@ pkcs11=0
 
 if [ "${context: -13}" = "-nsec3-optout" ]
 then
-       optout=1
+        optout=1
 fi
 
 if [ "${context: -7}" = "-pkcs11" ]
@@ -291,30 +311,30 @@ source backends/common
 start_master
 
 if [ "$skiplua" == "1" ]; then
-       skipreasons="$skipreasons nolua"
+        skipreasons="$skipreasons nolua"
 fi
 
 check_process
 
 dotests () {
-       nameserver=127.0.0.1 ./runtests $spectest
-       ./toxml
-       ./totar
-
-       cat ./trustedkeys
-
-       if [ -s "./failed_tests" ]
-       then
-               for t in `cat failed_tests`
-               do
-                       echo -e "\n\n$t"
-                       cat ${testsdir}/$t/diff
-               done
-               if [ "${!1}" -eq 0 ]
-               then
-                       eval "$1=1"
-               fi
-       fi
+        nameserver=127.0.0.1 ./runtests $spectest
+        ./toxml
+        ./totar
+
+        cat ./trustedkeys
+
+        if [ -s "./failed_tests" ]
+        then
+                for t in `cat failed_tests`
+                do
+                        echo -e "\n\n$t"
+                        cat ${testsdir}/$t/diff
+                done
+                if [ "${!1}" -eq 0 ]
+                then
+                        eval "$1=1"
+                fi
+        fi
 }
 
 ## TODO: give sdig a timeout
@@ -334,25 +354,25 @@ sleep 2
 
 if [ $presigned = no ] || [ $both = yes ]
 then
-       dotests RETVAL
+        dotests RETVAL
 fi
 
 if [ $presigned = yes ] || [ $both = yes ]
 then
-       start_slave
+        start_slave
 
-       export port
-       export context
-       export skipreasons
-       export backend
+        export port
+        export context
+        export skipreasons
+        export backend
 
-       dotests RETVAL
+        dotests RETVAL
 fi
 
 if [ "$wait" = "wait" ]
 then
-       echo tests done! push enter to terminate instance
-       read l
+        echo tests done! push enter to terminate instance
+        read l
 fi
 
 trap "kill_process $RETVAL" EXIT
index 16dbcea353a023bd6f087f2eacb853eaedc7a4c8..f2b00d5a0a1cafe611e7a206c6f4adf5b4e30e93 100644 (file)
--- a/tasks.py
+++ b/tasks.py
@@ -259,12 +259,16 @@ auth_backend_test_deps = dict(
 )
 
 @task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
-def install_auth_test_deps(c, backend): # FIXME: rename this, we do way more than apt-get
+def install_auth_test_deps_only(c, backend):
     extra=[]
     for b in backend:
         extra.extend(auth_backend_test_deps[b])
     c.sudo('DEBIAN_FRONTEND=noninteractive apt-get -y install ' + ' '.join(extra+auth_test_deps))
 
+@task(help={'backend': 'Backend to install test deps for, e.g. gsqlite3; can be repeated'}, iterable=['backend'], optional=['backend'])
+def install_auth_test_deps(c, backend): # FIXME: rename this, we do way more than apt-get
+    install_auth_test_deps_only(c, backend)
+
     c.run('chmod +x /opt/pdns-auth/bin/* /opt/pdns-auth/sbin/*')
     # c.run('''if [ ! -e $HOME/bin/jdnssec-verifyzone ]; then
     #               wget https://github.com/dblacka/jdnssec-tools/releases/download/0.14/jdnssec-tools-0.14.tar.gz
@@ -862,6 +866,22 @@ backend_regress_tests = dict(
     geoip_mmdb = ['geoip'],
 )
 
+backend_rootzone_tests = dict(
+    geoip = False,
+    geoip_mmdb = False,
+    lua2 = False,
+    ldap = False,
+    tinydns = False,
+    remote = False,
+    bind = True,
+    lmdb = True,
+    gmysql = True,
+    gpgsql = True,
+    gsqlite3 = True,
+    godbc_sqlite3 = True,
+    godbc_mssql = True,
+)
+
 godbc_mssql_credentials = {"username": "sa", "password": "SAsa12%%-not-a-secret-password"}
 
 godbc_config = f'''
@@ -916,6 +936,7 @@ def setup_softhsm(c):
 @task
 def test_auth_backend(c, backend):
     pdns_auth_env_vars = f'PDNS=/opt/pdns-auth/sbin/pdns_server PDNS2=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig NOTIFY=/opt/pdns-auth/bin/pdns_notify NSEC3DIG=/opt/pdns-auth/bin/nsec3dig SAXFR=/opt/pdns-auth/bin/saxfr ZONE2SQL=/opt/pdns-auth/bin/zone2sql ZONE2LDAP=/opt/pdns-auth/bin/zone2ldap ZONE2JSON=/opt/pdns-auth/bin/zone2json PDNSUTIL=/opt/pdns-auth/bin/pdnsutil PDNSCONTROL=/opt/pdns-auth/bin/pdns_control PDNSSERVER=/opt/pdns-auth/sbin/pdns_server SDIG=/opt/pdns-auth/bin/sdig GMYSQLHOST={auth_backend_ip_addr} GMYSQL2HOST={auth_backend_ip_addr} MYSQL_HOST={auth_backend_ip_addr} PGHOST={auth_backend_ip_addr} PGPORT=5432'
+    backend_env_vars = ''
 
     if backend == 'remote':
         ci_auth_install_remotebackend_test_deps(c)
@@ -928,39 +949,32 @@ def test_auth_backend(c, backend):
 
     if backend == 'bind':
         setup_softhsm(c)
-        with c.cd('regression-tests'):
-            for variant in backend_regress_tests[backend]:
-                c.run(f'{pdns_auth_env_vars} SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf ./start-test-stop 5300 {variant}')
-        return
+        backend_env_vars = 'SOFTHSM2_CONF=/opt/pdns-auth/softhsm/softhsm2.conf'
 
     if backend == 'godbc_sqlite3':
         setup_godbc_sqlite3(c)
-        with c.cd('regression-tests'):
-            for variant in backend_regress_tests[backend]:
-                c.run(f'{pdns_auth_env_vars} GODBC_SQLITE3_DSN=pdns-sqlite3-1 ./start-test-stop 5300 {variant}')
-        return
+        backend_env_vars = 'GODBC_SQLITE3_DSN=pdns-sqlite3-1'
 
     if backend == 'godbc_mssql':
         setup_godbc_mssql(c)
-        with c.cd('regression-tests'):
-            for variant in backend_regress_tests[backend]:
-                c.run(f'{pdns_auth_env_vars} GODBC_MSSQL_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL2_DSN=pdns-mssql-docker ./start-test-stop 5300 {variant}')
-        return
+        backend_env_vars = f'GODBC_MSSQL_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL_DSN=pdns-mssql-docker GODBC_MSSQL2_PASSWORD={godbc_mssql_credentials["password"]} GODBC_MSSQL2_USERNAME={godbc_mssql_credentials["username"]} GODBC_MSSQL2_DSN=pdns-mssql-docker'
 
     if backend == 'ldap':
         setup_ldap_client(c)
 
     if backend == 'geoip_mmdb':
-        with c.cd('regression-tests'):
-            for variant in backend_regress_tests[backend]:
-                c.run(f'{pdns_auth_env_vars} geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb ./start-test-stop 5300 {variant}')
-        return
+        backend_env_vars = 'geoipdatabase=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb'
 
     with c.cd('regression-tests'):
         if backend == 'lua2':
             c.run('touch trustedkeys')  # avoid silly error during cleanup
         for variant in backend_regress_tests[backend]:
-            c.run(f'{pdns_auth_env_vars} ./start-test-stop 5300 {variant}')
+            c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
+
+    if backend_rootzone_tests[backend]:
+        with c.cd('regression-tests.rootzone'):
+            for variant in backend_regress_tests[backend]:
+                c.run(f'{pdns_auth_env_vars} {backend_env_vars} ./start-test-stop 5300 {variant}')
 
     if backend == 'gsqlite3':
         if os.getenv('SKIP_IPV6_TESTS'):
@@ -1034,30 +1048,17 @@ def coverity_upload(c, email, project, tarball):
 
 @task
 def ci_build_and_install_quiche(c, repo):
-    with open(f'{repo}/builder-support/helpers/quiche.json') as quiche_json:
-        quiche_data = json.load(quiche_json)
-        quiche_version = quiche_data['version']
-        quiche_hash = quiche_data['SHA256SUM']
-
-    # we have to pass -L because GitHub will do a redirect, sadly
-    c.run(f'curl -L -o quiche-{quiche_version}.tar.gz https://github.com/cloudflare/quiche/archive/{quiche_version}.tar.gz')
-    # Line below should echo two spaces between digest and name
-    c.run(f'echo {quiche_hash}"  "quiche-{quiche_version}.tar.gz | sha256sum -c -')
-    c.run(f'tar xf quiche-{quiche_version}.tar.gz')
-    with c.cd(f'quiche-{quiche_version}'):
-        c.run('cargo build --release --no-default-features --features ffi,boringssl-boring-crate --package quiche')
-        # cannot use c.sudo() inside a cd() context, see https://github.com/pyinvoke/invoke/issues/687
-        c.run('sudo install -Dm644 quiche/include/quiche.h /usr/include')
-        c.run('sudo install -Dm644 target/release/libquiche.so /usr/lib')
-        c.run('install -D target/release/libquiche.so /opt/dnsdist/lib/libquiche.so')
-        c.run(f"""sudo install -Dm644 /dev/stdin /usr/lib/pkgconfig/quiche.pc <<PC
-# quiche
-Name: quiche
-Description: quiche library
-URL: https://github.com/cloudflare/quiche
-Version: {quiche_version}
-Libs: -lquiche
-PC""")
+    with c.cd(f'{repo}/builder-support/helpers/'):
+        # be careful that rust needs to have been installed system-wide,
+        # as the one installed in GitHub actions' Ubuntu images in /home/runner/.cargo/bin/cargo
+        # is not in the path for the root user (and shouldn't be)
+        c.run(f'sudo {repo}/builder-support/helpers/install_quiche.sh')
+
+    # cannot use c.sudo() inside a cd() context, see https://github.com/pyinvoke/invoke/issues/687
+    c.run('sudo mv /usr/lib/libdnsdist-quiche.so /usr/lib/libquiche.so')
+    c.run("sudo sed -i 's,^Libs:.*,Libs: -lquiche,g' /usr/lib/pkgconfig/quiche.pc")
+    c.run('mkdir -p /opt/dnsdist/lib')
+    c.run('cp /usr/lib/libquiche.so /opt/dnsdist/lib/libquiche.so')
 
 # this is run always
 def setup():