Version in base suite: 5.2.13-0+deb13u1 Base version: pdns-recursor_5.2.13-0+deb13u1 Target version: pdns-recursor_5.4.9-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/pdns-recursor/pdns-recursor_5.2.13-0+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/pdns-recursor/pdns-recursor_5.4.9-1~deb13u1.dsc COPYING | 9 Makefile.am | 70 Makefile.in | 746 RECURSOR-MIB.in | 6 RECURSOR-MIB.txt | 80 aclocal.m4 | 473 aggressive_nsec.cc | 54 aggressive_nsec.hh | 5 arguments.cc | 21 auth-catalogzone.hh | 13 axfr-retriever.cc | 35 axfr-retriever.hh | 4 base64.cc | 72 base64.hh | 5 build-aux/compile | 11 build-aux/config.guess | 112 build-aux/config.sub | 251 build-aux/depcomp | 15 build-aux/gen-version | 77 build-aux/install-sh | 14 build-aux/missing | 75 build-aux/test-driver | 15 builder-support/gen-version | 4 burtle.hh | 6 cachecleaner.hh | 2 channel.hh | 26 comment.hh | 7 config.h.in | 108 configure | 4328 +- configure.ac | 14 credentials.cc | 65 credentials.hh | 15 debian/.gitlab-ci.yml | 1 debian/changelog | 184 debian/control | 28 debian/copyright | 8 debian/gbp.conf | 4 debian/patches/0002-Relax-cargo-dependencies-for-trixie.patch | 30 debian/patches/series | 1 debian/patches/testrunner-log-verbosity | 4 debian/pdns-recursor.conffiles | 1 debian/pdns-recursor.lintian-overrides | 4 debian/pdns-recursor.postinst | 7 debian/pdns-recursor.preinst | 29 debian/pdns-recursor.sysusers | 1 debian/rules | 46 debian/source/lintian-overrides | 4 debian/watch | 8 dns.cc | 69 dns.hh | 68 dns_random.hh | 5 dnsbackend.hh | 197 dnslabeltext.cc | 109 dnslabeltext.rl | 5 dnsmessage.proto | 6 dnsname.cc | 378 dnsname.hh | 282 dnspacket.hh | 10 dnsparser.cc | 212 dnsparser.hh | 136 dnsrecords.cc | 63 dnsrecords.hh | 339 dnssec.hh | 189 dnssecinfra.cc | 51 dnssecinfra.hh | 2 dnsseckeeper.hh | 314 dnstap.cc | 15 dnstap.hh | 10 dnstap.proto | 23 dnswriter.cc | 49 dnswriter.hh | 13 dolog.hh | 47 ednscookies.cc | 119 ednscookies.hh | 32 ednsextendederror.hh | 2 ednsoptions.cc | 84 ednsoptions.hh | 7 ednssubnet.cc | 57 ednssubnet.hh | 45 effective_tld_names.dat |16409 --------- ext/Makefile.am | 1 ext/Makefile.in | 20 ext/arc4random/Makefile.am | 3 ext/arc4random/Makefile.in | 36 ext/arc4random/meson.build | 20 ext/json11/Makefile.am | 4 ext/json11/Makefile.in | 37 ext/json11/json11.cpp | 54 ext/json11/json11.hpp | 6 ext/json11/meson.build | 12 ext/luawrapper/include/LuaContext.hpp | 179 ext/luawrapper/meson.build | 3 ext/probds/Makefile.in | 33 ext/probds/meson.build | 12 ext/protozero/CHANGELOG.md | 449 ext/protozero/LICENSE.from_folly | 177 ext/protozero/LICENSE.md | 26 ext/protozero/include/protozero/basic_pbf_builder.hpp | 4 ext/protozero/include/protozero/basic_pbf_writer.hpp | 56 ext/protozero/include/protozero/buffer_string.hpp | 4 ext/protozero/include/protozero/config.hpp | 11 ext/protozero/include/protozero/data_view.hpp | 4 ext/protozero/include/protozero/pbf_message.hpp | 2 ext/protozero/include/protozero/pbf_reader.hpp | 8 ext/protozero/include/protozero/types.hpp | 2 ext/protozero/include/protozero/varint.hpp | 47 ext/protozero/include/protozero/version.hpp | 6 ext/protozero/meson.build | 3 ext/yahttp/Makefile.am | 5 ext/yahttp/Makefile.in | 25 ext/yahttp/meson.build | 3 ext/yahttp/yahttp/Makefile.am | 3 ext/yahttp/yahttp/Makefile.in | 36 ext/yahttp/yahttp/meson.build | 26 ext/yahttp/yahttp/reqresp.cpp | 36 ext/yahttp/yahttp/reqresp.hpp | 16 ext/yahttp/yahttp/router.cpp | 8 filterpo.cc | 4 filterpo.hh | 2 fstrm_logger.cc | 4 fstrm_logger.hh | 2 html/index.html | 2 html/js/handlebars-v4.0.11-min.js | 284 html/js/handlebars-v4.0.11.js | 4840 -- html/js/handlebars-v4.7.8-min.js | 29 html/js/handlebars-v4.7.8.js | 5972 +++ html/js/moment.js | 737 html/js/moment.min.js | 2 html/js/rickshaw.js | 703 html/js/rickshaw.min.js | 6 iputils.cc | 30 iputils.hh | 206 libssl.cc | 292 libssl.hh | 24 lock.hh | 8 logger.cc | 19 logger.hh | 17 logging.cc | 50 logging.hh | 60 logr.hh | 42 lua-base4.cc | 36 lua-base4.hh | 4 lua-recursor4.cc | 142 lua-recursor4.hh | 30 lwres.cc | 441 lwres.hh | 20 m4/ax_cxx_compile_stdcxx.m4 | 92 m4/ax_cxx_compile_stdcxx_20.m4 | 4 m4/pdns_check_curl.m4 | 4 m4/pdns_check_libcrypto.m4 | 2 m4/pdns_check_libcrypto_ecdsa.m4 | 4 m4/pdns_check_libcrypto_eddsa.m4 | 4 m4/pdns_enable_p11kit.m4 | 21 m4/pdns_with_gnutls.m4 | 34 m4/pdns_with_lua.m4 | 50 malloctrace.cc | 6 malloctrace.hh | 2 meson-dist-script.sh | 72 meson.build | 821 meson/atomics/atomic_add_fetch.cc | 8 meson/atomics/meson.build | 23 meson/auto-var-init/meson.build | 13 meson/boost-context/meson.build | 2 meson/boost-filesystem/meson.build | 2 meson/boost-program-options/meson.build | 2 meson/boost-serialization/meson.build | 7 meson/boost-test/meson.build | 5 meson/boost/meson.build | 5 meson/cdb/meson.build | 21 meson/clock-gettime/meson.build | 15 meson/code-coverage/meson.build | 31 meson/compiler-setup/meson.build | 22 meson/config/meson.build | 2 meson/cxx-fs/cxx-fs.cc | 8 meson/cxx-fs/meson.build | 36 meson/dlopen/meson.build | 15 meson/dnstap/meson.build | 16 meson/dot/meson.build | 8 meson/geoip/meson.build | 14 meson/gnutls/meson.build | 19 meson/gss-tsig/meson.build | 21 meson/hardening/control-flow/meson.build | 10 meson/hardening/fortify-source/meson.build | 37 meson/hardening/meson.build | 34 meson/hardening/relro/meson.build | 16 meson/hardening/stack-clash-prot/meson.build | 10 meson/hardening/stack-prot/meson.build | 8 meson/hardening/stack-smashing-prot/meson.build | 10 meson/ipcipher/meson.build | 9 meson/ldap/meson.build | 68 meson/libcap/meson.build | 5 meson/libcrypto/bn_new.cc | 7 meson/libcrypto/ecdsa/meson.build | 33 meson/libcrypto/eddsa/meson.build | 24 meson/libcrypto/meson.build | 118 meson/libcurl/meson.build | 4 meson/libdir/meson.build | 1 meson/libresolv/meson.build | 22 meson/libsnmp/meson.build | 40 meson/libsodium/meson.build | 21 meson/libssl-engines/meson.build | 5 meson/libssl/meson.build | 48 meson/libsystemd/meson.build | 14 meson/lmdb/meson.build | 11 meson/lua-records/meson.build | 32 meson/lua/meson.build | 54 meson/malloc-trace/meson.build | 2 meson/mmap/meson.build | 7 meson/mmdb/meson.build | 14 meson/mysql/meson.build | 36 meson/net-libs/meson.build | 44 meson/nod/meson.build | 22 meson/odbc/meson.build | 30 meson/pgsql/meson.build | 44 meson/pkcs11/meson.build | 15 meson/pkcs11/p11_kit_module_for_name.cc | 7 meson/platform/meson.build | 64 meson/prog-curl/meson.build | 3 meson/pthread-headers/meson.build | 18 meson/pthread-np/meson.build | 13 meson/pthread-setname/meson.build | 57 meson/pthread-setname/pthread_set_name_np_2args.cc | 9 meson/pthread-setname/pthread_set_name_np_void_2args.cc | 10 meson/pthread-setname/pthread_setname_np_1arg.cc | 9 meson/pthread-setname/pthread_setname_np_2args.cc | 10 meson/pthread-setname/pthread_setname_np_3args.cc | 9 meson/reproducible/meson.build | 48 meson/requirements.in | 9 meson/requirements.txt | 225 meson/sanitizers/address-sanitizer-fiber-switching/meson.build | 44 meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_1ptr.cc | 7 meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_3ptrs.cc | 7 meson/sanitizers/meson.build | 25 meson/socket-dir/meson.build | 2 meson/sqlite3/meson.build | 13 meson/strerror/meson.build | 13 meson/strerror/strerror_r.c | 8 meson/summary/meson.build | 5 meson/sysconfdir/meson.build | 1 meson/systemd/meson.build | 60 meson/timet-sign/meson.build | 10 meson/timet-sign/timet_sign.cc | 8 meson/timet-size/meson.build | 9 meson/tm-gmtoff/meson.build | 8 meson/various-functions/meson.build | 21 meson/various-headers/meson.build | 5 meson/verbose-logging/meson.build | 2 meson/version/meson.build | 2 meson/yaml-cpp/meson.build | 21 meson/zeromq/meson.build | 17 meson_options.txt | 27 metrics.py | 5 metrics_table.py | 116 minicurl.cc | 8 minicurl.hh | 5 misc.cc | 322 misc.hh | 172 mkpubsuffixcc | 22 mplexer.hh | 13 mtasker.hh | 12 mtasker_context.cc | 14 namespaces.hh | 1 negcache.cc | 79 negcache.hh | 40 nod.cc | 24 nod.hh | 5 noinitvector.hh | 1 nsecrecords.cc | 8 opensslsigners.cc | 68 packetcache.hh | 23 pdns-recursor.service.in | 1 pdns-recursor.service.meson.in | 53 pdns_recursor.1 | 7 pdns_recursor.cc | 792 pdnsexception.hh | 6 protozero-helpers.hh | 98 protozero-trace.cc | 605 protozero-trace.hh | 884 protozero.hh | 28 pubsuffix.cc |16553 +++++----- pubsuffix.hh | 1 pubsuffixloader.cc | 89 qtype.cc | 25 qtype.hh | 14 ratelimitedlog.hh | 22 rcpgenerator.cc | 304 rcpgenerator.hh | 10 rec-carbon.cc | 21 rec-cookiestore.cc | 57 rec-cookiestore.hh | 104 rec-eventtrace.cc | 115 rec-eventtrace.hh | 205 rec-lua-conf.cc | 285 rec-lua-conf.hh | 16 rec-main.cc | 800 rec-main.hh | 111 rec-metrics-gen.h | 282 rec-nsspeeds.cc | 229 rec-nsspeeds.hh | 172 rec-oids-gen.h | 174 rec-prometheus-gen.h | 200 rec-protozero.hh | 2 rec-responsestats.cc | 55 rec-responsestats.hh | 11 rec-rust-lib/Makefile.am | 33 rec-rust-lib/Makefile.in | 615 rec-rust-lib/README.md | 227 rec-rust-lib/cxxsettings-private.hh | 97 rec-rust-lib/cxxsettings.hh | 59 rec-rust-lib/cxxsupport.cc | 1549 rec-rust-lib/docs-new-preamble-in.rst | 683 rec-rust-lib/docs-old-preamble-in.rst | 41 rec-rust-lib/generate.py | 870 rec-rust-lib/meson.build | 36 rec-rust-lib/rust-bridge-in.rs | 460 rec-rust-lib/rust-preamble-in.rs | 51 rec-rust-lib/rust/Cargo.lock | 864 rec-rust-lib/rust/Cargo.toml | 38 rec-rust-lib/rust/Makefile.am | 32 rec-rust-lib/rust/Makefile.in | 610 rec-rust-lib/rust/build.rs | 13 rec-rust-lib/rust/build_recrust | 37 rec-rust-lib/rust/meson.build | 42 rec-rust-lib/rust/src/bridge.hh | 105 rec-rust-lib/rust/src/bridge.rs | 1457 rec-rust-lib/rust/src/helpers.rs | 82 rec-rust-lib/rust/src/lib.rs | 3921 ++ rec-rust-lib/rust/src/misc.rs | 69 rec-rust-lib/rust/src/web.rs | 1234 rec-rust-lib/table.py | 3678 ++ rec-snmp-gen.h | 174 rec-snmp.cc | 8 rec-system-resolve.cc | 34 rec-tcounters.cc | 2 rec-tcounters.hh | 57 rec-tcp.cc | 226 rec-tcpout.cc | 81 rec-tcpout.hh | 26 rec-web-stubs.hh | 38 rec-xfr.cc | 4 rec-zonetocache.cc | 8 rec_channel.cc | 182 rec_channel.hh | 36 rec_channel_rec.cc | 1666 - rec_control.1 | 27 rec_control.cc | 60 recpacketcache.cc | 27 recpacketcache.hh | 22 recursor_cache.cc | 322 recursor_cache.hh | 88 reczones-helpers.cc | 23 reczones.cc | 124 remote_logger.cc | 39 resolve-context.hh | 8 resolver.cc | 12 rpzloader.cc | 130 rpzloader.hh | 4 sanitizer.hh | 51 secpoll-recursor.cc | 33 secpoll-recursor.hh | 4 settings/Makefile.am | 33 settings/Makefile.in | 604 settings/README.md | 227 settings/cxxsettings-generated.cc | 2208 - settings/cxxsettings-private.hh | 97 settings/cxxsettings.hh | 59 settings/cxxsupport.cc | 1455 settings/docs-new-preamble-in.rst | 543 settings/docs-old-preamble-in.rst | 41 settings/generate.py | 842 settings/rust-bridge-in.rs | 398 settings/rust-preamble-in.rs | 48 settings/rust/Cargo.lock | 323 settings/rust/Cargo.toml | 21 settings/rust/Makefile.am | 20 settings/rust/Makefile.in | 587 settings/rust/build.rs | 7 settings/rust/src/bridge.hh | 30 settings/rust/src/bridge.rs | 1203 settings/rust/src/helpers.rs | 82 settings/rust/src/lib.rs | 3735 -- settings/table.py | 3636 -- sholder.hh | 11 shuffle.cc | 48 shuffle.hh | 1 sillyrecords.cc | 48 sodiumsigners.cc | 4 sstuff.hh | 40 svc-records.cc | 119 svc-records.hh | 104 syncres.cc | 501 syncres.hh | 64 taskqueue.cc | 4 tcounters.hh | 21 tcpiohandler.cc | 203 tcpiohandler.hh | 35 test-aggressive_nsec_cc.cc | 268 test-base64_cc.cc | 41 test-dns_random_hh.cc | 53 test-dnsname_cc.cc | 103 test-dnsrecordcontent.cc | 10 test-dnsrecords_cc.cc | 48 test-ednscookie_cc.cc | 116 test-ednsoptions_cc.cc | 97 test-filterpo_cc.cc | 18 test-iputils_hh.cc | 75 test-luawrapper.cc | 96 test-misc_hh.cc | 2 test-mtasker.cc | 4 test-packetcache_hh.cc | 40 test-protozero-trace.cc | 288 test-rcpgenerator_cc.cc | 211 test-rec-tcounters_cc.cc | 18 test-recpacketcache_cc.cc | 54 test-recursorcache_cc.cc | 366 test-reczones-helpers.cc | 19 test-rpzloader_cc.cc | 9 test-settings.cc | 31 test-shuffle_cc.cc | 58 test-signers.cc | 31 test-syncres_cc.cc | 73 test-syncres_cc.hh | 8 test-syncres_cc1.cc | 237 test-syncres_cc10.cc | 191 test-syncres_cc2.cc | 139 test-syncres_cc3.cc | 169 test-syncres_cc4.cc | 246 test-syncres_cc5.cc | 456 test-syncres_cc6.cc | 162 test-syncres_cc7.cc | 134 test-syncres_cc8.cc | 143 test-syncres_cc9.cc | 114 test-tsig.cc | 13 testrunner.cc | 6 threadname.cc | 4 ueberbackend.hh | 182 unix_utility.cc | 3 utility.hh | 1 validate-recursor.cc | 15 validate.cc | 179 validate.hh | 14 version.cc | 9 version.sh | 9 webserver.cc | 94 webserver.hh | 26 ws-api.cc | 98 ws-api.hh | 12 ws-recursor.cc | 431 ws-recursor.hh | 14 zonemd.cc | 16 zonemd.hh | 12 zoneparser-tng.cc | 38 zoneparser-tng.hh | 22 453 files changed, 54631 insertions(+), 56687 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8dst0qma/pdns-recursor_5.2.13-0+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8dst0qma/pdns-recursor_5.4.9-1~deb13u1.dsc: no acceptable signature found diff -Nru pdns-recursor-5.2.13/COPYING pdns-recursor-5.4.9/COPYING --- pdns-recursor-5.2.13/COPYING 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/COPYING 2026-10-26 09:46:36.000000000 +0000 @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -303,9 +303,8 @@ 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. + You should have received a copy of the GNU General Public License + along with this program; if not, see . Also add information on how to contact you by electronic and paper mail. @@ -336,4 +335,4 @@ proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. \ No newline at end of file +Public License instead of this License. diff -Nru pdns-recursor-5.2.13/Makefile.am pdns-recursor-5.4.9/Makefile.am --- pdns-recursor-5.2.13/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/Makefile.am 2026-10-26 08:26:51.000000000 +0000 @@ -1,16 +1,16 @@ JSON11_LIBS = $(top_builddir)/ext/json11/libjson11.la PROBDS_LIBS = $(top_builddir)/ext/probds/libprobds.la ARC4RANDOM_LIBS = $(top_builddir)/ext/arc4random/libarc4random.la -RUST_LIBS = $(top_builddir)/settings/rust/libsettings.a $(LIBDL) +RUST_LIBS = $(top_builddir)/rec-rust-lib/rust/librecrust.a $(LIBDL) AM_CPPFLAGS = $(LUA_CFLAGS) $(YAHTTP_CFLAGS) $(BOOST_CPPFLAGS) $(LIBSODIUM_CFLAGS) $(NET_SNMP_CFLAGS) $(LIBCAP_CFLAGS) $(SANITIZER_FLAGS) -O3 -Wall -pthread -DSYSCONFDIR=\"${sysconfdir}\" $(SYSTEMD_CFLAGS) AM_CPPFLAGS += \ -I$(top_srcdir)/ext/json11 \ -I$(top_srcdir)/ext/protozero/include \ - -I$(top_srcdir)/settings \ - -I$(top_builddir)/settings \ - -I$(top_srcdir)/settings/rust/src \ + -I$(top_srcdir)/rec-rust-lib \ + -I$(top_builddir)/rec-rust-lib \ + -I$(top_srcdir)/rec-rust-lib/rust/src \ $(YAHTTP_CFLAGS) \ $(LIBCRYPTO_INCLUDES) \ -DBOOST_CONTAINER_USE_STD_EXCEPTIONS @@ -46,15 +46,15 @@ recursor.yml-dist htmlfiles.h: incfiles ${srcdir}/html/* ${srcdir}/html/js/* - $(AM_V_GEN)$(srcdir)/incfiles > $@.tmp + $(AM_V_GEN)$(srcdir)/incfiles ${srcdir} > $@.tmp @mv $@.tmp $@ # Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make rec-metrics-gen%h rec-prometheus-gen%h rec-snmp-gen%h rec-oids-gen%h RECURSOR-MIB%txt: metrics.py metrics_table.py RECURSOR-MIB.in - $(PYTHON) metrics.py + $(PYTHON) ${srcdir}/metrics.py ${srcdir} . -# We explicitly build settings in two steps, as settings modifies files in the settings/rust subdir -SUBDIRS=ext settings settings/rust +# We explicitly build rec-rust-lib in two steps, as it modifies files in the rec-rust-lib/rust subdir +SUBDIRS=ext rec-rust-lib rec-rust-lib/rust if LUA AM_CPPFLAGS +=$(LUA_CFLAGS) @@ -67,7 +67,6 @@ dnslabeltext.cc \ dnslabeltext.rl \ dnsmessage.proto \ - effective_tld_names.dat \ epollmplexer.cc \ kqueuemplexer.cc \ lua_hpp.mk \ @@ -136,10 +135,11 @@ dnspacket.hh \ dnsparser.hh dnsparser.cc \ dnsrecords.cc dnsrecords.hh \ + dnssec.hh \ dnssecinfra.hh dnssecinfra.cc \ - dnsseckeeper.hh \ dnswriter.cc dnswriter.hh \ dolog.hh \ + ednscookies.cc ednscookies.hh \ ednsextendederror.cc ednsextendederror.hh \ ednsoptions.cc ednsoptions.hh \ ednspadding.cc ednspadding.hh \ @@ -174,6 +174,8 @@ pdns_recursor.cc \ pdnsexception.hh \ pollmplexer.cc \ + protozero-helpers.hh \ + protozero-trace.cc protozero-trace.hh \ protozero.cc protozero.hh \ proxy-protocol.cc proxy-protocol.hh \ pubsuffix.hh pubsuffix.cc \ @@ -183,11 +185,14 @@ ratelimitedlog.hh \ rcpgenerator.cc rcpgenerator.hh \ rec-carbon.cc \ + rec-cookiestore.cc rec-cookiestore.hh \ rec-eventtrace.cc rec-eventtrace.hh \ rec-lua-conf.hh rec-lua-conf.cc \ rec-main.hh rec-main.cc \ + rec-nsspeeds.cc rec-nsspeeds.hh \ rec-protozero.cc rec-protozero.hh \ rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc \ rec-snmp.hh rec-snmp.cc \ rec-system-resolve.hh rec-system-resolve.cc \ rec-taskqueue.cc rec-taskqueue.hh \ @@ -209,9 +214,9 @@ root-addresses.hh \ root-dnssec.hh \ rpzloader.cc rpzloader.hh \ + sanitizer.hh \ secpoll-recursor.cc secpoll-recursor.hh \ secpoll.cc secpoll.hh \ - settings/cxxsupport.cc \ sha.hh \ sholder.hh \ shuffle.cc shuffle.hh \ @@ -228,7 +233,6 @@ tcpiohandler.cc tcpiohandler.hh \ threadname.hh threadname.cc \ tsigverifier.cc tsigverifier.hh \ - ueberbackend.hh \ unix_utility.cc \ utility.hh \ uuid-utils.hh uuid-utils.cc \ @@ -242,7 +246,7 @@ zoneparser-tng.cc zoneparser-tng.hh nodist_pdns_recursor_SOURCES = \ - settings/cxxsettings-generated.cc + rec-rust-lib/cxxsettings-generated.cc if !HAVE_LUA_HPP BUILT_SOURCES += lua.hpp @@ -252,7 +256,6 @@ CLEANFILES += lua.hpp pdns_recursor_LDADD = \ - $(YAHTTP_LIBS) \ $(JSON11_LIBS) \ $(LIBCRYPTO_LIBS) \ $(BOOST_CONTEXT_LIBS) \ @@ -296,8 +299,8 @@ dnsname.cc dnsname.hh \ dnsparser.hh dnsparser.cc \ dnsrecords.cc \ + dnssec.hh \ dnssecinfra.cc \ - dnsseckeeper.hh \ dnswriter.cc dnswriter.hh \ ednscookies.cc ednscookies.hh \ ednsextendederror.cc ednsextendederror.hh \ @@ -319,15 +322,19 @@ opensslsigners.cc opensslsigners.hh \ pdnsexception.hh \ pollmplexer.cc \ + protozero-trace.cc protozero-trace.hh \ qtype.cc qtype.hh \ query-local-address.hh query-local-address.cc \ ratelimitedlog.hh \ rcpgenerator.cc \ rec-eventtrace.cc rec-eventtrace.hh \ + rec-nsspeeds.cc rec-nsspeeds.hh \ rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc \ rec-system-resolve.hh rec-system-resolve.cc \ rec-taskqueue.cc rec-taskqueue.hh \ rec-tcounters.cc rec-tcounters.hh \ + rec-web-stubs.hh \ rec-xfrtracker.cc \ rec-zonetocache.cc rec-zonetocache.hh \ recpacketcache.cc recpacketcache.hh \ @@ -337,8 +344,8 @@ root-dnssec.hh \ rpzloader.cc rpzloader.hh \ secpoll.cc \ - settings/cxxsupport.cc \ sholder.hh \ + shuffle.cc shuffle.hh \ sillyrecords.cc \ sortlist.cc sortlist.hh \ sstuff.hh \ @@ -357,6 +364,7 @@ test-dnsparser_hh.cc \ test-dnsrecordcontent.cc \ test-dnsrecords_cc.cc \ + test-ednscookie_cc.cc \ test-ednsoptions_cc.cc \ test-filterpo_cc.cc \ test-histogram_hh.cc \ @@ -368,6 +376,7 @@ test-mtasker.cc \ test-negcache_cc.cc \ test-packetcache_hh.cc \ + test-protozero-trace.cc \ test-rcpgenerator_cc.cc \ test-rec-system-resolve.cc \ test-rec-taskqueue.cc \ @@ -380,6 +389,7 @@ test-secpoll_cc.cc \ test-settings.cc \ test-sholder_hh.cc \ + test-shuffle_cc.cc \ test-signers.cc \ test-syncres_cc.cc \ test-syncres_cc.hh \ @@ -398,6 +408,7 @@ threadname.hh threadname.cc \ tsigverifier.cc tsigverifier.hh \ unix_utility.cc \ + uuid-utils.hh uuid-utils.cc \ validate-recursor.cc validate-recursor.hh \ validate.cc validate.hh \ version.cc version.hh \ @@ -405,7 +416,7 @@ zoneparser-tng.cc zoneparser-tng.hh nodist_testrunner_SOURCES = \ - settings/cxxsettings-generated.cc + rec-rust-lib/cxxsettings-generated.cc testrunner_LDFLAGS = \ $(AM_LDFLAGS) \ @@ -538,36 +549,32 @@ qtype.cc \ rcpgenerator.cc rcpgenerator.hh \ rec-lua-conf.cc rec-lua-conf.hh \ + rec-rust-lib/cxxsupport.cc \ rec-system-resolve.cc rec-system-resolve.hh \ + rec-web-stubs.hh \ rec_channel.cc rec_channel.hh \ rec_control.cc \ - settings/cxxsupport.cc \ sillyrecords.cc \ sortlist.cc sortlist.hh \ svc-records.cc svc-records.hh \ threadname.cc threadname.hh \ - unix_utility.cc + unix_utility.cc \ + uuid-utils.hh uuid-utils.cc nodist_rec_control_SOURCES = \ - settings/cxxsettings-generated.cc + rec-rust-lib/cxxsettings-generated.cc dnslabeltext.cc: dnslabeltext.rl $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc -curl_verbose = $(curl_verbose_$(V)) -curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY)) -curl_verbose_0 = @echo " CURL " $@; -$(srcdir)/effective_tld_names.dat: - $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi - -pubsuffix.cc: $(srcdir)/effective_tld_names.dat - $(srcdir)/mkpubsuffixcc $< $@ +pubsuffix.cc: + $(srcdir)/mkpubsuffixcc $@ ## Config file 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" + ./pdns_recursor --config=default 2> /dev/null > $@ ## Manpages MANPAGES=pdns_recursor.1 \ @@ -621,7 +628,7 @@ if HAVE_SYSTEMD pdns-recursor.service: pdns-recursor.service.in - $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' -e 's![@]service_user[@]!$(service_user)!' -e 's![@]service_group[@]!$(service_group)!' < $< > $@ + $(AM_V_GEN)sed -e 's![@]bindir[@]!$(bindir)!' -e 's![@]sbindir[@]!$(sbindir)!' -e 's![@]service_user[@]!$(service_user)!' -e 's![@]service_group[@]!$(service_group)!' < $< > $@ if !HAVE_SYSTEMD_WITH_RUNTIME_DIR_ENV if HAVE_SYSTEMD_PERCENT_T $(AM_V_GEN)sed -e 's!/pdns_recursor!& --socket-dir=%t/pdns-recursor!' -i $@ @@ -697,7 +704,8 @@ -e 's!SyslogIdentifier=.*!&-%i!' \ < $< > $@ if HAVE_SYSTEMD_PERCENT_T - $(AM_V_GEN)sed -e 's!RuntimeDirectory=.*!&-%i!' -i $@ + $(AM_V_GEN)sed -e 's!RuntimeDirectory=.*!&-%i!' \ + -e 's!--socket-dir=%t/pdns-recursor!--config-name=%i --socket-dir=%t/pdns-recursor-%i!' -i $@ if !HAVE_SYSTEMD_WITH_RUNTIME_DIR_ENV $(AM_V_GEN)sed -e 's!--socket-dir=[^ ]\+!&-%i !' -i $@ endif diff -Nru pdns-recursor-5.2.13/Makefile.in pdns-recursor-5.4.9/Makefile.in --- pdns-recursor-5.2.13/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/Makefile.in 2026-10-26 09:47:08.789333600 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -71,6 +71,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -244,56 +246,58 @@ coverage.cc coverage.hh credentials.cc credentials.hh dns.hh \ dns.cc dns_random.hh dnsbackend.hh dnslabeltext.cc dnsname.cc \ dnsname.hh dnspacket.hh dnsparser.hh dnsparser.cc \ - dnsrecords.cc dnsrecords.hh dnssecinfra.hh dnssecinfra.cc \ - dnsseckeeper.hh dnswriter.cc dnswriter.hh dolog.hh \ - ednsextendederror.cc ednsextendederror.hh ednsoptions.cc \ - ednsoptions.hh ednspadding.cc ednspadding.hh ednssubnet.cc \ - ednssubnet.hh filterpo.cc filterpo.hh fstrm_logger.cc \ - fstrm_logger.hh gettime.cc gettime.hh gss_context.cc \ - gss_context.hh histogram.hh iputils.hh iputils.cc ixfr.cc \ - ixfr.hh json.cc json.hh lazy_allocator.hh libssl.cc libssl.hh \ - lock.hh logger.hh logger.cc logging.hh logging.cc logr.hh \ - lua-base4.cc lua-base4.hh lua-recursor4-ffi.hh \ - lua-recursor4.cc lua-recursor4.hh lwres.cc lwres.hh misc.hh \ - misc.cc mplexer.hh mtasker.hh mtasker_context.cc \ - mtasker_context.hh namespaces.hh negcache.hh negcache.cc \ - noinitvector.hh nsecrecords.cc opensslsigners.cc \ - opensslsigners.hh packetcache.hh pdns_recursor.cc \ - pdnsexception.hh pollmplexer.cc protozero.cc protozero.hh \ - proxy-protocol.cc proxy-protocol.hh pubsuffix.hh pubsuffix.cc \ - pubsuffixloader.cc qtype.hh qtype.cc query-local-address.hh \ - query-local-address.cc ratelimitedlog.hh rcpgenerator.cc \ - rcpgenerator.hh rec-carbon.cc rec-eventtrace.cc \ - rec-eventtrace.hh rec-lua-conf.hh rec-lua-conf.cc rec-main.hh \ - rec-main.cc rec-protozero.cc rec-protozero.hh \ - rec-responsestats.hh rec-responsestats.cc rec-snmp.hh \ - rec-snmp.cc rec-system-resolve.hh rec-system-resolve.cc \ - rec-taskqueue.cc rec-taskqueue.hh rec-tcounters.cc \ - rec-tcounters.hh rec-tcp.cc rec-tcpout.cc rec-tcpout.hh \ - rec-xfr.cc rec-xfr.hh rec-xfrtracker.cc rec-zonetocache.cc \ - rec-zonetocache.hh rec_channel.cc rec_channel.hh \ - rec_metrics.hh rec_channel_rec.cc recpacketcache.cc \ - recpacketcache.hh recursor_cache.cc recursor_cache.hh \ - reczones-helpers.cc reczones-helpers.hh reczones.cc \ - remote_logger.cc remote_logger.hh resolve-context.hh \ - resolver.hh resolver.cc root-addresses.hh root-dnssec.hh \ - rpzloader.cc rpzloader.hh secpoll-recursor.cc \ - secpoll-recursor.hh secpoll.cc secpoll.hh \ - settings/cxxsupport.cc sha.hh sholder.hh shuffle.cc shuffle.hh \ + dnsrecords.cc dnsrecords.hh dnssec.hh dnssecinfra.hh \ + dnssecinfra.cc dnswriter.cc dnswriter.hh dolog.hh \ + ednscookies.cc ednscookies.hh ednsextendederror.cc \ + ednsextendederror.hh ednsoptions.cc ednsoptions.hh \ + ednspadding.cc ednspadding.hh ednssubnet.cc ednssubnet.hh \ + filterpo.cc filterpo.hh fstrm_logger.cc fstrm_logger.hh \ + gettime.cc gettime.hh gss_context.cc gss_context.hh \ + histogram.hh iputils.hh iputils.cc ixfr.cc ixfr.hh json.cc \ + json.hh lazy_allocator.hh libssl.cc libssl.hh lock.hh \ + logger.hh logger.cc logging.hh logging.cc logr.hh lua-base4.cc \ + lua-base4.hh lua-recursor4-ffi.hh lua-recursor4.cc \ + lua-recursor4.hh lwres.cc lwres.hh misc.hh misc.cc mplexer.hh \ + mtasker.hh mtasker_context.cc mtasker_context.hh namespaces.hh \ + negcache.hh negcache.cc noinitvector.hh nsecrecords.cc \ + opensslsigners.cc opensslsigners.hh packetcache.hh \ + pdns_recursor.cc pdnsexception.hh pollmplexer.cc \ + protozero-helpers.hh protozero-trace.cc protozero-trace.hh \ + protozero.cc protozero.hh proxy-protocol.cc proxy-protocol.hh \ + pubsuffix.hh pubsuffix.cc pubsuffixloader.cc qtype.hh qtype.cc \ + query-local-address.hh query-local-address.cc \ + ratelimitedlog.hh rcpgenerator.cc rcpgenerator.hh \ + rec-carbon.cc rec-cookiestore.cc rec-cookiestore.hh \ + rec-eventtrace.cc rec-eventtrace.hh rec-lua-conf.hh \ + rec-lua-conf.cc rec-main.hh rec-main.cc rec-nsspeeds.cc \ + rec-nsspeeds.hh rec-protozero.cc rec-protozero.hh \ + rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc rec-snmp.hh rec-snmp.cc \ + rec-system-resolve.hh rec-system-resolve.cc rec-taskqueue.cc \ + rec-taskqueue.hh rec-tcounters.cc rec-tcounters.hh rec-tcp.cc \ + rec-tcpout.cc rec-tcpout.hh rec-xfr.cc rec-xfr.hh \ + rec-xfrtracker.cc rec-zonetocache.cc rec-zonetocache.hh \ + rec_channel.cc rec_channel.hh rec_metrics.hh \ + rec_channel_rec.cc recpacketcache.cc recpacketcache.hh \ + recursor_cache.cc recursor_cache.hh reczones-helpers.cc \ + reczones-helpers.hh reczones.cc remote_logger.cc \ + remote_logger.hh resolve-context.hh resolver.hh resolver.cc \ + root-addresses.hh root-dnssec.hh rpzloader.cc rpzloader.hh \ + sanitizer.hh secpoll-recursor.cc secpoll-recursor.hh \ + secpoll.cc secpoll.hh sha.hh sholder.hh shuffle.cc shuffle.hh \ sillyrecords.cc snmp-agent.hh snmp-agent.cc sortlist.cc \ sortlist.hh sstuff.hh stable-bloom.hh stat_t.hh svc-records.cc \ svc-records.hh syncres.cc syncres.hh taskqueue.cc taskqueue.hh \ tcounters.hh tcpiohandler.cc tcpiohandler.hh threadname.hh \ - threadname.cc tsigverifier.cc tsigverifier.hh ueberbackend.hh \ - unix_utility.cc utility.hh uuid-utils.hh uuid-utils.cc \ - validate.cc validate.hh validate-recursor.cc \ - validate-recursor.hh version.cc version.hh views.hh \ - webserver.cc webserver.hh ws-api.cc ws-api.hh ws-recursor.cc \ - ws-recursor.hh zonemd.cc zonemd.hh zoneparser-tng.cc \ - zoneparser-tng.hh nod.hh nod.cc sodiumsigners.cc \ - malloctrace.cc malloctrace.hh kqueuemplexer.cc epollmplexer.cc \ - devpollmplexer.cc portsmplexer.cc dnstap.cc dnstap.hh \ - minicurl.cc minicurl.hh + threadname.cc tsigverifier.cc tsigverifier.hh unix_utility.cc \ + utility.hh uuid-utils.hh uuid-utils.cc validate.cc validate.hh \ + validate-recursor.cc validate-recursor.hh version.cc \ + version.hh views.hh webserver.cc webserver.hh ws-api.cc \ + ws-api.hh ws-recursor.cc ws-recursor.hh zonemd.cc zonemd.hh \ + zoneparser-tng.cc zoneparser-tng.hh nod.hh nod.cc \ + sodiumsigners.cc malloctrace.cc malloctrace.hh \ + kqueuemplexer.cc epollmplexer.cc devpollmplexer.cc \ + portsmplexer.cc dnstap.cc dnstap.hh minicurl.cc minicurl.hh am__dirstamp = $(am__leading_dot)dirstamp @NOD_ENABLED_TRUE@am__objects_1 = nod.$(OBJEXT) @LIBSODIUM_TRUE@am__objects_2 = sodiumsigners.$(OBJEXT) @@ -312,36 +316,38 @@ coverage.$(OBJEXT) credentials.$(OBJEXT) dns.$(OBJEXT) \ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \ dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \ - ednsextendederror.$(OBJEXT) ednsoptions.$(OBJEXT) \ - ednspadding.$(OBJEXT) ednssubnet.$(OBJEXT) filterpo.$(OBJEXT) \ - fstrm_logger.$(OBJEXT) gettime.$(OBJEXT) gss_context.$(OBJEXT) \ - iputils.$(OBJEXT) ixfr.$(OBJEXT) json.$(OBJEXT) \ - libssl.$(OBJEXT) logger.$(OBJEXT) logging.$(OBJEXT) \ - lua-base4.$(OBJEXT) lua-recursor4.$(OBJEXT) lwres.$(OBJEXT) \ - misc.$(OBJEXT) mtasker_context.$(OBJEXT) negcache.$(OBJEXT) \ + ednscookies.$(OBJEXT) ednsextendederror.$(OBJEXT) \ + ednsoptions.$(OBJEXT) ednspadding.$(OBJEXT) \ + ednssubnet.$(OBJEXT) filterpo.$(OBJEXT) fstrm_logger.$(OBJEXT) \ + gettime.$(OBJEXT) gss_context.$(OBJEXT) iputils.$(OBJEXT) \ + ixfr.$(OBJEXT) json.$(OBJEXT) libssl.$(OBJEXT) \ + logger.$(OBJEXT) logging.$(OBJEXT) lua-base4.$(OBJEXT) \ + lua-recursor4.$(OBJEXT) lwres.$(OBJEXT) misc.$(OBJEXT) \ + mtasker_context.$(OBJEXT) negcache.$(OBJEXT) \ nsecrecords.$(OBJEXT) opensslsigners.$(OBJEXT) \ pdns_recursor.$(OBJEXT) pollmplexer.$(OBJEXT) \ - protozero.$(OBJEXT) proxy-protocol.$(OBJEXT) \ - pubsuffix.$(OBJEXT) pubsuffixloader.$(OBJEXT) qtype.$(OBJEXT) \ + protozero-trace.$(OBJEXT) protozero.$(OBJEXT) \ + proxy-protocol.$(OBJEXT) pubsuffix.$(OBJEXT) \ + pubsuffixloader.$(OBJEXT) qtype.$(OBJEXT) \ query-local-address.$(OBJEXT) rcpgenerator.$(OBJEXT) \ - rec-carbon.$(OBJEXT) rec-eventtrace.$(OBJEXT) \ - rec-lua-conf.$(OBJEXT) rec-main.$(OBJEXT) \ + rec-carbon.$(OBJEXT) rec-cookiestore.$(OBJEXT) \ + rec-eventtrace.$(OBJEXT) rec-lua-conf.$(OBJEXT) \ + rec-main.$(OBJEXT) rec-nsspeeds.$(OBJEXT) \ rec-protozero.$(OBJEXT) rec-responsestats.$(OBJEXT) \ - rec-snmp.$(OBJEXT) rec-system-resolve.$(OBJEXT) \ - rec-taskqueue.$(OBJEXT) rec-tcounters.$(OBJEXT) \ - rec-tcp.$(OBJEXT) rec-tcpout.$(OBJEXT) rec-xfr.$(OBJEXT) \ - rec-xfrtracker.$(OBJEXT) rec-zonetocache.$(OBJEXT) \ - rec_channel.$(OBJEXT) rec_channel_rec.$(OBJEXT) \ - recpacketcache.$(OBJEXT) recursor_cache.$(OBJEXT) \ - reczones-helpers.$(OBJEXT) reczones.$(OBJEXT) \ - remote_logger.$(OBJEXT) resolver.$(OBJEXT) rpzloader.$(OBJEXT) \ - secpoll-recursor.$(OBJEXT) secpoll.$(OBJEXT) \ - settings/cxxsupport.$(OBJEXT) shuffle.$(OBJEXT) \ - sillyrecords.$(OBJEXT) snmp-agent.$(OBJEXT) sortlist.$(OBJEXT) \ - svc-records.$(OBJEXT) syncres.$(OBJEXT) taskqueue.$(OBJEXT) \ - tcpiohandler.$(OBJEXT) threadname.$(OBJEXT) \ - tsigverifier.$(OBJEXT) unix_utility.$(OBJEXT) \ - uuid-utils.$(OBJEXT) validate.$(OBJEXT) \ + rec-rust-lib/cxxsupport.$(OBJEXT) rec-snmp.$(OBJEXT) \ + rec-system-resolve.$(OBJEXT) rec-taskqueue.$(OBJEXT) \ + rec-tcounters.$(OBJEXT) rec-tcp.$(OBJEXT) rec-tcpout.$(OBJEXT) \ + rec-xfr.$(OBJEXT) rec-xfrtracker.$(OBJEXT) \ + rec-zonetocache.$(OBJEXT) rec_channel.$(OBJEXT) \ + rec_channel_rec.$(OBJEXT) recpacketcache.$(OBJEXT) \ + recursor_cache.$(OBJEXT) reczones-helpers.$(OBJEXT) \ + reczones.$(OBJEXT) remote_logger.$(OBJEXT) resolver.$(OBJEXT) \ + rpzloader.$(OBJEXT) secpoll-recursor.$(OBJEXT) \ + secpoll.$(OBJEXT) shuffle.$(OBJEXT) sillyrecords.$(OBJEXT) \ + snmp-agent.$(OBJEXT) sortlist.$(OBJEXT) svc-records.$(OBJEXT) \ + syncres.$(OBJEXT) taskqueue.$(OBJEXT) tcpiohandler.$(OBJEXT) \ + threadname.$(OBJEXT) tsigverifier.$(OBJEXT) \ + unix_utility.$(OBJEXT) uuid-utils.$(OBJEXT) validate.$(OBJEXT) \ validate-recursor.$(OBJEXT) version.$(OBJEXT) \ webserver.$(OBJEXT) ws-api.$(OBJEXT) ws-recursor.$(OBJEXT) \ zonemd.$(OBJEXT) zoneparser-tng.$(OBJEXT) $(am__objects_1) \ @@ -350,11 +356,11 @@ $(am__objects_8) $(am__objects_9) $(am__objects_10) am__objects_11 = nodist_pdns_recursor_OBJECTS = \ - settings/cxxsettings-generated.$(OBJEXT) $(am__objects_11) + rec-rust-lib/cxxsettings-generated.$(OBJEXT) $(am__objects_11) pdns_recursor_OBJECTS = $(am_pdns_recursor_OBJECTS) \ $(nodist_pdns_recursor_OBJECTS) am__DEPENDENCIES_1 = -am__DEPENDENCIES_2 = $(top_builddir)/settings/rust/libsettings.a \ +am__DEPENDENCIES_2 = $(top_builddir)/rec-rust-lib/rust/librecrust.a \ $(am__DEPENDENCIES_1) @NOD_ENABLED_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) @LIBSODIUM_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) @@ -362,14 +368,14 @@ @FSTRM_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) @HAVE_DNS_OVER_TLS_TRUE@@HAVE_LIBSSL_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1) @HAVE_LIBCURL_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1) -pdns_recursor_DEPENDENCIES = $(am__DEPENDENCIES_1) $(JSON11_LIBS) \ +pdns_recursor_DEPENDENCIES = $(JSON11_LIBS) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(PROBDS_LIBS) \ - $(am__DEPENDENCIES_1) $(ARC4RANDOM_LIBS) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \ - $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \ - $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) + $(am__DEPENDENCIES_1) $(PROBDS_LIBS) $(am__DEPENDENCIES_1) \ + $(ARC4RANDOM_LIBS) $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ + $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) \ + $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_7) \ + $(am__DEPENDENCIES_8) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -385,12 +391,13 @@ logger.$(OBJEXT) logging.$(OBJEXT) lua-base4.$(OBJEXT) \ misc.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \ rcpgenerator.$(OBJEXT) rec-lua-conf.$(OBJEXT) \ - rec-system-resolve.$(OBJEXT) rec_channel.$(OBJEXT) \ - rec_control.$(OBJEXT) settings/cxxsupport.$(OBJEXT) \ + rec-rust-lib/cxxsupport.$(OBJEXT) rec-system-resolve.$(OBJEXT) \ + rec_channel.$(OBJEXT) rec_control.$(OBJEXT) \ sillyrecords.$(OBJEXT) sortlist.$(OBJEXT) \ svc-records.$(OBJEXT) threadname.$(OBJEXT) \ - unix_utility.$(OBJEXT) -nodist_rec_control_OBJECTS = settings/cxxsettings-generated.$(OBJEXT) + unix_utility.$(OBJEXT) uuid-utils.$(OBJEXT) +nodist_rec_control_OBJECTS = \ + rec-rust-lib/cxxsettings-generated.$(OBJEXT) rec_control_OBJECTS = $(am_rec_control_OBJECTS) \ $(nodist_rec_control_OBJECTS) rec_control_DEPENDENCIES = $(am__DEPENDENCIES_1) $(ARC4RANDOM_LIBS) \ @@ -404,7 +411,7 @@ base64.cc base64.hh circular_buffer.hh credentials.cc \ credentials.hh dns.cc dns.hh dns_random.hh dnslabeltext.cc \ dnsname.cc dnsname.hh dnsparser.hh dnsparser.cc dnsrecords.cc \ - dnssecinfra.cc dnsseckeeper.hh dnswriter.cc dnswriter.hh \ + dnssec.hh dnssecinfra.cc dnswriter.cc dnswriter.hh \ ednscookies.cc ednscookies.hh ednsextendederror.cc \ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \ ednspadding.cc ednspadding.hh ednssubnet.cc ednssubnet.hh \ @@ -413,17 +420,19 @@ logger.hh logging.hh logging.cc logr.hh misc.cc misc.hh \ mtasker_context.cc namespaces.hh negcache.hh negcache.cc \ nsecrecords.cc opensslsigners.cc opensslsigners.hh \ - pdnsexception.hh pollmplexer.cc qtype.cc qtype.hh \ - query-local-address.hh query-local-address.cc \ - ratelimitedlog.hh rcpgenerator.cc rec-eventtrace.cc \ - rec-eventtrace.hh rec-responsestats.hh rec-responsestats.cc \ - rec-system-resolve.hh rec-system-resolve.cc rec-taskqueue.cc \ - rec-taskqueue.hh rec-tcounters.cc rec-tcounters.hh \ + pdnsexception.hh pollmplexer.cc protozero-trace.cc \ + protozero-trace.hh qtype.cc qtype.hh query-local-address.hh \ + query-local-address.cc ratelimitedlog.hh rcpgenerator.cc \ + rec-eventtrace.cc rec-eventtrace.hh rec-nsspeeds.cc \ + rec-nsspeeds.hh rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc rec-system-resolve.hh \ + rec-system-resolve.cc rec-taskqueue.cc rec-taskqueue.hh \ + rec-tcounters.cc rec-tcounters.hh rec-web-stubs.hh \ rec-xfrtracker.cc rec-zonetocache.cc rec-zonetocache.hh \ recpacketcache.cc recpacketcache.hh recursor_cache.cc \ recursor_cache.hh reczones-helpers.cc reczones-helpers.hh \ resolver.hh resolver.cc root-dnssec.hh rpzloader.cc \ - rpzloader.hh secpoll.cc settings/cxxsupport.cc sholder.hh \ + rpzloader.hh secpoll.cc sholder.hh shuffle.cc shuffle.hh \ sillyrecords.cc sortlist.cc sortlist.hh sstuff.hh \ stable-bloom.hh svc-records.cc svc-records.hh syncres.cc \ syncres.hh taskqueue.cc taskqueue.hh \ @@ -432,27 +441,29 @@ test-credentials_cc.cc test-dns_random_hh.cc \ test-dnsname_cc.cc test-dnsparser_hh.cc \ test-dnsrecordcontent.cc test-dnsrecords_cc.cc \ - test-ednsoptions_cc.cc test-filterpo_cc.cc \ - test-histogram_hh.cc test-iputils_hh.cc test-ixfr_cc.cc \ - test-luawrapper.cc test-misc_hh.cc test-mplexer.cc \ - test-mtasker.cc test-negcache_cc.cc test-packetcache_hh.cc \ + test-ednscookie_cc.cc test-ednsoptions_cc.cc \ + test-filterpo_cc.cc test-histogram_hh.cc test-iputils_hh.cc \ + test-ixfr_cc.cc test-luawrapper.cc test-misc_hh.cc \ + test-mplexer.cc test-mtasker.cc test-negcache_cc.cc \ + test-packetcache_hh.cc test-protozero-trace.cc \ test-rcpgenerator_cc.cc test-rec-system-resolve.cc \ test-rec-taskqueue.cc test-rec-tcounters_cc.cc \ test-rec-zonetocache.cc test-recpacketcache_cc.cc \ test-recursorcache_cc.cc test-reczones-helpers.cc \ 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 test-syncres_cc1.cc test-syncres_cc10.cc \ - test-syncres_cc2.cc test-syncres_cc3.cc test-syncres_cc4.cc \ - test-syncres_cc5.cc test-syncres_cc6.cc test-syncres_cc7.cc \ - test-syncres_cc8.cc test-syncres_cc9.cc test-tsig.cc \ - testrunner.cc threadname.hh threadname.cc tsigverifier.cc \ - tsigverifier.hh unix_utility.cc validate-recursor.cc \ - validate-recursor.hh validate.cc validate.hh version.cc \ - version.hh zonemd.cc zonemd.hh zoneparser-tng.cc \ - zoneparser-tng.hh nod.hh nod.cc test-nod_cc.cc \ - sodiumsigners.cc kqueuemplexer.cc epollmplexer.cc \ - devpollmplexer.cc portsmplexer.cc minicurl.cc minicurl.hh + test-sholder_hh.cc test-shuffle_cc.cc test-signers.cc \ + test-syncres_cc.cc test-syncres_cc.hh test-syncres_cc1.cc \ + test-syncres_cc10.cc test-syncres_cc2.cc test-syncres_cc3.cc \ + test-syncres_cc4.cc test-syncres_cc5.cc test-syncres_cc6.cc \ + test-syncres_cc7.cc test-syncres_cc8.cc test-syncres_cc9.cc \ + test-tsig.cc testrunner.cc threadname.hh threadname.cc \ + tsigverifier.cc tsigverifier.hh unix_utility.cc uuid-utils.hh \ + uuid-utils.cc validate-recursor.cc validate-recursor.hh \ + validate.cc validate.hh version.cc version.hh zonemd.cc \ + zonemd.hh zoneparser-tng.cc zoneparser-tng.hh nod.hh nod.cc \ + test-nod_cc.cc sodiumsigners.cc kqueuemplexer.cc \ + epollmplexer.cc devpollmplexer.cc portsmplexer.cc minicurl.cc \ + minicurl.hh @NOD_ENABLED_TRUE@am__objects_12 = nod.$(OBJEXT) test-nod_cc.$(OBJEXT) am_testrunner_OBJECTS = aggressive_nsec.$(OBJEXT) arguments.$(OBJEXT) \ axfr-retriever.$(OBJEXT) base32.$(OBJEXT) base64.$(OBJEXT) \ @@ -466,49 +477,52 @@ logger.$(OBJEXT) logging.$(OBJEXT) misc.$(OBJEXT) \ mtasker_context.$(OBJEXT) negcache.$(OBJEXT) \ nsecrecords.$(OBJEXT) opensslsigners.$(OBJEXT) \ - pollmplexer.$(OBJEXT) qtype.$(OBJEXT) \ - query-local-address.$(OBJEXT) rcpgenerator.$(OBJEXT) \ - rec-eventtrace.$(OBJEXT) rec-responsestats.$(OBJEXT) \ - rec-system-resolve.$(OBJEXT) rec-taskqueue.$(OBJEXT) \ - rec-tcounters.$(OBJEXT) rec-xfrtracker.$(OBJEXT) \ - rec-zonetocache.$(OBJEXT) recpacketcache.$(OBJEXT) \ - recursor_cache.$(OBJEXT) reczones-helpers.$(OBJEXT) \ - resolver.$(OBJEXT) rpzloader.$(OBJEXT) secpoll.$(OBJEXT) \ - settings/cxxsupport.$(OBJEXT) sillyrecords.$(OBJEXT) \ - sortlist.$(OBJEXT) svc-records.$(OBJEXT) syncres.$(OBJEXT) \ - taskqueue.$(OBJEXT) test-aggressive_nsec_cc.$(OBJEXT) \ - test-arguments_cc.$(OBJEXT) test-base32_cc.$(OBJEXT) \ - test-base64_cc.$(OBJEXT) test-credentials_cc.$(OBJEXT) \ - test-dns_random_hh.$(OBJEXT) test-dnsname_cc.$(OBJEXT) \ - test-dnsparser_hh.$(OBJEXT) test-dnsrecordcontent.$(OBJEXT) \ - test-dnsrecords_cc.$(OBJEXT) test-ednsoptions_cc.$(OBJEXT) \ + pollmplexer.$(OBJEXT) protozero-trace.$(OBJEXT) \ + qtype.$(OBJEXT) query-local-address.$(OBJEXT) \ + rcpgenerator.$(OBJEXT) rec-eventtrace.$(OBJEXT) \ + rec-nsspeeds.$(OBJEXT) rec-responsestats.$(OBJEXT) \ + rec-rust-lib/cxxsupport.$(OBJEXT) rec-system-resolve.$(OBJEXT) \ + rec-taskqueue.$(OBJEXT) rec-tcounters.$(OBJEXT) \ + rec-xfrtracker.$(OBJEXT) rec-zonetocache.$(OBJEXT) \ + recpacketcache.$(OBJEXT) recursor_cache.$(OBJEXT) \ + reczones-helpers.$(OBJEXT) resolver.$(OBJEXT) \ + rpzloader.$(OBJEXT) secpoll.$(OBJEXT) shuffle.$(OBJEXT) \ + sillyrecords.$(OBJEXT) sortlist.$(OBJEXT) \ + svc-records.$(OBJEXT) syncres.$(OBJEXT) taskqueue.$(OBJEXT) \ + test-aggressive_nsec_cc.$(OBJEXT) test-arguments_cc.$(OBJEXT) \ + test-base32_cc.$(OBJEXT) test-base64_cc.$(OBJEXT) \ + test-credentials_cc.$(OBJEXT) test-dns_random_hh.$(OBJEXT) \ + test-dnsname_cc.$(OBJEXT) test-dnsparser_hh.$(OBJEXT) \ + test-dnsrecordcontent.$(OBJEXT) test-dnsrecords_cc.$(OBJEXT) \ + test-ednscookie_cc.$(OBJEXT) test-ednsoptions_cc.$(OBJEXT) \ test-filterpo_cc.$(OBJEXT) test-histogram_hh.$(OBJEXT) \ test-iputils_hh.$(OBJEXT) test-ixfr_cc.$(OBJEXT) \ test-luawrapper.$(OBJEXT) test-misc_hh.$(OBJEXT) \ test-mplexer.$(OBJEXT) test-mtasker.$(OBJEXT) \ test-negcache_cc.$(OBJEXT) test-packetcache_hh.$(OBJEXT) \ - test-rcpgenerator_cc.$(OBJEXT) \ + test-protozero-trace.$(OBJEXT) test-rcpgenerator_cc.$(OBJEXT) \ test-rec-system-resolve.$(OBJEXT) test-rec-taskqueue.$(OBJEXT) \ test-rec-tcounters_cc.$(OBJEXT) test-rec-zonetocache.$(OBJEXT) \ test-recpacketcache_cc.$(OBJEXT) \ test-recursorcache_cc.$(OBJEXT) \ test-reczones-helpers.$(OBJEXT) test-rpzloader_cc.$(OBJEXT) \ test-secpoll_cc.$(OBJEXT) test-settings.$(OBJEXT) \ - test-sholder_hh.$(OBJEXT) test-signers.$(OBJEXT) \ - test-syncres_cc.$(OBJEXT) test-syncres_cc1.$(OBJEXT) \ - test-syncres_cc10.$(OBJEXT) test-syncres_cc2.$(OBJEXT) \ - test-syncres_cc3.$(OBJEXT) test-syncres_cc4.$(OBJEXT) \ - test-syncres_cc5.$(OBJEXT) test-syncres_cc6.$(OBJEXT) \ - test-syncres_cc7.$(OBJEXT) test-syncres_cc8.$(OBJEXT) \ - test-syncres_cc9.$(OBJEXT) test-tsig.$(OBJEXT) \ - testrunner.$(OBJEXT) threadname.$(OBJEXT) \ + test-sholder_hh.$(OBJEXT) test-shuffle_cc.$(OBJEXT) \ + test-signers.$(OBJEXT) test-syncres_cc.$(OBJEXT) \ + test-syncres_cc1.$(OBJEXT) test-syncres_cc10.$(OBJEXT) \ + test-syncres_cc2.$(OBJEXT) test-syncres_cc3.$(OBJEXT) \ + test-syncres_cc4.$(OBJEXT) test-syncres_cc5.$(OBJEXT) \ + test-syncres_cc6.$(OBJEXT) test-syncres_cc7.$(OBJEXT) \ + test-syncres_cc8.$(OBJEXT) test-syncres_cc9.$(OBJEXT) \ + test-tsig.$(OBJEXT) testrunner.$(OBJEXT) threadname.$(OBJEXT) \ tsigverifier.$(OBJEXT) unix_utility.$(OBJEXT) \ - validate-recursor.$(OBJEXT) validate.$(OBJEXT) \ - version.$(OBJEXT) zonemd.$(OBJEXT) zoneparser-tng.$(OBJEXT) \ - $(am__objects_12) $(am__objects_2) $(am__objects_4) \ - $(am__objects_5) $(am__objects_6) $(am__objects_7) \ - $(am__objects_8) $(am__objects_10) -nodist_testrunner_OBJECTS = settings/cxxsettings-generated.$(OBJEXT) + uuid-utils.$(OBJEXT) validate-recursor.$(OBJEXT) \ + validate.$(OBJEXT) version.$(OBJEXT) zonemd.$(OBJEXT) \ + zoneparser-tng.$(OBJEXT) $(am__objects_12) $(am__objects_2) \ + $(am__objects_4) $(am__objects_5) $(am__objects_6) \ + $(am__objects_7) $(am__objects_8) $(am__objects_10) +nodist_testrunner_OBJECTS = \ + rec-rust-lib/cxxsettings-generated.$(OBJEXT) testrunner_OBJECTS = $(am_testrunner_OBJECTS) \ $(nodist_testrunner_OBJECTS) testrunner_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -560,28 +574,29 @@ ./$(DEPDIR)/nod.Po ./$(DEPDIR)/nsecrecords.Po \ ./$(DEPDIR)/opensslsigners.Po ./$(DEPDIR)/pdns_recursor.Po \ ./$(DEPDIR)/pollmplexer.Po ./$(DEPDIR)/portsmplexer.Po \ - ./$(DEPDIR)/protozero.Po ./$(DEPDIR)/proxy-protocol.Po \ - ./$(DEPDIR)/pubsuffix.Po ./$(DEPDIR)/pubsuffixloader.Po \ - ./$(DEPDIR)/qtype.Po ./$(DEPDIR)/query-local-address.Po \ - ./$(DEPDIR)/rcpgenerator.Po ./$(DEPDIR)/rec-carbon.Po \ + ./$(DEPDIR)/protozero-trace.Po ./$(DEPDIR)/protozero.Po \ + ./$(DEPDIR)/proxy-protocol.Po ./$(DEPDIR)/pubsuffix.Po \ + ./$(DEPDIR)/pubsuffixloader.Po ./$(DEPDIR)/qtype.Po \ + ./$(DEPDIR)/query-local-address.Po ./$(DEPDIR)/rcpgenerator.Po \ + ./$(DEPDIR)/rec-carbon.Po ./$(DEPDIR)/rec-cookiestore.Po \ ./$(DEPDIR)/rec-eventtrace.Po ./$(DEPDIR)/rec-lua-conf.Po \ - ./$(DEPDIR)/rec-main.Po ./$(DEPDIR)/rec-protozero.Po \ - ./$(DEPDIR)/rec-responsestats.Po ./$(DEPDIR)/rec-snmp.Po \ - ./$(DEPDIR)/rec-system-resolve.Po ./$(DEPDIR)/rec-taskqueue.Po \ - ./$(DEPDIR)/rec-tcounters.Po ./$(DEPDIR)/rec-tcp.Po \ - ./$(DEPDIR)/rec-tcpout.Po ./$(DEPDIR)/rec-xfr.Po \ - ./$(DEPDIR)/rec-xfrtracker.Po ./$(DEPDIR)/rec-zonetocache.Po \ - ./$(DEPDIR)/rec_channel.Po ./$(DEPDIR)/rec_channel_rec.Po \ - ./$(DEPDIR)/rec_control.Po ./$(DEPDIR)/recpacketcache.Po \ - ./$(DEPDIR)/recursor_cache.Po ./$(DEPDIR)/reczones-helpers.Po \ - ./$(DEPDIR)/reczones.Po ./$(DEPDIR)/remote_logger.Po \ - ./$(DEPDIR)/resolver.Po ./$(DEPDIR)/rpzloader.Po \ - ./$(DEPDIR)/secpoll-recursor.Po ./$(DEPDIR)/secpoll.Po \ - ./$(DEPDIR)/shuffle.Po ./$(DEPDIR)/sillyrecords.Po \ - ./$(DEPDIR)/snmp-agent.Po ./$(DEPDIR)/sodiumsigners.Po \ - ./$(DEPDIR)/sortlist.Po ./$(DEPDIR)/svc-records.Po \ - ./$(DEPDIR)/syncres.Po ./$(DEPDIR)/taskqueue.Po \ - ./$(DEPDIR)/tcpiohandler.Po \ + ./$(DEPDIR)/rec-main.Po ./$(DEPDIR)/rec-nsspeeds.Po \ + ./$(DEPDIR)/rec-protozero.Po ./$(DEPDIR)/rec-responsestats.Po \ + ./$(DEPDIR)/rec-snmp.Po ./$(DEPDIR)/rec-system-resolve.Po \ + ./$(DEPDIR)/rec-taskqueue.Po ./$(DEPDIR)/rec-tcounters.Po \ + ./$(DEPDIR)/rec-tcp.Po ./$(DEPDIR)/rec-tcpout.Po \ + ./$(DEPDIR)/rec-xfr.Po ./$(DEPDIR)/rec-xfrtracker.Po \ + ./$(DEPDIR)/rec-zonetocache.Po ./$(DEPDIR)/rec_channel.Po \ + ./$(DEPDIR)/rec_channel_rec.Po ./$(DEPDIR)/rec_control.Po \ + ./$(DEPDIR)/recpacketcache.Po ./$(DEPDIR)/recursor_cache.Po \ + ./$(DEPDIR)/reczones-helpers.Po ./$(DEPDIR)/reczones.Po \ + ./$(DEPDIR)/remote_logger.Po ./$(DEPDIR)/resolver.Po \ + ./$(DEPDIR)/rpzloader.Po ./$(DEPDIR)/secpoll-recursor.Po \ + ./$(DEPDIR)/secpoll.Po ./$(DEPDIR)/shuffle.Po \ + ./$(DEPDIR)/sillyrecords.Po ./$(DEPDIR)/snmp-agent.Po \ + ./$(DEPDIR)/sodiumsigners.Po ./$(DEPDIR)/sortlist.Po \ + ./$(DEPDIR)/svc-records.Po ./$(DEPDIR)/syncres.Po \ + ./$(DEPDIR)/taskqueue.Po ./$(DEPDIR)/tcpiohandler.Po \ ./$(DEPDIR)/test-aggressive_nsec_cc.Po \ ./$(DEPDIR)/test-arguments_cc.Po ./$(DEPDIR)/test-base32_cc.Po \ ./$(DEPDIR)/test-base64_cc.Po \ @@ -591,6 +606,7 @@ ./$(DEPDIR)/test-dnsparser_hh.Po \ ./$(DEPDIR)/test-dnsrecordcontent.Po \ ./$(DEPDIR)/test-dnsrecords_cc.Po \ + ./$(DEPDIR)/test-ednscookie_cc.Po \ ./$(DEPDIR)/test-ednsoptions_cc.Po \ ./$(DEPDIR)/test-filterpo_cc.Po \ ./$(DEPDIR)/test-histogram_hh.Po \ @@ -599,6 +615,7 @@ ./$(DEPDIR)/test-mplexer.Po ./$(DEPDIR)/test-mtasker.Po \ ./$(DEPDIR)/test-negcache_cc.Po ./$(DEPDIR)/test-nod_cc.Po \ ./$(DEPDIR)/test-packetcache_hh.Po \ + ./$(DEPDIR)/test-protozero-trace.Po \ ./$(DEPDIR)/test-rcpgenerator_cc.Po \ ./$(DEPDIR)/test-rec-system-resolve.Po \ ./$(DEPDIR)/test-rec-taskqueue.Po \ @@ -609,8 +626,9 @@ ./$(DEPDIR)/test-reczones-helpers.Po \ ./$(DEPDIR)/test-rpzloader_cc.Po \ ./$(DEPDIR)/test-secpoll_cc.Po ./$(DEPDIR)/test-settings.Po \ - ./$(DEPDIR)/test-sholder_hh.Po ./$(DEPDIR)/test-signers.Po \ - ./$(DEPDIR)/test-syncres_cc.Po ./$(DEPDIR)/test-syncres_cc1.Po \ + ./$(DEPDIR)/test-sholder_hh.Po ./$(DEPDIR)/test-shuffle_cc.Po \ + ./$(DEPDIR)/test-signers.Po ./$(DEPDIR)/test-syncres_cc.Po \ + ./$(DEPDIR)/test-syncres_cc1.Po \ ./$(DEPDIR)/test-syncres_cc10.Po \ ./$(DEPDIR)/test-syncres_cc2.Po \ ./$(DEPDIR)/test-syncres_cc3.Po \ @@ -627,8 +645,8 @@ ./$(DEPDIR)/webserver.Po ./$(DEPDIR)/ws-api.Po \ ./$(DEPDIR)/ws-recursor.Po ./$(DEPDIR)/zonemd.Po \ ./$(DEPDIR)/zoneparser-tng.Po \ - settings/$(DEPDIR)/cxxsettings-generated.Po \ - settings/$(DEPDIR)/cxxsupport.Po + rec-rust-lib/$(DEPDIR)/cxxsettings-generated.Po \ + rec-rust-lib/$(DEPDIR)/cxxsupport.Po am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) @@ -706,10 +724,9 @@ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ + { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 NROFF = nroff @@ -850,6 +867,7 @@ # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ + $$am__collect_skipped_logs \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the @@ -874,6 +892,11 @@ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ +if test -n '$(IGNORE_SKIPPED_LOGS)'; then \ + am__collect_skipped_logs='--collect-skipped-logs no'; \ +else \ + am__collect_skipped_logs=''; \ +fi; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ @@ -939,8 +962,8 @@ top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -rf "$(distdir)" \ + find "$(distdir)" -type d ! -perm -700 -exec chmod u+rwx {} ';' \ + ; rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) @@ -969,7 +992,7 @@ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" -GZIP_ENV = --best +GZIP_ENV = -9 DIST_ARCHIVES = $(distdir).tar.bz2 DIST_TARGETS = dist-bzip2 # Exists only to be overridden by the user if desired. @@ -977,7 +1000,9 @@ distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = find . -type f -print +distcleancheck_listfiles = \ + find . \( -type f -a \! \ + \( -name .nfs* -o -name .smb* -o -name .__afs* \) \) -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CPPFLAGS = $(LUA_CFLAGS) $(YAHTTP_CFLAGS) $(BOOST_CPPFLAGS) \ @@ -985,11 +1010,11 @@ $(SANITIZER_FLAGS) -O3 -Wall -pthread \ -DSYSCONFDIR=\"${sysconfdir}\" $(SYSTEMD_CFLAGS) \ -I$(top_srcdir)/ext/json11 \ - -I$(top_srcdir)/ext/protozero/include -I$(top_srcdir)/settings \ - -I$(top_builddir)/settings -I$(top_srcdir)/settings/rust/src \ - $(YAHTTP_CFLAGS) $(LIBCRYPTO_INCLUDES) \ - -DBOOST_CONTAINER_USE_STD_EXCEPTIONS $(am__append_1) \ - $(am__append_2) $(am__append_34) + -I$(top_srcdir)/ext/protozero/include \ + -I$(top_srcdir)/rec-rust-lib -I$(top_builddir)/rec-rust-lib \ + -I$(top_srcdir)/rec-rust-lib/rust/src $(YAHTTP_CFLAGS) \ + $(LIBCRYPTO_INCLUDES) -DBOOST_CONTAINER_USE_STD_EXCEPTIONS \ + $(am__append_1) $(am__append_2) $(am__append_34) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ @@ -1134,8 +1159,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -1190,7 +1217,7 @@ JSON11_LIBS = $(top_builddir)/ext/json11/libjson11.la PROBDS_LIBS = $(top_builddir)/ext/probds/libprobds.la ARC4RANDOM_LIBS = $(top_builddir)/ext/arc4random/libarc4random.la -RUST_LIBS = $(top_builddir)/settings/rust/libsettings.a $(LIBDL) +RUST_LIBS = $(top_builddir)/rec-rust-lib/rust/librecrust.a $(LIBDL) AM_CXXFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" -DLOCALSTATEDIR=\"$(socketdir)\" \ -DNODCACHEDIRNOD=\"$(nodcachedir)/nod\" \ @@ -1205,8 +1232,8 @@ RECURSOR-MIB.txt $(am__append_4) CLEANFILES = htmlfiles.h recursor.yml-dist lua.hpp $(am__append_40) -# We explicitly build settings in two steps, as settings modifies files in the settings/rust subdir -SUBDIRS = ext settings settings/rust +# We explicitly build rec-rust-lib in two steps, as it modifies files in the rec-rust-lib/rust subdir +SUBDIRS = ext rec-rust-lib rec-rust-lib/rust EXTRA_DIST = \ contrib/* \ COPYING \ @@ -1214,7 +1241,6 @@ dnslabeltext.cc \ dnslabeltext.rl \ dnsmessage.proto \ - effective_tld_names.dat \ epollmplexer.cc \ kqueuemplexer.cc \ lua_hpp.mk \ @@ -1248,59 +1274,61 @@ coverage.cc coverage.hh credentials.cc credentials.hh dns.hh \ dns.cc dns_random.hh dnsbackend.hh dnslabeltext.cc dnsname.cc \ dnsname.hh dnspacket.hh dnsparser.hh dnsparser.cc \ - dnsrecords.cc dnsrecords.hh dnssecinfra.hh dnssecinfra.cc \ - dnsseckeeper.hh dnswriter.cc dnswriter.hh dolog.hh \ - ednsextendederror.cc ednsextendederror.hh ednsoptions.cc \ - ednsoptions.hh ednspadding.cc ednspadding.hh ednssubnet.cc \ - ednssubnet.hh filterpo.cc filterpo.hh fstrm_logger.cc \ - fstrm_logger.hh gettime.cc gettime.hh gss_context.cc \ - gss_context.hh histogram.hh iputils.hh iputils.cc ixfr.cc \ - ixfr.hh json.cc json.hh lazy_allocator.hh libssl.cc libssl.hh \ - lock.hh logger.hh logger.cc logging.hh logging.cc logr.hh \ - lua-base4.cc lua-base4.hh lua-recursor4-ffi.hh \ - lua-recursor4.cc lua-recursor4.hh lwres.cc lwres.hh misc.hh \ - misc.cc mplexer.hh mtasker.hh mtasker_context.cc \ - mtasker_context.hh namespaces.hh negcache.hh negcache.cc \ - noinitvector.hh nsecrecords.cc opensslsigners.cc \ - opensslsigners.hh packetcache.hh pdns_recursor.cc \ - pdnsexception.hh pollmplexer.cc protozero.cc protozero.hh \ - proxy-protocol.cc proxy-protocol.hh pubsuffix.hh pubsuffix.cc \ - pubsuffixloader.cc qtype.hh qtype.cc query-local-address.hh \ - query-local-address.cc ratelimitedlog.hh rcpgenerator.cc \ - rcpgenerator.hh rec-carbon.cc rec-eventtrace.cc \ - rec-eventtrace.hh rec-lua-conf.hh rec-lua-conf.cc rec-main.hh \ - rec-main.cc rec-protozero.cc rec-protozero.hh \ - rec-responsestats.hh rec-responsestats.cc rec-snmp.hh \ - rec-snmp.cc rec-system-resolve.hh rec-system-resolve.cc \ - rec-taskqueue.cc rec-taskqueue.hh rec-tcounters.cc \ - rec-tcounters.hh rec-tcp.cc rec-tcpout.cc rec-tcpout.hh \ - rec-xfr.cc rec-xfr.hh rec-xfrtracker.cc rec-zonetocache.cc \ - rec-zonetocache.hh rec_channel.cc rec_channel.hh \ - rec_metrics.hh rec_channel_rec.cc recpacketcache.cc \ - recpacketcache.hh recursor_cache.cc recursor_cache.hh \ - reczones-helpers.cc reczones-helpers.hh reczones.cc \ - remote_logger.cc remote_logger.hh resolve-context.hh \ - resolver.hh resolver.cc root-addresses.hh root-dnssec.hh \ - rpzloader.cc rpzloader.hh secpoll-recursor.cc \ - secpoll-recursor.hh secpoll.cc secpoll.hh \ - settings/cxxsupport.cc sha.hh sholder.hh shuffle.cc shuffle.hh \ + dnsrecords.cc dnsrecords.hh dnssec.hh dnssecinfra.hh \ + dnssecinfra.cc dnswriter.cc dnswriter.hh dolog.hh \ + ednscookies.cc ednscookies.hh ednsextendederror.cc \ + ednsextendederror.hh ednsoptions.cc ednsoptions.hh \ + ednspadding.cc ednspadding.hh ednssubnet.cc ednssubnet.hh \ + filterpo.cc filterpo.hh fstrm_logger.cc fstrm_logger.hh \ + gettime.cc gettime.hh gss_context.cc gss_context.hh \ + histogram.hh iputils.hh iputils.cc ixfr.cc ixfr.hh json.cc \ + json.hh lazy_allocator.hh libssl.cc libssl.hh lock.hh \ + logger.hh logger.cc logging.hh logging.cc logr.hh lua-base4.cc \ + lua-base4.hh lua-recursor4-ffi.hh lua-recursor4.cc \ + lua-recursor4.hh lwres.cc lwres.hh misc.hh misc.cc mplexer.hh \ + mtasker.hh mtasker_context.cc mtasker_context.hh namespaces.hh \ + negcache.hh negcache.cc noinitvector.hh nsecrecords.cc \ + opensslsigners.cc opensslsigners.hh packetcache.hh \ + pdns_recursor.cc pdnsexception.hh pollmplexer.cc \ + protozero-helpers.hh protozero-trace.cc protozero-trace.hh \ + protozero.cc protozero.hh proxy-protocol.cc proxy-protocol.hh \ + pubsuffix.hh pubsuffix.cc pubsuffixloader.cc qtype.hh qtype.cc \ + query-local-address.hh query-local-address.cc \ + ratelimitedlog.hh rcpgenerator.cc rcpgenerator.hh \ + rec-carbon.cc rec-cookiestore.cc rec-cookiestore.hh \ + rec-eventtrace.cc rec-eventtrace.hh rec-lua-conf.hh \ + rec-lua-conf.cc rec-main.hh rec-main.cc rec-nsspeeds.cc \ + rec-nsspeeds.hh rec-protozero.cc rec-protozero.hh \ + rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc rec-snmp.hh rec-snmp.cc \ + rec-system-resolve.hh rec-system-resolve.cc rec-taskqueue.cc \ + rec-taskqueue.hh rec-tcounters.cc rec-tcounters.hh rec-tcp.cc \ + rec-tcpout.cc rec-tcpout.hh rec-xfr.cc rec-xfr.hh \ + rec-xfrtracker.cc rec-zonetocache.cc rec-zonetocache.hh \ + rec_channel.cc rec_channel.hh rec_metrics.hh \ + rec_channel_rec.cc recpacketcache.cc recpacketcache.hh \ + recursor_cache.cc recursor_cache.hh reczones-helpers.cc \ + reczones-helpers.hh reczones.cc remote_logger.cc \ + remote_logger.hh resolve-context.hh resolver.hh resolver.cc \ + root-addresses.hh root-dnssec.hh rpzloader.cc rpzloader.hh \ + sanitizer.hh secpoll-recursor.cc secpoll-recursor.hh \ + secpoll.cc secpoll.hh sha.hh sholder.hh shuffle.cc shuffle.hh \ sillyrecords.cc snmp-agent.hh snmp-agent.cc sortlist.cc \ sortlist.hh sstuff.hh stable-bloom.hh stat_t.hh svc-records.cc \ svc-records.hh syncres.cc syncres.hh taskqueue.cc taskqueue.hh \ tcounters.hh tcpiohandler.cc tcpiohandler.hh threadname.hh \ - threadname.cc tsigverifier.cc tsigverifier.hh ueberbackend.hh \ - unix_utility.cc utility.hh uuid-utils.hh uuid-utils.cc \ - validate.cc validate.hh validate-recursor.cc \ - validate-recursor.hh version.cc version.hh views.hh \ - webserver.cc webserver.hh ws-api.cc ws-api.hh ws-recursor.cc \ - ws-recursor.hh zonemd.cc zonemd.hh zoneparser-tng.cc \ - zoneparser-tng.hh $(am__append_6) $(am__append_12) \ - $(am__append_17) $(am__append_22) $(am__append_24) \ - $(am__append_26) $(am__append_28) $(am__append_30) \ - $(am__append_32) $(am__append_36) -nodist_pdns_recursor_SOURCES = settings/cxxsettings-generated.cc \ + threadname.cc tsigverifier.cc tsigverifier.hh unix_utility.cc \ + utility.hh uuid-utils.hh uuid-utils.cc validate.cc validate.hh \ + validate-recursor.cc validate-recursor.hh version.cc \ + version.hh views.hh webserver.cc webserver.hh ws-api.cc \ + ws-api.hh ws-recursor.cc ws-recursor.hh zonemd.cc zonemd.hh \ + zoneparser-tng.cc zoneparser-tng.hh $(am__append_6) \ + $(am__append_12) $(am__append_17) $(am__append_22) \ + $(am__append_24) $(am__append_26) $(am__append_28) \ + $(am__append_30) $(am__append_32) $(am__append_36) +nodist_pdns_recursor_SOURCES = rec-rust-lib/cxxsettings-generated.cc \ $(am__append_5) -pdns_recursor_LDADD = $(YAHTTP_LIBS) $(JSON11_LIBS) $(LIBCRYPTO_LIBS) \ +pdns_recursor_LDADD = $(JSON11_LIBS) $(LIBCRYPTO_LIBS) \ $(BOOST_CONTEXT_LIBS) $(NET_SNMP_LIBS) $(SYSTEMD_LIBS) \ $(RT_LIBS) $(BOOST_SYSTEM_LIBS) $(PROBDS_LIBS) $(LIBCAP_LIBS) \ $(ARC4RANDOM_LIBS) $(RUST_LIBS) $(am__append_7) \ @@ -1319,7 +1347,7 @@ base64.cc base64.hh circular_buffer.hh credentials.cc \ credentials.hh dns.cc dns.hh dns_random.hh dnslabeltext.cc \ dnsname.cc dnsname.hh dnsparser.hh dnsparser.cc dnsrecords.cc \ - dnssecinfra.cc dnsseckeeper.hh dnswriter.cc dnswriter.hh \ + dnssec.hh dnssecinfra.cc dnswriter.cc dnswriter.hh \ ednscookies.cc ednscookies.hh ednsextendederror.cc \ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \ ednspadding.cc ednspadding.hh ednssubnet.cc ednssubnet.hh \ @@ -1328,17 +1356,19 @@ logger.hh logging.hh logging.cc logr.hh misc.cc misc.hh \ mtasker_context.cc namespaces.hh negcache.hh negcache.cc \ nsecrecords.cc opensslsigners.cc opensslsigners.hh \ - pdnsexception.hh pollmplexer.cc qtype.cc qtype.hh \ - query-local-address.hh query-local-address.cc \ - ratelimitedlog.hh rcpgenerator.cc rec-eventtrace.cc \ - rec-eventtrace.hh rec-responsestats.hh rec-responsestats.cc \ - rec-system-resolve.hh rec-system-resolve.cc rec-taskqueue.cc \ - rec-taskqueue.hh rec-tcounters.cc rec-tcounters.hh \ + pdnsexception.hh pollmplexer.cc protozero-trace.cc \ + protozero-trace.hh qtype.cc qtype.hh query-local-address.hh \ + query-local-address.cc ratelimitedlog.hh rcpgenerator.cc \ + rec-eventtrace.cc rec-eventtrace.hh rec-nsspeeds.cc \ + rec-nsspeeds.hh rec-responsestats.hh rec-responsestats.cc \ + rec-rust-lib/cxxsupport.cc rec-system-resolve.hh \ + rec-system-resolve.cc rec-taskqueue.cc rec-taskqueue.hh \ + rec-tcounters.cc rec-tcounters.hh rec-web-stubs.hh \ rec-xfrtracker.cc rec-zonetocache.cc rec-zonetocache.hh \ recpacketcache.cc recpacketcache.hh recursor_cache.cc \ recursor_cache.hh reczones-helpers.cc reczones-helpers.hh \ resolver.hh resolver.cc root-dnssec.hh rpzloader.cc \ - rpzloader.hh secpoll.cc settings/cxxsupport.cc sholder.hh \ + rpzloader.hh secpoll.cc sholder.hh shuffle.cc shuffle.hh \ sillyrecords.cc sortlist.cc sortlist.hh sstuff.hh \ stable-bloom.hh svc-records.cc svc-records.hh syncres.cc \ syncres.hh taskqueue.cc taskqueue.hh \ @@ -1347,29 +1377,31 @@ test-credentials_cc.cc test-dns_random_hh.cc \ test-dnsname_cc.cc test-dnsparser_hh.cc \ test-dnsrecordcontent.cc test-dnsrecords_cc.cc \ - test-ednsoptions_cc.cc test-filterpo_cc.cc \ - test-histogram_hh.cc test-iputils_hh.cc test-ixfr_cc.cc \ - test-luawrapper.cc test-misc_hh.cc test-mplexer.cc \ - test-mtasker.cc test-negcache_cc.cc test-packetcache_hh.cc \ + test-ednscookie_cc.cc test-ednsoptions_cc.cc \ + test-filterpo_cc.cc test-histogram_hh.cc test-iputils_hh.cc \ + test-ixfr_cc.cc test-luawrapper.cc test-misc_hh.cc \ + test-mplexer.cc test-mtasker.cc test-negcache_cc.cc \ + test-packetcache_hh.cc test-protozero-trace.cc \ test-rcpgenerator_cc.cc test-rec-system-resolve.cc \ test-rec-taskqueue.cc test-rec-tcounters_cc.cc \ test-rec-zonetocache.cc test-recpacketcache_cc.cc \ test-recursorcache_cc.cc test-reczones-helpers.cc \ 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 test-syncres_cc1.cc test-syncres_cc10.cc \ - test-syncres_cc2.cc test-syncres_cc3.cc test-syncres_cc4.cc \ - test-syncres_cc5.cc test-syncres_cc6.cc test-syncres_cc7.cc \ - test-syncres_cc8.cc test-syncres_cc9.cc test-tsig.cc \ - testrunner.cc threadname.hh threadname.cc tsigverifier.cc \ - tsigverifier.hh unix_utility.cc validate-recursor.cc \ - validate-recursor.hh validate.cc validate.hh version.cc \ - version.hh zonemd.cc zonemd.hh zoneparser-tng.cc \ - zoneparser-tng.hh $(am__append_9) $(am__append_15) \ - $(am__append_23) $(am__append_25) $(am__append_27) \ - $(am__append_29) $(am__append_31) $(am__append_38) + test-sholder_hh.cc test-shuffle_cc.cc test-signers.cc \ + test-syncres_cc.cc test-syncres_cc.hh test-syncres_cc1.cc \ + test-syncres_cc10.cc test-syncres_cc2.cc test-syncres_cc3.cc \ + test-syncres_cc4.cc test-syncres_cc5.cc test-syncres_cc6.cc \ + test-syncres_cc7.cc test-syncres_cc8.cc test-syncres_cc9.cc \ + test-tsig.cc testrunner.cc threadname.hh threadname.cc \ + tsigverifier.cc tsigverifier.hh unix_utility.cc uuid-utils.hh \ + uuid-utils.cc validate-recursor.cc validate-recursor.hh \ + validate.cc validate.hh version.cc version.hh zonemd.cc \ + zonemd.hh zoneparser-tng.cc zoneparser-tng.hh $(am__append_9) \ + $(am__append_15) $(am__append_23) $(am__append_25) \ + $(am__append_27) $(am__append_29) $(am__append_31) \ + $(am__append_38) nodist_testrunner_SOURCES = \ - settings/cxxsettings-generated.cc + rec-rust-lib/cxxsettings-generated.cc testrunner_LDFLAGS = $(AM_LDFLAGS) $(BOOST_CONTEXT_LDFLAGS) \ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) $(LIBCRYPTO_LDFLAGS) \ @@ -1399,22 +1431,21 @@ qtype.cc \ rcpgenerator.cc rcpgenerator.hh \ rec-lua-conf.cc rec-lua-conf.hh \ + rec-rust-lib/cxxsupport.cc \ rec-system-resolve.cc rec-system-resolve.hh \ + rec-web-stubs.hh \ rec_channel.cc rec_channel.hh \ rec_control.cc \ - settings/cxxsupport.cc \ sillyrecords.cc \ sortlist.cc sortlist.hh \ svc-records.cc svc-records.hh \ threadname.cc threadname.hh \ - unix_utility.cc + unix_utility.cc \ + uuid-utils.hh uuid-utils.cc nodist_rec_control_SOURCES = \ - settings/cxxsettings-generated.cc + rec-rust-lib/cxxsettings-generated.cc -curl_verbose = $(curl_verbose_$(V)) -curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY)) -curl_verbose_0 = @echo " CURL " $@; sysconf_DATA = recursor.yml-dist MANPAGES = pdns_recursor.1 \ rec_control.1 @@ -1470,12 +1501,12 @@ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h + $(AM_V_at)rm -f stamp-h1 + $(AM_V_GEN)cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ + $(AM_V_GEN)($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + $(AM_V_at)rm -f stamp-h1 + $(AM_V_at)touch $@ distclean-hdr: -rm -f config.h stamp-h1 @@ -1518,25 +1549,15 @@ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(bindir)" && rm -f $$files + cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: - @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list + $(am__rm_f) $(bin_PROGRAMS) + test -z "$(EXEEXT)" || $(am__rm_f) $(bin_PROGRAMS:$(EXEEXT)=) clean-noinstPROGRAMS: - @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list + $(am__rm_f) $(noinst_PROGRAMS) + test -z "$(EXEEXT)" || $(am__rm_f) $(noinst_PROGRAMS:$(EXEEXT)=) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ @@ -1576,26 +1597,22 @@ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(sbindir)" && rm -f $$files + cd "$(DESTDIR)$(sbindir)" && $(am__rm_f) $$files clean-sbinPROGRAMS: - @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -settings/$(am__dirstamp): - @$(MKDIR_P) settings - @: > settings/$(am__dirstamp) -settings/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) settings/$(DEPDIR) - @: > settings/$(DEPDIR)/$(am__dirstamp) -settings/cxxsupport.$(OBJEXT): settings/$(am__dirstamp) \ - settings/$(DEPDIR)/$(am__dirstamp) -settings/cxxsettings-generated.$(OBJEXT): settings/$(am__dirstamp) \ - settings/$(DEPDIR)/$(am__dirstamp) + $(am__rm_f) $(sbin_PROGRAMS) + test -z "$(EXEEXT)" || $(am__rm_f) $(sbin_PROGRAMS:$(EXEEXT)=) +rec-rust-lib/$(am__dirstamp): + @$(MKDIR_P) rec-rust-lib + @: >>rec-rust-lib/$(am__dirstamp) +rec-rust-lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) rec-rust-lib/$(DEPDIR) + @: >>rec-rust-lib/$(DEPDIR)/$(am__dirstamp) +rec-rust-lib/cxxsupport.$(OBJEXT): rec-rust-lib/$(am__dirstamp) \ + rec-rust-lib/$(DEPDIR)/$(am__dirstamp) +rec-rust-lib/cxxsettings-generated.$(OBJEXT): \ + rec-rust-lib/$(am__dirstamp) \ + rec-rust-lib/$(DEPDIR)/$(am__dirstamp) pdns_recursor$(EXEEXT): $(pdns_recursor_OBJECTS) $(pdns_recursor_DEPENDENCIES) $(EXTRA_pdns_recursor_DEPENDENCIES) @rm -f pdns_recursor$(EXEEXT) @@ -1611,7 +1628,7 @@ mostlyclean-compile: -rm -f *.$(OBJEXT) - -rm -f settings/*.$(OBJEXT) + -rm -f rec-rust-lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @@ -1665,6 +1682,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pdns_recursor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pollmplexer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/portsmplexer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protozero-trace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protozero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proxy-protocol.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubsuffix.Po@am__quote@ # am--include-marker @@ -1673,9 +1691,11 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query-local-address.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcpgenerator.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-carbon.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-cookiestore.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-eventtrace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-lua-conf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-nsspeeds.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-protozero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-responsestats.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rec-snmp.Po@am__quote@ # am--include-marker @@ -1718,6 +1738,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsparser_hh.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsrecordcontent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsrecords_cc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ednscookie_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ednsoptions_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-filterpo_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-histogram_hh.Po@am__quote@ # am--include-marker @@ -1730,6 +1751,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-negcache_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nod_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-packetcache_hh.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-protozero-trace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rcpgenerator_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rec-system-resolve.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rec-taskqueue.Po@am__quote@ # am--include-marker @@ -1742,6 +1764,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-secpoll_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-settings.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sholder_hh.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-shuffle_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-signers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-syncres_cc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-syncres_cc1.Po@am__quote@ # am--include-marker @@ -1768,12 +1791,12 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ws-recursor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zonemd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoneparser-tng.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@settings/$(DEPDIR)/cxxsettings-generated.Po@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@settings/$(DEPDIR)/cxxsupport.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@rec-rust-lib/$(DEPDIR)/cxxsettings-generated.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@rec-rust-lib/$(DEPDIR)/cxxsupport.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + @: >>$@ am--depfiles: $(am__depfiles_remade) @@ -2014,7 +2037,6 @@ am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: - $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ @@ -2090,10 +2112,37 @@ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ + output_system_information () \ + { \ + echo; \ + { uname -a | $(AWK) '{ \ + printf "System information (uname -a):"; \ + for (i = 1; i < NF; ++i) \ + { \ + if (i != 2) \ + printf " %s", $$i; \ + } \ + printf "\n"; \ +}'; } 2>&1; \ + if test -r /etc/os-release; then \ + echo "Distribution information (/etc/os-release):"; \ + sed 8q /etc/os-release; \ + elif test -r /etc/issue; then \ + echo "Distribution information (/etc/issue):"; \ + cat /etc/issue; \ + fi; \ + }; \ + please_report () \ + { \ +echo "Some test(s) failed. Please report this to $(PACKAGE_BUGREPORT),"; \ +echo "together with the test-suite.log file (gzipped) and your system"; \ +echo "information. Thanks."; \ + }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ + output_system_information; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ @@ -2113,26 +2162,25 @@ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ - echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG) for debugging.$${std}";\ if test -n "$(PACKAGE_BUGREPORT)"; then \ - echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + please_report | sed -e "s/^/$${col}/" -e s/'$$'/"$${std}"/; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: - @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list - @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @$(am__rm_f) $(RECHECK_LOGS) + @$(am__rm_f) $(RECHECK_LOGS:.log=.trs) + @$(am__rm_f) $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ - trs_list=`for i in $$bases; do echo $$i.trs; done`; \ - log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @$(am__rm_f) $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ @@ -2175,7 +2223,7 @@ distdir-am: $(DISTFILES) $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" + $(AM_V_at)$(MKDIR_P) "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -2288,7 +2336,7 @@ distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + eval GZIP= gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ @@ -2298,7 +2346,7 @@ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + eval GZIP= gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ @@ -2402,23 +2450,23 @@ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: - -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) - -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) - -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + -$(am__rm_f) $(TEST_LOGS) + -$(am__rm_f) $(TEST_LOGS:.log=.trs) + -$(am__rm_f) $(TEST_SUITE_LOG) clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + -$(am__rm_f) $(CLEANFILES) distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -rm -f settings/$(DEPDIR)/$(am__dirstamp) - -rm -f settings/$(am__dirstamp) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) rec-rust-lib/$(DEPDIR)/$(am__dirstamp) + -$(am__rm_f) rec-rust-lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -$(am__rm_f) $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool \ @@ -2426,7 +2474,7 @@ distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f ./$(DEPDIR)/aggressive_nsec.Po + -rm -f ./$(DEPDIR)/aggressive_nsec.Po -rm -f ./$(DEPDIR)/arguments.Po -rm -f ./$(DEPDIR)/axfr-retriever.Po -rm -f ./$(DEPDIR)/base32.Po @@ -2475,6 +2523,7 @@ -rm -f ./$(DEPDIR)/pdns_recursor.Po -rm -f ./$(DEPDIR)/pollmplexer.Po -rm -f ./$(DEPDIR)/portsmplexer.Po + -rm -f ./$(DEPDIR)/protozero-trace.Po -rm -f ./$(DEPDIR)/protozero.Po -rm -f ./$(DEPDIR)/proxy-protocol.Po -rm -f ./$(DEPDIR)/pubsuffix.Po @@ -2483,9 +2532,11 @@ -rm -f ./$(DEPDIR)/query-local-address.Po -rm -f ./$(DEPDIR)/rcpgenerator.Po -rm -f ./$(DEPDIR)/rec-carbon.Po + -rm -f ./$(DEPDIR)/rec-cookiestore.Po -rm -f ./$(DEPDIR)/rec-eventtrace.Po -rm -f ./$(DEPDIR)/rec-lua-conf.Po -rm -f ./$(DEPDIR)/rec-main.Po + -rm -f ./$(DEPDIR)/rec-nsspeeds.Po -rm -f ./$(DEPDIR)/rec-protozero.Po -rm -f ./$(DEPDIR)/rec-responsestats.Po -rm -f ./$(DEPDIR)/rec-snmp.Po @@ -2528,6 +2579,7 @@ -rm -f ./$(DEPDIR)/test-dnsparser_hh.Po -rm -f ./$(DEPDIR)/test-dnsrecordcontent.Po -rm -f ./$(DEPDIR)/test-dnsrecords_cc.Po + -rm -f ./$(DEPDIR)/test-ednscookie_cc.Po -rm -f ./$(DEPDIR)/test-ednsoptions_cc.Po -rm -f ./$(DEPDIR)/test-filterpo_cc.Po -rm -f ./$(DEPDIR)/test-histogram_hh.Po @@ -2540,6 +2592,7 @@ -rm -f ./$(DEPDIR)/test-negcache_cc.Po -rm -f ./$(DEPDIR)/test-nod_cc.Po -rm -f ./$(DEPDIR)/test-packetcache_hh.Po + -rm -f ./$(DEPDIR)/test-protozero-trace.Po -rm -f ./$(DEPDIR)/test-rcpgenerator_cc.Po -rm -f ./$(DEPDIR)/test-rec-system-resolve.Po -rm -f ./$(DEPDIR)/test-rec-taskqueue.Po @@ -2552,6 +2605,7 @@ -rm -f ./$(DEPDIR)/test-secpoll_cc.Po -rm -f ./$(DEPDIR)/test-settings.Po -rm -f ./$(DEPDIR)/test-sholder_hh.Po + -rm -f ./$(DEPDIR)/test-shuffle_cc.Po -rm -f ./$(DEPDIR)/test-signers.Po -rm -f ./$(DEPDIR)/test-syncres_cc.Po -rm -f ./$(DEPDIR)/test-syncres_cc1.Po @@ -2578,8 +2632,8 @@ -rm -f ./$(DEPDIR)/ws-recursor.Po -rm -f ./$(DEPDIR)/zonemd.Po -rm -f ./$(DEPDIR)/zoneparser-tng.Po - -rm -f settings/$(DEPDIR)/cxxsettings-generated.Po - -rm -f settings/$(DEPDIR)/cxxsupport.Po + -rm -f rec-rust-lib/$(DEPDIR)/cxxsettings-generated.Po + -rm -f rec-rust-lib/$(DEPDIR)/cxxsupport.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags @@ -2628,7 +2682,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -f ./$(DEPDIR)/aggressive_nsec.Po + -rm -f ./$(DEPDIR)/aggressive_nsec.Po -rm -f ./$(DEPDIR)/arguments.Po -rm -f ./$(DEPDIR)/axfr-retriever.Po -rm -f ./$(DEPDIR)/base32.Po @@ -2677,6 +2731,7 @@ -rm -f ./$(DEPDIR)/pdns_recursor.Po -rm -f ./$(DEPDIR)/pollmplexer.Po -rm -f ./$(DEPDIR)/portsmplexer.Po + -rm -f ./$(DEPDIR)/protozero-trace.Po -rm -f ./$(DEPDIR)/protozero.Po -rm -f ./$(DEPDIR)/proxy-protocol.Po -rm -f ./$(DEPDIR)/pubsuffix.Po @@ -2685,9 +2740,11 @@ -rm -f ./$(DEPDIR)/query-local-address.Po -rm -f ./$(DEPDIR)/rcpgenerator.Po -rm -f ./$(DEPDIR)/rec-carbon.Po + -rm -f ./$(DEPDIR)/rec-cookiestore.Po -rm -f ./$(DEPDIR)/rec-eventtrace.Po -rm -f ./$(DEPDIR)/rec-lua-conf.Po -rm -f ./$(DEPDIR)/rec-main.Po + -rm -f ./$(DEPDIR)/rec-nsspeeds.Po -rm -f ./$(DEPDIR)/rec-protozero.Po -rm -f ./$(DEPDIR)/rec-responsestats.Po -rm -f ./$(DEPDIR)/rec-snmp.Po @@ -2730,6 +2787,7 @@ -rm -f ./$(DEPDIR)/test-dnsparser_hh.Po -rm -f ./$(DEPDIR)/test-dnsrecordcontent.Po -rm -f ./$(DEPDIR)/test-dnsrecords_cc.Po + -rm -f ./$(DEPDIR)/test-ednscookie_cc.Po -rm -f ./$(DEPDIR)/test-ednsoptions_cc.Po -rm -f ./$(DEPDIR)/test-filterpo_cc.Po -rm -f ./$(DEPDIR)/test-histogram_hh.Po @@ -2742,6 +2800,7 @@ -rm -f ./$(DEPDIR)/test-negcache_cc.Po -rm -f ./$(DEPDIR)/test-nod_cc.Po -rm -f ./$(DEPDIR)/test-packetcache_hh.Po + -rm -f ./$(DEPDIR)/test-protozero-trace.Po -rm -f ./$(DEPDIR)/test-rcpgenerator_cc.Po -rm -f ./$(DEPDIR)/test-rec-system-resolve.Po -rm -f ./$(DEPDIR)/test-rec-taskqueue.Po @@ -2754,6 +2813,7 @@ -rm -f ./$(DEPDIR)/test-secpoll_cc.Po -rm -f ./$(DEPDIR)/test-settings.Po -rm -f ./$(DEPDIR)/test-sholder_hh.Po + -rm -f ./$(DEPDIR)/test-shuffle_cc.Po -rm -f ./$(DEPDIR)/test-signers.Po -rm -f ./$(DEPDIR)/test-syncres_cc.Po -rm -f ./$(DEPDIR)/test-syncres_cc1.Po @@ -2780,8 +2840,8 @@ -rm -f ./$(DEPDIR)/ws-recursor.Po -rm -f ./$(DEPDIR)/zonemd.Po -rm -f ./$(DEPDIR)/zoneparser-tng.Po - -rm -f settings/$(DEPDIR)/cxxsettings-generated.Po - -rm -f settings/$(DEPDIR)/cxxsupport.Po + -rm -f rec-rust-lib/$(DEPDIR)/cxxsettings-generated.Po + -rm -f rec-rust-lib/$(DEPDIR)/cxxsupport.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -2835,12 +2895,12 @@ htmlfiles.h: incfiles ${srcdir}/html/* ${srcdir}/html/js/* - $(AM_V_GEN)$(srcdir)/incfiles > $@.tmp + $(AM_V_GEN)$(srcdir)/incfiles ${srcdir} > $@.tmp @mv $@.tmp $@ # Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make rec-metrics-gen%h rec-prometheus-gen%h rec-snmp-gen%h rec-oids-gen%h RECURSOR-MIB%txt: metrics.py metrics_table.py RECURSOR-MIB.in - $(PYTHON) metrics.py + $(PYTHON) ${srcdir}/metrics.py ${srcdir} . dist-hook: for file in $$(find $(distdir)/docs -type l); do \ @@ -2853,14 +2913,12 @@ dnslabeltext.cc: dnslabeltext.rl $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc -$(srcdir)/effective_tld_names.dat: - $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi -pubsuffix.cc: $(srcdir)/effective_tld_names.dat - $(srcdir)/mkpubsuffixcc $< $@ +pubsuffix.cc: + $(srcdir)/mkpubsuffixcc $@ 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" + ./pdns_recursor --config=default 2> /dev/null > $@ @HAVE_MANPAGES_FALSE@@HAVE_VENV_TRUE@$(MANPAGES): %: docs/manpages/%.rst .venv @HAVE_MANPAGES_FALSE@@HAVE_VENV_TRUE@ $(builddir)/.venv/bin/python -msphinx -b man "$(srcdir)/docs" "$(builddir)" $< @@ -2902,7 +2960,7 @@ @HAVE_VENV_FALSE@ exit 1 @HAVE_SYSTEMD_TRUE@pdns-recursor.service: pdns-recursor.service.in -@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' -e 's![@]service_user[@]!$(service_user)!' -e 's![@]service_group[@]!$(service_group)!' < $< > $@ +@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's![@]bindir[@]!$(bindir)!' -e 's![@]sbindir[@]!$(sbindir)!' -e 's![@]service_user[@]!$(service_user)!' -e 's![@]service_group[@]!$(service_group)!' < $< > $@ @HAVE_SYSTEMD_PERCENT_T_TRUE@@HAVE_SYSTEMD_TRUE@@HAVE_SYSTEMD_WITH_RUNTIME_DIR_ENV_FALSE@ $(AM_V_GEN)sed -e 's!/pdns_recursor!& --socket-dir=%t/pdns-recursor!' -i $@ @HAVE_SYSTEMD_LOCK_PERSONALITY_FALSE@@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)perl -ni -e 'print unless /^LockPersonality/' $@ @HAVE_SYSTEMD_PRIVATE_DEVICES_FALSE@@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)perl -ni -e 'print unless /^PrivateDevices/' $@ @@ -2931,7 +2989,8 @@ @HAVE_SYSTEMD_TRUE@ -e 's!Recursor!& %i!' \ @HAVE_SYSTEMD_TRUE@ -e 's!SyslogIdentifier=.*!&-%i!' \ @HAVE_SYSTEMD_TRUE@ < $< > $@ -@HAVE_SYSTEMD_PERCENT_T_TRUE@@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's!RuntimeDirectory=.*!&-%i!' -i $@ +@HAVE_SYSTEMD_PERCENT_T_TRUE@@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's!RuntimeDirectory=.*!&-%i!' \ +@HAVE_SYSTEMD_PERCENT_T_TRUE@@HAVE_SYSTEMD_TRUE@ -e 's!--socket-dir=%t/pdns-recursor!--config-name=%i --socket-dir=%t/pdns-recursor-%i!' -i $@ @HAVE_SYSTEMD_PERCENT_T_TRUE@@HAVE_SYSTEMD_TRUE@@HAVE_SYSTEMD_WITH_RUNTIME_DIR_ENV_FALSE@ $(AM_V_GEN)sed -e 's!--socket-dir=[^ ]\+!&-%i !' -i $@ @HAVE_LUA_HPP_FALSE@lua.hpp: @HAVE_LUA_HPP_FALSE@ $(AM_V_GEN)echo 'extern "C" {' > $@ @@ -2943,3 +3002,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/RECURSOR-MIB.in pdns-recursor-5.4.9/RECURSOR-MIB.in --- pdns-recursor-5.2.13/RECURSOR-MIB.in 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/RECURSOR-MIB.in 2026-10-26 08:26:51.000000000 +0000 @@ -15,12 +15,16 @@ FROM SNMPv2-CONF; rec MODULE-IDENTITY - LAST-UPDATED "202408280000Z" + + LAST-UPDATED "202509100000Z" ORGANIZATION "PowerDNS BV" CONTACT-INFO "support@powerdns.com" DESCRIPTION "This MIB module describes information gathered through PowerDNS Recursor." + REVISION "202509100000Z" + DESCRIPTION "Added metrics related to cookies" + REVISION "202505270000Z" DESCRIPTION "Added metric for missing ECS in reply" diff -Nru pdns-recursor-5.2.13/RECURSOR-MIB.txt pdns-recursor-5.4.9/RECURSOR-MIB.txt --- pdns-recursor-5.2.13/RECURSOR-MIB.txt 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/RECURSOR-MIB.txt 2026-10-26 08:26:51.000000000 +0000 @@ -15,12 +15,16 @@ FROM SNMPv2-CONF; rec MODULE-IDENTITY - LAST-UPDATED "202408280000Z" + + LAST-UPDATED "202509100000Z" ORGANIZATION "PowerDNS BV" CONTACT-INFO "support@powerdns.com" DESCRIPTION "This MIB module describes information gathered through PowerDNS Recursor." + REVISION "202509100000Z" + DESCRIPTION "Added metrics related to cookies" + REVISION "202505270000Z" DESCRIPTION "Added metric for missing ECS in reply" @@ -1302,6 +1306,70 @@ "Number of answers where ECS info was missing" ::= { stats 153 } +cookieMalformed OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed cookies received" + ::= { stats 154 } + +cookieMatched OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of matching cookies received" + ::= { stats 155 } + +cookieMismatchTcp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of mismatched cookies received over TCP" + ::= { stats 156 } + +cookieMismatchUdp OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of mismatched cookies received over UDP" + ::= { stats 157 } + +cookieNotInReply OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an authoritative server sent a reply without a cookie" + ::= { stats 158 } + +cookieRetry OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of retries because authoritative server sent a BADCOOKIE reply" + ::= { stats 159 } + +cookiesSupported OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of authoritative server cookie probes resulting in success" + ::= { stats 160 } + +cookiesUnsupported OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of authoritative server cookie probes not resulting in success" + ::= { stats 161 } + --- --- Traps / Notifications --- @@ -1501,7 +1569,15 @@ maxChainWeight, chainLimits, tcpOverflow, - ecsMissing + ecsMissing, + cookieMalformed, + cookieMatched, + cookieMismatchTcp, + cookieMismatchUdp, + cookieNotInReply, + cookieRetry, + cookiesSupported, + cookiesUnsupported } STATUS current DESCRIPTION "Objects conformance group for PowerDNS Recursor" diff -Nru pdns-recursor-5.2.13/aclocal.m4 pdns-recursor-5.4.9/aclocal.m4 --- pdns-recursor-5.2.13/aclocal.m4 2026-08-05 12:01:43.000000000 +0000 +++ pdns-recursor-5.4.9/aclocal.m4 2026-10-26 09:47:07.395486800 +0000 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.5 -*- Autoconf -*- +# generated automatically by aclocal 1.17 -*- Autoconf -*- -# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# Copyright (C) 1996-2024 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,8 +14,8 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, -[m4_warning([this file was generated for autoconf 2.71. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, +[m4_warning([this file was generated for autoconf 2.72. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) @@ -68,8 +68,8 @@ [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ -dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) -dnl ---------------------------------- +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to @@ -77,6 +77,12 @@ dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. +dnl +dnl If pkg-config is not found or older than specified, it will result +dnl in an empty PKG_CONFIG variable. To avoid widespread issues with +dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting. +dnl You can specify [PKG_CONFIG=false] as an action instead, which would +dnl result in pkg-config tests failing, but no bogus error messages. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) @@ -97,6 +103,9 @@ AC_MSG_RESULT([no]) PKG_CONFIG="" fi +fi +if test -z "$PKG_CONFIG"; then + m4_default([$2], [AC_MSG_ERROR([pkg-config not found])]) fi[]dnl ])dnl PKG_PROG_PKG_CONFIG @@ -364,7 +373,7 @@ [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES -# Copyright (C) 2002-2021 Free Software Foundation, Inc. +# Copyright (C) 2002-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -376,10 +385,10 @@ # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.16' +[am__api_version='1.17' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.5], [], +m4_if([$1], [1.17], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -395,14 +404,14 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.5])dnl +[AM_AUTOMAKE_VERSION([1.17])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -454,7 +463,7 @@ # AM_COND_IF -*- Autoconf -*- -# Copyright (C) 2008-2021 Free Software Foundation, Inc. +# Copyright (C) 2008-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -491,7 +500,7 @@ # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2021 Free Software Foundation, Inc. +# Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -522,7 +531,7 @@ Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -654,7 +663,7 @@ # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: + # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported @@ -713,7 +722,7 @@ # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -781,7 +790,7 @@ # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -915,7 +924,7 @@ fi AC_SUBST([CSCOPE]) -AC_REQUIRE([AM_SILENT_RULES])dnl +AC_REQUIRE([_AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. @@ -923,47 +932,9 @@ [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +AC_REQUIRE([_AM_PROG_RM_F]) +AC_REQUIRE([_AM_PROG_XARGS_N]) -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) - fi -fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. @@ -996,7 +967,7 @@ done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1017,7 +988,7 @@ fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2021 Free Software Foundation, Inc. +# Copyright (C) 2003-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1038,7 +1009,7 @@ # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1081,7 +1052,7 @@ # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2021 Free Software Foundation, Inc. +# Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1115,7 +1086,7 @@ # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1144,7 +1115,7 @@ AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1191,7 +1162,7 @@ # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1225,10 +1196,12 @@ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], -[python python2 python3 dnl +[python python3 dnl + python3.20 python3.19 python3.18 python3.17 python3.16 dnl python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 dnl python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl python3.2 python3.1 python3.0 dnl + python2 dnl python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl python2.0]) @@ -1423,15 +1396,29 @@ if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': can_use_sysconfig = 0 except ImportError: - pass" + pass" # end of am_python_setup_sysconfig + + # More repeated code, for figuring out the installation scheme to use. + am_python_setup_scheme="if hasattr(sysconfig, 'get_default_scheme'): + scheme = sysconfig.get_default_scheme() + else: + scheme = sysconfig._get_default_scheme() + if scheme == 'posix_local': + if '$am_py_prefix' == '/usr': + scheme = 'deb_system' # should only happen during Debian package builds + else: + # Debian's default scheme installs to /usr/local/ but we want to + # follow the prefix, as we always have. + # See bugs#54412, #64837, et al. + scheme = 'posix_prefix'" # end of am_python_setup_scheme dnl emacs-page Set up 4 directories: dnl 1. pythondir: where to install python scripts. This is the dnl site-packages directory, not the python standard library - dnl directory like in previous automake betas. This behavior + dnl directory as in early automake betas. This behavior dnl is more consistent with lispdir.m4 for example. - dnl Query distutils for this directory. + dnl Query sysconfig or distutils (per above) for this directory. dnl AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)], [am_cv_python_pythondir], @@ -1443,7 +1430,11 @@ am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: - sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) + try: + $am_python_setup_scheme + sitedir = sysconfig.get_path('purelib', scheme, vars={'base':'$am_py_prefix'}) + except: + sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') @@ -1473,7 +1464,8 @@ dnl 3. pyexecdir: directory for installing python extension modules dnl (shared libraries). - dnl Query distutils for this directory. + dnl Query sysconfig or distutils for this directory. + dnl Much of this is the same as for prefix setup above. dnl AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)], [am_cv_python_pyexecdir], @@ -1485,7 +1477,11 @@ am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: - sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'}) + try: + $am_python_setup_scheme + sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase':'$am_py_exec_prefix'}) + except: + sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix') @@ -1536,7 +1532,23 @@ sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# Copyright (C) 2022-2024 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_RM_F +# --------------- +# Check whether 'rm -f' without any arguments works. +# https://bugs.gnu.org/10828 +AC_DEFUN([_AM_PROG_RM_F], +[am__rm_f_notfound= +AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) +AC_SUBST(am__rm_f_notfound) +]) + +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1555,16 +1567,169 @@ # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. +# _AM_SLEEP_FRACTIONAL_SECONDS +# ---------------------------- +AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl +AC_CACHE_CHECK([whether sleep supports fractional seconds], + am_cv_sleep_fractional_seconds, [dnl +AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], + [am_cv_sleep_fractional_seconds=no]) +])]) + +# _AM_FILESYSTEM_TIMESTAMP_RESOLUTION +# ----------------------------------- +# Determine the filesystem's resolution for file modification +# timestamps. The coarsest we know of is FAT, with a resolution +# of only two seconds, even with the most recent "exFAT" extensions. +# The finest (e.g. ext4 with large inodes, XFS, ZFS) is one +# nanosecond, matching clock_gettime. However, it is probably not +# possible to delay execution of a shell script for less than one +# millisecond, due to process creation overhead and scheduling +# granularity, so we don't check for anything finer than that. (See below.) +AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl +AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) +AC_CACHE_CHECK([filesystem timestamp resolution], + am_cv_filesystem_timestamp_resolution, [dnl +# Default to the worst case. +am_cv_filesystem_timestamp_resolution=2 + +# Only try to go finer than 1 sec if sleep can do it. +# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, +# - 1 sec is not much of a win compared to 2 sec, and +# - it takes 2 seconds to perform the test whether 1 sec works. +# +# Instead, just use the default 2s on platforms that have 1s resolution, +# accept the extra 1s delay when using $sleep in the Automake tests, in +# exchange for not incurring the 2s delay for running the test for all +# packages. +# +am_try_resolutions= +if test "$am_cv_sleep_fractional_seconds" = yes; then + # Even a millisecond often causes a bunch of false positives, + # so just try a hundredth of a second. The time saved between .001 and + # .01 is not terribly consequential. + am_try_resolutions="0.01 0.1 $am_try_resolutions" +fi + +# In order to catch current-generation FAT out, we must *modify* files +# that already exist; the *creation* timestamp is finer. Use names +# that make ls -t sort them differently when they have equal +# timestamps than when they have distinct timestamps, keeping +# in mind that ls -t prints the *newest* file first. +rm -f conftest.ts? +: > conftest.ts1 +: > conftest.ts2 +: > conftest.ts3 + +# Make sure ls -t actually works. Do 'set' in a subshell so we don't +# clobber the current shell's arguments. (Outer-level square brackets +# are removed by m4; they're present so that m4 does not expand +# ; be careful, easy to get confused.) +if ( + set X `[ls -t conftest.ts[12]]` && + { + test "$[]*" != "X conftest.ts1 conftest.ts2" || + test "$[]*" != "X conftest.ts2 conftest.ts1"; + } +); then :; else + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + _AS_ECHO_UNQUOTED( + ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], + [AS_MESSAGE_LOG_FD]) + AC_MSG_FAILURE([ls -t produces unexpected output. +Make sure there is not a broken ls alias in your environment.]) +fi + +for am_try_res in $am_try_resolutions; do + # Any one fine-grained sleep might happen to cross the boundary + # between two values of a coarser actual resolution, but if we do + # two fine-grained sleeps in a row, at least one of them will fall + # entirely within a coarse interval. + echo alpha > conftest.ts1 + sleep $am_try_res + echo beta > conftest.ts2 + sleep $am_try_res + echo gamma > conftest.ts3 + + # We assume that 'ls -t' will make use of high-resolution + # timestamps if the operating system supports them at all. + if (set X `ls -t conftest.ts?` && + test "$[]2" = conftest.ts3 && + test "$[]3" = conftest.ts2 && + test "$[]4" = conftest.ts1); then + # + # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, + # because we don't need to test make. + make_ok=true + if test $am_try_res != 1; then + # But if we've succeeded so far with a subsecond resolution, we + # have one more thing to check: make. It can happen that + # everything else supports the subsecond mtimes, but make doesn't; + # notably on macOS, which ships make 3.81 from 2006 (the last one + # released under GPLv2). https://bugs.gnu.org/68808 + # + # We test $MAKE if it is defined in the environment, else "make". + # It might get overridden later, but our hope is that in practice + # it does not matter: it is the system "make" which is (by far) + # the most likely to be broken, whereas if the user overrides it, + # probably they did so with a better, or at least not worse, make. + # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html + # + # Create a Makefile (real tab character here): + rm -f conftest.mk + echo 'conftest.ts1: conftest.ts2' >conftest.mk + echo ' touch conftest.ts2' >>conftest.mk + # + # Now, running + # touch conftest.ts1; touch conftest.ts2; make + # should touch ts1 because ts2 is newer. This could happen by luck, + # but most often, it will fail if make's support is insufficient. So + # test for several consecutive successes. + # + # (We reuse conftest.ts[12] because we still want to modify existing + # files, not create new ones, per above.) + n=0 + make=${MAKE-make} + until test $n -eq 3; do + echo one > conftest.ts1 + sleep $am_try_res + echo two > conftest.ts2 # ts2 should now be newer than ts1 + if $make -f conftest.mk | grep 'up to date' >/dev/null; then + make_ok=false + break # out of $n loop + fi + n=`expr $n + 1` + done + fi + # + if $make_ok; then + # Everything we know to check worked out, so call this resolution good. + am_cv_filesystem_timestamp_resolution=$am_try_res + break # out of $am_try_res loop + fi + # Otherwise, we'll go on to check the next resolution. + fi +done +rm -f conftest.ts? +# (end _am_filesystem_timestamp_resolution) +])]) + # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) +[AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) +# This check should not be cached, as it may vary across builds of +# different projects. +AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' @@ -1583,49 +1748,40 @@ # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken - alias in your environment]) - fi - if test "$[2]" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! +am_build_env_is_sane=no +am_has_slept=no +rm -f conftest.file +for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[]*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + test "$[]2" = conftest.file + ); then + am_build_env_is_sane=yes + break + fi + # Just in case. + sleep "$am_cv_filesystem_timestamp_resolution" + am_has_slept=yes +done + +AC_MSG_RESULT([$am_build_env_is_sane]) +if test "$am_build_env_is_sane" = no; then + AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi -AC_MSG_RESULT([yes]) + # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & +AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl + ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! -fi +]) AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then @@ -1636,18 +1792,18 @@ rm -f conftest.file ]) -# Copyright (C) 2009-2021 Free Software Foundation, Inc. +# Copyright (C) 2009-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# AM_SILENT_RULES([DEFAULT]) -# -------------------------- -# Enable less verbose build rules; with the default set to DEFAULT -# ("yes" being less verbose, "no" or empty being verbose). -AC_DEFUN([AM_SILENT_RULES], -[AC_ARG_ENABLE([silent-rules], [dnl +# _AM_SILENT_RULES +# ---------------- +# Enable less verbose build rules support. +AC_DEFUN([_AM_SILENT_RULES], +[AM_DEFAULT_VERBOSITY=1 +AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) @@ -1655,11 +1811,6 @@ [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; -esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. @@ -1678,14 +1829,6 @@ else am_cv_make_support_nested_variables=no fi]) -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl @@ -1694,9 +1837,33 @@ AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls +dnl to AM_SILENT_RULES to change the default value. +AC_CONFIG_COMMANDS_PRE([dnl +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; +esac +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +])dnl ]) -# Copyright (C) 2001-2021 Free Software Foundation, Inc. +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or +# empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_REQUIRE([_AM_SILENT_RULES]) +AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])]) + +# Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1724,7 +1891,7 @@ INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2021 Free Software Foundation, Inc. +# Copyright (C) 2006-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1743,7 +1910,7 @@ # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2021 Free Software Foundation, Inc. +# Copyright (C) 2004-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1789,15 +1956,19 @@ am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) + if test x$am_uid = xunknown; then + AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) + elif test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) else - AC_MSG_RESULT([no]) - _am_tools=none + AC_MSG_RESULT([no]) + _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) + if test x$gm_gid = xunknown; then + AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) + elif test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none @@ -1874,6 +2045,26 @@ AC_SUBST([am__untar]) ]) # _AM_PROG_TAR +# Copyright (C) 2022-2024 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_XARGS_N +# ---------------- +# Check whether 'xargs -n' works. It should work everywhere, so the fallback +# is not optimized at all as we never expect to use it. +AC_DEFUN([_AM_PROG_XARGS_N], +[AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl +AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 +3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) +AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl + am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' +])dnl +AC_SUBST(am__xargs_n) +]) + m4_include([m4/ac_pthread_set_name.m4]) m4_include([m4/ax_arg_default_enable_disable.m4]) m4_include([m4/ax_check_sign.m4]) diff -Nru pdns-recursor-5.2.13/aggressive_nsec.cc pdns-recursor-5.4.9/aggressive_nsec.cc --- pdns-recursor-5.2.13/aggressive_nsec.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/aggressive_nsec.cc 2026-10-26 08:26:51.000000000 +0000 @@ -172,7 +172,7 @@ auto& sidx = boost::multi_index::get(zoneEntry->d_entries); const auto toTrimForThisZone = static_cast(std::round(static_cast(toErase) * static_cast(zoneSize) / static_cast(entriesCount))); if (entriesCount < zoneSize) { - throw std::runtime_error("Inconsistent agggressive cache " + std::to_string(entriesCount) + " " + std::to_string(zoneSize)); + throw std::runtime_error("Inconsistent aggressive cache " + std::to_string(entriesCount) + " " + std::to_string(zoneSize)); } // This is comparable to what cachecleaner.hh::pruneMutexCollectionsVector() is doing, look there for an explanation entriesCount -= zoneSize; @@ -262,18 +262,16 @@ { size_t ret = sizeof(AggressiveNSECCache::ZoneEntry::CacheEntry); if (d_record) { - ret += d_record->serialize(g_rootdnsname, true).size(); + ret += d_record->sizeEstimate(); } for (const auto& entry : d_signatures) { if (entry) { - ret += sizeof(RRSIGRecordContent); - ret += entry->d_signer.wirelength(); - ret += entry->d_signature.size(); + ret += entry->sizeEstimate(); } } - ret += d_owner.wirelength(); - ret += d_next.wirelength(); - ret += d_qname.wirelength(); + ret += d_owner.sizeEstimate(); + ret += d_next.sizeEstimate(); + ret += d_qname.sizeEstimate(); return ret; } @@ -457,7 +455,7 @@ return false; } -static void addToRRSet(const time_t now, std::vector& recordSet, std::vector> signatures, const DNSName& owner, bool doDNSSEC, std::vector& ret, DNSResourceRecord::Place place = DNSResourceRecord::AUTHORITY) +static void addToRRSet(const time_t now, std::vector& recordSet, const MemRecursorCache::SigRecs& signatures, const DNSName& owner, bool doDNSSEC, std::vector& ret, DNSResourceRecord::Place place = DNSResourceRecord::AUTHORITY) { uint32_t ttl = 0; @@ -474,12 +472,12 @@ } if (doDNSSEC) { - for (auto& signature : signatures) { + for (const auto& signature : *signatures) { DNSRecord dr; dr.d_type = QType::RRSIG; dr.d_name = owner; dr.d_ttl = ttl; - dr.setContent(std::move(signature)); + dr.setContent(signature); dr.d_place = place; dr.d_class = QClass::IN; ret.push_back(std::move(dr)); @@ -517,9 +515,9 @@ vState cachedState; std::vector wcSet; - std::vector> wcSignatures; + MemRecursorCache::SigRecs wcSignatures = MemRecursorCache::s_emptySigRecs; - if (g_recCache->get(now, wildcardName, type, MemRecursorCache::RequireAuth, &wcSet, ComboAddress("127.0.0.1"), boost::none, doDNSSEC ? &wcSignatures : nullptr, nullptr, nullptr, &cachedState) <= 0 || cachedState != vState::Secure) { + if (g_recCache->get(now, wildcardName, type, MemRecursorCache::RequireAuth, &wcSet, ComboAddress("127.0.0.1"), MemRecursorCache::NOTAG, doDNSSEC ? &wcSignatures : nullptr, nullptr, nullptr, &cachedState) <= 0 || cachedState != vState::Secure) { VLOG(log, name << ": Unfortunately we don't have a valid entry for " << wildcardName << ", so we cannot synthesize from that wildcard" << endl); return false; } @@ -541,14 +539,14 @@ vState cachedState; std::vector wcSet; - std::vector> wcSignatures; + MemRecursorCache::SigRecs wcSignatures = MemRecursorCache::s_emptySigRecs; - if (g_recCache->get(now, wildcardName, type, MemRecursorCache::RequireAuth, &wcSet, ComboAddress("127.0.0.1"), boost::none, doDNSSEC ? &wcSignatures : nullptr, nullptr, nullptr, &cachedState) <= 0 || cachedState != vState::Secure) { + if (g_recCache->get(now, wildcardName, type, MemRecursorCache::RequireAuth, &wcSet, ComboAddress("127.0.0.1"), MemRecursorCache::NOTAG, doDNSSEC ? &wcSignatures : nullptr, nullptr, nullptr, &cachedState) <= 0 || cachedState != vState::Secure) { VLOG(log, name << ": Unfortunately we don't have a valid entry for " << wildcardName << ", so we cannot synthesize from that wildcard" << endl); return false; } - addToRRSet(now, wcSet, std::move(wcSignatures), name, doDNSSEC, ret, DNSResourceRecord::ANSWER); + addToRRSet(now, wcSet, wcSignatures, name, doDNSSEC, ret, DNSResourceRecord::ANSWER); // coverity[store_truncates_time_t] addRecordToRRSet(nsec.d_owner, QType::NSEC, nsec.d_ttd - now, nsec.d_record, nsec.d_signatures, doDNSSEC, ret); @@ -558,7 +556,7 @@ return true; } -bool AggressiveNSECCache::getNSEC3Denial(time_t now, std::shared_ptr>& zoneEntry, std::vector& soaSet, std::vector>& soaSignatures, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, const OptLog& log, pdns::validation::ValidationContext& validationContext) +bool AggressiveNSECCache::getNSEC3Denial(time_t now, std::shared_ptr>& zoneEntry, std::vector& soaSet, const MemRecursorCache::SigRecs& soaSignatures, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, const OptLog& log, pdns::validation::ValidationContext& validationContext) { DNSName zone; std::string salt; @@ -664,6 +662,20 @@ return false; } + if (nsec3->isSet(QType::DNAME)) { + /* rfc6672 section 5.3.2: DNAME Bit in NSEC Type Map + + In any negative response, the NSEC or NSEC3 [RFC5155] record type + bitmap SHOULD be checked to see that there was no DNAME that could + have been applied. If the DNAME bit in the type bitmap is set and + the query name is a subdomain of the closest encloser that is + asserted, then DNAME substitution should have been done, but the + substitution has not been done as specified. + */ + VLOG_NO_PREFIX(log, " but this NSEC3 has the DNAME bit set"); + return false; + } + found = true; break; } @@ -796,7 +808,7 @@ return true; } -bool AggressiveNSECCache::getDenial(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, const ComboAddress& who, const boost::optional& routingTag, bool doDNSSEC, pdns::validation::ValidationContext& validationContext, const OptLog& log) +bool AggressiveNSECCache::getDenial(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, const ComboAddress& who, const std::string& routingTag, bool doDNSSEC, pdns::validation::ValidationContext& validationContext, const OptLog& log) { std::shared_ptr> zoneEntry; if (type == QType::DS) { @@ -828,7 +840,7 @@ vState cachedState; std::vector soaSet; - std::vector> soaSignatures; + MemRecursorCache::SigRecs soaSignatures = MemRecursorCache::s_emptySigRecs; /* we might not actually need the SOA if we find a matching wildcard, but let's not bother for now */ if (g_recCache->get(now, zone, QType::SOA, MemRecursorCache::RequireAuth, &soaSet, who, routingTag, doDNSSEC ? &soaSignatures : nullptr, nullptr, nullptr, &cachedState) <= 0 || cachedState != vState::Secure) { VLOG(log, name << ": No valid SOA found for " << zone << ", which is the best match for " << name << endl); @@ -917,9 +929,9 @@ return false; } - ret.reserve(ret.size() + soaSet.size() + soaSignatures.size() + /* NSEC */ 1 + entry.d_signatures.size() + (needWildcard ? (/* NSEC */ 1 + wcEntry.d_signatures.size()) : 0)); + ret.reserve(ret.size() + soaSet.size() + soaSignatures->size() + /* NSEC */ 1 + entry.d_signatures.size() + (needWildcard ? (/* NSEC */ 1 + wcEntry.d_signatures.size()) : 0)); - addToRRSet(now, soaSet, std::move(soaSignatures), zone, doDNSSEC, ret); + addToRRSet(now, soaSet, soaSignatures, zone, doDNSSEC, ret); // coverity[store_truncates_time_t] addRecordToRRSet(entry.d_owner, QType::NSEC, entry.d_ttd - now, entry.d_record, entry.d_signatures, doDNSSEC, ret); diff -Nru pdns-recursor-5.2.13/aggressive_nsec.hh pdns-recursor-5.4.9/aggressive_nsec.hh --- pdns-recursor-5.2.13/aggressive_nsec.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/aggressive_nsec.hh 2026-10-26 08:26:51.000000000 +0000 @@ -38,6 +38,7 @@ #include "stat_t.hh" #include "logger.hh" #include "validate.hh" +#include "recursor_cache.hh" class AggressiveNSECCache { @@ -63,7 +64,7 @@ } void insertNSEC(const DNSName& zone, const DNSName& owner, const DNSRecord& record, const std::vector>& signatures, bool nsec3, const DNSName& qname = g_rootdnsname, QType qtype = QType::ENT); - bool getDenial(time_t, const DNSName& name, const QType& type, std::vector& ret, int& res, const ComboAddress& who, const boost::optional& routingTag, bool doDNSSEC, pdns::validation::ValidationContext& validationContext, const OptLog& log = std::nullopt); + bool getDenial(time_t, const DNSName& name, const QType& type, std::vector& ret, int& res, const ComboAddress& who, const MemRecursorCache::OptTag& routingTag, bool doDNSSEC, pdns::validation::ValidationContext& validationContext, const OptLog& log = std::nullopt); void removeZoneInfo(const DNSName& zone, bool subzones); @@ -157,7 +158,7 @@ std::shared_ptr> getBestZone(const DNSName& zone); bool getNSECBefore(time_t now, std::shared_ptr>& zoneEntry, const DNSName& name, ZoneEntry::CacheEntry& entry); bool getNSEC3(time_t now, std::shared_ptr>& zoneEntry, const DNSName& name, ZoneEntry::CacheEntry& entry); - bool getNSEC3Denial(time_t now, std::shared_ptr>& zoneEntry, std::vector& soaSet, std::vector>& soaSignatures, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, const OptLog&, pdns::validation::ValidationContext& validationContext); + bool getNSEC3Denial(time_t now, std::shared_ptr>& zoneEntry, std::vector& soaSet, const MemRecursorCache::SigRecs& soaSignatures, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, const OptLog&, pdns::validation::ValidationContext& validationContext); bool synthesizeFromNSEC3Wildcard(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, ZoneEntry::CacheEntry& nextCloser, const DNSName& wildcardName, const OptLog&); bool synthesizeFromNSECWildcard(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, ZoneEntry::CacheEntry& nsec, const DNSName& wildcardName, const OptLog&); diff -Nru pdns-recursor-5.2.13/arguments.cc pdns-recursor-5.4.9/arguments.cc --- pdns-recursor-5.2.13/arguments.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/arguments.cc 2026-10-26 09:46:36.000000000 +0000 @@ -111,7 +111,7 @@ vector parts; stringtok(parts, param->second, ", \t"); - return std::any_of(parts.begin(), parts.end(), [&](const std::string& str) { return str == val; }); + return std::find(parts.begin(), parts.end(), val) != parts.end(); } string ArgvMap::helpstring(string prefix) @@ -350,15 +350,6 @@ // ATM Shared between Recursor and Auth, is that a good idea? static const map deprecateList = { - {"stats-api-blacklist", "stats-api-disabled-list"}, - {"stats-carbon-blacklist", "stats-carbon-disabled-list"}, - {"stats-rec-control-blacklist", "stats-rec-control-disabled-list"}, - {"stats-snmp-blacklist", "stats-snmp-disabled-list"}, - {"edns-subnet-whitelist", "edns-subnet-allow-list"}, - {"new-domain-whitelist", "new-domain-ignore-list"}, - {"snmp-master-socket", "snmp-daemon-socket"}, - {"xpf-allow-from", "Proxy Protocol"}, - {"xpf-rr-code", "Proxy Protocol"}, {"domain-metadata-cache-ttl", "zone-metadata-cache-ttl"}, }; @@ -433,7 +424,7 @@ } else { d_params[var] = val; - d_cleared.insert(var); + d_cleared.insert(std::move(var)); } } else { @@ -583,14 +574,12 @@ // build name string fullName = directory + "/" + std::string(name); // ensure it's readable file - struct stat statInfo - { - }; + struct stat statInfo{}; if (stat(fullName.c_str(), &statInfo) != 0 || !S_ISREG(statInfo.st_mode)) { string msg = fullName + " is not a regular file"; SLOG(g_log << Logger::Error << msg << std::endl, d_log->info(Logr::Error, "Unable to open non-regular file", "name", Logging::Loggable(fullName))); - throw ArgException(msg); + throw ArgException(std::move(msg)); } vec.emplace_back(fullName); } @@ -602,7 +591,7 @@ string msg = directory + " is not accessible: " + stringerror(err); SLOG(g_log << Logger::Error << msg << std::endl, d_log->error(Logr::Error, err, "Directory is not accessible", "name", Logging::Loggable(directory))); - throw ArgException(msg); + throw ArgException(std::move(msg)); } std::sort(vec.begin(), vec.end(), CIStringComparePOSIX()); diff -Nru pdns-recursor-5.2.13/auth-catalogzone.hh pdns-recursor-5.4.9/auth-catalogzone.hh --- pdns-recursor-5.2.13/auth-catalogzone.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/auth-catalogzone.hh 2026-10-26 09:46:36.000000000 +0000 @@ -28,7 +28,7 @@ struct DomainInfo; -typedef map CatalogHashMap; +typedef map CatalogHashMap; class CatalogInfo { @@ -48,7 +48,7 @@ CatalogInfo() : d_id(0), d_type(CatalogType::None) {} - CatalogInfo(uint32_t id, const DNSName& zone, const std::string& options, CatalogType type) + CatalogInfo(uint32_t id, const ZoneName& zone, const std::string& options, CatalogType type) { d_id = id; d_zone = zone; @@ -60,9 +60,9 @@ void setType(CatalogType type) { d_type = type; } void updateHash(CatalogHashMap& hashes, const DomainInfo& di) const; - DNSName getUnique() const { return DNSName(toBase32Hex(hashQNameWithSalt(std::to_string(d_id), 0, d_zone))); } // salt with domain id to detect recreated zones - static DNSZoneRecord getCatalogVersionRecord(const DNSName& zone); - void toDNSZoneRecords(const DNSName& zone, vector& dzrs) const; + DNSName getUnique() const { return DNSName(toBase32Hex(hashQNameWithSalt(std::to_string(d_id), 0, DNSName(d_zone)))); } // salt with domain id to detect recreated zones + static DNSZoneRecord getCatalogVersionRecord(const ZoneName& zone); + void toDNSZoneRecords(const ZoneName& zone, vector& dzrs) const; bool operator<(const CatalogInfo& rhs) const { @@ -70,7 +70,8 @@ } uint32_t d_id; - DNSName d_zone, d_coo, d_unique; + ZoneName d_zone; + DNSName d_coo, d_unique; std::set d_group; vector d_primaries; diff -Nru pdns-recursor-5.2.13/axfr-retriever.cc pdns-recursor-5.4.9/axfr-retriever.cc --- pdns-recursor-5.2.13/axfr-retriever.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/axfr-retriever.cc 2026-10-26 09:46:36.000000000 +0000 @@ -30,12 +30,12 @@ using pdns::resolver::parseResult; AXFRRetriever::AXFRRetriever(const ComboAddress& remote, - const DNSName& domain, - const TSIGTriplet& tt, + const ZoneName& domain, + const TSIGTriplet& tsigConf, const ComboAddress* laddr, size_t maxReceivedBytes, - uint16_t timeout) - : d_buf(65536), d_tsigVerifier(tt, remote, d_trc), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes) + uint16_t timeout) : + d_buf(65536), d_tsigVerifier(tsigConf, remote, d_trc), d_maxReceivedBytes(maxReceivedBytes) { ComboAddress local; if (laddr != nullptr) { @@ -57,19 +57,21 @@ d_soacount = 0; vector packet; - DNSPacketWriter pw(packet, domain, QType::AXFR); - pw.getHeader()->id = dns_random_uint16(); - - if(!tt.name.empty()) { - if (tt.algo == DNSName("hmac-md5")) - d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int"); - else - d_trc.d_algoName = tt.algo; + DNSPacketWriter pwriter(packet, DNSName(domain), QType::AXFR); + pwriter.getHeader()->id = dns_random_uint16(); + + if (!tsigConf.name.empty()) { + if (tsigConf.algo == g_hmacmd5dnsname) { + d_trc.d_algoName = g_hmacmd5dnsname_long; + } + else { + d_trc.d_algoName = tsigConf.algo; + } d_trc.d_time = time(nullptr); d_trc.d_fudge = 300; - d_trc.d_origID=ntohs(pw.getHeader()->id); + d_trc.d_origID=ntohs(pwriter.getHeader()->id); d_trc.d_eRcode=0; - addTSIG(pw, d_trc, tt.name, tt.secret, "", false); + addTSIG(pwriter, d_trc, tsigConf.name, tsigConf.secret, "", false); } uint16_t replen=htons(packet.size()); @@ -103,7 +105,9 @@ AXFRRetriever::~AXFRRetriever() { - close(d_sock); + if (d_sock != -1) { + close(d_sock); + } } @@ -216,6 +220,7 @@ throw ResolverException("Error closing AXFR socket after connect() failed: "+e.reason); } + d_sock = -1; throw ResolverException("connect: "+stringerror()); } diff -Nru pdns-recursor-5.2.13/axfr-retriever.hh pdns-recursor-5.4.9/axfr-retriever.hh --- pdns-recursor-5.2.13/axfr-retriever.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/axfr-retriever.hh 2026-10-26 09:46:36.000000000 +0000 @@ -30,7 +30,7 @@ { public: AXFRRetriever(const ComboAddress& remote, - const DNSName& zone, + const ZoneName& zone, const TSIGTriplet& tt = TSIGTriplet(), const ComboAddress* laddr = NULL, size_t maxReceivedBytes=0, @@ -51,6 +51,6 @@ TSIGRecordContent d_trc; TSIGTCPVerifier d_tsigVerifier; - size_t d_receivedBytes; + size_t d_receivedBytes{0}; size_t d_maxReceivedBytes; }; diff -Nru pdns-recursor-5.2.13/base64.cc pdns-recursor-5.4.9/base64.cc --- pdns-recursor-5.2.13/base64.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/base64.cc 2026-10-26 09:46:36.000000000 +0000 @@ -19,36 +19,49 @@ * 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 "base64.hh" +#include +#include #include + #include #include #include -template int B64Decode(const std::string& src, Container& dst) +template +int B64Decode(const std::string& src, Container& dst) { - if (src.empty() ) { + if (src.empty()) { dst.clear(); return 0; } - int dlen = ( src.length() * 6 + 7 ) / 8 ; - ssize_t olen = 0; + // check if the dlen computation might overflow or it does not fit into an int (for IO_write) + if (src.length() > std::numeric_limits::max() / 7U || src.length() > std::numeric_limits::max()) { + throw std::runtime_error("B64Decode too large"); + } + const size_t dlen = (src.length() * 6U + 7U) / 8U; dst.resize(dlen); - BIO *bio, *b64; - bio = BIO_new(BIO_s_mem()); - BIO_write(bio, src.c_str(), src.length()); - b64 = BIO_new(BIO_f_base64()); - bio = BIO_push(b64, bio); - BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); - olen = BIO_read(b64, &dst.at(0), dlen); - if ((olen == 0 || olen == -1) && BIO_should_retry(bio)) { - BIO_free_all(bio); + auto bio = std::unique_ptr(BIO_new(BIO_s_mem()), BIO_free_all); + if (!bio) { + throw std::runtime_error("BIO_new failed"); + } + if (BIO_write(bio.get(), src.c_str(), src.length()) != static_cast(src.length())) { + throw std::runtime_error("BIO_write failed"); + } + auto* b64 = BIO_new(BIO_f_base64()); + if (b64 == nullptr) { + throw std::runtime_error("BIO_new failed"); + } + bio = std::unique_ptr(BIO_push(b64, bio.release()), BIO_free_all); + BIO_set_flags(bio.get(), BIO_FLAGS_BASE64_NO_NL); + auto olen = BIO_read(b64, &dst.at(0), dlen); + if ((olen == 0 || olen == -1) && BIO_should_retry(bio.get())) { throw std::runtime_error("BIO_read failed to read all data from memory buffer"); } - BIO_free_all(bio); + bio.reset(); if (olen > 0) { dst.resize(olen); return 0; @@ -61,25 +74,28 @@ std::string Base64Encode(const std::string& src) { if (!src.empty()) { - size_t olen = 0; - BIO *bio, *b64; - b64 = BIO_new(BIO_f_base64()); - bio = BIO_new(BIO_s_mem()); - bio = BIO_push(b64, bio); - BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); - int bioWriteRet = BIO_write(bio, src.c_str(), src.length()); - if (bioWriteRet < 0 || (size_t) bioWriteRet != src.length()) { - BIO_free_all(bio); + auto bio = std::unique_ptr(BIO_new(BIO_s_mem()), BIO_free_all); + if (!bio) { + throw std::runtime_error("BIO_new failed"); + } + auto* b64 = BIO_new(BIO_f_base64()); + if (b64 == nullptr) { + throw std::runtime_error("BIO_new failed"); + } + bio = std::unique_ptr(BIO_push(b64, bio.release()), BIO_free_all); + BIO_set_flags(bio.get(), BIO_FLAGS_BASE64_NO_NL); + int bioWriteRet = BIO_write(bio.get(), src.c_str(), src.length()); + if (bioWriteRet < 0 || static_cast(bioWriteRet) != src.length()) { throw std::runtime_error("BIO_write failed to write all data to memory buffer"); } - (void)BIO_flush(bio); + (void)BIO_flush(bio.get()); char* pp; std::string out; - olen = BIO_get_mem_data(bio, &pp); + auto olen = BIO_get_mem_data(bio.get(), &pp); if (olen > 0) { out = std::string(pp, olen); } - BIO_free_all(bio); + bio.reset(); return out; } return ""; diff -Nru pdns-recursor-5.2.13/base64.hh pdns-recursor-5.4.9/base64.hh --- pdns-recursor-5.2.13/base64.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/base64.hh 2026-10-26 09:46:36.000000000 +0000 @@ -22,5 +22,6 @@ #pragma once #include -template int B64Decode(const std::string& strInput, Container& strOutput); -std::string Base64Encode (const std::string& src); +template +int B64Decode(const std::string& strInput, Container& strOutput); +std::string Base64Encode(const std::string& src); diff -Nru pdns-recursor-5.2.13/build-aux/compile pdns-recursor-5.4.9/build-aux/compile --- pdns-recursor-5.2.13/build-aux/compile 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/compile 2026-10-26 09:47:08.729288300 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. -scriptversion=2018-03-07.03; # UTC +scriptversion=2024-06-19.01; # UTC -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify @@ -143,7 +143,7 @@ # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in - *.o | *.[oO][bB][jJ]) + *.o | *.lo | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift @@ -248,14 +248,17 @@ right script to run: please start by reading the file 'INSTALL'. Report bugs to . +GNU Automake home page: . +General help using GNU software: . EOF exit $? ;; -v | --v*) - echo "compile $scriptversion" + echo "compile (GNU Automake) $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; diff -Nru pdns-recursor-5.2.13/build-aux/config.guess pdns-recursor-5.4.9/build-aux/config.guess --- pdns-recursor-5.2.13/build-aux/config.guess 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/config.guess 2026-10-26 09:47:08.730288300 +0000 @@ -1,14 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2021 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2021-06-03' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -47,7 +47,7 @@ usage="\ Usage: $0 [OPTION] -Output the configuration name of the system \`$me' is run on. +Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit @@ -60,13 +60,13 @@ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2021 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -102,8 +102,8 @@ # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. +# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still +# use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. @@ -155,6 +155,9 @@ set_cc_for_build cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else #include #if defined(__UCLIBC__) LIBC=uclibc @@ -162,6 +165,8 @@ LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include /* First heuristic to detect musl libc. */ @@ -169,6 +174,7 @@ LIBC=musl #endif #endif + #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" @@ -437,7 +443,7 @@ # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 @@ -459,7 +465,7 @@ UNAME_RELEASE=`uname -v` ;; esac - # Japanese Language versions have a version number like `4.1.3-JL'. + # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; @@ -904,7 +910,7 @@ fi ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; @@ -929,6 +935,9 @@ i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) case $UNAME_MACHINE in x86) @@ -963,11 +972,37 @@ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __ARM_EABI__ + #ifdef __ARM_PCS_VFP + ABI=eabihf + #else + ABI=eabi + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; + esac + fi + GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be @@ -1033,7 +1068,16 @@ k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + kvx:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:cos:*:*) + GUESS=$UNAME_MACHINE-unknown-cos + ;; + kvx:mbr:*:*) + GUESS=$UNAME_MACHINE-unknown-mbr + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) @@ -1148,16 +1192,27 @@ ;; x86_64:Linux:*:*) set_cc_for_build + CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI=${LIBC}x32 - fi + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac fi - GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC @@ -1177,7 +1232,7 @@ GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility + # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; @@ -1318,7 +1373,7 @@ GUESS=ns32k-sni-sysv fi ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; @@ -1364,8 +1419,11 @@ BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; - x86_64:Haiku:*:*) - GUESS=x86_64-unknown-haiku + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE @@ -1522,6 +1580,9 @@ i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; @@ -1534,6 +1595,9 @@ *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac # Do we have a guess based on uname results? diff -Nru pdns-recursor-5.2.13/build-aux/config.sub pdns-recursor-5.4.9/build-aux/config.sub --- pdns-recursor-5.2.13/build-aux/config.sub 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/config.sub 2026-10-26 09:47:08.731288400 +0000 @@ -1,14 +1,14 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2021 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2021-08-14' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -76,13 +76,13 @@ version="\ GNU config.sub ($timestamp) -Copyright 1992-2021 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -130,7 +130,7 @@ # Separate into logical components for further validation case $1 in *-*-*-*-*) - echo Invalid configuration \`"$1"\': more than four components >&2 + echo "Invalid configuration '$1': more than four components" >&2 exit 1 ;; *-*-*-*) @@ -145,7 +145,8 @@ nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) + | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ + | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; @@ -943,7 +944,7 @@ EOF IFS=$saved_IFS ;; - # We use `pc' rather than `unknown' + # We use 'pc' rather than 'unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) @@ -1020,6 +1021,11 @@ ;; # Here we normalize CPU types with a missing or matching vendor + armh-unknown | armh-alt) + cpu=armv7l + vendor=alt + basic_os=${basic_os:-linux-gnueabihf} + ;; dpx20-unknown | dpx20-bull) cpu=rs6000 vendor=bull @@ -1070,7 +1076,7 @@ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) cpu=i586 ;; - pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*) cpu=i686 ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) @@ -1121,7 +1127,7 @@ xscale-* | xscalee[bl]-*) cpu=`echo "$cpu" | sed 's/^xscale/arm/'` ;; - arm64-*) + arm64-* | aarch64le-*) cpu=aarch64 ;; @@ -1175,7 +1181,7 @@ case $cpu in 1750a | 580 \ | a29k \ - | aarch64 | aarch64_be \ + | aarch64 | aarch64_be | aarch64c | arm64ec \ | abacus \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ @@ -1194,50 +1200,29 @@ | d10v | d30v | dlx | dsp16xx \ | e2k | elxsi | epiphany \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | javascript \ | h8300 | h8500 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i*86 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ + | kvx \ | le32 | le64 \ | lm32 \ - | loongarch32 | loongarch64 | loongarchx32 \ + | loongarch32 | loongarch64 \ | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ | m88110 | m88k | maxq | mb | mcore | mep | metag \ | microblaze | microblazeel \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64eb | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r3 | mipsisa32r3el \ - | mipsisa32r5 | mipsisa32r5el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r3 | mipsisa64r3el \ - | mipsisa64r5 | mipsisa64r5el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ + | mips* \ | mmix \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ + | nanomips* \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ @@ -1269,6 +1254,7 @@ | ubicom32 \ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ | vax \ + | vc4 \ | visium \ | w65 \ | wasm32 | wasm64 \ @@ -1280,7 +1266,7 @@ ;; *) - echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2 exit 1 ;; esac @@ -1301,11 +1287,12 @@ # Decode manufacturer-specific aliases for certain operating systems. -if test x$basic_os != x +if test x"$basic_os" != x then -# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. +obj= case $basic_os in gnu/linux*) kernel=linux @@ -1336,6 +1323,10 @@ kernel=linux os=`echo "$basic_os" | sed -e 's|linux|gnu|'` ;; + managarm*) + kernel=managarm + os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'` + ;; *) kernel= os=$basic_os @@ -1501,10 +1492,16 @@ os=eabi ;; *) - os=elf + os= + obj=elf ;; esac ;; + aout* | coff* | elf* | pe*) + # These are machine code file formats, not OSes + obj=$os + os= + ;; *) # No normalization, but not necessarily accepted, that comes below. ;; @@ -1523,12 +1520,15 @@ # system, and we'll never get to this point. kernel= +obj= case $cpu-$vendor in score-*) - os=elf + os= + obj=elf ;; spu-*) - os=elf + os= + obj=elf ;; *-acorn) os=riscix1.2 @@ -1538,28 +1538,35 @@ os=gnu ;; arm*-semi) - os=aout + os= + obj=aout ;; c4x-* | tic4x-*) - os=coff + os= + obj=coff ;; c8051-*) - os=elf + os= + obj=elf ;; clipper-intergraph) os=clix ;; hexagon-*) - os=elf + os= + obj=elf ;; tic54x-*) - os=coff + os= + obj=coff ;; tic55x-*) - os=coff + os= + obj=coff ;; tic6x-*) - os=coff + os= + obj=coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1581,19 +1588,24 @@ os=sunos3 ;; m68*-cisco) - os=aout + os= + obj=aout ;; mep-*) - os=elf + os= + obj=elf ;; mips*-cisco) - os=elf + os= + obj=elf ;; - mips*-*) - os=elf + mips*-*|nanomips*-*) + os= + obj=elf ;; or32-*) - os=coff + os= + obj=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 @@ -1602,7 +1614,8 @@ os=sunos4.1.1 ;; pru-*) - os=elf + os= + obj=elf ;; *-be) os=beos @@ -1683,10 +1696,12 @@ os=uxpv ;; *-rom68k) - os=coff + os= + obj=coff ;; *-*bug) - os=coff + os= + obj=coff ;; *-apple) os=macos @@ -1704,10 +1719,11 @@ fi -# Now, validate our (potentially fixed-up) OS. +# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ). + case $os in # Sometimes we do "kernel-libc", so those need to count as OSes. - musl* | newlib* | relibc* | uclibc*) + llvm* | musl* | newlib* | relibc* | uclibc*) ;; # Likewise for "kernel-abi" eabi* | gnueabi*) @@ -1715,6 +1731,9 @@ # VxWorks passes extra cpu info in the 4th filed. simlinux | simwindows | spe) ;; + # See `case $cpu-$os` validation below + ghcjs) + ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. @@ -1723,7 +1742,7 @@ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | hiux* | abug | nacl* | netware* | windows* \ - | os9* | macos* | osx* | ios* \ + | os9* | macos* | osx* | ios* | tvos* | watchos* \ | mpw* | magic* | mmixware* | mon960* | lnews* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ @@ -1732,11 +1751,11 @@ | mirbsd* | netbsd* | dicos* | openedition* | ose* \ | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ - | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | bosx* | nextstep* | cxux* | oabi* \ + | ptx* | ecoff* | winnt* | domain* | vsta* \ | udi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* | serenity* \ - | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | cygwin* | msys* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | mint* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ @@ -1748,49 +1767,117 @@ | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*) + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; + # This refers to builds using the UEFI calling convention + # (which depends on the architecture) and PE file format. + # Note that this is both a different calling convention and + # different file format than that of GNU-EFI + # (x86_64-w64-mingw32). + uefi) + ;; none) ;; + kernel* | msvc* ) + # Restricted further below + ;; + '') + if test x"$obj" = x + then + echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2 + fi + ;; *) - echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 + exit 1 + ;; +esac + +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; + *) + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ - | linux-musl* | linux-relibc* | linux-uclibc* ) +case $kernel-$os-$obj in + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- ) + ;; + uclinux-uclibc*- ) + ;; + managarm-mlibc*- | managarm-kernel*- ) ;; - uclinux-uclibc* ) + windows*-msvc*-) ;; - -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. - echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) + -kernel*- ) + echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 + exit 1 ;; - vxworks-simlinux | vxworks-simwindows | vxworks-spe) + *-kernel*- ) + echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 + exit 1 ;; - nto-qnx*) + *-msvc*- ) + echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 + exit 1 ;; - os2-emx) + kfreebsd*-gnu*- | kopensolaris*-gnu*-) + ;; + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) + ;; + nto-qnx*-) + ;; + os2-emx-) ;; - *-eabi* | *-gnueabi*) + *-eabi*- | *-gnueabi*-) ;; - -*) + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format + ;; + -*-) # Blank kernel with real OS is always fine. ;; - *-*) - echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) + echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac @@ -1873,7 +1960,7 @@ ;; esac -echo "$cpu-$vendor-${kernel:+$kernel-}$os" +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: diff -Nru pdns-recursor-5.2.13/build-aux/depcomp pdns-recursor-5.4.9/build-aux/depcomp --- pdns-recursor-5.2.13/build-aux/depcomp 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/depcomp 2026-10-26 09:47:08.762288800 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects -scriptversion=2018-03-07.03; # UTC +scriptversion=2024-06-19.01; # UTC -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -47,11 +47,13 @@ libtool Whether libtool is used (yes/no). Report bugs to . +GNU Automake home page: . +General help using GNU software: . EOF exit $? ;; -v | --v*) - echo "depcomp $scriptversion" + echo "depcomp (GNU Automake) $scriptversion" exit $? ;; esac @@ -113,7 +115,6 @@ # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz -digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then @@ -128,7 +129,7 @@ rm -f "$tmpdepfile" -# Avoid interferences from the environment. +# Avoid interference from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We @@ -198,8 +199,8 @@ ;; gcc) -## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. -## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## Note that this doesn't just cater to obsolete pre-3.x GCC compilers. +## but also to in-use compilers like IBM xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: diff -Nru pdns-recursor-5.2.13/build-aux/gen-version pdns-recursor-5.4.9/build-aux/gen-version --- pdns-recursor-5.2.13/build-aux/gen-version 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/gen-version 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,77 @@ +#!/bin/sh +if [ ! -z "${BUILDER_VERSION}" ]; then + printf ${BUILDER_VERSION} + exit 0 +fi + +VERSION="unknown" + +DIRTY="" +git status | grep -q clean || DIRTY='.dirty' + +# Special environment variable to signal that we are building a release, as this +# has consequences for the version number. +if [ "${IS_RELEASE}" = "YES" ]; then + TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)" + if [ -n "${TAG}" ]; then + # We're on a tag + echo "${TAG}${DIRTY}" > .version + printf "${TAG}${DIRTY}" + exit 0 + fi + echo 'This is not a tag, either tag this commit or do not set $IS_RELEASE' >&2 + exit 1 +fi + +# +# Generate the version number based on the branch +# +if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then + if [ -n "${BUILDER_MODULES}" ]; then + match=${BUILDER_MODULES} + [ $match = "authoritative" ] && match='auth' + [ $match = "recursor" ] && match='rec' + GIT_VERSION="$(git describe --match=${match}-* --tags | cut -d- -f2-)" + if [ $(echo ${GIT_VERSION} | awk -F"-" '{print NF-1}') = '3' ]; then + # A prerelease happened before + LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1-2)" + COMMITS_SINCE_TAG="$(echo ${GIT_VERSION} | cut -d- -f3)" + GIT_HASH="$(echo ${GIT_VERSION} | cut -d- -f4)" + elif [ $(echo ${GIT_VERSION} | awk -F"-" '{print NF-1}') = '1' ]; then + # Exactly on a pre-release + LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1-2)" + else + LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1)" + COMMITS_SINCE_TAG="$(echo ${GIT_VERSION} | cut -d- -f2)" + GIT_HASH="$(echo ${GIT_VERSION} | cut -d- -f3)" + fi + fi + + if [ -z "${GIT_VERSION}" ]; then + # BUILDER_SUPPORT has more than one product listed, fall back to the 0.0.0 logic + + # We used 0.0.XXXXgHASH for master in the previous incarnation of our build pipeline. + # This now becomes 0.0.XXXX.0.gHASH, as 0.0.0.XXXX.gHASH (which is more correct) + # would break upgrades for those running master + # This _should_ be ok for forever if we stick to X.Y.Z for version numbers + LAST_TAG=0.0 + COMMITS_SINCE_TAG="$(git rev-list --count 12c868770afc20b6cc0da439d881105151d557dd..HEAD 2> /dev/null).0" + [ "${COMMITS_SINCE_TAG}" = ".0" ] && COMMITS_SINCE_TAG=0.0 + GIT_HASH="g$(git rev-parse HEAD | cut -c1-10 2> /dev/null)" + fi + + BRANCH=".$(git rev-parse --abbrev-ref HEAD | perl -p -e 's/[^[:alnum:]]//g;')" + + TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)" + if [ -n "${TAG}" ]; then # We're exactly on a tag + COMMITS_SINCE_TAG="0" + GIT_HASH="g$(git show --no-patch --format=format:%h HEAD 2>/dev/null)" + if [ -z "$GIT_HASH" ]; then + GIT_HASH="g$(git show --format=format:%h HEAD | head -n1)" + fi + fi + + VERSION="${LAST_TAG}.${COMMITS_SINCE_TAG}${BRANCH}.${GIT_HASH}${DIRTY}" +fi + +printf $VERSION diff -Nru pdns-recursor-5.2.13/build-aux/install-sh pdns-recursor-5.4.9/build-aux/install-sh --- pdns-recursor-5.2.13/build-aux/install-sh 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/install-sh 2026-10-26 09:47:08.732288400 +0000 @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2020-11-14.01; # UTC +scriptversion=2024-06-19.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -124,9 +124,9 @@ If -S is not specified, no backups are attempted. -Email bug reports to bug-automake@gnu.org. -Automake home page: https://www.gnu.org/software/automake/ -" +Report bugs to . +GNU Automake home page: . +General help using GNU software: ." while test $# -ne 0; do case $1 in @@ -170,7 +170,7 @@ -T) is_target_a_directory=never;; - --version) echo "$0 $scriptversion"; exit $?;; + --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; --) shift break;; @@ -345,7 +345,7 @@ ' 0 # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directly in world-writable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && @@ -353,7 +353,7 @@ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. + # Check for POSIX incompatibility with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. diff -Nru pdns-recursor-5.2.13/build-aux/missing pdns-recursor-5.4.9/build-aux/missing --- pdns-recursor-5.2.13/build-aux/missing 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/missing 2026-10-26 09:47:08.733288300 +0000 @@ -1,9 +1,11 @@ #! /bin/sh -# Common wrapper for a few potentially missing GNU programs. +# Common wrapper for a few potentially missing GNU and other programs. -scriptversion=2018-03-07.03; # UTC +scriptversion=2024-06-07.14; # UTC -# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells + +# Copyright (C) 1996-2024 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify @@ -54,18 +56,20 @@ -v, --version output version information and exit Supported PROGRAM values: - aclocal autoconf autoheader autom4te automake makeinfo - bison yacc flex lex help2man +aclocal autoconf autogen autoheader autom4te automake autoreconf +bison flex help2man lex makeinfo perl yacc Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. -Send bug reports to ." +Report bugs to . +GNU Automake home page: . +General help using GNU software: ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) - echo "missing $scriptversion (GNU Automake)" + echo "missing (GNU Automake) $scriptversion" exit $? ;; @@ -108,7 +112,7 @@ program_details () { case $1 in - aclocal|automake) + aclocal|automake|autoreconf) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" @@ -123,6 +127,9 @@ echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; + *) + : + ;; esac } @@ -137,48 +144,55 @@ printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + autoheader_deps="'acconfig.h'" + automake_deps="'Makefile.am'" + aclocal_deps="'acinclude.m4'" case $normalized_program in + aclocal*) + echo "You should only need it if you modified $aclocal_deps or" + echo "$configure_deps." + ;; autoconf*) - echo "You should only need it if you modified 'configure.ac'," - echo "or m4 files included by it." - program_details 'autoconf' + echo "You should only need it if you modified $configure_deps." + ;; + autogen*) + echo "You should only need it if you modified a '.def' or '.tpl' file." + echo "You may want to install the GNU AutoGen package:" + echo "<$gnu_software_URL/autogen/>" ;; autoheader*) - echo "You should only need it if you modified 'acconfig.h' or" + echo "You should only need it if you modified $autoheader_deps or" echo "$configure_deps." - program_details 'autoheader' ;; automake*) - echo "You should only need it if you modified 'Makefile.am' or" - echo "$configure_deps." - program_details 'automake' - ;; - aclocal*) - echo "You should only need it if you modified 'acinclude.m4' or" + echo "You should only need it if you modified $automake_deps or" echo "$configure_deps." - program_details 'aclocal' ;; - autom4te*) + autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." - program_details 'autom4te' + ;; + autoreconf*) + echo "You should only need it if you modified $aclocal_deps or" + echo "$automake_deps or $autoheader_deps or $automake_deps or" + echo "$configure_deps." ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; - lex*|flex*) - echo "You should only need it if you modified a '.l' file." - echo "You may want to install the Fast Lexical Analyzer package:" - echo "<$flex_URL>" - ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." @@ -189,6 +203,12 @@ echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; + perl*) + echo "You should only need it to run GNU Autoconf, GNU Automake, " + echo " assorted other tools, or if you modified a Perl source file." + echo "You may want to install the Perl 5 language interpreter:" + echo "<$perl_URL>" + ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" @@ -197,6 +217,7 @@ echo "case some other package contains this missing '$1' program." ;; esac + program_details "$normalized_program" } give_advice "$1" | sed -e '1s/^/WARNING: /' \ diff -Nru pdns-recursor-5.2.13/build-aux/test-driver pdns-recursor-5.4.9/build-aux/test-driver --- pdns-recursor-5.2.13/build-aux/test-driver 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/build-aux/test-driver 2026-10-26 09:47:08.773289000 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # test-driver - basic testsuite driver script. -scriptversion=2018-03-07.03; # UTC +scriptversion=2024-06-19.01; # UTC -# Copyright (C) 2011-2021 Free Software Foundation, Inc. +# Copyright (C) 2011-2024 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -44,11 +44,16 @@ Usage: test-driver --test-name NAME --log-file PATH --trs-file PATH [--expect-failure {yes|no}] [--color-tests {yes|no}] + [--collect-skipped-logs {yes|no}] [--enable-hard-errors {yes|no}] [--] TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] The '--test-name', '--log-file' and '--trs-file' options are mandatory. See the GNU Automake documentation for information. + +Report bugs to . +GNU Automake home page: . +General help using GNU software: . END } @@ -57,15 +62,17 @@ trs_file= # Where to save the metadata of the test run. expect_failure=no color_tests=no +collect_skipped_logs=yes enable_hard_errors=yes while test $# -gt 0; do case $1 in --help) print_usage; exit $?;; - --version) echo "test-driver $scriptversion"; exit $?;; + --version) echo "test-driver (GNU Automake) $scriptversion"; exit $?;; --test-name) test_name=$2; shift;; --log-file) log_file=$2; shift;; --trs-file) trs_file=$2; shift;; --color-tests) color_tests=$2; shift;; + --collect-skipped-logs) collect_skipped_logs=$2; shift;; --expect-failure) expect_failure=$2; shift;; --enable-hard-errors) enable_hard_errors=$2; shift;; --) shift; break;; @@ -121,7 +128,7 @@ case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; - 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; + 77:*) col=$blu res=SKIP recheck=no gcopy=$collect_skipped_logs;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; diff -Nru pdns-recursor-5.2.13/builder-support/gen-version pdns-recursor-5.4.9/builder-support/gen-version --- pdns-recursor-5.2.13/builder-support/gen-version 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/builder-support/gen-version 2026-10-26 08:26:51.000000000 +0000 @@ -10,7 +10,7 @@ git status | grep -q clean || DIRTY='.dirty' # Special environment variable to signal that we are building a release, as this -# has consequenses for the version number. +# has consequences for the version number. if [ "${IS_RELEASE}" = "YES" ]; then TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)" if [ -n "${TAG}" ]; then @@ -53,7 +53,7 @@ # We used 0.0.XXXXgHASH for master in the previous incarnation of our build pipeline. # This now becomes 0.0.XXXX.0.gHASH, as 0.0.0.XXXX.gHASH (which is more correct) # would break upgrades for those running master - # This _should_ be ok for forever is we stick to X.Y.Z for version numbers + # This _should_ be ok for forever if we stick to X.Y.Z for version numbers LAST_TAG=0.0 COMMITS_SINCE_TAG="$(git rev-list --count 12c868770afc20b6cc0da439d881105151d557dd..HEAD 2> /dev/null).0" [ "${COMMITS_SINCE_TAG}" = ".0" ] && COMMITS_SINCE_TAG=0.0 diff -Nru pdns-recursor-5.2.13/burtle.hh pdns-recursor-5.4.9/burtle.hh --- pdns-recursor-5.2.13/burtle.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/burtle.hh 2026-10-26 09:46:36.000000000 +0000 @@ -178,3 +178,9 @@ /*-------------------------------------------- report the result */ return c; } + +template +inline uint32_t burtleCI(const T& k, uint32_t initval) +{ + return burtleCI(reinterpret_cast(k.data()), k.length(), initval); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): can't static_cast because of sign difference +} diff -Nru pdns-recursor-5.2.13/cachecleaner.hh pdns-recursor-5.4.9/cachecleaner.hh --- pdns-recursor-5.2.13/cachecleaner.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/cachecleaner.hh 2026-10-26 09:46:36.000000000 +0000 @@ -197,7 +197,7 @@ // // Suppose we have 10 perfectly balanced shards, each filled with // 100 entries. So cacheSize is 1000. When cleaning 10%, after shard - // 0 we still need to processs 900 entries, spread out of 9 + // 0 we still need to process 900 entries, spread out of 9 // shards. So cacheSize becomes 900, and toTrim 90, since we cleaned // 10 items from shard 0. Our fraction remains 10%. For the last // shard, we would end up with cacheSize 100, and to clean 10. diff -Nru pdns-recursor-5.2.13/channel.hh pdns-recursor-5.4.9/channel.hh --- pdns-recursor-5.2.13/channel.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/channel.hh 2026-10-26 09:46:36.000000000 +0000 @@ -24,29 +24,7 @@ #include #include "misc.hh" - -/* 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 - -#if __SANITIZE_THREAD__ -#if defined __has_include -#if __has_include() -#include -#else /* __has_include() */ -extern "C" void __tsan_acquire(void* addr); -extern "C" void __tsan_release(void* addr); -#endif /* __has_include() */ -#else /* defined __has_include */ -extern "C" void __tsan_acquire(void* addr); -extern "C" void __tsan_release(void* addr); -#endif /* defined __has_include */ -#endif /* __SANITIZE_THREAD__ */ +#include "sanitizer.hh" namespace pdns { @@ -243,7 +221,7 @@ not even to release it, so let's transfer it to a local object */ auto localObj = std::move(object); auto ptr = localObj.get(); - static_assert(sizeof(ptr) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranted not to interleaved and to either fully succeed or fail"); + static_assert(sizeof(ptr) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to interleaved and to either fully succeed or fail"); while (true) { #if __SANITIZE_THREAD__ __tsan_release(ptr); diff -Nru pdns-recursor-5.2.13/comment.hh pdns-recursor-5.4.9/comment.hh --- pdns-recursor-5.2.13/comment.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/comment.hh 2026-10-26 09:46:36.000000000 +0000 @@ -27,15 +27,12 @@ class Comment { public: - Comment() : modified_at(0), domain_id(0) {}; - ~Comment() = default; - // data DNSName qname; //!< the name of the associated RRset, for example: www.powerdns.com - time_t modified_at; + time_t modified_at{0}; string account; //!< account last updating this comment string content; //!< The actual comment. Example: blah blah - int domain_id; + domainid_t domain_id{0}; QType qtype; //!< qtype of the associated RRset, ie A, CNAME, MX etc }; diff -Nru pdns-recursor-5.2.13/config.h.in pdns-recursor-5.4.9/config.h.in --- pdns-recursor-5.2.13/config.h.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/config.h.in 2026-10-26 09:47:08.545204200 +0000 @@ -3,16 +3,16 @@ /* Set to the user and host that builds PowerDNS */ #undef BUILD_HOST -/* Define to 1 if you have the `accept4' function. */ +/* Define to 1 if you have the 'accept4' function. */ #undef HAVE_ACCEPT4 -/* Define to 1 if you have the `arc4random' function. */ +/* Define to 1 if you have the 'arc4random' function. */ #undef HAVE_ARC4RANDOM -/* Define to 1 if you have the `arc4random_buf' function. */ +/* Define to 1 if you have the 'arc4random_buf' function. */ #undef HAVE_ARC4RANDOM_BUF -/* Define to 1 if you have the `arc4random_uniform' function. */ +/* Define to 1 if you have the 'arc4random_uniform' function. */ #undef HAVE_ARC4RANDOM_UNIFORM /* Defined if the requested minimum BOOST version is satisfied */ @@ -57,43 +57,43 @@ /* Define to 1 if you have clock_gettime */ #undef HAVE_CLOCK_GETTIME -/* Define to 1 if you have the `crypto_box_curve25519xchacha20poly1305_easy' +/* Define to 1 if you have the 'crypto_box_curve25519xchacha20poly1305_easy' function. */ #undef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY -/* Define to 1 if you have the `crypto_box_easy_afternm' function. */ +/* Define to 1 if you have the 'crypto_box_easy_afternm' function. */ #undef HAVE_CRYPTO_BOX_EASY_AFTERNM -/* Define to 1 if you have the `CRYPTO_memcmp' function. */ +/* Define to 1 if you have the 'CRYPTO_memcmp' function. */ #undef HAVE_CRYPTO_MEMCMP -/* Define to 1 if you have the `crypto_shorthash' function. */ +/* Define to 1 if you have the 'crypto_shorthash' function. */ #undef HAVE_CRYPTO_SHORTHASH /* define if the compiler supports basic C++17 syntax */ #undef HAVE_CXX17 -/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you +/* Define to 1 if you have the declaration of 'NID_ED25519', and to 0 if you don't. */ #undef HAVE_DECL_NID_ED25519 -/* Define to 1 if you have the declaration of `NID_ED448', and to 0 if you +/* Define to 1 if you have the declaration of 'NID_ED448', and to 0 if you don't. */ #undef HAVE_DECL_NID_ED448 -/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you +/* Define to 1 if you have the declaration of 'NID_secp384r1', and to 0 if you don't. */ #undef HAVE_DECL_NID_SECP384R1 -/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0 +/* Define to 1 if you have the declaration of 'NID_X9_62_prime256v1', and to 0 if you don't. */ #undef HAVE_DECL_NID_X9_62_PRIME256V1 -/* Define to 1 if you have the declaration of `snmp_select_info2', and to 0 if +/* Define to 1 if you have the declaration of 'snmp_select_info2', and to 0 if you don't. */ #undef HAVE_DECL_SNMP_SELECT_INFO2 -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you +/* Define to 1 if you have the declaration of 'strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R @@ -103,19 +103,19 @@ /* Define to 1 if you enable DNS over TLS support */ #undef HAVE_DNS_OVER_TLS -/* Define to 1 if you have the `EVP_MD_CTX_free' function. */ +/* Define to 1 if you have the 'EVP_MD_CTX_free' function. */ #undef HAVE_EVP_MD_CTX_FREE -/* Define to 1 if you have the `EVP_MD_CTX_new' function. */ +/* Define to 1 if you have the 'EVP_MD_CTX_new' function. */ #undef HAVE_EVP_MD_CTX_NEW /* Define to 1 if you have EVP_PKEY_CTX_set1_scrypt_salt */ #undef HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT -/* Define to 1 if you have the `explicit_bzero' function. */ +/* Define to 1 if you have the 'explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO -/* Define to 1 if you have the `explicit_memset' function. */ +/* Define to 1 if you have the 'explicit_memset' function. */ #undef HAVE_EXPLICIT_MEMSET /* Define if ASAN fiber annotation interface is available. */ @@ -124,19 +124,19 @@ /* Define to 1 if you have libfstrm */ #undef HAVE_FSTRM -/* Define to 1 if you have the `fstrm_tcp_writer_init' function. */ +/* Define to 1 if you have the 'fstrm_tcp_writer_init' function. */ #undef HAVE_FSTRM_TCP_WRITER_INIT -/* Define to 1 if you have the `getentropy' function. */ +/* Define to 1 if you have the 'getentropy' function. */ #undef HAVE_GETENTROPY /* Define to 1 if you have getifaddrs */ #undef HAVE_GETIFADDRS -/* Define to 1 if you have the `getrandom' function. */ +/* Define to 1 if you have the 'getrandom' function. */ #undef HAVE_GETRANDOM -/* Define to 1 if you have the `gmtime_r' function. */ +/* Define to 1 if you have the 'gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the header file. */ @@ -172,13 +172,13 @@ /* Define to 1 if you have OpenSSL libssl */ #undef HAVE_LIBSSL -/* Define to 1 if you have the `localtime_r' function. */ +/* Define to 1 if you have the 'localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have lua */ #undef HAVE_LUA -/* Define to 1 if you have the `memset_s' function. */ +/* Define to 1 if you have the 'memset_s' function. */ #undef HAVE_MEMSET_S /* Define to 1 if you have the header file. */ @@ -187,10 +187,10 @@ /* Define if using Net SNMP. */ #undef HAVE_NET_SNMP -/* Define to 1 if you have the `OCSP_basic_sign' function. */ +/* Define to 1 if you have the 'OCSP_basic_sign' function. */ #undef HAVE_OCSP_BASIC_SIGN -/* Define to 1 if you have the `OPENSSL_init_crypto' function. */ +/* Define to 1 if you have the 'OPENSSL_init_crypto' function. */ #undef HAVE_OPENSSL_INIT_CRYPTO /* Define to 1 if you have pthread_getattr_np */ @@ -223,19 +223,19 @@ /* 2-arg void pthread_set_name_np */ #undef HAVE_PTHREAD_SET_NAME_NP_2_VOID -/* Define to 1 if you have the `randombytes_stir' function. */ +/* Define to 1 if you have the 'randombytes_stir' function. */ #undef HAVE_RANDOMBYTES_STIR -/* Define to 1 if you have the `RAND_bytes' function. */ +/* Define to 1 if you have the 'RAND_bytes' function. */ #undef HAVE_RAND_BYTES -/* Define to 1 if you have the `RAND_pseudo_bytes' function. */ +/* Define to 1 if you have the 'RAND_pseudo_bytes' function. */ #undef HAVE_RAND_PSEUDO_BYTES -/* Define to 1 if you have the `recvmmsg' function. */ +/* Define to 1 if you have the 'recvmmsg' function. */ #undef HAVE_RECVMMSG -/* Define to 1 if you have the `RSA_get0_key' function. */ +/* Define to 1 if you have the 'RSA_get0_key' function. */ #undef HAVE_RSA_GET0_KEY /* Define to 1 if you have the header @@ -251,49 +251,49 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SANITIZER_LSAN_INTERFACE_H -/* Define to 1 if you have the `sendmmsg' function. */ +/* Define to 1 if you have the 'sendmmsg' function. */ #undef HAVE_SENDMMSG /* define to 1 if snmp_select_info2 is available. */ #undef HAVE_SNMP_SELECT_INFO2 -/* Define to 1 if you have the `sodium_memcmp' function. */ +/* Define to 1 if you have the 'sodium_memcmp' function. */ #undef HAVE_SODIUM_MEMCMP -/* Define to 1 if you have the `SSL_CTX_get0_privatekey' function. */ +/* Define to 1 if you have the 'SSL_CTX_get0_privatekey' function. */ #undef HAVE_SSL_CTX_GET0_PRIVATEKEY -/* Define to 1 if you have the `SSL_CTX_set_alpn_protos' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_alpn_protos' function. */ #undef HAVE_SSL_CTX_SET_ALPN_PROTOS -/* Define to 1 if you have the `SSL_CTX_set_alpn_select_cb' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_alpn_select_cb' function. */ #undef HAVE_SSL_CTX_SET_ALPN_SELECT_CB -/* Define to 1 if you have the `SSL_CTX_set_ciphersuites' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_ciphersuites' function. */ #undef HAVE_SSL_CTX_SET_CIPHERSUITES -/* Define to 1 if you have the `SSL_CTX_set_keylog_callback' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_keylog_callback' function. */ #undef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK -/* Define to 1 if you have the `SSL_CTX_set_min_proto_version' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_min_proto_version' function. */ #undef HAVE_SSL_CTX_SET_MIN_PROTO_VERSION -/* Define to 1 if you have the `SSL_CTX_set_next_proto_select_cb' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_next_proto_select_cb' function. */ #undef HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB -/* Define to 1 if you have the `SSL_CTX_set_num_tickets' function. */ +/* Define to 1 if you have the 'SSL_CTX_set_num_tickets' function. */ #undef HAVE_SSL_CTX_SET_NUM_TICKETS -/* Define to 1 if you have the `SSL_CTX_use_cert_and_key' function. */ +/* Define to 1 if you have the 'SSL_CTX_use_cert_and_key' function. */ #undef HAVE_SSL_CTX_USE_CERT_AND_KEY -/* Define to 1 if you have the `SSL_get0_alpn_selected' function. */ +/* Define to 1 if you have the 'SSL_get0_alpn_selected' function. */ #undef HAVE_SSL_GET0_ALPN_SELECTED -/* Define to 1 if you have the `SSL_get0_next_proto_negotiated' function. */ +/* Define to 1 if you have the 'SSL_get0_next_proto_negotiated' function. */ #undef HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED -/* Define to 1 if you have the `SSL_set_hostflags' function. */ +/* Define to 1 if you have the 'SSL_set_hostflags' function. */ #undef HAVE_SSL_SET_HOSTFLAGS /* Define to 1 if you have the header file. */ @@ -305,10 +305,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the `strcasestr' function. */ -#undef HAVE_STRCASESTR - -/* Define if you have `strerror_r'. */ +/* Define if you have 'strerror_r'. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ @@ -443,16 +440,13 @@ /* Define if using Valgrind. */ #undef PDNS_USE_VALGRIND -/* This is the PowerDNS Recursor */ -#undef RECURSOR - /* Define to 1 for reproducible builds */ #undef REPRODUCIBLE /* The number of bytes in type time_t */ #undef SIZEOF_TIME_T -/* Define to 1 if all of the C90 standard headers exist (not just the ones +/* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS @@ -460,7 +454,7 @@ /* Define to 1 if strerror_r returns char *. */ #undef STRERROR_R_CHAR_P -/* Enable extensions on AIX 3, Interix. */ +/* Enable extensions on AIX, Interix, z/OS. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif @@ -521,11 +515,15 @@ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# undef __STDC_WANT_IEC_60559_EXT__ +#endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif -/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif diff -Nru pdns-recursor-5.2.13/configure pdns-recursor-5.4.9/configure --- pdns-recursor-5.2.13/configure 2026-08-05 12:01:44.000000000 +0000 +++ pdns-recursor-5.4.9/configure 2026-10-26 09:47:08.032277300 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for pdns-recursor 5.2.13. +# Generated by GNU Autoconf 2.72 for pdns-recursor 5.4.9. # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # @@ -15,7 +15,6 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -24,12 +23,13 @@ # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -101,7 +101,7 @@ ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -131,15 +131,14 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: @@ -147,12 +146,13 @@ # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi " @@ -170,8 +170,9 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else \$as_nop - exitcode=1; echo positional parameters were not saved. +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -193,14 +194,15 @@ if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else $as_nop - as_have_required=no +else case e in #( + e) as_have_required=no ;; +esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -233,12 +235,13 @@ if $as_found then : -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi +fi ;; +esac fi @@ -260,7 +263,7 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi @@ -279,7 +282,8 @@ $0: the script under such a shell if you do have one." fi exit 1 -fi +fi ;; +esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -318,14 +322,6 @@ as_fn_set_status $1 exit $1 } # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -394,11 +390,12 @@ { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -412,21 +409,14 @@ { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -500,6 +490,8 @@ /[$]LINENO/= ' <$as_myself | sed ' + t clear + :clear s/[$]LINENO.*/&-/ t lineno b @@ -548,7 +540,6 @@ as_echo='printf %s\n' as_echo_n='printf %s' - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -560,9 +551,9 @@ if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -587,10 +578,12 @@ as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated SHELL=${CONFIG_SHELL-/bin/sh} @@ -618,8 +611,8 @@ # Identity of this package. PACKAGE_NAME='pdns-recursor' PACKAGE_TARNAME='pdns-recursor' -PACKAGE_VERSION='5.2.13' -PACKAGE_STRING='pdns-recursor 5.2.13' +PACKAGE_VERSION='5.4.9' +PACKAGE_STRING='pdns-recursor 5.4.9' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -851,12 +844,12 @@ DUMPBIN LD FGREP +EGREP +GREP LIBTOOL CARGO SED HAVE_CXX17 -EGREP -GREP CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE @@ -889,6 +882,8 @@ LDFLAGS CFLAGS CC +am__xargs_n +am__rm_f_notfound AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V @@ -1148,7 +1143,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1174,7 +1169,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1387,7 +1382,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1403,7 +1398,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1433,8 +1428,8 @@ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" ;; *=*) @@ -1442,7 +1437,7 @@ # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1492,7 +1487,7 @@ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: `$host' +# There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -1560,7 +1555,7 @@ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1588,7 +1583,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pdns-recursor 5.2.13 to adapt to many kinds of systems. +'configure' configures pdns-recursor 5.4.9 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1602,11 +1597,11 @@ --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' + -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] + --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -1614,10 +1609,10 @@ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. +By default, 'make install' will install all the files in +'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify +an installation prefix other than '$ac_default_prefix' using '--prefix', +for instance '--prefix=\$HOME'. For better control, use the options below. @@ -1659,7 +1654,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pdns-recursor 5.2.13:";; + short | recursive ) echo "Configuration of pdns-recursor 5.4.9:";; esac cat <<\_ACEOF @@ -1792,7 +1787,7 @@ linker flags for SYSTEMD, overriding pkg-config PYTHON the Python interpreter -Use these variables to override the choices made by `configure' or to help +Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. @@ -1859,10 +1854,10 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pdns-recursor configure 5.2.13 -generated by GNU Autoconf 2.71 +pdns-recursor configure 5.4.9 +generated by GNU Autoconf 2.72 -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1901,11 +1896,12 @@ } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1924,8 +1920,8 @@ if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -1933,10 +1929,12 @@ if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -1973,11 +1971,12 @@ } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -2011,11 +2010,12 @@ } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -2053,11 +2053,12 @@ } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -2080,15 +2081,15 @@ if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. */ + which can conflict with char $2 (void); below. */ #include #undef $2 @@ -2099,7 +2100,7 @@ #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -2118,11 +2119,13 @@ if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2162,11 +2165,12 @@ } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -2189,15 +2193,15 @@ if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. */ + which can conflict with char $2 (void); below. */ #include #undef $2 @@ -2208,7 +2212,7 @@ #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -2227,11 +2231,13 @@ if ac_fn_cxx_try_link "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2253,8 +2259,8 @@ if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` +else case e in #( + e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2278,12 +2284,14 @@ if ac_fn_cxx_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS - + ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2304,8 +2312,8 @@ if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -2313,10 +2321,12 @@ if ac_fn_cxx_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -2348,8 +2358,8 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pdns-recursor $as_me 5.2.13, which was -generated by GNU Autoconf 2.71. Invocation command line was +It was created by pdns-recursor $as_me 5.4.9, which was +generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -2595,10 +2605,10 @@ printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi done @@ -2635,9 +2645,7 @@ /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -2651,6 +2659,21 @@ return s; } +/* C89 style stringification. */ +#define noexpand_stringify(a) #a +const char *stringified = noexpand_stringify(arbitrary+token=sequence); + +/* C89 style token pasting. Exercises some of the corner cases that + e.g. old MSVC gets wrong, but not very hard. */ +#define noexpand_concat(a,b) a##b +#define expand_concat(a,b) noexpand_concat(a,b) +extern int vA; +extern int vbee; +#define aye A +#define bee B +int *pvA = &expand_concat(v,aye); +int *pvbee = &noexpand_concat(v,bee); + /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated @@ -2678,16 +2701,19 @@ # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? +/* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif +// See if C++-style comments work. + #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); +extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare @@ -2737,7 +2763,6 @@ static inline int test_restrict (ccp restrict text) { - // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) @@ -2803,6 +2828,8 @@ ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; + // Work around memory leak warnings. + free (ia); // Check named initializers. struct named_init ni = { @@ -2824,7 +2851,7 @@ # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? +/* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif @@ -3156,7 +3183,6 @@ as_fn_append ac_func_cxx_list " localtime_r HAVE_LOCALTIME_R" as_fn_append ac_func_cxx_list " gmtime_r HAVE_GMTIME_R" -as_fn_append ac_func_cxx_list " strcasestr HAVE_STRCASESTR" as_fn_append ac_func_cxx_list " getrandom HAVE_GETRANDOM" as_fn_append ac_func_cxx_list " getentropy HAVE_GETENTROPY" as_fn_append ac_func_cxx_list " arc4random HAVE_ARC4RANDOM" @@ -3241,8 +3267,9 @@ if $as_found then : -else $as_nop - as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; +esac fi @@ -3270,12 +3297,12 @@ eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -3284,18 +3311,18 @@ ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. @@ -3311,11 +3338,11 @@ fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## @@ -3330,7 +3357,7 @@ -am__api_version='1.16' +am__api_version='1.17' @@ -3354,8 +3381,8 @@ if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS @@ -3409,7 +3436,8 @@ IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir - + ;; +esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install @@ -3432,6 +3460,165 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 +printf %s "checking whether sleep supports fractional seconds... " >&6; } +if test ${am_cv_sleep_fractional_seconds+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if sleep 0.001 2>/dev/null +then : + am_cv_sleep_fractional_seconds=yes +else case e in #( + e) am_cv_sleep_fractional_seconds=no ;; +esac +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 +printf "%s\n" "$am_cv_sleep_fractional_seconds" >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 +printf %s "checking filesystem timestamp resolution... " >&6; } +if test ${am_cv_filesystem_timestamp_resolution+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) # Default to the worst case. +am_cv_filesystem_timestamp_resolution=2 + +# Only try to go finer than 1 sec if sleep can do it. +# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, +# - 1 sec is not much of a win compared to 2 sec, and +# - it takes 2 seconds to perform the test whether 1 sec works. +# +# Instead, just use the default 2s on platforms that have 1s resolution, +# accept the extra 1s delay when using $sleep in the Automake tests, in +# exchange for not incurring the 2s delay for running the test for all +# packages. +# +am_try_resolutions= +if test "$am_cv_sleep_fractional_seconds" = yes; then + # Even a millisecond often causes a bunch of false positives, + # so just try a hundredth of a second. The time saved between .001 and + # .01 is not terribly consequential. + am_try_resolutions="0.01 0.1 $am_try_resolutions" +fi + +# In order to catch current-generation FAT out, we must *modify* files +# that already exist; the *creation* timestamp is finer. Use names +# that make ls -t sort them differently when they have equal +# timestamps than when they have distinct timestamps, keeping +# in mind that ls -t prints the *newest* file first. +rm -f conftest.ts? +: > conftest.ts1 +: > conftest.ts2 +: > conftest.ts3 + +# Make sure ls -t actually works. Do 'set' in a subshell so we don't +# clobber the current shell's arguments. (Outer-level square brackets +# are removed by m4; they're present so that m4 does not expand +# ; be careful, easy to get confused.) +if ( + set X `ls -t conftest.ts[12]` && + { + test "$*" != "X conftest.ts1 conftest.ts2" || + test "$*" != "X conftest.ts2 conftest.ts1"; + } +); then :; else + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + printf "%s\n" ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "ls -t produces unexpected output. +Make sure there is not a broken ls alias in your environment. +See 'config.log' for more details" "$LINENO" 5; } +fi + +for am_try_res in $am_try_resolutions; do + # Any one fine-grained sleep might happen to cross the boundary + # between two values of a coarser actual resolution, but if we do + # two fine-grained sleeps in a row, at least one of them will fall + # entirely within a coarse interval. + echo alpha > conftest.ts1 + sleep $am_try_res + echo beta > conftest.ts2 + sleep $am_try_res + echo gamma > conftest.ts3 + + # We assume that 'ls -t' will make use of high-resolution + # timestamps if the operating system supports them at all. + if (set X `ls -t conftest.ts?` && + test "$2" = conftest.ts3 && + test "$3" = conftest.ts2 && + test "$4" = conftest.ts1); then + # + # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, + # because we don't need to test make. + make_ok=true + if test $am_try_res != 1; then + # But if we've succeeded so far with a subsecond resolution, we + # have one more thing to check: make. It can happen that + # everything else supports the subsecond mtimes, but make doesn't; + # notably on macOS, which ships make 3.81 from 2006 (the last one + # released under GPLv2). https://bugs.gnu.org/68808 + # + # We test $MAKE if it is defined in the environment, else "make". + # It might get overridden later, but our hope is that in practice + # it does not matter: it is the system "make" which is (by far) + # the most likely to be broken, whereas if the user overrides it, + # probably they did so with a better, or at least not worse, make. + # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html + # + # Create a Makefile (real tab character here): + rm -f conftest.mk + echo 'conftest.ts1: conftest.ts2' >conftest.mk + echo ' touch conftest.ts2' >>conftest.mk + # + # Now, running + # touch conftest.ts1; touch conftest.ts2; make + # should touch ts1 because ts2 is newer. This could happen by luck, + # but most often, it will fail if make's support is insufficient. So + # test for several consecutive successes. + # + # (We reuse conftest.ts[12] because we still want to modify existing + # files, not create new ones, per above.) + n=0 + make=${MAKE-make} + until test $n -eq 3; do + echo one > conftest.ts1 + sleep $am_try_res + echo two > conftest.ts2 # ts2 should now be newer than ts1 + if $make -f conftest.mk | grep 'up to date' >/dev/null; then + make_ok=false + break # out of $n loop + fi + n=`expr $n + 1` + done + fi + # + if $make_ok; then + # Everything we know to check worked out, so call this resolution good. + am_cv_filesystem_timestamp_resolution=$am_try_res + break # out of $am_try_res loop + fi + # Otherwise, we'll go on to check the next resolution. + fi +done +rm -f conftest.ts? +# (end _am_filesystem_timestamp_resolution) + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 +printf "%s\n" "$am_cv_filesystem_timestamp_resolution" >&6; } + +# This check should not be cached, as it may vary across builds of +# different projects. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory @@ -3452,49 +3639,45 @@ # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then +am_build_env_is_sane=no +am_has_slept=no +rm -f conftest.file +for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + test "$2" = conftest.file + ); then + am_build_env_is_sane=yes + break + fi + # Just in case. + sleep "$am_cv_filesystem_timestamp_resolution" + am_has_slept=yes +done - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - as_fn_error $? "ls -t appears to fail. Make sure there is not a broken - alias in your environment" "$LINENO" 5 - fi - if test "$2" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$2" = conftest.file - ) -then - # Ok. - : -else - as_fn_error $? "newly created file is older than distributed files! +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 +printf "%s\n" "$am_build_env_is_sane" >&6; } +if test "$am_build_env_is_sane" = no; then + as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } + # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & +if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 +then : + +else case e in #( + e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! + ;; +esac fi rm -f conftest.file @@ -3505,7 +3688,7 @@ test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. -# By default was `s,x,x', remove it if useless. +# By default was 's,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` @@ -3548,8 +3731,8 @@ if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$STRIP"; then +else case e in #( + e) if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3571,7 +3754,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then @@ -3593,8 +3777,8 @@ if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_STRIP"; then +else case e in #( + e) if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3616,7 +3800,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then @@ -3652,8 +3837,8 @@ if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS @@ -3667,7 +3852,7 @@ as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ - 'BusyBox '* | \ + *'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; @@ -3676,18 +3861,17 @@ done done IFS=$as_save_IFS - + ;; +esac fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" + # As a last resort, use plain mkdir -p, + # in the hope it doesn't have the bugs of ancient mkdir. + MKDIR_P='mkdir -p' fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 @@ -3702,8 +3886,8 @@ if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AWK"; then +else case e in #( + e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -3725,7 +3909,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then @@ -3747,8 +3932,8 @@ if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 -else $as_nop - cat >conftest.make <<\_ACEOF +else case e in #( + e) cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' @@ -3760,7 +3945,8 @@ *) eval ac_cv_prog_make_${ac_make}_set=no;; esac -rm -f conftest.make +rm -f conftest.make ;; +esac fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 @@ -3781,25 +3967,21 @@ fi rmdir .tst 2>/dev/null +AM_DEFAULT_VERBOSITY=1 # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=1;; -esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 -else $as_nop - if printf "%s\n" 'TRUE=$(BAR$(V)) +else case e in #( + e) if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 @@ -3809,19 +3991,50 @@ am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no -fi +fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi AM_BACKSLASH='\' +am__rm_f_notfound= +if (rm -f && rm -fr && rm -rf) 2>/dev/null +then : + +else case e in #( + e) am__rm_f_notfound='""' ;; +esac +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 +printf %s "checking xargs -n works... " >&6; } +if test ${am_cv_xargs_n_works+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 +3" +then : + am_cv_xargs_n_works=yes +else case e in #( + e) am_cv_xargs_n_works=no ;; +esac +fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 +printf "%s\n" "$am_cv_xargs_n_works" >&6; } +if test "$am_cv_xargs_n_works" = yes +then : + am__xargs_n='xargs -n' +else case e in #( + e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' + ;; +esac +fi + if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." @@ -3844,7 +4057,7 @@ # Define the identity of the package. PACKAGE='pdns-recursor' - VERSION='5.2.13' + VERSION='5.4.9' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -3898,18 +4111,24 @@ am_gid=`id -g || echo unknown` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } - if test $am_uid -le $am_max_uid; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + if test x$am_uid = xunknown; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&5 +printf "%s\n" "$as_me: WARNING: ancient id detected; assuming current UID is ok, but dist-ustar might not work" >&2;} + elif test $am_uid -le $am_max_uid; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - _am_tools=none + _am_tools=none fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } - if test $am_gid -le $am_max_gid; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + if test x$gm_gid = xunknown; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&5 +printf "%s\n" "$as_me: WARNING: ancient id detected; assuming current GID is ok, but dist-ustar might not work" >&2;} + elif test $am_gid -le $am_max_gid; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 @@ -3996,8 +4215,9 @@ if test ${am_cv_prog_tar_ustar+y} then : printf %s "(cached) " >&6 -else $as_nop - am_cv_prog_tar_ustar=$_am_tool +else case e in #( + e) am_cv_prog_tar_ustar=$_am_tool ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 @@ -4022,89 +4242,12 @@ -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. -END - as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 - fi -fi -# Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=0;; -esac -am_make=${MAKE-make} -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -printf %s "checking whether $am_make supports nested variables... " >&6; } -if test ${am_cv_make_support_nested_variables+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if printf "%s\n" 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AM_BACKSLASH='\' +AM_DEFAULT_VERBOSITY=0 @@ -4194,8 +4337,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4217,7 +4360,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -4239,8 +4383,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4262,7 +4406,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -4297,8 +4442,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4320,7 +4465,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -4342,8 +4488,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -4382,7 +4528,8 @@ ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -4406,8 +4553,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4429,7 +4576,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -4455,8 +4603,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4478,7 +4626,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -4516,8 +4665,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4539,7 +4688,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -4561,8 +4711,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -4584,7 +4734,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -4613,10 +4764,10 @@ fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -4688,8 +4839,8 @@ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. +# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -4709,7 +4860,7 @@ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' + # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -4720,8 +4871,9 @@ done test "$ac_cv_exeext" = no && ac_cv_exeext= -else $as_nop - ac_file='' +else case e in #( + e) ac_file='' ;; +esac fi if test -z "$ac_file" then : @@ -4730,13 +4882,14 @@ printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } @@ -4760,10 +4913,10 @@ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. + # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) +# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will +# work properly (i.e., refer to 'conftest.exe'), while it won't with +# 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -4773,11 +4926,12 @@ * ) break;; esac done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -4793,6 +4947,8 @@ main (void) { FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; return ferror (f) || fclose (f) != 0; ; @@ -4832,26 +4988,27 @@ if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -4883,16 +5040,18 @@ break;; esac done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } @@ -4903,8 +5062,8 @@ if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -4921,12 +5080,14 @@ if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -4944,8 +5105,8 @@ if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -4963,8 +5124,8 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" +else case e in #( + e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4979,8 +5140,8 @@ if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4997,12 +5158,15 @@ then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -5029,8 +5193,8 @@ if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no +else case e in #( + e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5047,25 +5211,28 @@ test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" + CC="$CC $ac_cv_prog_cc_c11" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 + ac_prog_cc_stdc=c11 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -5075,8 +5242,8 @@ if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no +else case e in #( + e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5093,25 +5260,28 @@ test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" + CC="$CC $ac_cv_prog_cc_c99" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 + ac_prog_cc_stdc=c99 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -5121,8 +5291,8 @@ if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no +else case e in #( + e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5139,25 +5309,28 @@ test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" + CC="$CC $ac_cv_prog_cc_c89" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 + ac_prog_cc_stdc=c89 ;; +esac fi fi @@ -5178,8 +5351,8 @@ if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -5209,7 +5382,8 @@ fi done rm -f core conftest* - unset am_i + unset am_i ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } @@ -5235,8 +5409,8 @@ if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up @@ -5323,7 +5497,7 @@ # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: + # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported @@ -5340,7 +5514,8 @@ else am_cv_CC_dependencies_compiler_type=none fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } @@ -5398,8 +5573,8 @@ if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 @@ -5415,10 +5590,12 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes -else $as_nop - ac_cv_safe_to_define___extensions__=no +else case e in #( + e) ac_cv_safe_to_define___extensions__=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } @@ -5428,8 +5605,8 @@ if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_should_define__xopen_source=no +else case e in #( + e) ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5448,8 +5625,8 @@ if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 @@ -5467,10 +5644,12 @@ then : ac_cv_should_define__xopen_source=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi +fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } @@ -5495,6 +5674,8 @@ printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h @@ -5514,8 +5695,9 @@ printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h -else $as_nop - MINIX= +else case e in #( + e) MINIX= ;; +esac fi if test $ac_cv_safe_to_define___extensions__ = yes then : @@ -5542,15 +5724,16 @@ if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_build_alias=$build_alias +else case e in #( + e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } @@ -5577,14 +5760,15 @@ if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "x$host_alias" = x; then +else case e in #( + e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } @@ -5629,8 +5813,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5652,7 +5836,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5674,8 +5859,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5697,7 +5882,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -5732,8 +5918,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5755,7 +5941,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5777,8 +5964,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -5817,7 +6004,8 @@ ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5841,8 +6029,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5864,7 +6052,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5890,8 +6079,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5913,7 +6102,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -5951,8 +6141,8 @@ if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5974,7 +6164,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then @@ -5996,8 +6187,8 @@ if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -6019,7 +6210,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then @@ -6048,10 +6240,10 @@ fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -6083,8 +6275,8 @@ if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6101,12 +6293,14 @@ if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } @@ -6124,8 +6318,8 @@ if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -6143,8 +6337,8 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" +else case e in #( + e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6159,8 +6353,8 @@ if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6177,12 +6371,15 @@ then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } @@ -6209,8 +6406,8 @@ if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no +else case e in #( + e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6227,25 +6424,28 @@ test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" + CC="$CC $ac_cv_prog_cc_c11" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 + ac_prog_cc_stdc=c11 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -6255,8 +6455,8 @@ if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no +else case e in #( + e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6273,25 +6473,28 @@ test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" + CC="$CC $ac_cv_prog_cc_c99" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 + ac_prog_cc_stdc=c99 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno @@ -6301,8 +6504,8 @@ if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no +else case e in #( + e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6319,25 +6522,28 @@ test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" + CC="$CC $ac_cv_prog_cc_c89" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 + ac_prog_cc_stdc=c89 ;; +esac fi fi @@ -6358,8 +6564,8 @@ if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6389,7 +6595,8 @@ fi done rm -f core conftest* - unset am_i + unset am_i ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } @@ -6415,8 +6622,8 @@ if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up @@ -6503,7 +6710,7 @@ # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: + # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported @@ -6520,7 +6727,8 @@ else am_cv_CC_dependencies_compiler_type=none fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } @@ -6562,8 +6770,8 @@ if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then +else case e in #( + e) if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -6585,7 +6793,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then @@ -6611,8 +6820,8 @@ if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then +else case e in #( + e) if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -6634,7 +6843,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then @@ -6694,8 +6904,8 @@ if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6712,12 +6922,14 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } @@ -6735,8 +6947,8 @@ if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag +else case e in #( + e) ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" @@ -6754,8 +6966,8 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" +else case e in #( + e) CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6770,8 +6982,8 @@ if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag +else case e in #( + e) ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6788,12 +7000,15 @@ then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag + ac_cxx_werror_flag=$ac_save_cxx_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } @@ -6817,11 +7032,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_11=no +else case e in #( + e) ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6838,36 +7053,39 @@ test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" + CXX="$CXX $ac_cv_prog_cxx_cxx11" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 + ac_prog_cxx_stdcxx=cxx11 ;; +esac fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_98=no +else case e in #( + e) ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6884,25 +7102,28 @@ test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" + CXX="$CXX $ac_cv_prog_cxx_cxx98" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 + ac_prog_cxx_stdcxx=cxx98 ;; +esac fi fi @@ -6919,8 +7140,8 @@ if test ${am_cv_CXX_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up @@ -7007,7 +7228,7 @@ # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: + # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported @@ -7024,7 +7245,8 @@ else am_cv_CXX_dependencies_compiler_type=none fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } @@ -7060,8 +7282,8 @@ if test ${ac_cv_prog_CXXCPP+y} then : printf %s "(cached) " >&6 -else $as_nop - # Double quotes because $CXX needs to be expanded +else case e in #( + e) # Double quotes because $CXX needs to be expanded for CXXCPP in "$CXX -E" cpp /lib/cpp do ac_preproc_ok=false @@ -7079,9 +7301,10 @@ if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -7095,15 +7318,16 @@ then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : @@ -7112,7 +7336,8 @@ done ac_cv_prog_CXXCPP=$CXXCPP - + ;; +esac fi CXXCPP=$ac_cv_prog_CXXCPP else @@ -7135,9 +7360,10 @@ if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -7151,24 +7377,26 @@ then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi ac_ext=cpp @@ -7178,14 +7406,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5 +printf %s "checking for egrep -e... " >&6; } +if test ${ac_cv_path_EGREP_TRADITIONAL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then - ac_path_GREP_found=false +else case e in #( + e) if test -z "$EGREP_TRADITIONAL"; then + ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin @@ -7199,13 +7427,14 @@ for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in + ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue +# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. + # Check for GNU $ac_path_EGREP_TRADITIONAL +case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -7214,14 +7443,14 @@ cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - printf "%s\n" 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" + "$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then + if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" + ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break @@ -7229,35 +7458,24 @@ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - $ac_path_GREP_found && break 3 + $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then + : fi else - ac_cv_path_GREP=$GREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf "%s\n" "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} + if test "$ac_cv_path_EGREP_TRADITIONAL" then : - printf %s "(cached) " >&6 -else $as_nop - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false + ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E" +else case e in #( + e) if test -z "$EGREP_TRADITIONAL"; then + ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin @@ -7271,13 +7489,14 @@ for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in + ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue +# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. + # Check for GNU $ac_path_EGREP_TRADITIONAL +case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -7286,14 +7505,14 @@ cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl" + "$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then + if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" + ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break @@ -7301,33 +7520,35 @@ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - $ac_path_EGREP_found && break 3 + $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then + if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else - ac_cv_path_EGREP=$EGREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi - - fi + ;; +esac +fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5 +printf "%s\n" "$ac_cv_path_EGREP_TRADITIONAL" >&6; } + EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL # Check whether --enable-experimental_64bit_time_t_support_on_glibc was given. if test ${enable_experimental_64bit_time_t_support_on_glibc+y} then : enableval=$enable_experimental_64bit_time_t_support_on_glibc; enable_experimental_64bit_time_t_support_on_glibc=$enableval -else $as_nop - enable_experimental_64bit_time_t_support_on_glibc=no - +else case e in #( + e) enable_experimental_64bit_time_t_support_on_glibc=no + ;; +esac fi if test "x$enable_experimental_64bit_time_t_support_on_glibc" != "xno" @@ -7343,7 +7564,7 @@ _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : CFLAGS="${CFLAGS} -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64" @@ -7359,8 +7580,8 @@ if test ${ac_cv_sizeof_time_t+y} then : printf %s "(cached) " >&6 -else $as_nop - for ac_size in 4 8 1 2 16 ; do # List sizes in rough order of prevalence. +else case e in #( + e) for ac_size in 4 8 1 2 16 ; do # List sizes in rough order of prevalence. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7382,7 +7603,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test x$ac_cv_sizeof_time_t != x ; then break; fi done - + ;; +esac fi if test x$ac_cv_sizeof_time_t = x ; then @@ -7405,8 +7627,8 @@ if eval test \${ax_cv_decl_${typename}_signed+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7423,11 +7645,13 @@ if ac_fn_cxx_try_compile "$LINENO" then : eval "ax_cv_decl_${typename}_signed=\"yes\"" -else $as_nop - eval "ax_cv_decl_${typename}_signed=\"no\"" +else case e in #( + e) eval "ax_cv_decl_${typename}_signed=\"no\"" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi eval ac_res=\$ax_cv_decl_${typename}_signed { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -7441,9 +7665,7 @@ - -printf "%s\n" "#define RECURSOR 1" >>confdefs.h - +CPPFLAGS="-DRECURSOR $CPPFLAGS" # Warn when pkg.m4 is missing @@ -7458,17 +7680,24 @@ + + if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh` + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do + if test x"$switch" = xMSVC; then + switch=-std:c++${alternative} + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_${switch}_MSVC" | sed "$as_sed_sh"` + else + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_$switch" | sed "$as_sed_sh"` + fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5 printf %s "checking whether $CXX supports C++17 features with $switch... " >&6; } if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_CXX="$CXX" +else case e in #( + e) ac_save_CXX="$CXX" CXX="$CXX $switch" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7481,7 +7710,11 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" @@ -7768,7 +8001,7 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201402L +#elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" @@ -7888,7 +8121,7 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201703L +#elif __cplusplus < 201703L && !defined _MSC_VER #error "This is not a C++17 compiler" @@ -7903,7 +8136,8 @@ namespace test_constexpr_lambdas { - [[maybe_unused]] constexpr int foo = [](){return 42;}(); + + constexpr int foo = [](){return 42;}(); } @@ -8253,7 +8487,7 @@ } // namespace cxx17 -#endif // __cplusplus < 201703L +#endif // __cplusplus < 201703L && !defined _MSC_VER @@ -8261,11 +8495,13 @@ if ac_fn_cxx_try_compile "$LINENO" then : eval $cachevar=yes -else $as_nop - eval $cachevar=no +else case e in #( + e) eval $cachevar=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CXX="$ac_save_CXX" + CXX="$ac_save_CXX" ;; +esac fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -8312,8 +8548,8 @@ if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ +else case e in #( + e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done @@ -8338,9 +8574,10 @@ as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in +case `"$ac_path_SED" --version 2>&1` in #( *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8375,7 +8612,8 @@ else ac_cv_path_SED=$SED fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } @@ -8392,8 +8630,8 @@ if test ${ac_cv_prog_CARGO+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CARGO"; then +else case e in #( + e) if test -n "$CARGO"; then ac_cv_prog_CARGO="$CARGO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8416,7 +8654,8 @@ IFS=$as_save_IFS test -z "$ac_cv_prog_CARGO" && ac_cv_prog_CARGO="$CARGO" -fi +fi ;; +esac fi CARGO=$ac_cv_prog_CARGO if test -n "$CARGO"; then @@ -8575,8 +8814,8 @@ if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ +else case e in #( + e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done @@ -8601,9 +8840,10 @@ as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in +case `"$ac_path_SED" --version 2>&1` in #( *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8638,7 +8878,8 @@ else ac_cv_path_SED=$SED fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } @@ -8658,13 +8899,161 @@ +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + EGREP_TRADITIONAL=$EGREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 -else $as_nop - if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 +else case e in #( + e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then @@ -8686,9 +9075,10 @@ as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in +case `"$ac_path_FGREP" --version 2>&1` in #( *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -8724,7 +9114,8 @@ ac_cv_path_FGREP=$FGREP fi - fi + fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$ac_cv_path_FGREP" >&6; } @@ -8755,8 +9146,9 @@ if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else $as_nop - with_gnu_ld=no +else case e in #( + e) with_gnu_ld=no ;; +esac fi ac_prog=ld @@ -8801,8 +9193,8 @@ if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$LD"; then +else case e in #( + e) if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs @@ -8825,7 +9217,8 @@ IFS=$lt_save_ifs else lt_cv_path_LD=$LD # Let the user override the test with a path. -fi +fi ;; +esac fi LD=$lt_cv_path_LD @@ -8842,8 +9235,8 @@ if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 -else $as_nop - # I'd rather use --version here, but apparently some GNU lds only accept -v. +else case e in #( + e) # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 @@ -8870,8 +9264,8 @@ if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$NM"; then +else case e in #( + e) if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else @@ -8918,7 +9312,8 @@ IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} -fi +fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } @@ -8939,8 +9334,8 @@ if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$DUMPBIN"; then +else case e in #( + e) if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8962,7 +9357,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then @@ -8988,8 +9384,8 @@ if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_DUMPBIN"; then +else case e in #( + e) if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9011,7 +9407,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then @@ -9065,8 +9462,8 @@ if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_nm_interface="BSD nm" +else case e in #( + e) lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) @@ -9079,7 +9476,8 @@ if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi - rm -f conftest* + rm -f conftest* ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } @@ -9101,8 +9499,8 @@ if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 -else $as_nop - i=0 +else case e in #( + e) i=0 teststring=ABCD case $build_os in @@ -9224,7 +9622,8 @@ fi ;; esac - + ;; +esac fi if test -n "$lt_cv_sys_max_cmd_len"; then @@ -9281,8 +9680,8 @@ if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 -else $as_nop - case $host in +else case e in #( + e) case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys @@ -9313,7 +9712,8 @@ lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac - + ;; +esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd @@ -9329,8 +9729,8 @@ if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 -else $as_nop - #assume ordinary cross tools, or native build. +else case e in #( + e) #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) @@ -9341,7 +9741,8 @@ esac ;; esac - + ;; +esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd @@ -9357,8 +9758,9 @@ if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_ld_reload_flag='-r' +else case e in #( + e) lt_cv_ld_reload_flag='-r' ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$lt_cv_ld_reload_flag" >&6; } @@ -9399,8 +9801,8 @@ if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$FILECMD"; then +else case e in #( + e) if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9422,7 +9824,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then @@ -9444,8 +9847,8 @@ if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_FILECMD"; then +else case e in #( + e) if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9467,7 +9870,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then @@ -9507,8 +9911,8 @@ if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$OBJDUMP"; then +else case e in #( + e) if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9530,7 +9934,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then @@ -9552,8 +9957,8 @@ if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_OBJDUMP"; then +else case e in #( + e) if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9575,7 +9980,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then @@ -9616,8 +10022,8 @@ if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_file_magic_cmd='$MAGIC_CMD' +else case e in #( + e) lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support @@ -9810,7 +10216,8 @@ lt_cv_deplibs_check_method=pass_all ;; esac - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } @@ -9862,8 +10269,8 @@ if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$DLLTOOL"; then +else case e in #( + e) if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9885,7 +10292,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then @@ -9907,8 +10315,8 @@ if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_DLLTOOL"; then +else case e in #( + e) if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -9930,7 +10338,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then @@ -9972,8 +10381,8 @@ if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_sharedlib_from_linklib_cmd='unknown' +else case e in #( + e) lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) @@ -9993,7 +10402,8 @@ lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } @@ -10016,8 +10426,8 @@ if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AR"; then +else case e in #( + e) if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10039,7 +10449,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi AR=$ac_cv_prog_AR if test -n "$AR"; then @@ -10065,8 +10476,8 @@ if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_AR"; then +else case e in #( + e) if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10088,7 +10499,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then @@ -10150,8 +10562,8 @@ if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_ar_at_file=no +else case e in #( + e) lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10188,7 +10600,8 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } @@ -10213,8 +10626,8 @@ if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$STRIP"; then +else case e in #( + e) if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10236,7 +10649,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then @@ -10258,8 +10672,8 @@ if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_STRIP"; then +else case e in #( + e) if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10281,7 +10695,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then @@ -10322,8 +10737,8 @@ if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$RANLIB"; then +else case e in #( + e) if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10345,7 +10760,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then @@ -10367,8 +10783,8 @@ if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_RANLIB"; then +else case e in #( + e) if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -10390,7 +10806,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then @@ -10501,8 +10918,8 @@ if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] @@ -10757,7 +11174,8 @@ lt_cv_sys_global_symbol_pipe= fi done - + ;; +esac fi if test -z "$lt_cv_sys_global_symbol_pipe"; then @@ -10821,8 +11239,9 @@ if test ${with_sysroot+y} then : withval=$with_sysroot; -else $as_nop - with_sysroot=no +else case e in #( + e) with_sysroot=no ;; +esac fi @@ -10857,8 +11276,8 @@ if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 -else $as_nop - printf 0123456789abcdef0123456789abcdef >conftest.i +else case e in #( + e) printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then @@ -10894,7 +11313,8 @@ ac_cv_path_lt_DD=$lt_DD fi -rm -f conftest.i conftest2.i conftest.out +rm -f conftest.i conftest2.i conftest.out ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } @@ -10905,8 +11325,8 @@ if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 -else $as_nop - printf 0123456789abcdef0123456789abcdef >conftest.i +else case e in #( + e) printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then @@ -10914,7 +11334,8 @@ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } @@ -11124,8 +11545,8 @@ if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_ext=c +else case e in #( + e) ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -11145,8 +11566,9 @@ if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes -else $as_nop - lt_cv_cc_needs_belf=no +else case e in #( + e) lt_cv_cc_needs_belf=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -11155,7 +11577,8 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } @@ -11213,8 +11636,8 @@ if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$MANIFEST_TOOL"; then +else case e in #( + e) if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11236,7 +11659,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then @@ -11258,8 +11682,8 @@ if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_MANIFEST_TOOL"; then +else case e in #( + e) if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11281,7 +11705,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then @@ -11313,15 +11738,16 @@ if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_path_mainfest_tool=no +else case e in #( + e) lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi - rm -f conftest* + rm -f conftest* ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } @@ -11344,8 +11770,8 @@ if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$DSYMUTIL"; then +else case e in #( + e) if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11367,7 +11793,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then @@ -11389,8 +11816,8 @@ if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_DSYMUTIL"; then +else case e in #( + e) if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11412,7 +11839,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then @@ -11446,8 +11874,8 @@ if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$NMEDIT"; then +else case e in #( + e) if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11469,7 +11897,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then @@ -11491,8 +11920,8 @@ if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_NMEDIT"; then +else case e in #( + e) if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11514,7 +11943,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then @@ -11548,8 +11978,8 @@ if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$LIPO"; then +else case e in #( + e) if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11571,7 +12001,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then @@ -11593,8 +12024,8 @@ if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_LIPO"; then +else case e in #( + e) if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11616,7 +12047,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then @@ -11650,8 +12082,8 @@ if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$OTOOL"; then +else case e in #( + e) if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11673,7 +12105,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then @@ -11695,8 +12128,8 @@ if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_OTOOL"; then +else case e in #( + e) if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11718,7 +12151,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then @@ -11752,8 +12186,8 @@ if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$OTOOL64"; then +else case e in #( + e) if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11775,7 +12209,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then @@ -11797,8 +12232,8 @@ if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_OTOOL64"; then +else case e in #( + e) if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -11820,7 +12255,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then @@ -11877,8 +12313,8 @@ if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_apple_cc_single_mod=no +else case e in #( + e) lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE @@ -11904,7 +12340,8 @@ fi rm -rf libconftest.dylib* rm -f conftest.* - fi + fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } @@ -11914,8 +12351,8 @@ if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_ld_exported_symbols_list=no +else case e in #( + e) lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" @@ -11933,13 +12370,15 @@ if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes -else $as_nop - lt_cv_ld_exported_symbols_list=no +else case e in #( + e) lt_cv_ld_exported_symbols_list=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } @@ -11949,8 +12388,8 @@ if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_ld_force_load=no +else case e in #( + e) lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF @@ -11975,7 +12414,8 @@ fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$lt_cv_ld_force_load" >&6; } @@ -12095,8 +12535,9 @@ IFS=$lt_save_ifs ;; esac -else $as_nop - enable_shared=yes +else case e in #( + e) enable_shared=yes ;; +esac fi @@ -12127,8 +12568,9 @@ IFS=$lt_save_ifs ;; esac -else $as_nop - enable_static=yes +else case e in #( + e) enable_static=yes ;; +esac fi @@ -12159,8 +12601,9 @@ IFS=$lt_save_ifs ;; esac -else $as_nop - pic_mode=default +else case e in #( + e) pic_mode=default ;; +esac fi @@ -12190,8 +12633,9 @@ IFS=$lt_save_ifs ;; esac -else $as_nop - enable_fast_install=yes +else case e in #( + e) enable_fast_install=yes ;; +esac fi @@ -12218,15 +12662,17 @@ ;; esac lt_cv_with_aix_soname=$with_aix_soname -else $as_nop - if test ${lt_cv_with_aix_soname+y} +else case e in #( + e) if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_with_aix_soname=aix +else case e in #( + e) lt_cv_with_aix_soname=aix ;; +esac fi - with_aix_soname=$lt_cv_with_aix_soname + with_aix_soname=$lt_cv_with_aix_soname ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 @@ -12317,8 +12763,8 @@ if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -f .libs 2>/dev/null +else case e in #( + e) rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs @@ -12326,7 +12772,8 @@ # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi -rmdir .libs 2>/dev/null +rmdir .libs 2>/dev/null ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } @@ -12387,8 +12834,8 @@ if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 -else $as_nop - case $MAGIC_CMD in +else case e in #( + e) case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; @@ -12431,6 +12878,7 @@ IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; +esac ;; esac fi @@ -12454,8 +12902,8 @@ if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 -else $as_nop - case $MAGIC_CMD in +else case e in #( + e) case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; @@ -12498,6 +12946,7 @@ IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; +esac ;; esac fi @@ -12597,8 +13046,8 @@ if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_rtti_exceptions=no +else case e in #( + e) lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment @@ -12626,7 +13075,8 @@ fi fi $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } @@ -12991,8 +13441,9 @@ if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +else case e in #( + e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } @@ -13007,8 +13458,8 @@ if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_pic_works=no +else case e in #( + e) lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment @@ -13036,7 +13487,8 @@ fi fi $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } @@ -13072,8 +13524,8 @@ if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_static_works=no +else case e in #( + e) lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -13094,7 +13546,8 @@ fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } @@ -13116,8 +13569,8 @@ if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_c_o=no +else case e in #( + e) lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -13157,7 +13610,8 @@ cd .. $RM -r conftest $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } @@ -13172,8 +13626,8 @@ if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_c_o=no +else case e in #( + e) lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -13213,7 +13667,8 @@ cd .. $RM -r conftest $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } @@ -13808,8 +14263,8 @@ if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -13841,7 +14296,8 @@ if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi - + ;; +esac fi aix_libpath=$lt_cv_aix_libpath_ @@ -13863,8 +14319,8 @@ if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -13896,7 +14352,8 @@ if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi - + ;; +esac fi aix_libpath=$lt_cv_aix_libpath_ @@ -14147,8 +14604,8 @@ if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler__b=no +else case e in #( + e) lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -14169,7 +14626,8 @@ fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } @@ -14217,8 +14675,8 @@ if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 -else $as_nop - save_LDFLAGS=$LDFLAGS +else case e in #( + e) save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14227,12 +14685,14 @@ if ac_fn_c_try_link "$LINENO" then : lt_cv_irix_exported_symbol=yes -else $as_nop - lt_cv_irix_exported_symbol=no +else case e in #( + e) lt_cv_irix_exported_symbol=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS + LDFLAGS=$save_LDFLAGS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } @@ -14558,8 +15018,8 @@ if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 -else $as_nop - $RM conftest* +else case e in #( + e) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 @@ -14595,7 +15055,8 @@ cat conftest.err 1>&5 fi $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } @@ -15322,8 +15783,8 @@ if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_shlibpath_overrides_runpath=no +else case e in #( + e) lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ @@ -15350,7 +15811,8 @@ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir - + ;; +esac fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath @@ -15775,16 +16237,22 @@ if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dlopen (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); int main (void) { @@ -15796,24 +16264,27 @@ if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes -else $as_nop - ac_cv_lib_dl_dlopen=no +else case e in #( + e) ac_cv_lib_dl_dlopen=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else $as_nop - +else case e in #( + e) lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes - + ;; +esac fi ;; @@ -15831,22 +16302,28 @@ if test "x$ac_cv_func_shl_load" = xyes then : lt_cv_dlopen=shl_load -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char shl_load (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (void); int main (void) { @@ -15858,39 +16335,47 @@ if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes -else $as_nop - ac_cv_lib_dld_shl_load=no +else case e in #( + e) ac_cv_lib_dld_shl_load=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld -else $as_nop - ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +else case e in #( + e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes then : lt_cv_dlopen=dlopen -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dlopen (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); int main (void) { @@ -15902,34 +16387,42 @@ if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes -else $as_nop - ac_cv_lib_dl_dlopen=no +else case e in #( + e) ac_cv_lib_dl_dlopen=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dlopen (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); int main (void) { @@ -15941,34 +16434,42 @@ if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes -else $as_nop - ac_cv_lib_svld_dlopen=no +else case e in #( + e) ac_cv_lib_svld_dlopen=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dld_link (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (void); int main (void) { @@ -15980,12 +16481,14 @@ if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes -else $as_nop - ac_cv_lib_dld_dld_link=no +else case e in #( + e) ac_cv_lib_dld_dld_link=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } @@ -15994,19 +16497,24 @@ lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi - + ;; +esac fi - + ;; +esac fi - + ;; +esac fi - + ;; +esac fi - + ;; +esac fi ;; @@ -16034,8 +16542,8 @@ if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 -else $as_nop - if test yes = "$cross_compiling"; then : +else case e in #( + e) if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -16129,7 +16637,8 @@ fi rm -fr conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } @@ -16141,8 +16650,8 @@ if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 -else $as_nop - if test yes = "$cross_compiling"; then : +else case e in #( + e) if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 @@ -16236,7 +16745,8 @@ fi rm -fr conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$lt_cv_dlopen_self_static" >&6; } @@ -16394,8 +16904,8 @@ if test ${ac_cv_prog_CXXCPP+y} then : printf %s "(cached) " >&6 -else $as_nop - # Double quotes because $CXX needs to be expanded +else case e in #( + e) # Double quotes because $CXX needs to be expanded for CXXCPP in "$CXX -E" cpp /lib/cpp do ac_preproc_ok=false @@ -16413,9 +16923,10 @@ if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -16429,15 +16940,16 @@ then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : @@ -16446,7 +16958,8 @@ done ac_cv_prog_CXXCPP=$CXXCPP - + ;; +esac fi CXXCPP=$ac_cv_prog_CXXCPP else @@ -16469,9 +16982,10 @@ if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -16485,24 +16999,26 @@ then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi ac_ext=cpp @@ -16639,8 +17155,9 @@ if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes -else $as_nop - with_gnu_ld=no +else case e in #( + e) with_gnu_ld=no ;; +esac fi ac_prog=ld @@ -16685,8 +17202,8 @@ if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$LD"; then +else case e in #( + e) if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs @@ -16709,7 +17226,8 @@ IFS=$lt_save_ifs else lt_cv_path_LD=$LD # Let the user override the test with a path. -fi +fi ;; +esac fi LD=$lt_cv_path_LD @@ -16726,8 +17244,8 @@ if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 -else $as_nop - # I'd rather use --version here, but apparently some GNU lds only accept -v. +else case e in #( + e) # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 @@ -16934,8 +17453,8 @@ if test ${lt_cv_aix_libpath__CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -16967,7 +17486,8 @@ if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=/usr/lib:/lib fi - + ;; +esac fi aix_libpath=$lt_cv_aix_libpath__CXX @@ -16990,8 +17510,8 @@ if test ${lt_cv_aix_libpath__CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -17023,7 +17543,8 @@ if test -z "$lt_cv_aix_libpath__CXX"; then lt_cv_aix_libpath__CXX=/usr/lib:/lib fi - + ;; +esac fi aix_libpath=$lt_cv_aix_libpath__CXX @@ -18395,8 +18916,9 @@ if test ${lt_cv_prog_compiler_pic_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +else case e in #( + e) lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_CXX" >&6; } @@ -18411,8 +18933,8 @@ if test ${lt_cv_prog_compiler_pic_works_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_pic_works_CXX=no +else case e in #( + e) lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ## exclude from sc_useless_quotes_in_assignment @@ -18440,7 +18962,8 @@ fi fi $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works_CXX" >&6; } @@ -18470,8 +18993,8 @@ if test ${lt_cv_prog_compiler_static_works_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_static_works_CXX=no +else case e in #( + e) lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext @@ -18492,7 +19015,8 @@ fi $RM -r conftest* LDFLAGS=$save_LDFLAGS - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works_CXX" >&6; } @@ -18511,8 +19035,8 @@ if test ${lt_cv_prog_compiler_c_o_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_c_o_CXX=no +else case e in #( + e) lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -18552,7 +19076,8 @@ cd .. $RM -r conftest $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o_CXX" >&6; } @@ -18564,8 +19089,8 @@ if test ${lt_cv_prog_compiler_c_o_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_prog_compiler_c_o_CXX=no +else case e in #( + e) lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest @@ -18605,7 +19130,8 @@ cd .. $RM -r conftest $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o_CXX" >&6; } @@ -18710,8 +19236,8 @@ if test ${lt_cv_archive_cmds_need_lc_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - $RM conftest* +else case e in #( + e) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 @@ -18747,7 +19273,8 @@ cat conftest.err 1>&5 fi $RM conftest* - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc_CXX" >&6; } @@ -19311,8 +19838,8 @@ if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 -else $as_nop - lt_cv_shlibpath_overrides_runpath=no +else case e in #( + e) lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ @@ -19339,7 +19866,8 @@ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir - + ;; +esac fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath @@ -19822,8 +20350,8 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } -else $as_nop - LIBS="$LIBS -latomic" +else case e in #( + e) LIBS="$LIBS -latomic" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19840,16 +20368,18 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "libatomic needed, but linking with -latomic failed, cannot continue -See \`config.log' for more details" "$LINENO" 5; } - +See 'config.log' for more details" "$LINENO" 5; } + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -19863,8 +20393,8 @@ if test ${ac_cv_cxx_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_CFLAGS=$CFLAGS +else case e in #( + e) ac_save_CFLAGS=$CFLAGS ac_cv_cxx_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" @@ -19883,8 +20413,8 @@ if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - # This test program should compile successfully. +else case e in #( + e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the @@ -19912,26 +20442,29 @@ if test x"$ac_arg" = x then : ac_cv_cxx_undeclared_builtin_options='none needed' -else $as_nop - ac_cv_cxx_undeclared_builtin_options=$ac_arg +else case e in #( + e) ac_cv_cxx_undeclared_builtin_options=$ac_arg ;; +esac fi break fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_cxx_undeclared_builtin_options" >&6; } case $ac_cv_cxx_undeclared_builtin_options in #( 'cannot detect') : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CXX report undeclared builtins -See \`config.log' for more details" "$LINENO" 5; } ;; #( +See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_cxx_undeclared_builtin_options='' ;; #( *) : @@ -19944,8 +20477,8 @@ if test ${ac_cv_search_inet_aton+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19982,11 +20515,13 @@ if test ${ac_cv_search_inet_aton+y} then : -else $as_nop - ac_cv_search_inet_aton=no +else case e in #( + e) ac_cv_search_inet_aton=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 printf "%s\n" "$ac_cv_search_inet_aton" >&6; } @@ -20002,8 +20537,8 @@ if test ${ac_cv_search_gethostbyname+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20040,11 +20575,13 @@ if test ${ac_cv_search_gethostbyname+y} then : -else $as_nop - ac_cv_search_gethostbyname=no +else case e in #( + e) ac_cv_search_gethostbyname=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 printf "%s\n" "$ac_cv_search_gethostbyname" >&6; } @@ -20060,8 +20597,8 @@ if test ${ac_cv_search_socket+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20098,11 +20635,13 @@ if test ${ac_cv_search_socket+y} then : -else $as_nop - ac_cv_search_socket=no +else case e in #( + e) ac_cv_search_socket=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 printf "%s\n" "$ac_cv_search_socket" >&6; } @@ -20118,8 +20657,8 @@ if test ${ac_cv_search_gethostent+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20156,11 +20695,13 @@ if test ${ac_cv_search_gethostent+y} then : -else $as_nop - ac_cv_search_gethostent=no +else case e in #( + e) ac_cv_search_gethostent=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostent" >&5 printf "%s\n" "$ac_cv_search_gethostent" >&6; } @@ -20204,8 +20745,8 @@ if test ${ac_cv_search_res_query+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20242,11 +20783,13 @@ if test ${ac_cv_search_res_query+y} then : -else $as_nop - ac_cv_search_res_query=no +else case e in #( + e) ac_cv_search_res_query=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_query" >&5 printf "%s\n" "$ac_cv_search_res_query" >&6; } @@ -20255,14 +20798,14 @@ then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing __res_query" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing __res_query" >&5 printf %s "checking for library containing __res_query... " >&6; } if test ${ac_cv_search___res_query+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20299,11 +20842,13 @@ if test ${ac_cv_search___res_query+y} then : -else $as_nop - ac_cv_search___res_query=no +else case e in #( + e) ac_cv_search___res_query=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___res_query" >&5 printf "%s\n" "$ac_cv_search___res_query" >&6; } @@ -20313,7 +20858,8 @@ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi - + ;; +esac fi # macOS uses an alternative name internally @@ -20322,8 +20868,8 @@ if test ${ac_cv_search_res_9_query+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20360,11 +20906,13 @@ if test ${ac_cv_search_res_9_query+y} then : -else $as_nop - ac_cv_search_res_9_query=no +else case e in #( + e) ac_cv_search_res_9_query=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_9_query" >&5 printf "%s\n" "$ac_cv_search_res_9_query" >&6; } @@ -20418,8 +20966,8 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -20453,8 +21001,8 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -20488,8 +21036,8 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -20523,8 +21071,8 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } @@ -20558,27 +21106,32 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -20588,8 +21141,9 @@ if test "x$ac_cv_have_decl_strerror_r" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h @@ -20608,8 +21162,8 @@ if test ${ac_cv_func_strerror_r_char_p+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20635,7 +21189,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; } @@ -20653,8 +21208,8 @@ if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20691,11 +21246,13 @@ if test ${ac_cv_search_clock_gettime+y} then : -else $as_nop - ac_cv_search_clock_gettime=no +else case e in #( + e) ac_cv_search_clock_gettime=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } @@ -20747,8 +21304,8 @@ if test ${boost_cv_inc_path+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_inc_path=no +else case e in #( + e) boost_cv_inc_path=no ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -20817,8 +21374,9 @@ if ac_fn_cxx_try_compile "$LINENO" then : boost_cv_inc_path=yes -else $as_nop - boost_cv_version=no +else case e in #( + e) boost_cv_version=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam if test x"$boost_cv_inc_path" = xyes; then @@ -20834,7 +21392,8 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_inc_path" >&5 printf "%s\n" "$boost_cv_inc_path" >&6; } @@ -20860,8 +21419,8 @@ if test ${boost_cv_lib_version+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_ext=cpp +else case e in #( + e) ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -20886,7 +21445,8 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_version" >&5 printf "%s\n" "$boost_cv_lib_version" >&6; } @@ -20910,8 +21470,8 @@ if test ${boost_cv_pthread_flag+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_pthread_flag= +else case e in #( + e) boost_cv_pthread_flag= # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # (none): in case threads are in libc; should be tried before -Kthread and @@ -20975,7 +21535,8 @@ LIBS=$boost_pthreads__save_LIBS $boost_pthread_ok && break done - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_pthread_flag" >&5 printf "%s\n" "$boost_cv_pthread_flag" >&6; } @@ -20990,8 +21551,8 @@ if test ${boost_cv_lib_tag+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_tag=unknown +else case e in #( + e) boost_cv_lib_tag=unknown if test x$boost_cv_inc_path != xno; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -21321,7 +21882,8 @@ boost_cv_lib_tag= ;; esac -fi +fi ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5 printf "%s\n" "$boost_cv_lib_tag" >&6; } @@ -21329,8 +21891,9 @@ if test ${enable_static_boost+y} then : enableval=$enable_static_boost; enable_static_boost=yes -else $as_nop - enable_static_boost=no +else case e in #( + e) enable_static_boost=no ;; +esac fi # Check whether we do better use `mt' even though we weren't ask to. @@ -21359,8 +21922,9 @@ if ac_fn_cxx_try_compile "$LINENO" then : boost_guess_use_mt=: -else $as_nop - boost_guess_use_mt=false +else case e in #( + e) boost_guess_use_mt=false ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=cpp @@ -21396,8 +21960,9 @@ printf "%s\n" "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h -else $as_nop - as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5 ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -21438,8 +22003,9 @@ printf "%s\n" "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -21457,8 +22023,8 @@ if test ${boost_cv_lib_system+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_system=no +else case e in #( + e) boost_cv_lib_system=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -21499,14 +22065,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"yes" != x"no" +else case e in #( + e) if test x"yes" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost system" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -21586,13 +22153,14 @@ } then : boost_cv_lib_system=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_system=no + boost_cv_lib_system=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -21609,8 +22177,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -21650,13 +22218,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -21671,7 +22240,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -21690,7 +22260,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_system" >&5 printf "%s\n" "$boost_cv_lib_system" >&6; } @@ -21771,8 +22342,9 @@ printf "%s\n" "#define HAVE_BOOST_THREAD_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -21790,8 +22362,8 @@ if test ${boost_cv_lib_thread+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_thread=no +else case e in #( + e) boost_cv_lib_thread=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -21832,14 +22404,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"yes" != x"no" +else case e in #( + e) if test x"yes" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost thread" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -21919,13 +22492,14 @@ } then : boost_cv_lib_thread=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_thread=no + boost_cv_lib_thread=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -21942,8 +22516,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -21983,13 +22557,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -22004,7 +22579,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -22023,7 +22599,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_thread" >&5 printf "%s\n" "$boost_cv_lib_thread" >&6; } @@ -22105,8 +22682,9 @@ printf "%s\n" "#define HAVE_BOOST_CONTEXT_FIBER_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -22124,8 +22702,8 @@ if test ${boost_cv_lib_context+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_context=no +else case e in #( + e) boost_cv_lib_context=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -22184,14 +22762,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"yes" != x"no" +else case e in #( + e) if test x"yes" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost context" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -22271,13 +22850,14 @@ } then : boost_cv_lib_context=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_context=no + boost_cv_lib_context=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -22294,8 +22874,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -22335,13 +22915,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -22356,7 +22937,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -22375,7 +22957,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_context" >&5 printf "%s\n" "$boost_cv_lib_context" >&6; } @@ -22441,8 +23024,9 @@ printf "%s\n" "#define HAVE_BOOST_CONTEXT_EXECUTION_CONTEXT_V2_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -22460,8 +23044,8 @@ if test ${boost_cv_lib_context+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_context=no +else case e in #( + e) boost_cv_lib_context=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -22525,14 +23109,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"yes" != x"no" +else case e in #( + e) if test x"yes" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost context" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -22612,13 +23197,14 @@ } then : boost_cv_lib_context=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_context=no + boost_cv_lib_context=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -22635,8 +23221,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -22676,13 +23262,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -22697,7 +23284,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -22716,7 +23304,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_context" >&5 printf "%s\n" "$boost_cv_lib_context" >&6; } @@ -22782,8 +23371,9 @@ printf "%s\n" "#define HAVE_BOOST_CONTEXT_FCONTEXT_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -22801,8 +23391,8 @@ if test ${boost_cv_lib_context+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_context=no +else case e in #( + e) boost_cv_lib_context=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -22897,14 +23487,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"" != x"no" +else case e in #( + e) if test x"" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost context" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -22984,13 +23575,14 @@ } then : boost_cv_lib_context=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_context=no + boost_cv_lib_context=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -23007,8 +23599,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -23048,13 +23640,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -23069,7 +23662,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -23088,7 +23682,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_context" >&5 printf "%s\n" "$boost_cv_lib_context" >&6; } @@ -23137,9 +23732,10 @@ if test ${enable_unit_tests+y} then : enableval=$enable_unit_tests; enable_unit_tests=$enableval -else $as_nop - enable_unit_tests=no - +else case e in #( + e) enable_unit_tests=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_unit_tests" >&5 @@ -23185,8 +23781,9 @@ printf "%s\n" "#define HAVE_BOOST_TEST_UNIT_TEST_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -23204,8 +23801,8 @@ if test ${boost_cv_lib_unit_test_framework+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_unit_test_framework=no +else case e in #( + e) boost_cv_lib_unit_test_framework=no case "mt" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "Xmt" : 'Xmt-*\(.*\)'`;; #( @@ -23248,14 +23845,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"" != x"no" +else case e in #( + e) if test x"" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost unit_test_framework" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -23335,13 +23933,14 @@ } then : boost_cv_lib_unit_test_framework=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_unit_test_framework=no + boost_cv_lib_unit_test_framework=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -23358,8 +23957,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -23399,13 +23998,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -23420,7 +24020,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -23439,7 +24040,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_unit_test_framework" >&5 printf "%s\n" "$boost_cv_lib_unit_test_framework" >&6; } @@ -23492,8 +24094,9 @@ if test ${enable_reproducible+y} then : enableval=$enable_reproducible; enable_reproducible=$enableval -else $as_nop - enable_reproducible=no +else case e in #( + e) enable_reproducible=no ;; +esac fi @@ -23507,8 +24110,8 @@ printf "%s\n" "#define REPRODUCIBLE 1" >>confdefs.h -else $as_nop - +else case e in #( + e) build_user=$(id -u -n) case "$host_os" in @@ -23524,7 +24127,8 @@ printf "%s\n" "#define BUILD_HOST \"$build_user@$build_host\"" >>confdefs.h - + ;; +esac fi @@ -23534,9 +24138,10 @@ if test ${enable_coverage+y} then : enableval=$enable_coverage; enable_coverage=$enableval -else $as_nop - enable_coverage=no - +else case e in #( + e) enable_coverage=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_coverage" >&5 @@ -23550,8 +24155,8 @@ if test ${gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fprofile-instr-generate -fcoverage-mapping" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23568,13 +24173,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping=yes -else $as_nop - gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping=no +else case e in #( + e) gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping" >&5 printf "%s\n" "$gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping" >&6; } @@ -23584,10 +24191,11 @@ CFLAGS="$CFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping" CXXFLAGS="$CXXFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping" -else $as_nop - +else case e in #( + e) as_fn_error $? "$CXX does not support gathering coverage data in the clang format" "$LINENO" 5 - + ;; +esac fi @@ -23601,8 +24209,8 @@ if test ${gl_cv_warn_cxx__fprofile_arcs__ftest_coverage+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fprofile-arcs -ftest-coverage" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23619,13 +24227,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fprofile_arcs__ftest_coverage=yes -else $as_nop - gl_cv_warn_cxx__fprofile_arcs__ftest_coverage=no +else case e in #( + e) gl_cv_warn_cxx__fprofile_arcs__ftest_coverage=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" >&5 printf "%s\n" "$gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" >&6; } @@ -23636,10 +24246,11 @@ CXXFLAGS="$CXXFLAGS -DCOVERAGE --coverage" LDFLAGS="$LDFLAGS --coverage" -else $as_nop - +else case e in #( + e) as_fn_error $? "$CXX does not support gathering coverage data" "$LINENO" 5 - + ;; +esac fi @@ -23662,8 +24273,8 @@ if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - case $PKG_CONFIG in +else case e in #( + e) case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; @@ -23688,6 +24299,7 @@ IFS=$as_save_IFS ;; +esac ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG @@ -23710,8 +24322,8 @@ if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - case $ac_pt_PKG_CONFIG in +else case e in #( + e) case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; @@ -23736,6 +24348,7 @@ IFS=$as_save_IFS ;; +esac ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG @@ -23776,14 +24389,17 @@ PKG_CONFIG="" fi fi +if test -z "$PKG_CONFIG"; then + as_fn_error $? "pkg-config not found" "$LINENO" 5 +fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then +else case e in #( + e) if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -23802,9 +24418,10 @@ as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in +case `"$ac_path_GREP" --version 2>&1` in #( *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -23839,7 +24456,8 @@ else ac_cv_path_GREP=$GREP fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } @@ -23854,10 +24472,11 @@ withval=$with_lua; with_lua=$withval -else $as_nop - +else case e in #( + e) with_lua=auto - + ;; +esac fi @@ -23871,7 +24490,7 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_lua" >&5 printf "%s\n" "$with_lua" >&6; } - if test "x$with_lua" = "xno" -a "mandatory" = "mandatory" + if test "x$with_lua" = "xno" then : as_fn_error $? "--without-lua specified, but Lua is not optional" "$LINENO" 5 @@ -23882,14 +24501,11 @@ luajit_min_version='2.0.2' lua_min_version='5.1' - if test "x$with_lua" != "xno" + if test "x$with_lua" != "xauto" then : - if test "x$with_lua" != "xauto" -then : - - with_lua_version=${lua_min_version} - if echo "x$with_lua" | ${GREP} 'jit' >/dev/null 2>&1 + with_lua_version=${lua_min_version} + if echo "x$with_lua" | ${GREP} 'jit' >/dev/null 2>&1 then : with_lua_version=${luajit_min_version} fi @@ -23953,13 +24569,13 @@ echo "$LUA_PKG_ERRORS" >&5 - as_fn_error $? "Selected Lua ($with_lua) not found" "$LINENO" 5 + as_fn_error $? "Selected Lua ($with_lua) not found" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "Selected Lua ($with_lua) not found" "$LINENO" 5 + as_fn_error $? "Selected Lua ($with_lua) not found" "$LINENO" 5 else LUA_CFLAGS=$pkg_cv_LUA_CFLAGS @@ -23970,12 +24586,12 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - LUAPC=$with_lua + LUAPC=$with_lua fi -else $as_nop - +else case e in #( + e) pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for luajit >= ${luajit_min_version}" >&5 @@ -24046,18 +24662,18 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } - LUAPC=luajit + LUAPC=luajit printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h fi - if test -z "$LUAPC" + if test -z "$LUAPC" then : - found_lua=n + found_lua=n - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24133,14 +24749,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua5.3 + found_lua=y + LUAPC=lua5.3 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24216,14 +24832,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua-5.3 + found_lua=y + LUAPC=lua-5.3 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24299,14 +24915,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua53 + found_lua=y + LUAPC=lua53 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24382,14 +24998,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua5.2 + found_lua=y + LUAPC=lua5.2 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24465,14 +25081,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua-5.2 + found_lua=y + LUAPC=lua-5.2 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24548,14 +25164,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua52 + found_lua=y + LUAPC=lua52 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24631,14 +25247,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua5.1 + found_lua=y + LUAPC=lua5.1 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24714,14 +25330,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua-5.1 + found_lua=y + LUAPC=lua-5.1 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24797,14 +25413,14 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua51 + found_lua=y + LUAPC=lua51 fi fi - if test "$found_lua" != "y" + if test "$found_lua" != "y" then : @@ -24880,8 +25496,8 @@ printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h - found_lua=y - LUAPC=lua + found_lua=y + LUAPC=lua fi @@ -24889,12 +25505,11 @@ fi - -fi - + ;; +esac fi - if test -z "$LUAPC" -a "mandatory" = "mandatory" + if test -z "$LUAPC" then : as_fn_error $? "No Lua not found, but is mandatory" "$LINENO" 5 @@ -24954,9 +25569,10 @@ if test ${enable_verbose_logging+y} then : enableval=$enable_verbose_logging; enable_verbose_logging=$enableval -else $as_nop - enable_verbose_logging=no - +else case e in #( + e) enable_verbose_logging=no + ;; +esac fi @@ -24988,8 +25604,8 @@ ;; esac -else $as_nop - +else case e in #( + e) # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs if test -n "$ac_tool_prefix"; then @@ -25000,8 +25616,8 @@ if test ${ac_cv_prog_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$PKG_CONFIG"; then +else case e in #( + e) if test -n "$PKG_CONFIG"; then ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -25023,7 +25639,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi PKG_CONFIG=$ac_cv_prog_PKG_CONFIG if test -n "$PKG_CONFIG"; then @@ -25045,8 +25662,8 @@ if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_PKG_CONFIG"; then +else case e in #( + e) if test -n "$ac_ct_PKG_CONFIG"; then ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -25068,7 +25685,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG if test -n "$ac_ct_PKG_CONFIG"; then @@ -25100,6 +25718,7 @@ LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null` LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null` ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null` + sslincdir=`$PKG_CONFIG libcrypto --variable=includedir 2>/dev/null` found=true fi fi @@ -25109,7 +25728,8 @@ ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" fi - + ;; +esac fi @@ -25126,6 +25746,7 @@ LIBCRYPTO_INCLUDES="-I$ssldir/include" LIBCRYPTO_LDFLAGS="-L$ssldir/lib" LIBCRYPTO_LIBS="-lcrypto" + sslincdir="$ssldir/include" found=true { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } @@ -25235,15 +25856,16 @@ -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "OpenSSL/libcrypto not found" "$LINENO" 5 - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -25277,55 +25899,60 @@ # Find the headers we need for ECDSA libcrypto_ecdsa=yes - as_ac_Header=`printf "%s\n" "ac_cv_header_$ssldir/include/openssl/ecdsa.h" | $as_tr_sh` -ac_fn_cxx_check_header_compile "$LINENO" "$ssldir/include/openssl/ecdsa.h" "$as_ac_Header" "$ac_includes_default" + as_ac_Header=`printf "%s\n" "ac_cv_header_$sslincdir/openssl/ecdsa.h" | sed "$as_sed_sh"` +ac_fn_cxx_check_header_compile "$LINENO" "$sslincdir/openssl/ecdsa.h" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes" then : ac_fn_check_decl "$LINENO" "NID_X9_62_prime256v1" "ac_cv_have_decl_NID_X9_62_prime256v1" "$ac_includes_default -#include <$ssldir/include/openssl/evp.h> +#include <$sslincdir/openssl/evp.h> " "$ac_cxx_undeclared_builtin_options" "CXXFLAGS" if test "x$ac_cv_have_decl_NID_X9_62_prime256v1" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_NID_X9_62_PRIME256V1 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : : -else $as_nop - +else case e in #( + e) libcrypto_ecdsa=no - + ;; +esac fi ac_fn_check_decl "$LINENO" "NID_secp384r1" "ac_cv_have_decl_NID_secp384r1" "$ac_includes_default -#include <$ssldir/include/openssl/evp.h> +#include <$sslincdir/openssl/evp.h> " "$ac_cxx_undeclared_builtin_options" "CXXFLAGS" if test "x$ac_cv_have_decl_NID_secp384r1" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_NID_SECP384R1 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : : -else $as_nop - +else case e in #( + e) libcrypto_ecdsa=no - + ;; +esac fi -else $as_nop - +else case e in #( + e) libcrypto_ecdsa=no - + ;; +esac fi @@ -25358,13 +25985,14 @@ libcrypto_ed25519=no libcrypto_ed448=no ac_fn_check_decl "$LINENO" "NID_ED25519" "ac_cv_have_decl_NID_ED25519" "$ac_includes_default - #include <$ssldir/include/openssl/evp.h> + #include <$sslincdir/openssl/evp.h> " "$ac_cxx_undeclared_builtin_options" "CXXFLAGS" if test "x$ac_cv_have_decl_NID_ED25519" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_NID_ED25519 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 @@ -25375,18 +26003,20 @@ printf "%s\n" "#define HAVE_LIBCRYPTO_ED25519 1" >>confdefs.h -else $as_nop - : +else case e in #( + e) : ;; +esac fi ac_fn_check_decl "$LINENO" "NID_ED448" "ac_cv_have_decl_NID_ED448" "$ac_includes_default - #include <$ssldir/include/openssl/evp.h> + #include <$sslincdir/openssl/evp.h> " "$ac_cxx_undeclared_builtin_options" "CXXFLAGS" if test "x$ac_cv_have_decl_NID_ED448" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_NID_ED448 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 @@ -25397,8 +26027,9 @@ printf "%s\n" "#define HAVE_LIBCRYPTO_ED448 1" >>confdefs.h -else $as_nop - : +else case e in #( + e) : ;; +esac fi @@ -25409,8 +26040,9 @@ printf "%s\n" "#define HAVE_LIBCRYPTO_EDDSA 1" >>confdefs.h -else $as_nop - : +else case e in #( + e) : ;; +esac fi # Restore variables @@ -25426,8 +26058,9 @@ if test ${with_libsodium+y} then : withval=$with_libsodium; with_libsodium=$withval -else $as_nop - with_libsodium=auto +else case e in #( + e) with_libsodium=auto ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libsodium" >&5 @@ -25584,8 +26217,9 @@ if test ${with_libcap+y} then : withval=$with_libcap; with_libcap=$withval -else $as_nop - with_libcap=auto +else case e in #( + e) with_libcap=auto ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libcap" >&5 @@ -25701,8 +26335,8 @@ if test -n "$HAVE_LIBCURL" then : : -else $as_nop - +else case e in #( + e) @@ -25732,8 +26366,9 @@ if test ${with_libcurl+y} then : withval=$with_libcurl; _libcurl_with=$withval -else $as_nop - _libcurl_with="yes" +else case e in #( + e) _libcurl_with="yes" ;; +esac fi @@ -25748,8 +26383,8 @@ if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AWK"; then +else case e in #( + e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -25771,7 +26406,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then @@ -25801,8 +26437,8 @@ if test ${ac_cv_path__libcurl_config+y} then : printf %s "(cached) " >&6 -else $as_nop - case $_libcurl_config in +else case e in #( + e) case $_libcurl_config in [\\/]* | ?:[\\/]*) ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. ;; @@ -25827,6 +26463,7 @@ IFS=$as_save_IFS ;; +esac ;; esac fi _libcurl_config=$ac_cv_path__libcurl_config @@ -25847,8 +26484,8 @@ if test ${ac_cv_path__libcurl_config+y} then : printf %s "(cached) " >&6 -else $as_nop - case $_libcurl_config in +else case e in #( + e) case $_libcurl_config in [\\/]* | ?:[\\/]*) ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. ;; @@ -25873,6 +26510,7 @@ IFS=$as_save_IFS ;; +esac ;; esac fi _libcurl_config=$ac_cv_path__libcurl_config @@ -25893,8 +26531,9 @@ if test ${libcurl_cv_lib_curl_version+y} then : printf %s "(cached) " >&6 -else $as_nop - libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'` +else case e in #( + e) libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'` ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_version" >&5 printf "%s\n" "$libcurl_cv_lib_curl_version" >&6; } @@ -25908,14 +26547,15 @@ if test ${libcurl_cv_lib_version_ok+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $_libcurl_version -ge $_libcurl_wanted ; then libcurl_cv_lib_version_ok=yes else libcurl_cv_lib_version_ok=no fi - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_version_ok" >&5 printf "%s\n" "$libcurl_cv_lib_version_ok" >&6; } @@ -25963,8 +26603,8 @@ if test ${libcurl_cv_lib_curl_usable+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" _libcurl_save_libs=$LIBS @@ -25996,8 +26636,9 @@ if ac_fn_cxx_try_link "$LINENO" then : libcurl_cv_lib_curl_usable=yes -else $as_nop - libcurl_cv_lib_curl_usable=no +else case e in #( + e) libcurl_cv_lib_curl_usable=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -26006,7 +26647,8 @@ LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_usable" >&5 printf "%s\n" "$libcurl_cv_lib_curl_usable" >&6; } @@ -26025,10 +26667,11 @@ if test "x$ac_cv_func_curl_free" = xyes then : -else $as_nop - +else case e in #( + e) printf "%s\n" "#define curl_free free" >>confdefs.h - + ;; +esac fi @@ -26045,10 +26688,10 @@ for _libcurl_feature in $_libcurl_features ; do cat >>confdefs.h <<_ACEOF -#define `printf "%s\n" "libcurl_feature_$_libcurl_feature" | $as_tr_cpp` 1 +#define `printf "%s\n" "libcurl_feature_$_libcurl_feature" | sed "$as_sed_cpp"` 1 _ACEOF - eval `printf "%s\n" "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes + eval `printf "%s\n" "libcurl_feature_$_libcurl_feature" | sed "$as_sed_sh"`=yes done if test "x$_libcurl_protocols" = "x" ; then @@ -26076,10 +26719,10 @@ for _libcurl_protocol in $_libcurl_protocols ; do cat >>confdefs.h <<_ACEOF -#define `printf "%s\n" "libcurl_protocol_$_libcurl_protocol" | $as_tr_cpp` 1 +#define `printf "%s\n" "libcurl_protocol_$_libcurl_protocol" | sed "$as_sed_cpp"` 1 _ACEOF - eval `printf "%s\n" "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes + eval `printf "%s\n" "libcurl_protocol_$_libcurl_protocol" | sed "$as_sed_sh"`=yes done else unset LIBCURL @@ -26108,7 +26751,8 @@ unset _libcurl_with - + ;; +esac fi if test "$HAVE_LIBCURL" = "y"; then HAVE_LIBCURL_TRUE= @@ -26128,8 +26772,9 @@ if test ${with_net_snmp+y} then : withval=$with_net_snmp; with_net_snmp=$withval -else $as_nop - with_net_snmp=no +else case e in #( + e) with_net_snmp=no ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_net_snmp" >&5 @@ -26148,8 +26793,8 @@ if test ${ac_cv_prog_NET_SNMP_LIBS+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$NET_SNMP_LIBS"; then +else case e in #( + e) if test -n "$NET_SNMP_LIBS"; then ac_cv_prog_NET_SNMP_LIBS="$NET_SNMP_LIBS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -26171,7 +26816,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi NET_SNMP_LIBS=$ac_cv_prog_NET_SNMP_LIBS if test -n "$NET_SNMP_LIBS"; then @@ -26195,8 +26841,9 @@ if test "x$ac_cv_have_decl_snmp_select_info2" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi printf "%s\n" "#define HAVE_DECL_SNMP_SELECT_INFO2 $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 @@ -26206,8 +26853,9 @@ printf "%s\n" "#define HAVE_SNMP_SELECT_INFO2 1" >>confdefs.h -else $as_nop - : +else case e in #( + e) : ;; +esac fi @@ -26259,9 +26907,10 @@ if test ${enable_dns_over_tls+y} then : enableval=$enable_dns_over_tls; enable_dns_over_tls=$enableval -else $as_nop - enable_dns_over_tls=no - +else case e in #( + e) enable_dns_over_tls=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_tls" >&5 @@ -26296,8 +26945,9 @@ if test ${with_libssl+y} then : withval=$with_libssl; with_libssl=$withval -else $as_nop - with_libssl=auto +else case e in #( + e) with_libssl=auto ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libssl" >&5 @@ -26516,8 +27166,8 @@ if test ${ac_cv_prog_RAGEL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$RAGEL"; then +else case e in #( + e) if test -n "$RAGEL"; then ac_cv_prog_RAGEL="$RAGEL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -26539,7 +27189,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi RAGEL=$ac_cv_prog_RAGEL if test -n "$RAGEL"; then @@ -26565,8 +27216,8 @@ if test ${ac_cv_prog_CURL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CURL"; then +else case e in #( + e) if test -n "$CURL"; then ac_cv_prog_CURL="$CURL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -26588,7 +27239,8 @@ done IFS=$as_save_IFS -fi +fi ;; +esac fi CURL=$ac_cv_prog_CURL if test -n "$CURL"; then @@ -26601,8 +27253,8 @@ if test "x$CURL" = "x"; then - if test ! -f "${srcdir}/effective_tld_names.dat"; then - as_fn_error $? "curl is missing and you don't have ${srcdir}//effective_tld_names.dat. Install curl or download sources from www.powerdns.com" "$LINENO" 5 + if test ! -f "${srcdir}/pubsuffix.cc"; then + as_fn_error $? "curl is missing and you don't have ${srcdir}//pubsuffix.cc. Install curl or download sources from www.powerdns.com" "$LINENO" 5 fi fi @@ -26629,7 +27281,6 @@ - ac_fn_cxx_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes then : @@ -26665,8 +27316,8 @@ if test ${ac_cv_search_pthread_setaffinity_np+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -26703,11 +27354,13 @@ if test ${ac_cv_search_pthread_setaffinity_np+y} then : -else $as_nop - ac_cv_search_pthread_setaffinity_np=no +else case e in #( + e) ac_cv_search_pthread_setaffinity_np=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_setaffinity_np" >&5 printf "%s\n" "$ac_cv_search_pthread_setaffinity_np" >&6; } @@ -26725,8 +27378,8 @@ if test ${ac_cv_search_pthread_getattr_np+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -26763,11 +27416,13 @@ if test ${ac_cv_search_pthread_getattr_np+y} then : -else $as_nop - ac_cv_search_pthread_getattr_np=no +else case e in #( + e) ac_cv_search_pthread_getattr_np=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_getattr_np" >&5 printf "%s\n" "$ac_cv_search_pthread_getattr_np" >&6; } @@ -26785,8 +27440,8 @@ if test ${ac_cv_search_pthread_get_stackaddr_np+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -26823,11 +27478,13 @@ if test ${ac_cv_search_pthread_get_stackaddr_np+y} then : -else $as_nop - ac_cv_search_pthread_get_stackaddr_np=no +else case e in #( + e) ac_cv_search_pthread_get_stackaddr_np=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_get_stackaddr_np" >&5 printf "%s\n" "$ac_cv_search_pthread_get_stackaddr_np" >&6; } @@ -26845,8 +27502,8 @@ if test ${ac_cv_search_pthread_get_stacksize_np+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -26883,11 +27540,13 @@ if test ${ac_cv_search_pthread_get_stacksize_np+y} then : -else $as_nop - ac_cv_search_pthread_get_stacksize_np=no +else case e in #( + e) ac_cv_search_pthread_get_stacksize_np=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_get_stacksize_np" >&5 printf "%s\n" "$ac_cv_search_pthread_get_stacksize_np" >&6; } @@ -26921,9 +27580,10 @@ if test ${enable_nod+y} then : enableval=$enable_nod; enable_nod=$enableval -else $as_nop - enable_nod=auto - +else case e in #( + e) enable_nod=auto + ;; +esac fi @@ -26950,8 +27610,9 @@ printf "%s\n" "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h -else $as_nop - as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5 ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -26992,8 +27653,9 @@ printf "%s\n" "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -27011,8 +27673,8 @@ if test ${boost_cv_lib_system+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_system=no +else case e in #( + e) boost_cv_lib_system=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -27053,14 +27715,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"no" != x"no" +else case e in #( + e) if test x"no" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost system" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -27140,13 +27803,14 @@ } then : boost_cv_lib_system=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_system=no + boost_cv_lib_system=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -27163,8 +27827,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -27204,13 +27868,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -27225,7 +27890,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -27244,7 +27910,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_system" >&5 printf "%s\n" "$boost_cv_lib_system" >&6; } @@ -27315,8 +27982,9 @@ printf "%s\n" "#define HAVE_BOOST_FILESYSTEM_PATH_HPP 1" >>confdefs.h -else $as_nop - $not_found_header +else case e in #( + e) $not_found_header ;; +esac fi CPPFLAGS=$boost_save_CPPFLAGS @@ -27334,8 +28002,8 @@ if test ${boost_cv_lib_filesystem+y} then : printf %s "(cached) " >&6 -else $as_nop - boost_cv_lib_filesystem=no +else case e in #( + e) boost_cv_lib_filesystem=no case "" in #( (mt | mt-) boost_mt=-mt; boost_rtopt=;; #( (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #( @@ -27376,14 +28044,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_objext=do_not_rm_me_plz -else $as_nop - if test x"no" != x"no" +else case e in #( + e) if test x"no" != x"no" then : as_fn_error $? "cannot compile a test that uses Boost filesystem" "$LINENO" 5 fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam ac_objext=$boost_save_ac_objext @@ -27463,13 +28132,14 @@ } then : boost_cv_lib_filesystem=yes -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_cv_lib_filesystem=no + boost_cv_lib_filesystem=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -27486,8 +28156,8 @@ if test ${boost_cv_rpath_link_ldflag+y} then : printf %s "(cached) " >&6 -else $as_nop - case $boost_ldpath in +else case e in #( + e) case $boost_ldpath in '') # Nothing to do. boost_cv_rpath_link_ldflag= boost_rpath_link_ldflag_found=yes;; @@ -27527,13 +28197,14 @@ then : boost_rpath_link_ldflag_found=yes break -else $as_nop - if $boost_use_source; then +else case e in #( + e) if $boost_use_source; then printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi - boost_rpath_link_ldflag_found=no + boost_rpath_link_ldflag_found=no ;; +esac fi ac_objext=$boost_save_ac_objext ac_ext=$boost_save_ac_ext @@ -27548,7 +28219,8 @@ fi LDFLAGS=$boost_save_LDFLAGS LIBS=$boost_save_LIBS - + ;; +esac fi test x"$boost_ldpath" != x && @@ -27567,7 +28239,8 @@ done done # boost_lib_ rm -f conftest.$ac_objext - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_filesystem" >&5 printf "%s\n" "$boost_cv_lib_filesystem" >&6; } @@ -27625,8 +28298,9 @@ if test "x$BOOST_FILESYSTEM_LIBS" != "x" then : enable_nod="yes" -else $as_nop - enable_nod="no" +else case e in #( + e) enable_nod="no" ;; +esac fi fi @@ -27668,8 +28342,9 @@ if test ${enable_dnstap+y} then : enableval=$enable_dnstap; enable_dnstap=$enableval -else $as_nop - enable_dnstap=auto +else case e in #( + e) enable_dnstap=auto ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dnstap" >&5 @@ -27801,9 +28476,10 @@ if test ${enable_hardening+y} then : enableval=$enable_hardening; enable_hardening=$enableval -else $as_nop - enable_hardening=yes - +else case e in #( + e) enable_hardening=yes + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5 @@ -27814,8 +28490,8 @@ if test ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -27832,21 +28508,24 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Werror__Wunknown_warning_option=yes -else $as_nop - gl_cv_warn_cxx__Werror__Wunknown_warning_option=no +else case e in #( + e) gl_cv_warn_cxx__Werror__Wunknown_warning_option=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5 printf "%s\n" "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; } if test "x$gl_cv_warn_cxx__Werror__Wunknown_warning_option" = xyes then : gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror' -else $as_nop - gl_unknown_warnings_are_errors= +else case e in #( + e) gl_unknown_warnings_are_errors= ;; +esac fi if test "x$enable_hardening" != "xno" @@ -27866,8 +28545,8 @@ if test ${gl_cv_warn_cxx__pie+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -pie" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -27888,13 +28567,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__pie=yes -else $as_nop - gl_cv_warn_cxx__pie=no +else case e in #( + e) gl_cv_warn_cxx__pie=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__pie" >&5 printf "%s\n" "$gl_cv_warn_cxx__pie" >&6; } @@ -27904,15 +28585,15 @@ PIE_CFLAGS="-fPIE -DPIE" PIE_LDFLAGS="-pie" -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wl,-pie" >&5 printf %s "checking whether C++ compiler handles -Wl,-pie... " >&6; } if test ${gl_cv_warn_cxx__Wl__pie+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wl,-pie" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -27933,13 +28614,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wl__pie=yes -else $as_nop - gl_cv_warn_cxx__Wl__pie=no +else case e in #( + e) gl_cv_warn_cxx__Wl__pie=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wl__pie" >&5 printf "%s\n" "$gl_cv_warn_cxx__Wl__pie" >&6; } @@ -27951,7 +28634,8 @@ fi - + ;; +esac fi esac @@ -27965,8 +28649,8 @@ if test ${gl_cv_warn_cxx__fstack_protector+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fstack-protector" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -27983,13 +28667,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fstack_protector=yes -else $as_nop - gl_cv_warn_cxx__fstack_protector=no +else case e in #( + e) gl_cv_warn_cxx__fstack_protector=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fstack_protector" >&5 printf "%s\n" "$gl_cv_warn_cxx__fstack_protector" >&6; } @@ -28008,8 +28694,8 @@ if test ${gl_cv_warn_cxx___param_ssp_buffer_size_4+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors --param ssp-buffer-size=4" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28026,13 +28712,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx___param_ssp_buffer_size_4=yes -else $as_nop - gl_cv_warn_cxx___param_ssp_buffer_size_4=no +else case e in #( + e) gl_cv_warn_cxx___param_ssp_buffer_size_4=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx___param_ssp_buffer_size_4" >&5 printf "%s\n" "$gl_cv_warn_cxx___param_ssp_buffer_size_4" >&6; } @@ -28050,9 +28738,10 @@ if test ${enable_fortify_source+y} then : enableval=$enable_fortify_source; enable_fortify_source=$enableval -else $as_nop - enable_fortify_source=2 - +else case e in #( + e) enable_fortify_source=2 + ;; +esac fi @@ -28073,8 +28762,8 @@ if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_3+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=3" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28091,13 +28780,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__D_FORTIFY_SOURCE_3=yes -else $as_nop - gl_cv_warn_cxx__D_FORTIFY_SOURCE_3=no +else case e in #( + e) gl_cv_warn_cxx__D_FORTIFY_SOURCE_3=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" >&5 printf "%s\n" "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" >&6; } @@ -28107,8 +28798,9 @@ CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 $CFLAGS" CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 $CXXFLAGS" -else $as_nop - enable_fortify_source=2 +else case e in #( + e) enable_fortify_source=2 ;; +esac fi @@ -28122,8 +28814,8 @@ if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_2+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=2" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28140,13 +28832,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=yes -else $as_nop - gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=no +else case e in #( + e) gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&5 printf "%s\n" "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&6; } @@ -28156,8 +28850,9 @@ CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS" CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CXXFLAGS" -else $as_nop - enable_fortify_source=1 +else case e in #( + e) enable_fortify_source=1 ;; +esac fi @@ -28171,8 +28866,8 @@ if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=1" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28189,13 +28884,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__D_FORTIFY_SOURCE_1=yes -else $as_nop - gl_cv_warn_cxx__D_FORTIFY_SOURCE_1=no +else case e in #( + e) gl_cv_warn_cxx__D_FORTIFY_SOURCE_1=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" >&5 printf "%s\n" "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" >&6; } @@ -28205,8 +28902,9 @@ CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 $CFLAGS" CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 $CXXFLAGS" -else $as_nop - enable_fortify_source=no +else case e in #( + e) enable_fortify_source=no ;; +esac fi @@ -28237,10 +28935,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RELRO_LDFLAGS" >&5 printf "%s\n" "$RELRO_LDFLAGS" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 printf "%s\n" "unknown" >&6; } - + ;; +esac fi @@ -28253,8 +28952,9 @@ if test ${enable_auto_var_init+y} then : enableval=$enable_auto_var_init; enable_initautovars=$enableval -else $as_nop - enable_initautovars=no +else case e in #( + e) enable_initautovars=no ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_initautovars" >&5 @@ -28275,8 +28975,8 @@ if test ${gl_cv_warn_cxx__ftrivial_auto_var_init_zero+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -ftrivial-auto-var-init=zero" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28293,13 +28993,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__ftrivial_auto_var_init_zero=yes -else $as_nop - gl_cv_warn_cxx__ftrivial_auto_var_init_zero=no +else case e in #( + e) gl_cv_warn_cxx__ftrivial_auto_var_init_zero=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__ftrivial_auto_var_init_zero" >&5 printf "%s\n" "$gl_cv_warn_cxx__ftrivial_auto_var_init_zero" >&6; } @@ -28322,8 +29024,8 @@ if test ${gl_cv_warn_cxx__ftrivial_auto_var_init_pattern+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -ftrivial-auto-var-init=pattern" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28340,13 +29042,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__ftrivial_auto_var_init_pattern=yes -else $as_nop - gl_cv_warn_cxx__ftrivial_auto_var_init_pattern=no +else case e in #( + e) gl_cv_warn_cxx__ftrivial_auto_var_init_pattern=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" >&5 printf "%s\n" "$gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" >&6; } @@ -28370,9 +29074,10 @@ if test ${enable_asan+y} then : enableval=$enable_asan; enable_asan=$enableval -else $as_nop - enable_asan=no - +else case e in #( + e) enable_asan=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_asan" >&5 @@ -28386,8 +29091,8 @@ if test ${gl_cv_warn_cxx__fsanitize_address+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=address" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28404,13 +29109,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fsanitize_address=yes -else $as_nop - gl_cv_warn_cxx__fsanitize_address=no +else case e in #( + e) gl_cv_warn_cxx__fsanitize_address=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_address" >&5 printf "%s\n" "$gl_cv_warn_cxx__fsanitize_address" >&6; } @@ -28425,8 +29132,9 @@ then : printf "%s\n" "#define HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H 1" >>confdefs.h asan_headers=yes -else $as_nop - asan_headers=no +else case e in #( + e) asan_headers=no ;; +esac fi done @@ -28467,8 +29175,8 @@ printf "%s\n" "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR 1" >>confdefs.h -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -28496,24 +29204,27 @@ printf "%s\n" "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS 1" >>confdefs.h -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 printf "%s\n" "unknown" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available due to an unknown API version" >&5 printf "%s\n" "$as_me: ASAN fiber switching is not available due to an unknown API version" >&6;} - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available" >&5 printf "%s\n" "$as_me: ASAN fiber switching is not available" >&6;} - + ;; +esac fi fi @@ -28530,9 +29241,10 @@ done -else $as_nop - as_fn_error $? "Cannot enable AddressSanitizer" "$LINENO" 5 - +else case e in #( + e) as_fn_error $? "Cannot enable AddressSanitizer" "$LINENO" 5 + ;; +esac fi @@ -28547,9 +29259,10 @@ if test ${enable_msan+y} then : enableval=$enable_msan; enable_msan=$enableval -else $as_nop - enable_msan=no - +else case e in #( + e) enable_msan=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_msan" >&5 @@ -28563,8 +29276,8 @@ if test ${gl_cv_warn_cxx__fsanitize_memory+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=memory" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28581,22 +29294,25 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fsanitize_memory=yes -else $as_nop - gl_cv_warn_cxx__fsanitize_memory=no +else case e in #( + e) gl_cv_warn_cxx__fsanitize_memory=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_memory" >&5 printf "%s\n" "$gl_cv_warn_cxx__fsanitize_memory" >&6; } if test "x$gl_cv_warn_cxx__fsanitize_memory" = xyes then : SANITIZER_FLAGS="-fsanitize=memory $SANITIZER_FLAGS" -else $as_nop - as_fn_error $? "Cannot enable MemorySanitizer" "$LINENO" 5 - +else case e in #( + e) as_fn_error $? "Cannot enable MemorySanitizer" "$LINENO" 5 + ;; +esac fi @@ -28611,9 +29327,10 @@ if test ${enable_tsan+y} then : enableval=$enable_tsan; enable_tsan=$enableval -else $as_nop - enable_tsan=no - +else case e in #( + e) enable_tsan=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_tsan" >&5 @@ -28627,8 +29344,8 @@ if test ${gl_cv_warn_cxx__fsanitize_thread+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=thread" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28645,22 +29362,25 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fsanitize_thread=yes -else $as_nop - gl_cv_warn_cxx__fsanitize_thread=no +else case e in #( + e) gl_cv_warn_cxx__fsanitize_thread=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_thread" >&5 printf "%s\n" "$gl_cv_warn_cxx__fsanitize_thread" >&6; } if test "x$gl_cv_warn_cxx__fsanitize_thread" = xyes then : SANITIZER_FLAGS="-fsanitize=thread $SANITIZER_FLAGS" -else $as_nop - as_fn_error $? "Cannot enable ThreadSanitizer" "$LINENO" 5 - +else case e in #( + e) as_fn_error $? "Cannot enable ThreadSanitizer" "$LINENO" 5 + ;; +esac fi @@ -28675,9 +29395,10 @@ if test ${enable_lsan+y} then : enableval=$enable_lsan; enable_lsan=$enableval -else $as_nop - enable_lsan=no - +else case e in #( + e) enable_lsan=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_lsan" >&5 @@ -28691,8 +29412,8 @@ if test ${gl_cv_warn_cxx__fsanitize_leak+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=leak" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28709,22 +29430,25 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fsanitize_leak=yes -else $as_nop - gl_cv_warn_cxx__fsanitize_leak=no +else case e in #( + e) gl_cv_warn_cxx__fsanitize_leak=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_leak" >&5 printf "%s\n" "$gl_cv_warn_cxx__fsanitize_leak" >&6; } if test "x$gl_cv_warn_cxx__fsanitize_leak" = xyes then : SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS" -else $as_nop - as_fn_error $? "Cannot enable LeakSanitizer" "$LINENO" 5 - +else case e in #( + e) as_fn_error $? "Cannot enable LeakSanitizer" "$LINENO" 5 + ;; +esac fi for ac_header in sanitizer/lsan_interface.h @@ -28751,9 +29475,10 @@ if test ${enable_ubsan+y} then : enableval=$enable_ubsan; enable_ubsan=$enableval -else $as_nop - enable_ubsan=no - +else case e in #( + e) enable_ubsan=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_ubsan" >&5 @@ -28767,8 +29492,8 @@ if test ${gl_cv_warn_cxx__fsanitize_undefined+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=undefined" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28785,22 +29510,25 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fsanitize_undefined=yes -else $as_nop - gl_cv_warn_cxx__fsanitize_undefined=no +else case e in #( + e) gl_cv_warn_cxx__fsanitize_undefined=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_undefined" >&5 printf "%s\n" "$gl_cv_warn_cxx__fsanitize_undefined" >&6; } if test "x$gl_cv_warn_cxx__fsanitize_undefined" = xyes then : SANITIZER_FLAGS="-fsanitize=undefined $SANITIZER_FLAGS" -else $as_nop - as_fn_error $? "Cannot enable Undefined Behaviour Sanitizer" "$LINENO" 5 - +else case e in #( + e) as_fn_error $? "Cannot enable Undefined Behaviour Sanitizer" "$LINENO" 5 + ;; +esac fi @@ -28845,8 +29573,8 @@ if test ${gl_cv_warn_cxx__fno_omit_frame_pointer+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fno-omit-frame-pointer" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28863,13 +29591,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fno_omit_frame_pointer=yes -else $as_nop - gl_cv_warn_cxx__fno_omit_frame_pointer=no +else case e in #( + e) gl_cv_warn_cxx__fno_omit_frame_pointer=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_omit_frame_pointer" >&5 printf "%s\n" "$gl_cv_warn_cxx__fno_omit_frame_pointer" >&6; } @@ -28887,9 +29617,10 @@ if test ${enable_lto+y} then : enableval=$enable_lto; enable_lto=$enableval -else $as_nop - enable_lto=no - +else case e in #( + e) enable_lto=no + ;; +esac fi @@ -28905,8 +29636,8 @@ if test ${gl_cv_warn_cxx__flto_thin+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto=thin" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28923,13 +29654,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__flto_thin=yes -else $as_nop - gl_cv_warn_cxx__flto_thin=no +else case e in #( + e) gl_cv_warn_cxx__flto_thin=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto_thin" >&5 printf "%s\n" "$gl_cv_warn_cxx__flto_thin" >&6; } @@ -28940,8 +29673,9 @@ CXXFLAGS="-flto=thin $CXXFLAGS" LDFLAGS="-flto=thin $LDFLAGS" -else $as_nop - enable_lto=auto +else case e in #( + e) enable_lto=auto ;; +esac fi @@ -28955,8 +29689,8 @@ if test ${gl_cv_warn_cxx__flto_auto+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto=auto" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28973,13 +29707,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__flto_auto=yes -else $as_nop - gl_cv_warn_cxx__flto_auto=no +else case e in #( + e) gl_cv_warn_cxx__flto_auto=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto_auto" >&5 printf "%s\n" "$gl_cv_warn_cxx__flto_auto" >&6; } @@ -28990,8 +29726,9 @@ CXXFLAGS="-flto=auto $CXXFLAGS" LDFLAGS="-flto=auto $LDFLAGS" -else $as_nop - enable_lto=yes +else case e in #( + e) enable_lto=yes ;; +esac fi @@ -29005,8 +29742,8 @@ if test ${gl_cv_warn_cxx__flto+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -29023,13 +29760,15 @@ if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__flto=yes -else $as_nop - gl_cv_warn_cxx__flto=no +else case e in #( + e) gl_cv_warn_cxx__flto=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto" >&5 printf "%s\n" "$gl_cv_warn_cxx__flto" >&6; } @@ -29040,8 +29779,9 @@ CXXFLAGS="-flto $CXXFLAGS" LDFLAGS="-flto $LDFLAGS" -else $as_nop - enable_lto=no +else case e in #( + e) enable_lto=no ;; +esac fi @@ -29061,9 +29801,10 @@ if test ${enable_malloc_trace+y} then : enableval=$enable_malloc_trace; enable_malloc_trace=$enableval -else $as_nop - enable_malloc_trace=no - +else case e in #( + e) enable_malloc_trace=no + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_malloc_trace" >&5 @@ -29090,8 +29831,9 @@ if test ${enable_valgrind+y} then : enableval=$enable_valgrind; enable_valgrind=$enableval -else $as_nop - enable_valgrind=no +else case e in #( + e) enable_valgrind=no ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_valgrind" >&5 @@ -29110,8 +29852,9 @@ then : printf "%s\n" "#define HAVE_VALGRIND_VALGRIND_H 1" >>confdefs.h valgrind_headers=yes -else $as_nop - valgrind_headers=no +else case e in #( + e) valgrind_headers=no ;; +esac fi done @@ -29181,8 +29924,9 @@ if test ${with_systemd+y} then : withval=$with_systemd; SYSTEMD_DIR="$withval" -else $as_nop - SYSTEMD_DIR="" +else case e in #( + e) SYSTEMD_DIR="" ;; +esac fi @@ -29192,8 +29936,9 @@ if test ${with_systemd+y} then : withval=$with_systemd; SYSTEMD_MODULES_LOAD="$withval" -else $as_nop - SYSTEMD_MODULES_LOAD="" +else case e in #( + e) SYSTEMD_MODULES_LOAD="" ;; +esac fi @@ -29205,14 +29950,14 @@ then : for libname in systemd-daemon systemd; do - as_ac_Lib=`printf "%s\n" "ac_cv_lib_$libname""_sd_listen_fds" | $as_tr_sh` + as_ac_Lib=`printf "%s\n" "ac_cv_lib_$libname""_sd_listen_fds" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sd_listen_fds in -l$libname" >&5 printf %s "checking for sd_listen_fds in -l$libname... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-l$libname $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -29231,12 +29976,14 @@ if ac_fn_cxx_try_link "$LINENO" then : eval "$as_ac_Lib=yes" -else $as_nop - eval "$as_ac_Lib=no" +else case e in #( + e) eval "$as_ac_Lib=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -29347,8 +30094,8 @@ elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -29358,7 +30105,7 @@ See the pkg-config man page for more details. To get pkg-config, see . -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } else SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS @@ -29398,12 +30145,14 @@ fi -else $as_nop - systemd=n +else case e in #( + e) systemd=n ;; +esac fi -else $as_nop - systemd=n +else case e in #( + e) systemd=n ;; +esac fi @@ -29418,8 +30167,8 @@ if test ${ac_cv_path_SYSTEMCTL+y} then : printf %s "(cached) " >&6 -else $as_nop - case $SYSTEMCTL in +else case e in #( + e) case $SYSTEMCTL in [\\/]* | ?:[\\/]*) ac_cv_path_SYSTEMCTL="$SYSTEMCTL" # Let the user override the test with a path. ;; @@ -29445,6 +30194,7 @@ test -z "$ac_cv_path_SYSTEMCTL" && ac_cv_path_SYSTEMCTL="no" ;; +esac ;; esac fi SYSTEMCTL=$ac_cv_path_SYSTEMCTL @@ -29460,8 +30210,8 @@ if test "$SYSTEMCTL" = "no" then : as_fn_error $? "systemctl not found" "$LINENO" 5 -else $as_nop - +else case e in #( + e) _systemd_version=`${SYSTEMCTL} --version|head -1 | tr ".~" " " | cut -d" " -f 2` if test $_systemd_version -ge 183; then systemd_private_tmp=y @@ -29527,7 +30277,8 @@ if test $_systemd_version -ge 248; then systemd_private_ipc=y fi - + ;; +esac fi fi @@ -29765,10 +30516,11 @@ then : withval=$with_service_user; service_user=$withval -else $as_nop - service_user=pdns-recursor - +else case e in #( + e) service_user=pdns-recursor + ;; +esac fi @@ -29778,18 +30530,20 @@ then : withval=$with_service_group; service_group=$withval -else $as_nop - service_group=pdns-recursor - +else case e in #( + e) service_group=pdns-recursor + ;; +esac fi if test -z "$service_user" then : as_fn_error $? "No service user has been defined!" "$LINENO" 5 -else $as_nop - : +else case e in #( + e) : ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $service_user" >&5 printf "%s\n" "$service_user" >&6; } @@ -29823,10 +30577,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - as_fn_error $? "Python interpreter is too old" "$LINENO" 5 + as_fn_error $? "Python interpreter is too old" "$LINENO" 5 ;; +esac fi am_display_PYTHON=$PYTHON else @@ -29837,9 +30592,9 @@ if test ${am_cv_pathless_PYTHON+y} then : printf %s "(cached) " >&6 -else $as_nop - - for am_cv_pathless_PYTHON in python python2 python3 python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do +else case e in #( + e) + for am_cv_pathless_PYTHON in python python3 python3.20 python3.19 python3.18 python3.17 python3.16 python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do test "$am_cv_pathless_PYTHON" = none && break prog="import sys # split strings by '.' and convert to numeric. Append some zeros @@ -29858,7 +30613,8 @@ then : break fi - done + done ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 printf "%s\n" "$am_cv_pathless_PYTHON" >&6; } @@ -29873,8 +30629,8 @@ if test ${ac_cv_path_PYTHON+y} then : printf %s "(cached) " >&6 -else $as_nop - case $PYTHON in +else case e in #( + e) case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; @@ -29899,6 +30655,7 @@ IFS=$as_save_IFS ;; +esac ;; esac fi PYTHON=$ac_cv_path_PYTHON @@ -29925,8 +30682,9 @@ if test ${am_cv_python_version+y} then : printf %s "(cached) " >&6 -else $as_nop - am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[:2])"` +else case e in #( + e) am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[:2])"` ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 printf "%s\n" "$am_cv_python_version" >&6; } @@ -29938,8 +30696,9 @@ if test ${am_cv_python_platform+y} then : printf %s "(cached) " >&6 -else $as_nop - am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` +else case e in #( + e) am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 printf "%s\n" "$am_cv_python_platform" >&6; } @@ -29959,8 +30718,9 @@ if test ${with_python_sys_prefix+y} then : withval=$with_python_sys_prefix; am_use_python_sys=: -else $as_nop - am_use_python_sys=false +else case e in #( + e) am_use_python_sys=false ;; +esac fi @@ -29975,8 +30735,8 @@ printf %s "checking for explicit $am_display_PYTHON prefix... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_prefix" >&5 printf "%s\n" "$am_cv_python_prefix" >&6; } -else $as_nop - +else case e in #( + e) if $am_use_python_sys; then # using python sys.prefix value, not GNU { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for python default $am_display_PYTHON prefix" >&5 @@ -29984,8 +30744,9 @@ if test ${am_cv_python_prefix+y} then : printf %s "(cached) " >&6 -else $as_nop - am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"` +else case e in #( + e) am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"` ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_prefix" >&5 printf "%s\n" "$am_cv_python_prefix" >&6; } @@ -30006,7 +30767,8 @@ printf %s "checking for GNU default $am_display_PYTHON prefix... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_python_prefix" >&5 printf "%s\n" "$am_python_prefix" >&6; } - fi + fi ;; +esac fi # Substituting python_prefix_subst value. @@ -30025,8 +30787,8 @@ printf %s "checking for explicit $am_display_PYTHON exec_prefix... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5 printf "%s\n" "$am_cv_python_exec_prefix" >&6; } -else $as_nop - +else case e in #( + e) # no explicit --with-python_exec_prefix, but if # --with-python_prefix was given, use its value for python_exec_prefix too. if test -n "$with_python_prefix" @@ -30037,8 +30799,8 @@ printf %s "checking for python_prefix-given $am_display_PYTHON exec_prefix... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5 printf "%s\n" "$am_cv_python_exec_prefix" >&6; } -else $as_nop - +else case e in #( + e) # Set am__usable_exec_prefix whether using GNU or Python values, # since we use that variable for pyexecdir. if test "x$exec_prefix" = xNONE; then @@ -30053,8 +30815,9 @@ if test ${am_cv_python_exec_prefix+y} then : printf %s "(cached) " >&6 -else $as_nop - am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"` +else case e in #( + e) am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"` ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5 printf "%s\n" "$am_cv_python_exec_prefix" >&6; } @@ -30074,8 +30837,10 @@ printf %s "checking for GNU default $am_display_PYTHON exec_prefix... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_python_exec_prefix" >&5 printf "%s\n" "$am_python_exec_prefix" >&6; } - fi -fi + fi ;; +esac +fi ;; +esac fi # Substituting python_exec_prefix_subst. @@ -30100,7 +30865,21 @@ if python_implementation() == 'CPython' and sys.version[:3] == '2.7': can_use_sysconfig = 0 except ImportError: - pass" + pass" # end of am_python_setup_sysconfig + + # More repeated code, for figuring out the installation scheme to use. + am_python_setup_scheme="if hasattr(sysconfig, 'get_default_scheme'): + scheme = sysconfig.get_default_scheme() + else: + scheme = sysconfig._get_default_scheme() + if scheme == 'posix_local': + if '$am_py_prefix' == '/usr': + scheme = 'deb_system' # should only happen during Debian package builds + else: + # Debian's default scheme installs to /usr/local/ but we want to + # follow the prefix, as we always have. + # See bugs#54412, #64837, et al. + scheme = 'posix_prefix'" # end of am_python_setup_scheme { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory (pythondir)" >&5 @@ -30108,8 +30887,8 @@ if test ${am_cv_python_pythondir+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "x$am_cv_python_prefix" = x; then +else case e in #( + e) if test "x$am_cv_python_prefix" = x; then am_py_prefix=$am__usable_prefix else am_py_prefix=$am_cv_python_prefix @@ -30117,7 +30896,11 @@ am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: - sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) + try: + $am_python_setup_scheme + sitedir = sysconfig.get_path('purelib', scheme, vars={'base':'$am_py_prefix'}) + except: + sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') @@ -30136,7 +30919,8 @@ esac ;; esac - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 printf "%s\n" "$am_cv_python_pythondir" >&6; } @@ -30146,13 +30930,13 @@ pkgpythondir=\${pythondir}/$PACKAGE - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory (pyexecdir)" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory (pyexecdir)" >&5 printf %s "checking for $am_display_PYTHON extension module directory (pyexecdir)... " >&6; } if test ${am_cv_python_pyexecdir+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "x$am_cv_python_exec_prefix" = x; then +else case e in #( + e) if test "x$am_cv_python_exec_prefix" = x; then am_py_exec_prefix=$am__usable_exec_prefix else am_py_exec_prefix=$am_cv_python_exec_prefix @@ -30160,7 +30944,11 @@ am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: - sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'}) + try: + $am_python_setup_scheme + sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase':'$am_py_exec_prefix'}) + except: + sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix') @@ -30179,7 +30967,8 @@ esac ;; esac - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 printf "%s\n" "$am_cv_python_pyexecdir" >&6; } @@ -30279,7 +31068,7 @@ CCVERSION=`$CC --version | head -1` CXXVERSION=`$CXX --version | head -1` -ac_config_files="$ac_config_files Makefile ext/Makefile ext/arc4random/Makefile ext/json11/Makefile ext/probds/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile settings/Makefile settings/rust/Makefile" +ac_config_files="$ac_config_files Makefile ext/Makefile ext/arc4random/Makefile ext/json11/Makefile ext/probds/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile rec-rust-lib/Makefile rec-rust-lib/rust/Makefile" cat >confcache <<\_ACEOF @@ -30292,8 +31081,8 @@ # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the +# 'ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF @@ -30323,14 +31112,14 @@ (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote + # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) - # `set' quotes correctly as required by POSIX, so do not add quotes. + # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | @@ -30399,6 +31188,18 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; +esac +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi + if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' @@ -30652,7 +31453,6 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -30661,12 +31461,13 @@ # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -30738,7 +31539,7 @@ ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -30767,7 +31568,6 @@ } # as_fn_error - # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -30807,11 +31607,12 @@ { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -30825,11 +31626,12 @@ { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith @@ -30912,9 +31714,9 @@ if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -30995,10 +31797,12 @@ as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 @@ -31013,8 +31817,8 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pdns-recursor $as_me 5.2.13, which was -generated by GNU Autoconf 2.71. Invocation command line was +This file was extended by pdns-recursor $as_me 5.4.9, which was +generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -31046,7 +31850,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions +'$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -31081,11 +31885,11 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -pdns-recursor config.status 5.2.13 -configured by $0, generated by GNU Autoconf 2.71, +pdns-recursor config.status 5.4.9 +configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -31147,8 +31951,8 @@ ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; + as_fn_error $? "ambiguous option: '$1' +Try '$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ @@ -31156,8 +31960,8 @@ ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -31603,10 +32407,10 @@ "ext/probds/Makefile") CONFIG_FILES="$CONFIG_FILES ext/probds/Makefile" ;; "ext/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/Makefile" ;; "ext/yahttp/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/yahttp/Makefile" ;; - "settings/Makefile") CONFIG_FILES="$CONFIG_FILES settings/Makefile" ;; - "settings/rust/Makefile") CONFIG_FILES="$CONFIG_FILES settings/rust/Makefile" ;; + "rec-rust-lib/Makefile") CONFIG_FILES="$CONFIG_FILES rec-rust-lib/Makefile" ;; + "rec-rust-lib/rust/Makefile") CONFIG_FILES="$CONFIG_FILES rec-rust-lib/rust/Makefile" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done @@ -31626,7 +32430,7 @@ # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. +# after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= @@ -31650,7 +32454,7 @@ # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. +# This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then @@ -31808,13 +32612,13 @@ # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. +# This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF -# Transform confdefs.h into an awk script `defines.awk', embedded as +# Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. @@ -31924,7 +32728,7 @@ esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -31946,19 +32750,19 @@ -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. + # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is `configure' which instantiates (i.e., don't + # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` @@ -32091,7 +32895,7 @@ esac _ACEOF -# Neutralize VPATH when `$srcdir' = `.'. +# Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -32122,9 +32926,9 @@ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -32279,15 +33083,15 @@ (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} @@ -33063,9 +33867,10 @@ if test "x$pdns_configure_args" != "x" then : summary_conf_opts=$pdns_configure_args -else $as_nop - summary_conf_opts="(no options)" - +else case e in #( + e) summary_conf_opts="(no options)" + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: PowerDNS Recursor $VERSION configured with: $summary_conf_opts" >&5 printf "%s\n" "$as_me: PowerDNS Recursor $VERSION configured with: $summary_conf_opts" >&6;} @@ -33103,19 +33908,21 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed25519: yes" >&5 printf "%s\n" "$as_me: ed25519: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed25519: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed25519: no" >&5 printf "%s\n" "$as_me: ed25519: no" >&6;} - + ;; +esac fi if test "x$libcrypto_ed448" = "xyes" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed448: yes" >&5 printf "%s\n" "$as_me: ed448: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed448: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ed448: no" >&5 printf "%s\n" "$as_me: ed448: no" >&6;} - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Protobuf: yes" >&5 @@ -33125,19 +33932,21 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: SNMP: yes" >&5 printf "%s\n" "$as_me: SNMP: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: SNMP: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: SNMP: no" >&5 printf "%s\n" "$as_me: SNMP: no" >&6;} - + ;; +esac fi if test "x$systemd" != "xn" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: systemd: yes" >&5 printf "%s\n" "$as_me: systemd: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: systemd: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: systemd: no" >&5 printf "%s\n" "$as_me: systemd: no" >&6;} - + ;; +esac fi if test -z "$NOD_ENABLED_TRUE"; then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: nod: yes" >&5 @@ -33159,10 +33968,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over TLS: yes" >&5 printf "%s\n" "$as_me: DNS over TLS: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over TLS: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over TLS: no" >&5 printf "%s\n" "$as_me: DNS over TLS: no" >&6;} - + ;; +esac fi #AS_IF([test "x$enable_dns_over_tls" != "xno"], [ # AS_IF([test "x$GNUTLS_LIBS" != "x"], @@ -33177,10 +33987,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL: yes" >&5 printf "%s\n" "$as_me: OpenSSL: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL: no" >&5 printf "%s\n" "$as_me: OpenSSL: no" >&6;} - + ;; +esac fi fi @@ -33188,10 +33999,11 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libcurl: yes" >&5 printf "%s\n" "$as_me: libcurl: yes" >&6;} -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libcurl: no" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libcurl: no" >&5 printf "%s\n" "$as_me: libcurl: no" >&6;} - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5 printf "%s\n" "$as_me: " >&6;} diff -Nru pdns-recursor-5.2.13/configure.ac pdns-recursor-5.4.9/configure.ac --- pdns-recursor-5.2.13/configure.ac 2026-08-05 12:01:36.000000000 +0000 +++ pdns-recursor-5.4.9/configure.ac 2026-10-26 09:47:03.633207300 +0000 @@ -1,6 +1,6 @@ AC_PREREQ([2.69]) -AC_INIT([pdns-recursor], [5.2.13]) +AC_INIT([pdns-recursor], [5.4.9]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip tar-ustar -Wno-portability subdir-objects parallel-tests 1.11]) AM_SILENT_RULES([yes]) @@ -27,9 +27,7 @@ PDNS_CHECK_TIME_T -AC_DEFINE([RECURSOR], [1], - [This is the PowerDNS Recursor] -) +CPPFLAGS="-DRECURSOR $CPPFLAGS" # Warn when pkg.m4 is missing m4_pattern_forbid([^_?PKG_[A-Z_]+$], [*** pkg.m4 missing, please install pkg-config]) @@ -58,7 +56,7 @@ PDNS_ENABLE_REPRODUCIBLE PDNS_ENABLE_COVERAGE -PDNS_WITH_LUA([mandatory]) +PDNS_WITH_LUA AS_IF([test "x$LUAPC" = "xluajit"], [ # export all symbols to be able to use the Lua FFI interface AC_MSG_NOTICE([Adding -rdynamic to export all symbols for the Lua FFI interface]) @@ -105,7 +103,7 @@ dnl the *_r functions are in posix so we can use them unconditionally, but the ext/yahttp code is dnl using the defines. -AC_CHECK_FUNCS_ONCE([localtime_r gmtime_r strcasestr]) +AC_CHECK_FUNCS_ONCE([localtime_r gmtime_r]) AC_CHECK_FUNCS_ONCE([getrandom getentropy arc4random arc4random_uniform arc4random_buf]) PDNS_CHECK_SECURE_MEMSET @@ -192,8 +190,8 @@ ext/probds/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile - settings/Makefile - settings/rust/Makefile]) + rec-rust-lib/Makefile + rec-rust-lib/rust/Makefile]) AC_OUTPUT diff -Nru pdns-recursor-5.2.13/credentials.cc pdns-recursor-5.4.9/credentials.cc --- pdns-recursor-5.2.13/credentials.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/credentials.cc 2026-10-26 09:46:36.000000000 +0000 @@ -106,10 +106,11 @@ } // OpenSSL 3.0 changed the string arg to const unsigned char*, other versions use const char * + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) #if OPENSSL_VERSION_MAJOR >= 3 - auto passwordData = reinterpret_cast(password.data()); + const auto* passwordData = reinterpret_cast(password.data()); #else - auto passwordData = reinterpret_cast(password.data()); + const auto* passwordData = reinterpret_cast(password.data()); #endif if (EVP_PKEY_CTX_set1_pbe_pass(pctx.get(), passwordData, password.size()) <= 0) { throw std::runtime_error("Error adding the password to the scrypt context to hash the supplied password"); @@ -118,6 +119,7 @@ if (EVP_PKEY_CTX_set1_scrypt_salt(pctx.get(), reinterpret_cast(salt.data()), salt.size()) <= 0) { throw std::runtime_error("Error adding the salt to the scrypt context to hash the supplied password"); } + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) if (EVP_PKEY_CTX_set_scrypt_N(pctx.get(), workFactor) <= 0) { throw std::runtime_error("Error setting the work factor to the scrypt context to hash the supplied password"); @@ -135,6 +137,7 @@ out.resize(pwhash_output_size); size_t outlen = out.size(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) if (EVP_PKEY_derive(pctx.get(), reinterpret_cast(out.data()), &outlen) <= 0 || outlen != pwhash_output_size) { throw std::runtime_error("Error deriving the output from the scrypt context to hash the supplied password"); } @@ -152,7 +155,8 @@ std::string salt; salt.resize(pwhash_salt_size); - if (RAND_bytes(reinterpret_cast(salt.data()), salt.size()) != 1) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + if (RAND_bytes(reinterpret_cast(salt.data()), static_cast(salt.size())) != 1) { throw std::runtime_error("Error while generating a salt to hash the supplied password"); } @@ -371,6 +375,7 @@ if (!d_isHashed) { d_fallbackHashPerturb = dns_random_uint32(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) d_fallbackHash = burtle(reinterpret_cast(d_credentials.getString().data()), d_credentials.getString().size(), d_fallbackHashPerturb); } } @@ -386,14 +391,13 @@ if (d_isHashed) { return verifyPassword(d_credentials.getString(), d_salt, d_workFactor, d_parallelFactor, d_blockSize, password); } - else { - uint32_t fallback = burtle(reinterpret_cast(password.data()), password.size(), d_fallbackHashPerturb); - if (fallback != d_fallbackHash) { - return false; - } - - return constantTimeStringEquals(password, d_credentials.getString()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + uint32_t fallback = burtle(reinterpret_cast(password.data()), password.size(), d_fallbackHashPerturb); + if (fallback != d_fallbackHash) { + return false; } + + return constantTimeStringEquals(password, d_credentials.getString()); } bool CredentialsHolder::isHashingAvailable() @@ -410,8 +414,8 @@ SensitiveData CredentialsHolder::readFromTerminal() { - struct termios term; - struct termios oterm; + termios term{}; + termios oterm{}; bool restoreTermSettings = false; int termAction = TCSAFLUSH; #ifdef TCSASOFT @@ -438,19 +442,20 @@ } struct std::map signals; - struct sigaction sa; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = [](int /* s */) {}; - sigaction(SIGALRM, &sa, &signals[SIGALRM]); - sigaction(SIGHUP, &sa, &signals[SIGHUP]); - sigaction(SIGINT, &sa, &signals[SIGINT]); - sigaction(SIGPIPE, &sa, &signals[SIGPIPE]); - sigaction(SIGQUIT, &sa, &signals[SIGQUIT]); - sigaction(SIGTERM, &sa, &signals[SIGTERM]); - sigaction(SIGTSTP, &sa, &signals[SIGTSTP]); - sigaction(SIGTTIN, &sa, &signals[SIGTTIN]); - sigaction(SIGTTOU, &sa, &signals[SIGTTOU]); + struct sigaction sigact // just sigaction does not work, it clashes with sigaction(2) + {}; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigact.sa_handler = [](int /* s */) {}; + sigaction(SIGALRM, &sigact, &signals[SIGALRM]); + sigaction(SIGHUP, &sigact, &signals[SIGHUP]); + sigaction(SIGINT, &sigact, &signals[SIGINT]); + sigaction(SIGPIPE, &sigact, &signals[SIGPIPE]); + sigaction(SIGQUIT, &sigact, &signals[SIGQUIT]); + sigaction(SIGTERM, &sigact, &signals[SIGTERM]); + sigaction(SIGTSTP, &sigact, &signals[SIGTSTP]); + sigaction(SIGTTIN, &sigact, &signals[SIGTTIN]); + sigaction(SIGTTOU, &sigact, &signals[SIGTTOU]); std::string buffer; /* let's allocate a huge buffer now to prevent reallocation, @@ -458,10 +463,10 @@ buffer.reserve(512); for (;;) { - char ch = '\0'; - auto got = read(input, &ch, 1); - if (got == 1 && ch != '\n' && ch != '\r') { - buffer.push_back(ch); + char character = '\0'; + auto got = read(input, &character, 1); + if (got == 1 && character != '\n' && character != '\r') { + buffer.push_back(character); } else { break; @@ -476,5 +481,5 @@ sigaction(sig.first, &sig.second, nullptr); } - return SensitiveData(std::move(buffer)); + return {std::move(buffer)}; } diff -Nru pdns-recursor-5.2.13/credentials.hh pdns-recursor-5.4.9/credentials.hh --- pdns-recursor-5.2.13/credentials.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/credentials.hh 2026-10-26 09:46:36.000000000 +0000 @@ -27,13 +27,16 @@ class SensitiveData { public: + SensitiveData(const SensitiveData&) = delete; + SensitiveData(SensitiveData&&) = delete; + SensitiveData& operator=(const SensitiveData&) = delete; SensitiveData(size_t bytes); SensitiveData(std::string&& data); SensitiveData& operator=(SensitiveData&&) noexcept; ~SensitiveData(); void clear(); - const std::string& getString() const + [[nodiscard]] const std::string& getString() const { return d_data; } @@ -55,10 +58,12 @@ class CredentialsHolder { public: + CredentialsHolder(CredentialsHolder&&) = delete; + CredentialsHolder& operator=(CredentialsHolder&&) = delete; /* if hashPlaintext is true, the password is in cleartext and hashing is available, the hashed form will be kept in memory. Note that accepting hashed password from an untrusted source might open - us to a denial of service, since we currently don't cap the the parameters, + us to a denial of service, since we currently don't cap the parameters, including the work factor */ CredentialsHolder(std::string&& password, bool hashPlaintext); ~CredentialsHolder(); @@ -66,14 +71,14 @@ CredentialsHolder(const CredentialsHolder&) = delete; CredentialsHolder& operator=(const CredentialsHolder&) = delete; - bool matches(const std::string& password) const; + [[nodiscard]] bool matches(const std::string& password) const; /* whether it was constructed from a hashed and salted string */ - bool wasHashed() const + [[nodiscard]] bool wasHashed() const { return d_wasHashed; } /* whether it is hashed in memory */ - bool isHashed() const + [[nodiscard]] bool isHashed() const { return d_isHashed; } diff -Nru pdns-recursor-5.2.13/debian/.gitlab-ci.yml pdns-recursor-5.4.9/debian/.gitlab-ci.yml --- pdns-recursor-5.2.13/debian/.gitlab-ci.yml 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/.gitlab-ci.yml 2026-10-26 13:54:29.000000000 +0000 @@ -5,6 +5,7 @@ variables: RELEASE: 'unstable' SALSA_CI_DISABLE_APTLY: 1 + SALSA_CI_DISABLE_BLHC: 1 SALSA_CI_DISABLE_PIUPARTS: 1 SALSA_CI_DISABLE_REPROTEST: 1 SALSA_CI_DISABLE_BUILD_PACKAGE_ALL: 1 diff -Nru pdns-recursor-5.2.13/debian/changelog pdns-recursor-5.4.9/debian/changelog --- pdns-recursor-5.2.13/debian/changelog 2026-08-07 08:18:12.000000000 +0000 +++ pdns-recursor-5.4.9/debian/changelog 2026-10-26 17:32:14.000000000 +0000 @@ -1,61 +1,179 @@ -pdns-recursor (5.2.13-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.9-1~deb13u1) trixie-security; urgency=medium - * New upstream version 5.2.13, fixing security issue - CVE-2026-52682 + * Target trixie. + * Revert "Build with lld 22, matching rustc LLVM 22 usage" + * Revert "Enable LTO" + * Relax cargo dependencies for trixie - -- Chris Hofstaedtler Fri, 07 Aug 2026 10:18:12 +0200 + -- Chris Hofstaedtler Mon, 26 Oct 2026 18:32:14 +0100 -pdns-recursor (5.2.12-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.9-1) unstable; urgency=medium - * New upstream version 5.2.12, fixing security issues + * New upstream version 5.4.9 + + -- Chris Hofstaedtler Mon, 26 Oct 2026 14:55:17 +0100 + +pdns-recursor (5.4.8-1) unstable; urgency=medium + + * New upstream version 5.4.8, fixing CVE-2026-73206, CVE-2026-73205, + CVE-2026-85555, CVE-2026-85556, CVE-2026-85557, CVE-2026-85558, + CVE-2026-85559. + + -- Chris Hofstaedtler Wed, 21 Oct 2026 15:28:44 +0200 + +pdns-recursor (5.4.6-2) unstable; urgency=medium + + * Build with lld 22, matching rustc LLVM 22 usage + (Closes: #1149822) + + -- Chris Hofstaedtler Mon, 12 Oct 2026 16:19:19 +0200 + +pdns-recursor (5.4.6-1) unstable; urgency=medium + + * New upstream version 5.4.6 + + -- Chris Hofstaedtler Thu, 03 Sep 2026 10:40:21 +0200 + +pdns-recursor (5.4.5-1) unstable; urgency=medium + + * New upstream version 5.4.5, fixing CVE-2026-52682 + + -- Chris Hofstaedtler Thu, 06 Aug 2026 17:42:12 +0200 + +pdns-recursor (5.4.4-1) unstable; urgency=medium + + * New upstream version 5.4.4, fixing security issues CVE-2026-52686, CVE-2026-52688. + * lintian: ignore embedded-library libyaml false-positive - -- Chris Hofstaedtler Tue, 21 Jul 2026 15:41:43 +0200 + -- Chris Hofstaedtler Wed, 22 Jul 2026 01:13:11 +0200 -pdns-recursor (5.2.11-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.3-1) unstable; urgency=medium - * New upstream version 5.2.11, fixing security issues - CVE-2026-33612, CVE-2026-40012, CVE-2026-42005, CVE-2026-42390, - CVE-2026-42390, CVE-2026-42388, CVE-2026-42387, CVE-2026-52690. + * New upstream version 5.4.3, fixing CVE-2026-33612, CVE-2026-40012, + CVE-2026-42005, CVE-2026-42390, CVE-2026-42389, CVE-2026-42388, + CVE-2026-42387, CVE-2026-52690 - -- Chris Hofstaedtler Wed, 17 Jun 2026 00:19:21 +0200 + -- Chris Hofstaedtler Fri, 26 Jun 2026 18:47:40 +0200 -pdns-recursor (5.2.9-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.2-2) unstable; urgency=medium - * New upstream version 5.2.9, fixing CVE-2026-33257, CVE-2026-33258, - CVE-2026-33259, CVE-2026-33260, CVE-2026-33261, CVE-2026-33601, - CVE-2026-33600. + [ Luca Boccassi ] + * Install and use sysusers.d config file - -- Chris Hofstaedtler Sun, 26 Apr 2026 21:04:28 +0200 + -- Chris Hofstaedtler Sun, 21 Jun 2026 16:39:51 +0200 -pdns-recursor (5.2.8-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.2-1) unstable; urgency=medium - * New upstream version 5.2.8, fixing CVE-2026-24027 CVE-2026-0398 - (Closes: #1127490) + * New upstream version 5.4.2 + * d/watch: update to version 5 - -- Chris Hofstaedtler Wed, 11 Feb 2026 23:05:53 +0100 + -- Chris Hofstaedtler Wed, 03 Jun 2026 10:39:35 +0200 -pdns-recursor (5.2.7-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.1-2) unstable; urgency=medium - * New upstream version 5.2.7, fixing CVE-2025-59030. + * d/rules: drop useless override_dh_gencontrol + * Remove unused boost Build-Depends + * Always build with luajit, available on all release archs + * Enable LTO, like upstream - -- Chris Hofstaedtler Tue, 09 Dec 2025 11:13:14 +0100 + -- Chris Hofstaedtler Sat, 30 May 2026 00:44:33 +0200 -pdns-recursor (5.2.6-0+deb13u1) trixie-security; urgency=medium +pdns-recursor (5.4.1-1) unstable; urgency=medium - * New upstream version 5.2.6, fixing CVE-2025-59023. + * New upstream version 5.4.1, fixing security issues: + CVE-2026-33256, CVE-2026-33257, CVE-2026-33258, CVE-2026-33259, + CVE-2026-33260, CVE-2026-33261, CVE-2026-33262, CVE-2026-33601, + CVE-2026-33600 - -- Chris Hofstaedtler Wed, 22 Oct 2025 18:15:32 +0200 + -- Chris Hofstaedtler Wed, 22 Apr 2026 15:15:12 +0200 -pdns-recursor (5.2.4-2+deb13u1) trixie; urgency=medium +pdns-recursor (5.4.0-1) unstable; urgency=medium + + * New upstream version 5.4.0 + + -- Chris Hofstaedtler Mon, 09 Mar 2026 13:56:39 +0100 + +pdns-recursor (5.3.5-1) unstable; urgency=medium + + * New upstream version 5.3.5 + Fixes CVE-2026-24027, CVE-2026-0398 (Closes: #1127490) + + -- Chris Hofstaedtler Wed, 11 Feb 2026 15:13:35 +0100 + +pdns-recursor (5.3.4-2) unstable; urgency=medium + + * Drop Build-Depends: libboost-system-dev + + -- Chris Hofstaedtler Thu, 05 Feb 2026 23:34:17 +0100 + +pdns-recursor (5.3.4-1) unstable; urgency=medium + + * New upstream version 5.3.4 + * Rebase patches + + -- Chris Hofstaedtler Wed, 14 Jan 2026 12:32:52 +0100 + +pdns-recursor (5.3.3-1) unstable; urgency=medium + + * New upstream version 5.3.3 + Fixes CVE-2025-59029 (Closes: #1122196), + Fixes CVE-2025-59030 (Closes: #1122197). + * Preserve recursor.lua on upgrades, but not as conffile + + -- Chris Hofstaedtler Tue, 09 Dec 2025 11:01:36 +0100 + +pdns-recursor (5.3.1-1) unstable; urgency=medium + + * New upstream version 5.3.1, fixes CVE-2025-59023 and CVE-2025-59024. + (Closes: #1118751) + + -- Chris Hofstaedtler Wed, 22 Oct 2025 18:01:37 +0200 + +pdns-recursor (5.3.0-5) unstable; urgency=medium + + * Fix endian issue in tests on s390x + * d/copyright: Remove old FSF address + + -- Chris Hofstaedtler Sun, 07 Sep 2025 14:17:42 +0200 + +pdns-recursor (5.3.0-4) unstable; urgency=medium + + * Fix incorrectly applied rust-fix-build-with-multiple-available-cargos patch. + Causes startup failure while reading the YAML config. + + -- Chris Hofstaedtler Sat, 06 Sep 2025 21:53:52 +0200 + +pdns-recursor (5.3.0-3) unstable; urgency=medium - * d/gbp.conf: update for trixie branch - * d/rules: fix DEB_VERSION/DEB_VENDOR being empty. - Thanks to Steve Mokris (Closes: #1113814) * d/rules: stop setting CARGO_REGISTRY, fixes Static-Built-Using - Thanks to Fabian Gruenbichler. + * Build with meson instead of autotools + * Remove obsolete lintian overrides + + -- Chris Hofstaedtler Sat, 06 Sep 2025 18:43:24 +0200 + +pdns-recursor (5.3.0-2) unstable; urgency=medium + + * d/rules: fix DEB_VERSION/DEB_VENDOR being empty. + Thanks to Steve Mokris + + -- Chris Hofstaedtler Tue, 02 Sep 2025 23:06:05 +0200 + +pdns-recursor (5.3.0-1) unstable; urgency=medium + + * d/watch: update upstream URL (xz) + * New upstream version 5.3.0 + * Relax crate requirements + * Update crate dependencies + * Update path to internal rust crate + + -- Chris Hofstaedtler Thu, 28 Aug 2025 20:32:46 +0200 + +pdns-recursor (5.2.5-1) unstable; urgency=medium + + * New upstream version 5.2.5 - -- Chris Hofstaedtler Sun, 07 Sep 2025 13:22:57 +0200 + -- Chris Hofstaedtler Tue, 26 Aug 2025 19:44:06 +0200 pdns-recursor (5.2.4-2) unstable; urgency=medium diff -Nru pdns-recursor-5.2.13/debian/control pdns-recursor-5.4.9/debian/control --- pdns-recursor-5.2.13/debian/control 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/control 2026-10-26 17:32:09.000000000 +0000 @@ -9,37 +9,54 @@ Build-Depends: debhelper-compat (= 13), dh-cargo, + dh-sequence-installsysusers, architecture-is-64-bit, cargo, libboost-context-dev, libboost-dev, libboost-filesystem-dev, - libboost-program-options-dev, - libboost-system-dev, libboost-test-dev, - libboost-thread-dev, libcap-dev, libcurl4-openssl-dev, libfstrm-dev, - libluajit-5.1-dev (>= 2.1.0~beta3+dfsg-5.3) [amd64 arm64] | libluajit-5.1-dev [amd64] | liblua5.3-dev, + libluajit-5.1-dev, libprotobuf-dev, librust-base64-dev (>= 0.22.1-1~), + librust-bytes-dev, librust-cxx-build-dev (>= 1.0.130-1~), librust-cxx-dev (>= 1.0.130-1~), + librust-cxx-dev (<= 1.0.175~) | librust-cxx-dev (>= 1.0.181-1~), + librust-form-urlencoded-dev, + librust-http-body-util-dev, + librust-hyper+http1-dev, + librust-hyper+server-dev, + librust-hyper-rustls-dev, + librust-hyper-util+tokio-dev, librust-ipnet-dev (>= 2.8.0-1~), + librust-once-cell-dev, librust-once-cell-dev (>= 1.18.0-1~), + librust-ring-dev, + librust-rustls-dev, + librust-rustls-pemfile-dev, + librust-rustls-pki-types-dev, librust-serde-derive-dev, librust-serde-dev, librust-serde-yaml-dev (>= 0.9.34~), + librust-tokio+net-dev, + librust-tokio+rt-dev, + librust-tokio-dev, + librust-tokio-rustls-dev, + librust-uuid-dev, libsnmp-dev, libsodium-dev, libssl-dev, libsystemd-dev, + meson, pkgconf, protobuf-compiler, ragel, systemd, - systemd-dev | systemd, + systemd-dev | systemd (<< 257), Vcs-Git: https://salsa.debian.org/debian/pdns-recursor.git Vcs-Browser: https://salsa.debian.org/debian/pdns-recursor Homepage: https://www.powerdns.com/ @@ -51,7 +68,6 @@ Pre-Depends: ${misc:Pre-Depends}, Depends: - adduser, dns-root-data, publicsuffix, ${misc:Depends}, diff -Nru pdns-recursor-5.2.13/debian/copyright pdns-recursor-5.4.9/debian/copyright --- pdns-recursor-5.2.13/debian/copyright 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/copyright 2026-10-26 13:54:29.000000000 +0000 @@ -19,10 +19,6 @@ 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 St, Fifth Floor, Boston, MA 02110-1301 USA - . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. @@ -99,10 +95,6 @@ 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. - . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. diff -Nru pdns-recursor-5.2.13/debian/gbp.conf pdns-recursor-5.4.9/debian/gbp.conf --- pdns-recursor-5.2.13/debian/gbp.conf 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/gbp.conf 2026-10-26 13:54:29.000000000 +0000 @@ -1,4 +1,4 @@ [DEFAULT] pristine-tar = True -debian-branch = debian/trixie -upstream-branch = upstream/trixie +debian-branch = debian/latest +upstream-branch = upstream/latest diff -Nru pdns-recursor-5.2.13/debian/patches/0002-Relax-cargo-dependencies-for-trixie.patch pdns-recursor-5.4.9/debian/patches/0002-Relax-cargo-dependencies-for-trixie.patch --- pdns-recursor-5.2.13/debian/patches/0002-Relax-cargo-dependencies-for-trixie.patch 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/debian/patches/0002-Relax-cargo-dependencies-for-trixie.patch 2026-10-26 17:32:09.000000000 +0000 @@ -0,0 +1,30 @@ +From: Chris Hofstaedtler +Date: Mon, 26 Oct 2026 15:28:30 +0100 +Subject: Relax cargo dependencies for trixie + +--- + rec-rust-lib/rust/Cargo.toml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/rec-rust-lib/rust/Cargo.toml b/rec-rust-lib/rust/Cargo.toml +index 3e66b93..e62b130 100644 +--- a/rec-rust-lib/rust/Cargo.toml ++++ b/rec-rust-lib/rust/Cargo.toml +@@ -15,7 +15,7 @@ name = "recrust" + crate-type = ["staticlib"] + + [dependencies] +-cxx = "1.0.181" # issue #16101 ++cxx = "1.0.141" # issue #16101 + serde = { version = "1.0", features = ["derive"] } + serde_yaml = { version = "0.9.34" } + ipnet = "2.8" +@@ -25,7 +25,7 @@ hyper = { version = "1", features = ["server", "http1"]} + tokio = { version = "1" , features = ["rt", "net"]} + http-body-util = "0.1" + hyper-util = { version = "0.1", features = ["tokio"]} +-bytes = "1.11" ++bytes = "1.9" + form_urlencoded = "1.2" + hyper-rustls = { version = "0.27", default-features = false } + ring = "0.17.13" diff -Nru pdns-recursor-5.2.13/debian/patches/series pdns-recursor-5.4.9/debian/patches/series --- pdns-recursor-5.2.13/debian/patches/series 2026-07-24 13:21:07.000000000 +0000 +++ pdns-recursor-5.4.9/debian/patches/series 2026-10-26 17:32:09.000000000 +0000 @@ -1 +1,2 @@ testrunner-log-verbosity +0002-Relax-cargo-dependencies-for-trixie.patch diff -Nru pdns-recursor-5.2.13/debian/patches/testrunner-log-verbosity pdns-recursor-5.4.9/debian/patches/testrunner-log-verbosity --- pdns-recursor-5.2.13/debian/patches/testrunner-log-verbosity 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/patches/testrunner-log-verbosity 2026-10-26 14:28:33.000000000 +0000 @@ -7,10 +7,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am -index 8d2210f..ab0945d 100644 +index 068707b..c78d1b7 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -105,7 +105,7 @@ TESTS=test_libcrypto +@@ -104,7 +104,7 @@ TESTS=test_libcrypto if UNIT_TESTS noinst_PROGRAMS = testrunner diff -Nru pdns-recursor-5.2.13/debian/pdns-recursor.conffiles pdns-recursor-5.4.9/debian/pdns-recursor.conffiles --- pdns-recursor-5.2.13/debian/pdns-recursor.conffiles 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/pdns-recursor.conffiles 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -remove-on-upgrade /etc/powerdns/recursor.lua diff -Nru pdns-recursor-5.2.13/debian/pdns-recursor.lintian-overrides pdns-recursor-5.4.9/debian/pdns-recursor.lintian-overrides --- pdns-recursor-5.2.13/debian/pdns-recursor.lintian-overrides 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/pdns-recursor.lintian-overrides 2026-10-26 13:54:29.000000000 +0000 @@ -1,2 +1,6 @@ # Source carries OpenSSL Exception pdns-recursor: possible-gpl-code-linked-with-openssl + +# serde_yaml uses a rust port of libyaml, not the C libyaml +pdns-recursor: embedded-library libyaml [usr/bin/rec_control] +pdns-recursor: embedded-library libyaml [usr/sbin/pdns_recursor] diff -Nru pdns-recursor-5.2.13/debian/pdns-recursor.postinst pdns-recursor-5.4.9/debian/pdns-recursor.postinst --- pdns-recursor-5.2.13/debian/pdns-recursor.postinst 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/pdns-recursor.postinst 2026-10-26 13:54:29.000000000 +0000 @@ -3,8 +3,11 @@ case "$1" in configure) - addgroup --system pdns - adduser --system --home /var/spool/powerdns --shell /bin/false --ingroup pdns --disabled-password --disabled-login --gecos "PowerDNS" pdns + # restore /etc/powerdns/recursor.lua, but not as a conffile + if [ -e /etc/powerdns/recursor.lua.dpkg-bak ] && [ ! -e /etc/powerdns/recursor.lua ] && dpkg --compare-versions "$2" le "5.3.1-2"; then + echo Restoring /etc/powerdns/recursor.lua + mv /etc/powerdns/recursor.lua.dpkg-bak /etc/powerdns/recursor.lua + fi ;; *) diff -Nru pdns-recursor-5.2.13/debian/pdns-recursor.preinst pdns-recursor-5.4.9/debian/pdns-recursor.preinst --- pdns-recursor-5.2.13/debian/pdns-recursor.preinst 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/debian/pdns-recursor.preinst 2026-10-26 13:54:29.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +delete_unchanged() { + if [ -e "$1" ] && echo "$2 $1" | md5sum --check --status; then + echo "Removing unchanged configuration file $1" + rm -f "$1" + fi +} + +backup_conffile() { + if [ -e "$1" ]; then + echo "Moving configuration file $1 to $1.dpkg-bak" + mv -f "$1" "$1".dpkg-bak + fi +} + +case "$1" in + install|upgrade) + if dpkg --compare-versions "$2" le "5.3.1-2"; then + # clean up files we no longer ship + delete_unchanged /etc/powerdns/recursor.lua 52659f850195b3a3f07bf9fd3de4a7c0 + # will be moved back by postinst, if found + backup_conffile /etc/powerdns/recursor.lua + fi + ;; +esac + +#DEBHELPER# diff -Nru pdns-recursor-5.2.13/debian/pdns-recursor.sysusers pdns-recursor-5.4.9/debian/pdns-recursor.sysusers --- pdns-recursor-5.2.13/debian/pdns-recursor.sysusers 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/debian/pdns-recursor.sysusers 2026-10-26 13:54:29.000000000 +0000 @@ -0,0 +1 @@ +u! pdns - "PowerDNS" /var/spool/powerdns /bin/false diff -Nru pdns-recursor-5.2.13/debian/rules pdns-recursor-5.4.9/debian/rules --- pdns-recursor-5.2.13/debian/rules 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/rules 2026-10-26 17:32:09.000000000 +0000 @@ -19,14 +19,9 @@ # Vendor and version CXXFLAGS += -DPACKAGEVERSION='"$(DEB_VERSION).$(DEB_VENDOR)"' -CONFIGURE_ARGS = - -# Workaround for #1078387 https://github.com/PowerDNS/pdns/issues/14084 -CONFIGURE_ARGS += --with-libcrypto=/usr - %: - dh $@ + dh $@ --buildsystem=meson override_dh_auto_clean: dh_auto_clean @@ -36,25 +31,21 @@ override_dh_auto_configure: $(CARGO) prepare-debian debian/cargo_registry --link-from-system - echo> ./settings/rust/Cargo.lock + echo> ./rec-rust-lib/rust/Cargo.lock PATH=debian/configure-helpers/:$$PATH dh_auto_configure -- \ --sysconfdir=/etc/powerdns \ - --enable-systemd --with-systemd=$$(pkgconf --variable=systemdsystemunitdir systemd) \ - --enable-reproducible \ - --disable-silent-rules \ - --enable-unit-tests \ - --with-service-user=pdns \ - --with-service-group=pdns \ - --with-libcap \ - --with-libsodium \ - --with-lua \ - --with-net-snmp \ - --with-protobuf=yes \ - --enable-dns-over-tls \ - --enable-dnstap \ - $(CONFIGURE_ARGS) - cat config.log - grep 'OpenSSL ECDSA: yes' config.log + -Dreproducible=true \ + -Dunit-tests=true \ + -Dsystemd-service=enabled \ + -Dsystemd-service-user=pdns \ + -Dsystemd-service-group=pdns \ + -Dlibcap=enabled \ + -Dsigners-libsodium=enabled \ + -Dsigners-libcrypto=enabled \ + -Dlua=auto \ + -Dsnmp=enabled \ + -Ddns-over-tls=enabled \ + -Ddnstap=enabled override_dh_auto_install: dh_auto_install @@ -65,15 +56,12 @@ mv debian/pdns-recursor/etc/powerdns/recursor.yml-dist debian/pdns-recursor/usr/share/doc/pdns-recursor/examples/ install -m 644 -t debian/pdns-recursor/etc/powerdns debian/recursor.conf # workaround for static libs in non-default dir, see https://salsa.debian.org/rust-team/dh-cargo/-/issues/1 - ln -s ./settings/rust/target . - sed -e '/rustc-link-lib=static=settings/d' -i target/*/release/build/settings*/output + ln -s ./obj-*/target . + sed -e '/rustc-link-lib=static=recrust/d' -i target/*/release/build/recrust*/output /usr/share/cargo/bin/dh-cargo-built-using pdns-recursor override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) dh_auto_test - -cat testrunner.log + -cat ./obj-*/meson-logs/testlog.txt endif - -override_dh_gencontrol: - dh_gencontrol -- $(SUBSTVARS) diff -Nru pdns-recursor-5.2.13/debian/source/lintian-overrides pdns-recursor-5.4.9/debian/source/lintian-overrides --- pdns-recursor-5.2.13/debian/source/lintian-overrides 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/source/lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -# Source is in html/js/d3.js -pdns-recursor source: source-is-missing html/js/d3.js -pdns-recursor source: source-is-missing html/js/d3.v3.js -pdns-recursor source: source-is-missing html/js/handlebars-v4.0.11.js diff -Nru pdns-recursor-5.2.13/debian/watch pdns-recursor-5.4.9/debian/watch --- pdns-recursor-5.2.13/debian/watch 2026-08-07 08:17:55.000000000 +0000 +++ pdns-recursor-5.4.9/debian/watch 2026-10-26 13:54:29.000000000 +0000 @@ -1,3 +1,5 @@ -# Site Directory Pattern Version Script -version=3 -opts="versionmangle=s/-(alpha|beta|rc)/~$1/" https://downloads.powerdns.com/releases/ pdns-recursor-(5\..*)\.tar\.bz2 debian uupdate +Version: 5 + +Source: https://downloads.powerdns.com/releases/ +Matching-Pattern: pdns-recursor-(5\..*)\.tar\.xz +Versionmangle: s/-(alpha|beta|rc)/~$1/ diff -Nru pdns-recursor-5.2.13/dns.cc pdns-recursor-5.4.9/dns.cc --- pdns-recursor-5.2.13/dns.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dns.cc 2026-10-26 09:46:36.000000000 +0000 @@ -58,7 +58,7 @@ "Bad/missing Server Cookie" }; -static const std::array rcodes_short_s = { +static const std::array rcodes_short_s = { "noerror", "formerr", "servfail", @@ -69,39 +69,92 @@ "yxrrset", "nxrrset", "notauth", + "notzone", + "rcode11", + "rcode12", + "rcode13", + "rcode14", + "rcode15", + "badvers", + "badkey", + "badtime", + "badmode", + "badname", + "badalg", + "badtrunc", + "badcookie", }; std::string RCode::to_s(uint8_t rcode) { if (rcode > 0xF) { - return std::string("ErrOutOfRange"); + return "ErrOutOfRange"; } return ERCode::to_s(rcode); } std::string RCode::to_short_s(uint8_t rcode) { - if (rcode >= rcodes_short_s.size()) { - return "rcode" + std::to_string(rcode); + if (rcode > 0xF) { + return "ErrOutOfRange"; } - return rcodes_short_s.at(rcode); + return ERCode::to_short_s(rcode); +} + +std::optional RCode::from_short(const std::string_view& rcode_string) +{ + const auto* position = std::find(rcodes_short_s.begin(), rcodes_short_s.end(), rcode_string); + if (position == rcodes_short_s.end()) { + return std::nullopt; + } + auto code = std::distance(rcodes_short_s.begin(), position); + if (code > 0xF) { + return std::nullopt; + } + return code; } std::string ERCode::to_s(uint16_t rcode) { if (rcode >= RCode::rcodes_s.size()) { - return std::string("Err#")+std::to_string(rcode); + return std::string("Err#") + std::to_string(rcode); } return RCode::rcodes_s.at(rcode); } +std::string ERCode::to_short_s(uint16_t rcode) { + if (rcode >= rcodes_short_s.size()) { + return "rcode" + std::to_string(rcode); + } + return rcodes_short_s.at(rcode); +} + +std::optional ERCode::from_short(const std::string_view& ercode_string) +{ + const auto* position = std::find(rcodes_short_s.begin(), rcodes_short_s.end(), ercode_string); + if (position == rcodes_short_s.end()) { + return std::nullopt; + } + return std::distance(rcodes_short_s.begin(), position); +} + std::string Opcode::to_s(uint8_t opcode) { - static const std::array s_opcodes = { "Query", "IQuery", "Status", "3", "Notify", "Update" }; + static const std::array s_opcodes = { "Query", "IQuery", "Status", "", "Notify", "Update" }; - if (opcode >= s_opcodes.size()) { + if (opcode >= s_opcodes.size() || s_opcodes.at(opcode).empty()) { return std::to_string(opcode); } return s_opcodes.at(opcode); } +std::optional Opcode::from_lowercase_string(const std::string_view& opcode_string) +{ + static const std::array s_opcodes = { "query", "iquery", "status", "", "notify", "update" }; + const auto* position = std::find(s_opcodes.begin(), s_opcodes.end(), opcode_string); + if (position == s_opcodes.end() || position->empty()) { + return std::nullopt; + } + return std::distance(s_opcodes.begin(), position); +} + // 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& wasOK) { diff -Nru pdns-recursor-5.2.13/dns.hh pdns-recursor-5.4.9/dns.hh --- pdns-recursor-5.2.13/dns.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dns.hh 2026-10-26 09:46:36.000000000 +0000 @@ -23,6 +23,8 @@ #include "qtype.hh" #include "dnsname.hh" #include +#include +#include #include #undef BADSIG // signal.h SIG_ERR @@ -35,6 +37,7 @@ enum rcodes_ : uint8_t { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10}; static std::string to_s(uint8_t rcode); static std::string to_short_s(uint8_t rcode); + static std::optional from_short(const std::string_view& rcode_string); const static std::array rcodes_s; }; @@ -43,6 +46,8 @@ public: enum rcodes_ : uint16_t { BADVERS=16, BADSIG=16, BADKEY=17, BADTIME=18, BADMODE=19, BADNAME=20, BADALG=21, BADTRUNC=22, BADCOOKIE=23 }; static std::string to_s(uint16_t rcode); + static std::string to_short_s(uint16_t rcode); + static std::optional from_short(const std::string_view& ercode_string); }; class Opcode @@ -50,8 +55,16 @@ public: enum opcodes_ : uint8_t { Query=0, IQuery=1, Status=2, Notify=4, Update=5 }; static std::string to_s(uint8_t opcode); + static std::optional from_lowercase_string(const std::string_view& opcode_string); }; +// This needs to be a signed type, so that serialization of UnknownDomainID +// as text is "-1", for compatibility with the remote and pipe backends. +// See static_assert there for details. +using domainid_t = int32_t; + +constexpr domainid_t UnknownDomainID{-1}; + //! This class represents a resource record class DNSResourceRecord { @@ -78,12 +91,12 @@ // Aligned on 8-byte boundaries on systems where time_t is 8 bytes and int // is 4 bytes, aka modern linux on x86_64 - time_t last_modified{}; //!< For autocalculating SOA serial numbers - the backend needs to fill this in + time_t last_modified{}; //!< Timestamp of last update, if known by the backend uint32_t ttl{}; //!< Time To Live of this record uint32_t signttl{}; //!< If non-zero, use this TTL as original TTL in the RRSIG - int domain_id{-1}; //!< If a backend implements this, the domain_id of the zone this record is in + domainid_t domain_id{UnknownDomainID}; //!< If a backend implements this, the domain_id of the zone this record is in QType qtype; //!< qtype of this record, ie A, CNAME, MX etc uint16_t qclass{1}; //!< class of this record @@ -91,7 +104,7 @@ bool auth{true}; bool disabled{}; - bool operator==(const DNSResourceRecord& rhs); + bool operator==(const DNSResourceRecord& rhs) const; bool operator<(const DNSResourceRecord& other) const { @@ -123,39 +136,17 @@ static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4"); -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) -#include -#elif __linux__ || __GNU__ -# include - -#else // with thanks to - -# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ -# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ -# define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ - -#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ - defined(__i386) || defined(__ia64) || defined(__amd64) || \ - defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ - defined(__alpha__) || defined(__alpha) || \ - (defined(__Lynx__) && defined(__x86__)) -# define BYTE_ORDER LITTLE_ENDIAN -#endif - -#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ - defined(__sparc) || \ - defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ - defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ - defined(apollo) || defined(__convex__) || defined(_CRAY) || \ - defined(__hppa) || defined(__hp9000) || \ - defined(__hp9000s300) || defined(__hp9000s700) || \ - defined(__hp3000s900) || defined(MPE) || \ - defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \ - (defined(__Lynx__) && \ - (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) -# define BYTE_ORDER BIG_ENDIAN +#if __has_include() +#include // Recent posix +#elif __has_include() +#include // Common place on older BSD derived systems +#else +#error no endian.h found #endif +// Sanity check +#if !defined(BYTE_ORDER) +#error cannot determine byte order #endif struct dnsheader { @@ -173,7 +164,7 @@ 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 +#elif BYTE_ORDER == LITTLE_ENDIAN /* fields in third byte */ unsigned rd :1; /* recursion desired */ unsigned tc :1; /* truncated message */ @@ -214,6 +205,11 @@ d_p = &d_h; } } + dnsheader_aligned(const dnsheader_aligned&) = delete; + dnsheader_aligned(dnsheader_aligned&&) = delete; + dnsheader_aligned& operator=(const dnsheader_aligned&) = delete; + dnsheader_aligned& operator=(dnsheader_aligned&&) = delete; + ~dnsheader_aligned() = default; [[nodiscard]] const dnsheader* get() const { @@ -259,7 +255,7 @@ #if BYTE_ORDER == BIG_ENDIAN #define FLAGS_RD_OFFSET (8) #define FLAGS_CD_OFFSET (12) -#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN +#elif BYTE_ORDER == LITTLE_ENDIAN #define FLAGS_RD_OFFSET (0) #define FLAGS_CD_OFFSET (12) #endif diff -Nru pdns-recursor-5.2.13/dns_random.hh pdns-recursor-5.4.9/dns_random.hh --- pdns-recursor-5.2.13/dns_random.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dns_random.hh 2026-10-26 09:46:36.000000000 +0000 @@ -41,6 +41,11 @@ return arc4random() & 0xffff; } +inline void dns_random(void* buf, size_t size) +{ + arc4random_buf(buf, size); +} + namespace pdns { struct dns_random_engine diff -Nru pdns-recursor-5.2.13/dnsbackend.hh pdns-recursor-5.4.9/dnsbackend.hh --- pdns-recursor-5.2.13/dnsbackend.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsbackend.hh 2026-10-26 09:46:36.000000000 +0000 @@ -54,15 +54,15 @@ { DomainInfo() = default; - DNSName zone; - DNSName catalog; + ZoneName zone; + ZoneName catalog; time_t last_check{}; string options; string account; vector primaries; DNSBackend* backend{}; - uint32_t id{}; + domainid_t id{}; uint32_t notified_serial{}; bool receivedNotify{}; @@ -134,7 +134,7 @@ struct AutoPrimary { AutoPrimary(string new_ip, string new_nameserver, string new_account) : - ip(std::move(new_ip)), nameserver(std::move(new_nameserver)), account(std::move(new_account)){}; + ip(std::move(new_ip)), nameserver(std::move(new_nameserver)), account(std::move(new_account)) {}; std::string ip; std::string nameserver; std::string account; @@ -156,29 +156,45 @@ class DNSBackend { public: + enum Capabilities : unsigned int + { + CAP_DNSSEC = 1 << 0, // Backend supports DNSSEC + CAP_COMMENTS = 1 << 1, // Backend supports comments + CAP_DIRECT = 1 << 2, // Backend supports direct commands + CAP_LIST = 1 << 3, // Backend supports record enumeration + CAP_CREATE = 1 << 4, // Backend supports domain creation + CAP_VIEWS = 1 << 5, // Backend supports views + CAP_SEARCH = 1 << 6, // Backend supports record search + }; + + virtual unsigned int getCapabilities() = 0; + //! lookup() initiates a lookup. A lookup without results should not throw! - virtual void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) = 0; + virtual void lookup(const QType& qtype, const DNSName& qdomain, domainid_t zoneId, DNSPacket* pkt_p = nullptr) = 0; + virtual void APILookup(const QType& qtype, const DNSName& qdomain, domainid_t zoneId, bool include_disabled = false); virtual bool get(DNSResourceRecord&) = 0; //!< retrieves one DNSResource record, returns false if no more were available virtual bool get(DNSZoneRecord& zoneRecord); + //! Close state created by lookup(...). + virtual void lookupEnd(); //! Initiates a list of the specified domain /** Once initiated, DNSResourceRecord objects can be retrieved using get(). Should return false if the backend does not consider itself responsible for the id passed. \param domain_id ID of which a list is requested */ - virtual bool list(const DNSName& target, int domain_id, bool include_disabled = false) = 0; + virtual bool list(const ZoneName& target, domainid_t domain_id, bool include_disabled = false) = 0; virtual ~DNSBackend() = default; //! fills the soadata struct with the SOA details. Returns false if there is no SOA. - virtual bool getSOA(const DNSName& domain, SOAData& soaData); + virtual bool getSOA(const ZoneName& domain, domainid_t zoneId, SOAData& soaData); - virtual bool replaceRRSet(uint32_t /* domain_id */, const DNSName& /* qname */, const QType& /* qt */, const vector& /* rrset */) + virtual bool replaceRRSet(domainid_t /* domain_id */, const DNSName& /* qname */, const QType& /* qt */, const vector& /* rrset */) { return false; } - virtual bool listSubZone(const DNSName& /* zone */, int /* domain_id */) + virtual bool listSubZone(const ZoneName& /* zone */, domainid_t /* domain_id */) { return false; } @@ -188,9 +204,9 @@ { return (name == "PRESIGNED" || name == "NSEC3PARAM" || name == "NSEC3NARROW"); } - virtual bool getAllDomainMetadata(const DNSName& /* name */, std::map>& /* meta */) { return false; }; - virtual bool getDomainMetadata(const DNSName& /* name */, const std::string& /* kind */, std::vector& /* meta */) { return false; } - virtual bool getDomainMetadataOne(const DNSName& name, const std::string& kind, std::string& value) + virtual bool getAllDomainMetadata(const ZoneName& /* name */, std::map>& /* meta */) { return false; }; + virtual bool getDomainMetadata(const ZoneName& /* name */, const std::string& /* kind */, std::vector& /* meta */) { return false; } + virtual bool getDomainMetadataOne(const ZoneName& name, const std::string& kind, std::string& value) { std::vector meta; if (getDomainMetadata(name, kind, meta)) { @@ -202,8 +218,8 @@ return false; } - virtual bool setDomainMetadata(const DNSName& /* name */, const std::string& /* kind */, const std::vector& /* meta */) { return false; } - virtual bool setDomainMetadataOne(const DNSName& name, const std::string& kind, const std::string& value) + virtual bool setDomainMetadata(const ZoneName& /* name */, const std::string& /* kind */, const std::vector& /* meta */) { return false; } + virtual bool setDomainMetadataOne(const ZoneName& name, const std::string& kind, const std::string& value) { const std::vector meta(1, value); return setDomainMetadata(name, kind, meta); @@ -212,7 +228,7 @@ virtual void getAllDomains(vector* domains, bool getSerial, bool include_disabled); /** Determines if we are authoritative for a zone, and at what level */ - virtual bool getAuth(const DNSName& target, SOAData* /* sd */); + virtual bool getAuth(const ZoneName& target, SOAData* /* sd */); struct KeyData { @@ -223,47 +239,45 @@ bool published{false}; }; - virtual bool getDomainKeys(const DNSName& /* name */, std::vector& /* keys */) { return false; } - virtual bool removeDomainKey(const DNSName& /* name */, unsigned int /* id */) { return false; } - virtual bool addDomainKey(const DNSName& /* name */, const KeyData& /* key */, int64_t& /* id */) { return false; } - virtual bool activateDomainKey(const DNSName& /* name */, unsigned int /* id */) { return false; } - virtual bool deactivateDomainKey(const DNSName& /* name */, unsigned int /* id */) { return false; } - virtual bool publishDomainKey(const DNSName& /* name */, unsigned int /* id */) { return false; } - virtual bool unpublishDomainKey(const DNSName& /* name */, unsigned int /* id */) { return false; } + virtual bool getDomainKeys(const ZoneName& /* name */, std::vector& /* keys */) { return false; } + virtual bool removeDomainKey(const ZoneName& /* name */, unsigned int /* id */) { return false; } + virtual bool addDomainKey(const ZoneName& /* name */, const KeyData& /* key */, int64_t& /* id */) { return false; } + virtual bool activateDomainKey(const ZoneName& /* name */, unsigned int /* id */) { return false; } + virtual bool deactivateDomainKey(const ZoneName& /* name */, unsigned int /* id */) { return false; } + virtual bool publishDomainKey(const ZoneName& /* name */, unsigned int /* id */) { return false; } + virtual bool unpublishDomainKey(const ZoneName& /* name */, unsigned int /* id */) { return false; } virtual bool setTSIGKey(const DNSName& /* name */, const DNSName& /* algorithm */, const string& /* content */) { return false; } virtual bool getTSIGKey(const DNSName& /* name */, DNSName& /* algorithm */, string& /* content */) { return false; } virtual bool getTSIGKeys(std::vector& /* keys */) { return false; } virtual bool deleteTSIGKey(const DNSName& /* name */) { return false; } - virtual bool getBeforeAndAfterNamesAbsolute(uint32_t /* id */, const DNSName& /* qname */, DNSName& /* unhashed */, DNSName& /* before */, DNSName& /* after */) + virtual bool getBeforeAndAfterNamesAbsolute(domainid_t /* id */, const DNSName& qname, DNSName& /* unhashed */, DNSName& /* before */, DNSName& /* after */) { - std::cerr << "Default beforeAndAfterAbsolute called!" << std::endl; - abort(); - return false; + throw PDNSException("DNSSEC operation invoked on non-DNSSEC capable backend, qname: '" + qname.toLogString() + "'"); } - virtual bool getBeforeAndAfterNames(uint32_t /* id */, const DNSName& zonename, const DNSName& qname, DNSName& before, DNSName& after); + virtual bool getBeforeAndAfterNames(domainid_t /* id */, const ZoneName& zonename, const DNSName& qname, DNSName& before, DNSName& after); - virtual bool updateDNSSECOrderNameAndAuth(uint32_t /* domain_id */, const DNSName& /* qname */, const DNSName& /* ordername */, bool /* auth */, const uint16_t /* qtype */ = QType::ANY) + virtual bool updateDNSSECOrderNameAndAuth(domainid_t /* domain_id */, const DNSName& /* qname */, const DNSName& /* ordername */, bool /* auth */, const uint16_t /* qtype */, bool /* isNsec3 */) { return false; } - virtual bool updateEmptyNonTerminals(uint32_t /* domain_id */, set& /* insert */, set& /* erase */, bool /* remove */) + virtual bool updateEmptyNonTerminals(domainid_t /* domain_id */, set& /* insert */, set& /* erase */, bool /* remove */) { return false; } - virtual bool doesDNSSEC() + bool doesDNSSEC() { - return false; + return (getCapabilities() & CAP_DNSSEC) != 0; } // end DNSSEC // comments support - virtual bool listComments(uint32_t /* domain_id */) + virtual bool listComments(domainid_t /* domain_id */) { return false; // unsupported by this backend } @@ -278,14 +292,17 @@ return false; } - virtual bool replaceComments(const uint32_t /* domain_id */, const DNSName& /* qname */, const QType& /* qt */, const vector& /* comments */) + virtual bool replaceComments(const domainid_t /* domain_id */, const DNSName& /* qname */, const QType& /* qt */, const vector& /* comments */) { return false; } - //! returns true if primary ip is primary for domain name. - //! starts the transaction for updating domain qname (FIXME: what is id?) - virtual bool startTransaction(const DNSName& /* qname */, int /* id */ = -1) + //! starts the transaction for updating domain qname, destroying all + //! existing data for that domain if id is != UnknownDomainID. In this case, + //! the id MUST match the DomainInfo information for qname, or very bad things + //! will happen. + //! FIXME: replace this with a bool to make this a less error-prone interface. + virtual bool startTransaction(const ZoneName& /* qname */, domainid_t /* id */ = UnknownDomainID) { return false; } @@ -320,17 +337,17 @@ { return false; // no problem! } - virtual bool feedEnts(int /* domain_id */, map& /* nonterm */) + virtual bool feedEnts(domainid_t /* domain_id */, map& /* nonterm */) { return false; } - virtual bool feedEnts3(int /* domain_id */, const DNSName& /* domain */, map& /* nonterm */, const NSEC3PARAMRecordContent& /* ns3prc */, bool /* narrow */) + virtual bool feedEnts3(domainid_t /* domain_id */, const DNSName& /* domain */, map& /* nonterm */, const NSEC3PARAMRecordContent& /* ns3prc */, bool /* narrow */) { return false; } //! if this returns true, DomainInfo di contains information about the domain - virtual bool getDomainInfo(const DNSName& /* domain */, DomainInfo& /* di */, bool /* getSerial */ = true) + virtual bool getDomainInfo(const ZoneName& /* domain */, DomainInfo& /* di */, bool /* getSerial */ = true) { return false; } @@ -340,7 +357,7 @@ } //! get a list of IP addresses that should also be notified for a domain - virtual void alsoNotifies(const DNSName& domain, set* ips) + virtual void alsoNotifies(const ZoneName& domain, set* ips) { std::vector meta; getDomainMetadata(domain, "ALSO-NOTIFY", meta); @@ -353,52 +370,52 @@ } //! get list of all members in a catalog - virtual bool getCatalogMembers(const DNSName& /* catalog */, vector& /* members */, CatalogInfo::CatalogType /* type */) + [[nodiscard]] virtual bool getCatalogMembers(const ZoneName& /* catalog */, vector& /* members */, CatalogInfo::CatalogType /* type */) { return false; } //! Called by PowerDNS to inform a backend that a domain need to be checked for freshness - virtual void setStale(uint32_t /* domain_id */) + virtual void setStale(domainid_t /* domain_id */) { } //! Called by PowerDNS to inform a backend that a domain has been checked for freshness - virtual void setFresh(uint32_t /* domain_id */) + virtual void setFresh(domainid_t /* domain_id */) { } //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to secondaries - virtual void setNotified(uint32_t /* id */, uint32_t /* serial */) + virtual void setNotified(domainid_t /* id */, uint32_t /* serial */) { } //! Called when the Primary list of a domain should be changed - virtual bool setPrimaries(const DNSName& /* domain */, const vector& /* primaries */) + virtual bool setPrimaries(const ZoneName& /* domain */, const vector& /* primaries */) { return false; } //! Called when the Kind of a domain should be changed (primary -> native and similar) - virtual bool setKind(const DNSName& /* domain */, const DomainInfo::DomainKind /* kind */) + virtual bool setKind(const ZoneName& /* domain */, const DomainInfo::DomainKind /* kind */) { return false; } //! Called when the options of a domain should be changed - virtual bool setOptions(const DNSName& /* domain */, const string& /* options */) + virtual bool setOptions(const ZoneName& /* domain */, const string& /* options */) { return false; } //! Called when the catalog of a domain should be changed - virtual bool setCatalog(const DNSName& /* domain */, const DNSName& /* catalog */) + virtual bool setCatalog(const ZoneName& /* domain */, const ZoneName& /* catalog */) { return false; } //! Called when the Account of a domain should be changed - virtual bool setAccount(const DNSName& /* domain */, const string& /* account */) + virtual bool setAccount(const ZoneName& /* domain */, const string& /* account */) { return false; } @@ -424,26 +441,26 @@ return false; } - //! determine if ip is a autoprimary or a domain - virtual bool autoPrimaryBackend(const string& /* ip */, const DNSName& /* domain */, const vector& /* nsset */, string* /* nameserver */, string* /* account */, DNSBackend** /* db */) + //! determine if ip is an autoprimary or a domain + virtual bool autoPrimaryBackend(const string& /* ip */, const ZoneName& /* domain */, const vector& /* nsset */, string* /* nameserver */, string* /* account */, DNSBackend** /* db */) { return false; } //! called by PowerDNS to create a new domain - virtual bool createDomain(const DNSName& /* domain */, const DomainInfo::DomainKind /* kind */, const vector& /* primaries */, const string& /* account */) + virtual bool createDomain(const ZoneName& /* domain */, const DomainInfo::DomainKind /* kind */, const vector& /* primaries */, const string& /* account */) { return false; } - //! called by PowerDNS to create a secondary record for a autoPrimary - virtual bool createSecondaryDomain(const string& /* ip */, const DNSName& /* domain */, const string& /* nameserver */, const string& /* account */) + //! called by PowerDNS to create a secondary record for an autoprimary + virtual bool createSecondaryDomain(const string& /* ip */, const ZoneName& /* domain */, const string& /* nameserver */, const string& /* account */) { return false; } //! called to delete a domain, incl. all metadata, zone contents, etc. - virtual bool deleteDomain(const DNSName& /* domain */) + virtual bool deleteDomain(const ZoneName& /* domain */) { return false; } @@ -454,19 +471,70 @@ } //! Search for records, returns true if search was done successfully. - virtual bool searchRecords(const string& /* pattern */, size_t /* maxResults */, vector& /* result */) + virtual bool searchRecords(const string& pattern, size_t maxResults, vector& result); + + //! Search for comments, returns true if search was done successfully. + virtual bool searchComments(const string& /* pattern */, size_t /* maxResults */, vector& /* result */) { return false; } - //! Search for comments, returns true if search was done successfully. - virtual bool searchComments(const string& /* pattern */, size_t /* maxResults */, vector& /* result */) + virtual void viewList(vector& /* result */) + { + } + + virtual void viewListZones(const string& /* view */, vector& /* result */) + { + } + + virtual bool viewAddZone(const string& /* view */, const ZoneName& /* zone */) { return false; } + virtual bool viewDelZone(const string& /* view */, const ZoneName& /* zone */) + { + return false; + } + + virtual bool networkSet(const Netmask& /* net */, std::string& /* tag */) + { + return false; + } + + virtual bool networkList(vector>& /* networks */) + { + return false; + } + + //! Returns whether backend operations have caused files to be created. + virtual bool hasCreatedLocalFiles() const + { + return false; + } + + virtual void rectifyZoneHook(domainid_t /*domain_id*/, bool /*before*/) const + { + } + const string& getPrefix() { return d_prefix; }; + // The following routine allows callers to retrieve invalid records from + // the backend, which would not be returned by get(). This is used by + // pdnsutil for diagnostic purposes. + // The default implementation simply wraps get() and pretends there are + // no invalid or corrupted records in the backend storage. + + virtual bool get_unsafe(DNSResourceRecord& rec, std::vector>& invalid) + { + invalid.clear(); + return get(rec); + } + + virtual void flush() + { + } + protected: bool mustDo(const string& key); const string& getArg(const string& key); @@ -479,8 +547,8 @@ class BackendFactory { public: - BackendFactory(const string& name) : - d_name(name) {} + BackendFactory(string name) : + d_name(std::move(name)) {} virtual ~BackendFactory() = default; virtual DNSBackend* make(const string& suffix) = 0; virtual DNSBackend* makeMetadataOnly(const string& suffix) @@ -528,9 +596,14 @@ struct SOAData { SOAData() : - domain_id(-1){}; + domain_id(UnknownDomainID) {}; +#if defined(PDNS_AUTH) + const DNSName& qname() const { return zonename.operator const DNSName&(); } + ZoneName zonename; +#else DNSName qname; +#endif DNSName nameserver; DNSName rname; uint32_t ttl{}; @@ -540,7 +613,7 @@ uint32_t expire{}; uint32_t minimum{}; DNSBackend* db{}; - int domain_id{}; + domainid_t domain_id{}; [[nodiscard]] uint32_t getNegativeTTL() const { return min(ttl, minimum); } }; diff -Nru pdns-recursor-5.2.13/dnslabeltext.cc pdns-recursor-5.4.9/dnslabeltext.cc --- pdns-recursor-5.2.13/dnslabeltext.cc 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/dnslabeltext.cc 2026-10-26 09:47:08.000000000 +0000 @@ -1,10 +1,11 @@ -#line 1 "dnslabeltext.rl" +#line 1 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" #include #include #include #include #include +#include #include "dnsname.hh" #include "namespaces.hh" #include "dnswriter.hh" @@ -26,7 +27,7 @@ { // cerr<<"segmentDNSText("< ret; -#line 93 "dnslabeltext.cc" +#line 94 "librec-dnslabeltext.a.p/dnslabeltext.cc" { cs = dnstext_start; } -#line 96 "dnslabeltext.cc" +#line 97 "librec-dnslabeltext.a.p/dnslabeltext.cc" { int _klen; unsigned int _trans; @@ -175,27 +176,27 @@ switch ( *_acts++ ) { case 0: -#line 42 "dnslabeltext.rl" +#line 43 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { ret.push_back(segment); segment.clear(); } break; case 1: -#line 46 "dnslabeltext.rl" +#line 47 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { segment.clear(); } break; case 2: -#line 50 "dnslabeltext.rl" +#line 51 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { char c = *p; appendSplit(ret, segment, c); } break; case 3: -#line 54 "dnslabeltext.rl" +#line 55 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { char c = *p; val *= 10; @@ -204,19 +205,19 @@ } break; case 4: -#line 60 "dnslabeltext.rl" +#line 61 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { appendSplit(ret, segment, val); val=0; } break; case 5: -#line 65 "dnslabeltext.rl" +#line 66 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { appendSplit(ret, segment, *(p)); } break; -#line 204 "dnslabeltext.cc" +#line 205 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } @@ -233,13 +234,13 @@ while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 0: -#line 42 "dnslabeltext.rl" +#line 43 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { ret.push_back(segment); segment.clear(); } break; -#line 225 "dnslabeltext.cc" +#line 226 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } } @@ -247,7 +248,7 @@ _out: {} } -#line 78 "dnslabeltext.rl" +#line 79 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" if ( cs < dnstext_first_final ) { @@ -261,7 +262,7 @@ DNSName::string_t segmentDNSNameRaw(const char* realinput, size_t inputlen) { -#line 243 "dnslabeltext.cc" +#line 244 "librec-dnslabeltext.a.p/dnslabeltext.cc" static const char _dnsnameraw_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 2, 1, 5, @@ -312,7 +313,7 @@ static const int dnsnameraw_en_main = 1; -#line 94 "dnslabeltext.rl" +#line 95 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" (void)dnsnameraw_error; // silence warnings (void)dnsnameraw_en_main; @@ -333,12 +334,12 @@ unsigned char labellen=0; unsigned int lenpos=0; -#line 311 "dnslabeltext.cc" +#line 312 "librec-dnslabeltext.a.p/dnslabeltext.cc" { cs = dnsnameraw_start; } -#line 314 "dnslabeltext.cc" +#line 315 "librec-dnslabeltext.a.p/dnslabeltext.cc" { int _klen; unsigned int _trans; @@ -412,7 +413,7 @@ switch ( *_acts++ ) { case 0: -#line 114 "dnslabeltext.rl" +#line 115 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { if (labellen > 63) { throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen)); @@ -422,7 +423,7 @@ } break; case 1: -#line 121 "dnslabeltext.rl" +#line 122 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { lenpos=ret.size(); ret.append(1, (char)0); @@ -430,7 +431,7 @@ } break; case 2: -#line 127 "dnslabeltext.rl" +#line 128 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { char c = *p; ret.append(1, c); @@ -438,7 +439,7 @@ } break; case 3: -#line 132 "dnslabeltext.rl" +#line 133 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { char c = *p; val *= 10; @@ -446,7 +447,7 @@ } break; case 4: -#line 137 "dnslabeltext.rl" +#line 138 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { ret.append(1, val); labellen++; @@ -454,13 +455,13 @@ } break; case 5: -#line 143 "dnslabeltext.rl" +#line 144 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { ret.append(1, *(p)); labellen++; } break; -#line 429 "dnslabeltext.cc" +#line 430 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } @@ -477,7 +478,7 @@ while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 0: -#line 114 "dnslabeltext.rl" +#line 115 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { if (labellen > 63) { throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen)); @@ -487,14 +488,14 @@ } break; case 4: -#line 137 "dnslabeltext.rl" +#line 138 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { ret.append(1, val); labellen++; val=0; } break; -#line 460 "dnslabeltext.cc" +#line 461 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } } @@ -502,7 +503,7 @@ _out: {} } -#line 164 "dnslabeltext.rl" +#line 165 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" if ( cs < dnsnameraw_first_final ) { @@ -514,11 +515,11 @@ // Reads an RFC 1035 character string from 'in', puts the resulting bytes in 'out'. // Returns the amount of bytes read from 'in' -size_t parseRFC1035CharString(const std::string &in, std::string &val) { +size_t parseRFC1035CharString(std::string_view in, std::string &val) { val.clear(); val.reserve(in.size()); - const char *p = in.c_str(); + const char *p = in.data(); const char *pe = p + in.size(); int cs = 0; uint8_t escaped_octet = 0; @@ -531,7 +532,7 @@ * right place. */ -#line 493 "dnslabeltext.cc" +#line 494 "librec-dnslabeltext.a.p/dnslabeltext.cc" static const char _dns_text_to_string_actions[] = { 0, 1, 0, 1, 2, 1, 3, 2, 0, 1 @@ -597,12 +598,12 @@ static const int dns_text_to_string_en_main = 1; -#line 557 "dnslabeltext.cc" +#line 558 "librec-dnslabeltext.a.p/dnslabeltext.cc" { cs = dns_text_to_string_start; } -#line 232 "dnslabeltext.rl" +#line 233 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" // silence warnings @@ -610,7 +611,7 @@ (void) dns_text_to_string_error; (void) dns_text_to_string_en_main; -#line 566 "dnslabeltext.cc" +#line 567 "librec-dnslabeltext.a.p/dnslabeltext.cc" { int _klen; unsigned int _trans; @@ -685,7 +686,7 @@ switch ( *_acts++ ) { case 0: -#line 194 "dnslabeltext.rl" +#line 195 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { escaped_octet *= 10; escaped_octet += (*p)-'0'; @@ -693,26 +694,26 @@ } break; case 1: -#line 200 "dnslabeltext.rl" +#line 201 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { val += escaped_octet; escaped_octet = 0; } break; case 2: -#line 205 "dnslabeltext.rl" +#line 206 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { val += (*p); counter++; } break; case 3: -#line 210 "dnslabeltext.rl" +#line 211 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { counter++; } break; -#line 663 "dnslabeltext.cc" +#line 664 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } @@ -725,7 +726,7 @@ _out: {} } -#line 239 "dnslabeltext.rl" +#line 240 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" return counter; } @@ -743,7 +744,7 @@ std::string tmp; -#line 690 "dnslabeltext.cc" +#line 691 "librec-dnslabeltext.a.p/dnslabeltext.cc" static const char _dns_text_to_value_list_actions[] = { 0, 1, 0, 1, 2, 1, 3, 2, 2, 3, 2, 3, 1 @@ -794,12 +795,12 @@ static const int dns_text_to_value_list_en_main = 3; -#line 739 "dnslabeltext.cc" +#line 740 "librec-dnslabeltext.a.p/dnslabeltext.cc" { cs = dns_text_to_value_list_start; } -#line 288 "dnslabeltext.rl" +#line 289 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" // silence warnings @@ -807,7 +808,7 @@ (void) dns_text_to_value_list_error; (void) dns_text_to_value_list_en_main; -#line 748 "dnslabeltext.cc" +#line 749 "librec-dnslabeltext.a.p/dnslabeltext.cc" { int _klen; unsigned int _trans; @@ -882,20 +883,20 @@ switch ( *_acts++ ) { case 0: -#line 259 "dnslabeltext.rl" +#line 260 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { tmp += (*p); counter++; } break; case 1: -#line 264 "dnslabeltext.rl" +#line 265 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { tmp += (*p); } break; case 2: -#line 268 "dnslabeltext.rl" +#line 269 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { val.push_back(tmp); tmp.clear(); @@ -903,12 +904,12 @@ } break; case 3: -#line 274 "dnslabeltext.rl" +#line 275 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { counter++; } break; -#line 844 "dnslabeltext.cc" +#line 845 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } @@ -925,14 +926,14 @@ while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 2: -#line 268 "dnslabeltext.rl" +#line 269 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" { val.push_back(tmp); tmp.clear(); counter++; } break; -#line 866 "dnslabeltext.cc" +#line 867 "librec-dnslabeltext.a.p/dnslabeltext.cc" } } } @@ -940,7 +941,7 @@ _out: {} } -#line 295 "dnslabeltext.rl" +#line 296 "../../pdns-recursor/pdns/recursordist/./dnslabeltext.rl" if ( cs < dns_text_to_value_list_first_final ) { throw runtime_error("Unable to parse DNS SVCB value list '"+in+"'"); diff -Nru pdns-recursor-5.2.13/dnslabeltext.rl pdns-recursor-5.4.9/dnslabeltext.rl --- pdns-recursor-5.2.13/dnslabeltext.rl 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnslabeltext.rl 2026-10-26 09:46:36.000000000 +0000 @@ -3,6 +3,7 @@ #include #include #include +#include #include "dnsname.hh" #include "namespaces.hh" #include "dnswriter.hh" @@ -172,11 +173,11 @@ // Reads an RFC 1035 character string from 'in', puts the resulting bytes in 'out'. // Returns the amount of bytes read from 'in' -size_t parseRFC1035CharString(const std::string &in, std::string &val) { +size_t parseRFC1035CharString(std::string_view in, std::string &val) { val.clear(); val.reserve(in.size()); - const char *p = in.c_str(); + const char *p = in.data(); const char *pe = p + in.size(); int cs = 0; uint8_t escaped_octet = 0; diff -Nru pdns-recursor-5.2.13/dnsmessage.proto pdns-recursor-5.4.9/dnsmessage.proto --- pdns-recursor-5.2.13/dnsmessage.proto 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsmessage.proto 2026-10-26 09:46:36.000000000 +0000 @@ -170,6 +170,8 @@ LuaNoData = 108; LuaNXDomain = 109; LuaPostResolveFFI = 110; + + AuthRequest = 120; } message Event { @@ -190,6 +192,10 @@ optional uint32 outgoingQueries = 27; // Number of outgoing queries used to answer the query optional uint32 headerFlags = 28; // Flags field in wire format, 16 bits used optional uint32 ednsVersion = 29; // EDNS version and flags in wire format, see https://www.rfc-editor.org/rfc/rfc6891.html#section-6.1.3 + optional bytes openTelemetryData = 30; // Protobuf encoded Open Telemetry Data, see https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto + optional uint32 ede = 31; // EDNS error code, actually 16 bits + optional string edeText = 32; // EDNS error text + optional bytes openTelemetryTraceID = 33; // OpenTelemetry TraceID } message PBDNSMessageList { diff -Nru pdns-recursor-5.2.13/dnsname.cc pdns-recursor-5.4.9/dnsname.cc --- pdns-recursor-5.2.13/dnsname.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsname.cc 2026-10-26 09:46:36.000000000 +0000 @@ -29,7 +29,26 @@ #include -const DNSName g_rootdnsname("."), g_wildcarddnsname("*"); +const DNSName g_rootdnsname("."); +const DNSName g_wildcarddnsname("*"); +const DNSName g_coodnsname("coo"); +const DNSName g_groupdnsname("group"); +const DNSName g_versiondnsname("version"); +const DNSName g_zonesdnsname("zones"); + +const DNSName g_gsstsigdnsname("gss-tsig"); +const DNSName g_hmacmd5dnsname("hmac-md5"); +const DNSName g_hmacmd5dnsname_long("hmac-md5.sig-alg.reg.int"); +const DNSName g_hmacsha1dnsname("hmac-sha1"); +const DNSName g_hmacsha224dnsname("hmac-sha224"); +const DNSName g_hmacsha256dnsname("hmac-sha256"); +const DNSName g_hmacsha384dnsname("hmac-sha384"); +const DNSName g_hmacsha512dnsname("hmac-sha512"); + +const ZoneName g_rootzonename("."); + +uint16_t DNSName::s_maxPointersToPointers = 4; +uint16_t DNSName::s_maxPointersPerName = 10; /* raw storage in DNS label format, with trailing 0. W/o trailing 0, we are 'empty' @@ -99,7 +118,7 @@ } } -DNSName::DNSName(const char* pos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, uint16_t minOffset) +DNSName::DNSName(const char* pos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, uint16_t minOffset, size_t* pointerBudget) { if (offset >= len) throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")"); @@ -110,7 +129,7 @@ } } - packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset); + packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset, 0, pointerBudget); } static void checkLabelLength(uint8_t length) @@ -183,7 +202,7 @@ } // this should be the __only__ dns name parser in PowerDNS. -void DNSName::packetParser(const char* qpos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset) +void DNSName::packetParser(const char* qpos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset, uint16_t pointerChainLength, size_t *pointerBudget) { if (offset >= len) { throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")"); @@ -197,7 +216,24 @@ pdns::views::UnsignedCharView view(qpos, len); auto pos = parsePacketUncompressed(view, offset, uncompress); + labellen = view.at(pos); + if (pos == offset && labellen != 0) { + // It's a pointer + if (pointerBudget != nullptr) { + if (*pointerBudget == 0) { + throw std::range_error("Too many compression pointers processed in packet"); + } + (*pointerBudget)--; + } + // Are we chasing a pointer chain already for this name? + if (pointerChainLength++ > s_maxPointersToPointers) { + throw std::range_error("Too many pointer to pointers during decompression (" + std::to_string(pointerChainLength) + ")"); + } + } + else { + pointerChainLength = 0; // not an immediate pointer to pointer case any more + } pos++; if (labellen != 0 && pos < view.size()) { if (labellen < 0xc0) { @@ -219,11 +255,11 @@ throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos)+ " < "+std::to_string(minOffset)+")"); } - if (++depth > 100) { - throw std::range_error("Abort label decompression after 100 redirects"); + if (++depth > s_maxPointersPerName) { + throw std::range_error("Abort label decompression after too many redirects (" + std::to_string(depth) + ")"); } - packetParser(qpos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset); + packetParser(qpos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset, pointerChainLength, pointerBudget); pos++; } @@ -262,7 +298,7 @@ void DNSName::toString(std::string& output, const std::string& separator, const bool trailing) const { if (empty()) { - throw std::out_of_range("Attempt to print an unset dnsname"); + throw std::out_of_range("Attempt to print an unset DNSName"); } if (isRoot()) { @@ -303,7 +339,7 @@ std::string DNSName::toDNSString() const { if (empty()) { - throw std::out_of_range("Attempt to DNSString an unset dnsname"); + throw std::out_of_range("Attempt to DNSString an unset DNSName"); } return std::string(d_storage.c_str(), d_storage.length()); @@ -329,7 +365,7 @@ bool DNSName::isPartOf(const DNSName& parent) const { if(parent.empty() || empty()) { - throw std::out_of_range("empty dnsnames aren't part of anything"); + throw std::out_of_range("empty DNSNames aren't part of anything"); } if(parent.d_storage.size() > d_storage.size()) { @@ -351,7 +387,7 @@ return true; } if (static_cast(*us) > 63) { - throw std::out_of_range("illegal label length in dnsname"); + throw std::out_of_range("illegal label length in DNSName"); } } return false; @@ -466,12 +502,116 @@ d_storage = prep+d_storage; } -bool DNSName::slowCanonCompare(const DNSName& rhs) const +int DNSName::slowCanonCompare_three_way(const DNSName& rhs) const +{ + // Unfortunately we can't use std::lexicographical_compare_three_way() yet + // as this would require C++20. + const auto ours = getRawLabels(); + const auto rhsLabels = rhs.getRawLabels(); + auto iter1 = ours.rbegin(); + const auto& last1 = ours.rend(); + auto iter2 = rhsLabels.rbegin(); + const auto& last2 = rhsLabels.rend(); + while (iter1 != last1 && iter2 != last2) { + if (int res = pdns_ilexicographical_compare_three_way(*iter1, *iter2); res != 0) { + return res; + } + ++iter1; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ++iter2; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + } + if (iter1 == last1) { + if (iter2 != last2) { + return -1; // lt + } + } + else { + return 1; // gt + } + return 0; // eq +} + +int DNSName::canonCompare_three_way(const DNSName& rhs, bool pretty) const { - auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels(); - return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare()); + // 01234567890abcd + // us: 1a3www4ds9a2nl + // rhs: 3www6online3com + // to compare, we start at the back, is nl < com? no -> done + // + // 0,2,6,a + // 0,4,a + + std::array ourpos{}; + std::array rhspos{}; + uint8_t ourcount=0; + uint8_t rhscount=0; + //cout<<"Asked to compare "<(chr)) == 0) { + isNumerical = false; + break; + } + } + if (isNumerical) { + for (const auto chr : rhsstr) { + if (std::isdigit(static_cast(chr)) == 0) { + isNumerical = false; + break; + } + } + } + if (isNumerical) { + return ourlen < rhslen ? -1 : 1; + } + } + } + + int res = pdns_ilexicographical_compare_three_way(ourstr, rhsstr); + if (res != 0) { + return res; + } + } } + vector DNSName::getRawLabels() const { vector ret; @@ -523,9 +663,17 @@ /* * Returns true if the DNSName is a valid RFC 1123 hostname, this function uses * a regex on the string, so it is probably best not used when speed is essential. + * + * If allowUnderscore is set, underscore characters (`_') are allowed anywhere + * a letter or a digit would have been. In particular, leading underscores are + * allowed. */ -bool DNSName::isHostname() const +bool DNSName::isHostname(bool allowUnderscore) const { + if (allowUnderscore) { + static Regex hostNameRegexWithUnderscore = Regex("^(([A-Za-z0-9_]([A-Za-z0-9-_]*[A-Za-z0-9_])?)\\.)+$"); + return hostNameRegexWithUnderscore.match(this->toString()); + } static Regex hostNameRegex = Regex("^(([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)\\.)+$"); return hostNameRegex.match(this->toString()); } @@ -545,8 +693,8 @@ void DNSName::trimToLabels(unsigned int to) { - while(countLabels() > to && chopOff()) { - ; + for (auto nlabels = countLabels(); nlabels > to; --nlabels) { + chopOff(); } } @@ -735,3 +883,199 @@ { return d_position == 0; } + +bool DNSName::matchesUncompressedName(const std::string_view& wire_uncompressed) const +{ + if (wire_uncompressed.empty() != empty() || wire_uncompressed.size() < d_storage.size()) { + return false; + } + + return pdns_ilexicographical_compare_three_way(std::string_view(wire_uncompressed.data(), d_storage.size()), d_storage) == 0; +} + +#if defined(PDNS_AUTH) // [ +std::ostream & operator<<(std::ostream &ostr, const ZoneName& zone) +{ + return ostr << zone.toLogString(); +} + +size_t hash_value(ZoneName const& zone) +{ + return zone.hash(); +} + +// Sugar while ZoneName::operator DNSName are made explicit. These can't be +// made inline in class DNSName due to chicken-and-egg declaration order +// between DNSName and ZoneName. +bool DNSName::isPartOf(const ZoneName& rhs) const +{ + return isPartOf(rhs.operator const DNSName&()); +} +DNSName DNSName::makeRelative(const ZoneName& zone) const +{ + return makeRelative(zone.operator const DNSName&()); +} +void DNSName::makeUsRelative(const ZoneName& zone) +{ + makeUsRelative(zone.operator const DNSName&()); +} + +std::string_view::size_type ZoneName::findVariantSeparator(std::string_view name) +{ + std::string_view::size_type pos{0}; + + // Try to be as fast as possible in the non-variant case and exit + // quickly if we don't find two dots in a row. + while ((pos = name.find('.', pos)) != std::string_view::npos) { + ++pos; + if (pos >= name.length()) { // trailing single dot + return std::string_view::npos; + } + if (name.at(pos) == '.') { + // We have found two dots in a row, but the first dot might have been + // escaped. So we now need to count how many \ characters we can find a + // row before it; if their number is odd, the first dot is escaped and + // we need to keep searching. + size_t slashes{0}; + while (pos >= 2 + slashes && name.at(pos - 2 - slashes) == '\\') { + ++slashes; + } + if ((slashes % 2) == 0) { + break; + } + } + } + return pos; +} + +ZoneName::ZoneName(std::string_view name) +{ + if (auto sep = findVariantSeparator(name); sep != std::string_view::npos) { + setVariant(name.substr(sep + 1)); // ignore leading dot in variant name + name = name.substr(0, sep); // keep trailing dot in zone name + } + d_name = DNSName(name); +} + +ZoneName::ZoneName(std::string_view name, std::string_view::size_type sep) +{ + if (sep != std::string_view::npos) { + setVariant(name.substr(sep + 1)); // ignore leading dot in variant name + name = name.substr(0, sep); // keep trailing dot in zone name + } + d_name = DNSName(name); +} + +void ZoneName::setVariant(std::string_view variant) +{ + if (variant.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789_-") != std::string_view::npos) { + throw std::out_of_range("invalid character in variant name '" + std::string{variant} + "'"); + } + d_variant = variant; +} + +std::string ZoneName::toLogString() const +{ + std::string ret = d_name.toLogString(); + if (!d_variant.empty()) { + // Because toLogString() above uses toStringRootDot(), we do not want to + // output one too many dots if this is a root-with-variant. + ret.push_back('.'); + if (!d_name.isRoot()) { + ret.push_back('.'); + } + ret += d_variant; + } + return ret; +} + +std::string ZoneName::toString(const std::string& separator, const bool trailing) const +{ + std::string ret = d_name.toString(separator, trailing); + if (!d_variant.empty()) { + if (!trailing) { + ret.push_back('.'); + } + ret.push_back('.'); + ret += d_variant; + } + return ret; +} + +std::string ZoneName::toStringNoDot() const +{ + std::string ret = d_name.toStringNoDot(); + if (!d_variant.empty()) { + ret += ".."; + ret += d_variant; + } + return ret; +} + +std::string ZoneName::toStringRootDot() const +{ + std::string ret = d_name.toStringRootDot(); + if (!d_variant.empty()) { + if (!d_name.isRoot()) { + ret.push_back('.'); + } + ret.push_back('.'); + ret += d_variant; + } + return ret; +} + +size_t ZoneName::hash(size_t init) const +{ + if (!d_variant.empty()) { + init = burtleCI(d_variant, init); + } + + return d_name.hash(init); +} + +bool ZoneName::operator<(const ZoneName& rhs) const +{ + // Order by DNSName first, by variant second. + // Unfortunately we can't use std::lexicographical_compare_three_way() yet + // as this would require C++20. + auto iter1 = d_name.getStorage().rbegin(); + const auto last1 = d_name.getStorage().rend(); + auto iter2 = rhs.d_name.getStorage().rbegin(); + const auto last2 = rhs.d_name.getStorage().rend(); + while (iter1 != last1 && iter2 != last2) { + auto char1 = dns_tolower(*iter1); + auto char2 = dns_tolower(*iter2); + if (char1 < char2) { + return true; + } + if (char1 > char2) { + return false; + } + ++iter1; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ++iter2; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + } + if (iter1 == last1) { + if (iter2 != last2) { + return true; // our DNSName is shorter (subset) than the other + } + } + else { + return false; // our DNSName is longer (superset) than the other + } + // At this point, both DNSName compare equal, we have to compare + // variants (which are case-sensitive). + return d_variant < rhs.d_variant; +} + +int ZoneName::canonCompare_three_way(const ZoneName& rhs) const +{ + // Similarly to operator< above, this compares DNSName first, variant + // second. + if (int res = d_name.canonCompare_three_way(rhs.d_name); res != 0) { + return res; + } + // Both DNSName compare equal. + return d_variant.compare(rhs.d_variant); +} +#endif // ] diff -Nru pdns-recursor-5.2.13/dnsname.hh pdns-recursor-5.4.9/dnsname.hh --- pdns-recursor-5.2.13/dnsname.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsname.hh 2026-10-26 09:46:36.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -33,34 +34,34 @@ #include #include +using namespace std::string_view_literals; + #include #include -inline bool dns_isspace(char c) +inline bool dns_isspace(char chr) __attribute__((const)); +inline bool dns_isspace(char chr) { - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; + return chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n'; } -extern const unsigned char dns_toupper_table[256], dns_tolower_table[256]; +extern const unsigned char dns_toupper_table[256], dns_tolower_table[256]; -inline unsigned char dns_toupper(unsigned char c) +inline unsigned char dns_toupper(unsigned char chr) __attribute__((pure)); +inline unsigned char dns_toupper(unsigned char chr) { - return dns_toupper_table[c]; + return dns_toupper_table[chr]; } -inline unsigned char dns_tolower(unsigned char c) +inline unsigned char dns_tolower(unsigned char chr) __attribute__((pure)); +inline unsigned char dns_tolower(unsigned char chr) { - return dns_tolower_table[c]; + return dns_tolower_table[chr]; } #include "burtle.hh" #include "views.hh" -// #include "dns.hh" -// #include "logger.hh" - -//#include - /* Quest in life: accept escaped ascii presentations of DNS names and store them "natively" accept a DNS packet with an offset, and extract a DNS name from it @@ -73,10 +74,23 @@ NOTE: For now, everything MUST be . terminated, otherwise it is an error */ +// DNSName: represents a case-insensitive string, allowing for non-printable +// characters. It is used for all kinds of name (of hosts, domains, keys, +// algorithm...) overall the PowerDNS codebase. +// +// The following type traits are provided: +// - EqualityComparable +// - LessThanComparable +// - Hash +#if defined(PDNS_AUTH) +class ZoneName; +#endif class DNSName { public: static const size_t s_maxDNSNameLength = 255; + static uint16_t s_maxPointersToPointers; + static uint16_t s_maxPointersPerName; DNSName() = default; //!< Constructs an *empty* DNSName, NOT the root! // Work around assertion in some boost versions that do not like self-assignment of boost::container::string @@ -98,11 +112,13 @@ DNSName(DNSName&& a) = default; explicit DNSName(std::string_view sw); //!< Constructs from a human formatted, escaped presentation - DNSName(const char* p, size_t len, size_t offset, bool uncompress, uint16_t* qtype = nullptr, uint16_t* qclass = nullptr, unsigned int* consumed = nullptr, uint16_t minOffset = 0); //!< Construct from a DNS Packet, taking the first question if offset=12. If supplied, consumed is set to the number of bytes consumed from the packet, which will not be equal to the wire length of the resulting name in case of compression. + DNSName(const char* pos, size_t len, size_t offset, bool uncompress, uint16_t* qtype = nullptr, uint16_t* qclass = nullptr, unsigned int* consumed = nullptr, uint16_t minOffset = 0, size_t* pointerBudget = nullptr); //!< Construct from a DNS Packet, taking the first question if offset=12. If supplied, consumed is set to the number of bytes consumed from the packet, which will not be equal to the wire length of the resulting name in case of compression. bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name? Note that name.isPartOf(name). inline bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive) - empty compares to empty bool operator!=(const DNSName& other) const { return !(*this == other); } + // !< DNS-native (case insensitive) comparison against raw data in (uncompressed) wire format. The view has to start with the DNS name, but does not have to contain only a DNS name. Roughly, passing a view of a DNS packet starting just after the DNS header is OK, everything else is not because any names present later in the packet might be compressed. + bool matchesUncompressedName(const std::string_view& wire_uncompressed) const; std::string toString(const std::string& separator=".", const bool trailing=true) const; //!< Our human-friendly, escaped, representation void toString(std::string& output, const std::string& separator=".", const bool trailing=true) const; @@ -135,16 +151,17 @@ DNSName getCommonLabels(const DNSName& other) const; //!< Return the list of common labels from the top, for example 'c.d' for 'a.b.c.d' and 'x.y.c.d' DNSName labelReverse() const; bool isWildcard() const; - bool isHostname() const; + bool isHostname(bool allowUnderscore = false) const; unsigned int countLabels() const; size_t wirelength() const; //!< Number of total bytes in the name bool empty() const { return d_storage.empty(); } bool isRoot() const { return d_storage.size()==1 && d_storage[0]==0; } + bool hasLabels() const { return !empty() && !isRoot(); } void clear() { d_storage.clear(); } void trimToLabels(unsigned int); size_t hash(size_t init=0) const { - return burtleCI((const unsigned char*)d_storage.c_str(), d_storage.size(), init); + return burtleCI(d_storage, init); } DNSName& operator+=(const DNSName& rhs) { @@ -163,15 +180,22 @@ bool operator<(const DNSName& rhs) const // this delivers _some_ kind of ordering, but not one useful in a DNS context. Really fast though. { + struct DNSNameCompare + { + bool operator()(const unsigned char& lhs, const unsigned char& rhs) const + { + return dns_tolower(lhs) < dns_tolower(rhs); + } + }; + + // note that this is case insensitive, including on the label lengths return std::lexicographical_compare(d_storage.rbegin(), d_storage.rend(), - rhs.d_storage.rbegin(), rhs.d_storage.rend(), - [](const unsigned char& a, const unsigned char& b) { - return dns_tolower(a) < dns_tolower(b); - }); // note that this is case insensitive, including on the label lengths + rhs.d_storage.rbegin(), rhs.d_storage.rend(), DNSNameCompare()); } - inline bool canonCompare(const DNSName& rhs) const; - bool slowCanonCompare(const DNSName& rhs) const; + int slowCanonCompare_three_way(const DNSName& rhs) const; + int canonCompare_three_way(const DNSName& rhs, bool pretty = false) const; + inline bool canonCompare(const DNSName& rhs, bool pretty = false) const { return canonCompare_three_way(rhs, pretty) < 0; } typedef boost::container::string string_t; @@ -179,6 +203,13 @@ return d_storage; } + [[nodiscard]] size_t sizeEstimate() const + { + return d_storage.size(); // knowingly overestimating small strings as most string + // implementations have internal capacity and we always include + // sizeof(*this) + } + bool has8bitBytes() const; /* returns true if at least one byte of the labels forming the name is not included in [A-Za-z0-9_*./@ \\:-] */ class RawLabelsVisitor @@ -208,10 +239,17 @@ }; RawLabelsVisitor getRawLabelsVisitor() const; +#if defined(PDNS_AUTH) // [ + // Sugar while ZoneName::operator DNSName are made explicit + bool isPartOf(const ZoneName& rhs) const; + DNSName makeRelative(const ZoneName& zone) const; + void makeUsRelative(const ZoneName& zone); +#endif // ] + private: string_t d_storage; - void packetParser(const char* qpos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset); + void packetParser(const char* qpos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset, uint16_t pointerChainLength, size_t* pointerBudget); size_t parsePacketUncompressed(const pdns::views::UnsignedCharView& view, size_t position, bool uncompress); static void appendEscapedLabel(std::string& appendTo, const char* orig, size_t len); static std::string unescapeLabel(const std::string& orig); @@ -220,65 +258,6 @@ size_t hash_value(DNSName const& d); - -inline bool DNSName::canonCompare(const DNSName& rhs) const -{ - // 01234567890abcd - // us: 1a3www4ds9a2nl - // rhs: 3www6online3com - // to compare, we start at the back, is nl < com? no -> done - // - // 0,2,6,a - // 0,4,a - - uint8_t ourpos[64], rhspos[64]; - uint8_t ourcount=0, rhscount=0; - //cout<<"Asked to compare "< + struct hash { + size_t operator () (const ZoneName& dn) const { return dn.hash(0); } + }; +} + +struct CanonZoneNameCompare +{ + bool operator()(const ZoneName& a, const ZoneName& b) const + { + return a.canonCompare(b); + } +}; +#else // ] [ +using ZoneName = DNSName; +using CanonZoneNameCompare = CanonDNSNameCompare; +#endif // ] + +extern const ZoneName g_rootzonename; template struct SuffixMatchTree { - SuffixMatchTree(const std::string& name="", bool endNode_=false) : d_name(name), endNode(endNode_) + SuffixMatchTree(std::string name = "", bool endNode_ = false) : + d_name(std::move(name)), endNode(endNode_) {} SuffixMatchTree(const SuffixMatchTree& rhs): d_name(rhs.d_name), children(rhs.children), endNode(rhs.endNode) @@ -326,7 +430,7 @@ std::string d_name; mutable std::set> children; mutable bool endNode; - mutable T d_value; + mutable T d_value{}; /* this structure is used to do a lookup without allocating and copying a string, using C++14's heterogeneous lookups in ordered @@ -622,6 +726,16 @@ } return ret; } + + std::vector toVector() const + { + std::vector ret; + ret.reserve(d_nodes.size()); + for (const auto& n : d_nodes) { + ret.emplace_back(n); + } + return ret; + } private: mutable std::set d_nodes; // Only used for string generation diff -Nru pdns-recursor-5.2.13/dnspacket.hh pdns-recursor-5.4.9/dnspacket.hh --- pdns-recursor-5.2.13/dnspacket.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnspacket.hh 2026-10-26 09:46:36.000000000 +0000 @@ -33,9 +33,10 @@ #include #include -#include #include #include +#include + #include "qtype.hh" #include "dns.hh" #include "misc.hh" @@ -58,7 +59,7 @@ const string& getString(bool throwsOnTruncation=false); //!< for serialization - just passes the whole packet. If throwsOnTruncation is set, an exception will be raised if the records are too large to fit inside a single DNS payload, instead of setting the TC bit // address & socket manipulation - void setRemote(const ComboAddress*, std::optional = std::nullopt); + void setRemote(const ComboAddress*); ComboAddress getRemote() const; ComboAddress getInnerRemote() const; // for proxy protocol Netmask getRealRemote() const; @@ -139,7 +140,7 @@ DNSName qdomain; //!< qname of the question 4 - unsure how this is used DNSName qdomainwild; //!< wildcard matched by qname, used by LuaPolicyEngine - DNSName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine + ZoneName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine and AXFR string d_peer_principal; const DNSName& getTSIGKeyname() const; @@ -177,6 +178,9 @@ void cleanupGSS(int rcode); #endif + Netmask d_span; // network matching this packet, when views are used + std::string d_view; // view matching this packet, when views are used + private: void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies diff -Nru pdns-recursor-5.2.13/dnsparser.cc pdns-recursor-5.4.9/dnsparser.cc --- pdns-recursor-5.2.13/dnsparser.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsparser.cc 2026-10-26 09:46:36.000000000 +0000 @@ -23,7 +23,11 @@ #include "dnswriter.hh" #include #include +#include +#include +#include +#include "dns_random.hh" #include "namespaces.hh" #include "noinitvector.hh" @@ -80,7 +84,7 @@ pw.xfrBlob(string(d_record.begin(),d_record.end())); } -shared_ptr DNSRecordContent::deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass) +shared_ptr DNSRecordContent::deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass, bool internalRepresentation) { dnsheader dnsheader; memset(&dnsheader, 0, sizeof(dnsheader)); @@ -118,10 +122,11 @@ dr.d_type = qtype; dr.d_name = qname; dr.d_clen = serialized.size(); - PacketReader pr(std::string_view(reinterpret_cast(packet.data()), packet.size()), packet.size() - serialized.size() - sizeof(dnsrecordheader)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): packet.data() is uint8_t * + PacketReader reader(std::string_view(reinterpret_cast(packet.data()), packet.size()), packet.size() - serialized.size() - sizeof(dnsrecordheader), internalRepresentation); /* needed to get the record boundaries right */ - pr.getDnsrecordheader(drh); - auto content = DNSRecordContent::make(dr, pr, Opcode::Query); + reader.getDnsrecordheader(drh); + auto content = DNSRecordContent::make(dr, reader, Opcode::Query); return content; } @@ -226,7 +231,7 @@ return resourceRecord; } -void MOADNSParser::init(bool query, const std::string_view& packet) +void MOADNSParser::init(bool query, const std::string_view& packet, size_t pointerBudget) { if (packet.size() < sizeof(dnsheader)) throw MOADNSException("Packet shorter than minimal header"); @@ -247,6 +252,9 @@ unsigned int n=0; PacketReader pr(packet); + if (pointerBudget != 0) { + pr.setPointerBudget(pointerBudget); + } bool validPacket=false; try { d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then @@ -344,7 +352,7 @@ } for (const auto& record : d_answers) { - if (record.d_place == DNSResourceRecord::ADDITIONAL && record.d_type == QType::OPT) { + if (record.d_place == DNSResourceRecord::ADDITIONAL && record.d_type == QType::OPT && record.d_name.isRoot()) { return true; } } @@ -352,6 +360,8 @@ return false; } +size_t PacketReader::s_MaxPointersPerByte = 4; + void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah) { unsigned char *p = reinterpret_cast(&ah); @@ -453,9 +463,9 @@ DNSName PacketReader::getName() { - unsigned int consumed; + unsigned int consumed{}; try { - DNSName dn((const char*) d_content.data(), d_content.size(), d_pos, true /* uncompress */, nullptr /* qtype */, nullptr /* qclass */, &consumed, sizeof(dnsheader)); + DNSName dn((const char*) d_content.data(), d_content.size(), d_pos, true /* uncompress */, nullptr /* qtype */, nullptr /* qclass */, &consumed, sizeof(dnsheader), &d_pointerBudget); d_pos+=consumed; return dn; @@ -469,22 +479,25 @@ throw PDNSException("PacketReader::getName(): name is empty"); } -static string txtEscape(const string &name) +// FIXME see #6010 and #3503 if you want a proper solution +string txtEscape(const string &name) { string ret; - char ebuf[5]; + std::array ebuf{}; - for(char i : name) { - if((unsigned char) i >= 127 || (unsigned char) i < 32) { - snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)i); - ret += ebuf; + for (char letter : name) { + const unsigned uch = static_cast(letter); + if (uch >= 127 || uch < 32) { + snprintf(ebuf.data(), ebuf.size(), "\\%03u", uch); + ret += ebuf.data(); } - else if(i=='"' || i=='\\'){ + else if (letter == '"' || letter == '\\'){ ret += '\\'; - ret += i; + ret += letter; + } + else { + ret += letter; } - else - ret += i; } return ret; } @@ -586,13 +599,22 @@ } void PacketReader::xfrSvcParamKeyVals(set &kvs) { + int32_t lastKey{-1}; // Keep track of the last key, as ordering should be strict + while (d_pos < (d_startrecordpos + d_recordlen)) { if (d_pos + 2 > (d_startrecordpos + d_recordlen)) { throw std::out_of_range("incomplete key"); } uint16_t keyInt; xfr16BitInt(keyInt); + + if (keyInt <= lastKey) { + throw std::out_of_range("Found SVCParamKey " + std::to_string(keyInt) + " after SVCParamKey " + std::to_string(lastKey)); + } + lastKey = keyInt; + auto key = static_cast(keyInt); + uint16_t len; xfr16BitInt(len); @@ -629,15 +651,19 @@ if (alpnLen == 0) { throw std::out_of_range("alpn length of 0"); } + if (d_pos + alpnLen > stop) { + throw std::out_of_range("alpn length is larger than rest of alpn SVC Param"); + } xfrBlob(alpn, alpnLen); - alpns.push_back(alpn); + alpns.push_back(std::move(alpn)); } kvs.insert(SvcParam(key, std::move(alpns))); break; } + case SvcParam::ohttp: case SvcParam::no_default_alpn: { if (len != 0) { - throw std::out_of_range("invalid length for no-default-alpn"); + throw std::out_of_range("invalid length for " + SvcParam::keyToString(key)); } kvs.insert(SvcParam(key)); break; @@ -651,7 +677,7 @@ kvs.insert(SvcParam(key, port)); break; } - case SvcParam::ipv4hint: /* fall-through */ + case SvcParam::ipv4hint: case SvcParam::ipv6hint: { size_t addrLen = (key == SvcParam::ipv4hint ? 4 : 16); if (len % addrLen != 0) { @@ -665,7 +691,13 @@ xfrCAWithoutPort(key, addr); addresses.push_back(addr); } - kvs.insert(SvcParam(key, std::move(addresses))); + // If there were no addresses, and the input comes from internal + // representation, we can reasonably assume this is the serialization + // of "auto". + bool doAuto{d_internal && len == 0}; + auto param = SvcParam(key, std::move(addresses)); + param.setAutoHint(doAuto); + kvs.insert(std::move(param)); break; } case SvcParam::ech: { @@ -675,6 +707,23 @@ kvs.insert(SvcParam(key, blob)); break; } + case SvcParam::tls_supported_groups: { + if (len % 2 != 0) { + throw std::out_of_range("invalid length for " + SvcParam::keyToString(key)); + } + vector groups; + groups.reserve(len / 2); + auto stop = d_pos + len; + while (d_pos < stop) + { + uint16_t group = 0; + xfr16BitInt(group); + groups.push_back(group); + } + auto param = SvcParam(key, std::move(groups)); + kvs.insert(std::move(param)); + break; + } default: { std::string blob; blob.reserve(len); @@ -862,7 +911,7 @@ if (qtypes.find(ah.d_type) == qtypes.end()) { // if this is not a safe type if (safeTypes.find(ah.d_type) == safeTypes.end()) { - // "unsafe" types might countain compressed data, so cancel rewrite + // "unsafe" types might contain compressed data, so cancel rewrite newContent.clear(); return EIO; } @@ -879,7 +928,7 @@ if (qtypes.find(ah.d_type) == qtypes.end()) { if (safeTypes.find(ah.d_type) == safeTypes.end()) { - // "unsafe" types might countain compressed data, so cancel rewrite + // "unsafe" types might contain compressed data, so cancel rewrite newContent.clear(); return EIO; } @@ -895,7 +944,7 @@ if (qtypes.find(ah.d_type) == qtypes.end()) { if (safeTypes.find(ah.d_type) == safeTypes.end()) { - // "unsafe" types might countain compressed data, so cancel rewrite + // "unsafe" types might contain compressed data, so cancel rewrite newContent.clear(); return EIO; } @@ -975,6 +1024,87 @@ ageDNSPacket(packet.data(), packet.length(), seconds, aligned_dh); } +void shuffleDNSPacket(char* packet, size_t length, const dnsheader_aligned& aligned_dh) +{ + if (length < sizeof(dnsheader)) { + return; + } + try { + const dnsheader* dhp = aligned_dh.get(); + const uint16_t ancount = ntohs(dhp->ancount); + if (ancount == 1) { + // quick exit, nothing to shuffle + return; + } + + DNSPacketMangler dpm(packet, length); + + const uint16_t qdcount = ntohs(dhp->qdcount); + + for(size_t iter = 0; iter < qdcount; ++iter) { + dpm.skipDomainName(); + /* type and class */ + dpm.skipBytes(4); + } + + // for now shuffle only first rrset, only As and AAAAs + uint16_t rrset_type = 0; + DNSName rrset_dnsname{}; + std::vector> rrdata_indexes; + rrdata_indexes.reserve(ancount); + + for(size_t iter = 0; iter < ancount; ++iter) { + auto domain_start = dpm.getOffset(); + dpm.skipDomainName(); + const uint16_t dnstype = dpm.get16BitInt(); + if (dnstype == QType::A || dnstype == QType::AAAA) { + if (rrdata_indexes.empty()) { + rrset_type = dnstype; + rrset_dnsname = DNSName(packet, length, domain_start, true); + } else { + if (dnstype != rrset_type) { + break; + } + if (DNSName(packet, length, domain_start, true) != rrset_dnsname) { + break; + } + } + /* class */ + dpm.skipBytes(2); + + /* ttl */ + dpm.skipBytes(4); + rrdata_indexes.push_back(dpm.skipRDataAndReturnOffsets()); + } else { + if (!rrdata_indexes.empty()) { + break; + } + /* class */ + dpm.skipBytes(2); + + /* ttl */ + dpm.skipBytes(4); + dpm.skipRData(); + } + } + + if (rrdata_indexes.size() >= 2) { + using uid = std::uniform_int_distribution>::size_type>; + uid dist; + + pdns::dns_random_engine randomEngine; + for (auto swapped = rrdata_indexes.size() - 1; swapped > 0; --swapped) { + auto swapped_with = dist(randomEngine, uid::param_type(0, swapped)); + if (swapped != swapped_with) { + dpm.swapInPlace(rrdata_indexes.at(swapped), rrdata_indexes.at(swapped_with)); + } + } + } + } + catch(...) { + } +} + uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA) { uint32_t result = std::numeric_limits::max(); @@ -1009,9 +1139,7 @@ } const uint32_t ttl = dpm.get32BitInt(); - if (result > ttl) { - result = ttl; - } + result = std::min(result, ttl); dpm.skipRData(); } @@ -1153,6 +1281,11 @@ try { const dnsheader_aligned dh(packet); + if (dh->arcount == 0) { + // The OPT pseudo-RR, if present, has to be in the additional section (https://datatracker.ietf.org/doc/html/rfc6891#section-6.1.1) + return false; + } + DNSPacketMangler dpm(const_cast(packet), length); const uint16_t qdcount = ntohs(dh->qdcount); @@ -1162,19 +1295,30 @@ dpm.skipBytes(4); } const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); - for(size_t n = 0; n < numrecords; ++n) { - dpm.skipDomainName(); - const uint16_t dnstype = dpm.get16BitInt(); - const uint16_t dnsclass = dpm.get16BitInt(); + for(size_t index = 0; index < numrecords; ++index) { + const auto wasRoot = dpm.skipDomainName(); + const auto dnstype = dpm.get16BitInt(); + uint8_t section{}; + if (index < ntohs(dh->ancount)) { + section = 1; + } + else if (index < ntohs(dh->ancount) + ntohs(dh->nscount)) { + section = 2; + } + else { + section = 3; + } - if(dnstype == QType::OPT) { + if (section == 3 && dnstype == QType::OPT && wasRoot) { + const auto dnsclass = dpm.get16BitInt(); /* skip extended rcode and version */ dpm.skipBytes(2); *z = dpm.get16BitInt(); *payloadSize = dnsclass; return true; } - + /* skip class */ + dpm.skipBytes(2); /* TTL */ dpm.skipBytes(4); dpm.skipRData(); diff -Nru pdns-recursor-5.2.13/dnsparser.hh pdns-recursor-5.4.9/dnsparser.hh --- pdns-recursor-5.2.13/dnsparser.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsparser.hh 2026-10-26 09:46:36.000000000 +0000 @@ -68,14 +68,22 @@ class PacketReader { public: - PacketReader(const std::string_view& content, uint16_t initialPos=sizeof(dnsheader)) - : d_pos(initialPos), d_startrecordpos(initialPos), d_content(content) + PacketReader(const std::string_view& content, uint16_t initialPos=sizeof(dnsheader), bool internalRepresentation = false) + : d_pos(initialPos), d_startrecordpos(initialPos), d_content(content), d_internal(internalRepresentation) { - if(content.size() > std::numeric_limits::max()) + if (content.size() > std::numeric_limits::max()) { throw std::out_of_range("packet too large"); + } - d_recordlen = (uint16_t) content.size(); not_used = 0; + d_recordlen = static_cast(content.size()); + d_pointerBudget = static_cast(d_recordlen) * s_MaxPointersPerByte; + } + + // Default is s_MaxPointersPerByte * packet size + void setPointerBudget(size_t maxPointers) + { + d_pointerBudget = maxPointers; } uint32_t get32BitInt(); @@ -136,7 +144,7 @@ val=get8BitInt(); } - void xfrName(DNSName& name, bool /* compress */ = false, bool /* noDot */ = false) + void xfrName(DNSName& name, bool /* compress */ = false) { name = getName(); } @@ -180,12 +188,16 @@ d_pos += n; } + static size_t s_MaxPointersPerByte; + private: + size_t d_pointerBudget{0}; uint16_t d_pos; uint16_t d_startrecordpos; // needed for getBlob later on uint16_t d_recordlen; // ditto uint16_t not_used; // Aligns the whole class on 8-byte boundaries const std::string_view d_content; + bool d_internal; }; struct DNSRecord; @@ -201,22 +213,28 @@ virtual std::string getZoneRepresentation(bool noDot=false) const = 0; virtual ~DNSRecordContent() = default; virtual void toPacket(DNSPacketWriter& pw) const = 0; - // returns the wire format of the content, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set) - string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) const + // returns the wire format of the content or the full record, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set) + [[nodiscard]] string serialize(const DNSName& qname, bool canonic = false, bool lowerCase = false, bool full = false) const { vector packet; - DNSPacketWriter pw(packet, g_rootdnsname, 1); - if(canonic) - pw.setCanonic(true); + DNSPacketWriter packetWriter(packet, g_rootdnsname, QType::A); - if(lowerCase) - pw.setLowercase(true); + if (canonic) { + packetWriter.setCanonic(true); + } + if (lowerCase) { + packetWriter.setLowercase(true); + } - pw.startRecord(qname, this->getType()); - this->toPacket(pw); + packetWriter.startRecord(qname, getType()); + toPacket(packetWriter); string record; - pw.getRecordPayload(record); // needs to be called before commit() + if (full) { + packetWriter.getWireFormatContent(record); // needs to be called before commit() + } else { + packetWriter.getRecordPayload(record); // needs to be called before commit() + } return record; } @@ -225,8 +243,10 @@ return typeid(*this)==typeid(rhs) && this->getZoneRepresentation() == rhs.getZoneRepresentation(); } - // parse the content in wire format, possibly including compressed pointers pointing to the owner name - static shared_ptr deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass=QClass::IN); + // parse the content in wire format, possibly including compressed pointers pointing to the owner name. + // internalRepresentation is set when the data comes from an internal source, + // such as the LMDB backend. + static shared_ptr deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass=QClass::IN, bool internalRepresentation = false); void doRecordCheck(const struct DNSRecord&){} @@ -284,6 +304,8 @@ d_locked.store(true); } + [[nodiscard]] virtual size_t sizeEstimate() const = 0; + protected: typedef std::map, makerfunc_t* > typemap_t; typedef std::map, zmakerfunc_t* > zmakermap_t; @@ -387,10 +409,13 @@ auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type; auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type; - if(a.d_name.canonCompare(b.d_name)) + int res = a.d_name.canonCompare_three_way(b.d_name, true); + if (res < 0) { return true; - if(b.d_name.canonCompare(a.d_name)) + } + if (res > 0) { return false; + } if(std::tie(aType, a.d_class, a.d_ttl) < std::tie(bType, b.d_class, b.d_ttl)) return true; @@ -424,17 +449,26 @@ return *d_content == *rhs.d_content; } + + [[nodiscard]] size_t sizeEstimate() const + { + return sizeof(*this) + d_name.sizeEstimate() + (d_content ? d_content->sizeEstimate() : 0U); + } }; struct DNSZoneRecord { - int domain_id{-1}; + domainid_t domain_id{UnknownDomainID}; uint8_t scopeMask{0}; int signttl{0}; DNSName wildcardname; bool auth{true}; bool disabled{false}; DNSRecord dr; + + bool operator<(const DNSZoneRecord& other) const { + return dr.d_ttl < other.dr.d_ttl; + } }; class UnknownRecordContent : public DNSRecordContent @@ -460,6 +494,11 @@ return d_record; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_dr.sizeEstimate() + d_record.size(); + } + private: DNSRecord d_dr; vector d_record; @@ -476,9 +515,9 @@ } //! Parse from a pointer and length - MOADNSParser(bool query, const char *packet, unsigned int len) : d_tsigPos(0) + MOADNSParser(bool query, const char *packet, unsigned int len, size_t pointerBudget = 0) : d_tsigPos(0) { - init(query, std::string_view(packet, len)); + init(query, std::string_view(packet, len), pointerBudget); } DNSName d_qname; @@ -498,11 +537,12 @@ bool hasEDNS() const; private: - void init(bool query, const std::string_view& packet); + void init(bool query, const std::string_view& packet, size_t pointerBudget = 0); uint16_t d_tsigPos; }; string simpleCompress(const string& label, const string& root=""); +void shuffleDNSPacket(char* packet, size_t length, const dnsheader_aligned& aligned_dh); void ageDNSPacket(char* packet, size_t length, uint32_t seconds, const dnsheader_aligned&); void ageDNSPacket(std::string& packet, uint32_t seconds, const dnsheader_aligned&); void editDNSPacketTTL(char* packet, size_t length, const std::function& visitor); @@ -539,16 +579,19 @@ * The name is not checked for adherence to length restrictions. * Compression pointers are not followed. */ - void skipDomainName() + bool skipDomainName() { - uint8_t len; - while((len=get8BitInt())) { - if(len >= 0xc0) { // extended label + uint8_t len{}; + bool isRoot = true; + while ((len = get8BitInt()) != 0) { + isRoot = false; + if (len >= 0xc0) { // extended label get8BitInt(); - return; + return false; } skipBytes(len); } + return isRoot; } void skipBytes(uint16_t bytes) @@ -585,8 +628,17 @@ void skipRData() { - int toskip = get16BitInt(); + auto toskip = get16BitInt(); + moveOffset(toskip); + } + + std::pair skipRDataAndReturnOffsets() + { + auto toskip = get16BitInt(); + uint32_t start = d_offset; moveOffset(toskip); + uint32_t end = d_offset; + return std::pair(start, end); } void decreaseAndSkip32BitInt(uint32_t decrease) @@ -619,6 +671,30 @@ return d_offset; } + void swapInPlace(std::pair a, std::pair b) { + // some basic range checks + if (b.first < a.first) { + std::swap(a, b); + } + if (a.second-a.first != b.second-b.first) { + throw std::out_of_range("swap: segments have different lengths"); + } + if (a.second <= a.first) { + throw std::out_of_range("swap: ending of segment before start of segment"); + } + if (a.second > b.first) { + throw std::out_of_range("swap: overlapping segments"); + } + if (b.second > d_length) { + throw std::out_of_range("swap: ending of segment after end of array"); + } + // don't allow to swap what we haven't read yet + if (b.second > d_offset) { + throw std::out_of_range("swap: ending of segment after current offset"); + } + std::swap_ranges(d_packet+a.first, d_packet+a.second, d_packet+b.first); + } + private: void moveOffset(uint16_t by) { @@ -645,3 +721,5 @@ uint32_t d_notyouroffset; // only 'moveOffset' can touch this const uint32_t& d_offset; // look.. but don't touch }; + +string txtEscape(const string &name); diff -Nru pdns-recursor-5.2.13/dnsrecords.cc pdns-recursor-5.4.9/dnsrecords.cc --- pdns-recursor-5.2.13/dnsrecords.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsrecords.cc 2026-10-26 09:46:36.000000000 +0000 @@ -36,7 +36,10 @@ case QType::MX: if (content.size() >= 2 && *(content.rbegin()+1) == ' ') return; - /* Falls through. */ + [[fallthrough]]; +#if !defined(RECURSOR) + case QType::ALIAS: +#endif case QType::CNAME: case QType::DNAME: case QType::NS: @@ -64,6 +67,9 @@ if (*(last.rbegin()) != '.' && !noDot) ret << "."; break; +#if !defined(RECURSOR) + case QType::ALIAS: +#endif case QType::CNAME: case QType::DNAME: case QType::NS: @@ -79,7 +85,7 @@ return ret.str(); } -bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs) +bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs) const { string lcontent=toLower(content); string rcontent=toLower(rhs.content); @@ -89,7 +95,9 @@ std::tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl); } +//NOLINTBEGIN boilerplate_conv(A, conv.xfrIP(d_ip)); +//NOLINTEND ARecordContent::ARecordContent(uint32_t ip) { @@ -135,6 +143,7 @@ throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")"); } +//NOLINTBEGIN boilerplate_conv(AAAA, conv.xfrIP6(d_ip6); ); boilerplate_conv(NS, conv.xfrName(d_content, true)); @@ -165,6 +174,7 @@ boilerplate_conv(OPT, conv.xfrBlob(d_data) ); +//NOLINTEND #ifdef HAVE_LUA_RECORDS @@ -211,6 +221,7 @@ } } +//NOLINTBEGIN boilerplate_conv(TSIG, conv.xfrName(d_algoName); conv.xfr48BitInt(d_time); @@ -224,11 +235,13 @@ conv.xfr16BitInt(size); if (size>0) conv.xfrBlobNoSpaces(d_otherData, size); ); +//NOLINTEND MXRecordContent::MXRecordContent(uint16_t preference, DNSName mxname): d_preference(preference), d_mxname(std::move(mxname)) { } +//NOLINTBEGIN boilerplate_conv(MX, conv.xfr16BitInt(d_preference); conv.xfrName(d_mxname, true); @@ -289,22 +302,26 @@ conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); conv.xfrName(d_replacement); ) +//NOLINTEND SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName target) : d_weight(weight), d_port(port), d_target(std::move(target)), d_preference(preference) {} +//NOLINTBEGIN boilerplate_conv(SRV, conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); conv.xfrName(d_target); ) +//NOLINTEND SOARecordContent::SOARecordContent(DNSName mname, DNSName rname, const struct soatimes& st) : d_mname(std::move(mname)), d_rname(std::move(rname)), d_st(st) { } +//NOLINTBEGIN boilerplate_conv(SOA, conv.xfrName(d_mname, true); conv.xfrName(d_rname, true); @@ -351,7 +368,7 @@ boilerplate_conv(SVCB, conv.xfr16BitInt(d_priority); - conv.xfrName(d_target, false, true); + conv.xfrName(d_target, false); if (d_priority != 0) { conv.xfrSvcParamKeyVals(d_params); } @@ -359,12 +376,20 @@ boilerplate_conv(HTTPS, conv.xfr16BitInt(d_priority); - conv.xfrName(d_target, false, true); + conv.xfrName(d_target, false); if (d_priority != 0) { conv.xfrSvcParamKeyVals(d_params); } ) +boilerplate_conv(HHIT, + conv.xfrBlob(d_data); + ) + +boilerplate_conv(BRID, + conv.xfrBlob(d_data); + ) + boilerplate_conv(SMIMEA, conv.xfr8BitInt(d_certusage); conv.xfr8BitInt(d_selector); @@ -456,6 +481,7 @@ boilerplate_conv(LP, conv.xfr16BitInt(d_preference); conv.xfrName(d_fqdn, false);) +//NOLINTEND /* EUI48 start */ void EUI48RecordContent::report(const ReportIsOnlyCallableByReportAllTypes& /* unused */) @@ -780,7 +806,7 @@ try { auto newParam = SvcParam(key, std::move(h)); d_params.erase(p); - d_params.insert(newParam); + d_params.insert(std::move(newParam)); } catch (...) { // XXX maybe we should SERVFAIL instead? return; @@ -812,11 +838,7 @@ } set::const_iterator SVCBBaseRecordContent::getParamIt(const SvcParam::SvcParamKey &key) const { - auto p = std::find_if(d_params.begin(), d_params.end(), - [&key](const SvcParam ¶m) { - return param.getKey() == key; - }); - return p; + return std::find(d_params.begin(), d_params.end(), key); } std::shared_ptr SVCBRecordContent::clone() const @@ -831,6 +853,17 @@ /* SVCB end */ +std::shared_ptr HHITRecordContent::clone() const +{ + return {std::make_shared(*this)}; +} + +std::shared_ptr BRIDRecordContent::clone() const +{ + return {std::make_shared(*this)}; +} + +//NOLINTBEGIN boilerplate_conv(TKEY, conv.xfrName(d_algo); conv.xfr32BitInt(d_inception); @@ -856,6 +889,9 @@ conv.xfrText(d_value, true, false); /* no lenField */ ) +boilerplate_conv(RESINFO, conv.xfrText(d_text, true)); +//NOLINTEND + static uint16_t makeTag(const std::string& data) { const unsigned char* key=(const unsigned char*)data.c_str(); @@ -961,6 +997,8 @@ OPENPGPKEYRecordContent::report(guard); SVCBRecordContent::report(guard); HTTPSRecordContent::report(guard); + HHITRecordContent::report(guard); + BRIDRecordContent::report(guard); DLVRecordContent::report(guard); DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY"); @@ -971,6 +1009,7 @@ MINFORecordContent::report(guard); URIRecordContent::report(guard); CAARecordContent::report(guard); + RESINFORecordContent::report(guard); APLRecordContent::report(guard); IPSECKEYRecordContent::report(guard); CSYNCRecordContent::report(guard); @@ -1007,7 +1046,7 @@ /** * Check if the DNSNames that should be hostnames, are hostnames */ -void checkHostnameCorrectness(const DNSResourceRecord& rr) +void checkHostnameCorrectness(const DNSResourceRecord& rr, bool allowUnderscore) // NOLINT(readability-identifier-length) { if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) { DNSName toCheck; @@ -1028,7 +1067,7 @@ } else if ((rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) && toCheck == g_rootdnsname) { // allow null MX/SRV - } else if(!toCheck.isHostname()) { + } else if(!toCheck.isHostname(allowUnderscore)) { throw std::runtime_error(boost::str(boost::format("non-hostname content %s") % toCheck.toString())); } } diff -Nru pdns-recursor-5.2.13/dnsrecords.hh pdns-recursor-5.4.9/dnsrecords.hh --- pdns-recursor-5.2.13/dnsrecords.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsrecords.hh 2026-10-26 09:46:36.000000000 +0000 @@ -30,22 +30,26 @@ #include "rcpgenerator.hh" #include #include +#include #include "namespaces.hh" #include "iputils.hh" #include "svc-records.hh" struct ReportIsOnlyCallableByReportAllTypes; -#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ - RNAME##RecordContent(const string& zoneData); \ - static void report(const ReportIsOnlyCallableByReportAllTypes& guard); \ - static std::shared_ptr make(const DNSRecord &dr, PacketReader& pr); \ - static std::shared_ptr make(const string& zonedata); \ - string getZoneRepresentation(bool noDot=false) const override; \ - void toPacket(DNSPacketWriter& pw) const override; \ - uint16_t getType() const override { return QType::RNAME; } \ - template void xfrPacket(Convertor& conv, bool noDot=false) const; \ - template void xfrPacket(Convertor& conv, bool noDot=false); +#define includeboilerplate(RNAME) \ + RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ + RNAME##RecordContent(const string& zoneData); \ + static void report(const ReportIsOnlyCallableByReportAllTypes& guard); \ + static std::shared_ptr make(const DNSRecord& dr, PacketReader& pr); \ + static std::shared_ptr make(const string& zonedata); \ + string getZoneRepresentation(bool noDot = false) const override; \ + void toPacket(DNSPacketWriter& pw) const override; \ + uint16_t getType() const override { return QType::RNAME; } \ + template \ + void xfrPacket(Convertor& conv, bool noDot = false) const; \ + template \ + void xfrPacket(Convertor& conv, bool noDot = false); class NAPTRRecordContent : public DNSRecordContent { @@ -62,6 +66,10 @@ { return d_replacement; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_replacement.sizeEstimate() + d_flags.size() + d_services.size() + d_regexp.size(); + } private: uint16_t d_order, d_preference; string d_flags, d_services, d_regexp; @@ -83,6 +91,10 @@ return false; return d_ip == dynamic_cast(rhs).d_ip; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: uint32_t d_ip; }; @@ -100,6 +112,10 @@ return false; return d_ip6 == dynamic_cast(&rhs)->d_ip6; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_ip6.size(); + } private: string d_ip6; // why?? }; @@ -121,7 +137,10 @@ auto rrhs =dynamic_cast(&rhs); return std::tie(d_preference, d_mxname) == std::tie(rrhs->d_preference, rrhs->d_mxname); } - + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_mxname.sizeEstimate(); + } }; class KXRecordContent : public DNSRecordContent @@ -131,6 +150,10 @@ includeboilerplate(KX) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_exchanger.sizeEstimate(); + } private: uint16_t d_preference; DNSName d_exchanger; @@ -143,6 +166,10 @@ includeboilerplate(IPSECKEY) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_gateway.sizeEstimate() + d_publickey.size() + d_ip6.size(); + } private: uint32_t d_ip4; DNSName d_gateway; @@ -155,6 +182,10 @@ { public: includeboilerplate(DHCID) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.size(); + } private: string d_content; @@ -167,6 +198,10 @@ SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName target); includeboilerplate(SRV) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_target.sizeEstimate(); + } uint16_t d_weight, d_port; DNSName d_target; @@ -178,6 +213,10 @@ public: includeboilerplate(TSIG) TSIGRecordContent() = default; + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_algoName.sizeEstimate() + d_mac.size() + d_otherData.size(); + } uint16_t d_origID{0}; uint16_t d_fudge{0}; @@ -197,6 +236,11 @@ public: includeboilerplate(TXT) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_text.size(); + } + string d_text; }; @@ -205,6 +249,10 @@ { public: includeboilerplate(LUA) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + getCode().size(); + } string getCode() const; uint16_t d_type; string d_code; @@ -215,6 +263,10 @@ { public: includeboilerplate(ENT) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } }; class SPFRecordContent : public DNSRecordContent @@ -225,6 +277,10 @@ { return d_text; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_text.size(); + } private: string d_text; @@ -234,8 +290,8 @@ class NSRecordContent : public DNSRecordContent { public: - includeboilerplate(NS) - explicit NSRecordContent(const DNSName& content) : d_content(content){} + includeboilerplate(NS) explicit NSRecordContent(DNSName content) : + d_content(std::move(content)) {} const DNSName& getNS() const { return d_content; } bool operator==(const DNSRecordContent& rhs) const override { @@ -244,7 +300,10 @@ auto rrhs =dynamic_cast(&rhs); return d_content == rrhs->d_content; } - + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.sizeEstimate(); + } private: DNSName d_content; }; @@ -252,9 +311,13 @@ class PTRRecordContent : public DNSRecordContent { public: - includeboilerplate(PTR) - explicit PTRRecordContent(const DNSName& content) : d_content(content){} + includeboilerplate(PTR) explicit PTRRecordContent(DNSName content) : + d_content(std::move(content)) {} const DNSName& getContent() const { return d_content; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.sizeEstimate(); + } private: DNSName d_content; }; @@ -263,8 +326,13 @@ { public: includeboilerplate(CNAME) - CNAMERecordContent(const DNSName& content) : d_content(content){} + CNAMERecordContent(DNSName content) : + d_content(std::move(content)) {} DNSName getTarget() const { return d_content; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.sizeEstimate(); + } private: DNSName d_content; }; @@ -279,6 +347,10 @@ { return d_content; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.sizeEstimate(); + } private: DNSName d_content; }; @@ -288,8 +360,13 @@ { public: includeboilerplate(DNAME) - DNAMERecordContent(const DNSName& content) : d_content(content){} + DNAMERecordContent(DNSName content) : + d_content(std::move(content)) {} const DNSName& getTarget() const { return d_content; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_content.sizeEstimate(); + } private: DNSName d_content; }; @@ -299,6 +376,10 @@ { public: includeboilerplate(MB) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_madname.sizeEstimate(); + } private: DNSName d_madname; @@ -308,6 +389,10 @@ { public: includeboilerplate(MG) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_mgmname.sizeEstimate(); + } private: DNSName d_mgmname; @@ -317,6 +402,10 @@ { public: includeboilerplate(MR) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_alias.sizeEstimate(); + } private: DNSName d_alias; @@ -326,6 +415,10 @@ { public: includeboilerplate(MINFO) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_rmailbx.sizeEstimate() + d_emailbx.sizeEstimate(); + } private: DNSName d_rmailbx; @@ -338,6 +431,10 @@ OPTRecordContent() = default; includeboilerplate(OPT) void getData(vector > &opts) const; + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_data.size(); + } private: string d_data; }; @@ -347,6 +444,10 @@ { public: includeboilerplate(HINFO) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_cpu.size() + d_host.size(); + } private: string d_cpu, d_host; @@ -356,7 +457,10 @@ { public: includeboilerplate(RP) - + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_mbox.sizeEstimate() + d_info.sizeEstimate(); + } private: DNSName d_mbox, d_info; }; @@ -378,6 +482,10 @@ return std::tie(d_flags, d_protocol, d_algorithm, d_key) < std::tie(rhs.d_flags, rhs.d_protocol, rhs.d_algorithm, rhs.d_key); } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_key.size(); + } }; class CDNSKEYRecordContent : public DNSRecordContent @@ -386,6 +494,10 @@ CDNSKEYRecordContent(); includeboilerplate(CDNSKEY) uint16_t getTag(); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_key.size(); + } uint16_t d_flags{0}; uint8_t d_protocol{0}; @@ -412,6 +524,10 @@ } includeboilerplate(DS) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_digest.size(); + } uint16_t d_tag{0}; uint8_t d_algorithm{0}, d_digesttype{0}; @@ -423,6 +539,10 @@ public: CDSRecordContent(); includeboilerplate(CDS) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_digest.size(); + } uint16_t d_tag{0}; uint8_t d_algorithm{0}, d_digesttype{0}; @@ -434,6 +554,10 @@ public: DLVRecordContent(); includeboilerplate(DLV) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_digest.size(); + } uint16_t d_tag{0}; uint8_t d_algorithm{0}, d_digesttype{0}; @@ -445,6 +569,10 @@ { public: includeboilerplate(SSHFP) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_fingerprint.size(); + } private: uint8_t d_algorithm, d_fptype; @@ -455,6 +583,10 @@ { public: includeboilerplate(KEY) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_certificate.size(); + } private: uint16_t d_flags; @@ -466,6 +598,10 @@ { public: includeboilerplate(AFSDB) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_hostname.sizeEstimate(); + } private: uint16_t d_subtype; @@ -481,6 +617,10 @@ { public: includeboilerplate(CERT) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_certificate.size(); + } private: uint16_t d_type, d_tag; @@ -492,6 +632,10 @@ { public: includeboilerplate(TLSA) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_cert.size(); + } private: uint8_t d_certusage, d_selector, d_matchtype; @@ -502,6 +646,10 @@ { public: includeboilerplate(SMIMEA) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_cert.size(); + } private: uint8_t d_certusage, d_selector, d_matchtype; @@ -512,6 +660,10 @@ { public: includeboilerplate(OPENPGPKEY) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_keyring.size(); + } private: string d_keyring; @@ -536,6 +688,11 @@ SvcParam getParam(const SvcParam::SvcParamKey &key) const; virtual std::shared_ptr clone() const = 0; + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_params.size() * sizeof(SvcParam) + d_target.sizeEstimate(); + } + protected: std::set d_params; DNSName d_target; @@ -559,12 +716,40 @@ std::shared_ptr clone() const override; }; +class DRIPBaseRecordContent : public DNSKEYRecordContent +{ +public: + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_data.size(); + } + virtual std::shared_ptr clone() const = 0; +protected: + string d_data; +}; + +class HHITRecordContent : public DRIPBaseRecordContent { +public: + includeboilerplate(HHIT); + std::shared_ptr clone() const override; +}; + +class BRIDRecordContent : public DRIPBaseRecordContent { +public: + includeboilerplate(BRID); + std::shared_ptr clone() const override; +}; + class RRSIGRecordContent : public DNSRecordContent { public: RRSIGRecordContent(); includeboilerplate(RRSIG) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_signer.sizeEstimate() + d_signature.size(); + } uint16_t d_type{0}; uint16_t d_tag{0}; DNSName d_signer; @@ -589,6 +774,10 @@ public: RKEYRecordContent(); includeboilerplate(RKEY) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_key.size(); + } uint16_t d_flags{0}; uint8_t d_protocol{0}, d_algorithm{0}; string d_key; @@ -600,6 +789,10 @@ includeboilerplate(SOA) SOARecordContent(DNSName mname, DNSName rname, const struct soatimes& st); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_mname.sizeEstimate() + d_rname.sizeEstimate(); + } DNSName d_mname; DNSName d_rname; struct soatimes d_st; @@ -611,6 +804,10 @@ includeboilerplate(ZONEMD) //ZONEMDRecordContent(uint32_t serial, uint8_t scheme, uint8_t hashalgo, string digest); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_digest.size(); + } uint32_t d_serial; uint8_t d_scheme; uint8_t d_hashalgo; @@ -680,6 +877,14 @@ static constexpr size_t const nbTypes = 65536; + [[nodiscard]] size_t sizeEstimate() const + { + // for tree: size() nodes of roughly the size of the head node (very rough estimate as tree + // implementations can vary wildly on how they represent nodes of the tree, but we cannot access + // that private info) + return d_bitset ? nbTypes / 8 : d_set.size() * sizeof(std::set); + } + private: void migrateToBitSet() @@ -704,7 +909,7 @@ public: static void report(const ReportIsOnlyCallableByReportAllTypes& guard); NSECRecordContent() = default; - NSECRecordContent(const string& content, const DNSName& zone=DNSName()); + NSECRecordContent(const string& content, const ZoneName& zone=ZoneName()); static std::shared_ptr make(const DNSRecord &dr, PacketReader& pr); static std::shared_ptr make(const string& content); @@ -731,6 +936,10 @@ return d_bitmap.count(); } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_next.sizeEstimate() + d_bitmap.sizeEstimate(); + } DNSName d_next; private: NSECBitmap d_bitmap; @@ -741,7 +950,7 @@ public: static void report(const ReportIsOnlyCallableByReportAllTypes& guard); NSEC3RecordContent() = default; - NSEC3RecordContent(const string& content, const DNSName& zone=DNSName()); + NSEC3RecordContent(const string& content, const ZoneName& zone=ZoneName()); static std::shared_ptr make(const DNSRecord &dr, PacketReader& pr); static std::shared_ptr make(const string& content); @@ -778,6 +987,10 @@ return d_flags & 1; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_salt.size() + d_nexthash.size() + d_bitmap.sizeEstimate(); + } private: NSECBitmap d_bitmap; }; @@ -787,7 +1000,7 @@ public: static void report(const ReportIsOnlyCallableByReportAllTypes& guard); CSYNCRecordContent() = default; - CSYNCRecordContent(const string& content, const DNSName& zone=DNSName()); + CSYNCRecordContent(const string& content, const ZoneName& zone=ZoneName()); static std::shared_ptr make(const DNSRecord &dr, PacketReader& pr); static std::shared_ptr make(const string& content); @@ -804,6 +1017,11 @@ d_bitmap.set(type); } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_bitmap.sizeEstimate(); + } + private: uint32_t d_serial{0}; uint16_t d_flags{0}; @@ -815,7 +1033,7 @@ public: static void report(const ReportIsOnlyCallableByReportAllTypes& guard); NSEC3PARAMRecordContent() = default; - NSEC3PARAMRecordContent(const string& content, const DNSName& zone=DNSName()); + NSEC3PARAMRecordContent(const string& content, const ZoneName& zone=ZoneName()); static std::shared_ptr make(const DNSRecord &dr, PacketReader& pr); static std::shared_ptr make(const string& content); @@ -827,6 +1045,10 @@ return QType::NSEC3PARAM; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_salt.size(); + } uint8_t d_algorithm{0}, d_flags{0}; uint16_t d_iterations{0}; @@ -853,6 +1075,10 @@ return QType::LOC; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: }; @@ -861,6 +1087,10 @@ { public: includeboilerplate(NID); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: uint16_t d_preference; @@ -871,6 +1101,10 @@ { public: includeboilerplate(L32); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: uint16_t d_preference; @@ -881,6 +1115,10 @@ { public: includeboilerplate(L64); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: uint16_t d_preference; @@ -891,6 +1129,10 @@ { public: includeboilerplate(LP); + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_fqdn.sizeEstimate(); + } private: uint16_t d_preference; @@ -907,6 +1149,10 @@ string getZoneRepresentation(bool noDot=false) const override; void toPacket(DNSPacketWriter& pw) const override; uint16_t getType() const override { return QType::EUI48; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: // storage for the bytes uint8_t d_eui48[6]; @@ -922,6 +1168,10 @@ string getZoneRepresentation(bool noDot=false) const override; void toPacket(DNSPacketWriter& pw) const override; uint16_t getType() const override { return QType::EUI64; } + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this); + } private: // storage for the bytes uint8_t d_eui64[8]; @@ -944,6 +1194,10 @@ public: APLRecordContent() = default; includeboilerplate(APL) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + aplrdata.size() * sizeof(APLRDataElement); + } private: std::vector aplrdata; APLRDataElement parseAPLElement(const string &element); @@ -955,6 +1209,10 @@ public: TKEYRecordContent(); includeboilerplate(TKEY) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_algo.sizeEstimate() + d_key.size() + d_other.size(); + } // storage for the bytes uint16_t d_othersize{0}; @@ -974,19 +1232,40 @@ class URIRecordContent : public DNSRecordContent { public: includeboilerplate(URI) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_target.size(); + } private: uint16_t d_priority, d_weight; string d_target; }; class CAARecordContent : public DNSRecordContent { - public: - includeboilerplate(CAA) - private: +public: + includeboilerplate(CAA) + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_tag.size() + d_value.size(); + } +private: uint8_t d_flags; string d_tag, d_value; }; +class RESINFORecordContent : public DNSRecordContent +{ +public: + includeboilerplate(RESINFO) + + [[nodiscard]] size_t sizeEstimate() const override + { + return sizeof(*this) + d_text.size(); + } + + string d_text; +}; + #define boilerplate(RNAME) \ std::shared_ptr RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \ { \ @@ -1022,7 +1301,7 @@ xfrPacket(rtr); \ } \ catch(RecordTextException& rte) { \ - throw MOADNSException("Parsing record content (try 'pdnsutil check-zone'): "+string(rte.what())); \ + throw MOADNSException("Parsing record content (try 'pdnsutil zone check'): "+string(rte.what())); \ } \ } \ \ @@ -1059,6 +1338,10 @@ uint8_t d_extRCode, d_version; [[nodiscard]] vector>::const_iterator getFirstOption(uint16_t optionCode) const; + [[nodiscard]] uint16_t getCombinedERCode(uint8_t rcode) const + { + return (static_cast(d_extRCode) << 4) | rcode; + } }; //! Convenience function that fills out EDNS0 options, and returns true if there are any @@ -1066,4 +1349,4 @@ bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo); void reportAllTypes(); ComboAddress getAddr(const DNSRecord& dr, uint16_t defport=0); -void checkHostnameCorrectness(const DNSResourceRecord& rr); +void checkHostnameCorrectness(const DNSResourceRecord& rr, bool allowUnderscore = false); diff -Nru pdns-recursor-5.2.13/dnssec.hh pdns-recursor-5.4.9/dnssec.hh --- pdns-recursor-5.2.13/dnssec.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/dnssec.hh 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,189 @@ +/* + * 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 +#include "misc.hh" + +class DNSSEC +{ +public: + enum keytype_t : uint8_t + { + KSK, + ZSK, + CSK + }; + enum keyalgorithm_t : uint8_t + { + RSAMD5 = 1, + DH = 2, + DSA = 3, + RSASHA1 = 5, + DSANSEC3SHA1 = 6, + RSASHA1NSEC3SHA1 = 7, + RSASHA256 = 8, + RSASHA512 = 10, + ECCGOST = 12, + ECDSA256 = 13, + ECDSA384 = 14, + ED25519 = 15, + ED448 = 16 + }; + + enum dsdigestalgorithm_t : uint8_t + { + DIGEST_SHA1 = 1, + DIGEST_SHA256 = 2, + DIGEST_GOST = 3, + DIGEST_SHA384 = 4 + }; + + static std::string keyTypeToString(keytype_t keyType) + { + switch (keyType) { + case DNSSEC::KSK: + return "KSK"; + case DNSSEC::ZSK: + return "ZSK"; + case DNSSEC::CSK: + return "CSK"; + default: + return "UNKNOWN"; + } + } + + /* + * Returns the algorithm number based on the mnemonic (or old PowerDNS value of) a string. + * See https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml for the mapping + */ + static int shorthand2algorithm(const std::string& algorithm) + { + // XXX map based approach likely better + if (pdns_iequals(algorithm, "rsamd5")) { + return RSAMD5; + } + if (pdns_iequals(algorithm, "dh")) { + return DH; + } + if (pdns_iequals(algorithm, "dsa")) { + return DSA; + } + if (pdns_iequals(algorithm, "rsasha1")) { + return RSASHA1; + } + if (pdns_iequals(algorithm, "dsa-nsec3-sha1")) { + return DSANSEC3SHA1; + } + if (pdns_iequals(algorithm, "rsasha1-nsec3-sha1")) { + return RSASHA1NSEC3SHA1; + } + if (pdns_iequals(algorithm, "rsasha256")) { + return RSASHA256; + } + if (pdns_iequals(algorithm, "rsasha512")) { + return RSASHA512; + } + if (pdns_iequals(algorithm, "ecc-gost")) { + return ECCGOST; + } + if (pdns_iequals(algorithm, "gost")) { + return ECCGOST; + } + if (pdns_iequals(algorithm, "ecdsa256")) { + return ECDSA256; + } + if (pdns_iequals(algorithm, "ecdsap256sha256")) { + return ECDSA256; + } + if (pdns_iequals(algorithm, "ecdsa384")) { + return ECDSA384; + } + if (pdns_iequals(algorithm, "ecdsap384sha384")) { + return ECDSA384; + } + if (pdns_iequals(algorithm, "ed25519")) { + return ED25519; + } + if (pdns_iequals(algorithm, "ed448")) { + return ED448; + } + if (pdns_iequals(algorithm, "indirect")) { + return 252; + } + if (pdns_iequals(algorithm, "privatedns")) { + return 253; + } + if (pdns_iequals(algorithm, "privateoid")) { + return 254; + } + return -1; + } + + /* + * Returns the mnemonic from https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml + */ + static std::string algorithm2name(uint8_t algo) + { + switch (algo) { + case 0: + case 4: + case 9: + case 11: + return "Reserved"; + case RSAMD5: + return "RSAMD5"; + case DH: + return "DH"; + case DSA: + return "DSA"; + case RSASHA1: + return "RSASHA1"; + case DSANSEC3SHA1: + return "DSA-NSEC3-SHA1"; + case RSASHA1NSEC3SHA1: + return "RSASHA1-NSEC3-SHA1"; + case RSASHA256: + return "RSASHA256"; + case RSASHA512: + return "RSASHA512"; + case ECCGOST: + return "ECC-GOST"; + case ECDSA256: + return "ECDSAP256SHA256"; + case ECDSA384: + return "ECDSAP384SHA384"; + case ED25519: + return "ED25519"; + case ED448: + return "ED448"; + case 252: + return "INDIRECT"; + case 253: + return "PRIVATEDNS"; + case 254: + return "PRIVATEOID"; + default: + return "Unallocated/Reserved"; + } + } +}; diff -Nru pdns-recursor-5.2.13/dnssecinfra.cc pdns-recursor-5.4.9/dnssecinfra.cc --- pdns-recursor-5.2.13/dnssecinfra.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnssecinfra.cc 2026-10-26 09:46:36.000000000 +0000 @@ -35,7 +35,7 @@ #include #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include #include #include // for 'operator+=()' @@ -247,7 +247,7 @@ else { first = false; } - ret.append(DNSSECKeeper::algorithm2name(algo)); + ret.append(DNSSEC::algorithm2name(algo)); if (isAlgorithmSwitchedOff(algo)) { ret.append("(disabled)"); } @@ -373,11 +373,11 @@ string b64pubkey; string b64sig; switch (algo) { - case DNSSECKeeper::RSASHA1: + case DNSSEC::RSASHA1: b64pubkey = pubkey5; b64sig = sig5; break; - case DNSSECKeeper::RSASHA1NSEC3SHA1: + case DNSSEC::RSASHA1NSEC3SHA1: b64pubkey = pubkey7; b64sig = sig7; break; @@ -428,18 +428,23 @@ auto dckeSign = signer(algo); auto dckeVerify = verifier(algo); - cout<<"Testing algorithm "<getName()<<"' ->'"<getName()<<"' -> '"<getName()<<"' "; - unsigned int bits; - if(algo <= 10) - bits=2048; - else if(algo == DNSSECKeeper::ECCGOST || algo == DNSSECKeeper::ECDSA256 || algo == DNSSECKeeper::ED25519) + cout<<"Testing algorithm "<getName()<<"' ->'"<getName()<<"' -> '"<getName()<<"' "; + unsigned int bits{}; + if(algo <= 10) { + bits = 2048; + } + else if(algo == DNSSEC::ECCGOST || algo == DNSSEC::ECDSA256 || algo == DNSSEC::ED25519) { bits = 256; - else if(algo == DNSSECKeeper::ECDSA384) + } + else if(algo == DNSSEC::ECDSA384) { bits = 384; - else if(algo == DNSSECKeeper::ED448) + } + else if(algo == DNSSEC::ED448) { bits = 456; - else - throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo)); + } + else { + throw runtime_error("Can't guess key size for algorithm " + std::to_string(algo)); + } DTime dt; dt.set(); for(unsigned int n = 0; n < 100; ++n) @@ -532,7 +537,7 @@ return {}; } DNSName choppedQname(qname); - while (choppedQname.countLabels() > rrsig_labels) { + for (auto nlabels = fqdn_labels; nlabels > rrsig_labels; --nlabels) { choppedQname.chopOff(); } nameToHash = "\x01*" + choppedQname.toDNSStringLC(); @@ -586,14 +591,14 @@ static unsigned int digestToAlgorithmNumber(uint8_t digest) { switch(digest) { - case DNSSECKeeper::DIGEST_SHA1: - return DNSSECKeeper::RSASHA1; - case DNSSECKeeper::DIGEST_SHA256: - return DNSSECKeeper::RSASHA256; - case DNSSECKeeper::DIGEST_GOST: - return DNSSECKeeper::ECCGOST; - case DNSSECKeeper::DIGEST_SHA384: - return DNSSECKeeper::ECDSA384; + case DNSSEC::DIGEST_SHA1: + return DNSSEC::RSASHA1; + case DNSSEC::DIGEST_SHA256: + return DNSSEC::RSASHA256; + case DNSSEC::DIGEST_GOST: + return DNSSEC::ECCGOST; + case DNSSEC::DIGEST_SHA384: + return DNSSEC::ECDSA384; default: throw std::runtime_error("Unknown digest type " + std::to_string(digest)); } @@ -790,7 +795,7 @@ DNSPacketWriter dw(signVect, DNSName(), 0); auto pos=signVect.size(); if(!timersonly) { - dw.xfrName(tsigKeyName, false); + dw.xfrName(tsigKeyName.makeLowerCase(), false); dw.xfr16BitInt(QClass::ANY); // class dw.xfr32BitInt(0); // TTL dw.xfrName(trc.d_algoName.makeLowerCase(), false); diff -Nru pdns-recursor-5.2.13/dnssecinfra.hh pdns-recursor-5.4.9/dnssecinfra.hh --- pdns-recursor-5.2.13/dnssecinfra.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnssecinfra.hh 2026-10-26 09:46:36.000000000 +0000 @@ -292,7 +292,7 @@ void incrementHash(std::string& raw); void decrementHash(std::string& raw); -void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set& authSet, vector& rrs, DNSPacket* packet=nullptr); +void addRRSigs(DNSSECKeeper& dsk, UeberBackend& ueber, const std::set& authSet, vector& 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); diff -Nru pdns-recursor-5.2.13/dnsseckeeper.hh pdns-recursor-5.4.9/dnsseckeeper.hh --- pdns-recursor-5.2.13/dnsseckeeper.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnsseckeeper.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,314 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "dnssecinfra.hh" -#include "dnsrecords.hh" -#include "dnspacket.hh" -#include "ueberbackend.hh" -#include "lock.hh" - -using namespace ::boost::multi_index; - -class DNSSECKeeper : public boost::noncopyable -{ -public: - enum keytype_t { KSK, ZSK, CSK }; - enum keyalgorithm_t : uint8_t { - RSAMD5=1, - DH=2, - DSA=3, - RSASHA1=5, - DSANSEC3SHA1=6, - RSASHA1NSEC3SHA1=7, - RSASHA256=8, - RSASHA512=10, - ECCGOST=12, - ECDSA256=13, - ECDSA384=14, - ED25519=15, - ED448=16 - }; - - enum dsdigestalgorithm_t : uint8_t { - DIGEST_SHA1=1, - DIGEST_SHA256=2, - DIGEST_GOST=3, - DIGEST_SHA384=4 - }; - - struct KeyMetaData - { - string fname; - unsigned int id; - bool active; - keytype_t keyType; - bool hasSEPBit; - bool published; - }; - typedef std::pair keymeta_t; - typedef std::vector keyset_t; - - static string keyTypeToString(const keytype_t &keyType) - { - switch(keyType) { - case DNSSECKeeper::KSK: - return("KSK"); - case DNSSECKeeper::ZSK: - return("ZSK"); - case DNSSECKeeper::CSK: - return("CSK"); - default: - return("UNKNOWN"); - } - } - - /* - * Returns the algorithm number based on the mnemonic (or old PowerDNS value of) a string. - * See https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml for the mapping - */ - static int shorthand2algorithm(const string &algorithm) - { - if (pdns_iequals(algorithm, "rsamd5")) return RSAMD5; - if (pdns_iequals(algorithm, "dh")) return DH; - if (pdns_iequals(algorithm, "dsa")) return DSA; - if (pdns_iequals(algorithm, "rsasha1")) return RSASHA1; - if (pdns_iequals(algorithm, "dsa-nsec3-sha1")) return DSANSEC3SHA1; - if (pdns_iequals(algorithm, "rsasha1-nsec3-sha1")) return RSASHA1NSEC3SHA1; - if (pdns_iequals(algorithm, "rsasha256")) return RSASHA256; - if (pdns_iequals(algorithm, "rsasha512")) return RSASHA512; - if (pdns_iequals(algorithm, "ecc-gost")) return ECCGOST; - if (pdns_iequals(algorithm, "gost")) return ECCGOST; - if (pdns_iequals(algorithm, "ecdsa256")) return ECDSA256; - if (pdns_iequals(algorithm, "ecdsap256sha256")) return ECDSA256; - if (pdns_iequals(algorithm, "ecdsa384")) return ECDSA384; - if (pdns_iequals(algorithm, "ecdsap384sha384")) return ECDSA384; - if (pdns_iequals(algorithm, "ed25519")) return ED25519; - if (pdns_iequals(algorithm, "ed448")) return ED448; - if (pdns_iequals(algorithm, "indirect")) return 252; - if (pdns_iequals(algorithm, "privatedns")) return 253; - if (pdns_iequals(algorithm, "privateoid")) return 254; - return -1; - } - - /* - * Returns the mnemonic from https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml - */ - static string algorithm2name(uint8_t algo) { - switch(algo) { - case 0: - case 4: - case 9: - case 11: - return "Reserved"; - case RSAMD5: - return "RSAMD5"; - case DH: - return "DH"; - case DSA: - return "DSA"; - case RSASHA1: - return "RSASHA1"; - case DSANSEC3SHA1: - return "DSA-NSEC3-SHA1"; - case RSASHA1NSEC3SHA1: - return "RSASHA1-NSEC3-SHA1"; - case RSASHA256: - return "RSASHA256"; - case RSASHA512: - return "RSASHA512"; - case ECCGOST: - return "ECC-GOST"; - case ECDSA256: - return "ECDSAP256SHA256"; - case ECDSA384: - return "ECDSAP384SHA384"; - case ED25519: - return "ED25519"; - case ED448: - return "ED448"; - case 252: - return "INDIRECT"; - case 253: - return "PRIVATEDNS"; - case 254: - return "PRIVATEOID"; - default: - return "Unallocated/Reserved"; - } - } - -private: - UeberBackend* d_keymetadb; - bool d_ourDB; - -public: - DNSSECKeeper() : d_keymetadb( new UeberBackend("key-only")), d_ourDB(true) - { - - } - - DNSSECKeeper(UeberBackend* db) : d_keymetadb(db), d_ourDB(false) - { - } - - ~DNSSECKeeper() - { - if(d_ourDB) - delete d_keymetadb; - } - - static uint64_t dbdnssecCacheSizes(const std::string& str); - static void clearAllCaches(); - static bool clearKeyCache(const DNSName& name); - static bool clearMetaCache(const DNSName& name); - static void clearCaches(const DNSName& name); - - bool doesDNSSEC(); - bool isSecuredZone(const DNSName& zone, bool useCache=true); - keyset_t getEntryPoints(const DNSName& zname); - keyset_t getKeys(const DNSName& zone, bool useCache = true); - DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id); - bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int64_t& id, int bits=0, bool active=true, bool published=true); - bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, int64_t& id, bool active=true, bool published=true); - bool removeKey(const DNSName& zname, unsigned int id); - bool activateKey(const DNSName& zname, unsigned int id); - bool deactivateKey(const DNSName& zname, unsigned int id); - bool publishKey(const DNSName& zname, unsigned int id); - bool unpublishKey(const DNSName& zname, unsigned int id); - bool checkKeys(const DNSName& zname, std::optional>> errorMessages); - - bool getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* n3p=nullptr, bool* narrow=nullptr, bool useCache=true); - 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& 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); - bool setPublishCDNSKEY(const DNSName& zname, bool deleteAlg); - void getPublishCDNSKEY(const DNSName& zname, std::string& value); - bool unsetPublishCDNSKEY(const DNSName& zname); - bool setPublishCDS(const DNSName& zname, const string& digestAlgos); - void getPublishCDS(const DNSName& zname, std::string& value); - bool unsetPublishCDS(const DNSName& zname); - - bool TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname); - bool getTSIGForAccess(const DNSName& zone, const ComboAddress& primary, DNSName* keyname); - - void startTransaction(const DNSName& zone, int zone_id) - { - (*d_keymetadb->backends.begin())->startTransaction(zone, zone_id); - } - - void commitTransaction() - { - (*d_keymetadb->backends.begin())->commitTransaction(); - } - - void getFromMetaOrDefault(const DNSName& zname, const std::string& key, std::string& value, const std::string& defaultvalue); - bool getFromMeta(const DNSName& zname, const std::string& key, std::string& value); - void getSoaEdit(const DNSName& zname, std::string& value, bool useCache=true); - bool unSecureZone(const DNSName& zone, std::string& error); - bool rectifyZone(const DNSName& zone, std::string& error, std::string& info, bool doTransaction); - - static void setMaxEntries(size_t maxEntries); - - typedef std::map > METAValues; -private: - bool getFromMetaNoCache(const DNSName& name, const std::string& kind, std::string& value); - - int64_t d_metaCacheCleanAction{0}; - bool d_metaUpdate{false}; - - struct KeyCacheEntry - { - typedef vector keys_t; - - uint32_t isStale(time_t now) const - { - return d_ttd < now; - } - - DNSName d_domain; - mutable keys_t d_keys; - unsigned int d_ttd; - }; - - struct METACacheEntry - { - time_t isStale(time_t now) const - { - return d_ttd < now; - } - - DNSName d_domain; - mutable METAValues d_value; - time_t d_ttd; - }; - - struct KeyCacheTag{}; - struct CompositeTag{}; - struct SequencedTag{}; - - typedef multi_index_container< - KeyCacheEntry, - indexed_by< - hashed_unique,member >, - sequenced> - > - > keycache_t; - - typedef multi_index_container< - METACacheEntry, - indexed_by< - ordered_unique >, - sequenced> - > - > metacache_t; - - void cleanup(); - - static SharedLockGuarded s_keycache; - static SharedLockGuarded s_metacache; - static int64_t s_metaCacheCleanActions; - static AtomicCounter s_ops; - static time_t s_last_prune; - static size_t s_maxEntries; -}; - -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); -uint32_t calculateEditSOA(uint32_t old_serial, const string& kind, const DNSName& zonename); -// for SOA-EDIT-DNSUPDATE/API -bool increaseSOARecord(DNSResourceRecord& dr, const string& increaseKind, const string& editKind); -bool makeIncreasedSOARecord(SOAData& sd, const string& increaseKind, const string& editKind, DNSResourceRecord& rrout); -DNSZoneRecord makeEditedDNSZRFromSOAData(DNSSECKeeper& dk, const SOAData& sd, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER); diff -Nru pdns-recursor-5.2.13/dnstap.cc pdns-recursor-5.4.9/dnstap.cc --- pdns-recursor-5.2.13/dnstap.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnstap.cc 2026-10-26 09:46:36.000000000 +0000 @@ -1,6 +1,7 @@ #include #include "config.h" #include "gettime.hh" +#include "protozero/types.hpp" #include "dnstap.hh" #ifndef DISABLE_PROTOBUF @@ -53,7 +54,9 @@ query_zone = 11, response_time_sec = 12, response_time_nsec = 13, - response_message = 14 + response_message = 14, + policy = 15, + http_protocol = 16, }; } @@ -62,7 +65,7 @@ return std::move(d_buffer); } -DnstapMessage::DnstapMessage(std::string&& buffer, DnstapMessage::MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, DnstapMessage::ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const boost::optional& auth) : +DnstapMessage::DnstapMessage(std::string&& buffer, DnstapMessage::MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, DnstapMessage::ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const DNSName& auth, const std::optional httpProtocol) : d_buffer(std::move(buffer)) { protozero::pbf_writer pbf{d_buffer}; @@ -128,9 +131,13 @@ pbf_message.add_bytes(DnstapMessageFields::response_message, packet, len); } } + if (httpProtocol) { + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) + pbf_message.add_enum(DnstapMessageFields::http_protocol, static_cast(*httpProtocol)); + } - if (auth) { - pbf_message.add_bytes(DnstapMessageFields::query_zone, auth->toDNSString()); + if (!auth.empty()) { + pbf_message.add_bytes(DnstapMessageFields::query_zone, auth.toDNSString()); } pbf_message.commit(); diff -Nru pdns-recursor-5.2.13/dnstap.hh pdns-recursor-5.4.9/dnstap.hh --- pdns-recursor-5.2.13/dnstap.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnstap.hh 2026-10-26 09:46:36.000000000 +0000 @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include "config.h" @@ -30,7 +31,6 @@ #include "iputils.hh" #ifndef DISABLE_PROTOBUF -#include "protozero.hh" class DnstapMessage { @@ -60,8 +60,14 @@ DNSCryptTCP = 6, DoQ = 7 }; + enum class HttpProtocolType : uint32_t + { + HTTP1 = 1, + HTTP2 = 2, + HTTP3 = 3, + }; - DnstapMessage(std::string&& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const boost::optional& auth = boost::none); + DnstapMessage(std::string&& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const DNSName& auth, const std::optional httpProtocol = std::nullopt); void setExtra(const std::string& extra); std::string&& getBuffer(); diff -Nru pdns-recursor-5.2.13/dnstap.proto pdns-recursor-5.4.9/dnstap.proto --- pdns-recursor-5.2.13/dnstap.proto 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnstap.proto 2026-10-26 09:46:36.000000000 +0000 @@ -3,7 +3,7 @@ // This file contains the protobuf schemas for the "dnstap" structured event // replication format for DNS software. -// Written in 2013-2014 by Farsight Security, Inc. +// Written in 2013-2025 by the dnstap contributors. // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this file to the public @@ -12,7 +12,7 @@ // You should have received a copy of the CC0 Public Domain Dedication along // with this file. If not, see: // -// . +// . syntax = "proto2"; package dnstap; @@ -64,6 +64,15 @@ DOH = 4; // DNS over HTTPS (RFC 8484) DNSCryptUDP = 5; // DNSCrypt over UDP (https://dnscrypt.info/protocol) DNSCryptTCP = 6; // DNSCrypt over TCP (https://dnscrypt.info/protocol) + DOQ = 7; // DNS over QUIC (RFC 9250) +} + +// HttpProtocol: the HTTP protocol version used to transport a DNS message over +// an HTTP-based protocol such as DNS over HTTPS. +enum HttpProtocol { + HTTP1 = 1; // HTTP/1 + HTTP2 = 2; // HTTP/2 + HTTP3 = 3; // HTTP/3 } // Policy: information about any name server operator policy @@ -215,13 +224,13 @@ // tool from a DNS server, from the perspective of the tool. TOOL_RESPONSE = 12; - // UPDATE_QUERY is a DNS update query message received from a resolver + // UPDATE_QUERY is a Dynamic DNS Update request (RFC 2136) received // by an authoritative name server, from the perspective of the // authoritative name server. UPDATE_QUERY = 13; - // UPDATE_RESPONSE is a DNS update response message sent from an - // authoritative name server to a resolver, from the perspective of the + // UPDATE_RESPONSE is a Dynamic DNS Update response (RFC 2136) sent + // from an authoritative name server, from the perspective of the // authoritative name server. UPDATE_RESPONSE = 14; } @@ -284,6 +293,10 @@ // Operator policy applied to the processing of this message, if any. optional Policy policy = 15; + + // One of the HttpProtocol values described above. This field should only be + // set if socket_protocol is set to DOH. + optional HttpProtocol http_protocol = 16; } // All fields except for 'type' in the Message schema are optional. diff -Nru pdns-recursor-5.2.13/dnswriter.cc pdns-recursor-5.4.9/dnswriter.cc --- pdns-recursor-5.2.13/dnswriter.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/dnswriter.cc 2026-10-26 09:46:36.000000000 +0000 @@ -23,9 +23,7 @@ #include "config.h" #endif #include -#if BOOST_VERSION >= 105400 #include -#endif #include "dnswriter.hh" #include "misc.hh" #include "dnsparser.hh" @@ -40,9 +38,9 @@ */ - -template GenericDNSPacketWriter::GenericDNSPacketWriter(Container& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) - : d_content(content), d_qname(qname), d_canonic(false), d_lowerCase(false) +template +GenericDNSPacketWriter::GenericDNSPacketWriter(Container& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) : + d_content(content), d_qname(qname) { d_content.clear(); dnsheader dnsheader; @@ -131,6 +129,9 @@ template void GenericDNSPacketWriter::xfr48BitInt(uint64_t val) { + if ((val >> 48) != 0) { + throw runtime_error("Value too large to fit in 48 bits"); + } std::array bytes; uint16_t theLeft = htons((val >> 32)&0xffffU); uint32_t theRight = htonl(val & 0xffffffffU); @@ -145,23 +146,32 @@ d_content.insert(d_content.end(), val.content, val.content + sizeof(val.content)); } -template void GenericDNSPacketWriter::xfr32BitInt(uint32_t val) +template void GenericDNSPacketWriter::xfr32BitInt(uint64_t val) { - uint32_t rval=htonl(val); + if (val > std::numeric_limits::max()) { + throw runtime_error("Value too large to fit in 32 bits"); + } + uint32_t rval=htonl(static_cast(val)); uint8_t* ptr=reinterpret_cast(&rval); d_content.insert(d_content.end(), ptr, ptr+4); } -template void GenericDNSPacketWriter::xfr16BitInt(uint16_t val) +template void GenericDNSPacketWriter::xfr16BitInt(uint64_t val) { - uint16_t rval=htons(val); + if (val > std::numeric_limits::max()) { + throw runtime_error("Value too large to fit in 16 bits"); + } + uint16_t rval=htons(static_cast(val)); uint8_t* ptr=reinterpret_cast(&rval); d_content.insert(d_content.end(), ptr, ptr+2); } -template void GenericDNSPacketWriter::xfr8BitInt(uint8_t val) +template void GenericDNSPacketWriter::xfr8BitInt(uint64_t val) { - d_content.push_back(val); + if (val > std::numeric_limits::max()) { + throw runtime_error("Value too large to fit in 8 bits"); + } + d_content.push_back(static_cast(val)); } @@ -316,7 +326,7 @@ return bestpos; } // this is the absolute hottest function in the pdns recursor -template void GenericDNSPacketWriter::xfrName(const DNSName& name, bool compress, bool) +template void GenericDNSPacketWriter::xfrName(const DNSName& name, bool compress) { if(l_verbose) cout<<"Wants to write "< s_verboseStream; - static std::string s_structuredLevelPrefix; - static TimeFormat s_structuredTimeFormat; - static bool s_structuredLogging; static bool s_logTimestamps; static bool s_syslog; }; @@ -197,16 +168,8 @@ dnsdist::logging::logTime(stream); } - if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) { - stream << dnsdist::logging::LoggingConfiguration::getStructuredLoggingLevelPrefix() << "=\"" << syslogLevelToStr(level) << "\" "; - stream << "msg=" << std::quoted(output) << std::endl; - } - else { - stream << output << std::endl; - } -#else - stream << output << std::endl; #endif + stream << output << std::endl; } template diff -Nru pdns-recursor-5.2.13/ednscookies.cc pdns-recursor-5.4.9/ednscookies.cc --- pdns-recursor-5.2.13/ednscookies.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednscookies.cc 2026-10-26 09:46:36.000000000 +0000 @@ -19,11 +19,12 @@ * 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 "ednscookies.hh" -#include "misc.hh" +#include "dns_random.hh" +#include "iputils.hh" #ifdef HAVE_CRYPTO_SHORTHASH #include @@ -54,26 +55,64 @@ string EDNSCookiesOpt::makeOptString() const { string ret; - if (!isWellFormed()) + if (!isWellFormed()) { return ret; + } ret.assign(client); - if (server.length() != 0) + if (server.length() != 0) { ret.append(server); + } return ret; } +string EDNSCookiesOpt::toDisplayString() const +{ + std::ostringstream str; + str << makeHexDump(client, ""); + if (!server.empty()) { + str << '|'; + if (server.length() != 16) { + // It isn't a rfc9018 one + str << makeHexDump(server, ""); + } + else { + // It very likely is a rfc9018 one + str << makeHexDump(server.substr(0, 1), ""); // Version + str << '|'; + str << makeHexDump(server.substr(1, 3), ""); // Reserved + str << '|'; + str << makeHexDump(server.substr(4, 4), ""); // Timestamp + str << '|'; + str << makeHexDump(server.substr(8, 8), ""); // Hash + } + } + return str.str(); +} + void EDNSCookiesOpt::getEDNSCookiesOptFromString(const char* option, unsigned int len) { client.clear(); server.clear(); - if (len < 8) + if (len < 8) { return; - client = string(option, 8); + } + const std::string tmp(option, len); + client = tmp.substr(0, 8); if (len > 8) { - server = string(option + 8, len - 8); + server = tmp.substr(8); } } +static bool cookieTSIsValid(uint32_t timestamp, uint32_t now) +{ + // RFC 9018 section 4.3: + // The DNS server + // SHOULD allow cookies within a 1-hour period in the past and a + // 5-minute period into the future + // valid: now - 300 < timestamp < now + 3600 + return rfc1982LessThan(now - 300, timestamp) && rfc1982LessThan(timestamp, now + 3600); +} + bool EDNSCookiesOpt::isValid([[maybe_unused]] const string& secret, [[maybe_unused]] const ComboAddress& source) const { #ifdef HAVE_CRYPTO_SHORTHASH @@ -84,16 +123,12 @@ // Version is not 1, can't verify return false; } - uint32_t ts; - memcpy(&ts, &server[4], sizeof(ts)); - ts = ntohl(ts); + uint32_t timestamp{}; + memcpy(×tamp, &server[4], sizeof(timestamp)); + timestamp = ntohl(timestamp); // coverity[store_truncates_time_t] - uint32_t now = static_cast(time(nullptr)); - // RFC 9018 section 4.3: - // The DNS server - // SHOULD allow cookies within a 1-hour period in the past and a - // 5-minute period into the future - if (rfc1982LessThan(now + 300, ts) && rfc1982LessThan(ts + 3600, now)) { + auto now = static_cast(time(nullptr)); + if (!cookieTSIsValid(timestamp, now)) { return false; } if (secret.length() != crypto_shorthash_KEYBYTES) { @@ -103,11 +138,13 @@ string toHash = client + server.substr(0, 8) + source.toByteString(); string hashResult; hashResult.resize(8); - crypto_shorthash( - reinterpret_cast(&hashResult[0]), - reinterpret_cast(&toHash[0]), - toHash.length(), - reinterpret_cast(&secret[0])); + + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) + crypto_shorthash(reinterpret_cast(hashResult.data()), + reinterpret_cast(toHash.data()), + toHash.length(), + reinterpret_cast(secret.data())); + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) return constantTimeStringEquals(server.substr(8), hashResult); #else return false; @@ -119,30 +156,33 @@ if (server.size() < 16) { return true; } - uint32_t ts; - memcpy(&ts, &server[4], sizeof(ts)); - ts = ntohl(ts); + uint32_t timestamp{}; + memcpy(×tamp, &server.at(4), sizeof(timestamp)); + timestamp = ntohl(timestamp); // coverity[store_truncates_time_t] - uint32_t now = static_cast(time(nullptr)); - // RFC 9018 section 4.3: - // The DNS server - // SHOULD allow cookies within a 1-hour period in the past and a - // 5-minute period into the future - // If this is not the case, we need to refresh - if (rfc1982LessThan(now + 300, ts) && rfc1982LessThan(ts + 3600, now)) { + auto now = static_cast(time(nullptr)); + // If the cookie is not within acceptable time bounds, we need to refresh + if (!cookieTSIsValid(timestamp, now)) { return true; } // RFC 9018 section 4.3: // The DNS server SHOULD generate a new Server Cookie at least if the // received Server Cookie from the client is more than half an hour old - return rfc1982LessThan(ts + 1800, now); + return rfc1982LessThan(timestamp + 1800, now); +} + +void EDNSCookiesOpt::makeClientCookie() +{ + const size_t clientCookieSize = 8; + client.resize(clientCookieSize); + dns_random(client.data(), clientCookieSize); } bool EDNSCookiesOpt::makeServerCookie([[maybe_unused]] const string& secret, [[maybe_unused]] const ComboAddress& source) { #ifdef HAVE_CRYPTO_SHORTHASH - static_assert(EDNSCookieSecretSize == crypto_shorthash_KEYBYTES * 2, "The EDNSCookieSecretSize is not twice crypto_shorthash_KEYBYTES"); + static_assert(EDNSCookieSecretSize == crypto_shorthash_KEYBYTES * static_cast(2), "The EDNSCookieSecretSize is not twice crypto_shorthash_KEYBYTES"); if (isValid(secret, source) && !shouldRefresh()) { return true; @@ -158,6 +198,7 @@ server.resize(4, '\0'); // 3 reserved bytes // coverity[store_truncates_time_t] uint32_t now = htonl(static_cast(time(nullptr))); + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) server += string(reinterpret_cast(&now), sizeof(now)); server.resize(8); @@ -165,11 +206,11 @@ toHash += server; toHash += source.toByteString(); server.resize(16); - crypto_shorthash( - reinterpret_cast(&server[8]), - reinterpret_cast(&toHash[0]), - toHash.length(), - reinterpret_cast(&secret[0])); + crypto_shorthash(reinterpret_cast(&server.at(8)), + reinterpret_cast(toHash.data()), + toHash.length(), + reinterpret_cast(secret.data())); + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) return true; #else return false; diff -Nru pdns-recursor-5.2.13/ednscookies.hh pdns-recursor-5.4.9/ednscookies.hh --- pdns-recursor-5.2.13/ednscookies.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednscookies.hh 2026-10-26 09:46:36.000000000 +0000 @@ -20,8 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once -#include "namespaces.hh" -#include "iputils.hh" + +#include + +union ComboAddress; struct EDNSCookiesOpt { @@ -35,38 +37,42 @@ bool makeFromString(const std::string& option); bool makeFromString(const char* option, unsigned int len); - size_t size() const + [[nodiscard]] size_t size() const { return server.size() + client.size(); } - bool isWellFormed() const + [[nodiscard]] bool isWellFormed() const { // RFC7873 section 5.2.2 // In summary, valid cookie lengths are 8 and 16 to 40 inclusive. + // That's the total size. We account for client and server size separately return ( - client.size() == 8 && (server.size() == 0 || (server.size() >= 8 && server.size() <= 32))); + client.size() == 8 && (server.empty() || (server.size() >= 8 && server.size() <= 32))); } - bool isValid(const string& secret, const ComboAddress& source) const; - bool makeServerCookie(const string& secret, const ComboAddress& source); - string makeOptString() const; - string getServer() const + [[nodiscard]] bool isValid(const std::string& secret, const ComboAddress& source) const; + void makeClientCookie(); + bool makeServerCookie(const std::string& secret, const ComboAddress& source); + + [[nodiscard]] std::string makeOptString() const; + [[nodiscard]] std::string toDisplayString() const; + [[nodiscard]] std::string getServer() const { return server; } - string getClient() const + [[nodiscard]] std::string getClient() const { return client; } private: - bool shouldRefresh() const; + [[nodiscard]] bool shouldRefresh() const; // the client cookie - string client; + std::string client; // the server cookie - string server; + std::string server; void getEDNSCookiesOptFromString(const char* option, unsigned int len); }; diff -Nru pdns-recursor-5.2.13/ednsextendederror.hh pdns-recursor-5.4.9/ednsextendederror.hh --- pdns-recursor-5.2.13/ednsextendederror.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednsextendederror.hh 2026-10-26 09:46:36.000000000 +0000 @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once +#include + #include "namespaces.hh" struct EDNSExtendedError diff -Nru pdns-recursor-5.2.13/ednsoptions.cc pdns-recursor-5.4.9/ednsoptions.cc --- pdns-recursor-5.2.13/ednsoptions.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednsoptions.cc 2026-10-26 09:46:36.000000000 +0000 @@ -122,14 +122,14 @@ } for (index = 0; index < numrecords; ++index) { - dpm.skipDomainName(); + const bool wasRoot = dpm.skipDomainName(); uint8_t section = index < ntohs(dnsHeader->ancount) ? 1 : (index < (ntohs(dnsHeader->ancount) + ntohs(dnsHeader->nscount)) ? 2 : 3); uint16_t dnstype = dpm.get16BitInt(); dpm.get16BitInt(); dpm.skipBytes(4); /* TTL */ - if (section == 3 && dnstype == QType::OPT) { + if (section == 3 && dnstype == QType::OPT && wasRoot) { uint32_t offset = dpm.getOffset(); if (offset >= packet.size()) { return false; @@ -146,7 +146,7 @@ return false; } - return true; + return false; } /* extract all EDNS0 options from a pointer on the beginning rdLen of the OPT RR */ @@ -219,3 +219,81 @@ res.append((const char *) &payloadLen, sizeof payloadLen); res.append(payload); } + +template +int locateEDNSOptRR(const T& packet, uint16_t* optStart, size_t* optLen, bool* last) +{ + if (optStart == nullptr || optLen == nullptr || last == nullptr) { + throw std::runtime_error("Invalid values passed to locateEDNSOptRR"); + } + + if (packet.size() < sizeof(dnsheader)) { + throw std::runtime_error("Packet passed to locateEDNSOptRR was too small"); + } + + const dnsheader_aligned dnsHeader(packet.data()); + + if (ntohs(dnsHeader->arcount) == 0) { + return ENOENT; + } + + if (ntohs(dnsHeader->qdcount) != 1) { + throw std::runtime_error("Packet passed to locateEDNSOptRR did not have QDCOUNT=1"); + } + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + PacketReader packetReader(std::string_view(reinterpret_cast(packet.data()), packet.size())); + + size_t idx = 0; + DNSName rrname; + uint16_t ancount = ntohs(dnsHeader->ancount); + uint16_t nscount = ntohs(dnsHeader->nscount); + uint16_t arcount = ntohs(dnsHeader->arcount); + dnsrecordheader recordHeader{}; + + /* consume query section */ + rrname = packetReader.getName(); + packetReader.skip(4); // Skip Type and Class + + /* consume AN and NS */ + for (idx = 0; idx < ancount + nscount; idx++) { + rrname = packetReader.getName(); + packetReader.getDnsrecordheader(recordHeader); + packetReader.skip(recordHeader.d_clen); + } + + /* consume AR, looking for OPT */ + for (idx = 0; idx < arcount; idx++) { + uint16_t start = packetReader.getPosition(); + rrname = packetReader.getName(); + packetReader.getDnsrecordheader(recordHeader); + + if (rrname.isRoot() && recordHeader.d_type == QType::OPT) { + *optStart = start; + *optLen = (packetReader.getPosition() - start) + recordHeader.d_clen; + + if (packet.size() < (*optStart + *optLen)) { + throw std::range_error("Opt record overflow"); + } + + if (idx == ((size_t)arcount - 1)) { + *last = true; + } + else { + *last = false; + } + return 0; + } + packetReader.skip(recordHeader.d_clen); + } + + return ENOENT; +} + +#if defined(RECURSOR) +template int locateEDNSOptRR(const std::vector& packet, uint16_t* optStart, size_t* optLen, bool* last); +#endif +#if defined(DNSDIST) +template int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optLen, bool* last); +#endif + diff -Nru pdns-recursor-5.2.13/ednsoptions.hh pdns-recursor-5.4.9/ednsoptions.hh --- pdns-recursor-5.2.13/ednsoptions.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednsoptions.hh 2026-10-26 09:46:36.000000000 +0000 @@ -26,7 +26,8 @@ struct EDNSOptionCode { - enum EDNSOptionCodeEnum {NSID=3, DAU=5, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13, KEYTAG=14, EXTENDEDERROR=15}; + // Temporary code assigned for OpenTelemetry TraceID and SpanID + enum EDNSOptionCodeEnum : uint16_t {NSID=3, DAU=5, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13, KEYTAG=14, EXTENDEDERROR=15, TRACEPARENT=65500}; }; /* extract the position (relative to the optRR pointer!) and size of a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */ @@ -57,3 +58,7 @@ void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res); bool slowParseEDNSOptions(const PacketBuffer& packet, EDNSOptionViewMap& options); + +// called with std::vector and PacketBuffer +template +int locateEDNSOptRR(const T& packet, uint16_t* optStart, size_t* optLen, bool* last); diff -Nru pdns-recursor-5.2.13/ednssubnet.cc pdns-recursor-5.4.9/ednssubnet.cc --- pdns-recursor-5.2.13/ednssubnet.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednssubnet.cc 2026-10-26 09:46:36.000000000 +0000 @@ -19,29 +19,28 @@ * 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 "ednssubnet.hh" -#include "dns.hh" namespace { struct EDNSSubnetOptsWire { uint16_t family; - uint8_t sourceMask; - uint8_t scopeMask; + uint8_t sourcePrefixLength; + uint8_t scopePrefixLength; } GCCPACKATTRIBUTE; // BRRRRR } -bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso) +bool EDNSSubnetOpts::getFromString(const std::string& options, EDNSSubnetOpts* eso) { - // cerr<<"options.size:"< 0 ? (((esow.sourceMask - 1) >> 3) + 1) : 0; - // cerr<<"octetsin:"< 0 ? (((esow.sourcePrefixLength - 1) >> 3) + 1) : 0; + if (esow.family == 1) { if (len != sizeof(esow) + octetsin) { return false; @@ -84,35 +83,37 @@ else { return false; } - eso->source = Netmask(address, esow.sourceMask); - /* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise - more precision than they have. For this reason we truncate the address to scopeMask bits */ + eso->source = Netmask(address, esow.sourcePrefixLength); + /* 'address' has more bits set (potentially) than scopePrefixLength. This leads to odd looking netmasks that promise + more precision than they have. For this reason we truncate the address to scopePrefixLength bits */ - address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks - eso->scope = Netmask(address, esow.scopeMask); + address.truncate(esow.scopePrefixLength); // truncate will not throw for odd scopePrefixLengths + eso->scopeBits = esow.scopePrefixLength; return true; } -string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso) +std::string EDNSSubnetOpts::makeOptString() const { - string ret; + std::string ret; EDNSSubnetOptsWire esow{}; - uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); + uint16_t family = htons(source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); esow.family = family; - esow.sourceMask = eso.source.getBits(); - esow.scopeMask = eso.scope.getBits(); - ret.assign((const char*)&esow, sizeof(esow)); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) - int octetsout = ((esow.sourceMask - 1) >> 3) + 1; + esow.sourcePrefixLength = source.getBits(); + esow.scopePrefixLength = scopeBits; + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) + ret.assign(reinterpret_cast(&esow), sizeof(esow)); + int octetsout = ((esow.sourcePrefixLength - 1) >> 3) + 1; - ComboAddress src = eso.source.getNetwork(); - src.truncate(esow.sourceMask); + ComboAddress src = source.getNetwork(); + src.truncate(esow.sourcePrefixLength); if (family == htons(1)) { - ret.append((const char*)&src.sin4.sin_addr.s_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) + ret.append(reinterpret_cast(&src.sin4.sin_addr.s_addr), octetsout); } else { - ret.append((const char*)&src.sin6.sin6_addr.s6_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) + ret.append(reinterpret_cast(&src.sin6.sin6_addr.s6_addr), octetsout); } + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) return ret; } diff -Nru pdns-recursor-5.2.13/ednssubnet.hh pdns-recursor-5.4.9/ednssubnet.hh --- pdns-recursor-5.2.13/ednssubnet.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ednssubnet.hh 2026-10-26 09:46:36.000000000 +0000 @@ -20,16 +20,45 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once -#include "namespaces.hh" + #include "iputils.hh" -#include "dnsname.hh" -struct EDNSSubnetOpts +class EDNSSubnetOpts { +public: + void setSource(const Netmask& netmask) + { + source = netmask; + } + [[nodiscard]] const Netmask& getSource() const + { + return source; + } + [[nodiscard]] uint8_t getFamily() const + { + return source.getNetwork().sin4.sin_family; + } + [[nodiscard]] uint8_t getSourcePrefixLength() const + { + return source.getBits(); + } + void setScopePrefixLength(uint8_t scope) + { + scopeBits = scope; + } + [[nodiscard]] uint8_t getScopePrefixLength() const + { + return scopeBits; + } + [[nodiscard]] Netmask getScope() const + { + return {source.getNetwork(), scopeBits}; + } + [[nodiscard]] std::string makeOptString() const; + static bool getFromString(const std::string& options, EDNSSubnetOpts* eso); + static bool getFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso); + +private: Netmask source; - Netmask scope; + uint8_t scopeBits{}; }; - -bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso); -bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso); -string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso); diff -Nru pdns-recursor-5.2.13/effective_tld_names.dat pdns-recursor-5.4.9/effective_tld_names.dat --- pdns-recursor-5.2.13/effective_tld_names.dat 2026-08-05 12:02:34.000000000 +0000 +++ pdns-recursor-5.4.9/effective_tld_names.dat 1970-01-01 00:00:00.000000000 +0000 @@ -1,16409 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, -// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. - -// VERSION: 2026-07-25_14-20-03_UTC -// COMMIT: e1b8015c3b2f0f4f8c18659c2480fc1a22c07b20 - -// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. - -// ===BEGIN ICANN DOMAINS=== - -// ac : http://nic.ac/rules.htm -ac -com.ac -edu.ac -gov.ac -mil.ac -net.ac -org.ac - -// ad : https://www.iana.org/domains/root/db/ad.html -// Confirmed by Amadeu Abril i Abril (CORE) 2024-11-17 -ad - -// ae : https://www.iana.org/domains/root/db/ae.html -ae -ac.ae -co.ae -gov.ae -mil.ae -net.ae -org.ae -sch.ae - -// aero : https://information.aero/registration/policies/dmp -aero -// 2LDs -airline.aero -airport.aero -// 2LDs (currently not accepting registration, seemingly never have) -// As of 2024-07, these are marked as reserved for potential 3LD -// registrations (clause 11 "allocated subdomains" in the 2006 TLD -// policy), but the relevant industry partners have not opened them up -// for registration. Current status can be determined from the TLD's -// policy document: 2LDs that are open for registration must list -// their policy in the TLD's policy. Any 2LD without such a policy is -// not open for registrations. -accident-investigation.aero -accident-prevention.aero -aerobatic.aero -aeroclub.aero -aerodrome.aero -agents.aero -air-surveillance.aero -air-traffic-control.aero -aircraft.aero -airtraffic.aero -ambulance.aero -association.aero -author.aero -ballooning.aero -broker.aero -caa.aero -cargo.aero -catering.aero -certification.aero -championship.aero -charter.aero -civilaviation.aero -club.aero -conference.aero -consultant.aero -consulting.aero -control.aero -council.aero -crew.aero -design.aero -dgca.aero -educator.aero -emergency.aero -engine.aero -engineer.aero -entertainment.aero -equipment.aero -exchange.aero -express.aero -federation.aero -flight.aero -freight.aero -fuel.aero -gliding.aero -government.aero -groundhandling.aero -group.aero -hanggliding.aero -homebuilt.aero -insurance.aero -journal.aero -journalist.aero -leasing.aero -logistics.aero -magazine.aero -maintenance.aero -marketplace.aero -media.aero -microlight.aero -modelling.aero -navigation.aero -parachuting.aero -paragliding.aero -passenger-association.aero -pilot.aero -press.aero -production.aero -recreation.aero -repbody.aero -res.aero -research.aero -rotorcraft.aero -safety.aero -scientist.aero -services.aero -show.aero -skydiving.aero -software.aero -student.aero -taxi.aero -trader.aero -trading.aero -trainer.aero -union.aero -workinggroup.aero -works.aero - -// af : https://www.nic.af/domain-price -af -com.af -edu.af -gov.af -net.af -org.af - -// ag : http://www.nic.ag/prices.htm -ag -co.ag -com.ag -net.ag -nom.ag -org.ag - -// ai : http://nic.com.ai/ -ai -com.ai -net.ai -off.ai -org.ai - -// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 -al -com.al -edu.al -gov.al -mil.al -net.al -org.al - -// am : https://www.amnic.net/policy/en/Policy_EN.pdf -// Confirmed by ISOC AM 2024-11-18 -am -co.am -com.am -commune.am -net.am -org.am - -// ao : https://www.iana.org/domains/root/db/ao.html -// https://www.dns.ao/ao/ -ao -co.ao -ed.ao -edu.ao -gov.ao -gv.ao -it.ao -og.ao -org.ao -pb.ao - -// aq : https://www.iana.org/domains/root/db/aq.html -aq - -// ar : https://nic.ar/es/nic-argentina/normativa -ar -bet.ar -com.ar -coop.ar -edu.ar -gob.ar -gov.ar -int.ar -mil.ar -musica.ar -mutual.ar -net.ar -org.ar -seg.ar -senasa.ar -tur.ar - -// arpa : https://www.iana.org/domains/root/db/arpa.html -// Confirmed by registry 2008-06-18 -arpa -e164.arpa -home.arpa -in-addr.arpa -ip6.arpa -iris.arpa -uri.arpa -urn.arpa - -// as : https://www.iana.org/domains/root/db/as.html -as -gov.as - -// asia : https://www.iana.org/domains/root/db/asia.html -asia - -// at : https://www.iana.org/domains/root/db/at.html -// Confirmed by registry 2008-06-17 -at -ac.at -sth.ac.at -co.at -gv.at -or.at - -// au : https://www.iana.org/domains/root/db/au.html -// https://www.auda.org.au/ -// Confirmed by registry 2025-07-16 -au -// 2LDs -asn.au -com.au -edu.au -gov.au -id.au -net.au -org.au -// Historic 2LDs (closed to new registration, but sites still exist) -conf.au -oz.au -// CGDNs : https://www.auda.org.au/au-domain-names/the-different-au-domain-names/state-and-territory-domain-names/ -act.au -nsw.au -nt.au -qld.au -sa.au -tas.au -vic.au -wa.au -// 3LDs -act.edu.au -catholic.edu.au -// eq.edu.au - Removed at the request of the Queensland Department of Education -nsw.edu.au -nt.edu.au -qld.edu.au -sa.edu.au -tas.edu.au -vic.edu.au -wa.edu.au -// act.gov.au - Bug 984824 - Removed at request of Greg Tankard -// nsw.gov.au - Bug 547985 - Removed at request of -// nt.gov.au - Bug 940478 - Removed at request of Greg Connors -qld.gov.au -sa.gov.au -tas.gov.au -vic.gov.au -wa.gov.au -// 4LDs -// education.tas.edu.au - Removed at the request of the Department of Education Tasmania -// schools.nsw.edu.au - Removed at the request of the New South Wales Department of Education. - -// aw : https://www.iana.org/domains/root/db/aw.html -aw -com.aw - -// ax : https://www.iana.org/domains/root/db/ax.html -ax - -// az : https://www.iana.org/domains/root/db/az.html -// Confirmed via https://whois.az/?page_id=10 2024-12-11 -az -biz.az -co.az -com.az -edu.az -gov.az -info.az -int.az -mil.az -name.az -net.az -org.az -pp.az -// No longer available for registration, however domains exist as of 2024-12-11 -// see https://whois.az/?page_id=783 -pro.az - -// ba : https://www.iana.org/domains/root/db/ba.html -ba -com.ba -edu.ba -gov.ba -mil.ba -net.ba -org.ba - -// bb : https://www.iana.org/domains/root/db/bb.html -bb -biz.bb -co.bb -com.bb -edu.bb -gov.bb -info.bb -net.bb -org.bb -store.bb -tv.bb - -// bd : https://www.iana.org/domains/root/db/bd.html -// Confirmed by registry -bd -ac.bd -ai.bd -co.bd -com.bd -edu.bd -gov.bd -id.bd -info.bd -it.bd -mil.bd -net.bd -org.bd -sch.bd -tv.bd - -// be : https://www.iana.org/domains/root/db/be.html -// Confirmed by registry 2008-06-08 -be -ac.be - -// bf : https://www.iana.org/domains/root/db/bf.html -bf -gov.bf - -// bg : https://www.iana.org/domains/root/db/bg.html -// https://www.register.bg/user/static/rules/en/index.html -bg -0.bg -1.bg -2.bg -3.bg -4.bg -5.bg -6.bg -7.bg -8.bg -9.bg -a.bg -b.bg -c.bg -d.bg -e.bg -f.bg -g.bg -h.bg -i.bg -j.bg -k.bg -l.bg -m.bg -n.bg -o.bg -p.bg -q.bg -r.bg -s.bg -t.bg -u.bg -v.bg -w.bg -x.bg -y.bg -z.bg - -// bh : https://www.iana.org/domains/root/db/bh.html -bh -com.bh -edu.bh -gov.bh -net.bh -org.bh - -// bi : https://www.iana.org/domains/root/db/bi.html -// http://whois.nic.bi/ -bi -co.bi -com.bi -edu.bi -or.bi -org.bi - -// biz : https://www.iana.org/domains/root/db/biz.html -biz - -// bj : https://nic.bj/bj-suffixes.txt -// Submitted by registry -bj -africa.bj -agro.bj -architectes.bj -assur.bj -avocats.bj -co.bj -com.bj -eco.bj -econo.bj -edu.bj -info.bj -loisirs.bj -money.bj -net.bj -org.bj -ote.bj -restaurant.bj -resto.bj -tourism.bj -univ.bj - -// bm : https://www.bermudanic.bm/domain-registration/index.php -bm -com.bm -edu.bm -gov.bm -net.bm -org.bm - -// bn : http://www.bnnic.bn/faqs -bn -com.bn -edu.bn -gov.bn -net.bn -org.bn - -// bo : https://nic.bo -// Confirmed by registry 2024-11-19 -bo -com.bo -edu.bo -gob.bo -int.bo -mil.bo -net.bo -org.bo -tv.bo -web.bo -// Social Domains -academia.bo -agro.bo -arte.bo -blog.bo -bolivia.bo -ciencia.bo -cooperativa.bo -democracia.bo -deporte.bo -ecologia.bo -economia.bo -empresa.bo -indigena.bo -industria.bo -info.bo -medicina.bo -movimiento.bo -musica.bo -natural.bo -nombre.bo -noticias.bo -patria.bo -plurinacional.bo -politica.bo -profesional.bo -pueblo.bo -revista.bo -salud.bo -tecnologia.bo -tksat.bo -transporte.bo -wiki.bo - -// br : http://registro.br/dominio/categoria.html -// Submitted by registry -br -9guacu.br -abc.br -adm.br -adv.br -agr.br -aju.br -am.br -anani.br -aparecida.br -api.br -app.br -arq.br -art.br -ato.br -b.br -barueri.br -belem.br -bet.br -bhz.br -bib.br -bio.br -blog.br -bmd.br -boavista.br -bsb.br -campinagrande.br -campinas.br -caxias.br -cim.br -cng.br -cnt.br -com.br -contagem.br -coop.br -coz.br -cri.br -cuiaba.br -curitiba.br -def.br -des.br -det.br -dev.br -ecn.br -eco.br -edu.br -emp.br -enf.br -eng.br -esp.br -etc.br -eti.br -far.br -feira.br -flog.br -floripa.br -fm.br -fnd.br -fortal.br -fot.br -foz.br -fst.br -g12.br -geo.br -ggf.br -goiania.br -gov.br -// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil -ac.gov.br -al.gov.br -am.gov.br -ap.gov.br -ba.gov.br -ce.gov.br -df.gov.br -es.gov.br -go.gov.br -ma.gov.br -mg.gov.br -ms.gov.br -mt.gov.br -pa.gov.br -pb.gov.br -pe.gov.br -pi.gov.br -pr.gov.br -rj.gov.br -rn.gov.br -ro.gov.br -rr.gov.br -rs.gov.br -sc.gov.br -se.gov.br -sp.gov.br -to.gov.br -gru.br -ia.br -imb.br -ind.br -inf.br -jab.br -jampa.br -jdf.br -joinville.br -jor.br -jus.br -leg.br -leilao.br -lel.br -log.br -londrina.br -macapa.br -maceio.br -manaus.br -maringa.br -mat.br -med.br -mil.br -morena.br -mp.br -mus.br -natal.br -net.br -niteroi.br -*.nom.br -not.br -ntr.br -odo.br -ong.br -org.br -osasco.br -palmas.br -poa.br -ppg.br -pro.br -psc.br -psi.br -pvh.br -qsl.br -radio.br -rec.br -recife.br -rep.br -ribeirao.br -rio.br -riobranco.br -riopreto.br -salvador.br -sampa.br -santamaria.br -santoandre.br -saobernardo.br -saogonca.br -seg.br -sjc.br -slg.br -slz.br -social.br -sorocaba.br -srv.br -taxi.br -tc.br -tec.br -teo.br -the.br -tmp.br -trd.br -tur.br -tv.br -udi.br -vet.br -vix.br -vlog.br -wiki.br -xyz.br -zlg.br - -// bs : http://www.nic.bs/rules.html -bs -com.bs -edu.bs -gov.bs -net.bs -org.bs - -// bt : https://www.iana.org/domains/root/db/bt.html -bt -com.bt -edu.bt -gov.bt -net.bt -org.bt - -// bv : No registrations at this time. -// Submitted by registry -bv - -// bw : https://www.iana.org/domains/root/db/bw.html -// https://nic.net.bw/bw-name-structure -bw -ac.bw -co.bw -gov.bw -net.bw -org.bw - -// by : https://www.iana.org/domains/root/db/by.html -// http://tld.by/rules_2006_en.html -// list of other 2nd level tlds ? -by -gov.by -mil.by -// Official information does not indicate that com.by is a reserved -// second-level domain, but it's being used as one (see www.google.com.by and -// www.yahoo.com.by, for example), so we list it here for safety's sake. -com.by -// http://hoster.by/ -of.by - -// bz : https://www.iana.org/domains/root/db/bz.html -// http://www.belizenic.bz/ -bz -co.bz -com.bz -edu.bz -gov.bz -net.bz -org.bz - -// ca : https://www.iana.org/domains/root/db/ca.html -ca -// ca geographical names -ab.ca -bc.ca -mb.ca -nb.ca -nf.ca -nl.ca -ns.ca -nt.ca -nu.ca -on.ca -pe.ca -qc.ca -sk.ca -yk.ca -// gc.ca: https://en.wikipedia.org/wiki/.gc.ca -// see also: http://registry.gc.ca/en/SubdomainFAQ -gc.ca - -// cat : https://www.iana.org/domains/root/db/cat.html -cat - -// cc : https://www.iana.org/domains/root/db/cc.html -cc - -// cd : https://www.iana.org/domains/root/db/cd.html -// https://www.nic.cd -cd -gov.cd - -// cf : https://www.iana.org/domains/root/db/cf.html -cf - -// cg : https://www.iana.org/domains/root/db/cg.html -cg - -// ch : https://www.iana.org/domains/root/db/ch.html -ch - -// ci : https://www.iana.org/domains/root/db/ci.html -ci -ac.ci -aéroport.ci -asso.ci -co.ci -com.ci -ed.ci -edu.ci -go.ci -gouv.ci -int.ci -net.ci -or.ci -org.ci - -// ck : https://www.iana.org/domains/root/db/ck.html -*.ck -!www.ck - -// cl : https://www.nic.cl -// Confirmed by .CL registry -cl -co.cl -gob.cl -gov.cl -mil.cl - -// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927 -cm -co.cm -com.cm -gov.cm -net.cm - -// cn : https://www.iana.org/domains/root/db/cn.html -// Submitted by registry -cn -ac.cn -com.cn -edu.cn -gov.cn -mil.cn -net.cn -org.cn -公司.cn -網絡.cn -网络.cn -// cn geographic names -ah.cn -bj.cn -cq.cn -fj.cn -gd.cn -gs.cn -gx.cn -gz.cn -ha.cn -hb.cn -he.cn -hi.cn -hk.cn -hl.cn -hn.cn -jl.cn -js.cn -jx.cn -ln.cn -mo.cn -nm.cn -nx.cn -qh.cn -sc.cn -sd.cn -sh.cn -sn.cn -sx.cn -tj.cn -tw.cn -xj.cn -xz.cn -yn.cn -zj.cn - -// co : https://www.iana.org/domains/root/db/co.html -// https://www.cointernet.com.co/como-funciona-un-dominio-restringido -// Confirmed by registry 2024-11-18 -co -com.co -edu.co -gov.co -mil.co -net.co -nom.co -org.co - -// com : https://www.iana.org/domains/root/db/com.html -com - -// coop : https://www.iana.org/domains/root/db/coop.html -coop - -// cr : https://nic.cr/capitulo-1-registro-de-un-nombre-de-dominio/ -cr -ac.cr -co.cr -ed.cr -fi.cr -go.cr -or.cr -sa.cr - -// cu : https://www.iana.org/domains/root/db/cu.html -cu -com.cu -edu.cu -gob.cu -inf.cu -nat.cu -net.cu -org.cu - -// cv : https://www.iana.org/domains/root/db/cv.html -// https://ola.cv/domain-extensions-under-cv/ -// Confirmed by registry 2024-11-26 -cv -com.cv -edu.cv -id.cv -int.cv -net.cv -nome.cv -org.cv -publ.cv - -// cw : https://www.uoc.cw/cw-registry -// Confirmed by registry 2024-11-19 -cw -com.cw -edu.cw -net.cw -org.cw - -// cx : https://www.iana.org/domains/root/db/cx.html -// list of other 2nd level tlds ? -cx -gov.cx - -// cy : http://www.nic.cy/ -// Submitted by Panayiotou Fotia -// https://nic.cy/wp-content/uploads/2024/01/Create-Request-for-domain-name-registration-1.pdf -cy -ac.cy -biz.cy -com.cy -ekloges.cy -gov.cy -ltd.cy -mil.cy -net.cy -org.cy -press.cy -pro.cy -tm.cy - -// cz : https://www.iana.org/domains/root/db/cz.html -// Confirmed by registry 2025-08-06 -cz -gov.cz - -// de : https://www.iana.org/domains/root/db/de.html -// Confirmed by registry (with technical -// reservations) 2008-07-01 -de - -// dj : https://www.iana.org/domains/root/db/dj.html -dj - -// dk : https://www.iana.org/domains/root/db/dk.html -// Confirmed by registry 2008-06-17 -dk - -// dm : https://www.iana.org/domains/root/db/dm.html -// https://nic.dm/policies/pdf/DMRulesandGuidelines2024v1.pdf -// Confirmed by registry 2024-11-19 -dm -co.dm -com.dm -edu.dm -gov.dm -net.dm -org.dm - -// do : https://www.iana.org/domains/root/db/do.html -do -art.do -com.do -edu.do -gob.do -gov.do -mil.do -net.do -org.do -sld.do -web.do - -// dz : http://www.nic.dz/images/pdf_nic/charte.pdf -dz -art.dz -asso.dz -com.dz -edu.dz -gov.dz -net.dz -org.dz -pol.dz -soc.dz -tm.dz - -// ec : https://www.nic.ec/ -// Submitted by registry -ec -abg.ec -adm.ec -agron.ec -arqt.ec -art.ec -bar.ec -chef.ec -com.ec -cont.ec -cpa.ec -cue.ec -dent.ec -dgn.ec -disco.ec -doc.ec -edu.ec -eng.ec -esm.ec -fin.ec -fot.ec -gal.ec -gob.ec -gov.ec -gye.ec -ibr.ec -info.ec -k12.ec -lat.ec -loj.ec -med.ec -mil.ec -mktg.ec -mon.ec -net.ec -ntr.ec -odont.ec -org.ec -pro.ec -prof.ec -psic.ec -psiq.ec -pub.ec -rio.ec -rrpp.ec -sal.ec -tech.ec -tul.ec -tur.ec -uio.ec -vet.ec -xxx.ec - -// edu : https://www.iana.org/domains/root/db/edu.html -edu - -// ee : https://www.internet.ee/domains/general-domains-and-procedure-for-registration-of-sub-domains-under-general-domains -ee -aip.ee -com.ee -edu.ee -fie.ee -gov.ee -lib.ee -med.ee -org.ee -pri.ee -riik.ee - -// eg : https://www.iana.org/domains/root/db/eg.html -// https://domain.eg/en/domain-rules/subdomain-names-types/ -eg -ac.eg -com.eg -edu.eg -eun.eg -gov.eg -info.eg -me.eg -mil.eg -name.eg -net.eg -org.eg -sci.eg -sport.eg -tv.eg - -// er : https://www.iana.org/domains/root/db/er.html -*.er - -// es : https://www.dominios.es/en -es -com.es -edu.es -gob.es -nom.es -org.es - -// et : https://www.iana.org/domains/root/db/et.html -et -biz.et -com.et -edu.et -gov.et -info.et -name.et -net.et -org.et - -// eu : https://www.iana.org/domains/root/db/eu.html -eu - -// fi : https://www.iana.org/domains/root/db/fi.html -fi -// aland.fi : https://www.iana.org/domains/root/db/ax.html -// This domain is being phased out in favor of .ax. As there are still many -// domains under aland.fi, we still keep it on the list until aland.fi is -// completely removed. -aland.fi - -// fj : https://www.iana.org/domains/root/db/fj.html -fj -ac.fj -biz.fj -com.fj -edu.fj -gov.fj -id.fj -info.fj -mil.fj -name.fj -net.fj -org.fj -pro.fj - -// fk : https://www.iana.org/domains/root/db/fk.html -*.fk - -// fm : https://www.iana.org/domains/root/db/fm.html -fm -com.fm -edu.fm -net.fm -org.fm - -// fo : https://www.iana.org/domains/root/db/fo.html -fo - -// fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -fr -asso.fr -com.fr -gouv.fr -nom.fr -prd.fr -tm.fr -// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes -avoues.fr -cci.fr -greta.fr -huissier-justice.fr - -// ga : https://www.iana.org/domains/root/db/ga.html -ga - -// gb : This registry is effectively dormant -// Submitted by registry -gb - -// gd : https://www.iana.org/domains/root/db/gd.html -gd -edu.gd -gov.gd - -// ge : https://nic.ge/en/administrator/the-ge-domain-regulations -// Confirmed by registry 2024-11-20 -ge -com.ge -cyb.ge -edu.ge -gov.ge -llc.ge -net.ge -online.ge -org.ge -pvt.ge -school.ge -tnx.ge - -// gf : https://www.iana.org/domains/root/db/gf.html -gf - -// gg : https://www.channelisles.net/register-1/register-direct -// Confirmed by registry 2013-11-28 -gg -co.gg -net.gg -org.gg - -// gh : https://www.iana.org/domains/root/db/gh.html -// https://www.nic.gh/ -// Although domains directly at second level are not possible at the moment, -// they have been possible for some time and may come back. -gh -biz.gh -com.gh -edu.gh -gov.gh -mil.gh -net.gh -org.gh - -// gi : http://www.nic.gi/rules.html -gi -com.gi -edu.gi -gov.gi -ltd.gi -mod.gi -org.gi - -// gl : https://www.iana.org/domains/root/db/gl.html -// http://nic.gl -gl -co.gl -com.gl -edu.gl -net.gl -org.gl - -// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm -gm - -// gn : http://psg.com/dns/gn/gn.txt -// Submitted by registry -gn -ac.gn -com.gn -edu.gn -gov.gn -net.gn -org.gn - -// gov : https://www.iana.org/domains/root/db/gov.html -gov - -// gp : http://www.nic.gp/index.php?lang=en -gp -asso.gp -com.gp -edu.gp -mobi.gp -net.gp -org.gp - -// gq : https://www.iana.org/domains/root/db/gq.html -gq - -// gr : https://www.iana.org/domains/root/db/gr.html -// Submitted by registry -gr -com.gr -edu.gr -gov.gr -net.gr -org.gr - -// gs : https://www.iana.org/domains/root/db/gs.html -gs - -// gt : https://www.gt/sitio/registration_policy.php?lang=en -gt -com.gt -edu.gt -gob.gt -ind.gt -mil.gt -net.gt -org.gt - -// gu : http://gadao.gov.gu/register.html -// University of Guam : https://www.uog.edu -// Submitted by uognoc@triton.uog.edu -gu -com.gu -edu.gu -gov.gu -guam.gu -info.gu -net.gu -org.gu -web.gu - -// gw : https://www.iana.org/domains/root/db/gw.html -// gw : https://nic.gw/regras/ -gw - -// gy : https://www.iana.org/domains/root/db/gy.html -// http://registry.gy/ -gy -co.gy -com.gy -edu.gy -gov.gy -net.gy -org.gy - -// hk : https://www.hkirc.hk -// Submitted by registry -hk -com.hk -edu.hk -gov.hk -idv.hk -net.hk -org.hk -个人.hk -個人.hk -公司.hk -政府.hk -敎育.hk -教育.hk -箇人.hk -組織.hk -組织.hk -網絡.hk -網络.hk -组織.hk -组织.hk -网絡.hk -网络.hk - -// hm : https://www.iana.org/domains/root/db/hm.html -hm - -// hn : https://www.iana.org/domains/root/db/hn.html -hn -com.hn -edu.hn -gob.hn -mil.hn -net.hn -org.hn - -// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf -hr -com.hr -from.hr -iz.hr -name.hr - -// ht : http://www.nic.ht/info/charte.cfm -ht -adult.ht -art.ht -asso.ht -com.ht -coop.ht -edu.ht -firm.ht -gouv.ht -info.ht -med.ht -net.ht -org.ht -perso.ht -pol.ht -pro.ht -rel.ht -shop.ht - -// hu : https://www.iana.org/domains/root/db/hu.html -// Confirmed by registry 2008-06-12 -hu -2000.hu -agrar.hu -bolt.hu -casino.hu -city.hu -co.hu -erotica.hu -erotika.hu -film.hu -forum.hu -games.hu -hotel.hu -info.hu -ingatlan.hu -jogasz.hu -konyvelo.hu -lakas.hu -media.hu -news.hu -org.hu -priv.hu -reklam.hu -sex.hu -shop.hu -sport.hu -suli.hu -szex.hu -tm.hu -tozsde.hu -utazas.hu -video.hu - -// id : https://www.iana.org/domains/root/db/id.html -id -ac.id -ai.id -biz.id -co.id -desa.id -go.id -kop.id -mil.id -my.id -net.id -or.id -ponpes.id -sch.id -web.id -// xn--9tfky.id (.id, Und-Bali) -ᬩᬮᬶ.id - -// ie : https://www.iana.org/domains/root/db/ie.html -ie -gov.ie - -// il : http://www.isoc.org.il/domains/ -// see also: https://en.isoc.org.il/il-cctld/registration-rules -// ISOC-IL (operated by .il Registry) -il -ac.il -co.il -gov.il -idf.il -k12.il -muni.il -net.il -org.il -// xn--4dbrk0ce ("Israel", Hebrew) : IL -ישראל -// xn--4dbgdty6c.xn--4dbrk0ce. -אקדמיה.ישראל -// xn--5dbhl8d.xn--4dbrk0ce. -ישוב.ישראל -// xn--8dbq2a.xn--4dbrk0ce. -צהל.ישראל -// xn--hebda8b.xn--4dbrk0ce. -ממשל.ישראל - -// im : https://www.nic.im/ -// Submitted by registry -im -ac.im -co.im -ltd.co.im -plc.co.im -com.im -net.im -org.im -tt.im -tv.im - -// in : https://www.iana.org/domains/root/db/in.html -// see also: https://registry.in/policies -// Please note, that nic.in is not an official eTLD, but used by most -// government institutions. -// Confirmed by Gaurav Kansal 2025-11-06 -// Added aero.in, alumni.in, school.in and ub.in by Gaurav Kansal 2026-06-25 -in -5g.in -6g.in -ac.in -aero.in -ai.in -alumni.in -am.in -bank.in -bihar.in -biz.in -business.in -ca.in -cn.in -co.in -com.in -coop.in -cs.in -delhi.in -dr.in -edu.in -er.in -fin.in -firm.in -gen.in -gov.in -gujarat.in -ind.in -info.in -int.in -internet.in -io.in -me.in -mil.in -net.in -nic.in -org.in -pg.in -post.in -pro.in -res.in -school.in -travel.in -tv.in -ub.in -uk.in -up.in -us.in - -// info : https://www.iana.org/domains/root/db/info.html -info - -// int : https://www.iana.org/domains/root/db/int.html -// Confirmed by registry 2008-06-18 -int -eu.int - -// io : http://www.nic.io/rules.htm -io -co.io -com.io -edu.io -gov.io -mil.io -net.io -nom.io -org.io - -// iq : http://www.cmc.iq/english/iq/iqregister1.htm -iq -com.iq -edu.iq -gov.iq -mil.iq -net.iq -org.iq - -// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules -// Also see http://www.nic.ir/Internationalized_Domain_Names -// Two .ir entries added at request of , 2010-04-16 -ir -ac.ir -co.ir -gov.ir -id.ir -net.ir -org.ir -sch.ir -// xn--mgba3a4f16a.ir (.ir, Persian YEH) -ایران.ir -// xn--mgba3a4fra.ir (.ir, Arabic YEH) -ايران.ir - -// is : http://www.isnic.is/domain/rules.php -// Confirmed by registry 2024-11-17 -is - -// it : https://www.iana.org/domains/root/db/it.html -// https://www.nic.it/ -it -edu.it -gov.it -// Regions (3.3.1) -// https://www.nic.it/en/manage-your-it/forms-and-docs -> "Assignment and Management of domain names" -abr.it -abruzzo.it -aosta-valley.it -aostavalley.it -bas.it -basilicata.it -cal.it -calabria.it -cam.it -campania.it -emilia-romagna.it -emiliaromagna.it -emr.it -friuli-v-giulia.it -friuli-ve-giulia.it -friuli-vegiulia.it -friuli-venezia-giulia.it -friuli-veneziagiulia.it -friuli-vgiulia.it -friuliv-giulia.it -friulive-giulia.it -friulivegiulia.it -friulivenezia-giulia.it -friuliveneziagiulia.it -friulivgiulia.it -fvg.it -laz.it -lazio.it -lig.it -liguria.it -lom.it -lombardia.it -lombardy.it -lucania.it -mar.it -marche.it -mol.it -molise.it -piedmont.it -piemonte.it -pmn.it -pug.it -puglia.it -sar.it -sardegna.it -sardinia.it -sic.it -sicilia.it -sicily.it -taa.it -tos.it -toscana.it -trentin-sud-tirol.it -trentin-süd-tirol.it -trentin-sudtirol.it -trentin-südtirol.it -trentin-sued-tirol.it -trentin-suedtirol.it -trentino-a-adige.it -trentino-aadige.it -trentino-alto-adige.it -trentino-altoadige.it -trentino-s-tirol.it -trentino-stirol.it -trentino-sud-tirol.it -trentino-süd-tirol.it -trentino-sudtirol.it -trentino-südtirol.it -trentino-sued-tirol.it -trentino-suedtirol.it -trentinoa-adige.it -trentinoaadige.it -trentinoalto-adige.it -trentinoaltoadige.it -trentinos-tirol.it -trentinostirol.it -trentinosud-tirol.it -trentinosüd-tirol.it -trentinosüdtirol.it -trentinosued-tirol.it -trentinosuedtirol.it -trentinsud-tirol.it -trentinsüd-tirol.it -trentinsudtirol.it -trentinsüdtirol.it -trentinsued-tirol.it -trentinsuedtirol.it -tuscany.it -umb.it -umbria.it -val-d-aosta.it -val-daosta.it -vald-aosta.it -valle-aosta.it -valle-d-aosta.it -valle-daosta.it -valleaosta.it -valled-aosta.it -valledaosta.it -vallee-aoste.it -vallée-aoste.it -vallee-d-aoste.it -vallée-d-aoste.it -valleeaoste.it -valléeaoste.it -valleedaoste.it -valléedaoste.it -vao.it -vda.it -ven.it -veneto.it -// Provinces (3.3.2) -ag.it -agrigento.it -al.it -alessandria.it -alto-adige.it -altoadige.it -an.it -ancona.it -andria-barletta-trani.it -andria-trani-barletta.it -andriabarlettatrani.it -andriatranibarletta.it -ao.it -aosta.it -aoste.it -ap.it -aq.it -ar.it -arezzo.it -ascoli-piceno.it -ascolipiceno.it -asti.it -at.it -av.it -avellino.it -ba.it -balsan.it -balsan-sudtirol.it -balsan-südtirol.it -balsan-suedtirol.it -bari.it -barletta-trani-andria.it -barlettatraniandria.it -belluno.it -benevento.it -bergamo.it -bg.it -bi.it -biella.it -bl.it -bn.it -bo.it -bologna.it -bolzano.it -bolzano-altoadige.it -bozen.it -bozen-sudtirol.it -bozen-südtirol.it -bozen-suedtirol.it -br.it -brescia.it -brindisi.it -bs.it -bt.it -bulsan.it -bulsan-sudtirol.it -bulsan-südtirol.it -bulsan-suedtirol.it -bz.it -ca.it -cagliari.it -caltanissetta.it -campidano-medio.it -campidanomedio.it -campobasso.it -carbonia-iglesias.it -carboniaiglesias.it -carrara-massa.it -carraramassa.it -caserta.it -catania.it -catanzaro.it -cb.it -ce.it -cesena-forli.it -cesena-forlì.it -cesenaforli.it -cesenaforlì.it -ch.it -chieti.it -ci.it -cl.it -cn.it -co.it -como.it -cosenza.it -cr.it -cremona.it -crotone.it -cs.it -ct.it -cuneo.it -cz.it -dell-ogliastra.it -dellogliastra.it -en.it -enna.it -fc.it -fe.it -fermo.it -ferrara.it -fg.it -fi.it -firenze.it -florence.it -fm.it -foggia.it -forli-cesena.it -forlì-cesena.it -forlicesena.it -forlìcesena.it -fr.it -frosinone.it -ge.it -genoa.it -genova.it -go.it -gorizia.it -gr.it -grosseto.it -iglesias-carbonia.it -iglesiascarbonia.it -im.it -imperia.it -is.it -isernia.it -kr.it -la-spezia.it -laquila.it -laspezia.it -latina.it -lc.it -le.it -lecce.it -lecco.it -li.it -livorno.it -lo.it -lodi.it -lt.it -lu.it -lucca.it -macerata.it -mantova.it -massa-carrara.it -massacarrara.it -matera.it -mb.it -mc.it -me.it -medio-campidano.it -mediocampidano.it -messina.it -mi.it -milan.it -milano.it -mn.it -mo.it -modena.it -monza.it -monza-brianza.it -monza-e-della-brianza.it -monzabrianza.it -monzaebrianza.it -monzaedellabrianza.it -ms.it -mt.it -na.it -naples.it -napoli.it -no.it -novara.it -nu.it -nuoro.it -og.it -ogliastra.it -olbia-tempio.it -olbiatempio.it -or.it -oristano.it -ot.it -pa.it -padova.it -padua.it -palermo.it -parma.it -pavia.it -pc.it -pd.it -pe.it -perugia.it -pesaro-urbino.it -pesarourbino.it -pescara.it -pg.it -pi.it -piacenza.it -pisa.it -pistoia.it -pn.it -po.it -pordenone.it -potenza.it -pr.it -prato.it -pt.it -pu.it -pv.it -pz.it -ra.it -ragusa.it -ravenna.it -rc.it -re.it -reggio-calabria.it -reggio-emilia.it -reggiocalabria.it -reggioemilia.it -rg.it -ri.it -rieti.it -rimini.it -rm.it -rn.it -ro.it -roma.it -rome.it -rovigo.it -sa.it -salerno.it -sassari.it -savona.it -si.it -siena.it -siracusa.it -so.it -sondrio.it -sp.it -sr.it -ss.it -su.it -sud-sardegna.it -sudsardegna.it -südtirol.it -suedtirol.it -sv.it -ta.it -taranto.it -te.it -tempio-olbia.it -tempioolbia.it -teramo.it -terni.it -tn.it -to.it -torino.it -tp.it -tr.it -trani-andria-barletta.it -trani-barletta-andria.it -traniandriabarletta.it -tranibarlettaandria.it -trapani.it -trentino.it -trento.it -treviso.it -trieste.it -ts.it -turin.it -tv.it -ud.it -udine.it -urbino-pesaro.it -urbinopesaro.it -va.it -varese.it -vb.it -vc.it -ve.it -venezia.it -venice.it -verbania.it -verbano-cusio-ossola.it -vercelli.it -verona.it -vi.it -vibo-valentia.it -vibovalentia.it -vicenza.it -viterbo.it -vr.it -vs.it -vt.it -vv.it - -// je : https://www.iana.org/domains/root/db/je.html -// Confirmed by registry 2013-11-28 -je -co.je -net.je -org.je - -// jm : http://www.com.jm/register.html -*.jm - -// jo : https://www.dns.jo/JoFamily.aspx -// Confirmed by registry 2024-11-17 -jo -agri.jo -ai.jo -com.jo -edu.jo -eng.jo -fm.jo -gov.jo -mil.jo -net.jo -org.jo -per.jo -phd.jo -sch.jo -tv.jo - -// jobs : https://www.iana.org/domains/root/db/jobs.html -jobs - -// jp : https://www.iana.org/domains/root/db/jp.html -// http://jprs.co.jp/en/jpdomain.html -// Confirmed by registry 2024-11-22 -jp -// jp organizational type names -ac.jp -ad.jp -co.jp -ed.jp -go.jp -gr.jp -lg.jp -ne.jp -or.jp -// jp prefecture type names -aichi.jp -akita.jp -aomori.jp -chiba.jp -ehime.jp -fukui.jp -fukuoka.jp -fukushima.jp -gifu.jp -gunma.jp -hiroshima.jp -hokkaido.jp -hyogo.jp -ibaraki.jp -ishikawa.jp -iwate.jp -kagawa.jp -kagoshima.jp -kanagawa.jp -kochi.jp -kumamoto.jp -kyoto.jp -mie.jp -miyagi.jp -miyazaki.jp -nagano.jp -nagasaki.jp -nara.jp -niigata.jp -oita.jp -okayama.jp -okinawa.jp -osaka.jp -saga.jp -saitama.jp -shiga.jp -shimane.jp -shizuoka.jp -tochigi.jp -tokushima.jp -tokyo.jp -tottori.jp -toyama.jp -wakayama.jp -yamagata.jp -yamaguchi.jp -yamanashi.jp -三重.jp -京都.jp -佐賀.jp -兵庫.jp -北海道.jp -千葉.jp -和歌山.jp -埼玉.jp -大分.jp -大阪.jp -奈良.jp -宮城.jp -宮崎.jp -富山.jp -山口.jp -山形.jp -山梨.jp -岐阜.jp -岡山.jp -岩手.jp -島根.jp -広島.jp -徳島.jp -愛媛.jp -愛知.jp -新潟.jp -東京.jp -栃木.jp -沖縄.jp -滋賀.jp -熊本.jp -石川.jp -神奈川.jp -福井.jp -福岡.jp -福島.jp -秋田.jp -群馬.jp -茨城.jp -長崎.jp -長野.jp -青森.jp -静岡.jp -香川.jp -高知.jp -鳥取.jp -鹿児島.jp -// jp geographic type names -// http://jprs.jp/doc/rule/saisoku-1.html -// 2024-11-22: JPRS confirmed that jp geographic type names no longer accept new registrations. -// Once all existing registrations expire (marking full discontinuation), these suffixes -// will be removed from the PSL. -*.kawasaki.jp -!city.kawasaki.jp -*.kitakyushu.jp -!city.kitakyushu.jp -*.kobe.jp -!city.kobe.jp -*.nagoya.jp -!city.nagoya.jp -*.sapporo.jp -!city.sapporo.jp -*.sendai.jp -!city.sendai.jp -*.yokohama.jp -!city.yokohama.jp -// 4th level registration -aisai.aichi.jp -ama.aichi.jp -anjo.aichi.jp -asuke.aichi.jp -chiryu.aichi.jp -chita.aichi.jp -fuso.aichi.jp -gamagori.aichi.jp -handa.aichi.jp -hazu.aichi.jp -hekinan.aichi.jp -higashiura.aichi.jp -ichinomiya.aichi.jp -inazawa.aichi.jp -inuyama.aichi.jp -isshiki.aichi.jp -iwakura.aichi.jp -kanie.aichi.jp -kariya.aichi.jp -kasugai.aichi.jp -kira.aichi.jp -kiyosu.aichi.jp -komaki.aichi.jp -konan.aichi.jp -kota.aichi.jp -mihama.aichi.jp -miyoshi.aichi.jp -nishio.aichi.jp -nisshin.aichi.jp -obu.aichi.jp -oguchi.aichi.jp -oharu.aichi.jp -okazaki.aichi.jp -owariasahi.aichi.jp -seto.aichi.jp -shikatsu.aichi.jp -shinshiro.aichi.jp -shitara.aichi.jp -tahara.aichi.jp -takahama.aichi.jp -tobishima.aichi.jp -toei.aichi.jp -togo.aichi.jp -tokai.aichi.jp -tokoname.aichi.jp -toyoake.aichi.jp -toyohashi.aichi.jp -toyokawa.aichi.jp -toyone.aichi.jp -toyota.aichi.jp -tsushima.aichi.jp -yatomi.aichi.jp -akita.akita.jp -daisen.akita.jp -fujisato.akita.jp -gojome.akita.jp -hachirogata.akita.jp -happou.akita.jp -higashinaruse.akita.jp -honjo.akita.jp -honjyo.akita.jp -ikawa.akita.jp -kamikoani.akita.jp -kamioka.akita.jp -katagami.akita.jp -kazuno.akita.jp -kitaakita.akita.jp -kosaka.akita.jp -kyowa.akita.jp -misato.akita.jp -mitane.akita.jp -moriyoshi.akita.jp -nikaho.akita.jp -noshiro.akita.jp -odate.akita.jp -oga.akita.jp -ogata.akita.jp -semboku.akita.jp -yokote.akita.jp -yurihonjo.akita.jp -aomori.aomori.jp -gonohe.aomori.jp -hachinohe.aomori.jp -hashikami.aomori.jp -hiranai.aomori.jp -hirosaki.aomori.jp -itayanagi.aomori.jp -kuroishi.aomori.jp -misawa.aomori.jp -mutsu.aomori.jp -nakadomari.aomori.jp -noheji.aomori.jp -oirase.aomori.jp -owani.aomori.jp -rokunohe.aomori.jp -sannohe.aomori.jp -shichinohe.aomori.jp -shingo.aomori.jp -takko.aomori.jp -towada.aomori.jp -tsugaru.aomori.jp -tsuruta.aomori.jp -abiko.chiba.jp -asahi.chiba.jp -chonan.chiba.jp -chosei.chiba.jp -choshi.chiba.jp -chuo.chiba.jp -funabashi.chiba.jp -futtsu.chiba.jp -hanamigawa.chiba.jp -ichihara.chiba.jp -ichikawa.chiba.jp -ichinomiya.chiba.jp -inzai.chiba.jp -isumi.chiba.jp -kamagaya.chiba.jp -kamogawa.chiba.jp -kashiwa.chiba.jp -katori.chiba.jp -katsuura.chiba.jp -kimitsu.chiba.jp -kisarazu.chiba.jp -kozaki.chiba.jp -kujukuri.chiba.jp -kyonan.chiba.jp -matsudo.chiba.jp -midori.chiba.jp -mihama.chiba.jp -minamiboso.chiba.jp -mobara.chiba.jp -mutsuzawa.chiba.jp -nagara.chiba.jp -nagareyama.chiba.jp -narashino.chiba.jp -narita.chiba.jp -noda.chiba.jp -oamishirasato.chiba.jp -omigawa.chiba.jp -onjuku.chiba.jp -otaki.chiba.jp -sakae.chiba.jp -sakura.chiba.jp -shimofusa.chiba.jp -shirako.chiba.jp -shiroi.chiba.jp -shisui.chiba.jp -sodegaura.chiba.jp -sosa.chiba.jp -tako.chiba.jp -tateyama.chiba.jp -togane.chiba.jp -tohnosho.chiba.jp -tomisato.chiba.jp -urayasu.chiba.jp -yachimata.chiba.jp -yachiyo.chiba.jp -yokaichiba.chiba.jp -yokoshibahikari.chiba.jp -yotsukaido.chiba.jp -ainan.ehime.jp -honai.ehime.jp -ikata.ehime.jp -imabari.ehime.jp -iyo.ehime.jp -kamijima.ehime.jp -kihoku.ehime.jp -kumakogen.ehime.jp -masaki.ehime.jp -matsuno.ehime.jp -matsuyama.ehime.jp -namikata.ehime.jp -niihama.ehime.jp -ozu.ehime.jp -saijo.ehime.jp -seiyo.ehime.jp -shikokuchuo.ehime.jp -tobe.ehime.jp -toon.ehime.jp -uchiko.ehime.jp -uwajima.ehime.jp -yawatahama.ehime.jp -echizen.fukui.jp -eiheiji.fukui.jp -fukui.fukui.jp -ikeda.fukui.jp -katsuyama.fukui.jp -mihama.fukui.jp -minamiechizen.fukui.jp -obama.fukui.jp -ohi.fukui.jp -ono.fukui.jp -sabae.fukui.jp -sakai.fukui.jp -takahama.fukui.jp -tsuruga.fukui.jp -wakasa.fukui.jp -ashiya.fukuoka.jp -buzen.fukuoka.jp -chikugo.fukuoka.jp -chikuho.fukuoka.jp -chikujo.fukuoka.jp -chikushino.fukuoka.jp -chikuzen.fukuoka.jp -chuo.fukuoka.jp -dazaifu.fukuoka.jp -fukuchi.fukuoka.jp -hakata.fukuoka.jp -higashi.fukuoka.jp -hirokawa.fukuoka.jp -hisayama.fukuoka.jp -iizuka.fukuoka.jp -inatsuki.fukuoka.jp -kaho.fukuoka.jp -kasuga.fukuoka.jp -kasuya.fukuoka.jp -kawara.fukuoka.jp -keisen.fukuoka.jp -koga.fukuoka.jp -kurate.fukuoka.jp -kurogi.fukuoka.jp -kurume.fukuoka.jp -minami.fukuoka.jp -miyako.fukuoka.jp -miyama.fukuoka.jp -miyawaka.fukuoka.jp -mizumaki.fukuoka.jp -munakata.fukuoka.jp -nakagawa.fukuoka.jp -nakama.fukuoka.jp -nishi.fukuoka.jp -nogata.fukuoka.jp -ogori.fukuoka.jp -okagaki.fukuoka.jp -okawa.fukuoka.jp -oki.fukuoka.jp -omuta.fukuoka.jp -onga.fukuoka.jp -onojo.fukuoka.jp -oto.fukuoka.jp -saigawa.fukuoka.jp -sasaguri.fukuoka.jp -shingu.fukuoka.jp -shinyoshitomi.fukuoka.jp -shonai.fukuoka.jp -soeda.fukuoka.jp -sue.fukuoka.jp -tachiarai.fukuoka.jp -tagawa.fukuoka.jp -takata.fukuoka.jp -toho.fukuoka.jp -toyotsu.fukuoka.jp -tsuiki.fukuoka.jp -ukiha.fukuoka.jp -umi.fukuoka.jp -usui.fukuoka.jp -yamada.fukuoka.jp -yame.fukuoka.jp -yanagawa.fukuoka.jp -yukuhashi.fukuoka.jp -aizubange.fukushima.jp -aizumisato.fukushima.jp -aizuwakamatsu.fukushima.jp -asakawa.fukushima.jp -bandai.fukushima.jp -date.fukushima.jp -fukushima.fukushima.jp -furudono.fukushima.jp -futaba.fukushima.jp -hanawa.fukushima.jp -higashi.fukushima.jp -hirata.fukushima.jp -hirono.fukushima.jp -iitate.fukushima.jp -inawashiro.fukushima.jp -ishikawa.fukushima.jp -iwaki.fukushima.jp -izumizaki.fukushima.jp -kagamiishi.fukushima.jp -kaneyama.fukushima.jp -kawamata.fukushima.jp -kitakata.fukushima.jp -kitashiobara.fukushima.jp -koori.fukushima.jp -koriyama.fukushima.jp -kunimi.fukushima.jp -miharu.fukushima.jp -mishima.fukushima.jp -namie.fukushima.jp -nango.fukushima.jp -nishiaizu.fukushima.jp -nishigo.fukushima.jp -okuma.fukushima.jp -omotego.fukushima.jp -ono.fukushima.jp -otama.fukushima.jp -samegawa.fukushima.jp -shimogo.fukushima.jp -shirakawa.fukushima.jp -showa.fukushima.jp -soma.fukushima.jp -sukagawa.fukushima.jp -taishin.fukushima.jp -tamakawa.fukushima.jp -tanagura.fukushima.jp -tenei.fukushima.jp -yabuki.fukushima.jp -yamato.fukushima.jp -yamatsuri.fukushima.jp -yanaizu.fukushima.jp -yugawa.fukushima.jp -anpachi.gifu.jp -ena.gifu.jp -gifu.gifu.jp -ginan.gifu.jp -godo.gifu.jp -gujo.gifu.jp -hashima.gifu.jp -hichiso.gifu.jp -hida.gifu.jp -higashishirakawa.gifu.jp -ibigawa.gifu.jp -ikeda.gifu.jp -kakamigahara.gifu.jp -kani.gifu.jp -kasahara.gifu.jp -kasamatsu.gifu.jp -kawaue.gifu.jp -kitagata.gifu.jp -mino.gifu.jp -minokamo.gifu.jp -mitake.gifu.jp -mizunami.gifu.jp -motosu.gifu.jp -nakatsugawa.gifu.jp -ogaki.gifu.jp -sakahogi.gifu.jp -seki.gifu.jp -sekigahara.gifu.jp -shirakawa.gifu.jp -tajimi.gifu.jp -takayama.gifu.jp -tarui.gifu.jp -toki.gifu.jp -tomika.gifu.jp -wanouchi.gifu.jp -yamagata.gifu.jp -yaotsu.gifu.jp -yoro.gifu.jp -annaka.gunma.jp -chiyoda.gunma.jp -fujioka.gunma.jp -higashiagatsuma.gunma.jp -isesaki.gunma.jp -itakura.gunma.jp -kanna.gunma.jp -kanra.gunma.jp -katashina.gunma.jp -kawaba.gunma.jp -kiryu.gunma.jp -kusatsu.gunma.jp -maebashi.gunma.jp -meiwa.gunma.jp -midori.gunma.jp -minakami.gunma.jp -naganohara.gunma.jp -nakanojo.gunma.jp -nanmoku.gunma.jp -numata.gunma.jp -oizumi.gunma.jp -ora.gunma.jp -ota.gunma.jp -shibukawa.gunma.jp -shimonita.gunma.jp -shinto.gunma.jp -showa.gunma.jp -takasaki.gunma.jp -takayama.gunma.jp -tamamura.gunma.jp -tatebayashi.gunma.jp -tomioka.gunma.jp -tsukiyono.gunma.jp -tsumagoi.gunma.jp -ueno.gunma.jp -yoshioka.gunma.jp -asaminami.hiroshima.jp -daiwa.hiroshima.jp -etajima.hiroshima.jp -fuchu.hiroshima.jp -fukuyama.hiroshima.jp -hatsukaichi.hiroshima.jp -higashihiroshima.hiroshima.jp -hongo.hiroshima.jp -jinsekikogen.hiroshima.jp -kaita.hiroshima.jp -kui.hiroshima.jp -kumano.hiroshima.jp -kure.hiroshima.jp -mihara.hiroshima.jp -miyoshi.hiroshima.jp -naka.hiroshima.jp -onomichi.hiroshima.jp -osakikamijima.hiroshima.jp -otake.hiroshima.jp -saka.hiroshima.jp -sera.hiroshima.jp -seranishi.hiroshima.jp -shinichi.hiroshima.jp -shobara.hiroshima.jp -takehara.hiroshima.jp -abashiri.hokkaido.jp -abira.hokkaido.jp -aibetsu.hokkaido.jp -akabira.hokkaido.jp -akkeshi.hokkaido.jp -asahikawa.hokkaido.jp -ashibetsu.hokkaido.jp -ashoro.hokkaido.jp -assabu.hokkaido.jp -atsuma.hokkaido.jp -bibai.hokkaido.jp -biei.hokkaido.jp -bifuka.hokkaido.jp -bihoro.hokkaido.jp -biratori.hokkaido.jp -chippubetsu.hokkaido.jp -chitose.hokkaido.jp -date.hokkaido.jp -ebetsu.hokkaido.jp -embetsu.hokkaido.jp -eniwa.hokkaido.jp -erimo.hokkaido.jp -esan.hokkaido.jp -esashi.hokkaido.jp -fukagawa.hokkaido.jp -fukushima.hokkaido.jp -furano.hokkaido.jp -furubira.hokkaido.jp -haboro.hokkaido.jp -hakodate.hokkaido.jp -hamatonbetsu.hokkaido.jp -hidaka.hokkaido.jp -higashikagura.hokkaido.jp -higashikawa.hokkaido.jp -hiroo.hokkaido.jp -hokuryu.hokkaido.jp -hokuto.hokkaido.jp -honbetsu.hokkaido.jp -horokanai.hokkaido.jp -horonobe.hokkaido.jp -ikeda.hokkaido.jp -imakane.hokkaido.jp -ishikari.hokkaido.jp -iwamizawa.hokkaido.jp -iwanai.hokkaido.jp -kamifurano.hokkaido.jp -kamikawa.hokkaido.jp -kamishihoro.hokkaido.jp -kamisunagawa.hokkaido.jp -kamoenai.hokkaido.jp -kayabe.hokkaido.jp -kembuchi.hokkaido.jp -kikonai.hokkaido.jp -kimobetsu.hokkaido.jp -kitahiroshima.hokkaido.jp -kitami.hokkaido.jp -kiyosato.hokkaido.jp -koshimizu.hokkaido.jp -kunneppu.hokkaido.jp -kuriyama.hokkaido.jp -kuromatsunai.hokkaido.jp -kushiro.hokkaido.jp -kutchan.hokkaido.jp -kyowa.hokkaido.jp -mashike.hokkaido.jp -matsumae.hokkaido.jp -mikasa.hokkaido.jp -minamifurano.hokkaido.jp -mombetsu.hokkaido.jp -moseushi.hokkaido.jp -mukawa.hokkaido.jp -muroran.hokkaido.jp -naie.hokkaido.jp -nakagawa.hokkaido.jp -nakasatsunai.hokkaido.jp -nakatombetsu.hokkaido.jp -nanae.hokkaido.jp -nanporo.hokkaido.jp -nayoro.hokkaido.jp -nemuro.hokkaido.jp -niikappu.hokkaido.jp -niki.hokkaido.jp -nishiokoppe.hokkaido.jp -noboribetsu.hokkaido.jp -numata.hokkaido.jp -obihiro.hokkaido.jp -obira.hokkaido.jp -oketo.hokkaido.jp -okoppe.hokkaido.jp -otaru.hokkaido.jp -otobe.hokkaido.jp -otofuke.hokkaido.jp -otoineppu.hokkaido.jp -oumu.hokkaido.jp -ozora.hokkaido.jp -pippu.hokkaido.jp -rankoshi.hokkaido.jp -rebun.hokkaido.jp -rikubetsu.hokkaido.jp -rishiri.hokkaido.jp -rishirifuji.hokkaido.jp -saroma.hokkaido.jp -sarufutsu.hokkaido.jp -shakotan.hokkaido.jp -shari.hokkaido.jp -shibecha.hokkaido.jp -shibetsu.hokkaido.jp -shikabe.hokkaido.jp -shikaoi.hokkaido.jp -shimamaki.hokkaido.jp -shimizu.hokkaido.jp -shimokawa.hokkaido.jp -shinshinotsu.hokkaido.jp -shintoku.hokkaido.jp -shiranuka.hokkaido.jp -shiraoi.hokkaido.jp -shiriuchi.hokkaido.jp -sobetsu.hokkaido.jp -sunagawa.hokkaido.jp -taiki.hokkaido.jp -takasu.hokkaido.jp -takikawa.hokkaido.jp -takinoue.hokkaido.jp -teshikaga.hokkaido.jp -tobetsu.hokkaido.jp -tohma.hokkaido.jp -tomakomai.hokkaido.jp -tomari.hokkaido.jp -toya.hokkaido.jp -toyako.hokkaido.jp -toyotomi.hokkaido.jp -toyoura.hokkaido.jp -tsubetsu.hokkaido.jp -tsukigata.hokkaido.jp -urakawa.hokkaido.jp -urausu.hokkaido.jp -uryu.hokkaido.jp -utashinai.hokkaido.jp -wakkanai.hokkaido.jp -wassamu.hokkaido.jp -yakumo.hokkaido.jp -yoichi.hokkaido.jp -aioi.hyogo.jp -akashi.hyogo.jp -ako.hyogo.jp -amagasaki.hyogo.jp -aogaki.hyogo.jp -asago.hyogo.jp -ashiya.hyogo.jp -awaji.hyogo.jp -fukusaki.hyogo.jp -goshiki.hyogo.jp -harima.hyogo.jp -himeji.hyogo.jp -ichikawa.hyogo.jp -inagawa.hyogo.jp -itami.hyogo.jp -kakogawa.hyogo.jp -kamigori.hyogo.jp -kamikawa.hyogo.jp -kasai.hyogo.jp -kasuga.hyogo.jp -kawanishi.hyogo.jp -miki.hyogo.jp -minamiawaji.hyogo.jp -nishinomiya.hyogo.jp -nishiwaki.hyogo.jp -ono.hyogo.jp -sanda.hyogo.jp -sannan.hyogo.jp -sasayama.hyogo.jp -sayo.hyogo.jp -shingu.hyogo.jp -shinonsen.hyogo.jp -shiso.hyogo.jp -sumoto.hyogo.jp -taishi.hyogo.jp -taka.hyogo.jp -takarazuka.hyogo.jp -takasago.hyogo.jp -takino.hyogo.jp -tamba.hyogo.jp -tatsuno.hyogo.jp -toyooka.hyogo.jp -yabu.hyogo.jp -yashiro.hyogo.jp -yoka.hyogo.jp -yokawa.hyogo.jp -ami.ibaraki.jp -asahi.ibaraki.jp -bando.ibaraki.jp -chikusei.ibaraki.jp -daigo.ibaraki.jp -fujishiro.ibaraki.jp -hitachi.ibaraki.jp -hitachinaka.ibaraki.jp -hitachiomiya.ibaraki.jp -hitachiota.ibaraki.jp -ibaraki.ibaraki.jp -ina.ibaraki.jp -inashiki.ibaraki.jp -itako.ibaraki.jp -iwama.ibaraki.jp -joso.ibaraki.jp -kamisu.ibaraki.jp -kasama.ibaraki.jp -kashima.ibaraki.jp -kasumigaura.ibaraki.jp -koga.ibaraki.jp -miho.ibaraki.jp -mito.ibaraki.jp -moriya.ibaraki.jp -naka.ibaraki.jp -namegata.ibaraki.jp -oarai.ibaraki.jp -ogawa.ibaraki.jp -omitama.ibaraki.jp -ryugasaki.ibaraki.jp -sakai.ibaraki.jp -sakuragawa.ibaraki.jp -shimodate.ibaraki.jp -shimotsuma.ibaraki.jp -shirosato.ibaraki.jp -sowa.ibaraki.jp -suifu.ibaraki.jp -takahagi.ibaraki.jp -tamatsukuri.ibaraki.jp -tokai.ibaraki.jp -tomobe.ibaraki.jp -tone.ibaraki.jp -toride.ibaraki.jp -tsuchiura.ibaraki.jp -tsukuba.ibaraki.jp -uchihara.ibaraki.jp -ushiku.ibaraki.jp -yachiyo.ibaraki.jp -yamagata.ibaraki.jp -yawara.ibaraki.jp -yuki.ibaraki.jp -anamizu.ishikawa.jp -hakui.ishikawa.jp -hakusan.ishikawa.jp -kaga.ishikawa.jp -kahoku.ishikawa.jp -kanazawa.ishikawa.jp -kawakita.ishikawa.jp -komatsu.ishikawa.jp -nakanoto.ishikawa.jp -nanao.ishikawa.jp -nomi.ishikawa.jp -nonoichi.ishikawa.jp -noto.ishikawa.jp -shika.ishikawa.jp -suzu.ishikawa.jp -tsubata.ishikawa.jp -tsurugi.ishikawa.jp -uchinada.ishikawa.jp -wajima.ishikawa.jp -fudai.iwate.jp -fujisawa.iwate.jp -hanamaki.iwate.jp -hiraizumi.iwate.jp -hirono.iwate.jp -ichinohe.iwate.jp -ichinoseki.iwate.jp -iwaizumi.iwate.jp -iwate.iwate.jp -joboji.iwate.jp -kamaishi.iwate.jp -kanegasaki.iwate.jp -karumai.iwate.jp -kawai.iwate.jp -kitakami.iwate.jp -kuji.iwate.jp -kunohe.iwate.jp -kuzumaki.iwate.jp -miyako.iwate.jp -mizusawa.iwate.jp -morioka.iwate.jp -ninohe.iwate.jp -noda.iwate.jp -ofunato.iwate.jp -oshu.iwate.jp -otsuchi.iwate.jp -rikuzentakata.iwate.jp -shiwa.iwate.jp -shizukuishi.iwate.jp -sumita.iwate.jp -tanohata.iwate.jp -tono.iwate.jp -yahaba.iwate.jp -yamada.iwate.jp -ayagawa.kagawa.jp -higashikagawa.kagawa.jp -kanonji.kagawa.jp -kotohira.kagawa.jp -manno.kagawa.jp -marugame.kagawa.jp -mitoyo.kagawa.jp -naoshima.kagawa.jp -sanuki.kagawa.jp -tadotsu.kagawa.jp -takamatsu.kagawa.jp -tonosho.kagawa.jp -uchinomi.kagawa.jp -utazu.kagawa.jp -zentsuji.kagawa.jp -akune.kagoshima.jp -amami.kagoshima.jp -hioki.kagoshima.jp -isa.kagoshima.jp -isen.kagoshima.jp -izumi.kagoshima.jp -kagoshima.kagoshima.jp -kanoya.kagoshima.jp -kawanabe.kagoshima.jp -kinko.kagoshima.jp -kouyama.kagoshima.jp -makurazaki.kagoshima.jp -matsumoto.kagoshima.jp -minamitane.kagoshima.jp -nakatane.kagoshima.jp -nishinoomote.kagoshima.jp -satsumasendai.kagoshima.jp -soo.kagoshima.jp -tarumizu.kagoshima.jp -yusui.kagoshima.jp -aikawa.kanagawa.jp -atsugi.kanagawa.jp -ayase.kanagawa.jp -chigasaki.kanagawa.jp -ebina.kanagawa.jp -fujisawa.kanagawa.jp -hadano.kanagawa.jp -hakone.kanagawa.jp -hiratsuka.kanagawa.jp -isehara.kanagawa.jp -kaisei.kanagawa.jp -kamakura.kanagawa.jp -kiyokawa.kanagawa.jp -matsuda.kanagawa.jp -minamiashigara.kanagawa.jp -miura.kanagawa.jp -nakai.kanagawa.jp -ninomiya.kanagawa.jp -odawara.kanagawa.jp -oi.kanagawa.jp -oiso.kanagawa.jp -sagamihara.kanagawa.jp -samukawa.kanagawa.jp -tsukui.kanagawa.jp -yamakita.kanagawa.jp -yamato.kanagawa.jp -yokosuka.kanagawa.jp -yugawara.kanagawa.jp -zama.kanagawa.jp -zushi.kanagawa.jp -aki.kochi.jp -geisei.kochi.jp -hidaka.kochi.jp -higashitsuno.kochi.jp -ino.kochi.jp -kagami.kochi.jp -kami.kochi.jp -kitagawa.kochi.jp -kochi.kochi.jp -mihara.kochi.jp -motoyama.kochi.jp -muroto.kochi.jp -nahari.kochi.jp -nakamura.kochi.jp -nankoku.kochi.jp -nishitosa.kochi.jp -niyodogawa.kochi.jp -ochi.kochi.jp -okawa.kochi.jp -otoyo.kochi.jp -otsuki.kochi.jp -sakawa.kochi.jp -sukumo.kochi.jp -susaki.kochi.jp -tosa.kochi.jp -tosashimizu.kochi.jp -toyo.kochi.jp -tsuno.kochi.jp -umaji.kochi.jp -yasuda.kochi.jp -yusuhara.kochi.jp -amakusa.kumamoto.jp -arao.kumamoto.jp -aso.kumamoto.jp -choyo.kumamoto.jp -gyokuto.kumamoto.jp -kamiamakusa.kumamoto.jp -kikuchi.kumamoto.jp -kumamoto.kumamoto.jp -mashiki.kumamoto.jp -mifune.kumamoto.jp -minamata.kumamoto.jp -minamioguni.kumamoto.jp -nagasu.kumamoto.jp -nishihara.kumamoto.jp -oguni.kumamoto.jp -ozu.kumamoto.jp -sumoto.kumamoto.jp -takamori.kumamoto.jp -uki.kumamoto.jp -uto.kumamoto.jp -yamaga.kumamoto.jp -yamato.kumamoto.jp -yatsushiro.kumamoto.jp -ayabe.kyoto.jp -fukuchiyama.kyoto.jp -higashiyama.kyoto.jp -ide.kyoto.jp -ine.kyoto.jp -joyo.kyoto.jp -kameoka.kyoto.jp -kamo.kyoto.jp -kita.kyoto.jp -kizu.kyoto.jp -kumiyama.kyoto.jp -kyotamba.kyoto.jp -kyotanabe.kyoto.jp -kyotango.kyoto.jp -maizuru.kyoto.jp -minami.kyoto.jp -minamiyamashiro.kyoto.jp -miyazu.kyoto.jp -muko.kyoto.jp -nagaokakyo.kyoto.jp -nakagyo.kyoto.jp -nantan.kyoto.jp -oyamazaki.kyoto.jp -sakyo.kyoto.jp -seika.kyoto.jp -tanabe.kyoto.jp -uji.kyoto.jp -ujitawara.kyoto.jp -wazuka.kyoto.jp -yamashina.kyoto.jp -yawata.kyoto.jp -asahi.mie.jp -inabe.mie.jp -ise.mie.jp -kameyama.mie.jp -kawagoe.mie.jp -kiho.mie.jp -kisosaki.mie.jp -kiwa.mie.jp -komono.mie.jp -kumano.mie.jp -kuwana.mie.jp -matsusaka.mie.jp -meiwa.mie.jp -mihama.mie.jp -minamiise.mie.jp -misugi.mie.jp -miyama.mie.jp -nabari.mie.jp -shima.mie.jp -suzuka.mie.jp -tado.mie.jp -taiki.mie.jp -taki.mie.jp -tamaki.mie.jp -toba.mie.jp -tsu.mie.jp -udono.mie.jp -ureshino.mie.jp -watarai.mie.jp -yokkaichi.mie.jp -furukawa.miyagi.jp -higashimatsushima.miyagi.jp -ishinomaki.miyagi.jp -iwanuma.miyagi.jp -kakuda.miyagi.jp -kami.miyagi.jp -kawasaki.miyagi.jp -marumori.miyagi.jp -matsushima.miyagi.jp -minamisanriku.miyagi.jp -misato.miyagi.jp -murata.miyagi.jp -natori.miyagi.jp -ogawara.miyagi.jp -ohira.miyagi.jp -onagawa.miyagi.jp -osaki.miyagi.jp -rifu.miyagi.jp -semine.miyagi.jp -shibata.miyagi.jp -shichikashuku.miyagi.jp -shikama.miyagi.jp -shiogama.miyagi.jp -shiroishi.miyagi.jp -tagajo.miyagi.jp -taiwa.miyagi.jp -tome.miyagi.jp -tomiya.miyagi.jp -wakuya.miyagi.jp -watari.miyagi.jp -yamamoto.miyagi.jp -zao.miyagi.jp -aya.miyazaki.jp -ebino.miyazaki.jp -gokase.miyazaki.jp -hyuga.miyazaki.jp -kadogawa.miyazaki.jp -kawaminami.miyazaki.jp -kijo.miyazaki.jp -kitagawa.miyazaki.jp -kitakata.miyazaki.jp -kitaura.miyazaki.jp -kobayashi.miyazaki.jp -kunitomi.miyazaki.jp -kushima.miyazaki.jp -mimata.miyazaki.jp -miyakonojo.miyazaki.jp -miyazaki.miyazaki.jp -morotsuka.miyazaki.jp -nichinan.miyazaki.jp -nishimera.miyazaki.jp -nobeoka.miyazaki.jp -saito.miyazaki.jp -shiiba.miyazaki.jp -shintomi.miyazaki.jp -takaharu.miyazaki.jp -takanabe.miyazaki.jp -takazaki.miyazaki.jp -tsuno.miyazaki.jp -achi.nagano.jp -agematsu.nagano.jp -anan.nagano.jp -aoki.nagano.jp -asahi.nagano.jp -azumino.nagano.jp -chikuhoku.nagano.jp -chikuma.nagano.jp -chino.nagano.jp -fujimi.nagano.jp -hakuba.nagano.jp -hara.nagano.jp -hiraya.nagano.jp -iida.nagano.jp -iijima.nagano.jp -iiyama.nagano.jp -iizuna.nagano.jp -ikeda.nagano.jp -ikusaka.nagano.jp -ina.nagano.jp -karuizawa.nagano.jp -kawakami.nagano.jp -kiso.nagano.jp -kisofukushima.nagano.jp -kitaaiki.nagano.jp -komagane.nagano.jp -komoro.nagano.jp -matsukawa.nagano.jp -matsumoto.nagano.jp -miasa.nagano.jp -minamiaiki.nagano.jp -minamimaki.nagano.jp -minamiminowa.nagano.jp -minowa.nagano.jp -miyada.nagano.jp -miyota.nagano.jp -mochizuki.nagano.jp -nagano.nagano.jp -nagawa.nagano.jp -nagiso.nagano.jp -nakagawa.nagano.jp -nakano.nagano.jp -nozawaonsen.nagano.jp -obuse.nagano.jp -ogawa.nagano.jp -okaya.nagano.jp -omachi.nagano.jp -omi.nagano.jp -ookuwa.nagano.jp -ooshika.nagano.jp -otaki.nagano.jp -otari.nagano.jp -sakae.nagano.jp -sakaki.nagano.jp -saku.nagano.jp -sakuho.nagano.jp -shimosuwa.nagano.jp -shinanomachi.nagano.jp -shiojiri.nagano.jp -suwa.nagano.jp -suzaka.nagano.jp -takagi.nagano.jp -takamori.nagano.jp -takayama.nagano.jp -tateshina.nagano.jp -tatsuno.nagano.jp -togakushi.nagano.jp -togura.nagano.jp -tomi.nagano.jp -ueda.nagano.jp -wada.nagano.jp -yamagata.nagano.jp -yamanouchi.nagano.jp -yasaka.nagano.jp -yasuoka.nagano.jp -chijiwa.nagasaki.jp -futsu.nagasaki.jp -goto.nagasaki.jp -hasami.nagasaki.jp -hirado.nagasaki.jp -iki.nagasaki.jp -isahaya.nagasaki.jp -kawatana.nagasaki.jp -kuchinotsu.nagasaki.jp -matsuura.nagasaki.jp -nagasaki.nagasaki.jp -obama.nagasaki.jp -omura.nagasaki.jp -oseto.nagasaki.jp -saikai.nagasaki.jp -sasebo.nagasaki.jp -seihi.nagasaki.jp -shimabara.nagasaki.jp -shinkamigoto.nagasaki.jp -togitsu.nagasaki.jp -tsushima.nagasaki.jp -unzen.nagasaki.jp -ando.nara.jp -gose.nara.jp -heguri.nara.jp -higashiyoshino.nara.jp -ikaruga.nara.jp -ikoma.nara.jp -kamikitayama.nara.jp -kanmaki.nara.jp -kashiba.nara.jp -kashihara.nara.jp -katsuragi.nara.jp -kawai.nara.jp -kawakami.nara.jp -kawanishi.nara.jp -koryo.nara.jp -kurotaki.nara.jp -mitsue.nara.jp -miyake.nara.jp -nara.nara.jp -nosegawa.nara.jp -oji.nara.jp -ouda.nara.jp -oyodo.nara.jp -sakurai.nara.jp -sango.nara.jp -shimoichi.nara.jp -shimokitayama.nara.jp -shinjo.nara.jp -soni.nara.jp -takatori.nara.jp -tawaramoto.nara.jp -tenkawa.nara.jp -tenri.nara.jp -uda.nara.jp -yamatokoriyama.nara.jp -yamatotakada.nara.jp -yamazoe.nara.jp -yoshino.nara.jp -aga.niigata.jp -agano.niigata.jp -gosen.niigata.jp -itoigawa.niigata.jp -izumozaki.niigata.jp -joetsu.niigata.jp -kamo.niigata.jp -kariwa.niigata.jp -kashiwazaki.niigata.jp -minamiuonuma.niigata.jp -mitsuke.niigata.jp -muika.niigata.jp -murakami.niigata.jp -myoko.niigata.jp -nagaoka.niigata.jp -niigata.niigata.jp -ojiya.niigata.jp -omi.niigata.jp -sado.niigata.jp -sanjo.niigata.jp -seiro.niigata.jp -seirou.niigata.jp -sekikawa.niigata.jp -shibata.niigata.jp -tagami.niigata.jp -tainai.niigata.jp -tochio.niigata.jp -tokamachi.niigata.jp -tsubame.niigata.jp -tsunan.niigata.jp -uonuma.niigata.jp -yahiko.niigata.jp -yoita.niigata.jp -yuzawa.niigata.jp -beppu.oita.jp -bungoono.oita.jp -bungotakada.oita.jp -hasama.oita.jp -hiji.oita.jp -himeshima.oita.jp -hita.oita.jp -kamitsue.oita.jp -kokonoe.oita.jp -kuju.oita.jp -kunisaki.oita.jp -kusu.oita.jp -oita.oita.jp -saiki.oita.jp -taketa.oita.jp -tsukumi.oita.jp -usa.oita.jp -usuki.oita.jp -yufu.oita.jp -akaiwa.okayama.jp -asakuchi.okayama.jp -bizen.okayama.jp -hayashima.okayama.jp -ibara.okayama.jp -kagamino.okayama.jp -kasaoka.okayama.jp -kibichuo.okayama.jp -kumenan.okayama.jp -kurashiki.okayama.jp -maniwa.okayama.jp -misaki.okayama.jp -nagi.okayama.jp -niimi.okayama.jp -nishiawakura.okayama.jp -okayama.okayama.jp -satosho.okayama.jp -setouchi.okayama.jp -shinjo.okayama.jp -shoo.okayama.jp -soja.okayama.jp -takahashi.okayama.jp -tamano.okayama.jp -tsuyama.okayama.jp -wake.okayama.jp -yakage.okayama.jp -aguni.okinawa.jp -ginowan.okinawa.jp -ginoza.okinawa.jp -gushikami.okinawa.jp -haebaru.okinawa.jp -higashi.okinawa.jp -hirara.okinawa.jp -iheya.okinawa.jp -ishigaki.okinawa.jp -ishikawa.okinawa.jp -itoman.okinawa.jp -izena.okinawa.jp -kadena.okinawa.jp -kin.okinawa.jp -kitadaito.okinawa.jp -kitanakagusuku.okinawa.jp -kumejima.okinawa.jp -kunigami.okinawa.jp -minamidaito.okinawa.jp -motobu.okinawa.jp -nago.okinawa.jp -naha.okinawa.jp -nakagusuku.okinawa.jp -nakijin.okinawa.jp -nanjo.okinawa.jp -nishihara.okinawa.jp -ogimi.okinawa.jp -okinawa.okinawa.jp -onna.okinawa.jp -shimoji.okinawa.jp -taketomi.okinawa.jp -tarama.okinawa.jp -tokashiki.okinawa.jp -tomigusuku.okinawa.jp -tonaki.okinawa.jp -urasoe.okinawa.jp -uruma.okinawa.jp -yaese.okinawa.jp -yomitan.okinawa.jp -yonabaru.okinawa.jp -yonaguni.okinawa.jp -zamami.okinawa.jp -abeno.osaka.jp -chihayaakasaka.osaka.jp -chuo.osaka.jp -daito.osaka.jp -fujiidera.osaka.jp -habikino.osaka.jp -hannan.osaka.jp -higashiosaka.osaka.jp -higashisumiyoshi.osaka.jp -higashiyodogawa.osaka.jp -hirakata.osaka.jp -ibaraki.osaka.jp -ikeda.osaka.jp -izumi.osaka.jp -izumiotsu.osaka.jp -izumisano.osaka.jp -kadoma.osaka.jp -kaizuka.osaka.jp -kanan.osaka.jp -kashiwara.osaka.jp -katano.osaka.jp -kawachinagano.osaka.jp -kishiwada.osaka.jp -kita.osaka.jp -kumatori.osaka.jp -matsubara.osaka.jp -minato.osaka.jp -minoh.osaka.jp -misaki.osaka.jp -moriguchi.osaka.jp -neyagawa.osaka.jp -nishi.osaka.jp -nose.osaka.jp -osakasayama.osaka.jp -sakai.osaka.jp -sayama.osaka.jp -sennan.osaka.jp -settsu.osaka.jp -shijonawate.osaka.jp -shimamoto.osaka.jp -suita.osaka.jp -tadaoka.osaka.jp -taishi.osaka.jp -tajiri.osaka.jp -takaishi.osaka.jp -takatsuki.osaka.jp -tondabayashi.osaka.jp -toyonaka.osaka.jp -toyono.osaka.jp -yao.osaka.jp -ariake.saga.jp -arita.saga.jp -fukudomi.saga.jp -genkai.saga.jp -hamatama.saga.jp -hizen.saga.jp -imari.saga.jp -kamimine.saga.jp -kanzaki.saga.jp -karatsu.saga.jp -kashima.saga.jp -kitagata.saga.jp -kitahata.saga.jp -kiyama.saga.jp -kouhoku.saga.jp -kyuragi.saga.jp -nishiarita.saga.jp -ogi.saga.jp -omachi.saga.jp -ouchi.saga.jp -saga.saga.jp -shiroishi.saga.jp -taku.saga.jp -tara.saga.jp -tosu.saga.jp -yoshinogari.saga.jp -arakawa.saitama.jp -asaka.saitama.jp -chichibu.saitama.jp -fujimi.saitama.jp -fujimino.saitama.jp -fukaya.saitama.jp -hanno.saitama.jp -hanyu.saitama.jp -hasuda.saitama.jp -hatogaya.saitama.jp -hatoyama.saitama.jp -hidaka.saitama.jp -higashichichibu.saitama.jp -higashimatsuyama.saitama.jp -honjo.saitama.jp -ina.saitama.jp -iruma.saitama.jp -iwatsuki.saitama.jp -kamiizumi.saitama.jp -kamikawa.saitama.jp -kamisato.saitama.jp -kasukabe.saitama.jp -kawagoe.saitama.jp -kawaguchi.saitama.jp -kawajima.saitama.jp -kazo.saitama.jp -kitamoto.saitama.jp -koshigaya.saitama.jp -kounosu.saitama.jp -kuki.saitama.jp -kumagaya.saitama.jp -matsubushi.saitama.jp -minano.saitama.jp -misato.saitama.jp -miyashiro.saitama.jp -miyoshi.saitama.jp -moroyama.saitama.jp -nagatoro.saitama.jp -namegawa.saitama.jp -niiza.saitama.jp -ogano.saitama.jp -ogawa.saitama.jp -ogose.saitama.jp -okegawa.saitama.jp -omiya.saitama.jp -otaki.saitama.jp -ranzan.saitama.jp -ryokami.saitama.jp -saitama.saitama.jp -sakado.saitama.jp -satte.saitama.jp -sayama.saitama.jp -shiki.saitama.jp -shiraoka.saitama.jp -soka.saitama.jp -sugito.saitama.jp -toda.saitama.jp -tokigawa.saitama.jp -tokorozawa.saitama.jp -tsurugashima.saitama.jp -urawa.saitama.jp -warabi.saitama.jp -yashio.saitama.jp -yokoze.saitama.jp -yono.saitama.jp -yorii.saitama.jp -yoshida.saitama.jp -yoshikawa.saitama.jp -yoshimi.saitama.jp -aisho.shiga.jp -gamo.shiga.jp -higashiomi.shiga.jp -hikone.shiga.jp -koka.shiga.jp -konan.shiga.jp -kosei.shiga.jp -koto.shiga.jp -kusatsu.shiga.jp -maibara.shiga.jp -moriyama.shiga.jp -nagahama.shiga.jp -nishiazai.shiga.jp -notogawa.shiga.jp -omihachiman.shiga.jp -otsu.shiga.jp -ritto.shiga.jp -ryuoh.shiga.jp -takashima.shiga.jp -takatsuki.shiga.jp -torahime.shiga.jp -toyosato.shiga.jp -yasu.shiga.jp -akagi.shimane.jp -ama.shimane.jp -gotsu.shimane.jp -hamada.shimane.jp -higashiizumo.shimane.jp -hikawa.shimane.jp -hikimi.shimane.jp -izumo.shimane.jp -kakinoki.shimane.jp -masuda.shimane.jp -matsue.shimane.jp -misato.shimane.jp -nishinoshima.shimane.jp -ohda.shimane.jp -okinoshima.shimane.jp -okuizumo.shimane.jp -shimane.shimane.jp -tamayu.shimane.jp -tsuwano.shimane.jp -unnan.shimane.jp -yakumo.shimane.jp -yasugi.shimane.jp -yatsuka.shimane.jp -arai.shizuoka.jp -atami.shizuoka.jp -fuji.shizuoka.jp -fujieda.shizuoka.jp -fujikawa.shizuoka.jp -fujinomiya.shizuoka.jp -fukuroi.shizuoka.jp -gotemba.shizuoka.jp -haibara.shizuoka.jp -hamamatsu.shizuoka.jp -higashiizu.shizuoka.jp -ito.shizuoka.jp -iwata.shizuoka.jp -izu.shizuoka.jp -izunokuni.shizuoka.jp -kakegawa.shizuoka.jp -kannami.shizuoka.jp -kawanehon.shizuoka.jp -kawazu.shizuoka.jp -kikugawa.shizuoka.jp -kosai.shizuoka.jp -makinohara.shizuoka.jp -matsuzaki.shizuoka.jp -minamiizu.shizuoka.jp -mishima.shizuoka.jp -morimachi.shizuoka.jp -nishiizu.shizuoka.jp -numazu.shizuoka.jp -omaezaki.shizuoka.jp -shimada.shizuoka.jp -shimizu.shizuoka.jp -shimoda.shizuoka.jp -shizuoka.shizuoka.jp -susono.shizuoka.jp -yaizu.shizuoka.jp -yoshida.shizuoka.jp -ashikaga.tochigi.jp -bato.tochigi.jp -haga.tochigi.jp -ichikai.tochigi.jp -iwafune.tochigi.jp -kaminokawa.tochigi.jp -kanuma.tochigi.jp -karasuyama.tochigi.jp -kuroiso.tochigi.jp -mashiko.tochigi.jp -mibu.tochigi.jp -moka.tochigi.jp -motegi.tochigi.jp -nasu.tochigi.jp -nasushiobara.tochigi.jp -nikko.tochigi.jp -nishikata.tochigi.jp -nogi.tochigi.jp -ohira.tochigi.jp -ohtawara.tochigi.jp -oyama.tochigi.jp -sakura.tochigi.jp -sano.tochigi.jp -shimotsuke.tochigi.jp -shioya.tochigi.jp -takanezawa.tochigi.jp -tochigi.tochigi.jp -tsuga.tochigi.jp -ujiie.tochigi.jp -utsunomiya.tochigi.jp -yaita.tochigi.jp -aizumi.tokushima.jp -anan.tokushima.jp -ichiba.tokushima.jp -itano.tokushima.jp -kainan.tokushima.jp -komatsushima.tokushima.jp -matsushige.tokushima.jp -mima.tokushima.jp -minami.tokushima.jp -miyoshi.tokushima.jp -mugi.tokushima.jp -nakagawa.tokushima.jp -naruto.tokushima.jp -sanagochi.tokushima.jp -shishikui.tokushima.jp -tokushima.tokushima.jp -wajiki.tokushima.jp -adachi.tokyo.jp -akiruno.tokyo.jp -akishima.tokyo.jp -aogashima.tokyo.jp -arakawa.tokyo.jp -bunkyo.tokyo.jp -chiyoda.tokyo.jp -chofu.tokyo.jp -chuo.tokyo.jp -edogawa.tokyo.jp -fuchu.tokyo.jp -fussa.tokyo.jp -hachijo.tokyo.jp -hachioji.tokyo.jp -hamura.tokyo.jp -higashikurume.tokyo.jp -higashimurayama.tokyo.jp -higashiyamato.tokyo.jp -hino.tokyo.jp -hinode.tokyo.jp -hinohara.tokyo.jp -inagi.tokyo.jp -itabashi.tokyo.jp -katsushika.tokyo.jp -kita.tokyo.jp -kiyose.tokyo.jp -kodaira.tokyo.jp -koganei.tokyo.jp -kokubunji.tokyo.jp -komae.tokyo.jp -koto.tokyo.jp -kouzushima.tokyo.jp -kunitachi.tokyo.jp -machida.tokyo.jp -meguro.tokyo.jp -minato.tokyo.jp -mitaka.tokyo.jp -mizuho.tokyo.jp -musashimurayama.tokyo.jp -musashino.tokyo.jp -nakano.tokyo.jp -nerima.tokyo.jp -ogasawara.tokyo.jp -okutama.tokyo.jp -ome.tokyo.jp -oshima.tokyo.jp -ota.tokyo.jp -setagaya.tokyo.jp -shibuya.tokyo.jp -shinagawa.tokyo.jp -shinjuku.tokyo.jp -suginami.tokyo.jp -sumida.tokyo.jp -tachikawa.tokyo.jp -taito.tokyo.jp -tama.tokyo.jp -toshima.tokyo.jp -chizu.tottori.jp -hino.tottori.jp -kawahara.tottori.jp -koge.tottori.jp -kotoura.tottori.jp -misasa.tottori.jp -nanbu.tottori.jp -nichinan.tottori.jp -sakaiminato.tottori.jp -tottori.tottori.jp -wakasa.tottori.jp -yazu.tottori.jp -yonago.tottori.jp -asahi.toyama.jp -fuchu.toyama.jp -fukumitsu.toyama.jp -funahashi.toyama.jp -himi.toyama.jp -imizu.toyama.jp -inami.toyama.jp -johana.toyama.jp -kamiichi.toyama.jp -kurobe.toyama.jp -nakaniikawa.toyama.jp -namerikawa.toyama.jp -nanto.toyama.jp -nyuzen.toyama.jp -oyabe.toyama.jp -taira.toyama.jp -takaoka.toyama.jp -tateyama.toyama.jp -toga.toyama.jp -tonami.toyama.jp -toyama.toyama.jp -unazuki.toyama.jp -uozu.toyama.jp -yamada.toyama.jp -arida.wakayama.jp -aridagawa.wakayama.jp -gobo.wakayama.jp -hashimoto.wakayama.jp -hidaka.wakayama.jp -hirogawa.wakayama.jp -inami.wakayama.jp -iwade.wakayama.jp -kainan.wakayama.jp -kamitonda.wakayama.jp -katsuragi.wakayama.jp -kimino.wakayama.jp -kinokawa.wakayama.jp -kitayama.wakayama.jp -koya.wakayama.jp -koza.wakayama.jp -kozagawa.wakayama.jp -kudoyama.wakayama.jp -kushimoto.wakayama.jp -mihama.wakayama.jp -misato.wakayama.jp -nachikatsuura.wakayama.jp -shingu.wakayama.jp -shirahama.wakayama.jp -taiji.wakayama.jp -tanabe.wakayama.jp -wakayama.wakayama.jp -yuasa.wakayama.jp -yura.wakayama.jp -asahi.yamagata.jp -funagata.yamagata.jp -higashine.yamagata.jp -iide.yamagata.jp -kahoku.yamagata.jp -kaminoyama.yamagata.jp -kaneyama.yamagata.jp -kawanishi.yamagata.jp -mamurogawa.yamagata.jp -mikawa.yamagata.jp -murayama.yamagata.jp -nagai.yamagata.jp -nakayama.yamagata.jp -nanyo.yamagata.jp -nishikawa.yamagata.jp -obanazawa.yamagata.jp -oe.yamagata.jp -oguni.yamagata.jp -ohkura.yamagata.jp -oishida.yamagata.jp -sagae.yamagata.jp -sakata.yamagata.jp -sakegawa.yamagata.jp -shinjo.yamagata.jp -shirataka.yamagata.jp -shonai.yamagata.jp -takahata.yamagata.jp -tendo.yamagata.jp -tozawa.yamagata.jp -tsuruoka.yamagata.jp -yamagata.yamagata.jp -yamanobe.yamagata.jp -yonezawa.yamagata.jp -yuza.yamagata.jp -abu.yamaguchi.jp -hagi.yamaguchi.jp -hikari.yamaguchi.jp -hofu.yamaguchi.jp -iwakuni.yamaguchi.jp -kudamatsu.yamaguchi.jp -mitou.yamaguchi.jp -nagato.yamaguchi.jp -oshima.yamaguchi.jp -shimonoseki.yamaguchi.jp -shunan.yamaguchi.jp -tabuse.yamaguchi.jp -tokuyama.yamaguchi.jp -toyota.yamaguchi.jp -ube.yamaguchi.jp -yuu.yamaguchi.jp -chuo.yamanashi.jp -doshi.yamanashi.jp -fuefuki.yamanashi.jp -fujikawa.yamanashi.jp -fujikawaguchiko.yamanashi.jp -fujiyoshida.yamanashi.jp -hayakawa.yamanashi.jp -hokuto.yamanashi.jp -ichikawamisato.yamanashi.jp -kai.yamanashi.jp -kofu.yamanashi.jp -koshu.yamanashi.jp -kosuge.yamanashi.jp -minami-alps.yamanashi.jp -minobu.yamanashi.jp -nakamichi.yamanashi.jp -nanbu.yamanashi.jp -narusawa.yamanashi.jp -nirasaki.yamanashi.jp -nishikatsura.yamanashi.jp -oshino.yamanashi.jp -otsuki.yamanashi.jp -showa.yamanashi.jp -tabayama.yamanashi.jp -tsuru.yamanashi.jp -uenohara.yamanashi.jp -yamanakako.yamanashi.jp -yamanashi.yamanashi.jp - -// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains -ke -ac.ke -co.ke -go.ke -info.ke -me.ke -mobi.ke -ne.ke -or.ke -sc.ke - -// kg : http://www.domain.kg/dmn_n.html -kg -com.kg -edu.kg -gov.kg -mil.kg -net.kg -org.kg - -// kh : https://trc.gov.kh -// Submitted by khnic@trc.gov.kh -kh -com.kh -edu.kh -gov.kh -net.kh -org.kh - -// ki : https://www.iana.org/domains/root/db/ki.html -ki -biz.ki -com.ki -edu.ki -gov.ki -info.ki -net.ki -org.ki - -// km : https://www.iana.org/domains/root/db/km.html -// http://www.domaine.km/documents/charte.doc -km -ass.km -com.km -edu.km -gov.km -mil.km -nom.km -org.km -prd.km -tm.km -// These are only mentioned as proposed suggestions at domaine.km, but -// https://www.iana.org/domains/root/db/km.html says they're available for registration: -asso.km -coop.km -gouv.km -medecin.km -notaires.km -pharmaciens.km -presse.km -veterinaire.km - -// kn : https://www.iana.org/domains/root/db/kn.html -// http://www.dot.kn/domainRules.html -kn -edu.kn -gov.kn -net.kn -org.kn - -// kp : http://www.kcce.kp/en_index.php -kp -com.kp -edu.kp -gov.kp -org.kp -rep.kp -tra.kp - -// kr : https://www.iana.org/domains/root/db/kr.html -// see also: https://krnic.kisa.or.kr/jsp/infoboard/law/domBylawsReg.jsp -kr -ac.kr -ai.kr -co.kr -es.kr -go.kr -hs.kr -io.kr -it.kr -kg.kr -me.kr -mil.kr -ms.kr -ne.kr -or.kr -pe.kr -re.kr -sc.kr -// kr geographical names -busan.kr -chungbuk.kr -chungnam.kr -daegu.kr -daejeon.kr -gangwon.kr -gwangju.kr -gyeongbuk.kr -gyeonggi.kr -gyeongnam.kr -incheon.kr -jeju.kr -jeonbuk.kr -jeonnam.kr -seoul.kr -ulsan.kr - -// kw : https://www.nic.kw/policies/ -// Confirmed by registry -kw -com.kw -edu.kw -emb.kw -gov.kw -ind.kw -net.kw -org.kw - -// ky : http://www.icta.ky/da_ky_reg_dom.php -// Confirmed by registry 2008-06-17 -ky -com.ky -edu.ky -net.ky -org.ky - -// kz : https://www.iana.org/domains/root/db/kz.html -// see also: http://www.nic.kz/rules/index.jsp -kz -com.kz -edu.kz -gov.kz -mil.kz -net.kz -org.kz - -// la : https://www.iana.org/domains/root/db/la.html -// Submitted by registry -la -com.la -edu.la -gov.la -info.la -int.la -net.la -org.la -per.la - -// lb : https://www.iana.org/domains/root/db/lb.html -// Submitted by registry -lb -com.lb -edu.lb -gov.lb -net.lb -org.lb - -// lc : https://www.iana.org/domains/root/db/lc.html -// see also: http://www.nic.lc/rules.htm -lc -co.lc -com.lc -edu.lc -gov.lc -net.lc -org.lc - -// li : https://www.iana.org/domains/root/db/li.html -li - -// lk : https://www.iana.org/domains/root/db/lk.html -lk -ac.lk -assn.lk -com.lk -edu.lk -gov.lk -grp.lk -hotel.lk -int.lk -ltd.lk -net.lk -ngo.lk -org.lk -sch.lk -soc.lk -web.lk - -// lr : http://psg.com/dns/lr/lr.txt -// Submitted by registry -lr -com.lr -edu.lr -gov.lr -net.lr -org.lr - -// ls : http://www.nic.ls/ -// Confirmed by registry -ls -ac.ls -biz.ls -co.ls -edu.ls -gov.ls -info.ls -net.ls -org.ls -sc.ls - -// lt : https://www.iana.org/domains/root/db/lt.html -lt -// gov.lt : http://www.gov.lt/index_en.php -gov.lt - -// lu : http://www.dns.lu/en/ -lu - -// lv : https://www.iana.org/domains/root/db/lv.html -lv -asn.lv -com.lv -conf.lv -edu.lv -gov.lv -id.lv -mil.lv -net.lv -org.lv - -// ly : http://www.nic.ly/regulations.php -ly -com.ly -edu.ly -gov.ly -id.ly -med.ly -net.ly -org.ly -plc.ly -sch.ly - -// ma : https://www.iana.org/domains/root/db/ma.html -// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf -ma -ac.ma -co.ma -gov.ma -net.ma -org.ma -press.ma - -// mc : http://www.nic.mc/ -mc -asso.mc -tm.mc - -// md : https://www.iana.org/domains/root/db/md.html -md - -// me : https://www.iana.org/domains/root/db/me.html -me -ac.me -co.me -edu.me -gov.me -its.me -net.me -org.me -priv.me - -// mg : https://nic.mg -mg -co.mg -com.mg -edu.mg -gov.mg -mil.mg -nom.mg -org.mg -prd.mg - -// mh : https://www.iana.org/domains/root/db/mh.html -mh - -// mil : https://www.iana.org/domains/root/db/mil.html -mil - -// mk : https://www.iana.org/domains/root/db/mk.html -// see also: http://dns.marnet.net.mk/postapka.php -mk -com.mk -edu.mk -gov.mk -inf.mk -name.mk -net.mk -org.mk - -// ml : https://www.iana.org/domains/root/db/ml.html -// Confirmed by Boubacar NDIAYE 2024-12-31 -ml -ac.ml -art.ml -asso.ml -com.ml -edu.ml -gouv.ml -gov.ml -info.ml -inst.ml -net.ml -org.ml -pr.ml -presse.ml - -// mm : https://www.iana.org/domains/root/db/mm.html -*.mm - -// mn : https://www.iana.org/domains/root/db/mn.html -mn -edu.mn -gov.mn -org.mn - -// mo : http://www.monic.net.mo/ -mo -com.mo -edu.mo -gov.mo -net.mo -org.mo - -// mobi : https://www.iana.org/domains/root/db/mobi.html -mobi - -// mp : http://www.dot.mp/ -// Confirmed by registry 2008-06-17 -mp - -// mq : https://www.iana.org/domains/root/db/mq.html -mq - -// mr : https://www.iana.org/domains/root/db/mr.html -mr -gov.mr - -// ms : https://www.iana.org/domains/root/db/ms.html -ms -com.ms -edu.ms -gov.ms -net.ms -org.ms - -// mt : https://www.nic.org.mt/go/policy -// Submitted by registry -mt -com.mt -edu.mt -net.mt -org.mt - -// mu : https://www.iana.org/domains/root/db/mu.html -mu -ac.mu -co.mu -com.mu -gov.mu -net.mu -or.mu -org.mu - -// museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/ -museum - -// mv : https://www.iana.org/domains/root/db/mv.html -// "mv" included because, contra Wikipedia, google.mv exists. -mv -aero.mv -biz.mv -com.mv -coop.mv -edu.mv -gov.mv -info.mv -int.mv -mil.mv -museum.mv -name.mv -net.mv -org.mv -pro.mv - -// mw : http://www.registrar.mw/ -mw -ac.mw -biz.mw -co.mw -com.mw -coop.mw -edu.mw -gov.mw -int.mw -net.mw -org.mw - -// mx : http://www.nic.mx/ -// Submitted by registry -mx -com.mx -edu.mx -gob.mx -net.mx -org.mx - -// my : http://www.mynic.my/ -// Available strings: https://mynic.my/resources/domains/buying-a-domain/ -my -biz.my -com.my -edu.my -gov.my -mil.my -name.my -net.my -org.my - -// mz : http://www.uem.mz/ -// Submitted by registry -mz -ac.mz -adv.mz -co.mz -edu.mz -gov.mz -mil.mz -net.mz -org.mz - -// na : http://www.na-nic.com.na/ -na -alt.na -co.na -com.na -gov.na -net.na -org.na - -// name : http://www.nic.name/ -// Regarding 2LDs: https://github.com/publicsuffix/list/issues/2306 -name - -// nc : http://www.cctld.nc/ -nc -asso.nc -nom.nc - -// ne : https://www.iana.org/domains/root/db/ne.html -ne - -// net : https://www.iana.org/domains/root/db/net.html -net - -// nf : https://www.iana.org/domains/root/db/nf.html -nf -arts.nf -com.nf -firm.nf -info.nf -net.nf -other.nf -per.nf -rec.nf -store.nf -web.nf - -// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds -ng -com.ng -edu.ng -gov.ng -i.ng -mil.ng -mobi.ng -name.ng -net.ng -org.ng -sch.ng - -// ni : http://www.nic.ni/ -ni -ac.ni -biz.ni -co.ni -com.ni -edu.ni -gob.ni -in.ni -info.ni -int.ni -mil.ni -net.ni -nom.ni -org.ni -web.ni - -// nl : https://www.iana.org/domains/root/db/nl.html -// https://www.sidn.nl/ -nl - -// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ -// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ -// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ -// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ -// RSS feed: https://teknisk.norid.no/en/feed/ -no -// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ -fhs.no -folkebibl.no -fylkesbibl.no -gielda.no -herad.no -idrett.no -kommune.no -museum.no -priv.no -suohkan.no -tjielte.no -uenorge.no -vgs.no -// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ -dep.no -mil.no -stat.no -// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ -// counties -aa.no -ah.no -bu.no -fm.no -hl.no -hm.no -jan-mayen.no -mr.no -nl.no -nt.no -of.no -ol.no -oslo.no -rl.no -sf.no -st.no -svalbard.no -tm.no -tr.no -va.no -vf.no -// primary and lower secondary schools per county -gs.aa.no -gs.ah.no -gs.bu.no -gs.fm.no -gs.hl.no -gs.hm.no -gs.jan-mayen.no -gs.mr.no -gs.nl.no -gs.nt.no -gs.of.no -gs.ol.no -gs.oslo.no -gs.rl.no -gs.sf.no -gs.st.no -gs.svalbard.no -gs.tm.no -gs.tr.no -gs.va.no -gs.vf.no -// cities -akrehamn.no -åkrehamn.no -algard.no -ålgård.no -arna.no -bronnoysund.no -brønnøysund.no -brumunddal.no -bryne.no -drobak.no -drøbak.no -egersund.no -fetsund.no -floro.no -florø.no -fredrikstad.no -hokksund.no -honefoss.no -hønefoss.no -jessheim.no -jorpeland.no -jørpeland.no -kirkenes.no -kopervik.no -krokstadelva.no -langevag.no -langevåg.no -leirvik.no -mjondalen.no -mjøndalen.no -mo-i-rana.no -mosjoen.no -mosjøen.no -nesoddtangen.no -orkanger.no -osoyro.no -osøyro.no -raholt.no -råholt.no -sandnessjoen.no -sandnessjøen.no -skedsmokorset.no -slattum.no -spjelkavik.no -stathelle.no -stavern.no -stjordalshalsen.no -stjørdalshalsen.no -tananger.no -tranby.no -vossevangen.no -// communities -aarborte.no -aejrie.no -afjord.no -åfjord.no -agdenes.no -nes.akershus.no -aknoluokta.no -ákŋoluokta.no -al.no -ål.no -alaheadju.no -álaheadju.no -alesund.no -ålesund.no -alstahaug.no -alta.no -áltá.no -alvdal.no -amli.no -åmli.no -amot.no -åmot.no -andasuolo.no -andebu.no -andoy.no -andøy.no -ardal.no -årdal.no -aremark.no -arendal.no -ås.no -aseral.no -åseral.no -asker.no -askim.no -askoy.no -askøy.no -askvoll.no -asnes.no -åsnes.no -audnedal.no -aukra.no -aure.no -aurland.no -aurskog-holand.no -aurskog-høland.no -austevoll.no -austrheim.no -averoy.no -averøy.no -badaddja.no -bådåddjå.no -bærum.no -bahcavuotna.no -báhcavuotna.no -bahccavuotna.no -báhccavuotna.no -baidar.no -báidár.no -bajddar.no -bájddar.no -balat.no -bálát.no -balestrand.no -ballangen.no -balsfjord.no -bamble.no -bardu.no -barum.no -batsfjord.no -båtsfjord.no -bearalvahki.no -bearalváhki.no -beardu.no -beiarn.no -berg.no -bergen.no -berlevag.no -berlevåg.no -bievat.no -bievát.no -bindal.no -birkenes.no -bjerkreim.no -bjugn.no -bodo.no -bodø.no -bokn.no -bomlo.no -bømlo.no -bremanger.no -bronnoy.no -brønnøy.no -budejju.no -nes.buskerud.no -bygland.no -bykle.no -cahcesuolo.no -čáhcesuolo.no -davvenjarga.no -davvenjárga.no -davvesiida.no -deatnu.no -dielddanuorri.no -divtasvuodna.no -divttasvuotna.no -donna.no -dønna.no -dovre.no -drammen.no -drangedal.no -dyroy.no -dyrøy.no -eid.no -eidfjord.no -eidsberg.no -eidskog.no -eidsvoll.no -eigersund.no -elverum.no -enebakk.no -engerdal.no -etne.no -etnedal.no -evenassi.no -evenášši.no -evenes.no -evje-og-hornnes.no -farsund.no -fauske.no -fedje.no -fet.no -finnoy.no -finnøy.no -fitjar.no -fjaler.no -fjell.no -fla.no -flå.no -flakstad.no -flatanger.no -flekkefjord.no -flesberg.no -flora.no -folldal.no -forde.no -førde.no -forsand.no -fosnes.no -fræna.no -frana.no -frogn.no -froland.no -frosta.no -froya.no -frøya.no -fuoisku.no -fuossko.no -fusa.no -fyresdal.no -gaivuotna.no -gáivuotna.no -galsa.no -gálsá.no -gamvik.no -gangaviika.no -gáŋgaviika.no -gaular.no -gausdal.no -giehtavuoatna.no -gildeskal.no -gildeskål.no -giske.no -gjemnes.no -gjerdrum.no -gjerstad.no -gjesdal.no -gjovik.no -gjøvik.no -gloppen.no -gol.no -gran.no -grane.no -granvin.no -gratangen.no -grimstad.no -grong.no -grue.no -gulen.no -guovdageaidnu.no -ha.no -hå.no -habmer.no -hábmer.no -hadsel.no -hægebostad.no -hagebostad.no -halden.no -halsa.no -hamar.no -hamaroy.no -hamarøy.no -hammarfeasta.no -hámmárfeasta.no -hammerfest.no -hapmir.no -hápmir.no -haram.no -hareid.no -harstad.no -hasvik.no -hattfjelldal.no -haugesund.no -os.hedmark.no -valer.hedmark.no -våler.hedmark.no -hemne.no -hemnes.no -hemsedal.no -hitra.no -hjartdal.no -hjelmeland.no -hobol.no -hobøl.no -hof.no -hol.no -hole.no -holmestrand.no -holtalen.no -holtålen.no -os.hordaland.no -hornindal.no -horten.no -hoyanger.no -høyanger.no -hoylandet.no -høylandet.no -hurdal.no -hurum.no -hvaler.no -hyllestad.no -ibestad.no -inderoy.no -inderøy.no -iveland.no -ivgu.no -jevnaker.no -jolster.no -jølster.no -jondal.no -kafjord.no -kåfjord.no -karasjohka.no -kárášjohka.no -karasjok.no -karlsoy.no -karlsøy.no -karmoy.no -karmøy.no -kautokeino.no -klabu.no -klæbu.no -klepp.no -kongsberg.no -kongsvinger.no -kraanghke.no -kråanghke.no -kragero.no -kragerø.no -kristiansand.no -kristiansund.no -krodsherad.no -krødsherad.no -kvæfjord.no -kvænangen.no -kvafjord.no -kvalsund.no -kvam.no -kvanangen.no -kvinesdal.no -kvinnherad.no -kviteseid.no -kvitsoy.no -kvitsøy.no -laakesvuemie.no -lærdal.no -lahppi.no -láhppi.no -lardal.no -larvik.no -lavagis.no -lavangen.no -leangaviika.no -leaŋgaviika.no -lebesby.no -leikanger.no -leirfjord.no -leka.no -leksvik.no -lenvik.no -lerdal.no -lesja.no -levanger.no -lier.no -lierne.no -lillehammer.no -lillesand.no -lindas.no -lindås.no -lindesnes.no -loabat.no -loabát.no -lodingen.no -lødingen.no -lom.no -loppa.no -lorenskog.no -lørenskog.no -loten.no -løten.no -lund.no -lunner.no -luroy.no -lurøy.no -luster.no -lyngdal.no -lyngen.no -malatvuopmi.no -málatvuopmi.no -malselv.no -målselv.no -malvik.no -mandal.no -marker.no -marnardal.no -masfjorden.no -masoy.no -måsøy.no -matta-varjjat.no -mátta-várjjat.no -meland.no -meldal.no -melhus.no -meloy.no -meløy.no -meraker.no -meråker.no -midsund.no -midtre-gauldal.no -moareke.no -moåreke.no -modalen.no -modum.no -molde.no -heroy.more-og-romsdal.no -sande.more-og-romsdal.no -herøy.møre-og-romsdal.no -sande.møre-og-romsdal.no -moskenes.no -moss.no -muosat.no -muosát.no -naamesjevuemie.no -nååmesjevuemie.no -nærøy.no -namdalseid.no -namsos.no -namsskogan.no -nannestad.no -naroy.no -narviika.no -narvik.no -naustdal.no -navuotna.no -návuotna.no -nedre-eiker.no -nesna.no -nesodden.no -nesseby.no -nesset.no -nissedal.no -nittedal.no -nord-aurdal.no -nord-fron.no -nord-odal.no -norddal.no -nordkapp.no -bo.nordland.no -bø.nordland.no -heroy.nordland.no -herøy.nordland.no -nordre-land.no -nordreisa.no -nore-og-uvdal.no -notodden.no -notteroy.no -nøtterøy.no -odda.no -oksnes.no -øksnes.no -omasvuotna.no -oppdal.no -oppegard.no -oppegård.no -orkdal.no -orland.no -ørland.no -orskog.no -ørskog.no -orsta.no -ørsta.no -osen.no -osteroy.no -osterøy.no -valer.ostfold.no -våler.østfold.no -ostre-toten.no -østre-toten.no -overhalla.no -ovre-eiker.no -øvre-eiker.no -oyer.no -øyer.no -oygarden.no -øygarden.no -oystre-slidre.no -øystre-slidre.no -porsanger.no -porsangu.no -porsáŋgu.no -porsgrunn.no -rade.no -råde.no -radoy.no -radøy.no -rælingen.no -rahkkeravju.no -ráhkkerávju.no -raisa.no -ráisa.no -rakkestad.no -ralingen.no -rana.no -randaberg.no -rauma.no -re.no -rendalen.no -rennebu.no -rennesoy.no -rennesøy.no -rindal.no -ringebu.no -ringerike.no -ringsaker.no -risor.no -risør.no -rissa.no -roan.no -rodoy.no -rødøy.no -rollag.no -romsa.no -romskog.no -rømskog.no -roros.no -røros.no -rost.no -røst.no -royken.no -røyken.no -royrvik.no -røyrvik.no -ruovat.no -rygge.no -salangen.no -salat.no -sálat.no -sálát.no -saltdal.no -samnanger.no -sandefjord.no -sandnes.no -sandoy.no -sandøy.no -sarpsborg.no -sauda.no -sauherad.no -sel.no -selbu.no -selje.no -seljord.no -siellak.no -sigdal.no -siljan.no -sirdal.no -skanit.no -skánit.no -skanland.no -skånland.no -skaun.no -skedsmo.no -ski.no -skien.no -skierva.no -skiervá.no -skiptvet.no -skjak.no -skjåk.no -skjervoy.no -skjervøy.no -skodje.no -smola.no -smøla.no -snaase.no -snåase.no -snasa.no -snåsa.no -snillfjord.no -snoasa.no -sogndal.no -sogne.no -søgne.no -sokndal.no -sola.no -solund.no -somna.no -sømna.no -sondre-land.no -søndre-land.no -songdalen.no -sor-aurdal.no -sør-aurdal.no -sor-fron.no -sør-fron.no -sor-odal.no -sør-odal.no -sor-varanger.no -sør-varanger.no -sorfold.no -sørfold.no -sorreisa.no -sørreisa.no -sortland.no -sorum.no -sørum.no -spydeberg.no -stange.no -stavanger.no -steigen.no -steinkjer.no -stjordal.no -stjørdal.no -stokke.no -stor-elvdal.no -stord.no -stordal.no -storfjord.no -strand.no -stranda.no -stryn.no -sula.no -suldal.no -sund.no -sunndal.no -surnadal.no -sveio.no -svelvik.no -sykkylven.no -tana.no -bo.telemark.no -bø.telemark.no -time.no -tingvoll.no -tinn.no -tjeldsund.no -tjome.no -tjøme.no -tokke.no -tolga.no -tonsberg.no -tønsberg.no -torsken.no -træna.no -trana.no -tranoy.no -tranøy.no -troandin.no -trogstad.no -trøgstad.no -tromsa.no -tromso.no -tromsø.no -trondheim.no -trysil.no -tvedestrand.no -tydal.no -tynset.no -tysfjord.no -tysnes.no -tysvær.no -tysvar.no -ullensaker.no -ullensvang.no -ulstein.no -ulvik.no -unjarga.no -unjárga.no -utsira.no -vaapste.no -vadso.no -vadsø.no -værøy.no -vaga.no -vågå.no -vagan.no -vågan.no -vagsoy.no -vågsøy.no -vaksdal.no -valle.no -vang.no -vanylven.no -vardo.no -vardø.no -varggat.no -várggát.no -varoy.no -vefsn.no -vega.no -vegarshei.no -vegårshei.no -vennesla.no -verdal.no -verran.no -vestby.no -sande.vestfold.no -vestnes.no -vestre-slidre.no -vestre-toten.no -vestvagoy.no -vestvågøy.no -vevelstad.no -vik.no -vikna.no -vindafjord.no -voagat.no -volda.no -voss.no - -// np : http://www.mos.com.np/register.html -*.np - -// nr : http://cenpac.net.nr/dns/index.html -// Submitted by registry -nr -biz.nr -com.nr -edu.nr -gov.nr -info.nr -net.nr -org.nr - -// nu : https://www.iana.org/domains/root/db/nu.html -nu - -// nz : https://www.iana.org/domains/root/db/nz.html -// Submitted by registry -nz -ac.nz -co.nz -cri.nz -geek.nz -gen.nz -govt.nz -health.nz -iwi.nz -kiwi.nz -maori.nz -māori.nz -mil.nz -net.nz -org.nz -parliament.nz -school.nz - -// om : https://www.iana.org/domains/root/db/om.html -om -co.om -com.om -edu.om -gov.om -med.om -museum.om -net.om -org.om -pro.om - -// onion : https://tools.ietf.org/html/rfc7686 -onion - -// org : https://www.iana.org/domains/root/db/org.html -org - -// pa : http://www.nic.pa/ -// Some additional second level "domains" resolve directly as hostnames, such as -// pannet.pa, so we add a rule for "pa". -pa -abo.pa -ac.pa -com.pa -edu.pa -gob.pa -ing.pa -med.pa -net.pa -nom.pa -org.pa -sld.pa - -// pe : https://www.nic.pe/InformeFinalComision.pdf -pe -com.pe -edu.pe -gob.pe -mil.pe -net.pe -nom.pe -org.pe - -// pf : http://www.gobin.info/domainname/formulaire-pf.pdf -pf -com.pf -edu.pf -org.pf - -// pg : https://www.iana.org/domains/root/db/pg.html -*.pg - -// ph : https://www.iana.org/domains/root/db/ph.html -// Submitted by registry -ph -com.ph -edu.ph -gov.ph -i.ph -mil.ph -net.ph -ngo.ph -org.ph - -// pk : https://pk5.pknic.net.pk/pk5/msgNamepk.PK -// Contact Email: staff@pknic.net.pk -pk -ac.pk -biz.pk -com.pk -edu.pk -fam.pk -gkp.pk -gob.pk -gog.pk -gok.pk -gop.pk -gos.pk -gov.pk -net.pk -org.pk -web.pk - -// pl : https://www.dns.pl/en/ -// Confirmed by registry 2024-11-18 -pl -com.pl -net.pl -org.pl -// pl functional domains : https://www.dns.pl/en/list_of_functional_domain_names -agro.pl -aid.pl -atm.pl -auto.pl -biz.pl -edu.pl -gmina.pl -gsm.pl -info.pl -mail.pl -media.pl -miasta.pl -mil.pl -nieruchomosci.pl -nom.pl -pc.pl -powiat.pl -priv.pl -realestate.pl -rel.pl -sex.pl -shop.pl -sklep.pl -sos.pl -szkola.pl -targi.pl -tm.pl -tourism.pl -travel.pl -turystyka.pl -// Government domains : https://www.dns.pl/informacje_o_rejestracji_domen_gov_pl -// In accordance with the .gov.pl Domain Name Regulations : https://www.dns.pl/regulamin_gov_pl -gov.pl -ap.gov.pl -griw.gov.pl -ic.gov.pl -is.gov.pl -kmpsp.gov.pl -konsulat.gov.pl -kppsp.gov.pl -kwp.gov.pl -kwpsp.gov.pl -mup.gov.pl -mw.gov.pl -oia.gov.pl -oirm.gov.pl -oke.gov.pl -oow.gov.pl -oschr.gov.pl -oum.gov.pl -pa.gov.pl -pinb.gov.pl -piw.gov.pl -po.gov.pl -pr.gov.pl -psp.gov.pl -psse.gov.pl -pup.gov.pl -rzgw.gov.pl -sa.gov.pl -sdn.gov.pl -sko.gov.pl -so.gov.pl -sr.gov.pl -starostwo.gov.pl -ug.gov.pl -ugim.gov.pl -um.gov.pl -umig.gov.pl -upow.gov.pl -uppo.gov.pl -us.gov.pl -uw.gov.pl -uzs.gov.pl -wif.gov.pl -wiih.gov.pl -winb.gov.pl -wios.gov.pl -witd.gov.pl -wiw.gov.pl -wkz.gov.pl -wsa.gov.pl -wskr.gov.pl -wsse.gov.pl -wuoz.gov.pl -wzmiuw.gov.pl -zp.gov.pl -zpisdn.gov.pl -// pl regional domains : https://www.dns.pl/en/list_of_regional_domain_names -augustow.pl -babia-gora.pl -bedzin.pl -beskidy.pl -bialowieza.pl -bialystok.pl -bielawa.pl -bieszczady.pl -boleslawiec.pl -bydgoszcz.pl -bytom.pl -cieszyn.pl -czeladz.pl -czest.pl -dlugoleka.pl -elblag.pl -elk.pl -glogow.pl -gniezno.pl -gorlice.pl -grajewo.pl -ilawa.pl -jaworzno.pl -jelenia-gora.pl -jgora.pl -kalisz.pl -karpacz.pl -kartuzy.pl -kaszuby.pl -katowice.pl -kazimierz-dolny.pl -kepno.pl -ketrzyn.pl -klodzko.pl -kobierzyce.pl -kolobrzeg.pl -konin.pl -konskowola.pl -kutno.pl -lapy.pl -lebork.pl -legnica.pl -lezajsk.pl -limanowa.pl -lomza.pl -lowicz.pl -lubin.pl -lukow.pl -malbork.pl -malopolska.pl -mazowsze.pl -mazury.pl -mielec.pl -mielno.pl -mragowo.pl -naklo.pl -nowaruda.pl -nysa.pl -olawa.pl -olecko.pl -olkusz.pl -olsztyn.pl -opoczno.pl -opole.pl -ostroda.pl -ostroleka.pl -ostrowiec.pl -ostrowwlkp.pl -pila.pl -pisz.pl -podhale.pl -podlasie.pl -polkowice.pl -pomorskie.pl -pomorze.pl -prochowice.pl -pruszkow.pl -przeworsk.pl -pulawy.pl -radom.pl -rawa-maz.pl -rybnik.pl -rzeszow.pl -sanok.pl -sejny.pl -skoczow.pl -slask.pl -slupsk.pl -sosnowiec.pl -stalowa-wola.pl -starachowice.pl -stargard.pl -suwalki.pl -swidnica.pl -swiebodzin.pl -swinoujscie.pl -szczecin.pl -szczytno.pl -tarnobrzeg.pl -tgory.pl -turek.pl -tychy.pl -ustka.pl -walbrzych.pl -warmia.pl -warszawa.pl -waw.pl -wegrow.pl -wielun.pl -wlocl.pl -wloclawek.pl -wodzislaw.pl -wolomin.pl -wroclaw.pl -zachpomor.pl -zagan.pl -zarow.pl -zgora.pl -zgorzelec.pl - -// pm : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -pm - -// pn : https://www.iana.org/domains/root/db/pn.html -pn -co.pn -edu.pn -gov.pn -net.pn -org.pn - -// post : https://www.iana.org/domains/root/db/post.html -post - -// pr : http://www.nic.pr/index.asp?f=1 -pr -biz.pr -com.pr -edu.pr -gov.pr -info.pr -isla.pr -name.pr -net.pr -org.pr -pro.pr -// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html -ac.pr -est.pr -prof.pr - -// pro : http://registry.pro/get-pro -pro -aaa.pro -aca.pro -acct.pro -avocat.pro -bar.pro -cpa.pro -eng.pro -jur.pro -law.pro -med.pro -recht.pro - -// ps : https://www.iana.org/domains/root/db/ps.html -// http://www.nic.ps/registration/policy.html#reg -ps -com.ps -edu.ps -gov.ps -net.ps -org.ps -plo.ps -sec.ps - -// pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/ -pt -com.pt -edu.pt -gov.pt -int.pt -net.pt -nome.pt -org.pt -publ.pt - -// pw : https://www.iana.org/domains/root/db/pw.html -// Confirmed by registry in private correspondence with @dnsguru 2024-12-09 -pw -gov.pw - -// py : https://www.iana.org/domains/root/db/py.html -// Submitted by registry -py -com.py -coop.py -edu.py -gov.py -mil.py -net.py -org.py - -// qa : http://domains.qa/en/ -qa -com.qa -edu.qa -gov.qa -mil.qa -name.qa -net.qa -org.qa -sch.qa - -// re : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -// Confirmed by registry 2024-11-18 -re -// Closed for registration on 2013-03-15 but domains are still maintained -asso.re -com.re - -// ro : http://www.rotld.ro/ -ro -arts.ro -com.ro -firm.ro -info.ro -nom.ro -nt.ro -org.ro -rec.ro -store.ro -tm.ro -www.ro - -// rs : https://www.rnids.rs/en/domains/national-domains -rs -ac.rs -co.rs -edu.rs -gov.rs -in.rs -org.rs - -// ru : https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf -// Submitted by George Georgievsky -ru - -// rw : https://www.iana.org/domains/root/db/rw.html -rw -ac.rw -co.rw -coop.rw -gov.rw -mil.rw -net.rw -org.rw - -// sa : http://www.nic.net.sa/ -sa -com.sa -edu.sa -gov.sa -med.sa -net.sa -org.sa -pub.sa -sch.sa - -// sb : http://www.sbnic.net.sb/ -// Submitted by registry -sb -com.sb -edu.sb -gov.sb -net.sb -org.sb - -// sc : http://www.nic.sc/ -sc -com.sc -edu.sc -gov.sc -net.sc -org.sc - -// sd : https://www.iana.org/domains/root/db/sd.html -// Submitted by registry -sd -com.sd -edu.sd -gov.sd -info.sd -med.sd -net.sd -org.sd -tv.sd - -// se : https://www.iana.org/domains/root/db/se.html -// https://data.internetstiftelsen.se/barred_domains_list.txt -> Second level domains & Sub-domains -// Confirmed by Registry Services 2024-11-20 -se -a.se -ac.se -b.se -bd.se -brand.se -c.se -d.se -e.se -f.se -fh.se -fhsk.se -fhv.se -g.se -h.se -i.se -k.se -komforb.se -kommunalforbund.se -komvux.se -l.se -lanbib.se -m.se -n.se -naturbruksgymn.se -o.se -org.se -p.se -parti.se -pp.se -press.se -r.se -s.se -t.se -tm.se -u.se -w.se -x.se -y.se -z.se - -// sg : https://www.sgnic.sg/domain-registration/sg-categories-rules -// Confirmed by registry 2024-11-19 -sg -com.sg -edu.sg -gov.sg -net.sg -org.sg - -// sh : http://nic.sh/rules.htm -sh -com.sh -gov.sh -mil.sh -net.sh -org.sh - -// si : https://www.iana.org/domains/root/db/si.html -si - -// sj : No registrations at this time. -// Submitted by registry -sj - -// sk : https://www.iana.org/domains/root/db/sk.html -// https://sk-nic.sk/ -sk -org.sk - -// sl : http://www.nic.sl -// Submitted by registry -sl -com.sl -edu.sl -gov.sl -net.sl -org.sl - -// sm : https://www.iana.org/domains/root/db/sm.html -sm - -// sn : https://www.iana.org/domains/root/db/sn.html -sn -art.sn -com.sn -edu.sn -gouv.sn -org.sn -univ.sn - -// so : http://sonic.so/policies/ -so -com.so -edu.so -gov.so -me.so -net.so -org.so - -// sr : https://www.iana.org/domains/root/db/sr.html -sr - -// ss : https://registry.nic.ss/ -// Submitted by registry -ss -biz.ss -co.ss -com.ss -edu.ss -gov.ss -me.ss -net.ss -org.ss -sch.ss - -// st : http://www.nic.st/html/policyrules/ -st -co.st -com.st -consulado.st -edu.st -embaixada.st -mil.st -net.st -org.st -principe.st -saotome.st -store.st - -// su : https://www.iana.org/domains/root/db/su.html -su - -// sv : https://www.iana.org/domains/root/db/sv.html -sv -com.sv -edu.sv -gob.sv -org.sv -red.sv - -// sx : https://www.iana.org/domains/root/db/sx.html -// Submitted by registry -sx -gov.sx - -// sy : https://www.iana.org/domains/root/db/sy.html -sy -com.sy -edu.sy -gov.sy -mil.sy -net.sy -org.sy - -// sz : https://www.iana.org/domains/root/db/sz.html -// http://www.sispa.org.sz/ -sz -ac.sz -co.sz -org.sz - -// tc : https://www.iana.org/domains/root/db/tc.html -tc - -// td : https://www.iana.org/domains/root/db/td.html -td - -// tel : https://www.iana.org/domains/root/db/tel.html -// http://www.telnic.org/ -tel - -// tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -tf - -// tg : https://www.iana.org/domains/root/db/tg.html -// http://www.nic.tg/ -tg - -// th : https://www.iana.org/domains/root/db/th.html -// Submitted by registry -th -ac.th -co.th -go.th -in.th -mi.th -net.th -or.th - -// tj : http://www.nic.tj/policy.html -tj -biz.tj -co.tj -com.tj -edu.tj -go.tj -gov.tj -int.tj -mil.tj -name.tj -net.tj -nic.tj -org.tj -test.tj -web.tj - -// tk : https://www.iana.org/domains/root/db/tk.html -tk - -// tl : https://www.iana.org/domains/root/db/tl.html -tl -gov.tl - -// tm : https://www.nic.tm/local.html -// Confirmed by registry 2024-11-19 -tm -co.tm -com.tm -edu.tm -gov.tm -mil.tm -net.tm -nom.tm -org.tm - -// tn : http://www.registre.tn/fr/ -// https://whois.ati.tn/ -tn -com.tn -ens.tn -fin.tn -gov.tn -ind.tn -info.tn -intl.tn -mincom.tn -nat.tn -net.tn -org.tn -perso.tn -tourism.tn - -// to : https://www.iana.org/domains/root/db/to.html -// Submitted by registry -to -com.to -edu.to -gov.to -mil.to -net.to -org.to - -// tr : https://nic.tr/ -// https://nic.tr/forms/eng/policies.pdf -// https://nic.tr/index.php?USRACTN=PRICELST -tr -av.tr -bbs.tr -bel.tr -biz.tr -com.tr -dr.tr -edu.tr -gen.tr -gov.tr -info.tr -k12.tr -kep.tr -mil.tr -name.tr -net.tr -org.tr -pol.tr -tel.tr -tsk.tr -tv.tr -web.tr -// Used by Northern Cyprus -nc.tr -// Used by government agencies of Northern Cyprus -gov.nc.tr - -// tt : https://www.nic.tt/ -// Confirmed by registry 2024-11-19 -tt -biz.tt -co.tt -com.tt -edu.tt -gov.tt -info.tt -mil.tt -name.tt -net.tt -org.tt -pro.tt - -// tv : https://www.iana.org/domains/root/db/tv.html -// Not listing any 2LDs as reserved since none seem to exist in practice, -// Wikipedia notwithstanding. -tv - -// tw : https://www.iana.org/domains/root/db/tw.html -// https://twnic.tw/dnservice_catag.php -// Confirmed by registry 2024-11-26 -tw -club.tw -com.tw -ebiz.tw -edu.tw -game.tw -gov.tw -idv.tw -mil.tw -net.tw -org.tw - -// tz : http://www.tznic.or.tz/index.php/domains -// Submitted by registry -tz -ac.tz -co.tz -go.tz -hotel.tz -info.tz -me.tz -mil.tz -mobi.tz -ne.tz -or.tz -sc.tz -tv.tz - -// ua : https://hostmaster.ua/policy/?ua -// Submitted by registry -ua -// ua 2LD -com.ua -edu.ua -gov.ua -in.ua -net.ua -org.ua -// ua geographic names -// https://hostmaster.ua/2ld/ -cherkassy.ua -cherkasy.ua -chernigov.ua -chernihiv.ua -chernivtsi.ua -chernovtsy.ua -ck.ua -cn.ua -cr.ua -crimea.ua -cv.ua -dn.ua -dnepropetrovsk.ua -dnipropetrovsk.ua -donetsk.ua -dp.ua -if.ua -ivano-frankivsk.ua -kh.ua -kharkiv.ua -kharkov.ua -kherson.ua -khmelnitskiy.ua -khmelnytskyi.ua -kiev.ua -kirovograd.ua -km.ua -kr.ua -kropyvnytskyi.ua -krym.ua -ks.ua -kv.ua -kyiv.ua -lg.ua -lt.ua -lugansk.ua -luhansk.ua -lutsk.ua -lv.ua -lviv.ua -mk.ua -mykolaiv.ua -nikolaev.ua -od.ua -odesa.ua -odessa.ua -pl.ua -poltava.ua -rivne.ua -rovno.ua -rv.ua -sb.ua -sebastopol.ua -sevastopol.ua -sm.ua -sumy.ua -te.ua -ternopil.ua -uz.ua -uzhgorod.ua -uzhhorod.ua -vinnica.ua -vinnytsia.ua -vn.ua -volyn.ua -yalta.ua -zakarpattia.ua -zaporizhzhe.ua -zaporizhzhia.ua -zhitomir.ua -zhytomyr.ua -zp.ua -zt.ua - -// ug : https://www.registry.co.ug/ -// https://www.registry.co.ug, https://whois.co.ug -// Confirmed by registry 2025-01-20 -ug -ac.ug -co.ug -com.ug -edu.ug -go.ug -gov.ug -mil.ug -ne.ug -or.ug -org.ug -sc.ug -us.ug - -// uk : https://www.iana.org/domains/root/db/uk.html -// Submitted by registry -uk -ac.uk -co.uk -gov.uk -ltd.uk -me.uk -net.uk -nhs.uk -org.uk -plc.uk -police.uk -*.sch.uk - -// us : https://www.iana.org/domains/root/db/us.html -// Confirmed via the .us zone file by William Harrison 2024-12-10 -us -dni.us -isa.us -nsn.us -// Geographic Names -ak.us -al.us -ar.us -as.us -az.us -ca.us -co.us -ct.us -dc.us -de.us -fl.us -ga.us -gu.us -hi.us -ia.us -id.us -il.us -in.us -ks.us -ky.us -la.us -ma.us -md.us -me.us -mi.us -mn.us -mo.us -ms.us -mt.us -nc.us -nd.us -ne.us -nh.us -nj.us -nm.us -nv.us -ny.us -oh.us -ok.us -or.us -pa.us -pr.us -ri.us -sc.us -sd.us -tn.us -tx.us -ut.us -va.us -vi.us -vt.us -wa.us -wi.us -wv.us -wy.us -// The registrar notes several more specific domains available in each state, -// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat -// haphazard; in some states these domains resolve as addresses, while in others -// only subdomains are available, or even nothing at all. We include the -// most common ones where it's clear that different sites are different -// entities. -k12.ak.us -k12.al.us -k12.ar.us -k12.as.us -k12.az.us -k12.ca.us -k12.co.us -k12.ct.us -k12.dc.us -k12.fl.us -k12.ga.us -k12.gu.us -// k12.hi.us - Bug 614565 - Hawaii has a state-wide DOE login -k12.ia.us -k12.id.us -k12.il.us -k12.in.us -k12.ks.us -k12.ky.us -k12.la.us -k12.ma.us -k12.md.us -k12.me.us -k12.mi.us -k12.mn.us -k12.mo.us -k12.ms.us -k12.mt.us -k12.nc.us -k12.ne.us -k12.nh.us -k12.nj.us -k12.nm.us -k12.nv.us -k12.ny.us -k12.oh.us -k12.ok.us -k12.or.us -k12.pa.us -k12.pr.us -// k12.ri.us - Removed at request of Kim Cournoyer -k12.sc.us -// k12.sd.us - Bug 934131 - Removed at request of James Booze -k12.tn.us -k12.tx.us -k12.ut.us -k12.va.us -k12.vi.us -k12.vt.us -k12.wa.us -k12.wi.us -// k12.wv.us - Bug 947705 - Removed at request of Verne Britton -cc.ak.us -lib.ak.us -cc.al.us -lib.al.us -cc.ar.us -lib.ar.us -cc.as.us -lib.as.us -cc.az.us -lib.az.us -cc.ca.us -lib.ca.us -cc.co.us -lib.co.us -cc.ct.us -lib.ct.us -cc.dc.us -lib.dc.us -cc.de.us -cc.fl.us -lib.fl.us -cc.ga.us -lib.ga.us -cc.gu.us -lib.gu.us -cc.hi.us -lib.hi.us -cc.ia.us -lib.ia.us -cc.id.us -lib.id.us -cc.il.us -lib.il.us -cc.in.us -lib.in.us -cc.ks.us -lib.ks.us -cc.ky.us -lib.ky.us -cc.la.us -lib.la.us -cc.ma.us -lib.ma.us -cc.md.us -lib.md.us -cc.me.us -lib.me.us -cc.mi.us -lib.mi.us -cc.mn.us -lib.mn.us -cc.mo.us -lib.mo.us -cc.ms.us -cc.mt.us -lib.mt.us -cc.nc.us -lib.nc.us -cc.ne.us -lib.ne.us -cc.nh.us -lib.nh.us -cc.nj.us -lib.nj.us -cc.nm.us -lib.nm.us -cc.nv.us -lib.nv.us -cc.ny.us -lib.ny.us -cc.oh.us -lib.oh.us -cc.ok.us -lib.ok.us -cc.or.us -lib.or.us -cc.pa.us -lib.pa.us -cc.pr.us -lib.pr.us -cc.ri.us -lib.ri.us -cc.sc.us -lib.sc.us -cc.sd.us -lib.sd.us -cc.tn.us -lib.tn.us -cc.tx.us -lib.tx.us -cc.ut.us -lib.ut.us -cc.va.us -lib.va.us -cc.vi.us -lib.vi.us -cc.vt.us -lib.vt.us -cc.wa.us -lib.wa.us -cc.wi.us -lib.wi.us -cc.wv.us -cc.wy.us -k12.wy.us -// lib.wv.us - Bug 941670 - Removed at request of Larry W Arnold -lib.wy.us -// k12.ma.us contains school districts in Massachusetts. The 4LDs are -// managed independently except for private (PVT), charter (CHTR) and -// parochial (PAROCH) schools. Those are delegated directly to the -// 5LD operators. -chtr.k12.ma.us -paroch.k12.ma.us -pvt.k12.ma.us -// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following -// see also: https://domreg.merit.edu : domreg@merit.edu -// see also: whois -h whois.domreg.merit.edu help -ann-arbor.mi.us -cog.mi.us -dst.mi.us -eaton.mi.us -gen.mi.us -mus.mi.us -tec.mi.us -washtenaw.mi.us - -// uy : http://www.nic.org.uy/ -uy -com.uy -edu.uy -gub.uy -mil.uy -net.uy -org.uy - -// uz : http://www.reg.uz/ -uz -co.uz -com.uz -net.uz -org.uz - -// va : https://www.iana.org/domains/root/db/va.html -va - -// vc : https://www.iana.org/domains/root/db/vc.html -// Submitted by registry -vc -com.vc -edu.vc -gov.vc -mil.vc -net.vc -org.vc - -// ve : https://registro.nic.ve/ -// https://nic.ve/site/user-agreement -> under "III. Clasificación de Nombres de Dominio" -// Submitted by registry nic@nic.ve and nicve@conatel.gob.ve -ve -arts.ve -bib.ve -co.ve -com.ve -e12.ve -edu.ve -emprende.ve -firm.ve -gob.ve -gov.ve -ia.ve -info.ve -int.ve -mil.ve -net.ve -nom.ve -org.ve -rar.ve -rec.ve -store.ve -tec.ve -web.ve - -// vg : https://www.iana.org/domains/root/db/vg.html -// Confirmed by registry 2025-01-10 -vg -edu.vg - -// vi : https://www.iana.org/domains/root/db/vi.html -vi -co.vi -com.vi -k12.vi -net.vi -org.vi - -// vn : https://www.vnnic.vn/en/domain/cctld-vn -// https://vnnic.vn/sites/default/files/tailieu/vn.cctld.domains.txt -vn -ac.vn -ai.vn -biz.vn -com.vn -edu.vn -gov.vn -health.vn -id.vn -info.vn -int.vn -io.vn -name.vn -net.vn -org.vn -pro.vn - -// vn geographical names -angiang.vn -bacgiang.vn -backan.vn -baclieu.vn -bacninh.vn -baria-vungtau.vn -bentre.vn -binhdinh.vn -binhduong.vn -binhphuoc.vn -binhthuan.vn -camau.vn -cantho.vn -caobang.vn -daklak.vn -daknong.vn -danang.vn -dienbien.vn -dongnai.vn -dongthap.vn -gialai.vn -hagiang.vn -haiduong.vn -haiphong.vn -hanam.vn -hanoi.vn -hatinh.vn -haugiang.vn -hoabinh.vn -hue.vn -hungyen.vn -khanhhoa.vn -kiengiang.vn -kontum.vn -laichau.vn -lamdong.vn -langson.vn -laocai.vn -longan.vn -namdinh.vn -nghean.vn -ninhbinh.vn -ninhthuan.vn -phutho.vn -phuyen.vn -quangbinh.vn -quangnam.vn -quangngai.vn -quangninh.vn -quangtri.vn -soctrang.vn -sonla.vn -tayninh.vn -thaibinh.vn -thainguyen.vn -thanhhoa.vn -thanhphohochiminh.vn -thuathienhue.vn -tiengiang.vn -travinh.vn -tuyenquang.vn -vinhlong.vn -vinhphuc.vn -yenbai.vn - -// vu : https://www.iana.org/domains/root/db/vu.html -// http://www.vunic.vu/ -vu -com.vu -edu.vu -net.vu -org.vu - -// wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -wf - -// ws : https://www.iana.org/domains/root/db/ws.html -// http://samoanic.ws/index.dhtml -ws -com.ws -edu.ws -gov.ws -net.ws -org.ws - -// yt : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -yt - -// IDN ccTLDs -// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then -// U-label, and follow this format: -// // A-Label ("", [, variant info]) : -// // [sponsoring org] -// U-Label - -// xn--mgbaam7a8h ("Emerat", Arabic) : AE -// http://nic.ae/english/arabicdomain/rules.jsp -امارات - -// xn--y9a3aq ("hye", Armenian) : AM -// ISOC AM (operated by .am Registry) -հայ - -// xn--54b7fta0cc ("Bangla", Bangla) : BD -বাংলা - -// xn--90ae ("bg", Bulgarian) : BG -бг - -// xn--mgbcpq6gpa1a ("albahrain", Arabic) : BH -البحرين - -// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY -// Operated by .by registry -бел - -// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN -// CNNIC -// https://www.cnnic.cn/11/192/index.html -中国 - -// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN -// CNNIC -// https://www.cnnic.com.cn/AU/MediaC/Announcement/201609/t20160905_54470.htm -中國 - -// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ -الجزائر - -// xn--wgbh1c ("Egypt/Masr", Arabic) : EG -// http://www.dotmasr.eg/ -مصر - -// xn--e1a4c ("eu", Cyrillic) : EU -// https://eurid.eu -ею - -// xn--qxa6a ("eu", Greek) : EU -// https://eurid.eu -ευ - -// xn--mgbah1a3hjkrd ("Mauritania", Arabic) : MR -موريتانيا - -// xn--node ("ge", Georgian Mkhedruli) : GE -გე - -// xn--qxam ("el", Greek) : GR -// Hellenic Ministry of Infrastructure, Transport, and Networks -ελ - -// xn--j6w193g ("Hong Kong", Chinese) : HK -// https://www.hkirc.hk -// Submitted by registry -// https://www.hkirc.hk/content.jsp?id=30#!/34 -香港 -個人.香港 -公司.香港 -政府.香港 -教育.香港 -組織.香港 -網絡.香港 - -// xn--2scrj9c ("Bharat", Kannada) : IN -// India -ಭಾರತ - -// xn--3hcrj9c ("Bharat", Oriya) : IN -// India -ଭାରତ - -// xn--45br5cyl ("Bharatam", Assamese) : IN -// India -ভাৰত - -// xn--h2breg3eve ("Bharatam", Sanskrit) : IN -// India -भारतम् - -// xn--h2brj9c8c ("Bharot", Santali) : IN -// India -भारोत - -// xn--mgbgu82a ("Bharat", Sindhi) : IN -// India -ڀارت - -// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN -// India -ഭാരതം - -// xn--h2brj9c ("Bharat", Devanagari) : IN -// India -भारत - -// xn--mgbbh1a ("Bharat", Kashmiri) : IN -// India -بارت - -// xn--mgbbh1a71e ("Bharat", Arabic) : IN -// India -بھارت - -// xn--fpcrj9c3d ("Bharat", Telugu) : IN -// India -భారత్ - -// xn--gecrj9c ("Bharat", Gujarati) : IN -// India -ભારત - -// xn--s9brj9c ("Bharat", Gurmukhi) : IN -// India -ਭਾਰਤ - -// xn--45brj9c ("Bharat", Bengali) : IN -// India -ভারত - -// xn--xkc2dl3a5ee0h ("India", Tamil) : IN -// India -இந்தியா - -// xn--mgba3a4f16a ("Iran", Persian) : IR -ایران - -// xn--mgba3a4fra ("Iran", Arabic) : IR -ايران - -// xn--mgbtx2b ("Iraq", Arabic) : IQ -// Communications and Media Commission -عراق - -// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO -// National Information Technology Center (NITC) -// Royal Scientific Society, Al-Jubeiha -الاردن - -// xn--3e0b707e ("Republic of Korea", Hangul) : KR -한국 - -// xn--80ao21a ("Kaz", Kazakh) : KZ -қаз - -// xn--q7ce6a ("Lao", Lao) : LA -ລາວ - -// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK -// https://nic.lk -ලංකා - -// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK -// https://nic.lk -இலங்கை - -// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA -المغرب - -// xn--d1alf ("mkd", Macedonian) : MK -// MARnet -мкд - -// xn--l1acc ("mon", Mongolian) : MN -мон - -// xn--mix891f ("Macao", Chinese, Traditional) : MO -// MONIC / HNET Asia (Registry Operator for .mo) -澳門 - -// xn--mix082f ("Macao", Chinese, Simplified) : MO -澳门 - -// xn--mgbx4cd0ab ("Malaysia", Malay) : MY -مليسيا - -// xn--mgb9awbf ("Oman", Arabic) : OM -عمان - -// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK -پاکستان - -// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK -پاكستان - -// xn--ygbi2ammx ("Falasteen", Arabic) : PS -// The Palestinian National Internet Naming Authority (PNINA) -// http://www.pnina.ps -فلسطين - -// xn--90a3ac ("srb", Cyrillic) : RS -// https://www.rnids.rs/en/domains/national-domains -срб -ак.срб -обр.срб -од.срб -орг.срб -пр.срб -упр.срб - -// xn--p1ai ("rf", Russian-Cyrillic) : RU -// https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf -// Submitted by George Georgievsky -рф - -// xn--wgbl6a ("Qatar", Arabic) : QA -// http://www.ict.gov.qa/ -قطر - -// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA -// http://www.nic.net.sa/ -السعودية - -// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant): SA -السعودیة - -// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA -السعودیۃ - -// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA -السعوديه - -// xn--mgbpl2fh ("sudan", Arabic) : SD -// Operated by .sd registry -سودان - -// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG -新加坡 - -// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG -சிங்கப்பூர் - -// xn--ogbpf8fl ("Syria", Arabic) : SY -سورية - -// xn--mgbtf8fl ("Syria", Arabic, variant) : SY -سوريا - -// xn--o3cw4h ("Thai", Thai) : TH -// http://www.thnic.co.th -ไทย -ทหาร.ไทย -ธุรกิจ.ไทย -เน็ต.ไทย -รัฐบาล.ไทย -ศึกษา.ไทย -องค์กร.ไทย - -// xn--pgbs0dh ("Tunisia", Arabic) : TN -// http://nic.tn -تونس - -// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW -// https://twnic.tw/dnservice_catag.php -台灣 - -// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW -// http://www.twnic.net/english/dn/dn_07a.htm -台湾 - -// xn--nnx388a ("Taiwan", Chinese, variant) : TW -臺灣 - -// xn--j1amh ("ukr", Cyrillic) : UA -укр - -// xn--mgb2ddes ("AlYemen", Arabic) : YE -اليمن - -// xxx : http://icmregistry.com -xxx - -// ye : http://www.y.net.ye/services/domain_name.htm -ye -com.ye -edu.ye -gov.ye -mil.ye -net.ye -org.ye - -// za : https://www.iana.org/domains/root/db/za.html -ac.za -agric.za -alt.za -co.za -edu.za -gov.za -grondar.za -law.za -mil.za -net.za -ngo.za -nic.za -nis.za -nom.za -org.za -school.za -tm.za -web.za - -// zm : https://zicta.zm/ -// Submitted by registry -zm -ac.zm -biz.zm -co.zm -com.zm -edu.zm -gov.zm -info.zm -mil.zm -net.zm -org.zm -sch.zm - -// zw : https://www.potraz.gov.zw/ -// Confirmed by registry 2017-01-25 -zw -ac.zw -co.zw -gov.zw -mil.zw -org.zw - -// newGTLDs - -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2026-07-24T16:40:16Z -// This list is auto-generated, don't edit it manually. -// aaa : American Automobile Association, Inc. -// https://www.iana.org/domains/root/db/aaa.html -aaa - -// aarp : AARP -// https://www.iana.org/domains/root/db/aarp.html -aarp - -// abb : ABB Ltd -// https://www.iana.org/domains/root/db/abb.html -abb - -// abbott : Abbott Laboratories, Inc. -// https://www.iana.org/domains/root/db/abbott.html -abbott - -// abbvie : AbbVie Inc. -// https://www.iana.org/domains/root/db/abbvie.html -abbvie - -// abc : Disney Enterprises, Inc. -// https://www.iana.org/domains/root/db/abc.html -abc - -// able : Able Inc. -// https://www.iana.org/domains/root/db/able.html -able - -// abogado : Registry Services, LLC -// https://www.iana.org/domains/root/db/abogado.html -abogado - -// abudhabi : Abu Dhabi Systems and Information Centre -// https://www.iana.org/domains/root/db/abudhabi.html -abudhabi - -// academy : Binky Moon, LLC -// https://www.iana.org/domains/root/db/academy.html -academy - -// accenture : Accenture plc -// https://www.iana.org/domains/root/db/accenture.html -accenture - -// accountant : dot Accountant Limited -// https://www.iana.org/domains/root/db/accountant.html -accountant - -// accountants : Binky Moon, LLC -// https://www.iana.org/domains/root/db/accountants.html -accountants - -// aco : ACO Severin Ahlmann GmbH & Co. KG -// https://www.iana.org/domains/root/db/aco.html -aco - -// actor : Dog Beach, LLC -// https://www.iana.org/domains/root/db/actor.html -actor - -// ads : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/ads.html -ads - -// adult : ICM Registry AD LLC -// https://www.iana.org/domains/root/db/adult.html -adult - -// aeg : Aktiebolaget Electrolux -// https://www.iana.org/domains/root/db/aeg.html -aeg - -// aetna : Aetna Life Insurance Company -// https://www.iana.org/domains/root/db/aetna.html -aetna - -// afl : Australian Football League -// https://www.iana.org/domains/root/db/afl.html -afl - -// africa : ZA Central Registry NPC trading as Registry.Africa -// https://www.iana.org/domains/root/db/africa.html -africa - -// agakhan : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/agakhan.html -agakhan - -// agency : Binky Moon, LLC -// https://www.iana.org/domains/root/db/agency.html -agency - -// aig : American International Group, Inc. -// https://www.iana.org/domains/root/db/aig.html -aig - -// airbus : Airbus S.A.S. -// https://www.iana.org/domains/root/db/airbus.html -airbus - -// airforce : Dog Beach, LLC -// https://www.iana.org/domains/root/db/airforce.html -airforce - -// airtel : Bharti Airtel Limited -// https://www.iana.org/domains/root/db/airtel.html -airtel - -// akdn : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/akdn.html -akdn - -// alibaba : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/alibaba.html -alibaba - -// alipay : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/alipay.html -alipay - -// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft -// https://www.iana.org/domains/root/db/allfinanz.html -allfinanz - -// allstate : Allstate Fire and Casualty Insurance Company -// https://www.iana.org/domains/root/db/allstate.html -allstate - -// ally : Ally Financial Inc. -// https://www.iana.org/domains/root/db/ally.html -ally - -// alsace : Region Grand Est -// https://www.iana.org/domains/root/db/alsace.html -alsace - -// alstom : ALSTOM -// https://www.iana.org/domains/root/db/alstom.html -alstom - -// amazon : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/amazon.html -amazon - -// americanexpress : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/americanexpress.html -americanexpress - -// americanfamily : AmFam, Inc. -// https://www.iana.org/domains/root/db/americanfamily.html -americanfamily - -// amex : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/amex.html -amex - -// amfam : AmFam, Inc. -// https://www.iana.org/domains/root/db/amfam.html -amfam - -// amica : Amica Mutual Insurance Company -// https://www.iana.org/domains/root/db/amica.html -amica - -// amsterdam : Gemeente Amsterdam -// https://www.iana.org/domains/root/db/amsterdam.html -amsterdam - -// analytics : Campus IP LLC -// https://www.iana.org/domains/root/db/analytics.html -analytics - -// android : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/android.html -android - -// anquan : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/anquan.html -anquan - -// anz : Australia and New Zealand Banking Group Limited -// https://www.iana.org/domains/root/db/anz.html -anz - -// aol : AOL Media LLC -// https://www.iana.org/domains/root/db/aol.html -aol - -// apartments : Binky Moon, LLC -// https://www.iana.org/domains/root/db/apartments.html -apartments - -// app : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/app.html -app - -// apple : Apple Inc. -// https://www.iana.org/domains/root/db/apple.html -apple - -// aquarelle : Aquarelle.com -// https://www.iana.org/domains/root/db/aquarelle.html -aquarelle - -// arab : League of Arab States -// https://www.iana.org/domains/root/db/arab.html -arab - -// aramco : Aramco Services Company -// https://www.iana.org/domains/root/db/aramco.html -aramco - -// archi : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/archi.html -archi - -// army : Dog Beach, LLC -// https://www.iana.org/domains/root/db/army.html -army - -// art : UK Creative Ideas Limited -// https://www.iana.org/domains/root/db/art.html -art - -// arte : Association Relative à la Télévision Européenne G.E.I.E. -// https://www.iana.org/domains/root/db/arte.html -arte - -// asda : Asda Stores Limited -// https://www.iana.org/domains/root/db/asda.html -asda - -// associates : Binky Moon, LLC -// https://www.iana.org/domains/root/db/associates.html -associates - -// athleta : The Gap, Inc. -// https://www.iana.org/domains/root/db/athleta.html -athleta - -// attorney : Dog Beach, LLC -// https://www.iana.org/domains/root/db/attorney.html -attorney - -// auction : Dog Beach, LLC -// https://www.iana.org/domains/root/db/auction.html -auction - -// audi : AUDI Aktiengesellschaft -// https://www.iana.org/domains/root/db/audi.html -audi - -// audible : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/audible.html -audible - -// audio : XYZ.COM LLC -// https://www.iana.org/domains/root/db/audio.html -audio - -// auspost : Australian Postal Corporation -// https://www.iana.org/domains/root/db/auspost.html -auspost - -// author : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/author.html -author - -// auto : XYZ.COM LLC -// https://www.iana.org/domains/root/db/auto.html -auto - -// autos : XYZ.COM LLC -// https://www.iana.org/domains/root/db/autos.html -autos - -// aws : AWS Registry LLC -// https://www.iana.org/domains/root/db/aws.html -aws - -// axa : AXA Group Operations SAS -// https://www.iana.org/domains/root/db/axa.html -axa - -// azure : Microsoft Corporation -// https://www.iana.org/domains/root/db/azure.html -azure - -// baby : XYZ.COM LLC -// https://www.iana.org/domains/root/db/baby.html -baby - -// baidu : Baidu, Inc. -// https://www.iana.org/domains/root/db/baidu.html -baidu - -// banamex : Citigroup Inc. -// https://www.iana.org/domains/root/db/banamex.html -banamex - -// band : Dog Beach, LLC -// https://www.iana.org/domains/root/db/band.html -band - -// bank : fTLD Registry Services LLC -// https://www.iana.org/domains/root/db/bank.html -bank - -// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable -// https://www.iana.org/domains/root/db/bar.html -bar - -// barcelona : Municipi de Barcelona -// https://www.iana.org/domains/root/db/barcelona.html -barcelona - -// barclaycard : Barclays Bank PLC -// https://www.iana.org/domains/root/db/barclaycard.html -barclaycard - -// barclays : Barclays Bank PLC -// https://www.iana.org/domains/root/db/barclays.html -barclays - -// barefoot : Gallo Vineyards, Inc. -// https://www.iana.org/domains/root/db/barefoot.html -barefoot - -// bargains : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bargains.html -bargains - -// baseball : MLB Advanced Media DH, LLC -// https://www.iana.org/domains/root/db/baseball.html -baseball - -// basketball : Fédération Internationale de Basketball (FIBA) -// https://www.iana.org/domains/root/db/basketball.html -basketball - -// bauhaus : Werkhaus GmbH -// https://www.iana.org/domains/root/db/bauhaus.html -bauhaus - -// bayern : Bayern Connect GmbH -// https://www.iana.org/domains/root/db/bayern.html -bayern - -// bbc : British Broadcasting Corporation -// https://www.iana.org/domains/root/db/bbc.html -bbc - -// bbt : BB&T Corporation -// https://www.iana.org/domains/root/db/bbt.html -bbt - -// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A. -// https://www.iana.org/domains/root/db/bbva.html -bbva - -// bcg : The Boston Consulting Group, Inc. -// https://www.iana.org/domains/root/db/bcg.html -bcg - -// bcn : Municipi de Barcelona -// https://www.iana.org/domains/root/db/bcn.html -bcn - -// beats : Beats Electronics, LLC -// https://www.iana.org/domains/root/db/beats.html -beats - -// beauty : XYZ.COM LLC -// https://www.iana.org/domains/root/db/beauty.html -beauty - -// beer : Registry Services, LLC -// https://www.iana.org/domains/root/db/beer.html -beer - -// berlin : dotBERLIN GmbH & Co. KG -// https://www.iana.org/domains/root/db/berlin.html -berlin - -// best : BestTLD Pty Ltd -// https://www.iana.org/domains/root/db/best.html -best - -// bestbuy : BBY Solutions, Inc. -// https://www.iana.org/domains/root/db/bestbuy.html -bestbuy - -// bet : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/bet.html -bet - -// bharti : Bharti Enterprises (Holding) Private Limited -// https://www.iana.org/domains/root/db/bharti.html -bharti - -// bible : American Bible Society -// https://www.iana.org/domains/root/db/bible.html -bible - -// bid : dot Bid Limited -// https://www.iana.org/domains/root/db/bid.html -bid - -// bike : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bike.html -bike - -// bing : Microsoft Corporation -// https://www.iana.org/domains/root/db/bing.html -bing - -// bingo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bingo.html -bingo - -// bio : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/bio.html -bio - -// black : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/black.html -black - -// blackfriday : Registry Services, LLC -// https://www.iana.org/domains/root/db/blackfriday.html -blackfriday - -// blockbuster : Dish DBS Corporation -// https://www.iana.org/domains/root/db/blockbuster.html -blockbuster - -// blog : Knock Knock WHOIS There, LLC -// https://www.iana.org/domains/root/db/blog.html -blog - -// bloomberg : Bloomberg IP Holdings LLC -// https://www.iana.org/domains/root/db/bloomberg.html -bloomberg - -// blue : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/blue.html -blue - -// bms : Bristol-Myers Squibb Company -// https://www.iana.org/domains/root/db/bms.html -bms - -// bmw : Bayerische Motoren Werke Aktiengesellschaft -// https://www.iana.org/domains/root/db/bmw.html -bmw - -// bnpparibas : BNP Paribas -// https://www.iana.org/domains/root/db/bnpparibas.html -bnpparibas - -// boats : XYZ.COM LLC -// https://www.iana.org/domains/root/db/boats.html -boats - -// boehringer : Boehringer Ingelheim International GmbH -// https://www.iana.org/domains/root/db/boehringer.html -boehringer - -// bofa : Bank of America Corporation -// https://www.iana.org/domains/root/db/bofa.html -bofa - -// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br -// https://www.iana.org/domains/root/db/bom.html -bom - -// bond : ShortDot SA -// https://www.iana.org/domains/root/db/bond.html -bond - -// boo : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/boo.html -boo - -// book : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/book.html -book - -// booking : Booking.com B.V. -// https://www.iana.org/domains/root/db/booking.html -booking - -// bosch : Robert Bosch GMBH -// https://www.iana.org/domains/root/db/bosch.html -bosch - -// bostik : Bostik SA -// https://www.iana.org/domains/root/db/bostik.html -bostik - -// boston : Registry Services, LLC -// https://www.iana.org/domains/root/db/boston.html -boston - -// bot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/bot.html -bot - -// boutique : Binky Moon, LLC -// https://www.iana.org/domains/root/db/boutique.html -boutique - -// box : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/box.html -box - -// bradesco : Banco Bradesco S.A. -// https://www.iana.org/domains/root/db/bradesco.html -bradesco - -// bridgestone : Bridgestone Corporation -// https://www.iana.org/domains/root/db/bridgestone.html -bridgestone - -// broadway : Celebrate Broadway, Inc. -// https://www.iana.org/domains/root/db/broadway.html -broadway - -// broker : Dog Beach, LLC -// https://www.iana.org/domains/root/db/broker.html -broker - -// brother : Brother Industries, Ltd. -// https://www.iana.org/domains/root/db/brother.html -brother - -// brussels : DNS.be vzw -// https://www.iana.org/domains/root/db/brussels.html -brussels - -// build : Plan Bee LLC -// https://www.iana.org/domains/root/db/build.html -build - -// builders : Binky Moon, LLC -// https://www.iana.org/domains/root/db/builders.html -builders - -// business : Binky Moon, LLC -// https://www.iana.org/domains/root/db/business.html -business - -// buy : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/buy.html -buy - -// buzz : DOTSTRATEGY CO. -// https://www.iana.org/domains/root/db/buzz.html -buzz - -// bzh : Association www.bzh -// https://www.iana.org/domains/root/db/bzh.html -bzh - -// cab : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cab.html -cab - -// cafe : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cafe.html -cafe - -// cal : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/cal.html -cal - -// call : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/call.html -call - -// calvinklein : PVH gTLD Holdings LLC -// https://www.iana.org/domains/root/db/calvinklein.html -calvinklein - -// cam : Cam Connecting SARL -// https://www.iana.org/domains/root/db/cam.html -cam - -// camera : Binky Moon, LLC -// https://www.iana.org/domains/root/db/camera.html -camera - -// camp : Binky Moon, LLC -// https://www.iana.org/domains/root/db/camp.html -camp - -// canon : Canon Inc. -// https://www.iana.org/domains/root/db/canon.html -canon - -// capetown : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/capetown.html -capetown - -// capital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/capital.html -capital - -// capitalone : Capital One Financial Corporation -// https://www.iana.org/domains/root/db/capitalone.html -capitalone - -// car : XYZ.COM LLC -// https://www.iana.org/domains/root/db/car.html -car - -// caravan : Caravan International, Inc. -// https://www.iana.org/domains/root/db/caravan.html -caravan - -// cards : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cards.html -cards - -// care : Binky Moon, LLC -// https://www.iana.org/domains/root/db/care.html -care - -// career : dotCareer LLC -// https://www.iana.org/domains/root/db/career.html -career - -// careers : Binky Moon, LLC -// https://www.iana.org/domains/root/db/careers.html -careers - -// cars : XYZ.COM LLC -// https://www.iana.org/domains/root/db/cars.html -cars - -// casa : Registry Services, LLC -// https://www.iana.org/domains/root/db/casa.html -casa - -// case : Digity, LLC -// https://www.iana.org/domains/root/db/case.html -case - -// cash : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cash.html -cash - -// casino : Binky Moon, LLC -// https://www.iana.org/domains/root/db/casino.html -casino - -// catering : Binky Moon, LLC -// https://www.iana.org/domains/root/db/catering.html -catering - -// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/catholic.html -catholic - -// cba : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/cba.html -cba - -// cbn : The Christian Broadcasting Network, Inc. -// https://www.iana.org/domains/root/db/cbn.html -cbn - -// cbre : CBRE, Inc. -// https://www.iana.org/domains/root/db/cbre.html -cbre - -// center : Binky Moon, LLC -// https://www.iana.org/domains/root/db/center.html -center - -// ceo : XYZ.COM LLC -// https://www.iana.org/domains/root/db/ceo.html -ceo - -// cern : European Organization for Nuclear Research ("CERN") -// https://www.iana.org/domains/root/db/cern.html -cern - -// cfa : CFA Institute -// https://www.iana.org/domains/root/db/cfa.html -cfa - -// cfd : ShortDot SA -// https://www.iana.org/domains/root/db/cfd.html -cfd - -// chanel : Chanel International B.V. -// https://www.iana.org/domains/root/db/chanel.html -chanel - -// channel : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/channel.html -channel - -// charity : Public Interest Registry -// https://www.iana.org/domains/root/db/charity.html -charity - -// chase : JPMorgan Chase Bank, National Association -// https://www.iana.org/domains/root/db/chase.html -chase - -// chat : Binky Moon, LLC -// https://www.iana.org/domains/root/db/chat.html -chat - -// cheap : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cheap.html -cheap - -// chintai : CHINTAI Corporation -// https://www.iana.org/domains/root/db/chintai.html -chintai - -// christmas : XYZ.COM LLC -// https://www.iana.org/domains/root/db/christmas.html -christmas - -// chrome : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/chrome.html -chrome - -// church : Binky Moon, LLC -// https://www.iana.org/domains/root/db/church.html -church - -// cipriani : Hotel Cipriani Srl -// https://www.iana.org/domains/root/db/cipriani.html -cipriani - -// circle : Jolly Host, LLC -// https://www.iana.org/domains/root/db/circle.html -circle - -// cisco : Cisco Technology, Inc. -// https://www.iana.org/domains/root/db/cisco.html -cisco - -// citadel : Citadel Domain LLC -// https://www.iana.org/domains/root/db/citadel.html -citadel - -// citi : Citigroup Inc. -// https://www.iana.org/domains/root/db/citi.html -citi - -// citic : CITIC Group Corporation -// https://www.iana.org/domains/root/db/citic.html -citic - -// city : Binky Moon, LLC -// https://www.iana.org/domains/root/db/city.html -city - -// claims : Binky Moon, LLC -// https://www.iana.org/domains/root/db/claims.html -claims - -// cleaning : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cleaning.html -cleaning - -// click : Waterford Limited -// https://www.iana.org/domains/root/db/click.html -click - -// clinic : Binky Moon, LLC -// https://www.iana.org/domains/root/db/clinic.html -clinic - -// clinique : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/clinique.html -clinique - -// clothing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/clothing.html -clothing - -// cloud : Aruba PEC S.p.A. -// https://www.iana.org/domains/root/db/cloud.html -cloud - -// club : Registry Services, LLC -// https://www.iana.org/domains/root/db/club.html -club - -// clubmed : Club Méditerranée S.A. -// https://www.iana.org/domains/root/db/clubmed.html -clubmed - -// coach : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coach.html -coach - -// codes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/codes.html -codes - -// coffee : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coffee.html -coffee - -// college : XYZ.COM LLC -// https://www.iana.org/domains/root/db/college.html -college - -// cologne : dotKoeln GmbH -// https://www.iana.org/domains/root/db/cologne.html -cologne - -// commbank : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/commbank.html -commbank - -// community : Binky Moon, LLC -// https://www.iana.org/domains/root/db/community.html -community - -// company : Binky Moon, LLC -// https://www.iana.org/domains/root/db/company.html -company - -// compare : Registry Services, LLC -// https://www.iana.org/domains/root/db/compare.html -compare - -// computer : Binky Moon, LLC -// https://www.iana.org/domains/root/db/computer.html -computer - -// comsec : VeriSign, Inc. -// https://www.iana.org/domains/root/db/comsec.html -comsec - -// condos : Binky Moon, LLC -// https://www.iana.org/domains/root/db/condos.html -condos - -// construction : Binky Moon, LLC -// https://www.iana.org/domains/root/db/construction.html -construction - -// consulting : Dog Beach, LLC -// https://www.iana.org/domains/root/db/consulting.html -consulting - -// contact : Dog Beach, LLC -// https://www.iana.org/domains/root/db/contact.html -contact - -// contractors : Binky Moon, LLC -// https://www.iana.org/domains/root/db/contractors.html -contractors - -// cooking : Registry Services, LLC -// https://www.iana.org/domains/root/db/cooking.html -cooking - -// cool : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cool.html -cool - -// corsica : Collectivité de Corse -// https://www.iana.org/domains/root/db/corsica.html -corsica - -// country : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/country.html -country - -// coupon : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/coupon.html -coupon - -// coupons : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coupons.html -coupons - -// courses : Registry Services, LLC -// https://www.iana.org/domains/root/db/courses.html -courses - -// cpa : American Institute of Certified Public Accountants -// https://www.iana.org/domains/root/db/cpa.html -cpa - -// credit : Binky Moon, LLC -// https://www.iana.org/domains/root/db/credit.html -credit - -// creditcard : Binky Moon, LLC -// https://www.iana.org/domains/root/db/creditcard.html -creditcard - -// creditunion : DotCooperation LLC -// https://www.iana.org/domains/root/db/creditunion.html -creditunion - -// cricket : dot Cricket Limited -// https://www.iana.org/domains/root/db/cricket.html -cricket - -// crown : Crown Equipment Corporation -// https://www.iana.org/domains/root/db/crown.html -crown - -// crs : Federated Co-operatives Limited -// https://www.iana.org/domains/root/db/crs.html -crs - -// cruise : Viking River Cruises (Bermuda) Ltd. -// https://www.iana.org/domains/root/db/cruise.html -cruise - -// cruises : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cruises.html -cruises - -// cuisinella : SCHMIDT GROUPE S.A.S. -// https://www.iana.org/domains/root/db/cuisinella.html -cuisinella - -// cymru : Nominet UK -// https://www.iana.org/domains/root/db/cymru.html -cymru - -// cyou : ShortDot SA -// https://www.iana.org/domains/root/db/cyou.html -cyou - -// dad : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dad.html -dad - -// dance : Dog Beach, LLC -// https://www.iana.org/domains/root/db/dance.html -dance - -// data : Dish DBS Corporation -// https://www.iana.org/domains/root/db/data.html -data - -// date : dot Date Limited -// https://www.iana.org/domains/root/db/date.html -date - -// dating : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dating.html -dating - -// datsun : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/datsun.html -datsun - -// day : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/day.html -day - -// dclk : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dclk.html -dclk - -// dds : Registry Services, LLC -// https://www.iana.org/domains/root/db/dds.html -dds - -// deal : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/deal.html -deal - -// dealer : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/dealer.html -dealer - -// deals : Binky Moon, LLC -// https://www.iana.org/domains/root/db/deals.html -deals - -// degree : Dog Beach, LLC -// https://www.iana.org/domains/root/db/degree.html -degree - -// delivery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/delivery.html -delivery - -// dell : Dell Inc. -// https://www.iana.org/domains/root/db/dell.html -dell - -// deloitte : Deloitte Touche Tohmatsu -// https://www.iana.org/domains/root/db/deloitte.html -deloitte - -// delta : Delta Air Lines, Inc. -// https://www.iana.org/domains/root/db/delta.html -delta - -// democrat : Dog Beach, LLC -// https://www.iana.org/domains/root/db/democrat.html -democrat - -// dental : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dental.html -dental - -// dentist : Dog Beach, LLC -// https://www.iana.org/domains/root/db/dentist.html -dentist - -// desi -// https://www.iana.org/domains/root/db/desi.html -desi - -// design : Registry Services, LLC -// https://www.iana.org/domains/root/db/design.html -design - -// dev : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dev.html -dev - -// dhl : Deutsche Post AG -// https://www.iana.org/domains/root/db/dhl.html -dhl - -// diamonds : Binky Moon, LLC -// https://www.iana.org/domains/root/db/diamonds.html -diamonds - -// diet : XYZ.COM LLC -// https://www.iana.org/domains/root/db/diet.html -diet - -// digital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/digital.html -digital - -// direct : Binky Moon, LLC -// https://www.iana.org/domains/root/db/direct.html -direct - -// directory : Binky Moon, LLC -// https://www.iana.org/domains/root/db/directory.html -directory - -// discount : Binky Moon, LLC -// https://www.iana.org/domains/root/db/discount.html -discount - -// discover : Discover Financial Services -// https://www.iana.org/domains/root/db/discover.html -discover - -// dish : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dish.html -dish - -// diy : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/diy.html -diy - -// dnp : Dai Nippon Printing Co., Ltd. -// https://www.iana.org/domains/root/db/dnp.html -dnp - -// docs : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/docs.html -docs - -// doctor : Binky Moon, LLC -// https://www.iana.org/domains/root/db/doctor.html -doctor - -// dog : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dog.html -dog - -// domains : Binky Moon, LLC -// https://www.iana.org/domains/root/db/domains.html -domains - -// dot : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dot.html -dot - -// download : dot Support Limited -// https://www.iana.org/domains/root/db/download.html -download - -// drive : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/drive.html -drive - -// dtv : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dtv.html -dtv - -// dubai : Dubai Smart Government Department -// https://www.iana.org/domains/root/db/dubai.html -dubai - -// dupont : DuPont Specialty Products USA, LLC -// https://www.iana.org/domains/root/db/dupont.html -dupont - -// durban : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/durban.html -durban - -// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/dvag.html -dvag - -// dvr : DISH Technologies L.L.C. -// https://www.iana.org/domains/root/db/dvr.html -dvr - -// earth : Interlink Systems Innovation Institute K.K. -// https://www.iana.org/domains/root/db/earth.html -earth - -// eat : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/eat.html -eat - -// eco : Big Room Inc. -// https://www.iana.org/domains/root/db/eco.html -eco - -// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V. -// https://www.iana.org/domains/root/db/edeka.html -edeka - -// education : Binky Moon, LLC -// https://www.iana.org/domains/root/db/education.html -education - -// email : Binky Moon, LLC -// https://www.iana.org/domains/root/db/email.html -email - -// emerck : Merck KGaA -// https://www.iana.org/domains/root/db/emerck.html -emerck - -// energy : Binky Moon, LLC -// https://www.iana.org/domains/root/db/energy.html -energy - -// engineer : Dog Beach, LLC -// https://www.iana.org/domains/root/db/engineer.html -engineer - -// engineering : Binky Moon, LLC -// https://www.iana.org/domains/root/db/engineering.html -engineering - -// enterprises : Binky Moon, LLC -// https://www.iana.org/domains/root/db/enterprises.html -enterprises - -// epson : Seiko Epson Corporation -// https://www.iana.org/domains/root/db/epson.html -epson - -// equipment : Binky Moon, LLC -// https://www.iana.org/domains/root/db/equipment.html -equipment - -// ericsson : Telefonaktiebolaget L M Ericsson -// https://www.iana.org/domains/root/db/ericsson.html -ericsson - -// erni : ERNI Group Holding AG -// https://www.iana.org/domains/root/db/erni.html -erni - -// esq : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/esq.html -esq - -// estate : Binky Moon, LLC -// https://www.iana.org/domains/root/db/estate.html -estate - -// eurovision : European Broadcasting Union (EBU) -// https://www.iana.org/domains/root/db/eurovision.html -eurovision - -// eus : Puntueus Fundazioa -// https://www.iana.org/domains/root/db/eus.html -eus - -// events : Binky Moon, LLC -// https://www.iana.org/domains/root/db/events.html -events - -// exchange : Binky Moon, LLC -// https://www.iana.org/domains/root/db/exchange.html -exchange - -// expert : Binky Moon, LLC -// https://www.iana.org/domains/root/db/expert.html -expert - -// exposed : Binky Moon, LLC -// https://www.iana.org/domains/root/db/exposed.html -exposed - -// express : Binky Moon, LLC -// https://www.iana.org/domains/root/db/express.html -express - -// extraspace : Extra Space Storage LLC -// https://www.iana.org/domains/root/db/extraspace.html -extraspace - -// fage : Fage International S.A. -// https://www.iana.org/domains/root/db/fage.html -fage - -// fail : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fail.html -fail - -// fairwinds : FairWinds Partners, LLC -// https://www.iana.org/domains/root/db/fairwinds.html -fairwinds - -// faith : dot Faith Limited -// https://www.iana.org/domains/root/db/faith.html -faith - -// family : Dog Beach, LLC -// https://www.iana.org/domains/root/db/family.html -family - -// fan : Dog Beach, LLC -// https://www.iana.org/domains/root/db/fan.html -fan - -// fans : ZDNS International Limited -// https://www.iana.org/domains/root/db/fans.html -fans - -// farm : Binky Moon, LLC -// https://www.iana.org/domains/root/db/farm.html -farm - -// farmers : Farmers Insurance Exchange -// https://www.iana.org/domains/root/db/farmers.html -farmers - -// fashion : Registry Services, LLC -// https://www.iana.org/domains/root/db/fashion.html -fashion - -// fast : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/fast.html -fast - -// fedex : Federal Express Corporation -// https://www.iana.org/domains/root/db/fedex.html -fedex - -// feedback : Top Level Spectrum, Inc. -// https://www.iana.org/domains/root/db/feedback.html -feedback - -// ferrari : Fiat Chrysler Automobiles N.V. -// https://www.iana.org/domains/root/db/ferrari.html -ferrari - -// ferrero : Ferrero Trading Lux S.A. -// https://www.iana.org/domains/root/db/ferrero.html -ferrero - -// fidelity : Fidelity Brokerage Services LLC -// https://www.iana.org/domains/root/db/fidelity.html -fidelity - -// fido : Rogers Communications Canada Inc. -// https://www.iana.org/domains/root/db/fido.html -fido - -// film : Motion Picture Domain Registry Pty Ltd -// https://www.iana.org/domains/root/db/film.html -film - -// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br -// https://www.iana.org/domains/root/db/final.html -final - -// finance : Binky Moon, LLC -// https://www.iana.org/domains/root/db/finance.html -finance - -// financial : Binky Moon, LLC -// https://www.iana.org/domains/root/db/financial.html -financial - -// fire : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/fire.html -fire - -// firestone : Bridgestone Licensing Services, Inc -// https://www.iana.org/domains/root/db/firestone.html -firestone - -// firmdale : Firmdale Holdings Limited -// https://www.iana.org/domains/root/db/firmdale.html -firmdale - -// fish : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fish.html -fish - -// fishing : Registry Services, LLC -// https://www.iana.org/domains/root/db/fishing.html -fishing - -// fit : Registry Services, LLC -// https://www.iana.org/domains/root/db/fit.html -fit - -// fitness : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fitness.html -fitness - -// flickr : Flickr, Inc. -// https://www.iana.org/domains/root/db/flickr.html -flickr - -// flights : Binky Moon, LLC -// https://www.iana.org/domains/root/db/flights.html -flights - -// flir : FLIR Systems, Inc. -// https://www.iana.org/domains/root/db/flir.html -flir - -// florist : Binky Moon, LLC -// https://www.iana.org/domains/root/db/florist.html -florist - -// flowers : XYZ.COM LLC -// https://www.iana.org/domains/root/db/flowers.html -flowers - -// fly : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/fly.html -fly - -// foo : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/foo.html -foo - -// food : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/food.html -food - -// football : Binky Moon, LLC -// https://www.iana.org/domains/root/db/football.html -football - -// ford : Ford Motor Company -// https://www.iana.org/domains/root/db/ford.html -ford - -// forex : Dog Beach, LLC -// https://www.iana.org/domains/root/db/forex.html -forex - -// forsale : Dog Beach, LLC -// https://www.iana.org/domains/root/db/forsale.html -forsale - -// forum : Waterford Limited -// https://www.iana.org/domains/root/db/forum.html -forum - -// foundation : Public Interest Registry -// https://www.iana.org/domains/root/db/foundation.html -foundation - -// fox : FOX Registry, LLC -// https://www.iana.org/domains/root/db/fox.html -fox - -// free : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/free.html -free - -// fresenius : Fresenius Immobilien-Verwaltungs-GmbH -// https://www.iana.org/domains/root/db/fresenius.html -fresenius - -// frl : FRLregistry B.V. -// https://www.iana.org/domains/root/db/frl.html -frl - -// frogans : OP3FT -// https://www.iana.org/domains/root/db/frogans.html -frogans - -// frontier : Frontier Communications Corporation -// https://www.iana.org/domains/root/db/frontier.html -frontier - -// ftr : Frontier Communications Corporation -// https://www.iana.org/domains/root/db/ftr.html -ftr - -// fujitsu : Fujitsu Limited -// https://www.iana.org/domains/root/db/fujitsu.html -fujitsu - -// fun : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/fun.html -fun - -// fund : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fund.html -fund - -// furniture : Binky Moon, LLC -// https://www.iana.org/domains/root/db/furniture.html -furniture - -// futbol : Dog Beach, LLC -// https://www.iana.org/domains/root/db/futbol.html -futbol - -// fyi : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fyi.html -fyi - -// gal : Asociación puntoGAL -// https://www.iana.org/domains/root/db/gal.html -gal - -// gallery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gallery.html -gallery - -// gallo : Gallo Vineyards, Inc. -// https://www.iana.org/domains/root/db/gallo.html -gallo - -// gallup : Gallup, Inc. -// https://www.iana.org/domains/root/db/gallup.html -gallup - -// game : XYZ.COM LLC -// https://www.iana.org/domains/root/db/game.html -game - -// games : Dog Beach, LLC -// https://www.iana.org/domains/root/db/games.html -games - -// gap : The Gap, Inc. -// https://www.iana.org/domains/root/db/gap.html -gap - -// garden : Registry Services, LLC -// https://www.iana.org/domains/root/db/garden.html -garden - -// gay : Registry Services, LLC -// https://www.iana.org/domains/root/db/gay.html -gay - -// gbiz : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gbiz.html -gbiz - -// gdn : Joint Stock Company "Navigation-information systems" -// https://www.iana.org/domains/root/db/gdn.html -gdn - -// gea : GEA Group Aktiengesellschaft -// https://www.iana.org/domains/root/db/gea.html -gea - -// gent : Easyhost BV -// https://www.iana.org/domains/root/db/gent.html -gent - -// genting : Resorts World Inc Pte. Ltd. -// https://www.iana.org/domains/root/db/genting.html -genting - -// george : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/george.html -george - -// ggee : GMO Internet, Inc. -// https://www.iana.org/domains/root/db/ggee.html -ggee - -// gift : DotGift, LLC -// https://www.iana.org/domains/root/db/gift.html -gift - -// gifts : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gifts.html -gifts - -// gives : Public Interest Registry -// https://www.iana.org/domains/root/db/gives.html -gives - -// giving : Public Interest Registry -// https://www.iana.org/domains/root/db/giving.html -giving - -// glass : Binky Moon, LLC -// https://www.iana.org/domains/root/db/glass.html -glass - -// gle : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gle.html -gle - -// global : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/global.html -global - -// globo : Globo Comunicação e Participações S.A -// https://www.iana.org/domains/root/db/globo.html -globo - -// gmail : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gmail.html -gmail - -// gmbh : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gmbh.html -gmbh - -// gmo : GMO Internet, Inc. -// https://www.iana.org/domains/root/db/gmo.html -gmo - -// gmx : 1&1 Mail & Media GmbH -// https://www.iana.org/domains/root/db/gmx.html -gmx - -// godaddy : Go Daddy East, LLC -// https://www.iana.org/domains/root/db/godaddy.html -godaddy - -// gold : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gold.html -gold - -// goldpoint : YODOBASHI CAMERA CO.,LTD. -// https://www.iana.org/domains/root/db/goldpoint.html -goldpoint - -// golf : Binky Moon, LLC -// https://www.iana.org/domains/root/db/golf.html -golf - -// goodyear : The Goodyear Tire & Rubber Company -// https://www.iana.org/domains/root/db/goodyear.html -goodyear - -// goog : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/goog.html -goog - -// google : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/google.html -google - -// gop : Republican State Leadership Committee, Inc. -// https://www.iana.org/domains/root/db/gop.html -gop - -// got : Jolly Host, LLC -// https://www.iana.org/domains/root/db/got.html -got - -// grainger : Grainger Registry Services, LLC -// https://www.iana.org/domains/root/db/grainger.html -grainger - -// graphics : Binky Moon, LLC -// https://www.iana.org/domains/root/db/graphics.html -graphics - -// gratis : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gratis.html -gratis - -// green : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/green.html -green - -// gripe : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gripe.html -gripe - -// grocery : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/grocery.html -grocery - -// group : Binky Moon, LLC -// https://www.iana.org/domains/root/db/group.html -group - -// gucci : Guccio Gucci S.p.a. -// https://www.iana.org/domains/root/db/gucci.html -gucci - -// guge : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/guge.html -guge - -// guide : Binky Moon, LLC -// https://www.iana.org/domains/root/db/guide.html -guide - -// guitars : XYZ.COM LLC -// https://www.iana.org/domains/root/db/guitars.html -guitars - -// guru : Binky Moon, LLC -// https://www.iana.org/domains/root/db/guru.html -guru - -// hair : XYZ.COM LLC -// https://www.iana.org/domains/root/db/hair.html -hair - -// hamburg : Hamburg Top-Level-Domain GmbH -// https://www.iana.org/domains/root/db/hamburg.html -hamburg - -// hangout : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/hangout.html -hangout - -// haus : Dog Beach, LLC -// https://www.iana.org/domains/root/db/haus.html -haus - -// hbo : HBO Registry Services, Inc. -// https://www.iana.org/domains/root/db/hbo.html -hbo - -// hdfc : HDFC BANK LIMITED -// https://www.iana.org/domains/root/db/hdfc.html -hdfc - -// hdfcbank : HDFC BANK LIMITED -// https://www.iana.org/domains/root/db/hdfcbank.html -hdfcbank - -// health : Registry Services, LLC -// https://www.iana.org/domains/root/db/health.html -health - -// healthcare : Binky Moon, LLC -// https://www.iana.org/domains/root/db/healthcare.html -healthcare - -// help : Innovation service Limited -// https://www.iana.org/domains/root/db/help.html -help - -// helsinki : City of Helsinki -// https://www.iana.org/domains/root/db/helsinki.html -helsinki - -// here : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/here.html -here - -// hermes : HERMES INTERNATIONAL -// https://www.iana.org/domains/root/db/hermes.html -hermes - -// hiphop : Dot Hip Hop, LLC -// https://www.iana.org/domains/root/db/hiphop.html -hiphop - -// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc. -// https://www.iana.org/domains/root/db/hisamitsu.html -hisamitsu - -// hitachi : Hitachi, Ltd. -// https://www.iana.org/domains/root/db/hitachi.html -hitachi - -// hiv : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/hiv.html -hiv - -// hkt : PCCW-HKT DataCom Services Limited -// https://www.iana.org/domains/root/db/hkt.html -hkt - -// hockey : Binky Moon, LLC -// https://www.iana.org/domains/root/db/hockey.html -hockey - -// holdings : Binky Moon, LLC -// https://www.iana.org/domains/root/db/holdings.html -holdings - -// holiday : Binky Moon, LLC -// https://www.iana.org/domains/root/db/holiday.html -holiday - -// homedepot : Home Depot Product Authority, LLC -// https://www.iana.org/domains/root/db/homedepot.html -homedepot - -// homegoods : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/homegoods.html -homegoods - -// homes : XYZ.COM LLC -// https://www.iana.org/domains/root/db/homes.html -homes - -// homesense : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/homesense.html -homesense - -// honda : Honda Motor Co., Ltd. -// https://www.iana.org/domains/root/db/honda.html -honda - -// horse : Registry Services, LLC -// https://www.iana.org/domains/root/db/horse.html -horse - -// hospital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/hospital.html -hospital - -// host : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/host.html -host - -// hosting : XYZ.COM LLC -// https://www.iana.org/domains/root/db/hosting.html -hosting - -// hot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/hot.html -hot - -// hotel : HOTEL Top-Level-Domain S.a.r.l -// https://www.iana.org/domains/root/db/hotel.html -hotel - -// hotels : Booking.com B.V. -// https://www.iana.org/domains/root/db/hotels.html -hotels - -// hotmail : Microsoft Corporation -// https://www.iana.org/domains/root/db/hotmail.html -hotmail - -// house : Binky Moon, LLC -// https://www.iana.org/domains/root/db/house.html -house - -// how : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/how.html -how - -// hsbc : HSBC Global Services (UK) Limited -// https://www.iana.org/domains/root/db/hsbc.html -hsbc - -// hughes : Hughes Satellite Systems Corporation -// https://www.iana.org/domains/root/db/hughes.html -hughes - -// hyatt : Hyatt GTLD, L.L.C. -// https://www.iana.org/domains/root/db/hyatt.html -hyatt - -// hyundai : Hyundai Motor Company -// https://www.iana.org/domains/root/db/hyundai.html -hyundai - -// ibm : International Business Machines Corporation -// https://www.iana.org/domains/root/db/ibm.html -ibm - -// icbc : Industrial and Commercial Bank of China Limited -// https://www.iana.org/domains/root/db/icbc.html -icbc - -// ice : IntercontinentalExchange, Inc. -// https://www.iana.org/domains/root/db/ice.html -ice - -// icu : ShortDot SA -// https://www.iana.org/domains/root/db/icu.html -icu - -// ieee : IEEE Global LLC -// https://www.iana.org/domains/root/db/ieee.html -ieee - -// ifm : ifm electronic gmbh -// https://www.iana.org/domains/root/db/ifm.html -ifm - -// ikano : Ikano S.A. -// https://www.iana.org/domains/root/db/ikano.html -ikano - -// imamat : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/imamat.html -imamat - -// imdb : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/imdb.html -imdb - -// immo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/immo.html -immo - -// immobilien : Dog Beach, LLC -// https://www.iana.org/domains/root/db/immobilien.html -immobilien - -// inc : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/inc.html -inc - -// industries : Binky Moon, LLC -// https://www.iana.org/domains/root/db/industries.html -industries - -// infiniti : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/infiniti.html -infiniti - -// ing : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/ing.html -ing - -// ink : Registry Services, LLC -// https://www.iana.org/domains/root/db/ink.html -ink - -// institute : Binky Moon, LLC -// https://www.iana.org/domains/root/db/institute.html -institute - -// insurance : fTLD Registry Services LLC -// https://www.iana.org/domains/root/db/insurance.html -insurance - -// insure : Binky Moon, LLC -// https://www.iana.org/domains/root/db/insure.html -insure - -// international : Binky Moon, LLC -// https://www.iana.org/domains/root/db/international.html -international - -// intuit : Intuit Administrative Services, Inc. -// https://www.iana.org/domains/root/db/intuit.html -intuit - -// investments : Binky Moon, LLC -// https://www.iana.org/domains/root/db/investments.html -investments - -// ipiranga : Ipiranga Produtos de Petroleo S.A. -// https://www.iana.org/domains/root/db/ipiranga.html -ipiranga - -// irish : Binky Moon, LLC -// https://www.iana.org/domains/root/db/irish.html -irish - -// ismaili : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/ismaili.html -ismaili - -// ist : Istanbul Metropolitan Municipality -// https://www.iana.org/domains/root/db/ist.html -ist - -// istanbul : Istanbul Metropolitan Municipality -// https://www.iana.org/domains/root/db/istanbul.html -istanbul - -// itau : Itau Unibanco Holding S.A. -// https://www.iana.org/domains/root/db/itau.html -itau - -// itv : ITV Services Limited -// https://www.iana.org/domains/root/db/itv.html -itv - -// jaguar : Jaguar Land Rover Ltd -// https://www.iana.org/domains/root/db/jaguar.html -jaguar - -// java : Oracle Corporation -// https://www.iana.org/domains/root/db/java.html -java - -// jcb : JCB Co., Ltd. -// https://www.iana.org/domains/root/db/jcb.html -jcb - -// jeep : FCA US LLC. -// https://www.iana.org/domains/root/db/jeep.html -jeep - -// jetzt : Binky Moon, LLC -// https://www.iana.org/domains/root/db/jetzt.html -jetzt - -// jewelry : Binky Moon, LLC -// https://www.iana.org/domains/root/db/jewelry.html -jewelry - -// jio : Reliance Industries Limited -// https://www.iana.org/domains/root/db/jio.html -jio - -// jll : Jones Lang LaSalle Incorporated -// https://www.iana.org/domains/root/db/jll.html -jll - -// jmp : Matrix IP LLC -// https://www.iana.org/domains/root/db/jmp.html -jmp - -// jnj : Johnson & Johnson Services, Inc. -// https://www.iana.org/domains/root/db/jnj.html -jnj - -// joburg : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/joburg.html -joburg - -// jot : Jolly Host, LLC -// https://www.iana.org/domains/root/db/jot.html -jot - -// joy : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/joy.html -joy - -// jpmorgan : JPMorgan Chase Bank, National Association -// https://www.iana.org/domains/root/db/jpmorgan.html -jpmorgan - -// jprs : Japan Registry Services Co., Ltd. -// https://www.iana.org/domains/root/db/jprs.html -jprs - -// juegos : Dog Beach, LLC -// https://www.iana.org/domains/root/db/juegos.html -juegos - -// juniper : JUNIPER NETWORKS, INC. -// https://www.iana.org/domains/root/db/juniper.html -juniper - -// kaufen : Dog Beach, LLC -// https://www.iana.org/domains/root/db/kaufen.html -kaufen - -// kddi : KDDI CORPORATION -// https://www.iana.org/domains/root/db/kddi.html -kddi - -// kerryhotels : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kerryhotels.html -kerryhotels - -// kerryproperties : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kerryproperties.html -kerryproperties - -// kfh : Kuwait Finance House -// https://www.iana.org/domains/root/db/kfh.html -kfh - -// kia : KIA MOTORS CORPORATION -// https://www.iana.org/domains/root/db/kia.html -kia - -// kids : DotKids Foundation Limited -// https://www.iana.org/domains/root/db/kids.html -kids - -// kim : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/kim.html -kim - -// kindle : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/kindle.html -kindle - -// kitchen : Binky Moon, LLC -// https://www.iana.org/domains/root/db/kitchen.html -kitchen - -// kiwi : DOT KIWI LIMITED -// https://www.iana.org/domains/root/db/kiwi.html -kiwi - -// koeln : dotKoeln GmbH -// https://www.iana.org/domains/root/db/koeln.html -koeln - -// komatsu : Komatsu Ltd. -// https://www.iana.org/domains/root/db/komatsu.html -komatsu - -// kosher : Kosher Marketing Assets LLC -// https://www.iana.org/domains/root/db/kosher.html -kosher - -// kpmg : KPMG International Cooperative (KPMG International Genossenschaft) -// https://www.iana.org/domains/root/db/kpmg.html -kpmg - -// kpn : Koninklijke KPN N.V. -// https://www.iana.org/domains/root/db/kpn.html -kpn - -// krd : KRG Department of Information Technology -// https://www.iana.org/domains/root/db/krd.html -krd - -// kred : KredTLD Pty Ltd -// https://www.iana.org/domains/root/db/kred.html -kred - -// kuokgroup : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kuokgroup.html -kuokgroup - -// kyoto : Academic Institution: The University of Informatics -// https://www.iana.org/domains/root/db/kyoto.html -kyoto - -// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” -// https://www.iana.org/domains/root/db/lacaixa.html -lacaixa - -// lamborghini : Automobili Lamborghini S.p.A. -// https://www.iana.org/domains/root/db/lamborghini.html -lamborghini - -// lamer : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/lamer.html -lamer - -// land : Binky Moon, LLC -// https://www.iana.org/domains/root/db/land.html -land - -// landrover : Jaguar Land Rover Ltd -// https://www.iana.org/domains/root/db/landrover.html -landrover - -// lanxess : LANXESS Corporation -// https://www.iana.org/domains/root/db/lanxess.html -lanxess - -// lasalle : Jones Lang LaSalle Incorporated -// https://www.iana.org/domains/root/db/lasalle.html -lasalle - -// lat : XYZ.COM LLC -// https://www.iana.org/domains/root/db/lat.html -lat - -// latino : Dish DBS Corporation -// https://www.iana.org/domains/root/db/latino.html -latino - -// latrobe : La Trobe University -// https://www.iana.org/domains/root/db/latrobe.html -latrobe - -// law : Registry Services, LLC -// https://www.iana.org/domains/root/db/law.html -law - -// lawyer : Dog Beach, LLC -// https://www.iana.org/domains/root/db/lawyer.html -lawyer - -// lds : IRI Domain Management, LLC -// https://www.iana.org/domains/root/db/lds.html -lds - -// lease : Binky Moon, LLC -// https://www.iana.org/domains/root/db/lease.html -lease - -// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc -// https://www.iana.org/domains/root/db/leclerc.html -leclerc - -// lefrak : LeFrak Organization, Inc. -// https://www.iana.org/domains/root/db/lefrak.html -lefrak - -// legal : Binky Moon, LLC -// https://www.iana.org/domains/root/db/legal.html -legal - -// lego : LEGO Juris A/S -// https://www.iana.org/domains/root/db/lego.html -lego - -// lexus : TOYOTA MOTOR CORPORATION -// https://www.iana.org/domains/root/db/lexus.html -lexus - -// lgbt : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/lgbt.html -lgbt - -// lidl : Schwarz Domains und Services GmbH & Co. KG -// https://www.iana.org/domains/root/db/lidl.html -lidl - -// life : Binky Moon, LLC -// https://www.iana.org/domains/root/db/life.html -life - -// lifeinsurance : American Council of Life Insurers -// https://www.iana.org/domains/root/db/lifeinsurance.html -lifeinsurance - -// lifestyle : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/lifestyle.html -lifestyle - -// lighting : Binky Moon, LLC -// https://www.iana.org/domains/root/db/lighting.html -lighting - -// like : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/like.html -like - -// lilly : Eli Lilly and Company -// https://www.iana.org/domains/root/db/lilly.html -lilly - -// limited : Binky Moon, LLC -// https://www.iana.org/domains/root/db/limited.html -limited - -// limo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/limo.html -limo - -// lincoln : Ford Motor Company -// https://www.iana.org/domains/root/db/lincoln.html -lincoln - -// link : Nova Registry Ltd -// https://www.iana.org/domains/root/db/link.html -link - -// live : Dog Beach, LLC -// https://www.iana.org/domains/root/db/live.html -live - -// living : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/living.html -living - -// llc : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/llc.html -llc - -// llp : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/llp.html -llp - -// loan : dot Loan Limited -// https://www.iana.org/domains/root/db/loan.html -loan - -// loans : Binky Moon, LLC -// https://www.iana.org/domains/root/db/loans.html -loans - -// locker : Orange Domains LLC -// https://www.iana.org/domains/root/db/locker.html -locker - -// locus : Locus Analytics LLC -// https://www.iana.org/domains/root/db/locus.html -locus - -// lol : XYZ.COM LLC -// https://www.iana.org/domains/root/db/lol.html -lol - -// london : Dot London Domains Limited -// https://www.iana.org/domains/root/db/london.html -london - -// lotte : Lotte Holdings Co., Ltd. -// https://www.iana.org/domains/root/db/lotte.html -lotte - -// lotto : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/lotto.html -lotto - -// love : Waterford Limited -// https://www.iana.org/domains/root/db/love.html -love - -// lpl : LPL Holdings, Inc. -// https://www.iana.org/domains/root/db/lpl.html -lpl - -// lplfinancial : LPL Holdings, Inc. -// https://www.iana.org/domains/root/db/lplfinancial.html -lplfinancial - -// ltd : Binky Moon, LLC -// https://www.iana.org/domains/root/db/ltd.html -ltd - -// ltda : InterNetX, Corp -// https://www.iana.org/domains/root/db/ltda.html -ltda - -// lundbeck : H. Lundbeck A/S -// https://www.iana.org/domains/root/db/lundbeck.html -lundbeck - -// luxe : Registry Services, LLC -// https://www.iana.org/domains/root/db/luxe.html -luxe - -// luxury : Luxury Partners, LLC -// https://www.iana.org/domains/root/db/luxury.html -luxury - -// madrid : Comunidad de Madrid -// https://www.iana.org/domains/root/db/madrid.html -madrid - -// maif : Mutuelle Assurance Instituteur France (MAIF) -// https://www.iana.org/domains/root/db/maif.html -maif - -// maison : Binky Moon, LLC -// https://www.iana.org/domains/root/db/maison.html -maison - -// makeup : XYZ.COM LLC -// https://www.iana.org/domains/root/db/makeup.html -makeup - -// man : MAN Truck & Bus SE -// https://www.iana.org/domains/root/db/man.html -man - -// management : Binky Moon, LLC -// https://www.iana.org/domains/root/db/management.html -management - -// mango : PUNTO FA S.L. -// https://www.iana.org/domains/root/db/mango.html -mango - -// map : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/map.html -map - -// market : Dog Beach, LLC -// https://www.iana.org/domains/root/db/market.html -market - -// marketing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/marketing.html -marketing - -// markets : Dog Beach, LLC -// https://www.iana.org/domains/root/db/markets.html -markets - -// marriott : Marriott Worldwide Corporation -// https://www.iana.org/domains/root/db/marriott.html -marriott - -// marshalls : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/marshalls.html -marshalls - -// mattel : Mattel IT Services, Inc. -// https://www.iana.org/domains/root/db/mattel.html -mattel - -// mba : Binky Moon, LLC -// https://www.iana.org/domains/root/db/mba.html -mba - -// mckinsey : McKinsey Holdings, Inc. -// https://www.iana.org/domains/root/db/mckinsey.html -mckinsey - -// med : Medistry LLC -// https://www.iana.org/domains/root/db/med.html -med - -// media : Binky Moon, LLC -// https://www.iana.org/domains/root/db/media.html -media - -// meet : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/meet.html -meet - -// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation -// https://www.iana.org/domains/root/db/melbourne.html -melbourne - -// meme : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/meme.html -meme - -// memorial : Dog Beach, LLC -// https://www.iana.org/domains/root/db/memorial.html -memorial - -// men : Exclusive Registry Limited -// https://www.iana.org/domains/root/db/men.html -men - -// menu : Dot Menu Registry, LLC -// https://www.iana.org/domains/root/db/menu.html -menu - -// merck : Merck Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/merck.html -merck - -// merckmsd : MSD Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/merckmsd.html -merckmsd - -// miami : Registry Services, LLC -// https://www.iana.org/domains/root/db/miami.html -miami - -// microsoft : Microsoft Corporation -// https://www.iana.org/domains/root/db/microsoft.html -microsoft - -// mini : Bayerische Motoren Werke Aktiengesellschaft -// https://www.iana.org/domains/root/db/mini.html -mini - -// mint : Intuit Administrative Services, Inc. -// https://www.iana.org/domains/root/db/mint.html -mint - -// mit : Massachusetts Institute of Technology -// https://www.iana.org/domains/root/db/mit.html -mit - -// mitsubishi : Mitsubishi Corporation -// https://www.iana.org/domains/root/db/mitsubishi.html -mitsubishi - -// mlb : MLB Advanced Media DH, LLC -// https://www.iana.org/domains/root/db/mlb.html -mlb - -// mls : The Canadian Real Estate Association -// https://www.iana.org/domains/root/db/mls.html -mls - -// mma : MMA IARD -// https://www.iana.org/domains/root/db/mma.html -mma - -// mobile : Dish DBS Corporation -// https://www.iana.org/domains/root/db/mobile.html -mobile - -// moda : Dog Beach, LLC -// https://www.iana.org/domains/root/db/moda.html -moda - -// moe : Interlink Systems Innovation Institute K.K. -// https://www.iana.org/domains/root/db/moe.html -moe - -// moi : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/moi.html -moi - -// mom : XYZ.COM LLC -// https://www.iana.org/domains/root/db/mom.html -mom - -// monash : Monash University -// https://www.iana.org/domains/root/db/monash.html -monash - -// money : Binky Moon, LLC -// https://www.iana.org/domains/root/db/money.html -money - -// monster : XYZ.COM LLC -// https://www.iana.org/domains/root/db/monster.html -monster - -// mormon : IRI Domain Management, LLC -// https://www.iana.org/domains/root/db/mormon.html -mormon - -// mortgage : Dog Beach, LLC -// https://www.iana.org/domains/root/db/mortgage.html -mortgage - -// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) -// https://www.iana.org/domains/root/db/moscow.html -moscow - -// moto : Motorola Trademark Holdings, LLC -// https://www.iana.org/domains/root/db/moto.html -moto - -// motorcycles : XYZ.COM LLC -// https://www.iana.org/domains/root/db/motorcycles.html -motorcycles - -// mov : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/mov.html -mov - -// movie : Binky Moon, LLC -// https://www.iana.org/domains/root/db/movie.html -movie - -// msd : MSD Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/msd.html -msd - -// mtn : MTN Dubai Limited -// https://www.iana.org/domains/root/db/mtn.html -mtn - -// mtr : MTR Corporation Limited -// https://www.iana.org/domains/root/db/mtr.html -mtr - -// music : DotMusic Limited -// https://www.iana.org/domains/root/db/music.html -music - -// nab : National Australia Bank Limited -// https://www.iana.org/domains/root/db/nab.html -nab - -// nagoya : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/nagoya.html -nagoya - -// navy : Dog Beach, LLC -// https://www.iana.org/domains/root/db/navy.html -navy - -// nba : NBA REGISTRY, LLC -// https://www.iana.org/domains/root/db/nba.html -nba - -// nec : NEC Corporation -// https://www.iana.org/domains/root/db/nec.html -nec - -// netbank : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/netbank.html -netbank - -// netflix : Netflix, Inc. -// https://www.iana.org/domains/root/db/netflix.html -netflix - -// network : Binky Moon, LLC -// https://www.iana.org/domains/root/db/network.html -network - -// neustar : NeuStar, Inc. -// https://www.iana.org/domains/root/db/neustar.html -neustar - -// new : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/new.html -new - -// news : Dog Beach, LLC -// https://www.iana.org/domains/root/db/news.html -news - -// next : Next plc -// https://www.iana.org/domains/root/db/next.html -next - -// nextdirect : Next plc -// https://www.iana.org/domains/root/db/nextdirect.html -nextdirect - -// nexus : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/nexus.html -nexus - -// nfl : NFL Reg Ops LLC -// https://www.iana.org/domains/root/db/nfl.html -nfl - -// ngo : Public Interest Registry -// https://www.iana.org/domains/root/db/ngo.html -ngo - -// nhk : Japan Broadcasting Corporation (NHK) -// https://www.iana.org/domains/root/db/nhk.html -nhk - -// nico : DWANGO Co., Ltd. -// https://www.iana.org/domains/root/db/nico.html -nico - -// nike : NIKE, Inc. -// https://www.iana.org/domains/root/db/nike.html -nike - -// nikon : NIKON CORPORATION -// https://www.iana.org/domains/root/db/nikon.html -nikon - -// ninja : Dog Beach, LLC -// https://www.iana.org/domains/root/db/ninja.html -ninja - -// nissan : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/nissan.html -nissan - -// nissay : Nippon Life Insurance Company -// https://www.iana.org/domains/root/db/nissay.html -nissay - -// nokia : Nokia Corporation -// https://www.iana.org/domains/root/db/nokia.html -nokia - -// norton : Gen Digital Inc. -// https://www.iana.org/domains/root/db/norton.html -norton - -// now : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/now.html -now - -// nowruz -// https://www.iana.org/domains/root/db/nowruz.html -nowruz - -// nowtv : Starbucks (HK) Limited -// https://www.iana.org/domains/root/db/nowtv.html -nowtv - -// nra : National Rifle Association of America -// https://www.iana.org/domains/root/db/nra.html -nra - -// nrw : Minds + Machines GmbH -// https://www.iana.org/domains/root/db/nrw.html -nrw - -// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION -// https://www.iana.org/domains/root/db/ntt.html -ntt - -// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications -// https://www.iana.org/domains/root/db/nyc.html -nyc - -// obi : OBI Group Holding SE & Co. KGaA -// https://www.iana.org/domains/root/db/obi.html -obi - -// observer : Fegistry, LLC -// https://www.iana.org/domains/root/db/observer.html -observer - -// office : Microsoft Corporation -// https://www.iana.org/domains/root/db/office.html -office - -// okinawa : BRregistry, Inc. -// https://www.iana.org/domains/root/db/okinawa.html -okinawa - -// olayan : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/olayan.html -olayan - -// olayangroup : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/olayangroup.html -olayangroup - -// ollo : Dish DBS Corporation -// https://www.iana.org/domains/root/db/ollo.html -ollo - -// omega : The Swatch Group Ltd -// https://www.iana.org/domains/root/db/omega.html -omega - -// one : One.com A/S -// https://www.iana.org/domains/root/db/one.html -one - -// ong : Public Interest Registry -// https://www.iana.org/domains/root/db/ong.html -ong - -// onl : Jolly Host, LLC -// https://www.iana.org/domains/root/db/onl.html -onl - -// online : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/online.html -online - -// ooo : INFIBEAM AVENUES LIMITED -// https://www.iana.org/domains/root/db/ooo.html -ooo - -// open : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/open.html -open - -// oracle : Oracle Corporation -// https://www.iana.org/domains/root/db/oracle.html -oracle - -// orange : Orange Brand Services Limited -// https://www.iana.org/domains/root/db/orange.html -orange - -// organic : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/organic.html -organic - -// origins : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/origins.html -origins - -// osaka : Osaka Registry Co., Ltd. -// https://www.iana.org/domains/root/db/osaka.html -osaka - -// otsuka : Otsuka Holdings Co., Ltd. -// https://www.iana.org/domains/root/db/otsuka.html -otsuka - -// ott : Dish DBS Corporation -// https://www.iana.org/domains/root/db/ott.html -ott - -// ovh : MédiaBC -// https://www.iana.org/domains/root/db/ovh.html -ovh - -// page : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/page.html -page - -// panasonic : Panasonic Holdings Corporation -// https://www.iana.org/domains/root/db/panasonic.html -panasonic - -// paris : City of Paris -// https://www.iana.org/domains/root/db/paris.html -paris - -// pars -// https://www.iana.org/domains/root/db/pars.html -pars - -// partners : Binky Moon, LLC -// https://www.iana.org/domains/root/db/partners.html -partners - -// parts : Binky Moon, LLC -// https://www.iana.org/domains/root/db/parts.html -parts - -// party : Blue Sky Registry Limited -// https://www.iana.org/domains/root/db/party.html -party - -// pay : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/pay.html -pay - -// pccw : PCCW Enterprises Limited -// https://www.iana.org/domains/root/db/pccw.html -pccw - -// pet : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/pet.html -pet - -// pfizer : Pfizer Inc. -// https://www.iana.org/domains/root/db/pfizer.html -pfizer - -// pharmacy : National Association of Boards of Pharmacy -// https://www.iana.org/domains/root/db/pharmacy.html -pharmacy - -// phd : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/phd.html -phd - -// philips : Koninklijke Philips N.V. -// https://www.iana.org/domains/root/db/philips.html -philips - -// phone : Dish DBS Corporation -// https://www.iana.org/domains/root/db/phone.html -phone - -// photo : Registry Services, LLC -// https://www.iana.org/domains/root/db/photo.html -photo - -// photography : Binky Moon, LLC -// https://www.iana.org/domains/root/db/photography.html -photography - -// photos : Binky Moon, LLC -// https://www.iana.org/domains/root/db/photos.html -photos - -// physio : PhysBiz Pty Ltd -// https://www.iana.org/domains/root/db/physio.html -physio - -// pics : XYZ.COM LLC -// https://www.iana.org/domains/root/db/pics.html -pics - -// pictet : Banque Pictet & Cie SA -// https://www.iana.org/domains/root/db/pictet.html -pictet - -// pictures : Binky Moon, LLC -// https://www.iana.org/domains/root/db/pictures.html -pictures - -// pid : Top Level Spectrum, Inc. -// https://www.iana.org/domains/root/db/pid.html -pid - -// pin : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/pin.html -pin - -// ping : Ping Registry Provider, Inc. -// https://www.iana.org/domains/root/db/ping.html -ping - -// pink : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/pink.html -pink - -// pioneer : Pioneer Corporation -// https://www.iana.org/domains/root/db/pioneer.html -pioneer - -// pizza : Binky Moon, LLC -// https://www.iana.org/domains/root/db/pizza.html -pizza - -// place : Binky Moon, LLC -// https://www.iana.org/domains/root/db/place.html -place - -// play : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/play.html -play - -// playstation : Sony Interactive Entertainment Inc. -// https://www.iana.org/domains/root/db/playstation.html -playstation - -// plumbing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/plumbing.html -plumbing - -// plus : Binky Moon, LLC -// https://www.iana.org/domains/root/db/plus.html -plus - -// pnc : PNC Domain Co., LLC -// https://www.iana.org/domains/root/db/pnc.html -pnc - -// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/pohl.html -pohl - -// poker : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/poker.html -poker - -// politie : Politie Nederland -// https://www.iana.org/domains/root/db/politie.html -politie - -// porn : ICM Registry PN LLC -// https://www.iana.org/domains/root/db/porn.html -porn - -// praxi : Praxi S.p.A. -// https://www.iana.org/domains/root/db/praxi.html -praxi - -// press : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/press.html -press - -// prime : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/prime.html -prime - -// prod : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/prod.html -prod - -// productions : Binky Moon, LLC -// https://www.iana.org/domains/root/db/productions.html -productions - -// prof : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/prof.html -prof - -// progressive : Progressive Casualty Insurance Company -// https://www.iana.org/domains/root/db/progressive.html -progressive - -// promo : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/promo.html -promo - -// properties : Binky Moon, LLC -// https://www.iana.org/domains/root/db/properties.html -properties - -// property : Digital Property Infrastructure Limited -// https://www.iana.org/domains/root/db/property.html -property - -// protection : XYZ.COM LLC -// https://www.iana.org/domains/root/db/protection.html -protection - -// pru : Prudential Financial, Inc. -// https://www.iana.org/domains/root/db/pru.html -pru - -// prudential : Prudential Financial, Inc. -// https://www.iana.org/domains/root/db/prudential.html -prudential - -// pub : Dog Beach, LLC -// https://www.iana.org/domains/root/db/pub.html -pub - -// pwc : PricewaterhouseCoopers LLP -// https://www.iana.org/domains/root/db/pwc.html -pwc - -// qpon : dotQPON LLC -// https://www.iana.org/domains/root/db/qpon.html -qpon - -// quebec : PointQuébec Inc -// https://www.iana.org/domains/root/db/quebec.html -quebec - -// quest : XYZ.COM LLC -// https://www.iana.org/domains/root/db/quest.html -quest - -// racing : Premier Registry Limited -// https://www.iana.org/domains/root/db/racing.html -racing - -// radio : Digity, LLC -// https://www.iana.org/domains/root/db/radio.html -radio - -// read : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/read.html -read - -// realestate : dotRealEstate LLC -// https://www.iana.org/domains/root/db/realestate.html -realestate - -// realtor : Real Estate Domains LLC -// https://www.iana.org/domains/root/db/realtor.html -realtor - -// realty : Waterford Limited -// https://www.iana.org/domains/root/db/realty.html -realty - -// recipes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/recipes.html -recipes - -// red : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/red.html -red - -// redumbrella : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/redumbrella.html -redumbrella - -// rehab : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rehab.html -rehab - -// reise : Binky Moon, LLC -// https://www.iana.org/domains/root/db/reise.html -reise - -// reisen : Binky Moon, LLC -// https://www.iana.org/domains/root/db/reisen.html -reisen - -// reit : National Association of Real Estate Investment Trusts, Inc. -// https://www.iana.org/domains/root/db/reit.html -reit - -// reliance : Reliance Industries Limited -// https://www.iana.org/domains/root/db/reliance.html -reliance - -// ren : ZDNS International Limited -// https://www.iana.org/domains/root/db/ren.html -ren - -// rent : XYZ.COM LLC -// https://www.iana.org/domains/root/db/rent.html -rent - -// rentals : Binky Moon, LLC -// https://www.iana.org/domains/root/db/rentals.html -rentals - -// repair : Binky Moon, LLC -// https://www.iana.org/domains/root/db/repair.html -repair - -// report : Binky Moon, LLC -// https://www.iana.org/domains/root/db/report.html -report - -// republican : Dog Beach, LLC -// https://www.iana.org/domains/root/db/republican.html -republican - -// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable -// https://www.iana.org/domains/root/db/rest.html -rest - -// restaurant : Binky Moon, LLC -// https://www.iana.org/domains/root/db/restaurant.html -restaurant - -// review : dot Review Limited -// https://www.iana.org/domains/root/db/review.html -review - -// reviews : Dog Beach, LLC -// https://www.iana.org/domains/root/db/reviews.html -reviews - -// rexroth : Robert Bosch GMBH -// https://www.iana.org/domains/root/db/rexroth.html -rexroth - -// rich : iRegistry GmbH -// https://www.iana.org/domains/root/db/rich.html -rich - -// richardli : Pacific Century Asset Management (HK) Limited -// https://www.iana.org/domains/root/db/richardli.html -richardli - -// ricoh : Ricoh Company, Ltd. -// https://www.iana.org/domains/root/db/ricoh.html -ricoh - -// ril : Reliance Industries Limited -// https://www.iana.org/domains/root/db/ril.html -ril - -// rio : Empresa Municipal de Informática SA - IPLANRIO -// https://www.iana.org/domains/root/db/rio.html -rio - -// rip : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rip.html -rip - -// rocks : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rocks.html -rocks - -// rodeo : Registry Services, LLC -// https://www.iana.org/domains/root/db/rodeo.html -rodeo - -// rogers : Rogers Communications Canada Inc. -// https://www.iana.org/domains/root/db/rogers.html -rogers - -// room : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/room.html -room - -// rsvp : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/rsvp.html -rsvp - -// rugby : World Rugby Strategic Developments Limited -// https://www.iana.org/domains/root/db/rugby.html -rugby - -// ruhr : dotSaarland GmbH -// https://www.iana.org/domains/root/db/ruhr.html -ruhr - -// run : Binky Moon, LLC -// https://www.iana.org/domains/root/db/run.html -run - -// rwe : RWE AG -// https://www.iana.org/domains/root/db/rwe.html -rwe - -// ryukyu : BRregistry, Inc. -// https://www.iana.org/domains/root/db/ryukyu.html -ryukyu - -// saarland : dotSaarland GmbH -// https://www.iana.org/domains/root/db/saarland.html -saarland - -// safe : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/safe.html -safe - -// safety : Jolly Host, LLC -// https://www.iana.org/domains/root/db/safety.html -safety - -// sakura : SAKURA Internet Inc. -// https://www.iana.org/domains/root/db/sakura.html -sakura - -// sale : Dog Beach, LLC -// https://www.iana.org/domains/root/db/sale.html -sale - -// salon : Binky Moon, LLC -// https://www.iana.org/domains/root/db/salon.html -salon - -// samsclub : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/samsclub.html -samsclub - -// samsung : SAMSUNG SDS CO., LTD -// https://www.iana.org/domains/root/db/samsung.html -samsung - -// sandvik : Sandvik AB -// https://www.iana.org/domains/root/db/sandvik.html -sandvik - -// sandvikcoromant : Sandvik AB -// https://www.iana.org/domains/root/db/sandvikcoromant.html -sandvikcoromant - -// sanofi : Sanofi -// https://www.iana.org/domains/root/db/sanofi.html -sanofi - -// sap : SAP AG -// https://www.iana.org/domains/root/db/sap.html -sap - -// sarl : Binky Moon, LLC -// https://www.iana.org/domains/root/db/sarl.html -sarl - -// sas : Research IP LLC -// https://www.iana.org/domains/root/db/sas.html -sas - -// save : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/save.html -save - -// saxo : Saxo Bank A/S -// https://www.iana.org/domains/root/db/saxo.html -saxo - -// sbi : STATE BANK OF INDIA -// https://www.iana.org/domains/root/db/sbi.html -sbi - -// sbs : ShortDot SA -// https://www.iana.org/domains/root/db/sbs.html -sbs - -// scb : The Siam Commercial Bank Public Company Limited ("SCB") -// https://www.iana.org/domains/root/db/scb.html -scb - -// schaeffler : Schaeffler Technologies AG & Co. KG -// https://www.iana.org/domains/root/db/schaeffler.html -schaeffler - -// schmidt : SCHMIDT GROUPE S.A.S. -// https://www.iana.org/domains/root/db/schmidt.html -schmidt - -// scholarships : Scholarships.com, LLC -// https://www.iana.org/domains/root/db/scholarships.html -scholarships - -// school : Binky Moon, LLC -// https://www.iana.org/domains/root/db/school.html -school - -// schule : Binky Moon, LLC -// https://www.iana.org/domains/root/db/schule.html -schule - -// schwarz : Schwarz Domains und Services GmbH & Co. KG -// https://www.iana.org/domains/root/db/schwarz.html -schwarz - -// science : dot Science Limited -// https://www.iana.org/domains/root/db/science.html -science - -// scot : Dot Scot Registry Limited -// https://www.iana.org/domains/root/db/scot.html -scot - -// search : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/search.html -search - -// seat : SEAT, S.A. (Sociedad Unipersonal) -// https://www.iana.org/domains/root/db/seat.html -seat - -// secure : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/secure.html -secure - -// security : XYZ.COM LLC -// https://www.iana.org/domains/root/db/security.html -security - -// seek : Seek Limited -// https://www.iana.org/domains/root/db/seek.html -seek - -// select : Registry Services, LLC -// https://www.iana.org/domains/root/db/select.html -select - -// sener : Sener Ingeniería y Sistemas, S.A. -// https://www.iana.org/domains/root/db/sener.html -sener - -// services : Binky Moon, LLC -// https://www.iana.org/domains/root/db/services.html -services - -// seven : Seven West Media Ltd -// https://www.iana.org/domains/root/db/seven.html -seven - -// sew : SEW-EURODRIVE GmbH & Co KG -// https://www.iana.org/domains/root/db/sew.html -sew - -// sex : ICM Registry SX LLC -// https://www.iana.org/domains/root/db/sex.html -sex - -// sexy : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/sexy.html -sexy - -// sfr : Societe Francaise du Radiotelephone - SFR -// https://www.iana.org/domains/root/db/sfr.html -sfr - -// shangrila : Shangri‐La International Hotel Management Limited -// https://www.iana.org/domains/root/db/shangrila.html -shangrila - -// sharp : Sharp Corporation -// https://www.iana.org/domains/root/db/sharp.html -sharp - -// shell : Shell Information Technology International Inc -// https://www.iana.org/domains/root/db/shell.html -shell - -// shia -// https://www.iana.org/domains/root/db/shia.html -shia - -// shiksha : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/shiksha.html -shiksha - -// shoes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/shoes.html -shoes - -// shop : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/shop.html -shop - -// shopping : Binky Moon, LLC -// https://www.iana.org/domains/root/db/shopping.html -shopping - -// shouji : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/shouji.html -shouji - -// show : Binky Moon, LLC -// https://www.iana.org/domains/root/db/show.html -show - -// silk : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/silk.html -silk - -// sina : Sina Corporation -// https://www.iana.org/domains/root/db/sina.html -sina - -// singles : Binky Moon, LLC -// https://www.iana.org/domains/root/db/singles.html -singles - -// site : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/site.html -site - -// ski : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/ski.html -ski - -// skin : XYZ.COM LLC -// https://www.iana.org/domains/root/db/skin.html -skin - -// sky : Sky UK Limited -// https://www.iana.org/domains/root/db/sky.html -sky - -// skype : Microsoft Corporation -// https://www.iana.org/domains/root/db/skype.html -skype - -// sling : DISH Technologies L.L.C. -// https://www.iana.org/domains/root/db/sling.html -sling - -// smart : Smart Communications, Inc. (SMART) -// https://www.iana.org/domains/root/db/smart.html -smart - -// smile : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/smile.html -smile - -// sncf : Société Nationale SNCF -// https://www.iana.org/domains/root/db/sncf.html -sncf - -// soccer : Binky Moon, LLC -// https://www.iana.org/domains/root/db/soccer.html -soccer - -// social : Dog Beach, LLC -// https://www.iana.org/domains/root/db/social.html -social - -// softbank : SoftBank Group Corp. -// https://www.iana.org/domains/root/db/softbank.html -softbank - -// software : Dog Beach, LLC -// https://www.iana.org/domains/root/db/software.html -software - -// sohu : Sohu.com Limited -// https://www.iana.org/domains/root/db/sohu.html -sohu - -// solar : Binky Moon, LLC -// https://www.iana.org/domains/root/db/solar.html -solar - -// solutions : Binky Moon, LLC -// https://www.iana.org/domains/root/db/solutions.html -solutions - -// song : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/song.html -song - -// sony : Sony Group Corporation -// https://www.iana.org/domains/root/db/sony.html -sony - -// soy : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/soy.html -soy - -// spa : Asia Spa and Wellness Promotion Council Limited -// https://www.iana.org/domains/root/db/spa.html -spa - -// space : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/space.html -space - -// sport : SportAccord -// https://www.iana.org/domains/root/db/sport.html -sport - -// spot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/spot.html -spot - -// srl : InterNetX, Corp -// https://www.iana.org/domains/root/db/srl.html -srl - -// stada : STADA Arzneimittel AG -// https://www.iana.org/domains/root/db/stada.html -stada - -// staples : Staples, Inc. -// https://www.iana.org/domains/root/db/staples.html -staples - -// star : Star India Private Limited -// https://www.iana.org/domains/root/db/star.html -star - -// statebank : STATE BANK OF INDIA -// https://www.iana.org/domains/root/db/statebank.html -statebank - -// statefarm : State Farm Mutual Automobile Insurance Company -// https://www.iana.org/domains/root/db/statefarm.html -statefarm - -// stc : Saudi Telecom Company -// https://www.iana.org/domains/root/db/stc.html -stc - -// stcgroup : Saudi Telecom Company -// https://www.iana.org/domains/root/db/stcgroup.html -stcgroup - -// stockholm : Stockholms kommun -// https://www.iana.org/domains/root/db/stockholm.html -stockholm - -// storage : XYZ.COM LLC -// https://www.iana.org/domains/root/db/storage.html -storage - -// store : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/store.html -store - -// stream : dot Stream Limited -// https://www.iana.org/domains/root/db/stream.html -stream - -// studio : Dog Beach, LLC -// https://www.iana.org/domains/root/db/studio.html -studio - -// study : Registry Services, LLC -// https://www.iana.org/domains/root/db/study.html -study - -// style : Binky Moon, LLC -// https://www.iana.org/domains/root/db/style.html -style - -// sucks : Vox Populi Registry Ltd. -// https://www.iana.org/domains/root/db/sucks.html -sucks - -// supplies : Binky Moon, LLC -// https://www.iana.org/domains/root/db/supplies.html -supplies - -// supply : Binky Moon, LLC -// https://www.iana.org/domains/root/db/supply.html -supply - -// support : Binky Moon, LLC -// https://www.iana.org/domains/root/db/support.html -support - -// surf : Registry Services, LLC -// https://www.iana.org/domains/root/db/surf.html -surf - -// surgery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/surgery.html -surgery - -// suzuki : SUZUKI MOTOR CORPORATION -// https://www.iana.org/domains/root/db/suzuki.html -suzuki - -// swatch : The Swatch Group Ltd -// https://www.iana.org/domains/root/db/swatch.html -swatch - -// swiss : Swiss Confederation -// https://www.iana.org/domains/root/db/swiss.html -swiss - -// sydney : State of New South Wales, Department of Premier and Cabinet -// https://www.iana.org/domains/root/db/sydney.html -sydney - -// systems : Binky Moon, LLC -// https://www.iana.org/domains/root/db/systems.html -systems - -// tab : Tabcorp Holdings Limited -// https://www.iana.org/domains/root/db/tab.html -tab - -// taipei : Taipei City Government -// https://www.iana.org/domains/root/db/taipei.html -taipei - -// talk : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/talk.html -talk - -// taobao : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/taobao.html -taobao - -// target : Target Domain Holdings, LLC -// https://www.iana.org/domains/root/db/target.html -target - -// tatamotors : Tata Motors Ltd -// https://www.iana.org/domains/root/db/tatamotors.html -tatamotors - -// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" -// https://www.iana.org/domains/root/db/tatar.html -tatar - -// tattoo : Registry Services, LLC -// https://www.iana.org/domains/root/db/tattoo.html -tattoo - -// tax : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tax.html -tax - -// taxi : Binky Moon, LLC -// https://www.iana.org/domains/root/db/taxi.html -taxi - -// tci -// https://www.iana.org/domains/root/db/tci.html -tci - -// tdk : TDK Corporation -// https://www.iana.org/domains/root/db/tdk.html -tdk - -// team : Binky Moon, LLC -// https://www.iana.org/domains/root/db/team.html -team - -// tech : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/tech.html -tech - -// technology : Binky Moon, LLC -// https://www.iana.org/domains/root/db/technology.html -technology - -// temasek : Temasek Holdings (Private) Limited -// https://www.iana.org/domains/root/db/temasek.html -temasek - -// tennis : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tennis.html -tennis - -// teva : Teva Pharmaceutical Industries Limited -// https://www.iana.org/domains/root/db/teva.html -teva - -// thd : Home Depot Product Authority, LLC -// https://www.iana.org/domains/root/db/thd.html -thd - -// theater : Binky Moon, LLC -// https://www.iana.org/domains/root/db/theater.html -theater - -// theatre : XYZ.COM LLC -// https://www.iana.org/domains/root/db/theatre.html -theatre - -// tiaa : Teachers Insurance and Annuity Association of America -// https://www.iana.org/domains/root/db/tiaa.html -tiaa - -// tickets : XYZ.COM LLC -// https://www.iana.org/domains/root/db/tickets.html -tickets - -// tienda : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tienda.html -tienda - -// tips : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tips.html -tips - -// tires : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tires.html -tires - -// tirol : punkt Tirol GmbH -// https://www.iana.org/domains/root/db/tirol.html -tirol - -// tjmaxx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tjmaxx.html -tjmaxx - -// tjx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tjx.html -tjx - -// tkmaxx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tkmaxx.html -tkmaxx - -// tmall : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/tmall.html -tmall - -// today : Binky Moon, LLC -// https://www.iana.org/domains/root/db/today.html -today - -// tokyo : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/tokyo.html -tokyo - -// tools : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tools.html -tools - -// top : Hong Kong Zhongze International Limited -// https://www.iana.org/domains/root/db/top.html -top - -// toray : Toray Industries, Inc. -// https://www.iana.org/domains/root/db/toray.html -toray - -// toshiba : TOSHIBA Corporation -// https://www.iana.org/domains/root/db/toshiba.html -toshiba - -// total : TotalEnergies SE -// https://www.iana.org/domains/root/db/total.html -total - -// tours : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tours.html -tours - -// town : Binky Moon, LLC -// https://www.iana.org/domains/root/db/town.html -town - -// toyota : TOYOTA MOTOR CORPORATION -// https://www.iana.org/domains/root/db/toyota.html -toyota - -// toys : Binky Moon, LLC -// https://www.iana.org/domains/root/db/toys.html -toys - -// trade : Elite Registry Limited -// https://www.iana.org/domains/root/db/trade.html -trade - -// trading : Dog Beach, LLC -// https://www.iana.org/domains/root/db/trading.html -trading - -// training : Binky Moon, LLC -// https://www.iana.org/domains/root/db/training.html -training - -// travel : Dog Beach, LLC -// https://www.iana.org/domains/root/db/travel.html -travel - -// travelers : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/travelers.html -travelers - -// travelersinsurance : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/travelersinsurance.html -travelersinsurance - -// trust : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/trust.html -trust - -// trv : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/trv.html -trv - -// tube : Latin American Telecom LLC -// https://www.iana.org/domains/root/db/tube.html -tube - -// tui : TUI AG -// https://www.iana.org/domains/root/db/tui.html -tui - -// tunes : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/tunes.html -tunes - -// tushu : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/tushu.html -tushu - -// tvs : T V SUNDRAM IYENGAR & SONS LIMITED -// https://www.iana.org/domains/root/db/tvs.html -tvs - -// ubank : National Australia Bank Limited -// https://www.iana.org/domains/root/db/ubank.html -ubank - -// ubs : UBS AG -// https://www.iana.org/domains/root/db/ubs.html -ubs - -// unicom : China United Network Communications Corporation Limited -// https://www.iana.org/domains/root/db/unicom.html -unicom - -// university : Binky Moon, LLC -// https://www.iana.org/domains/root/db/university.html -university - -// uno : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/uno.html -uno - -// uol : UBN INTERNET LTDA. -// https://www.iana.org/domains/root/db/uol.html -uol - -// ups : UPS Market Driver, Inc. -// https://www.iana.org/domains/root/db/ups.html -ups - -// vacations : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vacations.html -vacations - -// vana : D3 Registry LLC -// https://www.iana.org/domains/root/db/vana.html -vana - -// vanguard : The Vanguard Group, Inc. -// https://www.iana.org/domains/root/db/vanguard.html -vanguard - -// vegas : Dot Vegas, Inc. -// https://www.iana.org/domains/root/db/vegas.html -vegas - -// ventures : Binky Moon, LLC -// https://www.iana.org/domains/root/db/ventures.html -ventures - -// verisign : VeriSign, Inc. -// https://www.iana.org/domains/root/db/verisign.html -verisign - -// versicherung : tldbox GmbH -// https://www.iana.org/domains/root/db/versicherung.html -versicherung - -// vet : Dog Beach, LLC -// https://www.iana.org/domains/root/db/vet.html -vet - -// viajes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/viajes.html -viajes - -// video : Dog Beach, LLC -// https://www.iana.org/domains/root/db/video.html -video - -// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe -// https://www.iana.org/domains/root/db/vig.html -vig - -// viking : Viking River Cruises (Bermuda) Ltd. -// https://www.iana.org/domains/root/db/viking.html -viking - -// villas : Binky Moon, LLC -// https://www.iana.org/domains/root/db/villas.html -villas - -// vin : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vin.html -vin - -// vip : Registry Services, LLC -// https://www.iana.org/domains/root/db/vip.html -vip - -// virgin : Virgin Enterprises Limited -// https://www.iana.org/domains/root/db/virgin.html -virgin - -// visa : Visa Worldwide Pte. Limited -// https://www.iana.org/domains/root/db/visa.html -visa - -// vision : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vision.html -vision - -// viva : Saudi Telecom Company -// https://www.iana.org/domains/root/db/viva.html -viva - -// vivo : Telefonica Brasil S.A. -// https://www.iana.org/domains/root/db/vivo.html -vivo - -// vlaanderen : DNS.be vzw -// https://www.iana.org/domains/root/db/vlaanderen.html -vlaanderen - -// vodka : Registry Services, LLC -// https://www.iana.org/domains/root/db/vodka.html -vodka - -// volvo : Volvo Holding Sverige Aktiebolag -// https://www.iana.org/domains/root/db/volvo.html -volvo - -// vote : Monolith Registry LLC -// https://www.iana.org/domains/root/db/vote.html -vote - -// voting : Valuetainment Corp. -// https://www.iana.org/domains/root/db/voting.html -voting - -// voto : Monolith Registry LLC -// https://www.iana.org/domains/root/db/voto.html -voto - -// voyage : Binky Moon, LLC -// https://www.iana.org/domains/root/db/voyage.html -voyage - -// wales : Nominet UK -// https://www.iana.org/domains/root/db/wales.html -wales - -// walmart : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/walmart.html -walmart - -// walter : Sandvik AB -// https://www.iana.org/domains/root/db/walter.html -walter - -// wang : Zodiac Wang Limited -// https://www.iana.org/domains/root/db/wang.html -wang - -// wanggou : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/wanggou.html -wanggou - -// watch : Binky Moon, LLC -// https://www.iana.org/domains/root/db/watch.html -watch - -// watches : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/watches.html -watches - -// weather : The Weather Company, LLC -// https://www.iana.org/domains/root/db/weather.html -weather - -// weatherchannel : The Weather Company, LLC -// https://www.iana.org/domains/root/db/weatherchannel.html -weatherchannel - -// web : VeriSign, Inc. -// https://www.iana.org/domains/root/db/web.html -web - -// webcam : dot Webcam Limited -// https://www.iana.org/domains/root/db/webcam.html -webcam - -// weber : Saint-Gobain Weber SA -// https://www.iana.org/domains/root/db/weber.html -weber - -// website : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/website.html -website - -// wed -// https://www.iana.org/domains/root/db/wed.html -wed - -// wedding : Registry Services, LLC -// https://www.iana.org/domains/root/db/wedding.html -wedding - -// weibo : Sina Corporation -// https://www.iana.org/domains/root/db/weibo.html -weibo - -// weir : Weir Group IP Limited -// https://www.iana.org/domains/root/db/weir.html -weir - -// whoswho : Who's Who Registry -// https://www.iana.org/domains/root/db/whoswho.html -whoswho - -// wien : domainworx Service & Management GmbH -// https://www.iana.org/domains/root/db/wien.html -wien - -// wiki : Registry Services, LLC -// https://www.iana.org/domains/root/db/wiki.html -wiki - -// williamhill : William Hill Organization Limited -// https://www.iana.org/domains/root/db/williamhill.html -williamhill - -// win : First Registry Limited -// https://www.iana.org/domains/root/db/win.html -win - -// windows : Microsoft Corporation -// https://www.iana.org/domains/root/db/windows.html -windows - -// wine : Binky Moon, LLC -// https://www.iana.org/domains/root/db/wine.html -wine - -// winners : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/winners.html -winners - -// wme : William Morris Endeavor Entertainment, LLC -// https://www.iana.org/domains/root/db/wme.html -wme - -// woodside : Woodside Petroleum Limited -// https://www.iana.org/domains/root/db/woodside.html -woodside - -// work : Registry Services, LLC -// https://www.iana.org/domains/root/db/work.html -work - -// works : Binky Moon, LLC -// https://www.iana.org/domains/root/db/works.html -works - -// world : Binky Moon, LLC -// https://www.iana.org/domains/root/db/world.html -world - -// wow : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/wow.html -wow - -// wtc : World Trade Centers Association, Inc. -// https://www.iana.org/domains/root/db/wtc.html -wtc - -// wtf : Binky Moon, LLC -// https://www.iana.org/domains/root/db/wtf.html -wtf - -// xbox : Microsoft Corporation -// https://www.iana.org/domains/root/db/xbox.html -xbox - -// xerox : Xerox DNHC LLC -// https://www.iana.org/domains/root/db/xerox.html -xerox - -// xihuan : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/xihuan.html -xihuan - -// xin : Elegant Leader Limited -// https://www.iana.org/domains/root/db/xin.html -xin - -// xn--11b4c3d : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--11b4c3d.html -कॉम - -// xn--1ck2e1b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--1ck2e1b.html -セール - -// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--1qqw23a.html -佛山 - -// xn--30rr7y : Excellent First Limited -// https://www.iana.org/domains/root/db/xn--30rr7y.html -慈善 - -// xn--3bst00m : Eagle Horizon Limited -// https://www.iana.org/domains/root/db/xn--3bst00m.html -集团 - -// xn--3ds443g : Beijing TLD Registry Technology Limited -// https://www.iana.org/domains/root/db/xn--3ds443g.html -在线 - -// xn--3pxu8k : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--3pxu8k.html -点看 - -// xn--42c2d9a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--42c2d9a.html -คอม - -// xn--45q11c : Zodiac Gemini Ltd -// https://www.iana.org/domains/root/db/xn--45q11c.html -八卦 - -// xn--4gbrim : Helium TLDs Ltd -// https://www.iana.org/domains/root/db/xn--4gbrim.html -موقع - -// xn--55qw42g : China Organizational Name Administration Center -// https://www.iana.org/domains/root/db/xn--55qw42g.html -公益 - -// xn--55qx5d : China Internet Network Information Center (CNNIC) -// https://www.iana.org/domains/root/db/xn--55qx5d.html -公司 - -// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited -// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html -香格里拉 - -// xn--5tzm5g : Jolly Host, LLC -// https://www.iana.org/domains/root/db/xn--5tzm5g.html -网站 - -// xn--6frz82g : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/xn--6frz82g.html -移动 - -// xn--6qq986b3xl : Tycoon Treasure Limited -// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html -我爱你 - -// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) -// https://www.iana.org/domains/root/db/xn--80adxhks.html -москва - -// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html -католик - -// xn--80asehdb : CORE Association -// https://www.iana.org/domains/root/db/xn--80asehdb.html -онлайн - -// xn--80aswg : CORE Association -// https://www.iana.org/domains/root/db/xn--80aswg.html -сайт - -// xn--8y0a063a : China United Network Communications Corporation Limited -// https://www.iana.org/domains/root/db/xn--8y0a063a.html -联通 - -// xn--9dbq2a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--9dbq2a.html -קום - -// xn--9et52u : RISE VICTORY LIMITED -// https://www.iana.org/domains/root/db/xn--9et52u.html -时尚 - -// xn--9krt00a : Sina Corporation -// https://www.iana.org/domains/root/db/xn--9krt00a.html -微博 - -// xn--b4w605ferd : Temasek Holdings (Private) Limited -// https://www.iana.org/domains/root/db/xn--b4w605ferd.html -淡马锡 - -// xn--bck1b9a5dre4c : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html -ファッション - -// xn--c1avg : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--c1avg.html -орг - -// xn--c2br7g : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--c2br7g.html -नेट - -// xn--cck2b3b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--cck2b3b.html -ストア - -// xn--cckwcxetd : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--cckwcxetd.html -アマゾン - -// xn--cg4bki : SAMSUNG SDS CO., LTD -// https://www.iana.org/domains/root/db/xn--cg4bki.html -삼성 - -// xn--czr694b : Internet DotTrademark Organisation Limited -// https://www.iana.org/domains/root/db/xn--czr694b.html -商标 - -// xn--czrs0t : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--czrs0t.html -商店 - -// xn--czru2d : Zodiac Aquarius Limited -// https://www.iana.org/domains/root/db/xn--czru2d.html -商城 - -// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet” -// https://www.iana.org/domains/root/db/xn--d1acj3b.html -дети - -// xn--eckvdtc9d : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html -ポイント - -// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--efvy88h.html -新闻 - -// xn--fct429k : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--fct429k.html -家電 - -// xn--fhbei : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--fhbei.html -كوم - -// xn--fiq228c5hs : Beijing TLD Registry Technology Limited -// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html -中文网 - -// xn--fiq64b : CITIC Group Corporation -// https://www.iana.org/domains/root/db/xn--fiq64b.html -中信 - -// xn--fjq720a : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--fjq720a.html -娱乐 - -// xn--flw351e : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--flw351e.html -谷歌 - -// xn--fzys8d69uvgm : PCCW Enterprises Limited -// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html -電訊盈科 - -// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD. -// https://www.iana.org/domains/root/db/xn--g2xx48c.html -购物 - -// xn--gckr3f0f : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--gckr3f0f.html -クラウド - -// xn--gk3at1e : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--gk3at1e.html -通販 - -// xn--hxt814e : Zodiac Taurus Limited -// https://www.iana.org/domains/root/db/xn--hxt814e.html -网店 - -// xn--i1b6b1a6a2e : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html -संगठन - -// xn--imr513n : Internet DotTrademark Organisation Limited -// https://www.iana.org/domains/root/db/xn--imr513n.html -餐厅 - -// xn--io0a7i : China Internet Network Information Center (CNNIC) -// https://www.iana.org/domains/root/db/xn--io0a7i.html -网络 - -// xn--j1aef : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--j1aef.html -ком - -// xn--jlq480n2rg : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html -亚马逊 - -// xn--jvr189m : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--jvr189m.html -食品 - -// xn--kcrx77d1x4a : Koninklijke Philips N.V. -// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html -飞利浦 - -// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd -// https://www.iana.org/domains/root/db/xn--kput3i.html -手机 - -// xn--mgba3a3ejt : Aramco Services Company -// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html -ارامكو - -// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html -العليان - -// xn--mgbab2bd : CORE Association -// https://www.iana.org/domains/root/db/xn--mgbab2bd.html -بازار - -// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre -// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html -ابوظبي - -// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html -كاثوليك - -// xn--mgbt3dhd -// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html -همراه - -// xn--mk1bu44c : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--mk1bu44c.html -닷컴 - -// xn--mxtq1m : Net-Chinese Co., Ltd. -// https://www.iana.org/domains/root/db/xn--mxtq1m.html -政府 - -// xn--ngbc5azd : International Domain Registry Pty. Ltd. -// https://www.iana.org/domains/root/db/xn--ngbc5azd.html -شبكة - -// xn--ngbe9e0a : Kuwait Finance House -// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html -بيتك - -// xn--ngbrx : League of Arab States -// https://www.iana.org/domains/root/db/xn--ngbrx.html -عرب - -// xn--nqv7f : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--nqv7f.html -机构 - -// xn--nqv7fs00ema : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html -组织机构 - -// xn--nyqy26a : Stable Tone Limited -// https://www.iana.org/domains/root/db/xn--nyqy26a.html -健康 - -// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited -// https://www.iana.org/domains/root/db/xn--otu796d.html -招聘 - -// xn--p1acf : Rusnames Limited -// https://www.iana.org/domains/root/db/xn--p1acf.html -рус - -// xn--pssy2u : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--pssy2u.html -大拿 - -// xn--q9jyb4c : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--q9jyb4c.html -みんな - -// xn--qcka1pmc : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--qcka1pmc.html -グーグル - -// xn--rhqv96g : Stable Tone Limited -// https://www.iana.org/domains/root/db/xn--rhqv96g.html -世界 - -// xn--rovu88b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--rovu88b.html -書籍 - -// xn--ses554g : KNET Co., Ltd. -// https://www.iana.org/domains/root/db/xn--ses554g.html -网址 - -// xn--t60b56a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--t60b56a.html -닷넷 - -// xn--tckwe : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--tckwe.html -コム - -// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html -天主教 - -// xn--unup4y : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--unup4y.html -游戏 - -// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html -vermögensberater - -// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html -vermögensberatung - -// xn--vhquv : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--vhquv.html -企业 - -// xn--vuq861b : Beijing Tele-info Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--vuq861b.html -信息 - -// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html -嘉里大酒店 - -// xn--w4rs40l : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/xn--w4rs40l.html -嘉里 - -// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--xhq521b.html -广东 - -// xn--zfr164b : China Organizational Name Administration Center -// https://www.iana.org/domains/root/db/xn--zfr164b.html -政务 - -// xyz : XYZ.COM LLC -// https://www.iana.org/domains/root/db/xyz.html -xyz - -// yachts : XYZ.COM LLC -// https://www.iana.org/domains/root/db/yachts.html -yachts - -// yahoo : Yahoo Inc. -// https://www.iana.org/domains/root/db/yahoo.html -yahoo - -// yamaxun : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/yamaxun.html -yamaxun - -// yandex : YANDEX, LLC -// https://www.iana.org/domains/root/db/yandex.html -yandex - -// yodobashi : YODOBASHI CAMERA CO.,LTD. -// https://www.iana.org/domains/root/db/yodobashi.html -yodobashi - -// yoga : Registry Services, LLC -// https://www.iana.org/domains/root/db/yoga.html -yoga - -// yokohama : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/yokohama.html -yokohama - -// you : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/you.html -you - -// youtube : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/youtube.html -youtube - -// yun : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/yun.html -yun - -// zappos : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/zappos.html -zappos - -// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.) -// https://www.iana.org/domains/root/db/zara.html -zara - -// zero : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/zero.html -zero - -// zip : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/zip.html -zip - -// zone : Binky Moon, LLC -// https://www.iana.org/domains/root/db/zone.html -zone - -// zuerich : Kanton Zürich (Canton of Zurich) -// https://www.iana.org/domains/root/db/zuerich.html -zuerich - -// ===END ICANN DOMAINS=== - -// ===BEGIN PRIVATE DOMAINS=== - -// (Note: these are in alphabetical order by company name) - -// .KRD : https://nic.krd -co.krd -edu.krd - -// .pl domains (grandfathered) -art.pl -gliwice.pl -krakow.pl -poznan.pl -wroc.pl -zakopane.pl - -// 1GB LLC : https://www.1gb.ua/ -// Submitted by 1GB LLC -cc.ua -inf.ua -ltd.ua - -// 611 blockchain domain name system : https://sixone.one/ -611.to - -// A2 Hosting -// Submitted by Tyler Hall -a2hosted.com -cpserver.com - -// ActiveTrail : https://www.activetrail.biz/ -// Submitted by Ofer Kalaora -activetrail.biz - -// Adaptable.io : https://adaptable.io -// Submitted by Mark Terrel -adaptable.app - -// addr.tools : https://addr.tools/ -// Submitted by Brian Shea -myaddr.dev -myaddr.io -dyn.addr.tools -myaddr.tools - -// Adobe : https://www.adobe.com/ -// Submitted by Ian Boston and Lars Trieloff -adobeaemcloud.com -*.dev.adobeaemcloud.com -aem.live -hlx.live -adobeaemcloud.net -aem.network -aem.page -hlx.page -aem.reviews - -// Adobe Developer Platform : https://developer.adobe.com -// Submitted by Jesse MacFadyen -adobeio-static.net -adobeioruntime.net - -// Africa.com Web Solutions Ltd : https://registry.africa.com -// Submitted by Gavin Brown -africa.com - -// AgentbaseAI Inc. : https://assistant-ui.com -// Submitted by Simon Farshid -*.auiusercontent.com - -// Agnat sp. z o.o. : https://domena.pl -// Submitted by Przemyslaw Plewa -beep.pl - -// Aiven : https://aiven.io/ -// Submitted by Aiven Security Team -aiven.app -aivencloud.com - -// Akamai : https://www.akamai.com/ -// Submitted by Akamai Team -akadns.net -akamai.net -akamai-staging.net -akamaiedge.net -akamaiedge-staging.net -akamaihd.net -akamaihd-staging.net -akamaiorigin.net -akamaiorigin-staging.net -akamaized.net -akamaized-staging.net -edgekey.net -edgekey-staging.net -edgesuite.net -edgesuite-staging.net - -// alboto.ca : http://alboto.ca -// Submitted by Anton Avramov -barsy.ca - -// Alces Software Ltd : http://alces-software.com -// Submitted by Mark J. Titorenko -*.compute.estate -*.alces.network - -// Alibaba Cloud API Gateway -// Submitted by Alibaba Cloud Security -alibabacloudcs.com -ms.fun -ms.show - -// all-inkl.com : https://all-inkl.com -// Submitted by Werner Kaltofen -kasserver.com - -// Altervista : https://www.altervista.org -// Submitted by Carlo Cannas -altervista.org - -// alwaysdata : https://www.alwaysdata.com -// Submitted by Cyril -alwaysdata.net - -// Amaze Software : https://amaze.co -// Submitted by Domain Admin -myamaze.net - -// Amazon : https://www.amazon.com/ -// Submitted by AWS Security -// Subsections of Amazon/subsidiaries will appear until "concludes" tag - -// Amazon API Gateway -// Submitted by AWS Security -// Reference: 6a4f5a95-8c7d-4077-a7af-9cf1abec0a53 -execute-api.cn-north-1.amazonaws.com.cn -execute-api.cn-northwest-1.amazonaws.com.cn -execute-api.af-south-1.amazonaws.com -execute-api.ap-east-1.amazonaws.com -execute-api.ap-northeast-1.amazonaws.com -execute-api.ap-northeast-2.amazonaws.com -execute-api.ap-northeast-3.amazonaws.com -execute-api.ap-south-1.amazonaws.com -execute-api.ap-south-2.amazonaws.com -execute-api.ap-southeast-1.amazonaws.com -execute-api.ap-southeast-2.amazonaws.com -execute-api.ap-southeast-3.amazonaws.com -execute-api.ap-southeast-4.amazonaws.com -execute-api.ap-southeast-5.amazonaws.com -execute-api.ca-central-1.amazonaws.com -execute-api.ca-west-1.amazonaws.com -execute-api.eu-central-1.amazonaws.com -execute-api.eu-central-2.amazonaws.com -execute-api.eu-north-1.amazonaws.com -execute-api.eu-south-1.amazonaws.com -execute-api.eu-south-2.amazonaws.com -execute-api.eu-west-1.amazonaws.com -execute-api.eu-west-2.amazonaws.com -execute-api.eu-west-3.amazonaws.com -execute-api.il-central-1.amazonaws.com -execute-api.me-central-1.amazonaws.com -execute-api.me-south-1.amazonaws.com -execute-api.sa-east-1.amazonaws.com -execute-api.us-east-1.amazonaws.com -execute-api.us-east-2.amazonaws.com -execute-api.us-gov-east-1.amazonaws.com -execute-api.us-gov-west-1.amazonaws.com -execute-api.us-west-1.amazonaws.com -execute-api.us-west-2.amazonaws.com - -// Amazon CloudFront -// Submitted by Donavan Miller -// Reference: 54144616-fd49-4435-8535-19c6a601bdb3 -cloudfront.net - -// Amazon Cognito -// Submitted by AWS Security -// Reference: d7d4a954-976e-403e-a010-de9ed0cfbbd1 -auth.af-south-1.amazoncognito.com -auth.ap-east-1.amazoncognito.com -auth.ap-northeast-1.amazoncognito.com -auth.ap-northeast-2.amazoncognito.com -auth.ap-northeast-3.amazoncognito.com -auth.ap-south-1.amazoncognito.com -auth.ap-south-2.amazoncognito.com -auth.ap-southeast-1.amazoncognito.com -auth.ap-southeast-2.amazoncognito.com -auth.ap-southeast-3.amazoncognito.com -auth.ap-southeast-4.amazoncognito.com -auth.ap-southeast-5.amazoncognito.com -auth.ap-southeast-7.amazoncognito.com -auth.ca-central-1.amazoncognito.com -auth.ca-west-1.amazoncognito.com -auth.eu-central-1.amazoncognito.com -auth.eu-central-2.amazoncognito.com -auth.eu-north-1.amazoncognito.com -auth.eu-south-1.amazoncognito.com -auth.eu-south-2.amazoncognito.com -auth.eu-west-1.amazoncognito.com -auth.eu-west-2.amazoncognito.com -auth.eu-west-3.amazoncognito.com -auth.il-central-1.amazoncognito.com -auth.me-central-1.amazoncognito.com -auth.me-south-1.amazoncognito.com -auth.mx-central-1.amazoncognito.com -auth.sa-east-1.amazoncognito.com -auth.us-east-1.amazoncognito.com -auth-fips.us-east-1.amazoncognito.com -auth.us-east-2.amazoncognito.com -auth-fips.us-east-2.amazoncognito.com -auth-fips.us-gov-east-1.amazoncognito.com -auth-fips.us-gov-west-1.amazoncognito.com -auth.us-west-1.amazoncognito.com -auth-fips.us-west-1.amazoncognito.com -auth.us-west-2.amazoncognito.com -auth-fips.us-west-2.amazoncognito.com -auth.cognito-idp.eusc-de-east-1.on.amazonwebservices.eu - -// Amazon EC2 -// Submitted by Luke Wells -// Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 -*.compute.amazonaws.com.cn -*.compute.amazonaws.com -*.compute-1.amazonaws.com -us-east-1.amazonaws.com - -// Amazon EMR -// Submitted by AWS Security -// Reference: 82f43f9f-bbb8-400e-8349-854f5a62f20d -emrappui-prod.cn-north-1.amazonaws.com.cn -emrnotebooks-prod.cn-north-1.amazonaws.com.cn -emrstudio-prod.cn-north-1.amazonaws.com.cn -emrappui-prod.cn-northwest-1.amazonaws.com.cn -emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn -emrstudio-prod.cn-northwest-1.amazonaws.com.cn -emrappui-prod.af-south-1.amazonaws.com -emrnotebooks-prod.af-south-1.amazonaws.com -emrstudio-prod.af-south-1.amazonaws.com -emrappui-prod.ap-east-1.amazonaws.com -emrnotebooks-prod.ap-east-1.amazonaws.com -emrstudio-prod.ap-east-1.amazonaws.com -emrappui-prod.ap-northeast-1.amazonaws.com -emrnotebooks-prod.ap-northeast-1.amazonaws.com -emrstudio-prod.ap-northeast-1.amazonaws.com -emrappui-prod.ap-northeast-2.amazonaws.com -emrnotebooks-prod.ap-northeast-2.amazonaws.com -emrstudio-prod.ap-northeast-2.amazonaws.com -emrappui-prod.ap-northeast-3.amazonaws.com -emrnotebooks-prod.ap-northeast-3.amazonaws.com -emrstudio-prod.ap-northeast-3.amazonaws.com -emrappui-prod.ap-south-1.amazonaws.com -emrnotebooks-prod.ap-south-1.amazonaws.com -emrstudio-prod.ap-south-1.amazonaws.com -emrappui-prod.ap-south-2.amazonaws.com -emrnotebooks-prod.ap-south-2.amazonaws.com -emrstudio-prod.ap-south-2.amazonaws.com -emrappui-prod.ap-southeast-1.amazonaws.com -emrnotebooks-prod.ap-southeast-1.amazonaws.com -emrstudio-prod.ap-southeast-1.amazonaws.com -emrappui-prod.ap-southeast-2.amazonaws.com -emrnotebooks-prod.ap-southeast-2.amazonaws.com -emrstudio-prod.ap-southeast-2.amazonaws.com -emrappui-prod.ap-southeast-3.amazonaws.com -emrnotebooks-prod.ap-southeast-3.amazonaws.com -emrstudio-prod.ap-southeast-3.amazonaws.com -emrappui-prod.ap-southeast-4.amazonaws.com -emrnotebooks-prod.ap-southeast-4.amazonaws.com -emrstudio-prod.ap-southeast-4.amazonaws.com -emrappui-prod.ca-central-1.amazonaws.com -emrnotebooks-prod.ca-central-1.amazonaws.com -emrstudio-prod.ca-central-1.amazonaws.com -emrappui-prod.ca-west-1.amazonaws.com -emrnotebooks-prod.ca-west-1.amazonaws.com -emrstudio-prod.ca-west-1.amazonaws.com -emrappui-prod.eu-central-1.amazonaws.com -emrnotebooks-prod.eu-central-1.amazonaws.com -emrstudio-prod.eu-central-1.amazonaws.com -emrappui-prod.eu-central-2.amazonaws.com -emrnotebooks-prod.eu-central-2.amazonaws.com -emrstudio-prod.eu-central-2.amazonaws.com -emrappui-prod.eu-north-1.amazonaws.com -emrnotebooks-prod.eu-north-1.amazonaws.com -emrstudio-prod.eu-north-1.amazonaws.com -emrappui-prod.eu-south-1.amazonaws.com -emrnotebooks-prod.eu-south-1.amazonaws.com -emrstudio-prod.eu-south-1.amazonaws.com -emrappui-prod.eu-south-2.amazonaws.com -emrnotebooks-prod.eu-south-2.amazonaws.com -emrstudio-prod.eu-south-2.amazonaws.com -emrappui-prod.eu-west-1.amazonaws.com -emrnotebooks-prod.eu-west-1.amazonaws.com -emrstudio-prod.eu-west-1.amazonaws.com -emrappui-prod.eu-west-2.amazonaws.com -emrnotebooks-prod.eu-west-2.amazonaws.com -emrstudio-prod.eu-west-2.amazonaws.com -emrappui-prod.eu-west-3.amazonaws.com -emrnotebooks-prod.eu-west-3.amazonaws.com -emrstudio-prod.eu-west-3.amazonaws.com -emrappui-prod.il-central-1.amazonaws.com -emrnotebooks-prod.il-central-1.amazonaws.com -emrstudio-prod.il-central-1.amazonaws.com -emrappui-prod.me-central-1.amazonaws.com -emrnotebooks-prod.me-central-1.amazonaws.com -emrstudio-prod.me-central-1.amazonaws.com -emrappui-prod.me-south-1.amazonaws.com -emrnotebooks-prod.me-south-1.amazonaws.com -emrstudio-prod.me-south-1.amazonaws.com -emrappui-prod.sa-east-1.amazonaws.com -emrnotebooks-prod.sa-east-1.amazonaws.com -emrstudio-prod.sa-east-1.amazonaws.com -emrappui-prod.us-east-1.amazonaws.com -emrnotebooks-prod.us-east-1.amazonaws.com -emrstudio-prod.us-east-1.amazonaws.com -emrappui-prod.us-east-2.amazonaws.com -emrnotebooks-prod.us-east-2.amazonaws.com -emrstudio-prod.us-east-2.amazonaws.com -emrappui-prod.us-gov-east-1.amazonaws.com -emrnotebooks-prod.us-gov-east-1.amazonaws.com -emrstudio-prod.us-gov-east-1.amazonaws.com -emrappui-prod.us-gov-west-1.amazonaws.com -emrnotebooks-prod.us-gov-west-1.amazonaws.com -emrstudio-prod.us-gov-west-1.amazonaws.com -emrappui-prod.us-west-1.amazonaws.com -emrnotebooks-prod.us-west-1.amazonaws.com -emrstudio-prod.us-west-1.amazonaws.com -emrappui-prod.us-west-2.amazonaws.com -emrnotebooks-prod.us-west-2.amazonaws.com -emrstudio-prod.us-west-2.amazonaws.com - -// Amazon Managed Workflows for Apache Airflow -// Submitted by AWS Security -// Reference: bfd043cc-2816-451d-894e-612c6b61a438 -*.airflow.af-south-1.on.aws -*.airflow.ap-east-1.on.aws -*.airflow.ap-northeast-1.on.aws -*.airflow.ap-northeast-2.on.aws -*.airflow.ap-northeast-3.on.aws -*.airflow.ap-south-1.on.aws -*.airflow.ap-south-2.on.aws -*.airflow.ap-southeast-1.on.aws -*.airflow.ap-southeast-2.on.aws -*.airflow.ap-southeast-3.on.aws -*.airflow.ap-southeast-4.on.aws -*.airflow.ap-southeast-5.on.aws -*.airflow.ca-central-1.on.aws -*.airflow.ca-west-1.on.aws -*.airflow.eu-central-1.on.aws -*.airflow.eu-central-2.on.aws -*.airflow.eu-north-1.on.aws -*.airflow.eu-south-1.on.aws -*.airflow.eu-south-2.on.aws -*.airflow.eu-west-1.on.aws -*.airflow.eu-west-2.on.aws -*.airflow.eu-west-3.on.aws -*.airflow.il-central-1.on.aws -*.airflow.me-central-1.on.aws -*.airflow.me-south-1.on.aws -*.airflow.sa-east-1.on.aws -*.airflow.us-east-1.on.aws -*.airflow.us-east-2.on.aws -*.airflow.us-west-1.on.aws -*.airflow.us-west-2.on.aws -*.cn-north-1.airflow.amazonaws.com.cn -*.cn-northwest-1.airflow.amazonaws.com.cn -*.airflow.cn-north-1.on.amazonwebservices.com.cn -*.airflow.cn-northwest-1.on.amazonwebservices.com.cn -*.af-south-1.airflow.amazonaws.com -*.ap-east-1.airflow.amazonaws.com -*.ap-northeast-1.airflow.amazonaws.com -*.ap-northeast-2.airflow.amazonaws.com -*.ap-northeast-3.airflow.amazonaws.com -*.ap-south-1.airflow.amazonaws.com -*.ap-south-2.airflow.amazonaws.com -*.ap-southeast-1.airflow.amazonaws.com -*.ap-southeast-2.airflow.amazonaws.com -*.ap-southeast-3.airflow.amazonaws.com -*.ap-southeast-4.airflow.amazonaws.com -*.ap-southeast-5.airflow.amazonaws.com -*.ap-southeast-7.airflow.amazonaws.com -*.ca-central-1.airflow.amazonaws.com -*.ca-west-1.airflow.amazonaws.com -*.eu-central-1.airflow.amazonaws.com -*.eu-central-2.airflow.amazonaws.com -*.eu-north-1.airflow.amazonaws.com -*.eu-south-1.airflow.amazonaws.com -*.eu-south-2.airflow.amazonaws.com -*.eu-west-1.airflow.amazonaws.com -*.eu-west-2.airflow.amazonaws.com -*.eu-west-3.airflow.amazonaws.com -*.il-central-1.airflow.amazonaws.com -*.me-central-1.airflow.amazonaws.com -*.me-south-1.airflow.amazonaws.com -*.sa-east-1.airflow.amazonaws.com -*.us-east-1.airflow.amazonaws.com -*.us-east-2.airflow.amazonaws.com -*.us-west-1.airflow.amazonaws.com -*.us-west-2.airflow.amazonaws.com - -// Amazon Relational Database Service -// Submitted by: AWS Security -// Reference: 5aa87906-fd4f-4831-8727-4ffca6094159 -*.rds.cn-north-1.amazonaws.com.cn -*.rds.cn-northwest-1.amazonaws.com.cn -*.af-south-1.rds.amazonaws.com -*.ap-east-1.rds.amazonaws.com -*.ap-east-2.rds.amazonaws.com -*.ap-northeast-1.rds.amazonaws.com -*.ap-northeast-2.rds.amazonaws.com -*.ap-northeast-3.rds.amazonaws.com -*.ap-south-1.rds.amazonaws.com -*.ap-south-2.rds.amazonaws.com -*.ap-southeast-1.rds.amazonaws.com -*.ap-southeast-2.rds.amazonaws.com -*.ap-southeast-3.rds.amazonaws.com -*.ap-southeast-4.rds.amazonaws.com -*.ap-southeast-5.rds.amazonaws.com -*.ap-southeast-6.rds.amazonaws.com -*.ap-southeast-7.rds.amazonaws.com -*.ca-central-1.rds.amazonaws.com -*.ca-west-1.rds.amazonaws.com -*.eu-central-1.rds.amazonaws.com -*.eu-central-2.rds.amazonaws.com -*.eu-west-1.rds.amazonaws.com -*.eu-west-2.rds.amazonaws.com -*.eu-west-3.rds.amazonaws.com -*.il-central-1.rds.amazonaws.com -*.me-central-1.rds.amazonaws.com -*.me-south-1.rds.amazonaws.com -*.mx-central-1.rds.amazonaws.com -*.sa-east-1.rds.amazonaws.com -*.us-east-1.rds.amazonaws.com -*.us-east-2.rds.amazonaws.com -*.us-gov-east-1.rds.amazonaws.com -*.us-gov-west-1.rds.amazonaws.com -*.us-northeast-1.rds.amazonaws.com -*.us-west-1.rds.amazonaws.com -*.us-west-2.rds.amazonaws.com - -// Amazon S3 -// Submitted by AWS Security -// Reference: 6f374c1c-1cc9-47de-8b2a-69ca56a3a3b6 -s3.dualstack.cn-north-1.amazonaws.com.cn -s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn -s3-website.dualstack.cn-north-1.amazonaws.com.cn -s3.cn-north-1.amazonaws.com.cn -s3-accesspoint.cn-north-1.amazonaws.com.cn -s3-deprecated.cn-north-1.amazonaws.com.cn -s3-object-lambda.cn-north-1.amazonaws.com.cn -s3-website.cn-north-1.amazonaws.com.cn -s3.dualstack.cn-northwest-1.amazonaws.com.cn -s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn -s3.cn-northwest-1.amazonaws.com.cn -s3-accesspoint.cn-northwest-1.amazonaws.com.cn -s3-object-lambda.cn-northwest-1.amazonaws.com.cn -s3-website.cn-northwest-1.amazonaws.com.cn -s3.dualstack.af-south-1.amazonaws.com -s3-accesspoint.dualstack.af-south-1.amazonaws.com -s3-website.dualstack.af-south-1.amazonaws.com -s3.af-south-1.amazonaws.com -s3-accesspoint.af-south-1.amazonaws.com -s3-object-lambda.af-south-1.amazonaws.com -s3-website.af-south-1.amazonaws.com -s3.dualstack.ap-east-1.amazonaws.com -s3-accesspoint.dualstack.ap-east-1.amazonaws.com -s3.ap-east-1.amazonaws.com -s3-accesspoint.ap-east-1.amazonaws.com -s3-object-lambda.ap-east-1.amazonaws.com -s3-website.ap-east-1.amazonaws.com -s3.dualstack.ap-northeast-1.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com -s3-website.dualstack.ap-northeast-1.amazonaws.com -s3.ap-northeast-1.amazonaws.com -s3-accesspoint.ap-northeast-1.amazonaws.com -s3-object-lambda.ap-northeast-1.amazonaws.com -s3-website.ap-northeast-1.amazonaws.com -s3.dualstack.ap-northeast-2.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com -s3-website.dualstack.ap-northeast-2.amazonaws.com -s3.ap-northeast-2.amazonaws.com -s3-accesspoint.ap-northeast-2.amazonaws.com -s3-object-lambda.ap-northeast-2.amazonaws.com -s3-website.ap-northeast-2.amazonaws.com -s3.dualstack.ap-northeast-3.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com -s3-website.dualstack.ap-northeast-3.amazonaws.com -s3.ap-northeast-3.amazonaws.com -s3-accesspoint.ap-northeast-3.amazonaws.com -s3-object-lambda.ap-northeast-3.amazonaws.com -s3-website.ap-northeast-3.amazonaws.com -s3.dualstack.ap-south-1.amazonaws.com -s3-accesspoint.dualstack.ap-south-1.amazonaws.com -s3-website.dualstack.ap-south-1.amazonaws.com -s3.ap-south-1.amazonaws.com -s3-accesspoint.ap-south-1.amazonaws.com -s3-object-lambda.ap-south-1.amazonaws.com -s3-website.ap-south-1.amazonaws.com -s3.dualstack.ap-south-2.amazonaws.com -s3-accesspoint.dualstack.ap-south-2.amazonaws.com -s3-website.dualstack.ap-south-2.amazonaws.com -s3.ap-south-2.amazonaws.com -s3-accesspoint.ap-south-2.amazonaws.com -s3-object-lambda.ap-south-2.amazonaws.com -s3-website.ap-south-2.amazonaws.com -s3.dualstack.ap-southeast-1.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com -s3-website.dualstack.ap-southeast-1.amazonaws.com -s3.ap-southeast-1.amazonaws.com -s3-accesspoint.ap-southeast-1.amazonaws.com -s3-object-lambda.ap-southeast-1.amazonaws.com -s3-website.ap-southeast-1.amazonaws.com -s3.dualstack.ap-southeast-2.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com -s3-website.dualstack.ap-southeast-2.amazonaws.com -s3.ap-southeast-2.amazonaws.com -s3-accesspoint.ap-southeast-2.amazonaws.com -s3-object-lambda.ap-southeast-2.amazonaws.com -s3-website.ap-southeast-2.amazonaws.com -s3.dualstack.ap-southeast-3.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com -s3-website.dualstack.ap-southeast-3.amazonaws.com -s3.ap-southeast-3.amazonaws.com -s3-accesspoint.ap-southeast-3.amazonaws.com -s3-object-lambda.ap-southeast-3.amazonaws.com -s3-website.ap-southeast-3.amazonaws.com -s3.dualstack.ap-southeast-4.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com -s3-website.dualstack.ap-southeast-4.amazonaws.com -s3.ap-southeast-4.amazonaws.com -s3-accesspoint.ap-southeast-4.amazonaws.com -s3-object-lambda.ap-southeast-4.amazonaws.com -s3-website.ap-southeast-4.amazonaws.com -s3.dualstack.ap-southeast-5.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com -s3-website.dualstack.ap-southeast-5.amazonaws.com -s3.ap-southeast-5.amazonaws.com -s3-accesspoint.ap-southeast-5.amazonaws.com -s3-deprecated.ap-southeast-5.amazonaws.com -s3-object-lambda.ap-southeast-5.amazonaws.com -s3-website.ap-southeast-5.amazonaws.com -s3.dualstack.ca-central-1.amazonaws.com -s3-accesspoint.dualstack.ca-central-1.amazonaws.com -s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com -s3-fips.dualstack.ca-central-1.amazonaws.com -s3-website.dualstack.ca-central-1.amazonaws.com -s3.ca-central-1.amazonaws.com -s3-accesspoint.ca-central-1.amazonaws.com -s3-accesspoint-fips.ca-central-1.amazonaws.com -s3-fips.ca-central-1.amazonaws.com -s3-object-lambda.ca-central-1.amazonaws.com -s3-website.ca-central-1.amazonaws.com -s3.dualstack.ca-west-1.amazonaws.com -s3-accesspoint.dualstack.ca-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com -s3-fips.dualstack.ca-west-1.amazonaws.com -s3-website.dualstack.ca-west-1.amazonaws.com -s3.ca-west-1.amazonaws.com -s3-accesspoint.ca-west-1.amazonaws.com -s3-accesspoint-fips.ca-west-1.amazonaws.com -s3-fips.ca-west-1.amazonaws.com -s3-object-lambda.ca-west-1.amazonaws.com -s3-website.ca-west-1.amazonaws.com -s3.dualstack.eu-central-1.amazonaws.com -s3-accesspoint.dualstack.eu-central-1.amazonaws.com -s3-website.dualstack.eu-central-1.amazonaws.com -s3.eu-central-1.amazonaws.com -s3-accesspoint.eu-central-1.amazonaws.com -s3-object-lambda.eu-central-1.amazonaws.com -s3-website.eu-central-1.amazonaws.com -s3.dualstack.eu-central-2.amazonaws.com -s3-accesspoint.dualstack.eu-central-2.amazonaws.com -s3-website.dualstack.eu-central-2.amazonaws.com -s3.eu-central-2.amazonaws.com -s3-accesspoint.eu-central-2.amazonaws.com -s3-object-lambda.eu-central-2.amazonaws.com -s3-website.eu-central-2.amazonaws.com -s3.dualstack.eu-north-1.amazonaws.com -s3-accesspoint.dualstack.eu-north-1.amazonaws.com -s3.eu-north-1.amazonaws.com -s3-accesspoint.eu-north-1.amazonaws.com -s3-object-lambda.eu-north-1.amazonaws.com -s3-website.eu-north-1.amazonaws.com -s3.dualstack.eu-south-1.amazonaws.com -s3-accesspoint.dualstack.eu-south-1.amazonaws.com -s3-website.dualstack.eu-south-1.amazonaws.com -s3.eu-south-1.amazonaws.com -s3-accesspoint.eu-south-1.amazonaws.com -s3-object-lambda.eu-south-1.amazonaws.com -s3-website.eu-south-1.amazonaws.com -s3.dualstack.eu-south-2.amazonaws.com -s3-accesspoint.dualstack.eu-south-2.amazonaws.com -s3-website.dualstack.eu-south-2.amazonaws.com -s3.eu-south-2.amazonaws.com -s3-accesspoint.eu-south-2.amazonaws.com -s3-object-lambda.eu-south-2.amazonaws.com -s3-website.eu-south-2.amazonaws.com -s3.dualstack.eu-west-1.amazonaws.com -s3-accesspoint.dualstack.eu-west-1.amazonaws.com -s3-website.dualstack.eu-west-1.amazonaws.com -s3.eu-west-1.amazonaws.com -s3-accesspoint.eu-west-1.amazonaws.com -s3-deprecated.eu-west-1.amazonaws.com -s3-object-lambda.eu-west-1.amazonaws.com -s3-website.eu-west-1.amazonaws.com -s3.dualstack.eu-west-2.amazonaws.com -s3-accesspoint.dualstack.eu-west-2.amazonaws.com -s3.eu-west-2.amazonaws.com -s3-accesspoint.eu-west-2.amazonaws.com -s3-object-lambda.eu-west-2.amazonaws.com -s3-website.eu-west-2.amazonaws.com -s3.dualstack.eu-west-3.amazonaws.com -s3-accesspoint.dualstack.eu-west-3.amazonaws.com -s3-website.dualstack.eu-west-3.amazonaws.com -s3.eu-west-3.amazonaws.com -s3-accesspoint.eu-west-3.amazonaws.com -s3-object-lambda.eu-west-3.amazonaws.com -s3-website.eu-west-3.amazonaws.com -s3.dualstack.il-central-1.amazonaws.com -s3-accesspoint.dualstack.il-central-1.amazonaws.com -s3-website.dualstack.il-central-1.amazonaws.com -s3.il-central-1.amazonaws.com -s3-accesspoint.il-central-1.amazonaws.com -s3-object-lambda.il-central-1.amazonaws.com -s3-website.il-central-1.amazonaws.com -s3.dualstack.me-central-1.amazonaws.com -s3-accesspoint.dualstack.me-central-1.amazonaws.com -s3-website.dualstack.me-central-1.amazonaws.com -s3.me-central-1.amazonaws.com -s3-accesspoint.me-central-1.amazonaws.com -s3-object-lambda.me-central-1.amazonaws.com -s3-website.me-central-1.amazonaws.com -s3.dualstack.me-south-1.amazonaws.com -s3-accesspoint.dualstack.me-south-1.amazonaws.com -s3.me-south-1.amazonaws.com -s3-accesspoint.me-south-1.amazonaws.com -s3-object-lambda.me-south-1.amazonaws.com -s3-website.me-south-1.amazonaws.com -s3.amazonaws.com -s3-1.amazonaws.com -s3-ap-east-1.amazonaws.com -s3-ap-northeast-1.amazonaws.com -s3-ap-northeast-2.amazonaws.com -s3-ap-northeast-3.amazonaws.com -s3-ap-south-1.amazonaws.com -s3-ap-southeast-1.amazonaws.com -s3-ap-southeast-2.amazonaws.com -s3-ca-central-1.amazonaws.com -s3-eu-central-1.amazonaws.com -s3-eu-north-1.amazonaws.com -s3-eu-west-1.amazonaws.com -s3-eu-west-2.amazonaws.com -s3-eu-west-3.amazonaws.com -s3-external-1.amazonaws.com -s3-fips-us-gov-east-1.amazonaws.com -s3-fips-us-gov-west-1.amazonaws.com -mrap.accesspoint.s3-global.amazonaws.com -s3-me-south-1.amazonaws.com -s3-sa-east-1.amazonaws.com -s3-us-east-2.amazonaws.com -s3-us-gov-east-1.amazonaws.com -s3-us-gov-west-1.amazonaws.com -s3-us-west-1.amazonaws.com -s3-us-west-2.amazonaws.com -s3-website-ap-northeast-1.amazonaws.com -s3-website-ap-southeast-1.amazonaws.com -s3-website-ap-southeast-2.amazonaws.com -s3-website-eu-west-1.amazonaws.com -s3-website-sa-east-1.amazonaws.com -s3-website-us-east-1.amazonaws.com -s3-website-us-gov-west-1.amazonaws.com -s3-website-us-west-1.amazonaws.com -s3-website-us-west-2.amazonaws.com -s3.dualstack.sa-east-1.amazonaws.com -s3-accesspoint.dualstack.sa-east-1.amazonaws.com -s3-website.dualstack.sa-east-1.amazonaws.com -s3.sa-east-1.amazonaws.com -s3-accesspoint.sa-east-1.amazonaws.com -s3-object-lambda.sa-east-1.amazonaws.com -s3-website.sa-east-1.amazonaws.com -s3.dualstack.us-east-1.amazonaws.com -s3-accesspoint.dualstack.us-east-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com -s3-fips.dualstack.us-east-1.amazonaws.com -s3-website.dualstack.us-east-1.amazonaws.com -s3.us-east-1.amazonaws.com -s3-accesspoint.us-east-1.amazonaws.com -s3-accesspoint-fips.us-east-1.amazonaws.com -s3-deprecated.us-east-1.amazonaws.com -s3-fips.us-east-1.amazonaws.com -s3-object-lambda.us-east-1.amazonaws.com -s3-website.us-east-1.amazonaws.com -s3.dualstack.us-east-2.amazonaws.com -s3-accesspoint.dualstack.us-east-2.amazonaws.com -s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com -s3-fips.dualstack.us-east-2.amazonaws.com -s3-website.dualstack.us-east-2.amazonaws.com -s3.us-east-2.amazonaws.com -s3-accesspoint.us-east-2.amazonaws.com -s3-accesspoint-fips.us-east-2.amazonaws.com -s3-deprecated.us-east-2.amazonaws.com -s3-fips.us-east-2.amazonaws.com -s3-object-lambda.us-east-2.amazonaws.com -s3-website.us-east-2.amazonaws.com -s3.dualstack.us-gov-east-1.amazonaws.com -s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com -s3-fips.dualstack.us-gov-east-1.amazonaws.com -s3-website.dualstack.us-gov-east-1.amazonaws.com -s3.us-gov-east-1.amazonaws.com -s3-accesspoint.us-gov-east-1.amazonaws.com -s3-accesspoint-fips.us-gov-east-1.amazonaws.com -s3-fips.us-gov-east-1.amazonaws.com -s3-object-lambda.us-gov-east-1.amazonaws.com -s3-website.us-gov-east-1.amazonaws.com -s3.dualstack.us-gov-west-1.amazonaws.com -s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com -s3-fips.dualstack.us-gov-west-1.amazonaws.com -s3-website.dualstack.us-gov-west-1.amazonaws.com -s3.us-gov-west-1.amazonaws.com -s3-accesspoint.us-gov-west-1.amazonaws.com -s3-accesspoint-fips.us-gov-west-1.amazonaws.com -s3-fips.us-gov-west-1.amazonaws.com -s3-object-lambda.us-gov-west-1.amazonaws.com -s3-website.us-gov-west-1.amazonaws.com -s3.dualstack.us-west-1.amazonaws.com -s3-accesspoint.dualstack.us-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com -s3-fips.dualstack.us-west-1.amazonaws.com -s3-website.dualstack.us-west-1.amazonaws.com -s3.us-west-1.amazonaws.com -s3-accesspoint.us-west-1.amazonaws.com -s3-accesspoint-fips.us-west-1.amazonaws.com -s3-fips.us-west-1.amazonaws.com -s3-object-lambda.us-west-1.amazonaws.com -s3-website.us-west-1.amazonaws.com -s3.dualstack.us-west-2.amazonaws.com -s3-accesspoint.dualstack.us-west-2.amazonaws.com -s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com -s3-fips.dualstack.us-west-2.amazonaws.com -s3-website.dualstack.us-west-2.amazonaws.com -s3.us-west-2.amazonaws.com -s3-accesspoint.us-west-2.amazonaws.com -s3-accesspoint-fips.us-west-2.amazonaws.com -s3-deprecated.us-west-2.amazonaws.com -s3-fips.us-west-2.amazonaws.com -s3-object-lambda.us-west-2.amazonaws.com -s3-website.us-west-2.amazonaws.com - -// Amazon SageMaker Ground Truth -// Submitted by AWS Security -// Reference: 98dbfde4-7802-48c3-8751-b60f204e0d9c -labeling.ap-northeast-1.sagemaker.aws -labeling.ap-northeast-2.sagemaker.aws -labeling.ap-south-1.sagemaker.aws -labeling.ap-southeast-1.sagemaker.aws -labeling.ap-southeast-2.sagemaker.aws -labeling.ca-central-1.sagemaker.aws -labeling.eu-central-1.sagemaker.aws -labeling.eu-west-1.sagemaker.aws -labeling.eu-west-2.sagemaker.aws -labeling.us-east-1.sagemaker.aws -labeling.us-east-2.sagemaker.aws -labeling.us-west-2.sagemaker.aws - -// Amazon SageMaker Notebook Instances -// Submitted by AWS Security -// Reference: b5ea56df-669e-43cc-9537-14aa172f5dfc -notebook.af-south-1.sagemaker.aws -notebook.ap-east-1.sagemaker.aws -notebook.ap-northeast-1.sagemaker.aws -notebook.ap-northeast-2.sagemaker.aws -notebook.ap-northeast-3.sagemaker.aws -notebook.ap-south-1.sagemaker.aws -notebook.ap-south-2.sagemaker.aws -notebook.ap-southeast-1.sagemaker.aws -notebook.ap-southeast-2.sagemaker.aws -notebook.ap-southeast-3.sagemaker.aws -notebook.ap-southeast-4.sagemaker.aws -notebook.ca-central-1.sagemaker.aws -notebook-fips.ca-central-1.sagemaker.aws -notebook.ca-west-1.sagemaker.aws -notebook-fips.ca-west-1.sagemaker.aws -notebook.eu-central-1.sagemaker.aws -notebook.eu-central-2.sagemaker.aws -notebook.eu-north-1.sagemaker.aws -notebook.eu-south-1.sagemaker.aws -notebook.eu-south-2.sagemaker.aws -notebook.eu-west-1.sagemaker.aws -notebook.eu-west-2.sagemaker.aws -notebook.eu-west-3.sagemaker.aws -notebook.il-central-1.sagemaker.aws -notebook.me-central-1.sagemaker.aws -notebook.me-south-1.sagemaker.aws -notebook.sa-east-1.sagemaker.aws -notebook.us-east-1.sagemaker.aws -notebook-fips.us-east-1.sagemaker.aws -notebook.us-east-2.sagemaker.aws -notebook-fips.us-east-2.sagemaker.aws -notebook.us-gov-east-1.sagemaker.aws -notebook-fips.us-gov-east-1.sagemaker.aws -notebook.us-gov-west-1.sagemaker.aws -notebook-fips.us-gov-west-1.sagemaker.aws -notebook.us-west-1.sagemaker.aws -notebook-fips.us-west-1.sagemaker.aws -notebook.us-west-2.sagemaker.aws -notebook-fips.us-west-2.sagemaker.aws -notebook.cn-north-1.sagemaker.com.cn -notebook.cn-northwest-1.sagemaker.com.cn - -// Amazon SageMaker Studio -// Submitted by AWS Security -// Reference: 475f237e-ab88-4041-9f41-7cfccdf66aeb -studio.af-south-1.sagemaker.aws -studio.ap-east-1.sagemaker.aws -studio.ap-northeast-1.sagemaker.aws -studio.ap-northeast-2.sagemaker.aws -studio.ap-northeast-3.sagemaker.aws -studio.ap-south-1.sagemaker.aws -studio.ap-southeast-1.sagemaker.aws -studio.ap-southeast-2.sagemaker.aws -studio.ap-southeast-3.sagemaker.aws -studio.ca-central-1.sagemaker.aws -studio.eu-central-1.sagemaker.aws -studio.eu-central-2.sagemaker.aws -studio.eu-north-1.sagemaker.aws -studio.eu-south-1.sagemaker.aws -studio.eu-south-2.sagemaker.aws -studio.eu-west-1.sagemaker.aws -studio.eu-west-2.sagemaker.aws -studio.eu-west-3.sagemaker.aws -studio.il-central-1.sagemaker.aws -studio.me-central-1.sagemaker.aws -studio.me-south-1.sagemaker.aws -studio.sa-east-1.sagemaker.aws -studio.us-east-1.sagemaker.aws -studio.us-east-2.sagemaker.aws -studio.us-gov-east-1.sagemaker.aws -studio-fips.us-gov-east-1.sagemaker.aws -studio.us-gov-west-1.sagemaker.aws -studio-fips.us-gov-west-1.sagemaker.aws -studio.us-west-1.sagemaker.aws -studio.us-west-2.sagemaker.aws -studio.cn-north-1.sagemaker.com.cn -studio.cn-northwest-1.sagemaker.com.cn - -// Amazon SageMaker with MLflow -// Submited by: AWS Security -// Reference: c19f92b3-a82a-452d-8189-831b572eea7e -*.experiments.sagemaker.aws - -// Analytics on AWS -// Submitted by AWS Security -// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd -analytics-gateway.ap-northeast-1.amazonaws.com -analytics-gateway.ap-northeast-2.amazonaws.com -analytics-gateway.ap-south-1.amazonaws.com -analytics-gateway.ap-southeast-1.amazonaws.com -analytics-gateway.ap-southeast-2.amazonaws.com -analytics-gateway.eu-central-1.amazonaws.com -analytics-gateway.eu-west-1.amazonaws.com -analytics-gateway.us-east-1.amazonaws.com -analytics-gateway.us-east-2.amazonaws.com -analytics-gateway.us-west-2.amazonaws.com - -// AWS Amplify -// Submitted by AWS Security -// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b -amplifyapp.com - -// AWS App Runner -// Submitted by AWS Security -// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316 -*.awsapprunner.com - -// AWS Cloud9 -// Submitted by: AWS Security -// Reference: 30717f72-4007-4f0f-8ed4-864c6f2efec9 -webview-assets.aws-cloud9.af-south-1.amazonaws.com -vfs.cloud9.af-south-1.amazonaws.com -webview-assets.cloud9.af-south-1.amazonaws.com -webview-assets.aws-cloud9.ap-east-1.amazonaws.com -vfs.cloud9.ap-east-1.amazonaws.com -webview-assets.cloud9.ap-east-1.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com -vfs.cloud9.ap-northeast-1.amazonaws.com -webview-assets.cloud9.ap-northeast-1.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com -vfs.cloud9.ap-northeast-2.amazonaws.com -webview-assets.cloud9.ap-northeast-2.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com -vfs.cloud9.ap-northeast-3.amazonaws.com -webview-assets.cloud9.ap-northeast-3.amazonaws.com -webview-assets.aws-cloud9.ap-south-1.amazonaws.com -vfs.cloud9.ap-south-1.amazonaws.com -webview-assets.cloud9.ap-south-1.amazonaws.com -webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com -vfs.cloud9.ap-southeast-1.amazonaws.com -webview-assets.cloud9.ap-southeast-1.amazonaws.com -webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com -vfs.cloud9.ap-southeast-2.amazonaws.com -webview-assets.cloud9.ap-southeast-2.amazonaws.com -webview-assets.aws-cloud9.ca-central-1.amazonaws.com -vfs.cloud9.ca-central-1.amazonaws.com -webview-assets.cloud9.ca-central-1.amazonaws.com -webview-assets.aws-cloud9.eu-central-1.amazonaws.com -vfs.cloud9.eu-central-1.amazonaws.com -webview-assets.cloud9.eu-central-1.amazonaws.com -webview-assets.aws-cloud9.eu-north-1.amazonaws.com -vfs.cloud9.eu-north-1.amazonaws.com -webview-assets.cloud9.eu-north-1.amazonaws.com -webview-assets.aws-cloud9.eu-south-1.amazonaws.com -vfs.cloud9.eu-south-1.amazonaws.com -webview-assets.cloud9.eu-south-1.amazonaws.com -webview-assets.aws-cloud9.eu-west-1.amazonaws.com -vfs.cloud9.eu-west-1.amazonaws.com -webview-assets.cloud9.eu-west-1.amazonaws.com -webview-assets.aws-cloud9.eu-west-2.amazonaws.com -vfs.cloud9.eu-west-2.amazonaws.com -webview-assets.cloud9.eu-west-2.amazonaws.com -webview-assets.aws-cloud9.eu-west-3.amazonaws.com -vfs.cloud9.eu-west-3.amazonaws.com -webview-assets.cloud9.eu-west-3.amazonaws.com -webview-assets.aws-cloud9.il-central-1.amazonaws.com -vfs.cloud9.il-central-1.amazonaws.com -webview-assets.aws-cloud9.me-south-1.amazonaws.com -vfs.cloud9.me-south-1.amazonaws.com -webview-assets.cloud9.me-south-1.amazonaws.com -webview-assets.aws-cloud9.sa-east-1.amazonaws.com -vfs.cloud9.sa-east-1.amazonaws.com -webview-assets.cloud9.sa-east-1.amazonaws.com -webview-assets.aws-cloud9.us-east-1.amazonaws.com -vfs.cloud9.us-east-1.amazonaws.com -webview-assets.cloud9.us-east-1.amazonaws.com -webview-assets.aws-cloud9.us-east-2.amazonaws.com -vfs.cloud9.us-east-2.amazonaws.com -webview-assets.cloud9.us-east-2.amazonaws.com -webview-assets.aws-cloud9.us-west-1.amazonaws.com -vfs.cloud9.us-west-1.amazonaws.com -webview-assets.cloud9.us-west-1.amazonaws.com -webview-assets.aws-cloud9.us-west-2.amazonaws.com -vfs.cloud9.us-west-2.amazonaws.com -webview-assets.cloud9.us-west-2.amazonaws.com - -// AWS Directory Service -// Submitted by AWS Security -// Reference: a13203e8-42dc-4045-a0d2-2ee67bed1068 -awsapps.com - -// AWS Elastic Beanstalk -// Submitted by AWS Security -// Reference: e4e02a54-eaf9-4fe7-b662-39ccbc011a04 -cn-north-1.eb.amazonaws.com.cn -cn-northwest-1.eb.amazonaws.com.cn -elasticbeanstalk.com -af-south-1.elasticbeanstalk.com -ap-east-1.elasticbeanstalk.com -ap-northeast-1.elasticbeanstalk.com -ap-northeast-2.elasticbeanstalk.com -ap-northeast-3.elasticbeanstalk.com -ap-south-1.elasticbeanstalk.com -ap-southeast-1.elasticbeanstalk.com -ap-southeast-2.elasticbeanstalk.com -ap-southeast-3.elasticbeanstalk.com -ap-southeast-5.elasticbeanstalk.com -ap-southeast-7.elasticbeanstalk.com -ca-central-1.elasticbeanstalk.com -eu-central-1.elasticbeanstalk.com -eu-north-1.elasticbeanstalk.com -eu-south-1.elasticbeanstalk.com -eu-south-2.elasticbeanstalk.com -eu-west-1.elasticbeanstalk.com -eu-west-2.elasticbeanstalk.com -eu-west-3.elasticbeanstalk.com -il-central-1.elasticbeanstalk.com -me-central-1.elasticbeanstalk.com -me-south-1.elasticbeanstalk.com -sa-east-1.elasticbeanstalk.com -us-east-1.elasticbeanstalk.com -us-east-2.elasticbeanstalk.com -us-gov-east-1.elasticbeanstalk.com -us-gov-west-1.elasticbeanstalk.com -us-west-1.elasticbeanstalk.com -us-west-2.elasticbeanstalk.com - -// (AWS) Elastic Load Balancing -// Submitted by Luke Wells -// Reference: 12a3d528-1bac-4433-a359-a395867ffed2 -*.elb.amazonaws.com.cn -*.elb.amazonaws.com - -// AWS Global Accelerator -// Submitted by Daniel Massaguer -// Reference: d916759d-a08b-4241-b536-4db887383a6a -awsglobalaccelerator.com - -// AWS Lambda Function URLs -// Submitted by AWS Security -// Reference: 57df74ca-0820-46a5-89ea-0f0d0c4714b7 -lambda-url.af-south-1.on.aws -lambda-url.ap-east-1.on.aws -lambda-url.ap-northeast-1.on.aws -lambda-url.ap-northeast-2.on.aws -lambda-url.ap-northeast-3.on.aws -lambda-url.ap-south-1.on.aws -lambda-url.ap-southeast-1.on.aws -lambda-url.ap-southeast-2.on.aws -lambda-url.ap-southeast-3.on.aws -lambda-url.ca-central-1.on.aws -lambda-url.eu-central-1.on.aws -lambda-url.eu-north-1.on.aws -lambda-url.eu-south-1.on.aws -lambda-url.eu-west-1.on.aws -lambda-url.eu-west-2.on.aws -lambda-url.eu-west-3.on.aws -lambda-url.me-south-1.on.aws -lambda-url.sa-east-1.on.aws -lambda-url.us-east-1.on.aws -lambda-url.us-east-2.on.aws -lambda-url.us-west-1.on.aws -lambda-url.us-west-2.on.aws - -// AWS re:Post Private -// Submitted by AWS Security -// Reference: 83385945-225f-416e-9aa0-ad0632bfdcee -*.private.repost.aws - -// AWS Transfer Family web apps -// Submitted by AWS Security -// Reference: 9265cdd3-f017-42ab-98bb-08bf427d3fc9 -transfer-webapp.af-south-1.on.aws -transfer-webapp.ap-east-1.on.aws -transfer-webapp.ap-northeast-1.on.aws -transfer-webapp.ap-northeast-2.on.aws -transfer-webapp.ap-northeast-3.on.aws -transfer-webapp.ap-south-1.on.aws -transfer-webapp.ap-south-2.on.aws -transfer-webapp.ap-southeast-1.on.aws -transfer-webapp.ap-southeast-2.on.aws -transfer-webapp.ap-southeast-3.on.aws -transfer-webapp.ap-southeast-4.on.aws -transfer-webapp.ap-southeast-5.on.aws -transfer-webapp.ap-southeast-7.on.aws -transfer-webapp.ca-central-1.on.aws -transfer-webapp.ca-west-1.on.aws -transfer-webapp.eu-central-1.on.aws -transfer-webapp.eu-central-2.on.aws -transfer-webapp.eu-north-1.on.aws -transfer-webapp.eu-south-1.on.aws -transfer-webapp.eu-south-2.on.aws -transfer-webapp.eu-west-1.on.aws -transfer-webapp.eu-west-2.on.aws -transfer-webapp.eu-west-3.on.aws -transfer-webapp.il-central-1.on.aws -transfer-webapp.me-central-1.on.aws -transfer-webapp.me-south-1.on.aws -transfer-webapp.mx-central-1.on.aws -transfer-webapp.sa-east-1.on.aws -transfer-webapp.us-east-1.on.aws -transfer-webapp.us-east-2.on.aws -transfer-webapp.us-gov-east-1.on.aws -transfer-webapp-fips.us-gov-east-1.on.aws -transfer-webapp.us-gov-west-1.on.aws -transfer-webapp-fips.us-gov-west-1.on.aws -transfer-webapp.us-west-1.on.aws -transfer-webapp.us-west-2.on.aws -transfer-webapp.cn-north-1.on.amazonwebservices.com.cn -transfer-webapp.cn-northwest-1.on.amazonwebservices.com.cn - -// eero -// Submitted by Yue Kang -// Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461 -eero.online -eero-stage.online - -// concludes Amazon - -// Anomaly : https://opencode.ai -// Submitted by Dax Raad -opentunnel.xyz - -// Antagonist B.V. : https://www.antagonist.nl/ -// Submitted by Sander Hoentjen -antagonist.cloud - -// Anthropic : https://www.anthropic.com/ -// Submitted by Sid Bidasaria -claude.app - -// Apigee : https://apigee.com/ -// Submitted by Apigee Security Team -apigee.io - -// Apis Networks : https://apisnetworks.com -// Submitted by Matt Saladna -panel.dev - -// Apphud : https://apphud.com -// Submitted by Alexander Selivanov -siiites.com - -// Apple : https://www.apple.com -// Submitted by Apple DNS -int.apple -*.cloud.int.apple -*.r.cloud.int.apple -*.ap-north-1.r.cloud.int.apple -*.ap-south-1.r.cloud.int.apple -*.ap-south-2.r.cloud.int.apple -*.eu-central-1.r.cloud.int.apple -*.eu-north-1.r.cloud.int.apple -*.us-central-1.r.cloud.int.apple -*.us-central-2.r.cloud.int.apple -*.us-east-1.r.cloud.int.apple -*.us-east-2.r.cloud.int.apple -*.us-west-1.r.cloud.int.apple -*.us-west-2.r.cloud.int.apple -*.us-west-3.r.cloud.int.apple - -// Appspace : https://www.appspace.com -// Submitted by Appspace Security Team -appspacehosted.com -appspaceusercontent.com - -// Appudo UG (haftungsbeschränkt) : https://www.appudo.com -// Submitted by Alexander Hochbaum -appudo.net - -// Appwrite : https://appwrite.io -// Submitted by Steven Nguyen -appwrite.global -appwrite.network -*.appwrite.run - -// Aptible : https://www.aptible.com/ -// Submitted by Thomas Orozco -on-aptible.com - -// Aquapal : https://aquapal.net/ -// Submitted by Aki Ueno -f5.si - -// ArvanCloud EdgeCompute -// Submitted by ArvanCloud CDN -arvanedge.ir - -// ASEINet : https://www.aseinet.com/ -// Submitted by Asei SEKIGUCHI -user.aseinet.ne.jp -gv.vc -d.gv.vc - -// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ -// Submitted by Hector Martin -user.party.eus - -// Association potager.org : https://potager.org/ -// Submitted by Lunar -pimienta.org -poivron.org -potager.org -sweetpepper.org - -// ASUSTOR Inc. : http://www.asustor.com -// Submitted by Vincent Tseng -myasustor.com - -// Atlassian : https://atlassian.com -// Submitted by Benjamin McAlary -*.atlassian-3p.com -*.atlassian-3p-us-gov-mod.com -*.atlassian-isolated-3p.com -cdn.prod.atlassian-dev.net - -// AVM : https://avm.de -// Submitted by Andreas Weise -myfritz.link -myfritz.net - -// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com -// Submitted by James Kennedy -*.awdev.ca -*.advisor.ws - -// AZ.pl sp. z.o.o : https://az.pl -// Submitted by Krzysztof Wolski -ecommerce-shop.pl - -// b-data GmbH : https://www.b-data.io -// Submitted by Olivier Benz -b-data.io - -// Balena : https://www.balena.io -// Submitted by Petros Angelatos -balena-devices.com - -// BASE, Inc. : https://binc.jp -// Submitted by Yuya NAGASAWA -base.ec -official.ec -buyshop.jp -fashionstore.jp -handcrafted.jp -kawaiishop.jp -supersale.jp -theshop.jp -shopselect.net -base.shop - -// BeagleBoard.org Foundation : https://beagleboard.org -// Submitted by Jason Kridner -beagleboard.io - -// Bear Blog : https://bearblog.dev -// Submitted by Herman Martinus -bearblog.dev - -// Beget LLC : https://beget.com -// Submitted by Lev Nekrasov & Nikita Radchenko -*.beget.app -*.begetcdn.cloud - -// Besties : https://besties.house -// Submitted by Hazel Cora -pages.gay - -// BinaryLane : http://www.binarylane.com -// Submitted by Nathan O'Sullivan -bnr.la - -// Bitbucket : http://bitbucket.org -// Submitted by Andy Ortlieb -bitbucket.io - -// Blackbaud, Inc. : https://www.blackbaud.com -// Submitted by Paul Crowder -blackbaudcdn.net - -// Blatech : http://www.blatech.net -// Submitted by Luke Bratch -of.je - -// Block, Inc. : https://block.xyz -// Submitted by Jonathan Boice -square.site - -// Blue Bite, LLC : https://bluebite.com -// Submitted by Joshua Weiss -bluebite.io - -// Boomla : https://boomla.com -// Submitted by Tibor Halter -boomla.net - -// Boutir : https://www.boutir.com -// Submitted by Eric Ng Ka Ka -boutir.com - -// Boxfuse : https://boxfuse.com -// Submitted by Axel Fontaine -boxfuse.io - -// bplaced : https://www.bplaced.net/ -// Submitted by Miroslav Bozic -square7.ch -bplaced.com -bplaced.de -square7.de -bplaced.net -square7.net - -// Brave : https://brave.com -// Submitted by Andrea Brancaleoni -brave.app -*.s.brave.app -brave.dev -*.s.brave.dev -brave.io -*.s.brave.io - -// Brendly : https://brendly.rs -// Submitted by Dusan Radovanovic -shop.brendly.ba -shop.brendly.hr -shop.brendly.rs - -// BrowserSafetyMark -// Submitted by Dave Tharp -browsersafetymark.io - -// BRS Media : https://brsmedia.com/ -// Submitted by Gavin Brown -radio.am -radio.fm - -// Bubble : https://bubble.io/ -// Submitted by Merlin Zhao -cdn.bubble.io -bubbleapps.io - -// bwCloud-OS : https://bwcloud-os.de/ -// Submitted by Klara Mall -*.bwcloud-os-instance.de - -// Caf.js Labs LLC : https://www.cafjs.com -// Submitted by Antonio Lain -cafjs.com - -// Canva Pty Ltd : https://canva.com/ -// Submitted by Joel Aquilina -canva-apps.cn -my.canvasite.cn -khsj.cn -canva-apps.com -canva-hosted-embed.com -canvacode.com -rice-labs.com -canva.link -canva.run -my.canva.site - -// Carrd : https://carrd.co -// Submitted by AJ -drr.ac -uwu.ai -carrd.co -crd.co -ju.mp - -// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk -// Submitted by Jamie Tanna -api.gov.uk - -// CDN77.com : http://www.cdn77.com -// Submitted by Jan Krpes -cdn77-storage.com -rsc.contentproxy9.cz -r.cdn77.net -cdn77-ssl.net -c.cdn77.org -rsc.cdn77.org -ssl.origin.cdn77-secure.org - -// CentralNic : https://teaminternet.com/ -// Submitted by registry -za.bz -br.com -cn.com -de.com -eu.com -jpn.com -mex.com -ru.com -sa.com -uk.com -us.com -za.com -com.de -gb.net -hu.net -jp.net -se.net -uk.net -ae.org -com.se - -// Cityhost LLC : https://cityhost.ua -// Submitted by Maksym Rivtin -cx.ua - -// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ -// Submitted by Rishabh Nambiar, Michael Brown, Rafael dos Santos Silva -discourse.diy -discourse.group -discourse.team - -// Clerk : https://www.clerk.dev -// Submitted by Colin Sidoti -clerk.app -clerkstage.app -*.lcl.dev -*.lclstage.dev -*.stg.dev -*.stgstage.dev - -// Clever Cloud : https://www.clever-cloud.com/ -// Submitted by Quentin Adam -cleverapps.cc -*.services.clever-cloud.com -cleverapps.io -cleverapps.tech - -// ClickRising : https://clickrising.com/ -// Submitted by Umut Gumeli -clickrising.net - -// Cloud DNS Ltd : http://www.cloudns.net -// Submitted by Aleksander Hristov & Boyan Peychev -cloudns.asia -cloudns.be -cloud-ip.biz -cloudns.biz -cloud-ip.cc -cloudns.cc -cloudns.ch -cloudns.cl -cloudns.club -abrdns.com -dnsabr.com -ip-ddns.com -cloudns.cx -cloudns.eu -cloudns.in -cloudns.info -ddns-ip.net -dns-cloud.net -dns-dynamic.net -cloudns.nz -cloudns.org -ip-dynamic.org -cloudns.ph -cloudns.pro -cloudns.pw -cloudns.us - -// Cloud66 : https://www.cloud66.com/ -// Submitted by Khash Sajadi -c66.me -cloud66.ws - -// CloudAccess.net : https://www.cloudaccess.net/ -// Submitted by Pawel Panek -jdevcloud.com -wpdevcloud.com -cloudaccess.host -freesite.host -cloudaccess.net - -// Cloudbees, Inc. : https://www.cloudbees.com/ -// Submitted by Mohideen Shajith -cloudbeesusercontent.io - -// Cloudera, Inc. : https://www.cloudera.com/ -// Submitted by Kedarnath Waikar -*.cloudera.site - -// Cloudflare, Inc. : https://www.cloudflare.com/ -// Submitted by Cloudflare Team -cloudflare.app -cf-ipfs.com -cloudflare-ipfs.com -trycloudflare.com -pages.dev -r2.dev -workers.dev -cloudflare.net -cdn.cloudflare.net -cdn.cloudflareanycast.net -cdn.cloudflarecn.net -cdn.cloudflareglobal.net - -// cloudscale.ch AG : https://www.cloudscale.ch/ -// Submitted by Gaudenz Steinlin -cust.cloudscale.ch -objects.lpg.cloudscale.ch -objects.rma.cloudscale.ch -lpg.objectstorage.ch -rma.objectstorage.ch - -// Clovyr : https://clovyr.io -// Submitted by Patrick Nielsen -wnext.app - -// CNPY : https://cnpy.gdn -// Submitted by Angelo Gladding -cnpy.gdn - -// Co & Co : https://co-co.nl/ -// Submitted by Govert Versluis -*.otap.co - -// co.ca : http://registry.co.ca/ -co.ca - -// co.com Registry, LLC : https://registry.co.com -// Submitted by Gavin Brown -co.com - -// Code For Host Inc Ltd : https://codeforhost.com -// Submitted by Mehedi Hasan -sch.ac -dev.cv -store.cv - -// Codeberg e. V. : https://codeberg.org -// Submitted by Moritz Marquardt -codeberg.page - -// CodeSandbox B.V. : https://codesandbox.io -// Submitted by Ives van Hoorne -csb.app -preview.csb.app - -// CoDNS B.V. -co.nl -co.no - -// Cognition AI, Inc. : https://cognition.ai -// Submitted by Philip Papurt -*.devinapps.com - -// Combell.com : https://www.combell.com -// Submitted by Combell Team -webhosting.be -prvw.eu -hosting-cluster.nl - -// Contentful GmbH : https://www.contentful.com -// Submitted by Contentful Developer Experience Team -ctfcloud.net - -// Convex : https://convex.dev/ -// Submitted by James Cowling -convex.app -convex.cloud -eu-west-1.convex.cloud -us-east-1.convex.cloud -convex.site -eu-west-1.convex.site -us-east-1.convex.site - -// Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ -// Submitted by George Georgievsky -ac.ru -edu.ru -gov.ru -int.ru -mil.ru - -// CoreSpeed, Inc. : https://corespeed.io -// Submitted by CoreSpeed Team -corespeed.app - -// COSIMO GmbH : http://www.cosimo.de -// Submitted by Rene Marticke -dyn.cosidns.de -dnsupdater.de -dynamisches-dns.de -internet-dns.de -l-o-g-i-n.de -dynamic-dns.info -feste-ip.net -knx-server.net -static-access.net - -// Craft Docs Ltd : https://www.craft.do/ -// Submitted by Zsombor Fuszenecker -craft.me - -// Craynic, s.r.o. : http://www.craynic.com/ -// Submitted by Ales Krajnik -realm.cz - -// cyber_Folks S.A. : https://cyberfolks.pl -// Submitted by Bartlomiej Kida -cfolks.pl - -// cyon GmbH : https://www.cyon.ch/ -// Submitted by Dominic Luechinger -cyon.link -cyon.site - -// Dansk.net : http://www.dansk.net/ -// Submitted by Anani Voule -biz.dk -co.dk -firm.dk -reg.dk -store.dk - -// dappnode.io : https://dappnode.io/ -// Submitted by Abel Boldu / DAppNode Team -dyndns.dappnode.io - -// Dark, Inc. : https://darklang.com -// Submitted by Paul Biggar -builtwithdark.com -darklang.io - -// DataDetect, LLC. : https://datadetect.com -// Submitted by Andrew Banchich -demo.datadetect.com -instance.datadetect.com - -// Datawire, Inc : https://www.datawire.io -// Submitted by Richard Li -edgestack.me - -// Datto, Inc. : https://www.datto.com/ -// Submitted by Philipp Heckel -dattolocal.com -dattorelay.com -dattoweb.com -mydatto.com -dattolocal.net -mydatto.net - -// ddnss.de : https://www.ddnss.de/ -// Submitted by Robert Niedziela -ddnss.de -dyn.ddnss.de -dyndns.ddnss.de -dyn-ip24.de -dyndns1.de -home-webserver.de -dyn.home-webserver.de -myhome-server.de -ddnss.org - -// Debian : https://www.debian.org/ -// Submitted by Peter Palfrader / Debian Sysadmin Team -debian.net - -// Definima : http://www.definima.com/ -// Submitted by Maxence Bitterli -definima.io -definima.net - -// Deno Land Inc : https://deno.com/ -// Submitted by Luca Casonato -deno.dev -deno-staging.dev -deno.net -sandbox.deno.net - -// DeployAgent : https://deployagent.com -// Submitted by Danny -deployagent.com -piebox.site -deployagent.space - -// deSEC : https://desec.io/ -// Submitted by Peter Thomassen -dedyn.io - -// Deuxfleurs : https://deuxfleurs.fr -// Submitted by Aeddis Desauw -deuxfleurs.eu -deuxfleurs.page - -// Developed Methods LLC : https://methods.dev -// Submitted by Patrick Lorio -*.at.ply.gg -d6.ply.gg -joinmc.link -playit.plus -*.at.playit.plus -with.playit.plus - -// Dfinity Foundation: https://dfinity.org/ -// Submitted by Dfinity Team -icp0.io -*.raw.icp0.io -icp1.io -*.raw.icp1.io -*.icp.net -caffeine.site -caffeine.xyz - -// dhosting.pl Sp. z o.o. : https://dhosting.pl/ -// Submitted by Szczepan Redzioch -mybox.company -intouch.email -mybox.me -mybox.page -dfirma.pl -dkonto.pl -you2.pl - -// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ -// Submitted by Braxton Huggins -ondigitalocean.app - -// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ -// Submitted by Robin H. Johnson -*.digitaloceanspaces.com - -// DigitalPlat : https://www.digitalplat.org/ -// Submitted by Edward Hsing -qzz.io -us.kg -xx.kg -dpdns.org - -// Discord Inc : https://discord.com -// Submitted by Sahn Lam -discordsays.com -discordsez.com - -// DNS Africa Ltd : https://dns.business -// Submitted by Calvin Browne -jozi.biz - -// DNSHE : https://www.dnshe.com -// Submitted by DNSHE Team -ccwu.cc -cc.cd -us.ci -de5.net - -// dnsHome : https://www.dnshome.de/ -// Submitted by Norbert Auler -dnshome.at -resolve.bar -ddns.berlin -dnshome.cloud -ddnssec.de -dnshome.de -dyndnssec.de -heimdns.de -srvdns.de -dnshome.eu -dnshome.it -dyn.now -heimdns.online -ddns.wtf - -// DotArai : https://www.dotarai.com/ -// Submitted by Atsadawat Netcharadsang -online.th -shop.th - -// dotScot Domains : https://domains.scot/ -// Submitted by DNS Team -co.scot -me.scot -org.scot - -// DrayTek Corp. : https://www.draytek.com/ -// Submitted by Paul Fang -drayddns.com - -// DreamCommerce : https://shoper.pl/ -// Submitted by Konrad Kotarba -shoparena.pl - -// DreamHost : http://www.dreamhost.com/ -// Submitted by Andrew Farmer -dreamhosters.com - -// Dreamyoungs, Inc. : https://durumis.com -// Submitted by Infra Team -durumis.com - -// DuckDNS : http://www.duckdns.org/ -// Submitted by Richard Harper -duckdns.org - -// dy.fi : http://dy.fi/ -// Submitted by Heikki Hannikainen -dy.fi -tunk.org - -// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ -dyndns.biz -for-better.biz -for-more.biz -for-some.biz -for-the.biz -selfip.biz -webhop.biz -ftpaccess.cc -game-server.cc -myphotos.cc -scrapping.cc -blogdns.com -cechire.com -dnsalias.com -dnsdojo.com -doesntexist.com -dontexist.com -doomdns.com -dyn-o-saur.com -dynalias.com -dyndns-at-home.com -dyndns-at-work.com -dyndns-blog.com -dyndns-free.com -dyndns-home.com -dyndns-ip.com -dyndns-mail.com -dyndns-office.com -dyndns-pics.com -dyndns-remote.com -dyndns-server.com -dyndns-web.com -dyndns-wiki.com -dyndns-work.com -est-a-la-maison.com -est-a-la-masion.com -est-le-patron.com -est-mon-blogueur.com -from-ak.com -from-al.com -from-ar.com -from-ca.com -from-ct.com -from-dc.com -from-de.com -from-fl.com -from-ga.com -from-hi.com -from-ia.com -from-id.com -from-il.com -from-in.com -from-ks.com -from-ky.com -from-ma.com -from-md.com -from-mi.com -from-mn.com -from-mo.com -from-ms.com -from-mt.com -from-nc.com -from-nd.com -from-ne.com -from-nh.com -from-nj.com -from-nm.com -from-nv.com -from-oh.com -from-ok.com -from-or.com -from-pa.com -from-pr.com -from-ri.com -from-sc.com -from-sd.com -from-tn.com -from-tx.com -from-ut.com -from-va.com -from-vt.com -from-wa.com -from-wi.com -from-wv.com -from-wy.com -getmyip.com -gotdns.com -hobby-site.com -homelinux.com -homeunix.com -iamallama.com -is-a-anarchist.com -is-a-blogger.com -is-a-bookkeeper.com -is-a-bulls-fan.com -is-a-caterer.com -is-a-chef.com -is-a-conservative.com -is-a-cpa.com -is-a-cubicle-slave.com -is-a-democrat.com -is-a-designer.com -is-a-doctor.com -is-a-financialadvisor.com -is-a-geek.com -is-a-green.com -is-a-guru.com -is-a-hard-worker.com -is-a-hunter.com -is-a-landscaper.com -is-a-lawyer.com -is-a-liberal.com -is-a-libertarian.com -is-a-llama.com -is-a-musician.com -is-a-nascarfan.com -is-a-nurse.com -is-a-painter.com -is-a-personaltrainer.com -is-a-photographer.com -is-a-player.com -is-a-republican.com -is-a-rockstar.com -is-a-socialist.com -is-a-student.com -is-a-teacher.com -is-a-techie.com -is-a-therapist.com -is-an-accountant.com -is-an-actor.com -is-an-actress.com -is-an-anarchist.com -is-an-artist.com -is-an-engineer.com -is-an-entertainer.com -is-certified.com -is-gone.com -is-into-anime.com -is-into-cars.com -is-into-cartoons.com -is-into-games.com -is-leet.com -is-not-certified.com -is-slick.com -is-uberleet.com -is-with-theband.com -isa-geek.com -isa-hockeynut.com -issmarterthanyou.com -likes-pie.com -likescandy.com -neat-url.com -saves-the-whales.com -selfip.com -sells-for-less.com -sells-for-u.com -servebbs.com -simple-url.com -space-to-rent.com -teaches-yoga.com -writesthisblog.com -ath.cx -fuettertdasnetz.de -isteingeek.de -istmein.de -lebtimnetz.de -leitungsen.de -traeumtgerade.de -barrel-of-knowledge.info -barrell-of-knowledge.info -dyndns.info -for-our.info -groks-the.info -groks-this.info -here-for-more.info -knowsitall.info -selfip.info -webhop.info -forgot.her.name -forgot.his.name -at-band-camp.net -blogdns.net -broke-it.net -buyshouses.net -dnsalias.net -dnsdojo.net -does-it.net -dontexist.net -dynalias.net -dynathome.net -endofinternet.net -from-az.net -from-co.net -from-la.net -from-ny.net -gets-it.net -ham-radio-op.net -homeftp.net -homeip.net -homelinux.net -homeunix.net -in-the-band.net -is-a-chef.net -is-a-geek.net -isa-geek.net -kicks-ass.net -office-on-the.net -podzone.net -scrapper-site.net -selfip.net -sells-it.net -servebbs.net -serveftp.net -thruhere.net -webhop.net -merseine.nu -mine.nu -shacknet.nu -blogdns.org -blogsite.org -boldlygoingnowhere.org -dnsalias.org -dnsdojo.org -doesntexist.org -dontexist.org -doomdns.org -dvrdns.org -dynalias.org -dyndns.org -go.dyndns.org -home.dyndns.org -endofinternet.org -endoftheinternet.org -from-me.org -game-host.org -gotdns.org -hobby-site.org -homedns.org -homeftp.org -homelinux.org -homeunix.org -is-a-bruinsfan.org -is-a-candidate.org -is-a-celticsfan.org -is-a-chef.org -is-a-geek.org -is-a-knight.org -is-a-linux-user.org -is-a-patsfan.org -is-a-soxfan.org -is-found.org -is-lost.org -is-saved.org -is-very-bad.org -is-very-evil.org -is-very-good.org -is-very-nice.org -is-very-sweet.org -isa-geek.org -kicks-ass.org -misconfused.org -podzone.org -readmyblog.org -selfip.org -sellsyourhome.org -servebbs.org -serveftp.org -servegame.org -stuff-4-sale.org -webhop.org -better-than.tv -dyndns.tv -on-the-web.tv -worse-than.tv -is-by.us -land-4-sale.us -stuff-4-sale.us -dyndns.ws -mypets.ws - -// Dynu.com : https://www.dynu.com/ -// Submitted by Sue Ye -1cooldns.com -bumbleshrimp.com -ddnsfree.com -ddnsgeek.com -ddnsguru.com -dynuddns.com -dynuhosting.com -giize.com -gleeze.com -kozow.com -loseyourip.com -ooguy.com -pivohosting.com -theworkpc.com -wiredbladehosting.com -casacam.net -dynu.net -dynuddns.net -mysynology.net -opik.net -spryt.net -accesscam.org -camdvr.org -freeddns.org -mywire.org -roxa.org -webredirect.org -myddns.rocks - -// dynv6 : https://dynv6.com -// Submitted by Dominik Menke -dynv6.net - -// E4YOU spol. s.r.o. : https://e4you.cz/ -// Submitted by Vladimir Dudr -e4.cz - -// Easypanel : https://easypanel.io -// Submitted by Andrei Canta -easypanel.app -easypanel.host - -// EasyWP : https://www.easywp.com -// Submitted by -*.ewp.live - -// eDirect Corp. : https://hosting.url.com.tw/ -// Submitted by C.S. chang -twmail.cc -twmail.net -twmail.org -mymailer.com.tw -url.tw - -// Electromagnetic Field : https://www.emfcamp.org -// Submitted by -at.emf.camp - -// Elefunc, Inc. : https://elefunc.com -// Submitted by Cetin Sert -rt.ht - -// Elementor : Elementor Ltd. -// Submitted by Anton Barkan -elementor.cloud -elementor.cool - -// Emergent : https://emergent.sh -// Submitted by Emergent Security Team -emergent.cloud -preview.emergentagent.com -emergent.host - -// Enalean SAS : https://www.enalean.com -// Submitted by Enalean Security Team -mytuleap.com -tuleap-partners.com - -// Encoretivity AB : https://encore.cloud -// Submitted by André Eriksson -encr.app -frontend.encr.app -encoreapi.com -lp.dev -api.lp.dev -objects.lp.dev - -// encoway GmbH : https://www.encoway.de -// Submitted by Marcel Daus -eu.encoway.cloud - -// EU.org : https://eu.org/ -// Submitted by Pierre Beyssac -eu.org -al.eu.org -asso.eu.org -at.eu.org -au.eu.org -be.eu.org -bg.eu.org -ca.eu.org -cd.eu.org -ch.eu.org -cn.eu.org -cy.eu.org -cz.eu.org -de.eu.org -dk.eu.org -edu.eu.org -ee.eu.org -es.eu.org -fi.eu.org -fr.eu.org -gr.eu.org -hr.eu.org -hu.eu.org -ie.eu.org -il.eu.org -in.eu.org -int.eu.org -is.eu.org -it.eu.org -jp.eu.org -kr.eu.org -lt.eu.org -lu.eu.org -lv.eu.org -me.eu.org -mk.eu.org -mt.eu.org -my.eu.org -net.eu.org -ng.eu.org -nl.eu.org -no.eu.org -nz.eu.org -pl.eu.org -pt.eu.org -ro.eu.org -ru.eu.org -se.eu.org -si.eu.org -sk.eu.org -tr.eu.org -uk.eu.org -us.eu.org - -// Eurobyte : https://eurobyte.ru -// Submitted by Evgeniy Subbotin -eurodir.ru - -// Evennode : http://www.evennode.com/ -// Submitted by Michal Kralik -eu-1.evennode.com -eu-2.evennode.com -eu-3.evennode.com -eu-4.evennode.com -us-1.evennode.com -us-2.evennode.com -us-3.evennode.com -us-4.evennode.com - -// Evervault : https://evervault.com -// Submitted by Hannah Neary -relay.evervault.app -relay.evervault.dev - -// Exe : https://exe.dev -// Submitted by Josh Bleecher Snyder -exe.xyz - -// Expo : https://expo.dev/ -// Submitted by Phil Pluckthun -expo.app -on.expo.app -staging.expo.app -on.staging.expo.app - -// fachschaften.org: https://fachschaften.org/ -// Submitted by Felix Schäfer -fspages.org - -// FAITID : https://faitid.org/ -// Submitted by Maxim Alzoba -// https://www.flexireg.net/stat_info -ru.net -adygeya.ru -bashkiria.ru -bir.ru -cbg.ru -com.ru -dagestan.ru -grozny.ru -kalmykia.ru -kustanai.ru -marine.ru -mordovia.ru -msk.ru -mytis.ru -nalchik.ru -nov.ru -pyatigorsk.ru -spb.ru -vladikavkaz.ru -vladimir.ru -abkhazia.su -adygeya.su -aktyubinsk.su -arkhangelsk.su -armenia.su -ashgabad.su -azerbaijan.su -balashov.su -bashkiria.su -bryansk.su -bukhara.su -chimkent.su -dagestan.su -east-kazakhstan.su -exnet.su -georgia.su -grozny.su -ivanovo.su -jambyl.su -kalmykia.su -kaluga.su -karacol.su -karaganda.su -karelia.su -khakassia.su -krasnodar.su -kurgan.su -kustanai.su -lenug.su -mangyshlak.su -mordovia.su -msk.su -murmansk.su -nalchik.su -navoi.su -north-kazakhstan.su -nov.su -obninsk.su -penza.su -pokrovsk.su -sochi.su -spb.su -tashkent.su -termez.su -togliatti.su -troitsk.su -tselinograd.su -tula.su -tuva.su -vladikavkaz.su -vladimir.su -vologda.su - -// Fancy Bits, LLC : http://getchannels.com -// Submitted by Aman Gupta -channelsdvr.net -u.channelsdvr.net - -// Fastly Inc. : http://www.fastly.com/ -// Submitted by Fastly Security -edgecompute.app -fastly-edge.com -fastly-terrarium.com -freetls.fastly.net -map.fastly.net -a.prod.fastly.net -global.prod.fastly.net -a.ssl.fastly.net -b.ssl.fastly.net -global.ssl.fastly.net -fastlylb.net -map.fastlylb.net - -// Fastmail : https://www.fastmail.com/ -// Submitted by Marc Bradshaw -*.user.fm - -// FASTVPS EESTI OU : https://fastvps.ru/ -// Submitted by Likhachev Vasiliy -fastvps-server.com -fastvps.host -myfast.host -fastvps.site -myfast.space - -// FearWorks Media Ltd. : https://fearworksmedia.co.uk -// Submitted by Keith Fairley -conn.uk -copro.uk -hosp.uk - -// Fedora : https://fedoraproject.org/ -// Submitted by Patrick Uiterwijk -fedorainfracloud.org -fedorapeople.org -cloud.fedoraproject.org -app.os.fedoraproject.org -app.os.stg.fedoraproject.org - -// Fermax : https://fermax.com/ -// Submitted by Koen Van Isterdael -mydobiss.com - -// FH Muenster : https://www.fh-muenster.de -// Submitted by Robin Naundorf -fh-muenster.io - -// Figma : https://www.figma.com -// Submitted by Nick Frost -payload.dev -figma.site -figma-gov.site -preview.site - -// Filegear Inc. : https://www.filegear.com -// Submitted by Jason Zhu -filegear.me - -// Firebase, Inc. -// Submitted by Chris Raynor -firebaseapp.com - -// FlashDrive : https://flashdrive.io -// Submitted by Eric Chan -fldrv.com - -// Fleek Labs Inc : https://fleek.xyz -// Submitted by Parsa Ghadimi -on-fleek.app - -// FlutterFlow : https://flutterflow.io -// Submitted by Anton Emelyanov -flutterflow.app - -// fly.io : https://fly.io -// Submitted by Kurt Mackey -sprites.app -fly.dev - -// FoundryLabs, Inc : https://e2b.dev/ -// Submitted by Jiri Sveceny -e2b.app - -// Framer : https://www.framer.com -// Submitted by Koen Rouwhorst -framer.ai -framer.app -framercanvas.com -framer.media -framer.photos -framer.website -framer.wiki - -// Frederik Braun : https://frederik-braun.com -// Submitted by Frederik Braun -*.0e.vc - -// Freebox : http://www.freebox.fr -// Submitted by Romain Fliedel -freebox-os.com -freeboxos.com -fbx-os.fr -fbxos.fr -freebox-os.fr -freeboxos.fr - -// freedesktop.org : https://www.freedesktop.org -// Submitted by Daniel Stone -freedesktop.org - -// freemyip.com : https://freemyip.com -// Submitted by Cadence -freemyip.com - -// Frusky MEDIA&PR : https://www.frusky.de -// Submitted by Victor Pupynin -*.frusky.de - -// FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at -// Submitted by Daniel A. Maierhofer -wien.funkfeuer.at - -// Future Versatile Group. : https://www.fvg-on.net/ -// T.Kabu -daemon.asia -dix.asia -mydns.bz -0am.jp -0g0.jp -0j0.jp -0t0.jp -mydns.jp -pgw.jp -wjg.jp -keyword-on.net -live-on.net -server-on.net -mydns.tw -mydns.vc - -// Futureweb GmbH : https://www.futureweb.at -// Submitted by Andreas Schnederle-Wagner -*.futurecms.at -*.ex.futurecms.at -*.in.futurecms.at -futurehosting.at -futuremailing.at -*.ex.ortsinfo.at -*.kunden.ortsinfo.at -*.statics.cloud - -// Gadget Software Inc. : https://gadget.dev -// Submitted by Harry Brundage -gadget.app -gadget.host - -// GCom Internet : https://www.gcom.net.au -// Submitted by Leo Julius -aliases121.com - -// GDS : https://www.gov.uk/service-manual/technology/managing-domain-names -// Submitted by Stephen Ford -campaign.gov.uk -service.gov.uk -independent-commission.uk -independent-inquest.uk -independent-inquiry.uk -independent-panel.uk -independent-review.uk -public-inquiry.uk -royal-commission.uk - -// Gehirn Inc. : https://www.gehirn.co.jp/ -// Submitted by Kohei YOSHIDA -gehirn.ne.jp -usercontent.jp - -// Gentlent, Inc. : https://www.gentlent.com -// Submitted by Tom Klein -gentapps.com -gentlentapis.com -cdn-edges.net - -// GignoSystemJapan : http://gsj.bz -// Submitted by GignoSystemJapan -gsj.bz - -// GitBook Inc. : https://www.gitbook.com/ -// Submitted by Samy Pesse -gitbook.io - -// GitHub, Inc. -// Submitted by Patrick Toomey -github.app -githubusercontent.com -githubpreview.dev -github.io - -// GitLab, Inc. : https://about.gitlab.com/ -// Submitted by Alex Hanselka -gitlab.io - -// Gitplac.si : https://gitplac.si -// Submitted by Aljaž Starc -gitapp.si -gitpage.si - -// Global NOG Alliance : https://nogalliance.org/ -// Submitted by Sander Steffann -nog.community - -// Globe Hosting SRL : https://www.globehosting.com/ -// Submitted by Gavin Brown -co.ro -shop.ro - -// GMO Pepabo, Inc. : https://pepabo.com/ -// Submitted by Hosting Div -lolipop.io -angry.jp -babyblue.jp -babymilk.jp -backdrop.jp -bambina.jp -bitter.jp -blush.jp -boo.jp -boy.jp -boyfriend.jp -but.jp -candypop.jp -capoo.jp -catfood.jp -cheap.jp -chicappa.jp -chillout.jp -chips.jp -chowder.jp -chu.jp -ciao.jp -cocotte.jp -coolblog.jp -cranky.jp -cutegirl.jp -daa.jp -deca.jp -deci.jp -digick.jp -egoism.jp -fakefur.jp -fem.jp -flier.jp -floppy.jp -fool.jp -frenchkiss.jp -girlfriend.jp -girly.jp -gloomy.jp -gonna.jp -greater.jp -hacca.jp -heavy.jp -her.jp -hiho.jp -hippy.jp -holy.jp -hungry.jp -icurus.jp -itigo.jp -jellybean.jp -kikirara.jp -kill.jp -kilo.jp -kuron.jp -littlestar.jp -lolipopmc.jp -lolitapunk.jp -lomo.jp -lovepop.jp -lovesick.jp -main.jp -mods.jp -mond.jp -mongolian.jp -moo.jp -namaste.jp -nikita.jp -nobushi.jp -noor.jp -oops.jp -parallel.jp -parasite.jp -pecori.jp -peewee.jp -penne.jp -pepper.jp -perma.jp -pigboat.jp -pinoko.jp -punyu.jp -pupu.jp -pussycat.jp -pya.jp -raindrop.jp -readymade.jp -sadist.jp -schoolbus.jp -secret.jp -staba.jp -stripper.jp -sub.jp -sunnyday.jp -thick.jp -tonkotsu.jp -under.jp -upper.jp -velvet.jp -verse.jp -versus.jp -vivian.jp -watson.jp -weblike.jp -whitesnow.jp -zombie.jp -heteml.net - -// GNTC, Inc. : https://gntc.com/ -// Submitted by VibeHost Security -vibehost.space - -// GoDaddy Registry : https://registry.godaddy -// Submitted by Rohan Durrant -graphic.design - -// GoIP DNS Services : http://www.goip.de -// Submitted by Christian Poulter -goip.de - -// Google, Inc. -// Submitted by Shannon McCabe -*.hosted.app -*.run.app -*.mtls.run.app -web.app -*.0emm.com -appspot.com -*.r.appspot.com -blogspot.com -codespot.com -googleapis.com -googlecode.com -pagespeedmobilizer.com -withgoogle.com -withyoutube.com -*.gateway.dev -cloud.goog -translate.goog -*.usercontent.goog -cloudfunctions.net - -// Goupile : https://goupile.fr -// Submitted by Niels Martignene -goupile.fr - -// GOV.UK Pay : https://www.payments.service.gov.uk/ -// Submitted by Richard Baker -pymnt.uk - -// Government of the Netherlands : https://www.government.nl -// Submitted by -gov.nl - -// Grafana Labs : https://grafana.com/ -// Submitted by Platform Engineering -grafana-dev.net - -// GrayJay Web Solutions Inc. : https://grayjaysports.ca -// Submitted by Matt Yamkowy -grayjayleagues.com - -// Grebedoc : https://grebedoc.dev -// Submitted by Catherine Zotova -grebedoc.dev - -// GünstigBestellen : https://günstigbestellen.de -// Submitted by Furkan Akkoc -günstigbestellen.de -günstigliefern.de - -// GV.UY : https://nic.gv.uy -// Submitted by cheng -gv.uy - -// Hackclub Nest : https://hackclub.app -// Submitted by Cyteon -hackclub.app - -// Häkkinen.fi : https://www.häkkinen.fi/ -// Submitted by Eero Häkkinen -häkkinen.fi - -// Hashbang : https://hashbang.sh -hashbang.sh - -// Hasura : https://hasura.io -// Submitted by Shahidh K Muhammed -hasura.app -hasura-app.io - -// Hatena Co., Ltd. : https://hatena.co.jp -// Submitted by Masato Nakamura -hatenablog.com -hatenadiary.com -hateblo.jp -hatenablog.jp -hatenadiary.jp -hatenadiary.org - -// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages) : https://www.hs-heilbronn.de -// Submitted by Richard Zowalla -pages.it.hs-heilbronn.de -pages-research.it.hs-heilbronn.de - -// HeiyuSpace : https://lazycat.cloud -// Submitted by Xia Bin -heiyu.space - -// Helio Networks : https://heliohost.org -// Submitted by Ben Frede -helioho.st -heliohost.us - -// Hepforge : https://www.hepforge.org -// Submitted by David Grellscheid -hepforge.org - -// Hercules : https://hercules.app -// Submitted by Brendan Falk -onhercules.app -hercules-app.com -hercules-dev.com - -// Heroku : https://www.heroku.com/ -// Submitted by Shumon Huque -herokuapp.com - -// Heyflow : https://www.heyflow.com -// Submitted by Mirko Nitschke -heyflow.page -heyflow.site - -// Hibernating Rhinos -// Submitted by Oren Eini -ravendb.cloud -ravendb.community -development.run -ravendb.run - -// HiDNS : https://www.hidoha.net -// Submitted by ifeng -hidns.co -hidns.vip - -// home.pl S.A. : https://home.pl -// Submitted by Krzysztof Wolski -homesklep.pl - -// Homebase : https://homebase.id/ -// Submitted by Jason Babo -*.kin.one -*.id.pub -*.kin.pub - -// HOOC AG : https://www.hooc.ch -// Submitted by Fabrizio Steiner -seprox.hooc.me - -// Hoplix : https://www.hoplix.com -// Submitted by Danilo De Franco -hoplix.shop - -// HOSTBIP REGISTRY : https://www.hostbip.com/ -// Submitted by Atanunu Igbunuroghene -orx.biz -biz.ng -co.biz.ng -dl.biz.ng -go.biz.ng -lg.biz.ng -on.biz.ng -col.ng -firm.ng -gen.ng -ltd.ng -ngo.ng -plc.ng - -// Hostinger : https://hostinger.com -// Submitted by Valentinas Cirba -hstgr.cloud - -// HostyHosting : https://hostyhosting.com -hostyhosting.io - -// Hugging Face : https://huggingface.co -// Submitted by Eliott Coyac -hf.space -static.hf.space - -// Hypernode B.V. : https://www.hypernode.com/ -// Submitted by Cipriano Groenendal -hypernode.io - -// I-O DATA DEVICE, INC. : http://www.iodata.com/ -// Submitted by Yuji Minagawa -iobb.net - -// i-registry s.r.o. : http://www.i-registry.cz/ -// Submitted by Martin Semrad -co.cz - -// Ici la Lune : http://www.icilalune.com/ -// Submitted by Simon Morvan -*.moonscale.io -moonscale.net - -// iDOT Services Limited : http://www.domain.gr.com -// Submitted by Gavin Brown -gr.com - -// iki.fi -// Submitted by Hannu Aronsson -iki.fi - -// iliad italia : https://www.iliad.it -// Submitted by Marios Makassikis -ibxos.it -iliadboxos.it - -// Imagine : https://imagine.dev -// Submitted by Steven Nguyen -imagine.diy -imagine-proxy.work - -// Incsub, LLC : https://incsub.com/ -// Submitted by Aaron Edwards -smushcdn.com -wphostedmail.com -wpmucdn.com -tempurl.host -wpmudev.host - -// Individual Network Berlin e.V. : https://www.in-berlin.de/ -// Submitted by Christian Seitz -dyn-berlin.de -in-berlin.de -in-brb.de -in-butter.de -in-dsl.de -in-vpn.de -in-dsl.net -in-vpn.net -in-dsl.org -in-vpn.org - -// Inferno Communications : https://inferno.co.uk -// Submitted by Connor McFarlane -oninferno.net - -// info.cx : http://info.cx -// Submitted by June Slater -info.cx - -// Interlegis : http://www.interlegis.leg.br -// Submitted by Gabriel Ferreira -ac.leg.br -al.leg.br -am.leg.br -ap.leg.br -ba.leg.br -ce.leg.br -df.leg.br -es.leg.br -go.leg.br -ma.leg.br -mg.leg.br -ms.leg.br -mt.leg.br -pa.leg.br -pb.leg.br -pe.leg.br -pi.leg.br -pr.leg.br -rj.leg.br -rn.leg.br -ro.leg.br -rr.leg.br -rs.leg.br -sc.leg.br -se.leg.br -sp.leg.br -to.leg.br - -// intermetrics GmbH : https://pixolino.com/ -// Submitted by Wolfgang Schwarz -pixolino.com - -// Internet-Pro, LLP : https://netangels.ru/ -// Submitted by Vasiliy Sheredeko -na4u.ru - -// Inventor Services : https://inventor.gg/ -// Submitted by Inventor Team -botdash.app -botdash.dev -botdash.gg -botdash.net -botda.sh -botdash.xyz - -// IONOS SE : https://www.ionos.com/ -// IONOS Group SE : https://www.ionos-group.com/ -// Submitted by Henrik Willert -apps-1and1.com -live-website.com -webspace-host.com -apps-1and1.net -websitebuilder.online -app-ionos.space - -// iopsys software solutions AB : https://iopsys.eu/ -// Submitted by Roman Azarenko -iopsys.se - -// IPFS Project : https://ipfs.tech/ -// Submitted by Interplanetary Shipyard -*.inbrowser.dev -*.dweb.link -*.inbrowser.link - -// IPiFony Systems, Inc. : https://www.ipifony.com/ -// Submitted by Matthew Hardeman -ipifony.net - -// IPv64.net : https://ipv64.net/ -// Submitted by Dennis Schröder -home64.de -ipv64.de -ipv64.net - -// ir.md : https://nic.ir.md -// Submitted by Ali Soizi -ir.md - -// is-a-good.dev : https://is-a-good.dev -// Submitted by William Harrison -is-a-good.dev - -// IServ GmbH : https://iserv.de -// Submitted by Kim Brodowski -iservschule.de -mein-iserv.de -schuldock.de -schulplattform.de -schulserver.de -test-iserv.de -iserv.dev -iserv.host - -// Ispmanager : https://www.ispmanager.com/ -// Submitted by Ispmanager infrastructure team -ispmanager.name - -// Jelastic, Inc. : https://jelastic.com/ -// Submitted by Ihor Kolodyuk -mel.cloudlets.com.au -cloud.interhostsolutions.be -alp1.ae.flow.ch -appengine.flow.ch -es-1.axarnet.cloud -diadem.cloud -vip.jelastic.cloud -jele.cloud -it1.eur.aruba.jenv-aruba.cloud -it1.jenv-aruba.cloud -keliweb.cloud -cs.keliweb.cloud -oxa.cloud -tn.oxa.cloud -uk.oxa.cloud -primetel.cloud -uk.primetel.cloud -ca.reclaim.cloud -uk.reclaim.cloud -us.reclaim.cloud -ch.trendhosting.cloud -de.trendhosting.cloud -jele.club -dopaas.com -paas.hosted-by-previder.com -rag-cloud.hosteur.com -rag-cloud-ch.hosteur.com -jcloud.ik-server.com -jcloud-ver-jpc.ik-server.com -demo.jelastic.com -paas.massivegrid.com -jed.wafaicloud.com -ryd.wafaicloud.com -j.scaleforce.com.cy -jelastic.dogado.eu -fi.cloudplatform.fi -demo.datacenter.fi -paas.datacenter.fi -jele.host -mircloud.host -paas.beebyte.io -sekd1.beebyteapp.io -jele.io -jc.neen.it -jcloud.kz -cloudjiffy.net -fra1-de.cloudjiffy.net -west1-us.cloudjiffy.net -jls-sto1.elastx.net -jls-sto2.elastx.net -jls-sto3.elastx.net -fr-1.paas.massivegrid.net -lon-1.paas.massivegrid.net -lon-2.paas.massivegrid.net -ny-1.paas.massivegrid.net -ny-2.paas.massivegrid.net -sg-1.paas.massivegrid.net -jelastic.saveincloud.net -nordeste-idc.saveincloud.net -j.scaleforce.net -sdscloud.pl -unicloud.pl -mircloud.ru -enscaled.sg -jele.site -jelastic.team -orangecloud.tn -j.layershift.co.uk -phx.enscaled.us -mircloud.us - -// Jino : https://www.jino.ru -// Submitted by Sergey Ulyashin -myjino.ru -*.hosting.myjino.ru -*.landing.myjino.ru -*.spectrum.myjino.ru -*.vps.myjino.ru - -// Jotelulu S.L. : https://jotelulu.com -// Submitted by Daniel Fariña -jote.cloud -jotelulu.cloud -eu1-plenit.com -la1-plenit.com -us1-plenit.com - -// JouwWeb B.V. : https://www.jouwweb.nl -// Submitted by Camilo Sperberg -webadorsite.com -jouwweb.site - -// JS.ORG : http://dns.js.org -// Submitted by Stefan Keim -js.org - -// K2 Cloud : https://k2.cloud/ -// Submitted by K2 Cloud -elastic.k2.cloud -lb.ru-msk.k2.cloud -s3.ru-msk.k2.cloud -website.ru-msk.k2.cloud -lb.ru-spb.k2.cloud -s3.ru-spb.k2.cloud -website.ru-spb.k2.cloud -s3.k2.cloud -website.k2.cloud - -// KaasHosting : http://www.kaashosting.nl/ -// Submitted by Wouter Bakker -kaas.gg -khplay.nl - -// Kapsi : https://kapsi.fi -// Submitted by Tomi Juntunen -kapsi.fi - -// KataBump : https://katabump.com -// Submitted by Thibault Lapeyre -kdns.fr - -// Katholieke Universiteit Leuven : https://www.kuleuven.be -// Submitted by Abuse KU Leuven -ezproxy.kuleuven.be -kuleuven.cloud - -// Keenetic : https://keenetic.com -// Submitted by Alexey Nikitin -keenetic.io -keenetic.link -keenetic.name -keenetic.pro - -// Kevin Service : https://kevsrv.me -// Submitted by Kevin Service Team -ae.kg - -// Keyweb AG : https://www.keyweb.de -// Submitted by Martin Dannehl -keymachine.de - -// Kilo Code, Inc. : https://kilo.ai -// Submitted by Remon Oldenbeuving -kiloapps.ai -kiloapps.io - -// KingHost : https://king.host -// Submitted by Felipe Keller Braz -kinghost.net -uni5.net - -// KnightPoint Systems, LLC : http://www.knightpoint.com/ -// Submitted by Roy Keene -knightpoint.systems - -// KoobinEvent, SL : https://www.koobin.com -// Submitted by Iván Oliva -koobin.events - -// Krellian Ltd. : https://krellian.com -// Submitted by Ben Francis -webthings.io -krellian.net - -// KUROKU LTD : https://kuroku.ltd/ -// Submitted by DisposaBoy -oya.to - -// KV GmbH : https://www.nic.co.de -// Submitted by KV GmbH -// Abuse reports to -co.de - -// Laravel Holdings, Inc. : https://laravel.com -// Submitted by André Valentin & James Brooks -shiptoday.app -shiptoday.build -laravel.cloud -on-forge.com -on-vapor.com - -// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de -// Submitted by Lars Laehn -git-repos.de -lcube-server.de -svn-repos.de - -// Leadpages : https://www.leadpages.net -// Submitted by Greg Dallavalle -leadpages.co -lpages.co -lpusercontent.com - -// Leapcell : https://leapcell.io/ -// Submitted by Leapcell Team -leapcell.app -leapcell.dev -leapcell.online - -// Liara : https://liara.ir -// Submitted by Amirhossein Badinloo -liara.run -iran.liara.run - -// libp2p project : https://libp2p.io -// Submitted by Interplanetary Shipyard -libp2p.direct - -// Libre IT Ltd : https://libre.nz -// Submitted by Tomas Maggio -runcontainers.dev - -// Lifetime Hosting : https://Lifetime.Hosting/ -// Submitted by Mike Fillator -co.business -co.education -co.events -co.financial -co.network -co.place -co.technology - -// linkyard ldt : https://www.linkyard.ch/ -// Submitted by Mario Siegenthaler -linkyard-cloud.ch -linkyard.cloud - -// Linode : https://linode.com -// Submitted by -members.linode.com -*.nodebalancer.linode.com -*.linodeobjects.com -ip.linodeusercontent.com - -// LiquidNet Ltd : http://www.liquidnetlimited.com/ -// Submitted by Victor Velchev -we.bs - -// Listen53 : https://www.l53.net -// Submitted by Gerry Keh -filegear-sg.me -ggff.net - -// Localcert : https://localcert.dev -// Submitted by Lann Martin -*.user.localcert.dev - -// Localtonet : https://localtonet.com/ -// Submitted by Burak Isleyici -localtonet.com -*.localto.net - -// Lodz University of Technology LODMAN regional domains : https://www.man.lodz.pl/dns -// Submitted by Piotr Wilk -lodz.pl -pabianice.pl -plock.pl -sieradz.pl -skierniewice.pl -zgierz.pl - -// Log'in Line : https://www.loginline.com/ -// Submitted by Rémi Mach -loginline.app -loginline.dev -loginline.io -loginline.services -loginline.site - -// Lõhmus Family, The : https://lohmus.me/ -// Submitted by Heiki Lõhmus -lohmus.me - -// Lovable : https://lovable.dev -// Submitted by Fabian Hedin -lovable.app -lovableproject.com -lovable.run -lovable.sh - -// LubMAN UMCS Sp. z o.o : https://lubman.pl/ -// Submitted by Ireneusz Maliszewski -krasnik.pl -leczna.pl -lubartow.pl -lublin.pl -poniatowa.pl -swidnik.pl - -// Lug.org.uk : https://lug.org.uk -// Submitted by Jon Spriggs -glug.org.uk -lug.org.uk -lugs.org.uk - -// Lukanet Ltd : https://lukanet.com -// Submitted by Anton Avramov -barsy.bg -barsy.club -barsycenter.com -barsyonline.com -barsy.de -barsy.dev -barsy.eu -barsy.gr -barsy.in -barsy.info -barsy.io -barsy.me -barsy.menu -barsyonline.menu -barsy.mobi -barsy.net -barsy.online -barsy.org -barsy.pro -barsy.pub -barsy.ro -barsy.rs -barsy.shop -barsyonline.shop -barsy.site -barsy.store -barsy.support -barsy.uk -barsy.co.uk -barsyonline.co.uk - -// Lutra : https://lutra.ai -// Submitted by Joshua Newman -*.lutrausercontent.com - -// Luyani Inc. : https://luyani.com/ -// Submitted by Umut Gumeli -luyani.app -luyani.net - -// Magento Commerce -// Submitted by Damien Tournoud -*.magentosite.cloud - -// Magic Patterns : https://www.magicpatterns.com -// Submitted by Teddy Ni -magicpatterns.app -magicpatternsapp.com - -// Mail.Ru Group : https://hb.cldmail.ru -// Submitted by Ilya Zaretskiy -hb.cldmail.ru - -// MathWorks : https://www.mathworks.com/ -// Submitted by Emily Reed -matlab.cloud -modelscape.com -mwcloudnonprod.com -polyspace.com - -// May First - People Link : https://mayfirst.org/ -// Submitted by Jamie McClelland -mayfirst.info - -// McHost : https://mchost.ru -// Submitted by Evgeniy Subbotin -mcdir.me -mcdir.ru -vps.mcdir.ru -mcpre.ru - -// Mediatech : https://mediatech.by -// Submitted by Evgeniy Kozhuhovskiy -mediatech.by -mediatech.dev - -// Medicom Health : https://medicomhealth.com -// Submitted by Michael Olson -hra.health - -// MedusaJS, Inc : https://medusajs.com/ -// Submitted by Stevche Radevski -medusajs.app - -// Memset hosting : https://www.memset.com -// Submitted by Tom Whitwell -miniserver.com -memset.net - -// Messerli Informatik AG : https://www.messerli.ch/ -// Submitted by Ruben Schmidmeister -messerli.app - -// Meta Platforms, Inc. : https://meta.com/ -// Submitted by Jacob Cordero -atmeta.com -apps.fbsbx.com -*.metaaiusercontent.com - -// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Zdeněk Šustr and Radim Janča -*.cloud.metacentrum.cz -custom.metacentrum.cz -flt.cloud.muni.cz -usr.cloud.muni.cz - -// Meteor Development Group : https://www.meteor.com/hosting -// Submitted by Pierre Carrier -meteorapp.com -eu.meteorapp.com - -// Michau Enterprises Limited : http://www.co.pl/ -co.pl - -// Microsoft Corporation : http://microsoft.com -// Submitted by Public Suffix List Admin -// Managed by Corporate Domains -// Microsoft Azure : https://home.azure -*.azurecontainer.io -azure-api.net -azure-mobile.net -azureedge.net -azurefd.net -azurestaticapps.net -1.azurestaticapps.net -2.azurestaticapps.net -3.azurestaticapps.net -4.azurestaticapps.net -5.azurestaticapps.net -6.azurestaticapps.net -7.azurestaticapps.net -centralus.azurestaticapps.net -eastasia.azurestaticapps.net -eastus2.azurestaticapps.net -westeurope.azurestaticapps.net -westus2.azurestaticapps.net -azurewebsites.net -cloudapp.net -trafficmanager.net -blob.core.usgovcloudapi.net -file.core.usgovcloudapi.net -web.core.usgovcloudapi.net -servicebus.usgovcloudapi.net -usgovcloudapp.net -usgovtrafficmanager.net -blob.core.windows.net -file.core.windows.net -web.core.windows.net -servicebus.windows.net -azure-api.us -azurewebsites.us - -// MikroTik : https://mikrotik.com -// Submitted by MikroTik SysAdmin Team -routingthecloud.com -sn.mynetname.net -routingthecloud.net -routingthecloud.org - -// Million Software, Inc : https://million.dev/ -// Submitted by Rayhan Noufal Arayilakath -same-app.com -same-preview.com - -// minion.systems : http://minion.systems -// Submitted by Robert Böttinger -csx.cc - -// Miren, Inc. : https://miren.dev -// Submitted by Miren Product Team -miren.app -miren.systems - -// Mittwald CM Service GmbH & Co. KG : https://mittwald.de -// Submitted by Marco Rieger -mydbserver.com -webspaceconfig.de -mittwald.info -mittwaldserver.info -typo3server.info -project.space - -// MKM : https://mkm.fan/ -// Submitted by Kashi Ahmer -mkm.fan - -// Mocha : https://getmocha.com -// Submitted by Ben Reinhart -mocha.app -mochausercontent.com -mocha-sandbox.dev - -// MODX Systems LLC : https://modx.com -// Submitted by Elizabeth Southwell -modx.dev - -// Mozilla Foundation : https://mozilla.org/ -// Submitted by glob -bmoattachments.org - -// MSK-IX : https://www.msk-ix.ru/ -// Submitted by Khannanov Roman -net.ru -org.ru -pp.ru - -// MyOwn srl : https://www.myown.eu/ -// Submitted by Stephane Bouvard -my.be - -// Mythic Beasts : https://www.mythic-beasts.com -// Submitted by Paul Cammish -hostedpi.com -caracal.mythic-beasts.com -customer.mythic-beasts.com -fentiger.mythic-beasts.com -lynx.mythic-beasts.com -ocelot.mythic-beasts.com -oncilla.mythic-beasts.com -onza.mythic-beasts.com -sphinx.mythic-beasts.com -vs.mythic-beasts.com -x.mythic-beasts.com -yali.mythic-beasts.com -cust.retrosnub.co.uk - -// Nabu Casa : https://www.nabucasa.com -// Submitted by Paulus Schoutsen -ui.nabu.casa - -// Needle Tools GmbH : https://needle.tools -// Submitted by Felix Herbst -needle.run - -// Neo : https://www.neo.space -// Submitted by Ankit Kulkarni -co.site - -// Net at Work Gmbh : https://www.netatwork.de -// Submitted by Jan Jaeschke -cloud.nospamproxy.com -o365.cloud.nospamproxy.com - -// Net libre : https://www.netlib.re -// Submitted by Philippe PITTOLI -netlib.re - -// Netlify : https://www.netlify.com -// Submitted by Jessica Parsons -netlify.app - -// Neustar Inc. -// Submitted by Trung Tran -4u.com - -// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ -// Submitted by Jeff Wheelhouse -nfshost.com - -// NFT.Storage : https://nft.storage/ -// Submitted by Vasco Santos or -ipfs.nftstorage.link - -// NGO.US Registry : https://nic.ngo.us -// Submitted by Alstra Solutions Ltd. Networking Team -ngo.us - -// ngrok : https://ngrok.com/ -// Submitted by Alan Shreve -ngrok.app -ngrok-free.app -ngrok.dev -ngrok-free.dev -ngrok.io -ap.ngrok.io -au.ngrok.io -eu.ngrok.io -in.ngrok.io -jp.ngrok.io -sa.ngrok.io -us.ngrok.io -ngrok.pizza -ngrok.pro - -// Nicolaus Copernicus University in Torun - MSK TORMAN : https://www.man.torun.pl -torun.pl - -// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ -// Submitted by Nicholas Ford -nh-serv.co.uk -nimsite.uk - -// No-IP.com : https://noip.com/ -// Submitted by Deven Reza -mmafan.biz -myftp.biz -no-ip.biz -no-ip.ca -fantasyleague.cc -gotdns.ch -3utilities.com -blogsyte.com -ciscofreak.com -damnserver.com -ddnsking.com -ditchyourip.com -dnsiskinky.com -dynns.com -geekgalaxy.com -health-carereform.com -homesecuritymac.com -homesecuritypc.com -myactivedirectory.com -mysecuritycamera.com -myvnc.com -net-freaks.com -onthewifi.com -point2this.com -quicksytes.com -securitytactics.com -servebeer.com -servecounterstrike.com -serveexchange.com -serveftp.com -servegame.com -servehalflife.com -servehttp.com -servehumour.com -serveirc.com -servemp3.com -servep2p.com -servepics.com -servequake.com -servesarcasm.com -stufftoread.com -unusualperson.com -workisboring.com -dvrcam.info -ilovecollege.info -no-ip.info -brasilia.me -ddns.me -dnsfor.me -hopto.me -loginto.me -noip.me -webhop.me -bounceme.net -ddns.net -eating-organic.net -mydissent.net -myeffect.net -mymediapc.net -mypsx.net -mysecuritycamera.net -nhlfan.net -no-ip.net -pgafan.net -privatizehealthinsurance.net -redirectme.net -serveblog.net -serveminecraft.net -sytes.net -cable-modem.org -collegefan.org -couchpotatofries.org -hopto.org -mlbfan.org -myftp.org -mysecuritycamera.org -nflfan.org -no-ip.org -read-books.org -ufcfan.org -zapto.org -no-ip.co.uk -golffan.us -noip.us -pointto.us - -// NodeArt : https://nodeart.io -// Submitted by Konstantin Nosov -stage.nodeart.io - -// Noop : https://noop.app -// Submitted by Nathaniel Schweinberg -*.developer.app -noop.app - -// Northflank Ltd. : https://northflank.com/ -// Submitted by Marco Suter -*.northflank.app -*.build.run -*.code.run -*.database.run -*.migration.run - -// Northwest Nexus dba NuOz : https://nuoz.net/ -// An RFC 1480 locality domain delegate host -// Submitted by Peter Briggs on behalf of NuOz -aberdeen.wa.us -bainbridge-isl.wa.us -bellevue.wa.us -bremerton.wa.us -centralia.wa.us -chehalis.wa.us -forks.wa.us -gig-harbor.wa.us -hoquiam.wa.us -keyport.wa.us -kingston.wa.us -olympia.wa.us -port-angeles.wa.us -port-ludlow.wa.us -port-orchard.wa.us -port-townsend.wa.us -poulsbo.wa.us -redmond.wa.us -renton.wa.us -sea.wa.us -seattle.wa.us -sequim.wa.us -shelton.wa.us -silverdale.wa.us -yarrow-point.wa.us - -// Noticeable : https://noticeable.io -// Submitted by Laurent Pellegrino -noticeable.news - -// Notion Labs, Inc : https://www.notion.so/ -// Submitted by Jess Yao -notion.site - -// Now-DNS : https://now-dns.com -// Submitted by Steve Russell -dnsking.ch -mypi.co -myiphost.com -forumz.info -soundcast.me -tcp4.me -dnsup.net -hicam.net -now-dns.net -ownip.net -vpndns.net -dynserv.org -now-dns.org -x443.pw -ntdll.top -freeddns.us - -// nsupdate.info : https://www.nsupdate.info/ -// Submitted by Thomas Waldmann -nsupdate.info -nerdpol.ovh - -// O3O.Foundation : https://o3o.foundation/ -// Submitted by the prvcy.page Registry Team -prvcy.page - -// Observable, Inc. : https://observablehq.com -// Submitted by Mike Bostock -observablehq.cloud -static.observableusercontent.com - -// OMG.LOL : https://omg.lol -// Submitted by Adam Newbold -omg.lol - -// Omnibond Systems, LLC. : https://www.omnibond.com -// Submitted by Cole Estep -cloudycluster.net - -// OmniWe Limited : https://omniwe.com -// Submitted by Vicary Archangel -omniwe.site - -// One.com : https://www.one.com/ -// Submitted by Jacob Bunk Nielsen -123webseite.at -123website.be -simplesite.com.br -123website.ch -simplesite.com -123webseite.de -123hjemmeside.dk -123miweb.es -123kotisivu.fi -123siteweb.fr -simplesite.gr -123homepage.it -123website.lu -123website.nl -123hjemmeside.no -service.one -website.one -simplesite.pl -123paginaweb.pt -123minsida.se - -// ONID : https://get.onid.ca -// Submitted by ONID Engineering Team -onid.ca - -// Open Domains : https://open-domains.net -// Submitted by William Harrison -is-a-fullstack.dev -is-cool.dev -is-not-a.dev -localplayer.dev -is-local.org - -// Open Social : https://www.getopensocial.com/ -// Submitted by Alexander Varwijk -opensocial.site - -// OpenAI : https://openai.com -// Submitted by Thomas Shadwell -*.oaiusercontent.com -chatgpt.site - -// OpenCraft GmbH : http://opencraft.com/ -// Submitted by Sven Marnach -opencraft.hosting - -// OpenHost : https://registry.openhost.uk -// Submitted by OpenHost Registry Team -16-b.it -32-b.it -64-b.it - -// OpenResearch GmbH : https://openresearch.com/ -// Submitted by Philipp Schmid -orsites.com - -// Opera Software, A.S.A. -// Submitted by Yngve Pettersen -operaunite.com - -// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/ -// Submitted by Gregory Drake -// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label -*.customer-oci.com -*.oci.customer-oci.com -*.ocp.customer-oci.com -*.ocs.customer-oci.com -*.oraclecloudapps.com -*.oraclegovcloudapps.com -*.oraclegovcloudapps.uk - -// Orange : https://www.orange.com -// Submitted by Alexandre Linte -tech.orange - -// OsSav Technology Ltd. : https://ossav.com/ -// Submitted by OsSav Technology Ltd. -// https://nic.can.re -can.re - -// Oursky Limited : https://authgear.com/ -// Submitted by Authgear Team & Skygear Developer -authgear-staging.com -authgearapps.com - -// OutSystems -// Submitted by Duarte Santos -outsystemscloud.com - -// OVHcloud : https://ovhcloud.com -// Submitted by Vincent Cassé -*.hosting.ovh.net -*.webpaas.ovh.net - -// OwnProvider GmbH : http://www.ownprovider.com -// Submitted by Jan Moennich -ownprovider.com -own.pm - -// OwO : https://whats-th.is/ -// Submitted by Dean Sheather -*.owo.codes - -// OX : http://www.ox.rs -// Submitted by Adam Grand -ox.rs - -// oy.lc -// Submitted by Charly Coste -oy.lc - -// Pagefog : https://pagefog.com/ -// Submitted by Derek Myers -pgfog.com - -// Pantheon Systems, Inc. : https://pantheon.io/ -// Submitted by Gary Dylina -gotpantheon.com -pantheonsite.io - -// Paywhirl, Inc : https://paywhirl.com/ -// Submitted by Daniel Netzer -*.paywhirl.com - -// pcarrier.ca Software Inc : https://pcarrier.ca/ -// Submitted by Pierre Carrier -*.xmit.co -xmit.dev -madethis.site -srv.us -gh.srv.us -gl.srv.us - -// Peplink | Pepwave : http://peplink.com/ -// Submitted by Steve Leung -mypep.link - -// Perplexity AI : https://www.perplexity.ai/ -// Submitted by Alec Xiang -pplx.app - -// Perspecta : https://perspecta.com/ -// Submitted by Kenneth Van Alstyne -perspecta.cloud - -// Ping Identity : https://www.pingidentity.com -// Submitted by Ping Identity -forgeblocks.com -id.forgerock.io - -// Plain : https://www.plain.com/ -// Submitted by Jesús Hernández -support.site - -// Planet-Work : https://www.planet-work.com/ -// Submitted by Frédéric VANNIÈRE -on-web.fr - -// Platform.sh : https://platform.sh -// Submitted by Nikola Kotur -*.upsun.app -upsunapp.com -ent.platform.sh -eu.platform.sh -us.platform.sh -*.platformsh.site -*.tst.site - -// Playcode : https://playcode.io -// Submitted by Ruslan Ianberdin -playcode.site - -// Pley AB : https://www.pley.com/ -// Submitted by Henning Pohl -pley.games - -// Porter : https://porter.run/ -// Submitted by Rudraksh MK -onporter.run - -// Positive Codes Technology Company : http://co.bn/faq.html -// Submitted by Zulfais -co.bn - -// Postman, Inc : https://postman.com -// Submitted by Rahul Dhawan -postman-echo.com -pstmn.io -mock.pstmn.io -httpbin.org - -// prequalifyme.today : https://prequalifyme.today -// Submitted by DeepakTiwari deepak@ivylead.io -prequalifyme.today - -// prgmr.com : https://prgmr.com/ -// Submitted by Sarah Newman -xen.prgmr.com - -// priv.at : http://www.nic.priv.at/ -// Submitted by registry -priv.at - -// PROJECT ELIV : https://eliv.kr/ -// Submitted by PROJECT ELIV DomainName Team -c01.kr -eliv-api.kr -eliv-cdn.kr -eliv-dns.kr -mmv.kr -vki.kr - -// project-study : https://project-study.com -// Submitted by yumenewa -dev.project-study.com - -// PSL Sandbox : https://github.com/groundcat/PSL-Sandbox -// Submitted by groundcat -platter-app.dev - -// PT Ekossistim Indo Digital : https://e.id -// Submitted by Eid Team -e.id - -// Publication Presse Communication SARL : https://ppcom.fr -// Submitted by Yaacov Akiba Slama -chirurgiens-dentistes-en-france.fr -byen.site - -// PublicZone : https://publiczone.org/ -// Submitted by PublicZone NOC Team -nyc.mn -*.cn.st - -// pubtls.org : https://www.pubtls.org -// Submitted by Kor Nielsen -pubtls.org - -// Puter : https://puter.com -// Submitted by Puter Security Team -puter.app -puter.site -puter.work - -// PythonAnywhere LLP : https://www.pythonanywhere.com -// Submitted by Giles Thomas -pythonanywhere.com -eu.pythonanywhere.com - -// QA2 -// Submitted by Daniel Dent : https://www.danieldent.com/ -qa2.com - -// QCX -// Submitted by Cassandra Beelen -qcx.io -*.sys.qcx.io - -// QNAP System Inc : https://www.qnap.com -// Submitted by Nick Chang -myqnapcloud.cn -alpha-myqnapcloud.com -dev-myqnapcloud.com -mycloudnas.com -mynascloud.com -myqnapcloud.com - -// QOTO, Org. -// Submitted by Jeffrey Phillips Freeman -qoto.io - -// Qualifio : https://qualifio.com/ -// Submitted by Xavier De Cock -qualifioapp.com - -// Quality Unit : https://qualityunit.com -// Submitted by Vasyl Tsalko -ladesk.com - -// Qualy : https://qualyhq.com -// Submitted by Raphael Arias -*.qualyhqpartner.com -*.qualyhqportal.com - -// QuickBackend : https://www.quickbackend.com -// Submitted by Dani Biro -qbuser.com - -// Quip : https://quip.com -// Submitted by Patrick Linehan -*.quipelements.com - -// Qutheory LLC : http://qutheory.io -// Submitted by Jonas Schwartz -vapor.cloud -vaporcloud.io - -// Rackmaze LLC : https://www.rackmaze.com -// Submitted by Kirill Pertsev -rackmaze.com -rackmaze.net - -// Rad Web Hosting : https://radwebhosting.com -// Submitted by Scott Claeys -cloudsite.builders -myradweb.net -servername.us - -// Radix FZC : http://domains.in.net -// Submitted by Gavin Brown -web.in -in.net - -// Raidboxes GmbH : https://raidboxes.de -// Submitted by Auke Tembrink -myrdbx.io -site.rb-hosting.io - -// Railway Corporation : https://railway.com -// Submitted by Phineas Walton -up.railway.app - -// Rancher Labs, Inc : https://rancher.com -// Submitted by Vincent Fiduccia -*.on-rancher.cloud -*.on-k3s.io -*.on-rio.io - -// RavPage : https://www.ravpage.co.il -// Submitted by Roni Horowitz -ravpage.co.il - -// Read The Docs, Inc : https://www.readthedocs.org -// Submitted by David Fischer -readthedocs-hosted.com -readthedocs.io - -// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ -// Submitted by Tim Kramer -rhcloud.com - -// Redgate Software : https://red-gate.com -// Submitted by Andrew Farries -instances.spawn.cc - -// Redpanda Data : https://redpanda.com -// Submitted by Infrastructure Team -*.clusters.rdpa.co -*.srvrless.rdpa.co - -// Render : https://render.com -// Submitted by Anurag Goel -onrender.com -app.render.com - -// Repl.it : https://repl.it -// Submitted by Lincoln Bergeson -replit.app -id.replit.app -firewalledreplit.co -id.firewalledreplit.co -repl.co -id.repl.co -replit.dev -archer.replit.dev -bones.replit.dev -canary.replit.dev -global.replit.dev -hacker.replit.dev -id.replit.dev -janeway.replit.dev -kim.replit.dev -kira.replit.dev -kirk.replit.dev -odo.replit.dev -paris.replit.dev -picard.replit.dev -pike.replit.dev -prerelease.replit.dev -reed.replit.dev -riker.replit.dev -sisko.replit.dev -spock.replit.dev -staging.replit.dev -sulu.replit.dev -tarpit.replit.dev -teams.replit.dev -tucker.replit.dev -wesley.replit.dev -worf.replit.dev -repl.run - -// Resin.io : https://resin.io -// Submitted by Tim Perry -resindevice.io -devices.resinstaging.io - -// Rico Developments Limited : https://adimo.co -// Submitted by Colin Brown -adimo.co.uk - -// Riseup Networks : https://riseup.net -// Submitted by Micah Anderson -itcouldbewor.se - -// Roar Domains LLC : https://roar.basketball/ -// Submitted by Gavin Brown -aus.basketball -nz.basketball - -// ROBOT PAYMENT INC. : https://www.robotpayment.co.jp/ -// Submitted by Kentaro Takamori -subsc-pay.com -subsc-pay.net - -// Rochester Institute of Technology : http://www.rit.edu/ -// Submitted by Jennifer Herting -git-pages.rit.edu - -// Rocky Enterprise Software Foundation : https://resf.org -// Submitted by Neil Hanlon -rocky.page - -// Ruhr University Bochum : https://www.ruhr-uni-bochum.de/ -// Submitted by Andreas Jobs -rub.de -ruhr-uni-bochum.de -io.noc.ruhr-uni-bochum.de - -// Rusnames Limited : http://rusnames.ru/ -// Submitted by Sergey Zotov -биз.рус -ком.рус -крым.рус -мир.рус -мск.рус -орг.рус -самара.рус -сочи.рус -спб.рус -я.рус - -// Russian Academy of Sciences -// Submitted by Tech Support -ras.ru - -// Sakura Frp : https://www.natfrp.com -// Submitted by Bobo Liu -nyat.app - -// SAKURA Internet Inc. : https://www.sakura.ad.jp/ -// Submitted by Internet Service Department -180r.com -dojin.com -sakuratan.com -sakuraweb.com -x0.com -2-d.jp -bona.jp -crap.jp -daynight.jp -eek.jp -flop.jp -halfmoon.jp -jeez.jp -matrix.jp -mimoza.jp -ivory.ne.jp -mail-box.ne.jp -mints.ne.jp -mokuren.ne.jp -opal.ne.jp -sakura.ne.jp -sumomo.ne.jp -topaz.ne.jp -netgamers.jp -nyanta.jp -o0o0.jp -rdy.jp -rgr.jp -rulez.jp -s3.isk01.sakurastorage.jp -s3.isk02.sakurastorage.jp -saloon.jp -sblo.jp -skr.jp -tank.jp -uh-oh.jp -undo.jp -rs.webaccel.jp -user.webaccel.jp -websozai.jp -xii.jp -squares.net -jpn.org -kirara.st -x0.to -from.tv -sakura.tv - -// Salesforce.com, Inc. : https://salesforce.com/ -// Submitted by Salesforce Public Suffix List Team -*.builder.code.com -*.dev-builder.code.com -*.stg-builder.code.com -*.001.test.code-builder-stg.platform.salesforce.com -*.aa.crm.dev -*.ab.crm.dev -*.ac.crm.dev -*.ad.crm.dev -*.ae.crm.dev -*.af.crm.dev -*.ci.crm.dev -*.d.crm.dev -*.pa.crm.dev -*.pb.crm.dev -*.pc.crm.dev -*.pd.crm.dev -*.pe.crm.dev -*.pf.crm.dev -*.w.crm.dev -*.wa.crm.dev -*.wb.crm.dev -*.wc.crm.dev -*.wd.crm.dev -*.we.crm.dev -*.wf.crm.dev - -// Sandstorm Development Group, Inc. : https://sandcats.io/ -// Submitted by Asheesh Laroia -sandcats.io - -// Sav.com, LLC : https://marketing.sav.com/ -// Submitted by Mukul Kudegave -sav.case - -// SBE network solutions GmbH : https://www.sbe.de/ -// Submitted by Norman Meilick -logoip.com -logoip.de - -// Scaleway : https://www.scaleway.com/ -// Submitted by Scaleway PSL Maintainer -fr-par-1.baremetal.scw.cloud -fr-par-2.baremetal.scw.cloud -nl-ams-1.baremetal.scw.cloud -cockpit.fr-par.scw.cloud -ddl.fr-par.scw.cloud -dtwh.fr-par.scw.cloud -fnc.fr-par.scw.cloud -functions.fnc.fr-par.scw.cloud -ifr.fr-par.scw.cloud -k8s.fr-par.scw.cloud -nodes.k8s.fr-par.scw.cloud -kafk.fr-par.scw.cloud -mgdb.fr-par.scw.cloud -rdb.fr-par.scw.cloud -s3.fr-par.scw.cloud -s3-website.fr-par.scw.cloud -scbl.fr-par.scw.cloud -whm.fr-par.scw.cloud -priv.instances.scw.cloud -pub.instances.scw.cloud -k8s.scw.cloud -cockpit.nl-ams.scw.cloud -ddl.nl-ams.scw.cloud -dtwh.nl-ams.scw.cloud -ifr.nl-ams.scw.cloud -k8s.nl-ams.scw.cloud -nodes.k8s.nl-ams.scw.cloud -kafk.nl-ams.scw.cloud -mgdb.nl-ams.scw.cloud -rdb.nl-ams.scw.cloud -s3.nl-ams.scw.cloud -s3-website.nl-ams.scw.cloud -scbl.nl-ams.scw.cloud -whm.nl-ams.scw.cloud -cockpit.pl-waw.scw.cloud -ddl.pl-waw.scw.cloud -dtwh.pl-waw.scw.cloud -ifr.pl-waw.scw.cloud -k8s.pl-waw.scw.cloud -nodes.k8s.pl-waw.scw.cloud -kafk.pl-waw.scw.cloud -mgdb.pl-waw.scw.cloud -rdb.pl-waw.scw.cloud -s3.pl-waw.scw.cloud -s3-website.pl-waw.scw.cloud -scbl.pl-waw.scw.cloud -scalebook.scw.cloud -smartlabeling.scw.cloud -dedibox.fr - -// schokokeks.org GbR : https://schokokeks.org/ -// Submitted by Hanno Böck -schokokeks.net - -// Scottish Government : https://www.gov.scot -// Submitted by Martin Ellis -gov.scot -service.gov.scot -mygov.scot - -// Scry Security : http://www.scrysec.com -// Submitted by Shante Adam -scrysec.com - -// Scrypted : https://scrypted.app -// Submitted by Koushik Dutta -client.scrypted.io - -// Securepoint GmbH : https://www.securepoint.de -// Submitted by Erik Anders -firewall-gateway.com -firewall-gateway.de -my-gateway.de -my-router.de -spdns.de -spdns.eu -firewall-gateway.net -my-firewall.org -myfirewall.org -spdns.org - -// Seidat : https://www.seidat.com -// Submitted by Artem Kondratev -seidat.net - -// Sellfy : https://sellfy.com -// Submitted by Yuriy Romadin -sellfy.store - -// Sendmsg : https://www.sendmsg.co.il -// Submitted by Assaf Stern -minisite.ms - -// Senseering GmbH : https://www.senseering.de -// Submitted by Felix Mönckemeyer -senseering.net - -// Servebolt AS : https://servebolt.com -// Submitted by Daniel Kjeserud -servebolt.cloud - -// Service Online LLC : http://drs.ua/ -// Submitted by Serhii Bulakh -biz.ua -co.ua -pp.ua - -// Shanghai Accounting Society : https://www.sasf.org.cn -// Submitted by Information Administration -as.sh.cn - -// Shanghai Oray Information Technology Co., Ltd.: https://www.oray.com/ -// Submitted by: Shanghai Oray Information Technology Co., Ltd. -vicp.fun -yicp.fun -zicp.fun - -// Sheezy.Art : https://sheezy.art -// Submitted by Nyoom -sheezy.games - -// Shopblocks : http://www.shopblocks.com/ -// Submitted by Alex Bowers -myshopblocks.com - -// Shopify : https://www.shopify.com -// Submitted by Alex Richter -myshopify.com - -// Shopit : https://www.shopitcommerce.com/ -// Submitted by Craig McMahon -shopitsite.com - -// shopware AG : https://shopware.com -// Submitted by Jens Küper -shopware.shop -shopware.store - -// Siemens Mobility GmbH -// Submitted by Oliver Graebner -mo-siemens.io - -// SinaAppEngine : http://sae.sina.com.cn/ -// Submitted by SinaAppEngine -1kapp.com -appchizi.com -applinzi.com -sinaapp.com -vipsinaapp.com - -// Siteleaf : https://www.siteleaf.com/ -// Submitted by Skylar Challand -siteleaf.net - -// Small Technology Foundation : https://small-tech.org -// Submitted by Aral Balkan -small-web.org - -// Smallregistry by Promopixel SARL : https://www.smallregistry.net -// Former AFNIC's SLDs -// Submitted by Jérôme Lipowicz -aeroport.fr -avocat.fr -chambagri.fr -chirurgiens-dentistes.fr -experts-comptables.fr -medecin.fr -notaires.fr -pharmacien.fr -port.fr -veterinaire.fr - -// Smoove.io : https://www.smoove.io/ -// Submitted by Dan Kozak -vp4.me - -// Snowflake Inc : https://www.snowflake.com/ -// Submitted by Sam Haar -*.snowflake.app -*.privatelink.snowflake.app -streamlit.app -streamlitapp.com - -// Snowplow Analytics : https://snowplowanalytics.com/ -// Submitted by Ian Streeter -try-snowplow.com - -// Software Consulting Michal Zalewski : https://www.mafelo.com -// Submitted by Michal Zalewski -mafelo.net - -// Solana Name Service : https://sns.id -// Submitted by Solana Name Service -sol.site - -// Sony Interactive Entertainment LLC : https://sie.com/ -// Submitted by David Coles -playstation-cloud.com - -// SourceHut : https://sourcehut.org -// Submitted by Drew DeVault -srht.site - -// SourceLair PC : https://www.sourcelair.com -// Submitted by Antonis Kalipetis -apps.lair.io -*.stolos.io - -// sourceWAY GmbH : https://sourceway.de -// Submitted by Richard Reiber -4.at -my.at -my.de -*.nxa.eu -nx.gw - -// Spawnbase : https://spawnbase.ai -// Submitted by Alexander Zuev -spawnbase.app - -// SpeedPartner GmbH : https://www.speedpartner.de/ -// Submitted by Stefan Neufeind -customer.speedpartner.de - -// Spreadshop (sprd.net AG) : https://www.spreadshop.com/ -// Submitted by Martin Breest -myspreadshop.at -myspreadshop.com.au -myspreadshop.be -myspreadshop.ca -myspreadshop.ch -myspreadshop.com -myspreadshop.de -myspreadshop.dk -myspreadshop.es -myspreadshop.fi -myspreadshop.fr -myspreadshop.ie -myspreadshop.it -myspreadshop.net -myspreadshop.nl -myspreadshop.no -myspreadshop.pl -myspreadshop.se -myspreadshop.co.uk - -// StackBlitz : https://stackblitz.com -// Submitted by Dominic Elm & Albert Pai -w-corp-staticblitz.com -w-credentialless-staticblitz.com -w-staticblitz.com -bolt.host - -// Stackhero : https://www.stackhero.io -// Submitted by Adrien Gillon -stackhero-network.com - -// STACKIT GmbH & Co. KG : https://www.stackit.de/en/ -// Submitted by STACKIT-DNS Team (Simon Stier) -runs.onstackit.cloud -stackit.gg -stackit.rocks -stackit.run -stackit.zone - -// Stackryze : https://stackryze.com -// Submitted by Sudheer Bhuvana -sryze.cc -indevs.in - -// Staclar : https://staclar.com -// Submitted by Q Misell -// Submitted by Matthias Merkel -musician.io -novecore.site - -// statichost.eu : https://www.statichost.eu -// Submitted by Eric Selin -statichost.page - -// stereosense GmbH : https://www.involve.me -// Submitted by Florian Burmann -feedback.ac -forms.ac -assessments.cx -calculators.cx -funnels.cx -paynow.cx -quizzes.cx -researched.cx -tests.cx -surveys.so - -// Storacha Network : https://storacha.network -// Submitted by Alan Shaw -ipfs.storacha.link -ipfs.w3s.link - -// Storebase : https://www.storebase.io -// Submitted by Tony Schirmer -storebase.store - -// Strapi : https://strapi.io/ -// Submitted by Florent Baldino -strapiapp.com -media.strapiapp.com - -// Strategic System Consulting (eApps Hosting) : https://www.eapps.com/ -// Submitted by Alex Oancea -vps-host.net -atl.jelastic.vps-host.net -njs.jelastic.vps-host.net -ric.jelastic.vps-host.net - -// Streak : https://streak.com -// Submitted by Blake Kadatz -streak-link.com -streaklinks.com -streakusercontent.com - -// Student-Run Computing Facility : https://www.srcf.net/ -// Submitted by Edwin Balani -soc.srcf.net -user.srcf.net - -// Studenten Net Twente : http://www.snt.utwente.nl/ -// Submitted by Silke Hofstra -utwente.io - -// Sub 6 Limited : http://www.sub6.com -// Submitted by Dan Miller -temp-dns.com - -// Supabase : https://supabase.io -// Submitted by Supabase Security -supabase.co -realtime.supabase.co -storage.supabase.co -supabase.in -supabase.net - -// Syncloud : https://syncloud.org -// Submitted by Boris Rybalkin -syncloud.it - -// Synology, Inc. : https://www.synology.com/ -// Submitted by Rony Weng -dscloud.biz -direct.quickconnect.cn -dsmynas.com -familyds.com -diskstation.me -dscloud.me -i234.me -myds.me -synology.me -dscloud.mobi -dsmynas.net -familyds.net -dsmynas.org -familyds.org -direct.quickconnect.to -vpnplus.to - -// Tabit Technologies Ltd. : https://tabit.cloud/ -// Submitted by Oren Agiv -mytabit.com -mytabit.co.il -tabitorder.co.il - -// TAIFUN Software AG : http://taifun-software.de -// Submitted by Bjoern Henke -taifun-dns.de - -// Tailor Inc. : https://www.tailor.tech -// Submitted by Ryuzo Yamamoto -erp.dev -web.erp.dev - -// Tailscale Inc. : https://www.tailscale.com -// Submitted by David Anderson -ts.net -*.c.ts.net - -// TASK geographical domains : https://task.gda.pl/en/services/for-entrepreneurs/ -gda.pl -gdansk.pl -gdynia.pl -med.pl -sopot.pl - -// Tave Creative Corp : https://tave.com/ -// Submitted by Adrian Ziemkowski -taveusercontent.com - -// tawk.to, Inc : https://www.tawk.to -// Submitted by tawk.to developer team -p.tawk.email -p.tawkto.email - -// Tche.br : https://tche.br -// Submitted by Bruno Lorensi -tche.br - -// team.blue : https://team.blue -// Submitted by Cedric Dubois -site.tb-hosting.com -directwp.eu - -// TechEdge Limited: https://www.nic.uk.cc/ -// Submitted by TechEdge Developer -ec.cc -eu.cc -gu.cc -uk.cc -us.cc - -// Teckids e.V. : https://www.teckids.org -// Submitted by Dominik George -edugit.io -s3.teckids.org - -// Telebit : https://telebit.cloud -// Submitted by AJ ONeal -telebit.app -telebit.io -*.telebit.xyz - -// Teleport : https://goteleport.com -// Submitted by Rob Picard -teleport.sh - -// Thingdust AG : https://thingdust.com/ -// Submitted by Adrian Imboden -*.firenet.ch -*.svc.firenet.ch -reservd.com -thingdustdata.com -cust.dev.thingdust.io -reservd.dev.thingdust.io -cust.disrec.thingdust.io -reservd.disrec.thingdust.io -cust.prod.thingdust.io -cust.testing.thingdust.io -reservd.testing.thingdust.io - -// ticket i/O GmbH : https://ticket.io -// Submitted by Christian Franke -tickets.io - -// Tigris Data, Inc. : https://www.tigrisdata.com -// Submitted by Bo Cao -t3.storage.dev -t3.storageapi.dev - -// Tlon.io : https://tlon.io -// Submitted by Mark Staarink -arvo.network -azimuth.network -tlon.network - -// Tor Project, Inc. : https://torproject.org -// Submitted by Antoine Beaupré -torproject.net -pages.torproject.net - -// TownNews.com : http://www.townnews.com -// Submitted by Dustin Ward -townnews-staging.com - -// TrafficPlex GmbH : https://www.trafficplex.de/ -// Submitted by Phillipp Röll -12hp.at -2ix.at -4lima.at -lima-city.at -12hp.ch -2ix.ch -4lima.ch -lima-city.ch -trafficplex.cloud -de.cool -12hp.de -2ix.de -4lima.de -lima-city.de -1337.pictures -clan.rip -lima-city.rocks -webspace.rocks -lima.zone - -// TransIP : https://www.transip.nl -// Submitted by Rory Breuk and Cedric Dubois -*.transurl.be -*.transurl.eu -site.transip.me -*.transurl.nl - -// Triton Data Center project : https://tritondatacenter.com -// Submitted by Triton Data Center staff -*.triton.zone - -// Tunnelmole: https://tunnelmole.com -// Submitted by Robbie Cahill -tunnelmole.net - -// TuxFamily : http://tuxfamily.org -// Submitted by TuxFamily administrators -tuxfamily.org - -// Typedream : https://typedream.com -// Submitted by Putri Karunia -typedream.app - -// Typeform : https://www.typeform.com -// Submitted by Typeform -pro.typeform.com - -// Uberspace : https://uberspace.de -// Submitted by Moritz Werner -uber.space - -// UDR Limited : http://www.udr.hk.com -// Submitted by registry -hk.com -inc.hk -ltd.hk -hk.org - -// UK Intis Telecom LTD : https://it.com -// Submitted by ITComdomains -it.com - -// Umso Software Inc. : https://www.umso.com -// Submitted by Alexis Taylor -umso.co - -// Unison Computing, PBC : https://unison.cloud -// Submitted by Simon Højberg -unison-services.cloud - -// United Gameserver GmbH : https://united-gameserver.de -// Submitted by Stefan Schwarz -virtual-user.de -virtualuser.de - -// United States Writing Corporation : https://uswriting.co -// Submitted by Andrew Sampson -obj.ag - -// UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/ -// see also: whois -h whois.udr.org.yt help -// Submitted by Atanunu Igbunuroghene -name.pm -sch.tf -biz.wf -sch.wf -org.yt - -// University of Banja Luka : https://unibl.org -// Domains for Republic of Srpska administrative entity. -// Submitted by Marko Ivanovic -rs.ba - -// University of Bielsko-Biala regional domain : http://dns.bielsko.pl/ -// Submitted by Marcin -bielsko.pl - -// urown.net : https://urown.net -// Submitted by Hostmaster -urown.cloud -dnsupdate.info - -// US REGISTRY LLC : http://us.org -// Submitted by Gavin Brown -us.org - -// V.UA Domain Registry: https://www.v.ua/ -// Submitted by Serhii Rostilo -v.ua - -// Val Town, Inc : https://val.town/ -// Submitted by Tom MacWright -val.run -web.val.run - -// Vercel, Inc : https://vercel.com/ -// Submitted by Laurens Duijvesteijn -vercel.app -v0.build -vercel.dev -vusercontent.net -vercel.run -now.sh - -// VeryPositive SIA : http://very.lv -// Submitted by Danko Aleksejevs -2038.io - -// Virtual-Info : https://www.virtual-info.info/ -// Submitted by Adnan RIHAN -v-info.info - -// VistaBlog : https://vistablog.ir/ -// Submitted by Hossein Piri -vistablog.ir - -// Viva Republica, Inc. : https://toss.im/ -// Submitted by Deus Team -deus-canvas.com - -// vivenu GmbH : https://vivenu.com/ -// Submitted by Marvin Frick -vivenushop.com -vivenushop.dev - -// Voorloper.com : https://voorloper.com -// Submitted by Nathan van Bakel -voorloper.cloud - -// Vultr Objects : https://www.vultr.com/products/object-storage/ -// Submitted by Niels Maumenee -*.vultrobjects.com - -// Waffle Computer Inc., Ltd. : https://docs.waffleinfo.com -// Submitted by Masayuki Note -wafflecell.com - -// Walrus : https://walrus.xyz -// Submitted by Max Spector -wal.app - -// Wasmer: https://wasmer.io -// Submitted by Lorentz Kinde -wasmer.app - -// Webflow, Inc. : https://www.webflow.com -// Submitted by Webflow Security Team -webflow.io -webflowtest.io - -// WebHare bv : https://www.webhare.com/ -// Submitted by Arnold Hendriks -*.webhare.dev - -// WebHotelier Technologies Ltd : https://www.webhotelier.net/ -// Submitted by Apostolos Tsakpinis -hotelwithflight.com -reserve-online.net -book.online - -// WebPros International, LLC : https://webpros.com/ -// Submitted by Nicolas Rochelemagne -cprapid.com -pleskns.com -wp2.host -pdns.page -plesk.page -cpanel.site -wpsquared.site - -// WebWaddle Ltd : https://webwaddle.com/ -// Submitted by Merlin Glander -*.wadl.top - -// Western Digital Technologies, Inc : https://www.wdc.com -// Submitted by Jung Jin -remotewd.com - -// Whatbox Inc. : https://whatbox.ca/ -// Submitted by Anthony Ryan -box.ca - -// WIARD Enterprises : https://wiardweb.com -// Submitted by Kidd Hustle -pages.wiardweb.com - -// Wikimedia Foundation : https://wikitech.wikimedia.org -// Submitted by Timo Tijhof -toolforge.org -wmcloud.org -beta.wmcloud.org -wmflabs.org - -// William Harrison : https://wharrison.com.au -// Submitted by William Harrison -vps.hrsn.au -hrsn.dev -is-a.dev -localcert.net - -// Windsurf : https://windsurf.com -// Submitted by Douglas Chen -windsurf.app -windsurf.build - -// WirelessCar : https://wirelesscar.com -// Submitted by Martin Lindberg -drive-platform.com -drive-platform.io - -// WISP : https://wisp.gg -// Submitted by Stepan Fedotov -panel.gg -daemon.panel.gg - -// Wix.com, Inc. : https://www.wix.com -// Submitted by Shahar Talmi / Alon Kochba -base44.app -base44-sandbox.com -wixsite.com -wixstudio.com -editorx.io -wixstudio.io -wix.run - -// Wizard Zines : https://wizardzines.com -// Submitted by Julia Evans -messwithdns.com - -// WoltLab GmbH : https://www.woltlab.com -// Submitted by Tim Düsterhus -woltlab-demo.com -myforum.community -community-pro.de -diskussionsbereich.de -community-pro.net -meinforum.net - -// Woods Valldata : https://www.woodsvalldata.co.uk/ -// Submitted by Chris Whittle -affinitylottery.org.uk -raffleentry.org.uk -weeklylottery.org.uk - -// WP Engine : https://wpengine.com/ -// Submitted by Michael Smith -// Submitted by Brandon DuRette -wpenginepowered.com -js.wpenginepowered.com - -// xAI : https://x.ai/ -// Submitted by Asim Shrestha -grok.me - -// XenonCloud GbR : https://xenoncloud.net -// Submitted by Julian Uphoff -*.xenonconnect.de -half.host - -// XnBay Technology : http://www.xnbay.com/ -// Submitted by XnBay Developer -xnbay.com -u2.xnbay.com -u2-local.xnbay.com - -// XS4ALL Internet bv : https://www.xs4all.nl/ -// Submitted by Daniel Mostertman -cistron.nl -demon.nl -xs4all.space - -// xTool : https://xtool.com -// Submitted by Echo -xtooldevice.com - -// Yandex.Cloud LLC : https://cloud.yandex.com -// Submitted by Alexander Lodin -yandexcloud.net -storage.yandexcloud.net -website.yandexcloud.net -sourcecraft.site - -// YesCourse Pty Ltd : https://yescourse.com -// Submitted by Atul Bhouraskar -official.academy - -// Yola : https://www.yola.com/ -// Submitted by Stefano Rivera -yolasite.com - -// Yunohost : https://yunohost.org -// Submitted by Valentin Grimaud -ynh.fr -nohost.me -noho.st - -// ZaNiC : http://www.za.net/ -// Submitted by registry -za.net -za.org - -// ZAP-Hosting GmbH & Co. KG : https://zap-hosting.com -// Submitted by Julian Alker -zap.cloud - -// Zeabur : https://zeabur.com/ -// Submitted by Zeabur Team -zeabur.app - -// Zerops : https://zerops.io/ -// Submitted by Zerops Team -*.zerops.app -prg1-zerops.zone -*.zerops.zone - -// Zine EOOD : https://zine.bg/ -// Submitted by Martin Angelov -bss.design - -// Zitcom A/S : https://www.zitcom.dk -// Submitted by Emil Stahl -basicserver.io -virtualserver.io -enterprisecloud.nu - -// Zone.ID: https://zone.id -// Submitted by Gx1.org -zone.id -nett.to - -// ZoneABC : https://zoneabc.net -// Submitted by ZoneABC Team -zabc.net - -// ===END PRIVATE DOMAINS=== diff -Nru pdns-recursor-5.2.13/ext/Makefile.am pdns-recursor-5.4.9/ext/Makefile.am --- pdns-recursor-5.2.13/ext/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/Makefile.am 2026-10-26 08:26:51.000000000 +0000 @@ -1,6 +1,5 @@ SUBDIRS = \ arc4random \ - yahttp \ json11 \ probds diff -Nru pdns-recursor-5.2.13/ext/Makefile.in pdns-recursor-5.4.9/ext/Makefile.in --- pdns-recursor-5.2.13/ext/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/Makefile.in 2026-10-26 09:47:08.801876000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -69,6 +69,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -372,8 +374,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -427,7 +431,6 @@ top_srcdir = @top_srcdir@ SUBDIRS = \ arc4random \ - yahttp \ json11 \ probds @@ -666,8 +669,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -759,3 +762,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/arc4random/Makefile.am pdns-recursor-5.4.9/ext/arc4random/Makefile.am --- pdns-recursor-5.2.13/ext/arc4random/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/arc4random/Makefile.am 2026-10-26 09:46:36.000000000 +0000 @@ -9,3 +9,6 @@ explicit_bzero.c \ includes.h \ log.h + +EXTRA_DIST = \ + meson.build diff -Nru pdns-recursor-5.2.13/ext/arc4random/Makefile.in pdns-recursor-5.4.9/ext/arc4random/Makefile.in --- pdns-recursor-5.2.13/ext/arc4random/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/arc4random/Makefile.in 2026-10-26 09:47:08.816343500 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -70,6 +70,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -367,8 +369,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -432,6 +436,9 @@ includes.h \ log.h +EXTRA_DIST = \ + meson.build + all: all-am .SUFFIXES: @@ -467,15 +474,13 @@ $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + -$(am__rm_f) $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } + echo rm -f $${locs}; \ + $(am__rm_f) $${locs} libarc4random.la: $(libarc4random_la_OBJECTS) $(libarc4random_la_DEPENDENCIES) $(EXTRA_libarc4random_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libarc4random_la_OBJECTS) $(libarc4random_la_LIBADD) $(LIBS) @@ -493,7 +498,7 @@ $(am__depfiles_remade): @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + @: >>$@ am--depfiles: $(am__depfiles_remade) @@ -639,8 +644,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -651,7 +656,7 @@ mostlyclean-am distclean: distclean-am - -rm -f ./$(DEPDIR)/arc4random.Plo + -rm -f ./$(DEPDIR)/arc4random.Plo -rm -f ./$(DEPDIR)/arc4random_uniform.Plo -rm -f ./$(DEPDIR)/bsd-getentropy.Plo -rm -f ./$(DEPDIR)/explicit_bzero.Plo @@ -700,7 +705,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/arc4random.Plo + -rm -f ./$(DEPDIR)/arc4random.Plo -rm -f ./$(DEPDIR)/arc4random_uniform.Plo -rm -f ./$(DEPDIR)/bsd-getentropy.Plo -rm -f ./$(DEPDIR)/explicit_bzero.Plo @@ -744,3 +749,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/arc4random/meson.build pdns-recursor-5.4.9/ext/arc4random/meson.build --- pdns-recursor-5.2.13/ext/arc4random/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/arc4random/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,20 @@ +lib_arc4random = static_library( + 'arc4random', + 'arc4random.c', + 'arc4random_uniform.c', + 'bsd-getentropy.c', + 'explicit_bzero.c', + extra_files: [ + 'arc4random.h', + 'arc4random.hh', + 'chacha_private.h', + 'includes.h', + 'log.h', + ], + dependencies: [dep_pdns], +) + +dep_arc4random = declare_dependency( + link_with: lib_arc4random, + include_directories: include_directories('.'), +) diff -Nru pdns-recursor-5.2.13/ext/json11/Makefile.am pdns-recursor-5.4.9/ext/json11/Makefile.am --- pdns-recursor-5.2.13/ext/json11/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/json11/Makefile.am 2026-10-26 09:46:36.000000000 +0000 @@ -1,2 +1,6 @@ noinst_LTLIBRARIES = libjson11.la libjson11_la_SOURCES = json11.cpp json11.hpp + +EXTRA_DIST = \ + LICENSE.txt \ + meson.build diff -Nru pdns-recursor-5.2.13/ext/json11/Makefile.in pdns-recursor-5.4.9/ext/json11/Makefile.in --- pdns-recursor-5.2.13/ext/json11/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/json11/Makefile.in 2026-10-26 09:47:08.830735000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -70,6 +70,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -382,8 +384,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -437,6 +441,10 @@ top_srcdir = @top_srcdir@ noinst_LTLIBRARIES = libjson11.la libjson11_la_SOURCES = json11.cpp json11.hpp +EXTRA_DIST = \ + LICENSE.txt \ + meson.build + all: all-am .SUFFIXES: @@ -472,15 +480,13 @@ $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + -$(am__rm_f) $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } + echo rm -f $${locs}; \ + $(am__rm_f) $${locs} libjson11.la: $(libjson11_la_OBJECTS) $(libjson11_la_DEPENDENCIES) $(EXTRA_libjson11_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libjson11_la_OBJECTS) $(libjson11_la_LIBADD) $(LIBS) @@ -495,7 +501,7 @@ $(am__depfiles_remade): @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + @: >>$@ am--depfiles: $(am__depfiles_remade) @@ -641,8 +647,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -653,7 +659,7 @@ mostlyclean-am distclean: distclean-am - -rm -f ./$(DEPDIR)/json11.Plo + -rm -f ./$(DEPDIR)/json11.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -699,7 +705,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/json11.Plo + -rm -f ./$(DEPDIR)/json11.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -740,3 +746,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/json11/json11.cpp pdns-recursor-5.4.9/ext/json11/json11.cpp --- pdns-recursor-5.2.13/ext/json11/json11.cpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/json11/json11.cpp 2026-10-26 09:46:36.000000000 +0000 @@ -302,15 +302,23 @@ */ bool Json::operator== (const Json &other) const { - if (m_ptr->type() != other.m_ptr->type()) + if (m_ptr == other.m_ptr) { + return true; + } + if (m_ptr->type() != other.m_ptr->type()) { return false; + } return m_ptr->equals(other.m_ptr.get()); } bool Json::operator< (const Json &other) const { - if (m_ptr->type() != other.m_ptr->type()) + if (m_ptr == other.m_ptr) { + return false; + } + if (m_ptr->type() != other.m_ptr->type()) { return m_ptr->type() < other.m_ptr->type(); + } return m_ptr->less(other.m_ptr.get()); } @@ -386,16 +394,12 @@ if (str[i] == '/') { i++; if (i == str.size()) - return fail("unexpected end of input inside comment", false); + return fail("unexpected end of input after start of comment", false); if (str[i] == '/') { // inline comment i++; - if (i == str.size()) - return fail("unexpected end of input inside inline comment", false); - // advance until next line - while (str[i] != '\n') { + // advance until next line, or end of input + while (i < str.size() && str[i] != '\n') { i++; - if (i == str.size()) - return fail("unexpected end of input inside inline comment", false); } comment_found = true; } @@ -411,9 +415,6 @@ "unexpected end of input inside multi-line comment", false); } i += 2; - if (i == str.size()) - return fail( - "unexpected end of input inside multi-line comment", false); comment_found = true; } else @@ -432,6 +433,9 @@ bool comment_found = false; do { comment_found = consume_comment(); + if (failed) { + return; + } consume_whitespace(); } while(comment_found); @@ -445,8 +449,12 @@ */ char get_next_token() { consume_garbage(); - if (i == str.size()) + if (failed) { + return (char)0; + } + if (i == str.size()) { return fail("unexpected end of input", (char)0); + } return str[i++]; } @@ -738,8 +746,12 @@ // Check for any trailing garbage parser.consume_garbage(); - if (parser.i != in.size()) + if (parser.failed) { + return {}; + } + if (parser.i != in.size()) { return parser.fail("unexpected trailing " + esc(in[parser.i])); + } return result; } @@ -754,10 +766,16 @@ vector json_vec; while (parser.i != in.size() && !parser.failed) { json_vec.push_back(parser.parse_json(0)); + if (parser.failed) { + break; + } + // Check for another object parser.consume_garbage(); - if (!parser.failed) - parser_stop_pos = parser.i; + if (parser.failed) { + break; + } + parser_stop_pos = parser.i; } return json_vec; } @@ -772,8 +790,10 @@ return false; } + const auto& obj_items = object_items(); for (auto & item : types) { - if ((*this)[item.first].type() != item.second) { + const auto it = obj_items.find(item.first); // NOLINT(readability-identifier-length) + if (it == obj_items.cend() || it->second.type() != item.second) { err = "bad type for " + item.first + " in " + dump(); return false; } diff -Nru pdns-recursor-5.2.13/ext/json11/json11.hpp pdns-recursor-5.4.9/ext/json11/json11.hpp --- pdns-recursor-5.2.13/ext/json11/json11.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/json11/json11.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -107,14 +107,14 @@ // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) template ::value - && std::is_constructible::value, + std::is_constructible().begin()->first)>::value + && std::is_constructible().begin()->second)>::value, int>::type = 0> Json(const M & m) : Json(object(m.begin(), m.end())) {} // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) template ::value, + std::is_constructible().begin())>::value, int>::type = 0> Json(const V & v) : Json(array(v.begin(), v.end())) {} diff -Nru pdns-recursor-5.2.13/ext/json11/meson.build pdns-recursor-5.4.9/ext/json11/meson.build --- pdns-recursor-5.2.13/ext/json11/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/json11/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,12 @@ +lib_json11 = static_library( + 'json11', + 'json11.cpp', + extra_files: [ + 'json11.hpp', + ], +) + +dep_json11 = declare_dependency( + link_with: lib_json11, + include_directories: include_directories('.'), +) diff -Nru pdns-recursor-5.2.13/ext/luawrapper/include/LuaContext.hpp pdns-recursor-5.4.9/ext/luawrapper/include/LuaContext.hpp --- pdns-recursor-5.2.13/ext/luawrapper/include/LuaContext.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/luawrapper/include/LuaContext.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -55,6 +55,18 @@ #include #include +#if __cplusplus >= 201703L +#include +#include +#endif /* C++17 */ + +// Set the older gcc define for tsan if clang or modern gcc tell us we have tsan. +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define __SANITIZE_THREAD__ 1 +#endif +#endif + #if defined(_MSC_VER) && _MSC_VER < 1900 # include "misc/exception.hpp" #endif @@ -66,6 +78,7 @@ #endif #define LUACONTEXT_GLOBAL_EQ "e5ddced079fc405aa4937b386ca387d2" +#define LUACONTEXT_DEBUG_TRACEBACK "8d143f0add7ad7fa323d0d1d12f3f114" // I would prefer a lightuserdata in the registry index #define EQ_FUNCTION_NAME "__eq" #define TOSTRING_FUNCTION_NAME "__tostring" @@ -96,7 +109,17 @@ explicit LuaContext(bool openDefaultLibs = true) { // luaL_newstate can return null if allocation failed - mState = luaL_newstate(); +#if defined(__SANITIZE_THREAD__) && defined(LUAJIT_VERSION) && defined(__aarch64__) + // on arm64 with luajit and TSAN, allocation may fail spuriously, so keep retrying a bit + int tries = 100; +#else + int tries = 1; +#endif + for (; tries > 0; tries--) { + mState = luaL_newstate(); + if (mState != nullptr) { break; } + } +#undef RETRIES if (mState == nullptr) throw std::bad_alloc(); @@ -112,7 +135,12 @@ if (openDefaultLibs) luaL_openlibs(mState); - writeGlobalEq(); + writeGlobalEq(); + lua_pushliteral(mState, LUACONTEXT_DEBUG_TRACEBACK); // ref + lua_getglobal(mState, "debug"); // ref, debug + lua_getfield(mState, -1, "traceback"); // ref, debug, traceback + lua_remove(mState, -2); // ref, traceback + lua_settable(mState, LUA_REGISTRYINDEX); // [] } void writeGlobalEq() { @@ -122,7 +150,7 @@ lua_gettable(lua, -2); /* if not found, return false */ if (lua_isnil(lua, -1)) { - lua_pop(lua, -2); + lua_pop(lua, 2); lua_pushboolean(lua, false); return 1; } @@ -1417,9 +1445,8 @@ } static int gettraceback(lua_State* L) { - lua_getglobal(L, "debug"); // stack: error, debug library - lua_getfield(L, -1, "traceback"); // stack: error, debug library, debug.traceback function - lua_remove(L, -2); // stack: error, debug.traceback function + lua_pushliteral(L, LUACONTEXT_DEBUG_TRACEBACK); // stack: error, ref + lua_rawget(L, LUA_REGISTRYINDEX); // stack: error, debug.traceback lua_pushstring(L, ""); // stack: error, debug.traceback, "" lua_pushinteger(L, 2); // stack: error, debug.traceback, "", 2 lua_call(L, 2, 1); // stack: error, traceback @@ -1449,21 +1476,26 @@ // if pcall failed, analyzing the problem and throwing if (pcallReturnValue != 0) { + switch (pcallReturnValue) { + case LUA_ERRMEM: + throw std::bad_alloc{}; + case LUA_ERRERR: + throw ExecutionErrorException("while handling a Lua error, the traceback handler failed (LUA_ERRERR)"); + // all other values should have left us an error and a traceback + } + - // stack top: {error, traceback} - lua_rawgeti(state, -1, 1); // stack top: {error, traceback}, error - lua_rawgeti(state, -2, 2); // stack top: {error, traceback}, error, traceback - lua_remove(state, -3); // stack top: error, traceback - - PushedObject traceBackRef{state, 1}; - const auto traceBack = readTopAndPop(state, std::move(traceBackRef)); // stack top: error - PushedObject errorCode{state, 1}; - - // an error occurred during execution, either an error message or a std::exception_ptr was pushed on the stack - if (pcallReturnValue == LUA_ERRMEM) { - throw std::bad_alloc{}; + if (lua_gettop(state) >= 1 && lua_type(state, -1) == LUA_TTABLE) { + // stack top: {error, traceback} + lua_rawgeti(state, -1, 1); // stack top: {error, traceback}, error + lua_rawgeti(state, -2, 2); // stack top: {error, traceback}, error, traceback + lua_remove(state, -3); // stack top: error, traceback + + PushedObject traceBackRef{state, 1}; + const auto traceBack = readTopAndPop(state, std::move(traceBackRef)); // stack top: error + PushedObject errorCode{state, 1}; - } else if (pcallReturnValue == LUA_ERRRUN) { + // an error occurred during execution, either an error message or a std::exception_ptr was pushed on the stack if (lua_isstring(state, 1)) { // the error is a string const auto str = readTopAndPop(state, std::move(errorCode)); @@ -1484,6 +1516,9 @@ throw ExecutionErrorException{"Unknown Lua error"}; } } + else { + throw ExecutionErrorException("while handling a Lua error, the traceback handler did not return a table (" + std::to_string(pcallReturnValue) + ")"); + } } return PushedObject{state, outArguments}; @@ -1873,8 +1908,8 @@ // the only case where "min != max" is with boost::optional at the end of the list template struct FunctionArgumentsCounter {}; - - // true is the template parameter is a boost::optional + + // true if the template parameter is a boost::optional or std::optional template struct IsOptional : public std::false_type {}; }; @@ -1970,6 +2005,10 @@ // implementation of IsOptional template struct LuaContext::IsOptional> : public std::true_type {}; +#if __cplusplus >= 201703L +template +struct LuaContext::IsOptional> : public std::true_type {}; +#endif /* C++ 17 */ // implementation of LuaFunctionCaller template @@ -2523,6 +2562,25 @@ }; }; +#if __cplusplus >= 201703L +// std::variant +template +struct LuaContext::Pusher> +{ + static const int minSize = PusherMinSize::size; + static const int maxSize = PusherMaxSize::size; + + static PushedObject push(lua_State* state, const std::variant& value) noexcept { + PushedObject obj{state, 0}; + std::visit([&](auto&& arg) { + using T = std::decay_t; + obj = Pusher::push(state, arg); + }, value); + return obj; + } +}; +#endif /* C++17 */ + // boost::optional template struct LuaContext::Pusher> { @@ -2542,6 +2600,27 @@ } }; +#if __cplusplus >= 201703L +// std::optional +template +struct LuaContext::Pusher> { + typedef Pusher::type> + UnderlyingPusher; + + static const int minSize = UnderlyingPusher::minSize < 1 ? UnderlyingPusher::minSize : 1; + static const int maxSize = UnderlyingPusher::maxSize > 1 ? UnderlyingPusher::maxSize : 1; + + static PushedObject push(lua_State* state, const std::optional& value) noexcept { + if (value.has_value()) { + return UnderlyingPusher::push(state, value.value()); + } else { + lua_pushnil(state); + return PushedObject{state, 1}; + } + } +}; +#endif /* C++17 */ + // tuple template struct LuaContext::Pusher> { @@ -2891,7 +2970,27 @@ } }; -// variant +#if __cplusplus >= 201703L +// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) +template +struct LuaContext::Reader> +{ + static auto read(lua_State* state, int index) + -> boost::optional> + { + if (lua_isnil(state, index)) { + return boost::optional>{std::optional()}; + } + if (auto&& other = Reader::read(state, index)) { + return std::move(std::optional(*other)); + } + return boost::none; + } +}; +// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks) +#endif /* C++ 17 */ + +// boost::variant template struct LuaContext::Reader> { @@ -2938,6 +3037,42 @@ } }; +#if __cplusplus >= 201703L +// std::variant +template +struct LuaContext::Reader> +{ + using ReturnType = std::variant; + +private: + template static boost::optional variantRead(lua_State* state, int index) + { + constexpr auto nbTypes = std::variant_size_v; + if constexpr (I >= nbTypes) { + return boost::none; + } + using InitialType = std::variant_alternative_t; + using DecayedType = std::decay_t; + if (const auto val = Reader::read(state, index)) { + // we are using the initial, non-decayed type so that a + // cv-qualifiers are not ignored + return ReturnType{std::in_place_type, *val}; + } + if constexpr (I < (nbTypes - 1)) { + return variantRead(state, index); + } + return boost::none; + } + +public: + static auto read(lua_State* state, int index) + -> boost::optional + { + return variantRead(state, index); + } +}; +#endif /* C++ 17 */ + // reading a tuple // tuple have an additional argument for their functions, that is the maximum size to read // if maxSize is smaller than the tuple size, then the remaining parameters will be left to default value diff -Nru pdns-recursor-5.2.13/ext/luawrapper/meson.build pdns-recursor-5.4.9/ext/luawrapper/meson.build --- pdns-recursor-5.2.13/ext/luawrapper/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/luawrapper/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,3 @@ +dep_luawrapper = declare_dependency( + include_directories: include_directories('include'), +) diff -Nru pdns-recursor-5.2.13/ext/probds/Makefile.in pdns-recursor-5.4.9/ext/probds/Makefile.in --- pdns-recursor-5.2.13/ext/probds/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/probds/Makefile.in 2026-10-26 09:47:08.845049100 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -70,6 +70,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -382,8 +384,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -472,15 +476,13 @@ $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + -$(am__rm_f) $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } + echo rm -f $${locs}; \ + $(am__rm_f) $${locs} libprobds.la: $(libprobds_la_OBJECTS) $(libprobds_la_DEPENDENCIES) $(EXTRA_libprobds_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libprobds_la_OBJECTS) $(libprobds_la_LIBADD) $(LIBS) @@ -495,7 +497,7 @@ $(am__depfiles_remade): @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + @: >>$@ am--depfiles: $(am__depfiles_remade) @@ -641,8 +643,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -653,7 +655,7 @@ mostlyclean-am distclean: distclean-am - -rm -f ./$(DEPDIR)/murmur3.Plo + -rm -f ./$(DEPDIR)/murmur3.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -699,7 +701,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/murmur3.Plo + -rm -f ./$(DEPDIR)/murmur3.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -740,3 +742,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/probds/meson.build pdns-recursor-5.4.9/ext/probds/meson.build --- pdns-recursor-5.2.13/ext/probds/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/probds/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -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('.'), +) diff -Nru pdns-recursor-5.2.13/ext/protozero/CHANGELOG.md pdns-recursor-5.4.9/ext/protozero/CHANGELOG.md --- pdns-recursor-5.2.13/ext/protozero/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/CHANGELOG.md 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,449 @@ + +# Changelog + +All notable changes to this project will be documented in this file. +The format is based on [Keep a Changelog](https://keepachangelog.com/) +This project adheres to [Semantic Versioning](https://semver.org/). + +## [unreleased] - + +### Added + +### Changed + +### Fixed + + +## [1.8.0] - 2024-01-13 + +### Changed + +- Switched to C++14 as minimum requirement. Modernised the code accordingly. +- Only the tests need the Protobuf library when building. +- Improve compatibility with various STL flavors. +- Change license formatting to get recognized by license scanning tools. +- Add lots of `const` in places where we can. Also fix some other issues + reported by clang-tidy. +- Various other code cleanups. +- Modernize documentation config, CMake config and CI workflows. + +### Fixed + +- `basic_pbf_builder` constructor can not be noexcept. + + +## [1.7.1] - 2022-01-10 + +### Changed + +- Don't build tests if the standard CMake `BUILD_TESTING` variable is set to + off. +- Now needs CMake 3.5.0 or greater. +- Update included catch2 framework to current version v2.13.8. +- Only enable clang-tidy make target if protobuf was found. +- Allow setting C++ version to compile with in CMake config. + +### Fixed + +- Fixes undefined behaviour in `float` and `double` byteswap. +- Add missing includes of "config.hpp". +- Avoid narrowing conversion by doing an explicit `static_cast`. + + +## [1.7.0] - 2020-06-08 + +### Added + +- Support for buffer types other that `std::string`. `pbf_writer` is now + just a typedef for `basic_pbf_writer`. Other buffer types + can be used with `basic_pbf_writer`. See `doc/advanced.md` for details. + +### Changed + +- Switched to *catch2* for testing. +- Some minor tweaks. + +### Fixed + +- Removed some undefined behaviour. + + +## [1.6.8] - 2019-08-15 + +### Changed + +- Various code cleanups due to clang-tidy warnings. + +### Fixed + +- Made `data_view::compare` noexcept. + + +## [1.6.7] - 2018-02-21 + +### Fixed + +- Signed-unsigned comparison on 32 bit systems. + + +## [1.6.6] - 2018-02-20 + +### Fixed + +- Fixed several place with possible undefined behaviour. + + +## [1.6.5] - 2018-02-05 + +### Fixed + +- Avoid UB: Do not calculate pointer outside array bounds. +- Specify proto2 syntax in .proto files to appease protoc. + + +## [1.6.4] - 2018-11-08 + +### Added + +- Add function `data()` to get the not yet read data from a `pbf_reader`. +- New `add_packed_fixed()` template function for `pbf_writer`. +- New `length_of_varint()` helper function calculates how long a varint + would be for a specified value. + +### Changed + +- More consistent implementation of operators as free friend functions. + +### Fixed + +- Fixed some zigzag encoding tests on MSVC. +- Add extra cast so we do an xor with unsigned ints. +- No more bitwise operations on signed integers in varint decoder. +- No more bitwise operations on signed integers in zigzag encoder/decoder. + + +## [1.6.3] - 2018-07-17 + +### Changed + +- Moved `byteswap_inplace` functions from detail into protozero namespace. + They can be useful outsize protozero. +- More asserts and unit tests and small cleanups. + + +## [1.6.2] - 2018-03-09 + +### Changed + +- Update included catch.hpp to v1.12.0. +- Move basic unit tests into their own directory (`test/unit`). +- Improved clang-tidy config and fixed some code producing warnings. + +### Fixed + +- Buffer overflow in pbf-decoder tool. + + +## [1.6.1] - 2017-11-16 + +### Added + +- Document internal handling of varints. +- Add aliases for fixed iterators, too. + +### Changed + +- The `const_fixed_iterator` is now a random access iterator making code + using it potentially more performant (for instance when using + `std::distance`) +- Overloads `std::distance` for the varint and svarint iterators. This is + better than the workaround with the `rage_size` function used before. + +### Fixed + +- Rename `.proto` files in some tests to be unique. This solves a problem + when building with newer versions of the Google Protobuf library. +- Floating point comparisons in tests are now always correctly done using + `Approx()`. + + +## [1.6.0] - 2017-10-24 + +### Added + +- Comparison functions (<, <=, >, >=) for `data_view`. Allows use in `std::map` + for instance. +- Tool `pbf-decoder` for decoding raw messages. This has limited use for + normal users, but it can be used for fuzzing. + +### Changed + +- Protozero now uses CMake to build the tests etc. This does not affect + simple users of the library, but if you are using CMake yourself you might + want to use the `cmake/FindProtozero.cmake` module provided. The README + contains more information about build options. +- Moved `data_view` class from `types.hpp` into its own header file + `data_view.hpp`. +- Implementation of the `const_fixed_iterator` to use only a single pointer + instead of two. +- Made `operator==` and `operator!=` on `data_view` constexpr. +- The `pbf_reader` constructor taking a `std::pair` is deprecated. Use one + of the other constructors instead. + +### Fixed + +- Varints where the last byte was larger than what would fit in 64bit were + triggering undefined behaviour. This can only happen when the message + being decoded was corrupt in some way. +- Do not assert when reading too long varints for bools any more. A valid + encoder should never generate varints with more than one byte for bools, + but if they are longer that's not really a problem, so just handle it. +- Throw exception if the length of a packed repeated field of a fixed-length + type is invalid. The length must always be a multiple of the size of the + underlying type. This can only happen if the data is corrupted in some way, + a valid encoder would never generate data like this. +- Throw an exception when reading invalid tags. This can only happen if the + data is corrupted in some way, a valid encoder would never generate invalid + tags. + + +## [1.5.3] - 2017-09-22 + +### Added + +- More documentation. +- New `size()` method on iterator range used for packed repeated fields to + find out how many elements there are in the range. This is much faster + compared to the `std::difference()` call you had to do before, because the + varints don't have to be fully decoded. See [Advanced + Topics](doc/advanced.md) for details. + +### Changed + +- Updated clang-tidy settings in Makefiles and fixed a lot of minor issues + reported by clang-tidy. +- Update included catch.hpp to version 1.10.0. +- Miscellaneous code cleanups. +- Support for invalid state in `pbf_writer` and `packed_repeated_fields`. + This fixes move construction and move assignement in `pbf_writer` and + disables the copy construction and copy assignement which don't have + clear semantics. It introduces an invalid or empty state in the + `pbf_writer`, `pbf_builder`, and `packed_repeated_fields` classes used for + default-constructed, moved from, or committed objects. There is a new + `commit()` function for `pbf_writer` and the `packed_repeated_fields` which + basically does the same as the destructor but can be called explicitly. + +### Fixed + +- The `empty()` method of the iterator range now returns a `bool` instead of + a `size_t`. + + +## [1.5.2] - 2017-06-30 + +### Added + +- Add missing two-parameter version of `pbf_message::next()` function. +- Add `data_view::empty()` function. +- Add missing versions of `add_bytes()`, `add_string()`, and `add_message()` + to `pbf_builder`. + +### Changed + +- Clarify include file usage in tutorial. +- Updated included Catch unit test framework to version 1.9.6 and updated + tests to work with the current version. +- Make some constructors explicit (best practice to avoid silent conversions). + +### Fixed + +- Important bugfix in `data_view` equality operator. The equality operator is + actually never used in the protozero code itself, but users of protozero + might use it. This is a serious bug that could lead to buffer overrun type + problems. + + +## [1.5.1] - 2017-01-14 + +### Added + +- Better documentation for `tag_and_type()` in doc/advanced.md. + +### Fixed + +- Fixed broken "make doc" build. + + +## [1.5.0] - 2017-01-12 + +### Added + +- Add `add_bytes_vectored()` methods to `pbf_writer` and `pbf_builder`. This + allows single-copy scatter-gather type adding of data that has been prepared + in pieces to a protobuf message. +- New functions to check the tag and wire type at the same time: Two parameter + version of `pbf_reader::next()` and `pbf_reader::tag_and_type()` can be used + together with the free function `tag_and_type()` to easily and quickly check + that not only the tag but also the wire type is correct for a field. + +### Changed + +- `packed_field_*` classes now work with `pbf_builder`. +- Reorganized documentation. Advanced docs are now under doc/advanced.md. + +### Fixed + +- `packed_field` class is now non-copyable because data can get corrupted if + you copy it around. +- Comparison operators of `data_view` now have const& parameters. +- Make zigzag encoding/decoding functions constexpr. + + +## [1.4.5] - 2016-11-18 + +### Fixed + +- Undefined behaviour in packed fixed iterator. As a result, the macro + `PROTOZERO_DO_NOT_USE_BARE_POINTER` is not used any more. + + +## [1.4.4] - 2016-11-15 + +### Fixed + +- Byteswap implementation. + + +## [1.4.3] - 2016-11-15 + +### Fixed + +- Undefined behaviour in byte swapping code. +- Rename some parameters to avoid "shadow" warning from some compilers. + + +## [1.4.2] - 2016-08-27 + +### Fixed + +- Compile fix: Variable shadowing. + + +## [1.4.1] - 2016-08-21 + +### Fixed + +- GCC 4.8 compile fixed + +### Added + +- New ability to dynamically require the module as a node module to ease + building against from other node C++ modules. + +## [1.4.0] - 2016-07-22 + +### Changed + +- Use more efficient new `skip_varint()` function when iterating over + packed varints. +- Split `decode_varint()` function into two functions speeding up the + common case where a varint is only one byte long. +- Introduce new class `iterator_range` used instead of `std::pair` of + iterators. This way the objects can be used in range-based for loops. + Read UPGRADING.md for details. +- Introduce new class `data_view` and functions using and returning it. + Read UPGRADING.md for details. + + +## [1.3.0] - 2016-02-18 + +### Added + +- Added `config.hpp` header which now includes all the macro magic to + configure the library for different architectures etc. +- New way to create repeated packed fields without using an iterator. +- Add `rollback()` function to `pbf_writer` for "manual" rollback. + +### Changed + +- Various test and documentation cleanups. +- Rename `pbf_types.hpp` to `types.hpp`. + + +## [1.2.3] - 2015-11-30 + +### Added + +- Added `config.hpp` header which now includes all the macro magic to + configure the library for different architectures etc. + +### Fixed + +- Unaligned access to floats/doubles on some ARM architectures. + + +## [1.2.2] - 2015-10-13 + +### Fixed + +- Fix the recently broken writing of bools on big-endian architectures. + + +## [1.2.1] - 2015-10-12 + +### Fixed + +- Removed unneeded code (1-byte "swap") which lead to test failures. + + +## [1.2.0] - 2015-10-08 + +### Added + +- `pbf_message` and `pbf_builder` template classes wrapping `pbf_reader` + and `pbf_writer`, respectively. The new classes are the preferred + interface now. + +### Changed + +- Improved byte swapping operation. +- Detect some types of data corruption earlier and throw. + + +## [1.1.0] - 2015-08-22 + +### Changed + +- Make pbf reader and writer code endianess-aware. + + +[unreleased]: https://github.com/osmcode/libosmium/compare/v1.8.0...HEAD +[1.8.0]: https://github.com/osmcode/libosmium/compare/v1.7.1...v1.8.0 +[1.7.1]: https://github.com/osmcode/libosmium/compare/v1.7.0...v1.7.1 +[1.7.0]: https://github.com/osmcode/libosmium/compare/v1.6.8...v1.7.0 +[1.6.8]: https://github.com/osmcode/libosmium/compare/v1.6.7...v1.6.8 +[1.6.7]: https://github.com/osmcode/libosmium/compare/v1.6.6...v1.6.7 +[1.6.6]: https://github.com/osmcode/libosmium/compare/v1.6.5...v1.6.6 +[1.6.5]: https://github.com/osmcode/libosmium/compare/v1.6.4...v1.6.5 +[1.6.4]: https://github.com/osmcode/libosmium/compare/v1.6.3...v1.6.4 +[1.6.3]: https://github.com/osmcode/libosmium/compare/v1.6.2...v1.6.3 +[1.6.2]: https://github.com/osmcode/libosmium/compare/v1.6.1...v1.6.2 +[1.6.1]: https://github.com/osmcode/libosmium/compare/v1.6.0...v1.6.1 +[1.6.0]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.6.0 +[1.5.3]: https://github.com/osmcode/libosmium/compare/v1.5.2...v1.5.3 +[1.5.2]: https://github.com/osmcode/libosmium/compare/v1.5.1...v1.5.2 +[1.5.1]: https://github.com/osmcode/libosmium/compare/v1.5.0...v1.5.1 +[1.5.0]: https://github.com/osmcode/libosmium/compare/v1.4.5...v1.5.0 +[1.4.5]: https://github.com/osmcode/libosmium/compare/v1.4.4...v1.4.5 +[1.4.4]: https://github.com/osmcode/libosmium/compare/v1.4.3...v1.4.4 +[1.4.3]: https://github.com/osmcode/libosmium/compare/v1.4.2...v1.4.3 +[1.4.2]: https://github.com/osmcode/libosmium/compare/v1.4.1...v1.4.2 +[1.4.1]: https://github.com/osmcode/libosmium/compare/v1.4.0...v1.4.1 +[1.4.0]: https://github.com/osmcode/libosmium/compare/v1.3.0...v1.4.0 +[1.3.0]: https://github.com/osmcode/libosmium/compare/v1.2.3...v1.3.0 +[1.2.3]: https://github.com/osmcode/libosmium/compare/v1.2.2...v1.2.3 +[1.2.2]: https://github.com/osmcode/libosmium/compare/v1.2.1...v1.2.2 +[1.2.1]: https://github.com/osmcode/libosmium/compare/v1.2.0...v1.2.1 +[1.2.0]: https://github.com/osmcode/libosmium/compare/v1.1.0...v1.2.0 +[1.1.0]: https://github.com/osmcode/libosmium/compare/v1.0.0...v1.1.0 + diff -Nru pdns-recursor-5.2.13/ext/protozero/LICENSE.from_folly pdns-recursor-5.4.9/ext/protozero/LICENSE.from_folly --- pdns-recursor-5.2.13/ext/protozero/LICENSE.from_folly 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/LICENSE.from_folly 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff -Nru pdns-recursor-5.2.13/ext/protozero/LICENSE.md pdns-recursor-5.4.9/ext/protozero/LICENSE.md --- pdns-recursor-5.2.13/ext/protozero/LICENSE.md 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/LICENSE.md 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,26 @@ +Copyright (C) 2022, Mapbox. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/basic_pbf_builder.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/basic_pbf_builder.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/basic_pbf_builder.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/basic_pbf_builder.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -40,7 +40,7 @@ template class basic_pbf_builder : public basic_pbf_writer { - static_assert(std::is_same::type>::value, + static_assert(std::is_same>::value, "T must be enum with underlying type protozero::pbf_tag_type"); public: @@ -67,7 +67,7 @@ * @param tag Tag of the field that will be written */ template - basic_pbf_builder(basic_pbf_writer& parent_writer, P tag) noexcept : + basic_pbf_builder(basic_pbf_writer& parent_writer, P tag) : basic_pbf_writer{parent_writer, pbf_tag_type(tag)} { } diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/basic_pbf_writer.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/basic_pbf_writer.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/basic_pbf_writer.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/basic_pbf_writer.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -85,7 +85,7 @@ void add_field(pbf_tag_type tag, pbf_wire_type type) { protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1U << 29U) - 1))) && "tag out of range"); - const uint32_t b = (tag << 3U) | uint32_t(type); + const uint32_t b = (tag << 3U) | static_cast(type); add_varint(b); } @@ -105,7 +105,7 @@ } template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { // NOLINT(performance-unnecessary-value-param) if (first == last) { return; } @@ -118,7 +118,7 @@ } template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { // NOLINT(performance-unnecessary-value-param) if (first == last) { return; } @@ -133,7 +133,7 @@ } template - void add_packed_varint(pbf_tag_type tag, It first, It last) { + void add_packed_varint(pbf_tag_type tag, It first, It last) { // NOLINT(performance-unnecessary-value-param) if (first == last) { return; } @@ -146,7 +146,7 @@ } template - void add_packed_svarint(pbf_tag_type tag, It first, It last) { + void add_packed_svarint(pbf_tag_type tag, It first, It last) { // NOLINT(performance-unnecessary-value-param) if (first == last) { return; } @@ -162,7 +162,7 @@ // a length-delimited field. The length has to fit into pbf_length_type, // and a varint needs 8 bit for every 7 bit. enum : int { - reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1 + reserve_bytes = (sizeof(pbf_length_type) * 8 / 7) + 1 }; // If m_rollpack_pos is set to this special value, it means that when @@ -181,7 +181,7 @@ buffer_customization::append_zeros(m_data, std::size_t(reserve_bytes)); } else { m_rollback_pos = size_is_known; - add_length_varint(tag, pbf_length_type(size)); + add_length_varint(tag, static_cast(size)); reserve(size); } m_pos = buffer_customization::size(m_data); @@ -391,7 +391,7 @@ add_field(tag, pbf_wire_type::varint); protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); protozero_assert(m_data); - m_data->push_back(char(value)); + m_data->push_back(static_cast(value)); } /** @@ -401,7 +401,7 @@ * @param value Value to be written */ void add_enum(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); + add_tagged_varint(tag, static_cast(value)); } /** @@ -411,7 +411,7 @@ * @param value Value to be written */ void add_int32(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); + add_tagged_varint(tag, static_cast(value)); } /** @@ -441,7 +441,7 @@ * @param value Value to be written */ void add_int64(pbf_tag_type tag, int64_t value) { - add_tagged_varint(tag, uint64_t(value)); + add_tagged_varint(tag, static_cast(value)); } /** @@ -541,7 +541,7 @@ protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); protozero_assert(m_data); protozero_assert(size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(size)); + add_length_varint(tag, static_cast(size)); buffer_customization::append(m_data, value, size); } @@ -602,7 +602,7 @@ size_t sum_size = 0; (void)std::initializer_list{sum_size += values.size()...}; protozero_assert(sum_size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(sum_size)); + add_length_varint(tag, static_cast(sum_size)); buffer_customization::reserve_additional(m_data, sum_size); (void)std::initializer_list{(buffer_customization::append(m_data, values.data(), values.size()), 0)...}; } @@ -697,7 +697,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -711,7 +711,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -725,7 +725,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -739,7 +739,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_svarint(tag, first, last); } @@ -753,7 +753,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -767,7 +767,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -781,7 +781,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_svarint(tag, first, last); } @@ -795,7 +795,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_varint(tag, first, last); } @@ -817,7 +817,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) static_assert(std::is_same::value || std::is_same::value || std::is_same::value || @@ -838,7 +838,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } @@ -853,7 +853,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } @@ -868,7 +868,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } @@ -883,7 +883,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } @@ -898,7 +898,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } @@ -913,7 +913,7 @@ * @param last Iterator pointing one past the end of data */ template - void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { + void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { // NOLINT(performance-unnecessary-value-param) add_packed_fixed(tag, first, last, typename std::iterator_traits::iterator_category{}); } diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/buffer_string.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/buffer_string.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/buffer_string.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/buffer_string.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -57,8 +57,8 @@ protozero_assert(from <= buffer->size()); protozero_assert(to <= buffer->size()); protozero_assert(from <= to); - buffer->erase(std::next(buffer->begin(), static_cast(from)), - std::next(buffer->begin(), static_cast(to))); + buffer->erase(buffer->begin() + static_cast(from), + buffer->begin() + static_cast(to)); } static char* at_pos(std::string* buffer, std::size_t pos) { diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/config.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/config.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/config.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/config.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -18,6 +18,14 @@ * @brief Contains macro checks for different configurations. */ +#if __has_include() +#include // Recent posix +#elif __has_include() +#include // Common place on older BSD derived systems +#else +#error no endian.h found +#endif + #define PROTOZERO_LITTLE_ENDIAN 1234 #define PROTOZERO_BIG_ENDIAN 4321 @@ -35,6 +43,9 @@ # define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN #endif +// Sanity check +static_assert(PROTOZERO_BYTE_ORDER == BYTE_ORDER); + // Check whether __builtin_bswap is available #if defined(__GNUC__) || defined(__clang__) # define PROTOZERO_USE_BUILTIN_BSWAP diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/data_view.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/data_view.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/data_view.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/data_view.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -173,7 +173,7 @@ * @param lhs First object. * @param rhs Second object. */ -inline constexpr bool operator==(const data_view lhs, const data_view rhs) noexcept { +constexpr bool operator==(const data_view lhs, const data_view rhs) noexcept { return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data()); } @@ -185,7 +185,7 @@ * @param lhs First object. * @param rhs Second object. */ -inline constexpr bool operator!=(const data_view lhs, const data_view rhs) noexcept { +constexpr bool operator!=(const data_view lhs, const data_view rhs) noexcept { return !(lhs == rhs); } diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/pbf_message.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/pbf_message.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/pbf_message.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/pbf_message.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -64,7 +64,7 @@ template class pbf_message : public pbf_reader { - static_assert(std::is_same::type>::value, + static_assert(std::is_same>::value, "T must be enum with underlying type protozero::pbf_tag_type"); public: diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/pbf_reader.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/pbf_reader.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/pbf_reader.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/pbf_reader.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -76,9 +76,9 @@ template T get_fixed() { T result; - const char* data = m_data; + const char* tmp_data = m_data; skip_bytes(sizeof(T)); - std::memcpy(&result, data, sizeof(T)); + std::memcpy(&result, tmp_data, sizeof(T)); #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN byteswap_inplace(&result); #endif @@ -263,7 +263,7 @@ * and how it is encoded for this number to have any meaning. */ std::size_t length() const noexcept { - return std::size_t(m_end - m_data); + return static_cast(m_end - m_data); } /** @@ -287,7 +287,7 @@ } const auto value = get_varint(); - m_tag = pbf_tag_type(value >> 3U); + m_tag = static_cast(value >> 3U); // tags 0 and 19000 to 19999 are not allowed as per // https://developers.google.com/protocol-buffers/docs/proto#assigning-tags diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/types.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/types.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/types.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/types.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -52,7 +52,7 @@ * See pbf_reader.tag_and_type() for an example how to use this. */ template -constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept { +constexpr uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept { return (static_cast(static_cast(tag)) << 3U) | static_cast(wire_type); } diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/varint.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/varint.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/varint.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/varint.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -26,7 +26,7 @@ /** * The maximum length of a 64 bit varint. */ -constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1; +constexpr const int8_t max_varint_length = (sizeof(uint64_t) * 8 / 7) + 1; namespace detail { @@ -40,28 +40,28 @@ if (iend - begin >= max_varint_length) { // fast path do { int64_t b = *p++; - val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; } - b = *p++; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; } + val = ((static_cast(b) & 0x7fU) ); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 7U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 14U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 21U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 28U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 35U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 42U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 49U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x7fU) << 56U); if (b >= 0) { break; } + b = *p++; val |= ((static_cast(b) & 0x01U) << 63U); if (b >= 0) { break; } throw varint_too_long_exception{}; } while (false); } else { unsigned int shift = 0; while (p != iend && *p < 0) { - val |= (uint64_t(*p++) & 0x7fU) << shift; + val |= (static_cast(*p++) & 0x7fU) << shift; shift += 7; } if (p == iend) { throw end_of_buffer_exception{}; } - val |= uint64_t(*p++) << shift; + val |= static_cast(*p++) << shift; } *data = reinterpret_cast(p); @@ -148,11 +148,11 @@ int n = 1; while (value >= 0x80U) { - *data++ = char((value & 0x7fU) | 0x80U); + *data++ = static_cast((value & 0x7fU) | 0x80U); value >>= 7U; ++n; } - *data = char(value); + *data = static_cast(value); return n; } @@ -163,16 +163,15 @@ * @tparam TBuffer A buffer type. * @param buffer Output buffer the varint will be written to. * @param value The integer that will be encoded. - * @returns the number of bytes written * @throws Any exception thrown by calling the buffer_push_back() function. */ template inline void add_varint_to_buffer(TBuffer* buffer, uint64_t value) { while (value >= 0x80U) { - buffer_customization::push_back(buffer, char((value & 0x7fU) | 0x80U)); + buffer_customization::push_back(buffer, static_cast((value & 0x7fU) | 0x80U)); value >>= 7U; } - buffer_customization::push_back(buffer, char(value)); + buffer_customization::push_back(buffer, static_cast(value)); } /** @@ -186,11 +185,11 @@ int n = 1; while (value >= 0x80U) { - *data++ = char((value & 0x7fU) | 0x80U); + *data++ = static_cast((value & 0x7fU) | 0x80U); value >>= 7U; ++n; } - *data = char(value); + *data = static_cast(value); return n; } @@ -215,28 +214,28 @@ /** * ZigZag encodes a 32 bit integer. */ -inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept { +constexpr uint32_t encode_zigzag32(int32_t value) noexcept { return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 31U)); } /** * ZigZag encodes a 64 bit integer. */ -inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept { +constexpr uint64_t encode_zigzag64(int64_t value) noexcept { return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 63U)); } /** * Decodes a 32 bit ZigZag-encoded integer. */ -inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept { +constexpr int32_t decode_zigzag32(uint32_t value) noexcept { return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } /** * Decodes a 64 bit ZigZag-encoded integer. */ -inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept { +constexpr int64_t decode_zigzag64(uint64_t value) noexcept { return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } diff -Nru pdns-recursor-5.2.13/ext/protozero/include/protozero/version.hpp pdns-recursor-5.4.9/ext/protozero/include/protozero/version.hpp --- pdns-recursor-5.2.13/ext/protozero/include/protozero/version.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/include/protozero/version.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -20,15 +20,15 @@ #define PROTOZERO_VERSION_MAJOR 1 /// The minor version number -#define PROTOZERO_VERSION_MINOR 7 +#define PROTOZERO_VERSION_MINOR 8 /// The patch number -#define PROTOZERO_VERSION_PATCH 1 +#define PROTOZERO_VERSION_PATCH 0 /// The complete version number #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) /// Version number as string -#define PROTOZERO_VERSION_STRING "1.7.1" +#define PROTOZERO_VERSION_STRING "1.8.0" #endif // PROTOZERO_VERSION_HPP diff -Nru pdns-recursor-5.2.13/ext/protozero/meson.build pdns-recursor-5.4.9/ext/protozero/meson.build --- pdns-recursor-5.2.13/ext/protozero/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/protozero/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,3 @@ +dep_protozero = declare_dependency( + include_directories: include_directories('include'), +) diff -Nru pdns-recursor-5.2.13/ext/yahttp/Makefile.am pdns-recursor-5.4.9/ext/yahttp/Makefile.am --- pdns-recursor-5.2.13/ext/yahttp/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/Makefile.am 2026-10-26 09:46:36.000000000 +0000 @@ -1,3 +1,6 @@ SUBDIRS = yahttp -EXTRA_DIST = LICENSE README.md +EXTRA_DIST = \ + LICENSE \ + README.md \ + meson.build diff -Nru pdns-recursor-5.2.13/ext/yahttp/Makefile.in pdns-recursor-5.4.9/ext/yahttp/Makefile.in --- pdns-recursor-5.2.13/ext/yahttp/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/Makefile.in 2026-10-26 09:47:08.856458200 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -69,6 +69,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -373,8 +375,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -427,7 +431,11 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = yahttp -EXTRA_DIST = LICENSE README.md +EXTRA_DIST = \ + LICENSE \ + README.md \ + meson.build + all: all-recursive .SUFFIXES: @@ -652,8 +660,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -745,3 +753,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/yahttp/meson.build pdns-recursor-5.4.9/ext/yahttp/meson.build --- pdns-recursor-5.2.13/ext/yahttp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,3 @@ +module_dist = ['LICENSE', 'README.md'] + +subdir('yahttp') diff -Nru pdns-recursor-5.2.13/ext/yahttp/yahttp/Makefile.am pdns-recursor-5.4.9/ext/yahttp/yahttp/Makefile.am --- pdns-recursor-5.2.13/ext/yahttp/yahttp/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/yahttp/Makefile.am 2026-10-26 09:46:36.000000000 +0000 @@ -11,3 +11,6 @@ utility.hpp \ yahttp-config.h \ yahttp.hpp + +EXTRA_DIST = \ + meson.build diff -Nru pdns-recursor-5.2.13/ext/yahttp/yahttp/Makefile.in pdns-recursor-5.4.9/ext/yahttp/yahttp/Makefile.in --- pdns-recursor-5.2.13/ext/yahttp/yahttp/Makefile.in 2026-08-05 12:01:45.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/yahttp/Makefile.in 2026-10-26 09:47:08.871093500 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. +# Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2021 Free Software Foundation, Inc. +# Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -70,6 +70,8 @@ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -382,8 +384,10 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -448,6 +452,9 @@ yahttp-config.h \ yahttp.hpp +EXTRA_DIST = \ + meson.build + all: all-am .SUFFIXES: @@ -483,15 +490,13 @@ $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + -$(am__rm_f) $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } + echo rm -f $${locs}; \ + $(am__rm_f) $${locs} libyahttp.la: $(libyahttp_la_OBJECTS) $(libyahttp_la_DEPENDENCIES) $(EXTRA_libyahttp_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) $(libyahttp_la_OBJECTS) $(libyahttp_la_LIBADD) $(LIBS) @@ -507,7 +512,7 @@ $(am__depfiles_remade): @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + @: >>$@ am--depfiles: $(am__depfiles_remade) @@ -653,8 +658,8 @@ clean-generic: distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -665,7 +670,7 @@ mostlyclean-am distclean: distclean-am - -rm -f ./$(DEPDIR)/reqresp.Plo + -rm -f ./$(DEPDIR)/reqresp.Plo -rm -f ./$(DEPDIR)/router.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ @@ -712,7 +717,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/reqresp.Plo + -rm -f ./$(DEPDIR)/reqresp.Plo -rm -f ./$(DEPDIR)/router.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -754,3 +759,10 @@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/ext/yahttp/yahttp/meson.build pdns-recursor-5.4.9/ext/yahttp/yahttp/meson.build --- pdns-recursor-5.2.13/ext/yahttp/yahttp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/yahttp/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,26 @@ +lib_yahttp = static_library( + 'yahttp', + 'reqresp.cpp', + 'router.cpp', + extra_files: [ + 'cookie.hpp', + 'exception.hpp', + 'reqresp.hpp', + 'router.hpp', + 'url.hpp', + 'utility.hpp', + 'yahttp-config.h', + 'yahttp.hpp', + ], + cpp_args: '-Wno-overloaded-virtual', + dependencies: [dep_pdns], +) + +dep_yahttp = declare_dependency( + link_with: lib_yahttp, + include_directories: include_directories('..'), +) + +dep_yahttp_header_only = declare_dependency( + include_directories: include_directories('..'), +) diff -Nru pdns-recursor-5.2.13/ext/yahttp/yahttp/reqresp.cpp pdns-recursor-5.4.9/ext/yahttp/yahttp/reqresp.cpp --- pdns-recursor-5.2.13/ext/yahttp/yahttp/reqresp.cpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/yahttp/reqresp.cpp 2026-10-26 09:46:36.000000000 +0000 @@ -40,19 +40,7 @@ } template - bool AsyncLoader::feed(const std::string& somedata) - { - if (state < 2) { - headersize += somedata.length(); // maye include some body data, we don't know yet... - if (headersize > target->max_header_size) { - if (target->kind == YAHTTP_TYPE_REQUEST) { - throw ParseError("Request header too large"); - } - else { - throw ParseError("Response header too large"); - } - } - } + bool AsyncLoader::feed(const std::string& somedata) { buffer.append(somedata); while(state < 2) { int cr=0; @@ -167,8 +155,8 @@ maxbody = minbody; } if (minbody < 1) return true; // guess there isn't anything left. - if (target->kind == YAHTTP_TYPE_REQUEST && minbody > target->max_request_size) throw ParseError("Max request body size exceeded"); - else if (target->kind == YAHTTP_TYPE_RESPONSE && minbody > target->max_response_size) throw ParseError("Max response body size exceeded"); + if (target->kind == YAHTTP_TYPE_REQUEST && static_cast(minbody) > target->max_request_size) throw ParseError("Max request body size exceeded"); + else if (target->kind == YAHTTP_TYPE_RESPONSE && static_cast(minbody) > target->max_response_size) throw ParseError("Max response body size exceeded"); } if (maxbody == 0) hasBody = false; @@ -181,34 +169,26 @@ if (chunk_size == 0) { char buf[100]; // read chunk length - if ((pos = buffer.find('\n')) == std::string::npos) { - if (buffer.size() > 99) { - throw ParseError("Nonsensical chunk_size"); - } - return false; - } + if ((pos = buffer.find('\n')) == std::string::npos) return false; if (pos > 99) throw ParseError("Impossible chunk_size"); buffer.copy(buf, pos); buf[pos]=0; // just in case... buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer - if (sscanf(buf, "%zx", &chunk_size) != 1) { + if (sscanf(buf, "%x", &chunk_size) != 1) { throw ParseError("Unable to parse chunk size"); } if (chunk_size == 0) { state = 3; break; } // last chunk - if (chunk_size > (std::numeric_limits::max() - 2) || chunk_size > maxbody) { + if (chunk_size > (std::numeric_limits::max() - 2)) { throw ParseError("Chunk is too large"); } } else { int crlf=1; - if (buffer.size() < chunk_size+1) return false; // expect newline + if (buffer.size() < static_cast(chunk_size+1)) return false; // expect newline if (buffer.at(chunk_size) == '\r') { - if (buffer.size() < chunk_size+2 || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return + if (buffer.size() < static_cast(chunk_size+2) || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return crlf=2; } else if (buffer.at(chunk_size) != '\n') return false; - if (bodybuf.str().length() + chunk_size > maxbody) { - throw ParseError("Chunked body is too large"); - } std::string tmp = buffer.substr(0, chunk_size); buffer.erase(buffer.begin(), buffer.begin()+chunk_size+crlf); bodybuf << tmp; diff -Nru pdns-recursor-5.2.13/ext/yahttp/yahttp/reqresp.hpp pdns-recursor-5.4.9/ext/yahttp/yahttp/reqresp.hpp --- pdns-recursor-5.2.13/ext/yahttp/yahttp/reqresp.hpp 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ext/yahttp/yahttp/reqresp.hpp 2026-10-26 09:46:36.000000000 +0000 @@ -20,10 +20,6 @@ #include -#ifndef YAHTTP_MAX_HEADER_SIZE -#define YAHTTP_MAX_HEADER_SIZE (100 * 1024) -#endif - #ifndef YAHTTP_MAX_REQUEST_SIZE #define YAHTTP_MAX_REQUEST_SIZE 2097152 #endif @@ -112,7 +108,6 @@ #endif max_request_size = YAHTTP_MAX_REQUEST_SIZE; max_response_size = YAHTTP_MAX_RESPONSE_SIZE; - max_header_size = YAHTTP_MAX_HEADER_SIZE; url = ""; method = ""; statusText = ""; @@ -135,7 +130,6 @@ this->parameters = rhs.parameters; this->getvars = rhs.getvars; this->body = rhs.body; this->max_request_size = rhs.max_request_size; this->max_response_size = rhs.max_response_size; this->version = rhs.version; - this->max_header_size = rhs.max_header_size; #ifdef HAVE_CPP_FUNC_PTR this->renderer = rhs.renderer; #endif @@ -149,7 +143,6 @@ this->parameters = rhs.parameters; this->getvars = rhs.getvars; this->body = rhs.body; this->max_request_size = rhs.max_request_size; this->max_response_size = rhs.max_response_size; this->version = rhs.version; - this->max_header_size = rhs.max_header_size; #ifdef HAVE_CPP_FUNC_PTR this->renderer = rhs.renderer; #endif @@ -173,9 +166,8 @@ std::string body; // renderer; //target = target_; hasBody = false; buffer = ""; - headersize = 0; this->target->initialize(); }; //method != method) { // method did not match, record it though so we can return correct result matched = false; - seen = true; + // The OPTIONS handler registered in pdns/webserver.cc matches every + // url, and would cause "not found" errors to always be superseded + // with "found, but wrong method" errors, so don't pretend there has + // been a match in this case. + if (method != "OPTIONS") { + seen = true; + } continue; } if (matched) { diff -Nru pdns-recursor-5.2.13/filterpo.cc pdns-recursor-5.4.9/filterpo.cc --- pdns-recursor-5.2.13/filterpo.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/filterpo.cc 2026-10-26 08:26:51.000000000 +0000 @@ -348,7 +348,7 @@ } const auto& zoneName = zone->getName(); if (discardedPolicies.find(zoneName) != discardedPolicies.end()) { - return false; + continue; } if (zone->findResponsePolicy(address, pol)) { @@ -395,7 +395,7 @@ if (d_zoneData->d_ignoreDuplicates) { return; } - throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(pol.d_kind) + " but a policy of kind " + getKindToString(existingPol.d_kind) + " already exists for for the following name: " + n.toLogString()); + throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(pol.d_kind) + " but a policy of kind " + getKindToString(existingPol.d_kind) + " already exists for the following name: " + n.toLogString()); } addCustom(existingPol, pol); diff -Nru pdns-recursor-5.2.13/filterpo.hh pdns-recursor-5.4.9/filterpo.hh --- pdns-recursor-5.2.13/filterpo.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/filterpo.hh 2026-10-26 08:26:51.000000000 +0000 @@ -98,7 +98,7 @@ std::string d_name; std::string d_extendedErrorExtra; DNSRecord d_soa{}; - boost::optional d_extendedErrorCode{boost::none}; + std::optional d_extendedErrorCode{std::nullopt}; Priority d_priority{maximumPriority}; bool d_policyOverridesGettag{true}; bool d_includeSOA{false}; diff -Nru pdns-recursor-5.2.13/fstrm_logger.cc pdns-recursor-5.4.9/fstrm_logger.cc --- pdns-recursor-5.2.13/fstrm_logger.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/fstrm_logger.cc 2026-10-26 09:46:36.000000000 +0000 @@ -30,9 +30,7 @@ } if (d_family == AF_UNIX) { - struct sockaddr_un local - { - }; + struct sockaddr_un local{}; if (makeUNsockaddr(d_address, &local) != 0) { throw std::runtime_error("FrameStreamLogger: Unable to use '" + d_address + "', it is not a valid UNIX socket path."); } diff -Nru pdns-recursor-5.2.13/fstrm_logger.hh pdns-recursor-5.4.9/fstrm_logger.hh --- pdns-recursor-5.2.13/fstrm_logger.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/fstrm_logger.hh 2026-10-26 09:46:36.000000000 +0000 @@ -36,7 +36,7 @@ class FrameStreamLogger : public RemoteLoggerInterface { public: - FrameStreamLogger(int family, std::string address, bool connect, const std::unordered_map& options = std::unordered_map()); + FrameStreamLogger(int family, std::string address, bool connect, const std::unordered_map& options = std::unordered_map()); FrameStreamLogger(const FrameStreamLogger&) = delete; FrameStreamLogger(FrameStreamLogger&&) = delete; FrameStreamLogger& operator=(const FrameStreamLogger&) = delete; diff -Nru pdns-recursor-5.2.13/html/index.html pdns-recursor-5.4.9/html/index.html --- pdns-recursor-5.2.13/html/index.html 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/html/index.html 2026-10-26 08:26:51.000000000 +0000 @@ -4,7 +4,7 @@ - + diff -Nru pdns-recursor-5.2.13/html/js/handlebars-v4.0.11-min.js pdns-recursor-5.4.9/html/js/handlebars-v4.0.11-min.js --- pdns-recursor-5.2.13/html/js/handlebars-v4.0.11-min.js 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/html/js/handlebars-v4.0.11-min.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,284 +0,0 @@ - -(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==='object'&&typeof module==='object') -module.exports=factory();else if(typeof define==='function'&&define.amd) -define([],factory);else if(typeof exports==='object') -exports["Handlebars"]=factory();else -root["Handlebars"]=factory();})(this,function(){return(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]) -return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:false};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.loaded=true;return module.exports;} -__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.p="";return __webpack_require__(0);}) -([(function(module,exports,__webpack_require__){'use strict';var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;var _handlebarsRuntime=__webpack_require__(2);var _handlebarsRuntime2=_interopRequireDefault(_handlebarsRuntime);var _handlebarsCompilerAst=__webpack_require__(35);var _handlebarsCompilerAst2=_interopRequireDefault(_handlebarsCompilerAst);var _handlebarsCompilerBase=__webpack_require__(36);var _handlebarsCompilerCompiler=__webpack_require__(41);var _handlebarsCompilerJavascriptCompiler=__webpack_require__(42);var _handlebarsCompilerJavascriptCompiler2=_interopRequireDefault(_handlebarsCompilerJavascriptCompiler);var _handlebarsCompilerVisitor=__webpack_require__(39);var _handlebarsCompilerVisitor2=_interopRequireDefault(_handlebarsCompilerVisitor);var _handlebarsNoConflict=__webpack_require__(34);var _handlebarsNoConflict2=_interopRequireDefault(_handlebarsNoConflict);var _create=_handlebarsRuntime2['default'].create;function create(){var hb=_create();hb.compile=function(input,options){return _handlebarsCompilerCompiler.compile(input,options,hb);};hb.precompile=function(input,options){return _handlebarsCompilerCompiler.precompile(input,options,hb);};hb.AST=_handlebarsCompilerAst2['default'];hb.Compiler=_handlebarsCompilerCompiler.Compiler;hb.JavaScriptCompiler=_handlebarsCompilerJavascriptCompiler2['default'];hb.Parser=_handlebarsCompilerBase.parser;hb.parse=_handlebarsCompilerBase.parse;return hb;} -var inst=create();inst.create=create;_handlebarsNoConflict2['default'](inst);inst.Visitor=_handlebarsCompilerVisitor2['default'];inst['default']=inst;exports['default']=inst;module.exports=exports['default'];}),(function(module,exports){"use strict";exports["default"]=function(obj){return obj&&obj.__esModule?obj:{"default":obj};};exports.__esModule=true;}),(function(module,exports,__webpack_require__){'use strict';var _interopRequireWildcard=__webpack_require__(3)['default'];var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;var _handlebarsBase=__webpack_require__(4);var base=_interopRequireWildcard(_handlebarsBase);var _handlebarsSafeString=__webpack_require__(21);var _handlebarsSafeString2=_interopRequireDefault(_handlebarsSafeString);var _handlebarsException=__webpack_require__(6);var _handlebarsException2=_interopRequireDefault(_handlebarsException);var _handlebarsUtils=__webpack_require__(5);var Utils=_interopRequireWildcard(_handlebarsUtils);var _handlebarsRuntime=__webpack_require__(22);var runtime=_interopRequireWildcard(_handlebarsRuntime);var _handlebarsNoConflict=__webpack_require__(34);var _handlebarsNoConflict2=_interopRequireDefault(_handlebarsNoConflict);function create(){var hb=new base.HandlebarsEnvironment();Utils.extend(hb,base);hb.SafeString=_handlebarsSafeString2['default'];hb.Exception=_handlebarsException2['default'];hb.Utils=Utils;hb.escapeExpression=Utils.escapeExpression;hb.VM=runtime;hb.template=function(spec){return runtime.template(spec,hb);};return hb;} -var inst=create();inst.create=create;_handlebarsNoConflict2['default'](inst);inst['default']=inst;exports['default']=inst;module.exports=exports['default'];}),(function(module,exports){"use strict";exports["default"]=function(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}} -newObj["default"]=obj;return newObj;}};exports.__esModule=true;}),(function(module,exports,__webpack_require__){'use strict';var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;exports.HandlebarsEnvironment=HandlebarsEnvironment;var _utils=__webpack_require__(5);var _exception=__webpack_require__(6);var _exception2=_interopRequireDefault(_exception);var _helpers=__webpack_require__(10);var _decorators=__webpack_require__(18);var _logger=__webpack_require__(20);var _logger2=_interopRequireDefault(_logger);var VERSION='4.0.11';exports.VERSION=VERSION;var COMPILER_REVISION=7;exports.COMPILER_REVISION=COMPILER_REVISION;var REVISION_CHANGES={1:'<= 1.0.rc.2',2:'== 1.0.0-rc.3',3:'== 1.0.0-rc.4',4:'== 1.x.x',5:'== 2.0.0-alpha.x',6:'>= 2.0.0-beta.1',7:'>= 4.0.0'};exports.REVISION_CHANGES=REVISION_CHANGES;var objectType='[object Object]';function HandlebarsEnvironment(helpers,partials,decorators){this.helpers=helpers||{};this.partials=partials||{};this.decorators=decorators||{};_helpers.registerDefaultHelpers(this);_decorators.registerDefaultDecorators(this);} -HandlebarsEnvironment.prototype={constructor:HandlebarsEnvironment,logger:_logger2['default'],log:_logger2['default'].log,registerHelper:function registerHelper(name,fn){if(_utils.toString.call(name)===objectType){if(fn){throw new _exception2['default']('Arg not supported with multiple helpers');} -_utils.extend(this.helpers,name);}else{this.helpers[name]=fn;}},unregisterHelper:function unregisterHelper(name){delete this.helpers[name];},registerPartial:function registerPartial(name,partial){if(_utils.toString.call(name)===objectType){_utils.extend(this.partials,name);}else{if(typeof partial==='undefined'){throw new _exception2['default']('Attempting to register a partial called "'+name+'" as undefined');} -this.partials[name]=partial;}},unregisterPartial:function unregisterPartial(name){delete this.partials[name];},registerDecorator:function registerDecorator(name,fn){if(_utils.toString.call(name)===objectType){if(fn){throw new _exception2['default']('Arg not supported with multiple decorators');} -_utils.extend(this.decorators,name);}else{this.decorators[name]=fn;}},unregisterDecorator:function unregisterDecorator(name){delete this.decorators[name];}};var log=_logger2['default'].log;exports.log=log;exports.createFrame=_utils.createFrame;exports.logger=_logger2['default'];}),(function(module,exports){'use strict';exports.__esModule=true;exports.extend=extend;exports.indexOf=indexOf;exports.escapeExpression=escapeExpression;exports.isEmpty=isEmpty;exports.createFrame=createFrame;exports.blockParams=blockParams;exports.appendContextPath=appendContextPath;var escape={'&':'&','<':'<','>':'>','"':'"',"'":''','`':'`','=':'='};var badChars=/[&<>"'`=]/g,possible=/[&<>"'`=]/;function escapeChar(chr){return escape[chr];} -function extend(obj){for(var i=1;i0){if(options.ids){options.ids=[options.name];} -return instance.helpers.each(context,options);}else{return inverse(this);}}else{if(options.data&&options.ids){var data=_utils.createFrame(options.data);data.contextPath=_utils.appendContextPath(options.data.contextPath,options.name);options={data:data};} -return fn(context,options);}});};module.exports=exports['default'];}),(function(module,exports,__webpack_require__){'use strict';var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;var _utils=__webpack_require__(5);var _exception=__webpack_require__(6);var _exception2=_interopRequireDefault(_exception);exports['default']=function(instance){instance.registerHelper('each',function(context,options){if(!options){throw new _exception2['default']('Must pass iterator to #each');} -var fn=options.fn,inverse=options.inverse,i=0,ret='',data=undefined,contextPath=undefined;if(options.data&&options.ids){contextPath=_utils.appendContextPath(options.data.contextPath,options.ids[0])+'.';} -if(_utils.isFunction(context)){context=context.call(this);} -if(options.data){data=_utils.createFrame(options.data);} -function execIteration(field,index,last){if(data){data.key=field;data.index=index;data.first=index===0;data.last=!!last;if(contextPath){data.contextPath=contextPath+field;}} -ret=ret+fn(context[field],{data:data,blockParams:_utils.blockParams([context[field],field],[contextPath+field,null])});} -if(context&&typeof context==='object'){if(_utils.isArray(context)){for(var j=context.length;i=0){level=levelMap;}else{level=parseInt(level,10);}} -return level;},log:function log(level){level=logger.lookupLevel(level);if(typeof console!=='undefined'&&logger.lookupLevel(logger.level)<=level){var method=logger.methodMap[level];if(!console[method]){method='log';} -for(var _len=arguments.length,message=Array(_len>1?_len-1:0),_key=1;_key<_len;_key++){message[_key-1]=arguments[_key];} -console[method].apply(console,message);}}};exports['default']=logger;module.exports=exports['default'];}),(function(module,exports){'use strict';exports.__esModule=true;function SafeString(string){this.string=string;} -SafeString.prototype.toString=SafeString.prototype.toHTML=function(){return''+this.string;};exports['default']=SafeString;module.exports=exports['default'];}),(function(module,exports,__webpack_require__){'use strict';var _Object$seal=__webpack_require__(23)['default'];var _interopRequireWildcard=__webpack_require__(3)['default'];var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;exports.checkRevision=checkRevision;exports.template=template;exports.wrapProgram=wrapProgram;exports.resolvePartial=resolvePartial;exports.invokePartial=invokePartial;exports.noop=noop;var _utils=__webpack_require__(5);var Utils=_interopRequireWildcard(_utils);var _exception=__webpack_require__(6);var _exception2=_interopRequireDefault(_exception);var _base=__webpack_require__(4);function checkRevision(compilerInfo){var compilerRevision=compilerInfo&&compilerInfo[0]||1,currentRevision=_base.COMPILER_REVISION;if(compilerRevision!==currentRevision){if(compilerRevision2){expected.push("'"+this.terminals_[p]+"'");} -if(this.lexer.showPosition){errStr="Parse error on line "+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(", ")+", got '"+(this.terminals_[symbol]||symbol)+"'";}else{errStr="Parse error on line "+(yylineno+1)+": Unexpected "+(symbol==1?"end of input":"'"+(this.terminals_[symbol]||symbol)+"'");} -this.parseError(errStr,{text:this.lexer.match,token:this.terminals_[symbol]||symbol,line:this.lexer.yylineno,loc:yyloc,expected:expected});}} -if(action[0]instanceof Array&&action.length>1){throw new Error("Parse Error: multiple actions possible at state: "+state+", token: "+symbol);} -switch(action[0]){case 1:stack.push(symbol);vstack.push(this.lexer.yytext);lstack.push(this.lexer.yylloc);stack.push(action[1]);symbol=null;if(!preErrorSymbol){yyleng=this.lexer.yyleng;yytext=this.lexer.yytext;yylineno=this.lexer.yylineno;yyloc=this.lexer.yylloc;if(recovering>0)recovering--;}else{symbol=preErrorSymbol;preErrorSymbol=null;} -break;case 2:len=this.productions_[action[1]][1];yyval.$=vstack[vstack.length-len];yyval._$={first_line:lstack[lstack.length-(len||1)].first_line,last_line:lstack[lstack.length-1].last_line,first_column:lstack[lstack.length-(len||1)].first_column,last_column:lstack[lstack.length-1].last_column};if(ranges){yyval._$.range=[lstack[lstack.length-(len||1)].range[0],lstack[lstack.length-1].range[1]];} -r=this.performAction.call(yyval,yytext,yyleng,yylineno,this.yy,action[1],vstack,lstack);if(typeof r!=="undefined"){return r;} -if(len){stack=stack.slice(0,-1*len*2);vstack=vstack.slice(0,-1*len);lstack=lstack.slice(0,-1*len);} -stack.push(this.productions_[action[1]][0]);vstack.push(yyval.$);lstack.push(yyval._$);newState=table[stack[stack.length-2]][stack[stack.length-1]];stack.push(newState);break;case 3:return true;}} -return true;}};var lexer=(function(){var lexer={EOF:1,parseError:function parseError(str,hash){if(this.yy.parser){this.yy.parser.parseError(str,hash);}else{throw new Error(str);}},setInput:function setInput(input){this._input=input;this._more=this._less=this.done=false;this.yylineno=this.yyleng=0;this.yytext=this.matched=this.match='';this.conditionStack=['INITIAL'];this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0};if(this.options.ranges)this.yylloc.range=[0,0];this.offset=0;return this;},input:function input(){var ch=this._input[0];this.yytext+=ch;this.yyleng++;this.offset++;this.match+=ch;this.matched+=ch;var lines=ch.match(/(?:\r\n?|\n).*/g);if(lines){this.yylineno++;this.yylloc.last_line++;}else{this.yylloc.last_column++;} -if(this.options.ranges)this.yylloc.range[1]++;this._input=this._input.slice(1);return ch;},unput:function unput(ch){var len=ch.length;var lines=ch.split(/(?:\r\n?|\n)/g);this._input=ch+this._input;this.yytext=this.yytext.substr(0,this.yytext.length-len-1);this.offset-=len;var oldLines=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1);this.matched=this.matched.substr(0,this.matched.length-1);if(lines.length-1)this.yylineno-=lines.length-1;var r=this.yylloc.range;this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:lines?(lines.length===oldLines.length?this.yylloc.first_column:0)+oldLines[oldLines.length-lines.length].length-lines[0].length:this.yylloc.first_column-len};if(this.options.ranges){this.yylloc.range=[r[0],r[0]+this.yyleng-len];} -return this;},more:function more(){this._more=true;return this;},less:function less(n){this.unput(this.match.slice(n));},pastInput:function pastInput(){var past=this.matched.substr(0,this.matched.length-this.match.length);return(past.length>20?'...':'')+past.substr(-20).replace(/\n/g,"");},upcomingInput:function upcomingInput(){var next=this.match;if(next.length<20){next+=this._input.substr(0,20-next.length);} -return(next.substr(0,20)+(next.length>20?'...':'')).replace(/\n/g,"");},showPosition:function showPosition(){var pre=this.pastInput();var c=new Array(pre.length+1).join("-");return pre+this.upcomingInput()+"\n"+c+"^";},next:function next(){if(this.done){return this.EOF;} -if(!this._input)this.done=true;var token,match,tempMatch,index,col,lines;if(!this._more){this.yytext='';this.match='';} -var rules=this._currentRules();for(var i=0;imatch[0].length)){match=tempMatch;index=i;if(!this.options.flex)break;}} -if(match){lines=match[0].match(/(?:\r\n?|\n).*/g);if(lines)this.yylineno+=lines.length;this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:lines?lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+match[0].length};this.yytext+=match[0];this.match+=match[0];this.matches=match;this.yyleng=this.yytext.length;if(this.options.ranges){this.yylloc.range=[this.offset,this.offset+=this.yyleng];} -this._more=false;this._input=this._input.slice(match[0].length);this.matched+=match[0];token=this.performAction.call(this,this.yy,this,rules[index],this.conditionStack[this.conditionStack.length-1]);if(this.done&&this._input)this.done=false;if(token)return token;else return;} -if(this._input===""){return this.EOF;}else{return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),{text:"",token:null,line:this.yylineno});}},lex:function lex(){var r=this.next();if(typeof r!=='undefined'){return r;}else{return this.lex();}},begin:function begin(condition){this.conditionStack.push(condition);},popState:function popState(){return this.conditionStack.pop();},_currentRules:function _currentRules(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;},topState:function topState(){return this.conditionStack[this.conditionStack.length-2];},pushState:function begin(condition){this.begin(condition);}};lexer.options={};lexer.performAction=function anonymous(yy,yy_,$avoiding_name_collisions,YY_START){function strip(start,end){return yy_.yytext=yy_.yytext.substr(start,yy_.yyleng-end);} -var YYSTATE=YY_START;switch($avoiding_name_collisions){case 0:if(yy_.yytext.slice(-2)==="\\\\"){strip(0,1);this.begin("mu");}else if(yy_.yytext.slice(-1)==="\\"){strip(0,1);this.begin("emu");}else{this.begin("mu");} -if(yy_.yytext)return 15;break;case 1:return 15;break;case 2:this.popState();return 15;break;case 3:this.begin('raw');return 15;break;case 4:this.popState();if(this.conditionStack[this.conditionStack.length-1]==='raw'){return 15;}else{yy_.yytext=yy_.yytext.substr(5,yy_.yyleng-9);return'END_RAW_BLOCK';} -break;case 5:return 15;break;case 6:this.popState();return 14;break;case 7:return 65;break;case 8:return 68;break;case 9:return 19;break;case 10:this.popState();this.begin('raw');return 23;break;case 11:return 55;break;case 12:return 60;break;case 13:return 29;break;case 14:return 47;break;case 15:this.popState();return 44;break;case 16:this.popState();return 44;break;case 17:return 34;break;case 18:return 39;break;case 19:return 51;break;case 20:return 48;break;case 21:this.unput(yy_.yytext);this.popState();this.begin('com');break;case 22:this.popState();return 14;break;case 23:return 48;break;case 24:return 73;break;case 25:return 72;break;case 26:return 72;break;case 27:return 87;break;case 28:break;case 29:this.popState();return 54;break;case 30:this.popState();return 33;break;case 31:yy_.yytext=strip(1,2).replace(/\\"/g,'"');return 80;break;case 32:yy_.yytext=strip(1,2).replace(/\\'/g,"'");return 80;break;case 33:return 85;break;case 34:return 82;break;case 35:return 82;break;case 36:return 83;break;case 37:return 84;break;case 38:return 81;break;case 39:return 75;break;case 40:return 77;break;case 41:return 72;break;case 42:yy_.yytext=yy_.yytext.replace(/\\([\\\]])/g,'$1');return 72;break;case 43:return'INVALID';break;case 44:return 5;break;}};lexer.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{(?=[^\/]))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#>)/,/^(?:\{\{(~)?#\*?)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?\*?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[(\\\]|[^\]])*\])/,/^(?:.)/,/^(?:$)/];lexer.conditions={"mu":{"rules":[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[6],"inclusive":false},"raw":{"rules":[3,4,5],"inclusive":false},"INITIAL":{"rules":[0,1,44],"inclusive":true}};return lexer;})();parser.lexer=lexer;function Parser(){this.yy={};}Parser.prototype=parser;parser.Parser=Parser;return new Parser();})();exports["default"]=handlebars;module.exports=exports["default"];}),(function(module,exports,__webpack_require__){'use strict';var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;var _visitor=__webpack_require__(39);var _visitor2=_interopRequireDefault(_visitor);function WhitespaceControl(){var options=arguments.length<=0||arguments[0]===undefined?{}:arguments[0];this.options=options;} -WhitespaceControl.prototype=new _visitor2['default']();WhitespaceControl.prototype.Program=function(program){var doStandalone=!this.options.ignoreStandalone;var isRoot=!this.isRootSeen;this.isRootSeen=true;var body=program.body;for(var i=0,l=body.length;i0){throw new _exception2['default']('Invalid path: '+original,{loc:loc});}else if(part==='..'){depth++;depthString+='../';}}else{dig.push(part);}} -return{type:'PathExpression',data:data,depth:depth,parts:dig,original:original,loc:loc};} -function prepareMustache(path,params,hash,open,strip,locInfo){var escapeFlag=open.charAt(3)||open.charAt(2),escaped=escapeFlag!=='{'&&escapeFlag!=='&';var decorator=/\*/.test(open);return{type:decorator?'Decorator':'MustacheStatement',path:path,params:params,hash:hash,escaped:escaped,strip:strip,loc:this.locInfo(locInfo)};} -function prepareRawBlock(openRawBlock,contents,close,locInfo){validateClose(openRawBlock,close);locInfo=this.locInfo(locInfo);var program={type:'Program',body:contents,strip:{},loc:locInfo};return{type:'BlockStatement',path:openRawBlock.path,params:openRawBlock.params,hash:openRawBlock.hash,program:program,openStrip:{},inverseStrip:{},closeStrip:{},loc:locInfo};} -function prepareBlock(openBlock,program,inverseAndProgram,close,inverted,locInfo){if(close&&close.path){validateClose(openBlock,close);} -var decorator=/\*/.test(openBlock.open);program.blockParams=openBlock.blockParams;var inverse=undefined,inverseStrip=undefined;if(inverseAndProgram){if(decorator){throw new _exception2['default']('Unexpected inverse block on decorator',inverseAndProgram);} -if(inverseAndProgram.chain){inverseAndProgram.program.body[0].closeStrip=close.strip;} -inverseStrip=inverseAndProgram.strip;inverse=inverseAndProgram.program;} -if(inverted){inverted=inverse;inverse=program;program=inverted;} -return{type:decorator?'DecoratorBlock':'BlockStatement',path:openBlock.path,params:openBlock.params,hash:openBlock.hash,program:program,inverse:inverse,openStrip:openBlock.strip,inverseStrip:inverseStrip,closeStrip:close&&close.strip,loc:this.locInfo(locInfo)};} -function prepareProgram(statements,loc){if(!loc&&statements.length){var firstLoc=statements[0].loc,lastLoc=statements[statements.length-1].loc;if(firstLoc&&lastLoc){loc={source:firstLoc.source,start:{line:firstLoc.start.line,column:firstLoc.start.column},end:{line:lastLoc.end.line,column:lastLoc.end.column}};}} -return{type:'Program',body:statements,strip:{},loc:loc};} -function preparePartialBlock(open,program,close,locInfo){validateClose(open,close);return{type:'PartialBlockStatement',name:open.path,params:open.params,hash:open.hash,program:program,openStrip:open.strip,closeStrip:close&&close.strip,loc:this.locInfo(locInfo)};}}),(function(module,exports,__webpack_require__){'use strict';var _interopRequireDefault=__webpack_require__(1)['default'];exports.__esModule=true;exports.Compiler=Compiler;exports.precompile=precompile;exports.compile=compile;var _exception=__webpack_require__(6);var _exception2=_interopRequireDefault(_exception);var _utils=__webpack_require__(5);var _ast=__webpack_require__(35);var _ast2=_interopRequireDefault(_ast);var slice=[].slice;function Compiler(){} -Compiler.prototype={compiler:Compiler,equals:function equals(other){var len=this.opcodes.length;if(other.opcodes.length!==len){return false;} -for(var i=0;i1){throw new _exception2['default']('Unsupported number of partial arguments: '+params.length,partial);}else if(!params.length){if(this.options.explicitPartialContext){this.opcode('pushLiteral','undefined');}else{params.push({type:'PathExpression',parts:[],depth:0});}} -var partialName=partial.name.original,isDynamic=partial.name.type==='SubExpression';if(isDynamic){this.accept(partial.name);} -this.setupFullMustacheParams(partial,program,undefined,true);var indent=partial.indent||'';if(this.options.preventIndent&&indent){this.opcode('appendContent',indent);indent='';} -this.opcode('invokePartial',isDynamic,partialName,indent);this.opcode('append');},PartialBlockStatement:function PartialBlockStatement(partialBlock){this.PartialStatement(partialBlock);},MustacheStatement:function MustacheStatement(mustache){this.SubExpression(mustache);if(mustache.escaped&&!this.options.noEscape){this.opcode('appendEscaped');}else{this.opcode('append');}},Decorator:function Decorator(decorator){this.DecoratorBlock(decorator);},ContentStatement:function ContentStatement(content){if(content.value){this.opcode('appendContent',content.value);}},CommentStatement:function CommentStatement(){},SubExpression:function SubExpression(sexpr){transformLiteralToPath(sexpr);var type=this.classifySexpr(sexpr);if(type==='simple'){this.simpleSexpr(sexpr);}else if(type==='helper'){this.helperSexpr(sexpr);}else{this.ambiguousSexpr(sexpr);}},ambiguousSexpr:function ambiguousSexpr(sexpr,program,inverse){var path=sexpr.path,name=path.parts[0],isBlock=program!=null||inverse!=null;this.opcode('getContext',path.depth);this.opcode('pushProgram',program);this.opcode('pushProgram',inverse);path.strict=true;this.accept(path);this.opcode('invokeAmbiguous',name,isBlock);},simpleSexpr:function simpleSexpr(sexpr){var path=sexpr.path;path.strict=true;this.accept(path);this.opcode('resolvePossibleLambda');},helperSexpr:function helperSexpr(sexpr,program,inverse){var params=this.setupFullMustacheParams(sexpr,program,inverse),path=sexpr.path,name=path.parts[0];if(this.options.knownHelpers[name]){this.opcode('invokeKnownHelper',params.length,name);}else if(this.options.knownHelpersOnly){throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper '+name,sexpr);}else{path.strict=true;path.falsy=true;this.accept(path);this.opcode('invokeHelper',params.length,path.original,_ast2['default'].helpers.simpleId(path));}},PathExpression:function PathExpression(path){this.addDepth(path.depth);this.opcode('getContext',path.depth);var name=path.parts[0],scoped=_ast2['default'].helpers.scopedId(path),blockParamId=!path.depth&&!scoped&&this.blockParamIndex(name);if(blockParamId){this.opcode('lookupBlockParam',blockParamId,path.parts);}else if(!name){this.opcode('pushContext');}else if(path.data){this.options.data=true;this.opcode('lookupData',path.depth,path.parts,path.strict);}else{this.opcode('lookupOnContext',path.parts,path.falsy,path.strict,scoped);}},StringLiteral:function StringLiteral(string){this.opcode('pushString',string.value);},NumberLiteral:function NumberLiteral(number){this.opcode('pushLiteral',number.value);},BooleanLiteral:function BooleanLiteral(bool){this.opcode('pushLiteral',bool.value);},UndefinedLiteral:function UndefinedLiteral(){this.opcode('pushLiteral','undefined');},NullLiteral:function NullLiteral(){this.opcode('pushLiteral','null');},Hash:function Hash(hash){var pairs=hash.pairs,i=0,l=pairs.length;this.opcode('pushHash');for(;i=0){return[depth,param];}}}};function precompile(input,options,env){if(input==null||typeof input!=='string'&&input.type!=='Program'){throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed '+input);} -options=options||{};if(!('data'in options)){options.data=true;} -if(options.compat){options.useDepths=true;} -var ast=env.parse(input,options),environment=new env.Compiler().compile(ast,options);return new env.JavaScriptCompiler().compile(environment,options);} -function compile(input,options,env){if(options===undefined)options={};if(input==null||typeof input!=='string'&&input.type!=='Program'){throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed '+input);} -options=_utils.extend({},options);if(!('data'in options)){options.data=true;} -if(options.compat){options.useDepths=true;} -var compiled=undefined;function compileInput(){var ast=env.parse(input,options),environment=new env.Compiler().compile(ast,options),templateSpec=new env.JavaScriptCompiler().compile(environment,options,undefined,true);return env.template(templateSpec);} -function ret(context,execOptions){if(!compiled){compiled=compileInput();} -return compiled.call(this,context,execOptions);} -ret._setup=function(setupOptions){if(!compiled){compiled=compileInput();} -return compiled._setup(setupOptions);};ret._child=function(i,data,blockParams,depths){if(!compiled){compiled=compileInput();} -return compiled._child(i,data,blockParams,depths);};return ret;} -function argEquals(a,b){if(a===b){return true;} -if(_utils.isArray(a)&&_utils.isArray(b)&&a.length===b.length){for(var i=0;i0){varDeclarations+=', '+locals.join(', ');} -var aliasCount=0;for(var alias in this.aliases){var node=this.aliases[alias];if(this.aliases.hasOwnProperty(alias)&&node.children&&node.referenceCount>1){varDeclarations+=', alias'+ ++aliasCount+'='+alias;node.children[0]='alias'+aliasCount;}} -var params=['container','depth0','helpers','partials','data'];if(this.useBlockParams||this.useDepths){params.push('blockParams');} -if(this.useDepths){params.push('depths');} -var source=this.mergeSource(varDeclarations);if(asObject){params.push(source);return Function.apply(this,params);}else{return this.source.wrap(['function(',params.join(','),') {\n ',source,'}']);}},mergeSource:function mergeSource(varDeclarations){var isSimple=this.environment.isSimple,appendOnly=!this.forceBuffer,appendFirst=undefined,sourceSeen=undefined,bufferStart=undefined,bufferEnd=undefined;this.source.each(function(line){if(line.appendToBuffer){if(bufferStart){line.prepend(' + ');}else{bufferStart=line;} -bufferEnd=line;}else{if(bufferStart){if(!sourceSeen){appendFirst=true;}else{bufferStart.prepend('buffer += ');} -bufferEnd.add(';');bufferStart=bufferEnd=undefined;} -sourceSeen=true;if(!isSimple){appendOnly=false;}}});if(appendOnly){if(bufferStart){bufferStart.prepend('return ');bufferEnd.add(';');}else if(!sourceSeen){this.source.push('return "";');}}else{varDeclarations+=', buffer = '+(appendFirst?'':this.initializeBuffer());if(bufferStart){bufferStart.prepend('return buffer + ');bufferEnd.add(';');}else{this.source.push('return buffer;');}} -if(varDeclarations){this.source.prepend('var '+varDeclarations.substring(2)+(appendFirst?'':';\n'));} -return this.source.merge();},blockValue:function blockValue(name){var blockHelperMissing=this.aliasable('helpers.blockHelperMissing'),params=[this.contextName(0)];this.setupHelperArgs(name,0,params);var blockName=this.popStack();params.splice(1,0,blockName);this.push(this.source.functionCall(blockHelperMissing,'call',params));},ambiguousBlockValue:function ambiguousBlockValue(){var blockHelperMissing=this.aliasable('helpers.blockHelperMissing'),params=[this.contextName(0)];this.setupHelperArgs('',0,params,true);this.flushInline();var current=this.topStack();params.splice(1,0,current);this.pushSource(['if (!',this.lastHelper,') { ',current,' = ',this.source.functionCall(blockHelperMissing,'call',params),'}']);},appendContent:function appendContent(content){if(this.pendingContent){content=this.pendingContent+content;}else{this.pendingLocation=this.source.currentLocation;} -this.pendingContent=content;},append:function append(){if(this.isInline()){this.replaceStack(function(current){return[' != null ? ',current,' : ""'];});this.pushSource(this.appendToBuffer(this.popStack()));}else{var local=this.popStack();this.pushSource(['if (',local,' != null) { ',this.appendToBuffer(local,undefined,true),' }']);if(this.environment.isSimple){this.pushSource(['else { ',this.appendToBuffer("''",undefined,true),' }']);}}},appendEscaped:function appendEscaped(){this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'),'(',this.popStack(),')']));},getContext:function getContext(depth){this.lastContext=depth;},pushContext:function pushContext(){this.pushStackLiteral(this.contextName(this.lastContext));},lookupOnContext:function lookupOnContext(parts,falsy,strict,scoped){var i=0;if(!scoped&&this.options.compat&&!this.lastContext){this.push(this.depthedLookup(parts[i++]));}else{this.pushContext();} -this.resolvePath('context',parts,i,falsy,strict);},lookupBlockParam:function lookupBlockParam(blockParamId,parts){this.useBlockParams=true;this.push(['blockParams[',blockParamId[0],'][',blockParamId[1],']']);this.resolvePath('context',parts,1);},lookupData:function lookupData(depth,parts,strict){if(!depth){this.pushStackLiteral('data');}else{this.pushStackLiteral('container.data(data, '+depth+')');} -this.resolvePath('data',parts,0,true,strict);},resolvePath:function resolvePath(type,parts,i,falsy,strict){var _this=this;if(this.options.strict||this.options.assumeObjects){this.push(strictLookup(this.options.strict&&strict,this,parts,type));return;} -var len=parts.length;for(;ithis.stackVars.length){this.stackVars.push('stack'+this.stackSlot);} -return this.topStackName();},topStackName:function topStackName(){return'stack'+this.stackSlot;},flushInline:function flushInline(){var inlineStack=this.inlineStack;this.inlineStack=[];for(var i=0,len=inlineStack.length;i= 2.0.0-beta.1', - 7: '>= 4.0.0' - }; - - exports.REVISION_CHANGES = REVISION_CHANGES; - var objectType = '[object Object]'; - - function HandlebarsEnvironment(helpers, partials, decorators) { - this.helpers = helpers || {}; - this.partials = partials || {}; - this.decorators = decorators || {}; - - _helpers.registerDefaultHelpers(this); - _decorators.registerDefaultDecorators(this); - } - - HandlebarsEnvironment.prototype = { - constructor: HandlebarsEnvironment, - - logger: _logger2['default'], - log: _logger2['default'].log, - - registerHelper: function registerHelper(name, fn) { - if (_utils.toString.call(name) === objectType) { - if (fn) { - throw new _exception2['default']('Arg not supported with multiple helpers'); - } - _utils.extend(this.helpers, name); - } else { - this.helpers[name] = fn; - } - }, - unregisterHelper: function unregisterHelper(name) { - delete this.helpers[name]; - }, - - registerPartial: function registerPartial(name, partial) { - if (_utils.toString.call(name) === objectType) { - _utils.extend(this.partials, name); - } else { - if (typeof partial === 'undefined') { - throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); - } - this.partials[name] = partial; - } - }, - unregisterPartial: function unregisterPartial(name) { - delete this.partials[name]; - }, - - registerDecorator: function registerDecorator(name, fn) { - if (_utils.toString.call(name) === objectType) { - if (fn) { - throw new _exception2['default']('Arg not supported with multiple decorators'); - } - _utils.extend(this.decorators, name); - } else { - this.decorators[name] = fn; - } - }, - unregisterDecorator: function unregisterDecorator(name) { - delete this.decorators[name]; - } - }; - - var log = _logger2['default'].log; - - exports.log = log; - exports.createFrame = _utils.createFrame; - exports.logger = _logger2['default']; - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - exports.extend = extend; - exports.indexOf = indexOf; - exports.escapeExpression = escapeExpression; - exports.isEmpty = isEmpty; - exports.createFrame = createFrame; - exports.blockParams = blockParams; - exports.appendContextPath = appendContextPath; - var escape = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`', - '=': '=' - }; - - var badChars = /[&<>"'`=]/g, - possible = /[&<>"'`=]/; - - function escapeChar(chr) { - return escape[chr]; - } - - function extend(obj /* , ...source */) { - for (var i = 1; i < arguments.length; i++) { - for (var key in arguments[i]) { - if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { - obj[key] = arguments[i][key]; - } - } - } - - return obj; - } - - var toString = Object.prototype.toString; - - exports.toString = toString; - // Sourced from lodash - // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt - /* eslint-disable func-style */ - var isFunction = function isFunction(value) { - return typeof value === 'function'; - }; - // fallback for older versions of Chrome and Safari - /* istanbul ignore next */ - if (isFunction(/x/)) { - exports.isFunction = isFunction = function (value) { - return typeof value === 'function' && toString.call(value) === '[object Function]'; - }; - } - exports.isFunction = isFunction; - - /* eslint-enable func-style */ - - /* istanbul ignore next */ - var isArray = Array.isArray || function (value) { - return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; - }; - - exports.isArray = isArray; - // Older IE versions do not directly support indexOf so we must implement our own, sadly. - - function indexOf(array, value) { - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === value) { - return i; - } - } - return -1; - } - - function escapeExpression(string) { - if (typeof string !== 'string') { - // don't escape SafeStrings, since they're already safe - if (string && string.toHTML) { - return string.toHTML(); - } else if (string == null) { - return ''; - } else if (!string) { - return string + ''; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = '' + string; - } - - if (!possible.test(string)) { - return string; - } - return string.replace(badChars, escapeChar); - } - - function isEmpty(value) { - if (!value && value !== 0) { - return true; - } else if (isArray(value) && value.length === 0) { - return true; - } else { - return false; - } - } - - function createFrame(object) { - var frame = extend({}, object); - frame._parent = object; - return frame; - } - - function blockParams(params, ids) { - params.path = ids; - return params; - } - - function appendContextPath(contextPath, id) { - return (contextPath ? contextPath + '.' : '') + id; - } - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _Object$defineProperty = __webpack_require__(7)['default']; - - exports.__esModule = true; - - var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - - function Exception(message, node) { - var loc = node && node.loc, - line = undefined, - column = undefined; - if (loc) { - line = loc.start.line; - column = loc.start.column; - - message += ' - ' + line + ':' + column; - } - - var tmp = Error.prototype.constructor.call(this, message); - - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } - - /* istanbul ignore else */ - if (Error.captureStackTrace) { - Error.captureStackTrace(this, Exception); - } - - try { - if (loc) { - this.lineNumber = line; - - // Work around issue under safari where we can't directly set the column value - /* istanbul ignore next */ - if (_Object$defineProperty) { - Object.defineProperty(this, 'column', { - value: column, - enumerable: true - }); - } else { - this.column = column; - } - } - } catch (nop) { - /* Ignore if the browser is very particular */ - } - } - - Exception.prototype = new Error(); - - exports['default'] = Exception; - module.exports = exports['default']; - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - module.exports = { "default": __webpack_require__(8), __esModule: true }; - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - - var $ = __webpack_require__(9); - module.exports = function defineProperty(it, key, desc){ - return $.setDesc(it, key, desc); - }; - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - var $Object = Object; - module.exports = { - create: $Object.create, - getProto: $Object.getPrototypeOf, - isEnum: {}.propertyIsEnumerable, - getDesc: $Object.getOwnPropertyDescriptor, - setDesc: $Object.defineProperty, - setDescs: $Object.defineProperties, - getKeys: $Object.keys, - getNames: $Object.getOwnPropertyNames, - getSymbols: $Object.getOwnPropertySymbols, - each: [].forEach - }; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.registerDefaultHelpers = registerDefaultHelpers; - - var _helpersBlockHelperMissing = __webpack_require__(11); - - var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); - - var _helpersEach = __webpack_require__(12); - - var _helpersEach2 = _interopRequireDefault(_helpersEach); - - var _helpersHelperMissing = __webpack_require__(13); - - var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); - - var _helpersIf = __webpack_require__(14); - - var _helpersIf2 = _interopRequireDefault(_helpersIf); - - var _helpersLog = __webpack_require__(15); - - var _helpersLog2 = _interopRequireDefault(_helpersLog); - - var _helpersLookup = __webpack_require__(16); - - var _helpersLookup2 = _interopRequireDefault(_helpersLookup); - - var _helpersWith = __webpack_require__(17); - - var _helpersWith2 = _interopRequireDefault(_helpersWith); - - function registerDefaultHelpers(instance) { - _helpersBlockHelperMissing2['default'](instance); - _helpersEach2['default'](instance); - _helpersHelperMissing2['default'](instance); - _helpersIf2['default'](instance); - _helpersLog2['default'](instance); - _helpersLookup2['default'](instance); - _helpersWith2['default'](instance); - } - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('blockHelperMissing', function (context, options) { - var inverse = options.inverse, - fn = options.fn; - - if (context === true) { - return fn(this); - } else if (context === false || context == null) { - return inverse(this); - } else if (_utils.isArray(context)) { - if (context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - - return instance.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - if (options.data && options.ids) { - var data = _utils.createFrame(options.data); - data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); - options = { data: data }; - } - - return fn(context, options); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - exports['default'] = function (instance) { - instance.registerHelper('each', function (context, options) { - if (!options) { - throw new _exception2['default']('Must pass iterator to #each'); - } - - var fn = options.fn, - inverse = options.inverse, - i = 0, - ret = '', - data = undefined, - contextPath = undefined; - - if (options.data && options.ids) { - contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } - - if (_utils.isFunction(context)) { - context = context.call(this); - } - - if (options.data) { - data = _utils.createFrame(options.data); - } - - function execIteration(field, index, last) { - if (data) { - data.key = field; - data.index = index; - data.first = index === 0; - data.last = !!last; - - if (contextPath) { - data.contextPath = contextPath + field; - } - } - - ret = ret + fn(context[field], { - data: data, - blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) - }); - } - - if (context && typeof context === 'object') { - if (_utils.isArray(context)) { - for (var j = context.length; i < j; i++) { - if (i in context) { - execIteration(i, i, i === context.length - 1); - } - } - } else { - var priorKey = undefined; - - for (var key in context) { - if (context.hasOwnProperty(key)) { - // We're running the iterations one step out of sync so we can detect - // the last iteration without have to scan the object twice and create - // an itermediate keys array. - if (priorKey !== undefined) { - execIteration(priorKey, i - 1); - } - priorKey = key; - i++; - } - } - if (priorKey !== undefined) { - execIteration(priorKey, i - 1, true); - } - } - } - - if (i === 0) { - ret = inverse(this); - } - - return ret; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - exports['default'] = function (instance) { - instance.registerHelper('helperMissing', function () /* [args, ]options */{ - if (arguments.length === 1) { - // A missing field in a {{foo}} construct. - return undefined; - } else { - // Someone is actually trying to call something, blow up. - throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('if', function (conditional, options) { - if (_utils.isFunction(conditional)) { - conditional = conditional.call(this); - } - - // Default behavior is to render the positive path if the value is truthy and not empty. - // The `includeZero` option may be set to treat the condtional as purely not empty based on the - // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. - if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { - return options.inverse(this); - } else { - return options.fn(this); - } - }); - - instance.registerHelper('unless', function (conditional, options) { - return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash }); - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (instance) { - instance.registerHelper('log', function () /* message, options */{ - var args = [undefined], - options = arguments[arguments.length - 1]; - for (var i = 0; i < arguments.length - 1; i++) { - args.push(arguments[i]); - } - - var level = 1; - if (options.hash.level != null) { - level = options.hash.level; - } else if (options.data && options.data.level != null) { - level = options.data.level; - } - args[0] = level; - - instance.log.apply(instance, args); - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (instance) { - instance.registerHelper('lookup', function (obj, field) { - return obj && obj[field]; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('with', function (context, options) { - if (_utils.isFunction(context)) { - context = context.call(this); - } - - var fn = options.fn; - - if (!_utils.isEmpty(context)) { - var data = options.data; - if (options.data && options.ids) { - data = _utils.createFrame(options.data); - data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); - } - - return fn(context, { - data: data, - blockParams: _utils.blockParams([context], [data && data.contextPath]) - }); - } else { - return options.inverse(this); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.registerDefaultDecorators = registerDefaultDecorators; - - var _decoratorsInline = __webpack_require__(19); - - var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); - - function registerDefaultDecorators(instance) { - _decoratorsInline2['default'](instance); - } - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerDecorator('inline', function (fn, props, container, options) { - var ret = fn; - if (!props.partials) { - props.partials = {}; - ret = function (context, options) { - // Create a new partials stack frame prior to exec. - var original = container.partials; - container.partials = _utils.extend({}, original, props.partials); - var ret = fn(context, options); - container.partials = original; - return ret; - }; - } - - props.partials[options.args[0]] = options.fn; - - return ret; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var logger = { - methodMap: ['debug', 'info', 'warn', 'error'], - level: 'info', - - // Maps a given level value to the `methodMap` indexes above. - lookupLevel: function lookupLevel(level) { - if (typeof level === 'string') { - var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); - if (levelMap >= 0) { - level = levelMap; - } else { - level = parseInt(level, 10); - } - } - - return level; - }, - - // Can be overridden in the host environment - log: function log(level) { - level = logger.lookupLevel(level); - - if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { - var method = logger.methodMap[level]; - if (!console[method]) { - // eslint-disable-line no-console - method = 'log'; - } - - for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - message[_key - 1] = arguments[_key]; - } - - console[method].apply(console, message); // eslint-disable-line no-console - } - } - }; - - exports['default'] = logger; - module.exports = exports['default']; - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - - // Build out our basic SafeString type - 'use strict'; - - exports.__esModule = true; - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = SafeString.prototype.toHTML = function () { - return '' + this.string; - }; - - exports['default'] = SafeString; - module.exports = exports['default']; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _Object$seal = __webpack_require__(23)['default']; - - var _interopRequireWildcard = __webpack_require__(3)['default']; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.checkRevision = checkRevision; - exports.template = template; - exports.wrapProgram = wrapProgram; - exports.resolvePartial = resolvePartial; - exports.invokePartial = invokePartial; - exports.noop = noop; - - var _utils = __webpack_require__(5); - - var Utils = _interopRequireWildcard(_utils); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _base = __webpack_require__(4); - - function checkRevision(compilerInfo) { - var compilerRevision = compilerInfo && compilerInfo[0] || 1, - currentRevision = _base.COMPILER_REVISION; - - if (compilerRevision !== currentRevision) { - if (compilerRevision < currentRevision) { - var runtimeVersions = _base.REVISION_CHANGES[currentRevision], - compilerVersions = _base.REVISION_CHANGES[compilerRevision]; - throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); - } else { - // Use the embedded version info since the runtime doesn't know about this revision yet - throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); - } - } - } - - function template(templateSpec, env) { - /* istanbul ignore next */ - if (!env) { - throw new _exception2['default']('No environment passed to template'); - } - if (!templateSpec || !templateSpec.main) { - throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); - } - - templateSpec.main.decorator = templateSpec.main_d; - - // Note: Using env.VM references rather than local var references throughout this section to allow - // for external users to override these as psuedo-supported APIs. - env.VM.checkRevision(templateSpec.compiler); - - function invokePartialWrapper(partial, context, options) { - if (options.hash) { - context = Utils.extend({}, context, options.hash); - if (options.ids) { - options.ids[0] = true; - } - } - - partial = env.VM.resolvePartial.call(this, partial, context, options); - var result = env.VM.invokePartial.call(this, partial, context, options); - - if (result == null && env.compile) { - options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); - result = options.partials[options.name](context, options); - } - if (result != null) { - if (options.indent) { - var lines = result.split('\n'); - for (var i = 0, l = lines.length; i < l; i++) { - if (!lines[i] && i + 1 === l) { - break; - } - - lines[i] = options.indent + lines[i]; - } - result = lines.join('\n'); - } - return result; - } else { - throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); - } - } - - // Just add water - var container = { - strict: function strict(obj, name) { - if (!(name in obj)) { - throw new _exception2['default']('"' + name + '" not defined in ' + obj); - } - return obj[name]; - }, - lookup: function lookup(depths, name) { - var len = depths.length; - for (var i = 0; i < len; i++) { - if (depths[i] && depths[i][name] != null) { - return depths[i][name]; - } - } - }, - lambda: function lambda(current, context) { - return typeof current === 'function' ? current.call(context) : current; - }, - - escapeExpression: Utils.escapeExpression, - invokePartial: invokePartialWrapper, - - fn: function fn(i) { - var ret = templateSpec[i]; - ret.decorator = templateSpec[i + '_d']; - return ret; - }, - - programs: [], - program: function program(i, data, declaredBlockParams, blockParams, depths) { - var programWrapper = this.programs[i], - fn = this.fn(i); - if (data || depths || blockParams || declaredBlockParams) { - programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); - } else if (!programWrapper) { - programWrapper = this.programs[i] = wrapProgram(this, i, fn); - } - return programWrapper; - }, - - data: function data(value, depth) { - while (value && depth--) { - value = value._parent; - } - return value; - }, - merge: function merge(param, common) { - var obj = param || common; - - if (param && common && param !== common) { - obj = Utils.extend({}, common, param); - } - - return obj; - }, - // An empty object to use as replacement for null-contexts - nullContext: _Object$seal({}), - - noop: env.VM.noop, - compilerInfo: templateSpec.compiler - }; - - function ret(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var data = options.data; - - ret._setup(options); - if (!options.partial && templateSpec.useData) { - data = initData(context, data); - } - var depths = undefined, - blockParams = templateSpec.useBlockParams ? [] : undefined; - if (templateSpec.useDepths) { - if (options.depths) { - depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; - } else { - depths = [context]; - } - } - - function main(context /*, options*/) { - return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); - } - main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); - return main(context, options); - } - ret.isTop = true; - - ret._setup = function (options) { - if (!options.partial) { - container.helpers = container.merge(options.helpers, env.helpers); - - if (templateSpec.usePartial) { - container.partials = container.merge(options.partials, env.partials); - } - if (templateSpec.usePartial || templateSpec.useDecorators) { - container.decorators = container.merge(options.decorators, env.decorators); - } - } else { - container.helpers = options.helpers; - container.partials = options.partials; - container.decorators = options.decorators; - } - }; - - ret._child = function (i, data, blockParams, depths) { - if (templateSpec.useBlockParams && !blockParams) { - throw new _exception2['default']('must pass block params'); - } - if (templateSpec.useDepths && !depths) { - throw new _exception2['default']('must pass parent depths'); - } - - return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); - }; - return ret; - } - - function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { - function prog(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var currentDepths = depths; - if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { - currentDepths = [context].concat(depths); - } - - return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); - } - - prog = executeDecorators(fn, prog, container, depths, data, blockParams); - - prog.program = i; - prog.depth = depths ? depths.length : 0; - prog.blockParams = declaredBlockParams || 0; - return prog; - } - - function resolvePartial(partial, context, options) { - if (!partial) { - if (options.name === '@partial-block') { - partial = options.data['partial-block']; - } else { - partial = options.partials[options.name]; - } - } else if (!partial.call && !options.name) { - // This is a dynamic partial that returned a string - options.name = partial; - partial = options.partials[partial]; - } - return partial; - } - - function invokePartial(partial, context, options) { - // Use the current closure context to save the partial-block if this partial - var currentPartialBlock = options.data && options.data['partial-block']; - options.partial = true; - if (options.ids) { - options.data.contextPath = options.ids[0] || options.data.contextPath; - } - - var partialBlock = undefined; - if (options.fn && options.fn !== noop) { - (function () { - options.data = _base.createFrame(options.data); - // Wrapper function to get access to currentPartialBlock from the closure - var fn = options.fn; - partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - // Restore the partial-block from the closure for the execution of the block - // i.e. the part inside the block of the partial call. - options.data = _base.createFrame(options.data); - options.data['partial-block'] = currentPartialBlock; - return fn(context, options); - }; - if (fn.partials) { - options.partials = Utils.extend({}, options.partials, fn.partials); - } - })(); - } - - if (partial === undefined && partialBlock) { - partial = partialBlock; - } - - if (partial === undefined) { - throw new _exception2['default']('The partial ' + options.name + ' could not be found'); - } else if (partial instanceof Function) { - return partial(context, options); - } - } - - function noop() { - return ''; - } - - function initData(context, data) { - if (!data || !('root' in data)) { - data = data ? _base.createFrame(data) : {}; - data.root = context; - } - return data; - } - - function executeDecorators(fn, prog, container, depths, data, blockParams) { - if (fn.decorator) { - var props = {}; - prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); - Utils.extend(prog, props); - } - return prog; - } - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - - module.exports = { "default": __webpack_require__(24), __esModule: true }; - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - - __webpack_require__(25); - module.exports = __webpack_require__(30).Object.seal; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - - // 19.1.2.17 Object.seal(O) - var isObject = __webpack_require__(26); - - __webpack_require__(27)('seal', function($seal){ - return function seal(it){ - return $seal && isObject(it) ? $seal(it) : it; - }; - }); - -/***/ }), -/* 26 */ -/***/ (function(module, exports) { - - module.exports = function(it){ - return typeof it === 'object' ? it !== null : typeof it === 'function'; - }; - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - - // most Object methods by ES6 should accept primitives - var $export = __webpack_require__(28) - , core = __webpack_require__(30) - , fails = __webpack_require__(33); - module.exports = function(KEY, exec){ - var fn = (core.Object || {})[KEY] || Object[KEY] - , exp = {}; - exp[KEY] = exec(fn); - $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); - }; - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - - var global = __webpack_require__(29) - , core = __webpack_require__(30) - , ctx = __webpack_require__(31) - , PROTOTYPE = 'prototype'; - - var $export = function(type, name, source){ - var IS_FORCED = type & $export.F - , IS_GLOBAL = type & $export.G - , IS_STATIC = type & $export.S - , IS_PROTO = type & $export.P - , IS_BIND = type & $export.B - , IS_WRAP = type & $export.W - , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) - , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] - , key, own, out; - if(IS_GLOBAL)source = name; - for(key in source){ - // contains in native - own = !IS_FORCED && target && key in target; - if(own && key in exports)continue; - // export native or passed - out = own ? target[key] : source[key]; - // prevent global pollution for namespaces - exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] - // bind timers to global for call from export context - : IS_BIND && own ? ctx(out, global) - // wrap global constructors for prevent change them in library - : IS_WRAP && target[key] == out ? (function(C){ - var F = function(param){ - return this instanceof C ? new C(param) : C(param); - }; - F[PROTOTYPE] = C[PROTOTYPE]; - return F; - // make static versions for prototype methods - })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; - if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; - } - }; - // type bitmap - $export.F = 1; // forced - $export.G = 2; // global - $export.S = 4; // static - $export.P = 8; // proto - $export.B = 16; // bind - $export.W = 32; // wrap - module.exports = $export; - -/***/ }), -/* 29 */ -/***/ (function(module, exports) { - - // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 - var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); - if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef - -/***/ }), -/* 30 */ -/***/ (function(module, exports) { - - var core = module.exports = {version: '1.2.6'}; - if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef - -/***/ }), -/* 31 */ -/***/ (function(module, exports, __webpack_require__) { - - // optional / simple context binding - var aFunction = __webpack_require__(32); - module.exports = function(fn, that, length){ - aFunction(fn); - if(that === undefined)return fn; - switch(length){ - case 1: return function(a){ - return fn.call(that, a); - }; - case 2: return function(a, b){ - return fn.call(that, a, b); - }; - case 3: return function(a, b, c){ - return fn.call(that, a, b, c); - }; - } - return function(/* ...args */){ - return fn.apply(that, arguments); - }; - }; - -/***/ }), -/* 32 */ -/***/ (function(module, exports) { - - module.exports = function(it){ - if(typeof it != 'function')throw TypeError(it + ' is not a function!'); - return it; - }; - -/***/ }), -/* 33 */ -/***/ (function(module, exports) { - - module.exports = function(exec){ - try { - return !!exec(); - } catch(e){ - return true; - } - }; - -/***/ }), -/* 34 */ -/***/ (function(module, exports) { - - /* WEBPACK VAR INJECTION */(function(global) {/* global window */ - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (Handlebars) { - /* istanbul ignore next */ - var root = typeof global !== 'undefined' ? global : window, - $Handlebars = root.Handlebars; - /* istanbul ignore next */ - Handlebars.noConflict = function () { - if (root.Handlebars === Handlebars) { - root.Handlebars = $Handlebars; - } - return Handlebars; - }; - }; - - module.exports = exports['default']; - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - -/***/ }), -/* 35 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - var AST = { - // Public API used to evaluate derived attributes regarding AST nodes - helpers: { - // a mustache is definitely a helper if: - // * it is an eligible helper, and - // * it has at least one parameter or hash segment - helperExpression: function helperExpression(node) { - return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash); - }, - - scopedId: function scopedId(path) { - return (/^\.|this\b/.test(path.original) - ); - }, - - // an ID is simple if it only has one part, and that part is not - // `..` or `this`. - simpleId: function simpleId(path) { - return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; - } - } - }; - - // Must be exported as an object rather than the root of the module as the jison lexer - // must modify the object to operate properly. - exports['default'] = AST; - module.exports = exports['default']; - -/***/ }), -/* 36 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - var _interopRequireWildcard = __webpack_require__(3)['default']; - - exports.__esModule = true; - exports.parse = parse; - - var _parser = __webpack_require__(37); - - var _parser2 = _interopRequireDefault(_parser); - - var _whitespaceControl = __webpack_require__(38); - - var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl); - - var _helpers = __webpack_require__(40); - - var Helpers = _interopRequireWildcard(_helpers); - - var _utils = __webpack_require__(5); - - exports.parser = _parser2['default']; - - var yy = {}; - _utils.extend(yy, Helpers); - - function parse(input, options) { - // Just return if an already-compiled AST was passed in. - if (input.type === 'Program') { - return input; - } - - _parser2['default'].yy = yy; - - // Altering the shared object here, but this is ok as parser is a sync operation - yy.locInfo = function (locInfo) { - return new yy.SourceLocation(options && options.srcName, locInfo); - }; - - var strip = new _whitespaceControl2['default'](options); - return strip.accept(_parser2['default'].parse(input)); - } - -/***/ }), -/* 37 */ -/***/ (function(module, exports) { - - // File ignored in coverage tests via setting in .istanbul.yml - /* Jison generated parser */ - "use strict"; - - exports.__esModule = true; - var handlebars = (function () { - var parser = { trace: function trace() {}, - yy: {}, - symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition_plus0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 }, - terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" }, - productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 1], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$ - /**/) { - - var $0 = $$.length - 1; - switch (yystate) { - case 1: - return $$[$0 - 1]; - break; - case 2: - this.$ = yy.prepareProgram($$[$0]); - break; - case 3: - this.$ = $$[$0]; - break; - case 4: - this.$ = $$[$0]; - break; - case 5: - this.$ = $$[$0]; - break; - case 6: - this.$ = $$[$0]; - break; - case 7: - this.$ = $$[$0]; - break; - case 8: - this.$ = $$[$0]; - break; - case 9: - this.$ = { - type: 'CommentStatement', - value: yy.stripComment($$[$0]), - strip: yy.stripFlags($$[$0], $$[$0]), - loc: yy.locInfo(this._$) - }; - - break; - case 10: - this.$ = { - type: 'ContentStatement', - original: $$[$0], - value: $$[$0], - loc: yy.locInfo(this._$) - }; - - break; - case 11: - this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); - break; - case 12: - this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] }; - break; - case 13: - this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$); - break; - case 14: - this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$); - break; - case 15: - this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 16: - this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 17: - this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 18: - this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] }; - break; - case 19: - var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$), - program = yy.prepareProgram([inverse], $$[$0 - 1].loc); - program.chained = true; - - this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true }; - - break; - case 20: - this.$ = $$[$0]; - break; - case 21: - this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) }; - break; - case 22: - this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); - break; - case 23: - this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); - break; - case 24: - this.$ = { - type: 'PartialStatement', - name: $$[$0 - 3], - params: $$[$0 - 2], - hash: $$[$0 - 1], - indent: '', - strip: yy.stripFlags($$[$0 - 4], $$[$0]), - loc: yy.locInfo(this._$) - }; - - break; - case 25: - this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); - break; - case 26: - this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) }; - break; - case 27: - this.$ = $$[$0]; - break; - case 28: - this.$ = $$[$0]; - break; - case 29: - this.$ = { - type: 'SubExpression', - path: $$[$0 - 3], - params: $$[$0 - 2], - hash: $$[$0 - 1], - loc: yy.locInfo(this._$) - }; - - break; - case 30: - this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 31: - this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 32: - this.$ = yy.id($$[$0 - 1]); - break; - case 33: - this.$ = $$[$0]; - break; - case 34: - this.$ = $$[$0]; - break; - case 35: - this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 36: - this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) }; - break; - case 37: - this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) }; - break; - case 38: - this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) }; - break; - case 39: - this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) }; - break; - case 40: - this.$ = $$[$0]; - break; - case 41: - this.$ = $$[$0]; - break; - case 42: - this.$ = yy.preparePath(true, $$[$0], this._$); - break; - case 43: - this.$ = yy.preparePath(false, $$[$0], this._$); - break; - case 44: - $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2]; - break; - case 45: - this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }]; - break; - case 46: - this.$ = []; - break; - case 47: - $$[$0 - 1].push($$[$0]); - break; - case 48: - this.$ = [$$[$0]]; - break; - case 49: - $$[$0 - 1].push($$[$0]); - break; - case 50: - this.$ = []; - break; - case 51: - $$[$0 - 1].push($$[$0]); - break; - case 58: - this.$ = []; - break; - case 59: - $$[$0 - 1].push($$[$0]); - break; - case 64: - this.$ = []; - break; - case 65: - $$[$0 - 1].push($$[$0]); - break; - case 70: - this.$ = []; - break; - case 71: - $$[$0 - 1].push($$[$0]); - break; - case 78: - this.$ = []; - break; - case 79: - $$[$0 - 1].push($$[$0]); - break; - case 82: - this.$ = []; - break; - case 83: - $$[$0 - 1].push($$[$0]); - break; - case 86: - this.$ = []; - break; - case 87: - $$[$0 - 1].push($$[$0]); - break; - case 90: - this.$ = []; - break; - case 91: - $$[$0 - 1].push($$[$0]); - break; - case 94: - this.$ = []; - break; - case 95: - $$[$0 - 1].push($$[$0]); - break; - case 98: - this.$ = [$$[$0]]; - break; - case 99: - $$[$0 - 1].push($$[$0]); - break; - case 100: - this.$ = [$$[$0]]; - break; - case 101: - $$[$0 - 1].push($$[$0]); - break; - } - }, - table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 13: 40, 15: [1, 20], 17: 39 }, { 20: 42, 56: 41, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 45, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 48, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 42, 56: 49, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 50, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 51] }, { 72: [1, 35], 86: 52 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 53, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 54, 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 55, 47: [2, 54] }, { 28: 60, 43: 61, 44: [1, 59], 47: [2, 56] }, { 13: 63, 15: [1, 20], 18: [1, 62] }, { 15: [2, 48], 18: [2, 48] }, { 33: [2, 86], 57: 64, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 65, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 66, 47: [1, 67] }, { 30: 68, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 69, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 70, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 71, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 75, 33: [2, 80], 50: 72, 63: 73, 64: 76, 65: [1, 44], 69: 74, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 80] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 51] }, { 20: 75, 53: 81, 54: [2, 84], 63: 82, 64: 76, 65: [1, 44], 69: 83, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 84, 47: [1, 67] }, { 47: [2, 55] }, { 4: 85, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 86, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 87, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 88, 47: [1, 67] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 75, 33: [2, 88], 58: 89, 63: 90, 64: 76, 65: [1, 44], 69: 91, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 92, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 93, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 31: 94, 33: [2, 60], 63: 95, 64: 76, 65: [1, 44], 69: 96, 70: 77, 71: 78, 72: [1, 79], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 66], 36: 97, 63: 98, 64: 76, 65: [1, 44], 69: 99, 70: 77, 71: 78, 72: [1, 79], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 22: 100, 23: [2, 52], 63: 101, 64: 76, 65: [1, 44], 69: 102, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 92], 62: 103, 63: 104, 64: 76, 65: [1, 44], 69: 105, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 106] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 107, 72: [1, 108], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 109], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 110] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 112, 46: 111, 47: [2, 76] }, { 33: [2, 70], 40: 113, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 114] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 75, 63: 116, 64: 76, 65: [1, 44], 67: 115, 68: [2, 96], 69: 117, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 118] }, { 32: 119, 33: [2, 62], 74: 120, 75: [1, 121] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 122, 74: 123, 75: [1, 121] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 124] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 125] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 109] }, { 20: 75, 63: 126, 64: 76, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 75, 33: [2, 72], 41: 127, 63: 128, 64: 76, 65: [1, 44], 69: 129, 70: 77, 71: 78, 72: [1, 79], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 130] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 131] }, { 33: [2, 63] }, { 72: [1, 133], 76: 132 }, { 33: [1, 134] }, { 33: [2, 69] }, { 15: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 135, 74: 136, 75: [1, 121] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 138], 77: [1, 137] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 139] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }], - defaultActions: { 4: [2, 1], 55: [2, 55], 57: [2, 20], 61: [2, 57], 74: [2, 81], 83: [2, 85], 87: [2, 18], 91: [2, 89], 102: [2, 53], 105: [2, 93], 111: [2, 19], 112: [2, 77], 117: [2, 97], 120: [2, 63], 123: [2, 69], 124: [2, 12], 136: [2, 75], 137: [2, 32] }, - parseError: function parseError(str, hash) { - throw new Error(str); - }, - parse: function parse(input) { - var self = this, - stack = [0], - vstack = [null], - lstack = [], - table = this.table, - yytext = "", - yylineno = 0, - yyleng = 0, - recovering = 0, - TERROR = 2, - EOF = 1; - this.lexer.setInput(input); - this.lexer.yy = this.yy; - this.yy.lexer = this.lexer; - this.yy.parser = this; - if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {}; - var yyloc = this.lexer.yylloc; - lstack.push(yyloc); - var ranges = this.lexer.options && this.lexer.options.ranges; - if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError; - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - function lex() { - var token; - token = self.lexer.lex() || 1; - if (typeof token !== "number") { - token = self.symbols_[token] || token; - } - return token; - } - var symbol, - preErrorSymbol, - state, - action, - a, - r, - yyval = {}, - p, - len, - newState, - expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == "undefined") { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === "undefined" || !action.length || !action[0]) { - var errStr = ""; - if (!recovering) { - expected = []; - for (p in table[state]) if (this.terminals_[p] && p > 2) { - expected.push("'" + this.terminals_[p] + "'"); - } - if (this.lexer.showPosition) { - errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; - } else { - errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); - } - this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected }); - } - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(this.lexer.yytext); - lstack.push(this.lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - if (recovering > 0) recovering--; - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column }; - if (ranges) { - yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; - } - r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); - if (typeof r !== "undefined") { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; - } - }; - /* Jison generated lexer */ - var lexer = (function () { - var lexer = { EOF: 1, - parseError: function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - setInput: function setInput(input) { - this._input = input; - this._more = this._less = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 }; - if (this.options.ranges) this.yylloc.range = [0, 0]; - this.offset = 0; - return this; - }, - input: function input() { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) this.yylloc.range[1]++; - - this._input = this._input.slice(1); - return ch; - }, - unput: function unput(ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) this.yylineno -= lines.length - 1; - var r = this.yylloc.range; - - this.yylloc = { first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - return this; - }, - more: function more() { - this._more = true; - return this; - }, - less: function less(n) { - this.unput(this.match.slice(n)); - }, - pastInput: function pastInput() { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); - }, - upcomingInput: function upcomingInput() { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20 - next.length); - } - return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - showPosition: function showPosition() { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - next: function next() { - if (this.done) { - return this.EOF; - } - if (!this._input) this.done = true; - - var token, match, tempMatch, index, col, lines; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (!this.options.flex) break; - } - } - if (match) { - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) this.yylineno += lines.length; - this.yylloc = { first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) this.done = false; - if (token) return token;else return; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno }); - } - }, - lex: function lex() { - var r = this.next(); - if (typeof r !== 'undefined') { - return r; - } else { - return this.lex(); - } - }, - begin: function begin(condition) { - this.conditionStack.push(condition); - }, - popState: function popState() { - return this.conditionStack.pop(); - }, - _currentRules: function _currentRules() { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - }, - topState: function topState() { - return this.conditionStack[this.conditionStack.length - 2]; - }, - pushState: function begin(condition) { - this.begin(condition); - } }; - lexer.options = {}; - lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START - /**/) { - - function strip(start, end) { - return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng - end); - } - - var YYSTATE = YY_START; - switch ($avoiding_name_collisions) { - case 0: - if (yy_.yytext.slice(-2) === "\\\\") { - strip(0, 1); - this.begin("mu"); - } else if (yy_.yytext.slice(-1) === "\\") { - strip(0, 1); - this.begin("emu"); - } else { - this.begin("mu"); - } - if (yy_.yytext) return 15; - - break; - case 1: - return 15; - break; - case 2: - this.popState(); - return 15; - - break; - case 3: - this.begin('raw');return 15; - break; - case 4: - this.popState(); - // Should be using `this.topState()` below, but it currently - // returns the second top instead of the first top. Opened an - // issue about it at https://github.com/zaach/jison/issues/291 - if (this.conditionStack[this.conditionStack.length - 1] === 'raw') { - return 15; - } else { - yy_.yytext = yy_.yytext.substr(5, yy_.yyleng - 9); - return 'END_RAW_BLOCK'; - } - - break; - case 5: - return 15; - break; - case 6: - this.popState(); - return 14; - - break; - case 7: - return 65; - break; - case 8: - return 68; - break; - case 9: - return 19; - break; - case 10: - this.popState(); - this.begin('raw'); - return 23; - - break; - case 11: - return 55; - break; - case 12: - return 60; - break; - case 13: - return 29; - break; - case 14: - return 47; - break; - case 15: - this.popState();return 44; - break; - case 16: - this.popState();return 44; - break; - case 17: - return 34; - break; - case 18: - return 39; - break; - case 19: - return 51; - break; - case 20: - return 48; - break; - case 21: - this.unput(yy_.yytext); - this.popState(); - this.begin('com'); - - break; - case 22: - this.popState(); - return 14; - - break; - case 23: - return 48; - break; - case 24: - return 73; - break; - case 25: - return 72; - break; - case 26: - return 72; - break; - case 27: - return 87; - break; - case 28: - // ignore whitespace - break; - case 29: - this.popState();return 54; - break; - case 30: - this.popState();return 33; - break; - case 31: - yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80; - break; - case 32: - yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80; - break; - case 33: - return 85; - break; - case 34: - return 82; - break; - case 35: - return 82; - break; - case 36: - return 83; - break; - case 37: - return 84; - break; - case 38: - return 81; - break; - case 39: - return 75; - break; - case 40: - return 77; - break; - case 41: - return 72; - break; - case 42: - yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72; - break; - case 43: - return 'INVALID'; - break; - case 44: - return 5; - break; - } - }; - lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^\/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]*?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/]; - lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } }; - return lexer; - })(); - parser.lexer = lexer; - function Parser() { - this.yy = {}; - }Parser.prototype = parser;parser.Parser = Parser; - return new Parser(); - })();exports["default"] = handlebars; - module.exports = exports["default"]; - -/***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _visitor = __webpack_require__(39); - - var _visitor2 = _interopRequireDefault(_visitor); - - function WhitespaceControl() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - this.options = options; - } - WhitespaceControl.prototype = new _visitor2['default'](); - - WhitespaceControl.prototype.Program = function (program) { - var doStandalone = !this.options.ignoreStandalone; - - var isRoot = !this.isRootSeen; - this.isRootSeen = true; - - var body = program.body; - for (var i = 0, l = body.length; i < l; i++) { - var current = body[i], - strip = this.accept(current); - - if (!strip) { - continue; - } - - var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), - _isNextWhitespace = isNextWhitespace(body, i, isRoot), - openStandalone = strip.openStandalone && _isPrevWhitespace, - closeStandalone = strip.closeStandalone && _isNextWhitespace, - inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; - - if (strip.close) { - omitRight(body, i, true); - } - if (strip.open) { - omitLeft(body, i, true); - } - - if (doStandalone && inlineStandalone) { - omitRight(body, i); - - if (omitLeft(body, i)) { - // If we are on a standalone node, save the indent info for partials - if (current.type === 'PartialStatement') { - // Pull out the whitespace from the final line - current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1]; - } - } - } - if (doStandalone && openStandalone) { - omitRight((current.program || current.inverse).body); - - // Strip out the previous content node if it's whitespace only - omitLeft(body, i); - } - if (doStandalone && closeStandalone) { - // Always strip the next node - omitRight(body, i); - - omitLeft((current.inverse || current.program).body); - } - } - - return program; - }; - - WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) { - this.accept(block.program); - this.accept(block.inverse); - - // Find the inverse program that is involed with whitespace stripping. - var program = block.program || block.inverse, - inverse = block.program && block.inverse, - firstInverse = inverse, - lastInverse = inverse; - - if (inverse && inverse.chained) { - firstInverse = inverse.body[0].program; - - // Walk the inverse chain to find the last inverse that is actually in the chain. - while (lastInverse.chained) { - lastInverse = lastInverse.body[lastInverse.body.length - 1].program; - } - } - - var strip = { - open: block.openStrip.open, - close: block.closeStrip.close, - - // Determine the standalone candiacy. Basically flag our content as being possibly standalone - // so our parent can determine if we actually are standalone - openStandalone: isNextWhitespace(program.body), - closeStandalone: isPrevWhitespace((firstInverse || program).body) - }; - - if (block.openStrip.close) { - omitRight(program.body, null, true); - } - - if (inverse) { - var inverseStrip = block.inverseStrip; - - if (inverseStrip.open) { - omitLeft(program.body, null, true); - } - - if (inverseStrip.close) { - omitRight(firstInverse.body, null, true); - } - if (block.closeStrip.open) { - omitLeft(lastInverse.body, null, true); - } - - // Find standalone else statments - if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { - omitLeft(program.body); - omitRight(firstInverse.body); - } - } else if (block.closeStrip.open) { - omitLeft(program.body, null, true); - } - - return strip; - }; - - WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) { - return mustache.strip; - }; - - WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) { - /* istanbul ignore next */ - var strip = node.strip || {}; - return { - inlineStandalone: true, - open: strip.open, - close: strip.close - }; - }; - - function isPrevWhitespace(body, i, isRoot) { - if (i === undefined) { - i = body.length; - } - - // Nodes that end with newlines are considered whitespace (but are special - // cased for strip operations) - var prev = body[i - 1], - sibling = body[i - 2]; - if (!prev) { - return isRoot; - } - - if (prev.type === 'ContentStatement') { - return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original); - } - } - function isNextWhitespace(body, i, isRoot) { - if (i === undefined) { - i = -1; - } - - var next = body[i + 1], - sibling = body[i + 2]; - if (!next) { - return isRoot; - } - - if (next.type === 'ContentStatement') { - return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original); - } - } - - // Marks the node to the right of the position as omitted. - // I.e. {{foo}}' ' will mark the ' ' node as omitted. - // - // If i is undefined, then the first child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitRight(body, i, multiple) { - var current = body[i == null ? 0 : i + 1]; - if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) { - return; - } - - var original = current.value; - current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, ''); - current.rightStripped = current.value !== original; - } - - // Marks the node to the left of the position as omitted. - // I.e. ' '{{foo}} will mark the ' ' node as omitted. - // - // If i is undefined then the last child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitLeft(body, i, multiple) { - var current = body[i == null ? body.length - 1 : i - 1]; - if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) { - return; - } - - // We omit the last node if it's whitespace only and not preceeded by a non-content node. - var original = current.value; - current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, ''); - current.leftStripped = current.value !== original; - return current.leftStripped; - } - - exports['default'] = WhitespaceControl; - module.exports = exports['default']; - -/***/ }), -/* 39 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - function Visitor() { - this.parents = []; - } - - Visitor.prototype = { - constructor: Visitor, - mutating: false, - - // Visits a given value. If mutating, will replace the value if necessary. - acceptKey: function acceptKey(node, name) { - var value = this.accept(node[name]); - if (this.mutating) { - // Hacky sanity check: This may have a few false positives for type for the helper - // methods but will generally do the right thing without a lot of overhead. - if (value && !Visitor.prototype[value.type]) { - throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); - } - node[name] = value; - } - }, - - // Performs an accept operation with added sanity check to ensure - // required keys are not removed. - acceptRequired: function acceptRequired(node, name) { - this.acceptKey(node, name); - - if (!node[name]) { - throw new _exception2['default'](node.type + ' requires ' + name); - } - }, - - // Traverses a given array. If mutating, empty respnses will be removed - // for child elements. - acceptArray: function acceptArray(array) { - for (var i = 0, l = array.length; i < l; i++) { - this.acceptKey(array, i); - - if (!array[i]) { - array.splice(i, 1); - i--; - l--; - } - } - }, - - accept: function accept(object) { - if (!object) { - return; - } - - /* istanbul ignore next: Sanity code */ - if (!this[object.type]) { - throw new _exception2['default']('Unknown type: ' + object.type, object); - } - - if (this.current) { - this.parents.unshift(this.current); - } - this.current = object; - - var ret = this[object.type](object); - - this.current = this.parents.shift(); - - if (!this.mutating || ret) { - return ret; - } else if (ret !== false) { - return object; - } - }, - - Program: function Program(program) { - this.acceptArray(program.body); - }, - - MustacheStatement: visitSubExpression, - Decorator: visitSubExpression, - - BlockStatement: visitBlock, - DecoratorBlock: visitBlock, - - PartialStatement: visitPartial, - PartialBlockStatement: function PartialBlockStatement(partial) { - visitPartial.call(this, partial); - - this.acceptKey(partial, 'program'); - }, - - ContentStatement: function ContentStatement() /* content */{}, - CommentStatement: function CommentStatement() /* comment */{}, - - SubExpression: visitSubExpression, - - PathExpression: function PathExpression() /* path */{}, - - StringLiteral: function StringLiteral() /* string */{}, - NumberLiteral: function NumberLiteral() /* number */{}, - BooleanLiteral: function BooleanLiteral() /* bool */{}, - UndefinedLiteral: function UndefinedLiteral() /* literal */{}, - NullLiteral: function NullLiteral() /* literal */{}, - - Hash: function Hash(hash) { - this.acceptArray(hash.pairs); - }, - HashPair: function HashPair(pair) { - this.acceptRequired(pair, 'value'); - } - }; - - function visitSubExpression(mustache) { - this.acceptRequired(mustache, 'path'); - this.acceptArray(mustache.params); - this.acceptKey(mustache, 'hash'); - } - function visitBlock(block) { - visitSubExpression.call(this, block); - - this.acceptKey(block, 'program'); - this.acceptKey(block, 'inverse'); - } - function visitPartial(partial) { - this.acceptRequired(partial, 'name'); - this.acceptArray(partial.params); - this.acceptKey(partial, 'hash'); - } - - exports['default'] = Visitor; - module.exports = exports['default']; - -/***/ }), -/* 40 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.SourceLocation = SourceLocation; - exports.id = id; - exports.stripFlags = stripFlags; - exports.stripComment = stripComment; - exports.preparePath = preparePath; - exports.prepareMustache = prepareMustache; - exports.prepareRawBlock = prepareRawBlock; - exports.prepareBlock = prepareBlock; - exports.prepareProgram = prepareProgram; - exports.preparePartialBlock = preparePartialBlock; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - function validateClose(open, close) { - close = close.path ? close.path.original : close; - - if (open.path.original !== close) { - var errorNode = { loc: open.path.loc }; - - throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode); - } - } - - function SourceLocation(source, locInfo) { - this.source = source; - this.start = { - line: locInfo.first_line, - column: locInfo.first_column - }; - this.end = { - line: locInfo.last_line, - column: locInfo.last_column - }; - } - - function id(token) { - if (/^\[.*\]$/.test(token)) { - return token.substr(1, token.length - 2); - } else { - return token; - } - } - - function stripFlags(open, close) { - return { - open: open.charAt(2) === '~', - close: close.charAt(close.length - 3) === '~' - }; - } - - function stripComment(comment) { - return comment.replace(/^\{\{~?\!-?-?/, '').replace(/-?-?~?\}\}$/, ''); - } - - function preparePath(data, parts, loc) { - loc = this.locInfo(loc); - - var original = data ? '@' : '', - dig = [], - depth = 0, - depthString = ''; - - for (var i = 0, l = parts.length; i < l; i++) { - var part = parts[i].part, - - // If we have [] syntax then we do not treat path references as operators, - // i.e. foo.[this] resolves to approximately context.foo['this'] - isLiteral = parts[i].original !== part; - original += (parts[i].separator || '') + part; - - if (!isLiteral && (part === '..' || part === '.' || part === 'this')) { - if (dig.length > 0) { - throw new _exception2['default']('Invalid path: ' + original, { loc: loc }); - } else if (part === '..') { - depth++; - depthString += '../'; - } - } else { - dig.push(part); - } - } - - return { - type: 'PathExpression', - data: data, - depth: depth, - parts: dig, - original: original, - loc: loc - }; - } - - function prepareMustache(path, params, hash, open, strip, locInfo) { - // Must use charAt to support IE pre-10 - var escapeFlag = open.charAt(3) || open.charAt(2), - escaped = escapeFlag !== '{' && escapeFlag !== '&'; - - var decorator = /\*/.test(open); - return { - type: decorator ? 'Decorator' : 'MustacheStatement', - path: path, - params: params, - hash: hash, - escaped: escaped, - strip: strip, - loc: this.locInfo(locInfo) - }; - } - - function prepareRawBlock(openRawBlock, contents, close, locInfo) { - validateClose(openRawBlock, close); - - locInfo = this.locInfo(locInfo); - var program = { - type: 'Program', - body: contents, - strip: {}, - loc: locInfo - }; - - return { - type: 'BlockStatement', - path: openRawBlock.path, - params: openRawBlock.params, - hash: openRawBlock.hash, - program: program, - openStrip: {}, - inverseStrip: {}, - closeStrip: {}, - loc: locInfo - }; - } - - function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { - if (close && close.path) { - validateClose(openBlock, close); - } - - var decorator = /\*/.test(openBlock.open); - - program.blockParams = openBlock.blockParams; - - var inverse = undefined, - inverseStrip = undefined; - - if (inverseAndProgram) { - if (decorator) { - throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram); - } - - if (inverseAndProgram.chain) { - inverseAndProgram.program.body[0].closeStrip = close.strip; - } - - inverseStrip = inverseAndProgram.strip; - inverse = inverseAndProgram.program; - } - - if (inverted) { - inverted = inverse; - inverse = program; - program = inverted; - } - - return { - type: decorator ? 'DecoratorBlock' : 'BlockStatement', - path: openBlock.path, - params: openBlock.params, - hash: openBlock.hash, - program: program, - inverse: inverse, - openStrip: openBlock.strip, - inverseStrip: inverseStrip, - closeStrip: close && close.strip, - loc: this.locInfo(locInfo) - }; - } - - function prepareProgram(statements, loc) { - if (!loc && statements.length) { - var firstLoc = statements[0].loc, - lastLoc = statements[statements.length - 1].loc; - - /* istanbul ignore else */ - if (firstLoc && lastLoc) { - loc = { - source: firstLoc.source, - start: { - line: firstLoc.start.line, - column: firstLoc.start.column - }, - end: { - line: lastLoc.end.line, - column: lastLoc.end.column - } - }; - } - } - - return { - type: 'Program', - body: statements, - strip: {}, - loc: loc - }; - } - - function preparePartialBlock(open, program, close, locInfo) { - validateClose(open, close); - - return { - type: 'PartialBlockStatement', - name: open.path, - params: open.params, - hash: open.hash, - program: program, - openStrip: open.strip, - closeStrip: close && close.strip, - loc: this.locInfo(locInfo) - }; - } - -/***/ }), -/* 41 */ -/***/ (function(module, exports, __webpack_require__) { - - /* eslint-disable new-cap */ - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.Compiler = Compiler; - exports.precompile = precompile; - exports.compile = compile; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _utils = __webpack_require__(5); - - var _ast = __webpack_require__(35); - - var _ast2 = _interopRequireDefault(_ast); - - var slice = [].slice; - - function Compiler() {} - - // the foundHelper register will disambiguate helper lookup from finding a - // function in a context. This is necessary for mustache compatibility, which - // requires that context functions in blocks are evaluated by blockHelperMissing, - // and then proceed as if the resulting value was provided to blockHelperMissing. - - Compiler.prototype = { - compiler: Compiler, - - equals: function equals(other) { - var len = this.opcodes.length; - if (other.opcodes.length !== len) { - return false; - } - - for (var i = 0; i < len; i++) { - var opcode = this.opcodes[i], - otherOpcode = other.opcodes[i]; - if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { - return false; - } - } - - // We know that length is the same between the two arrays because they are directly tied - // to the opcode behavior above. - len = this.children.length; - for (var i = 0; i < len; i++) { - if (!this.children[i].equals(other.children[i])) { - return false; - } - } - - return true; - }, - - guid: 0, - - compile: function compile(program, options) { - this.sourceNode = []; - this.opcodes = []; - this.children = []; - this.options = options; - this.stringParams = options.stringParams; - this.trackIds = options.trackIds; - - options.blockParams = options.blockParams || []; - - // These changes will propagate to the other compiler components - var knownHelpers = options.knownHelpers; - options.knownHelpers = { - 'helperMissing': true, - 'blockHelperMissing': true, - 'each': true, - 'if': true, - 'unless': true, - 'with': true, - 'log': true, - 'lookup': true - }; - if (knownHelpers) { - for (var _name in knownHelpers) { - /* istanbul ignore else */ - if (_name in knownHelpers) { - this.options.knownHelpers[_name] = knownHelpers[_name]; - } - } - } - - return this.accept(program); - }, - - compileProgram: function compileProgram(program) { - var childCompiler = new this.compiler(), - // eslint-disable-line new-cap - result = childCompiler.compile(program, this.options), - guid = this.guid++; - - this.usePartial = this.usePartial || result.usePartial; - - this.children[guid] = result; - this.useDepths = this.useDepths || result.useDepths; - - return guid; - }, - - accept: function accept(node) { - /* istanbul ignore next: Sanity code */ - if (!this[node.type]) { - throw new _exception2['default']('Unknown type: ' + node.type, node); - } - - this.sourceNode.unshift(node); - var ret = this[node.type](node); - this.sourceNode.shift(); - return ret; - }, - - Program: function Program(program) { - this.options.blockParams.unshift(program.blockParams); - - var body = program.body, - bodyLength = body.length; - for (var i = 0; i < bodyLength; i++) { - this.accept(body[i]); - } - - this.options.blockParams.shift(); - - this.isSimple = bodyLength === 1; - this.blockParams = program.blockParams ? program.blockParams.length : 0; - - return this; - }, - - BlockStatement: function BlockStatement(block) { - transformLiteralToPath(block); - - var program = block.program, - inverse = block.inverse; - - program = program && this.compileProgram(program); - inverse = inverse && this.compileProgram(inverse); - - var type = this.classifySexpr(block); - - if (type === 'helper') { - this.helperSexpr(block, program, inverse); - } else if (type === 'simple') { - this.simpleSexpr(block); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('emptyHash'); - this.opcode('blockValue', block.path.original); - } else { - this.ambiguousSexpr(block, program, inverse); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('emptyHash'); - this.opcode('ambiguousBlockValue'); - } - - this.opcode('append'); - }, - - DecoratorBlock: function DecoratorBlock(decorator) { - var program = decorator.program && this.compileProgram(decorator.program); - var params = this.setupFullMustacheParams(decorator, program, undefined), - path = decorator.path; - - this.useDecorators = true; - this.opcode('registerDecorator', params.length, path.original); - }, - - PartialStatement: function PartialStatement(partial) { - this.usePartial = true; - - var program = partial.program; - if (program) { - program = this.compileProgram(partial.program); - } - - var params = partial.params; - if (params.length > 1) { - throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial); - } else if (!params.length) { - if (this.options.explicitPartialContext) { - this.opcode('pushLiteral', 'undefined'); - } else { - params.push({ type: 'PathExpression', parts: [], depth: 0 }); - } - } - - var partialName = partial.name.original, - isDynamic = partial.name.type === 'SubExpression'; - if (isDynamic) { - this.accept(partial.name); - } - - this.setupFullMustacheParams(partial, program, undefined, true); - - var indent = partial.indent || ''; - if (this.options.preventIndent && indent) { - this.opcode('appendContent', indent); - indent = ''; - } - - this.opcode('invokePartial', isDynamic, partialName, indent); - this.opcode('append'); - }, - PartialBlockStatement: function PartialBlockStatement(partialBlock) { - this.PartialStatement(partialBlock); - }, - - MustacheStatement: function MustacheStatement(mustache) { - this.SubExpression(mustache); - - if (mustache.escaped && !this.options.noEscape) { - this.opcode('appendEscaped'); - } else { - this.opcode('append'); - } - }, - Decorator: function Decorator(decorator) { - this.DecoratorBlock(decorator); - }, - - ContentStatement: function ContentStatement(content) { - if (content.value) { - this.opcode('appendContent', content.value); - } - }, - - CommentStatement: function CommentStatement() {}, - - SubExpression: function SubExpression(sexpr) { - transformLiteralToPath(sexpr); - var type = this.classifySexpr(sexpr); - - if (type === 'simple') { - this.simpleSexpr(sexpr); - } else if (type === 'helper') { - this.helperSexpr(sexpr); - } else { - this.ambiguousSexpr(sexpr); - } - }, - ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) { - var path = sexpr.path, - name = path.parts[0], - isBlock = program != null || inverse != null; - - this.opcode('getContext', path.depth); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - path.strict = true; - this.accept(path); - - this.opcode('invokeAmbiguous', name, isBlock); - }, - - simpleSexpr: function simpleSexpr(sexpr) { - var path = sexpr.path; - path.strict = true; - this.accept(path); - this.opcode('resolvePossibleLambda'); - }, - - helperSexpr: function helperSexpr(sexpr, program, inverse) { - var params = this.setupFullMustacheParams(sexpr, program, inverse), - path = sexpr.path, - name = path.parts[0]; - - if (this.options.knownHelpers[name]) { - this.opcode('invokeKnownHelper', params.length, name); - } else if (this.options.knownHelpersOnly) { - throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); - } else { - path.strict = true; - path.falsy = true; - - this.accept(path); - this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path)); - } - }, - - PathExpression: function PathExpression(path) { - this.addDepth(path.depth); - this.opcode('getContext', path.depth); - - var name = path.parts[0], - scoped = _ast2['default'].helpers.scopedId(path), - blockParamId = !path.depth && !scoped && this.blockParamIndex(name); - - if (blockParamId) { - this.opcode('lookupBlockParam', blockParamId, path.parts); - } else if (!name) { - // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` - this.opcode('pushContext'); - } else if (path.data) { - this.options.data = true; - this.opcode('lookupData', path.depth, path.parts, path.strict); - } else { - this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped); - } - }, - - StringLiteral: function StringLiteral(string) { - this.opcode('pushString', string.value); - }, - - NumberLiteral: function NumberLiteral(number) { - this.opcode('pushLiteral', number.value); - }, - - BooleanLiteral: function BooleanLiteral(bool) { - this.opcode('pushLiteral', bool.value); - }, - - UndefinedLiteral: function UndefinedLiteral() { - this.opcode('pushLiteral', 'undefined'); - }, - - NullLiteral: function NullLiteral() { - this.opcode('pushLiteral', 'null'); - }, - - Hash: function Hash(hash) { - var pairs = hash.pairs, - i = 0, - l = pairs.length; - - this.opcode('pushHash'); - - for (; i < l; i++) { - this.pushParam(pairs[i].value); - } - while (i--) { - this.opcode('assignToHash', pairs[i].key); - } - this.opcode('popHash'); - }, - - // HELPERS - opcode: function opcode(name) { - this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc }); - }, - - addDepth: function addDepth(depth) { - if (!depth) { - return; - } - - this.useDepths = true; - }, - - classifySexpr: function classifySexpr(sexpr) { - var isSimple = _ast2['default'].helpers.simpleId(sexpr.path); - - var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); - - // a mustache is an eligible helper if: - // * its id is simple (a single part, not `this` or `..`) - var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr); - - // if a mustache is an eligible helper but not a definite - // helper, it is ambiguous, and will be resolved in a later - // pass or at runtime. - var isEligible = !isBlockParam && (isHelper || isSimple); - - // if ambiguous, we can possibly resolve the ambiguity now - // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. - if (isEligible && !isHelper) { - var _name2 = sexpr.path.parts[0], - options = this.options; - - if (options.knownHelpers[_name2]) { - isHelper = true; - } else if (options.knownHelpersOnly) { - isEligible = false; - } - } - - if (isHelper) { - return 'helper'; - } else if (isEligible) { - return 'ambiguous'; - } else { - return 'simple'; - } - }, - - pushParams: function pushParams(params) { - for (var i = 0, l = params.length; i < l; i++) { - this.pushParam(params[i]); - } - }, - - pushParam: function pushParam(val) { - var value = val.value != null ? val.value : val.original || ''; - - if (this.stringParams) { - if (value.replace) { - value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.'); - } - - if (val.depth) { - this.addDepth(val.depth); - } - this.opcode('getContext', val.depth || 0); - this.opcode('pushStringParam', value, val.type); - - if (val.type === 'SubExpression') { - // SubExpressions get evaluated and passed in - // in string params mode. - this.accept(val); - } - } else { - if (this.trackIds) { - var blockParamIndex = undefined; - if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) { - blockParamIndex = this.blockParamIndex(val.parts[0]); - } - if (blockParamIndex) { - var blockParamChild = val.parts.slice(1).join('.'); - this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); - } else { - value = val.original || value; - if (value.replace) { - value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, ''); - } - - this.opcode('pushId', val.type, value); - } - } - this.accept(val); - } - }, - - setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) { - var params = sexpr.params; - this.pushParams(params); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - if (sexpr.hash) { - this.accept(sexpr.hash); - } else { - this.opcode('emptyHash', omitEmpty); - } - - return params; - }, - - blockParamIndex: function blockParamIndex(name) { - for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { - var blockParams = this.options.blockParams[depth], - param = blockParams && _utils.indexOf(blockParams, name); - if (blockParams && param >= 0) { - return [depth, param]; - } - } - } - }; - - function precompile(input, options, env) { - if (input == null || typeof input !== 'string' && input.type !== 'Program') { - throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); - } - - options = options || {}; - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } - - var ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options); - return new env.JavaScriptCompiler().compile(environment, options); - } - - function compile(input, options, env) { - if (options === undefined) options = {}; - - if (input == null || typeof input !== 'string' && input.type !== 'Program') { - throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); - } - - options = _utils.extend({}, options); - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } - - var compiled = undefined; - - function compileInput() { - var ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options), - templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); - return env.template(templateSpec); - } - - // Template is only compiled on first use and cached after that point. - function ret(context, execOptions) { - if (!compiled) { - compiled = compileInput(); - } - return compiled.call(this, context, execOptions); - } - ret._setup = function (setupOptions) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._setup(setupOptions); - }; - ret._child = function (i, data, blockParams, depths) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._child(i, data, blockParams, depths); - }; - return ret; - } - - function argEquals(a, b) { - if (a === b) { - return true; - } - - if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) { - for (var i = 0; i < a.length; i++) { - if (!argEquals(a[i], b[i])) { - return false; - } - } - return true; - } - } - - function transformLiteralToPath(sexpr) { - if (!sexpr.path.parts) { - var literal = sexpr.path; - // Casting to string here to make false and 0 literal values play nicely with the rest - // of the system. - sexpr.path = { - type: 'PathExpression', - data: false, - depth: 0, - parts: [literal.original + ''], - original: literal.original + '', - loc: literal.loc - }; - } - } - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _base = __webpack_require__(4); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _utils = __webpack_require__(5); - - var _codeGen = __webpack_require__(43); - - var _codeGen2 = _interopRequireDefault(_codeGen); - - function Literal(value) { - this.value = value; - } - - function JavaScriptCompiler() {} - - JavaScriptCompiler.prototype = { - // PUBLIC API: You can override these methods in a subclass to provide - // alternative compiled forms for name lookup and buffering semantics - nameLookup: function nameLookup(parent, name /* , type*/) { - if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return [parent, '.', name]; - } else { - return [parent, '[', JSON.stringify(name), ']']; - } - }, - depthedLookup: function depthedLookup(name) { - return [this.aliasable('container.lookup'), '(depths, "', name, '")']; - }, - - compilerInfo: function compilerInfo() { - var revision = _base.COMPILER_REVISION, - versions = _base.REVISION_CHANGES[revision]; - return [revision, versions]; - }, - - appendToBuffer: function appendToBuffer(source, location, explicit) { - // Force a source as this simplifies the merge logic. - if (!_utils.isArray(source)) { - source = [source]; - } - source = this.source.wrap(source, location); - - if (this.environment.isSimple) { - return ['return ', source, ';']; - } else if (explicit) { - // This is a case where the buffer operation occurs as a child of another - // construct, generally braces. We have to explicitly output these buffer - // operations to ensure that the emitted code goes in the correct location. - return ['buffer += ', source, ';']; - } else { - source.appendToBuffer = true; - return source; - } - }, - - initializeBuffer: function initializeBuffer() { - return this.quotedString(''); - }, - // END PUBLIC API - - compile: function compile(environment, options, context, asObject) { - this.environment = environment; - this.options = options; - this.stringParams = this.options.stringParams; - this.trackIds = this.options.trackIds; - this.precompile = !asObject; - - this.name = this.environment.name; - this.isChild = !!context; - this.context = context || { - decorators: [], - programs: [], - environments: [] - }; - - this.preamble(); - - this.stackSlot = 0; - this.stackVars = []; - this.aliases = {}; - this.registers = { list: [] }; - this.hashes = []; - this.compileStack = []; - this.inlineStack = []; - this.blockParams = []; - - this.compileChildren(environment, options); - - this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; - this.useBlockParams = this.useBlockParams || environment.useBlockParams; - - var opcodes = environment.opcodes, - opcode = undefined, - firstLoc = undefined, - i = undefined, - l = undefined; - - for (i = 0, l = opcodes.length; i < l; i++) { - opcode = opcodes[i]; - - this.source.currentLocation = opcode.loc; - firstLoc = firstLoc || opcode.loc; - this[opcode.opcode].apply(this, opcode.args); - } - - // Flush any trailing content that might be pending. - this.source.currentLocation = firstLoc; - this.pushSource(''); - - /* istanbul ignore next */ - if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { - throw new _exception2['default']('Compile completed with content left on stack'); - } - - if (!this.decorators.isEmpty()) { - this.useDecorators = true; - - this.decorators.prepend('var decorators = container.decorators;\n'); - this.decorators.push('return fn;'); - - if (asObject) { - this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); - } else { - this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); - this.decorators.push('}\n'); - this.decorators = this.decorators.merge(); - } - } else { - this.decorators = undefined; - } - - var fn = this.createFunctionContext(asObject); - if (!this.isChild) { - var ret = { - compiler: this.compilerInfo(), - main: fn - }; - - if (this.decorators) { - ret.main_d = this.decorators; // eslint-disable-line camelcase - ret.useDecorators = true; - } - - var _context = this.context; - var programs = _context.programs; - var decorators = _context.decorators; - - for (i = 0, l = programs.length; i < l; i++) { - if (programs[i]) { - ret[i] = programs[i]; - if (decorators[i]) { - ret[i + '_d'] = decorators[i]; - ret.useDecorators = true; - } - } - } - - if (this.environment.usePartial) { - ret.usePartial = true; - } - if (this.options.data) { - ret.useData = true; - } - if (this.useDepths) { - ret.useDepths = true; - } - if (this.useBlockParams) { - ret.useBlockParams = true; - } - if (this.options.compat) { - ret.compat = true; - } - - if (!asObject) { - ret.compiler = JSON.stringify(ret.compiler); - - this.source.currentLocation = { start: { line: 1, column: 0 } }; - ret = this.objectLiteral(ret); - - if (options.srcName) { - ret = ret.toStringWithSourceMap({ file: options.destName }); - ret.map = ret.map && ret.map.toString(); - } else { - ret = ret.toString(); - } - } else { - ret.compilerOptions = this.options; - } - - return ret; - } else { - return fn; - } - }, - - preamble: function preamble() { - // track the last context pushed into place to allow skipping the - // getContext opcode when it would be a noop - this.lastContext = 0; - this.source = new _codeGen2['default'](this.options.srcName); - this.decorators = new _codeGen2['default'](this.options.srcName); - }, - - createFunctionContext: function createFunctionContext(asObject) { - var varDeclarations = ''; - - var locals = this.stackVars.concat(this.registers.list); - if (locals.length > 0) { - varDeclarations += ', ' + locals.join(', '); - } - - // Generate minimizer alias mappings - // - // When using true SourceNodes, this will update all references to the given alias - // as the source nodes are reused in situ. For the non-source node compilation mode, - // aliases will not be used, but this case is already being run on the client and - // we aren't concern about minimizing the template size. - var aliasCount = 0; - for (var alias in this.aliases) { - // eslint-disable-line guard-for-in - var node = this.aliases[alias]; - - if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { - varDeclarations += ', alias' + ++aliasCount + '=' + alias; - node.children[0] = 'alias' + aliasCount; - } - } - - var params = ['container', 'depth0', 'helpers', 'partials', 'data']; - - if (this.useBlockParams || this.useDepths) { - params.push('blockParams'); - } - if (this.useDepths) { - params.push('depths'); - } - - // Perform a second pass over the output to merge content when possible - var source = this.mergeSource(varDeclarations); - - if (asObject) { - params.push(source); - - return Function.apply(this, params); - } else { - return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); - } - }, - mergeSource: function mergeSource(varDeclarations) { - var isSimple = this.environment.isSimple, - appendOnly = !this.forceBuffer, - appendFirst = undefined, - sourceSeen = undefined, - bufferStart = undefined, - bufferEnd = undefined; - this.source.each(function (line) { - if (line.appendToBuffer) { - if (bufferStart) { - line.prepend(' + '); - } else { - bufferStart = line; - } - bufferEnd = line; - } else { - if (bufferStart) { - if (!sourceSeen) { - appendFirst = true; - } else { - bufferStart.prepend('buffer += '); - } - bufferEnd.add(';'); - bufferStart = bufferEnd = undefined; - } - - sourceSeen = true; - if (!isSimple) { - appendOnly = false; - } - } - }); - - if (appendOnly) { - if (bufferStart) { - bufferStart.prepend('return '); - bufferEnd.add(';'); - } else if (!sourceSeen) { - this.source.push('return "";'); - } - } else { - varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); - - if (bufferStart) { - bufferStart.prepend('return buffer + '); - bufferEnd.add(';'); - } else { - this.source.push('return buffer;'); - } - } - - if (varDeclarations) { - this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); - } - - return this.source.merge(); - }, - - // [blockValue] - // - // On stack, before: hash, inverse, program, value - // On stack, after: return value of blockHelperMissing - // - // The purpose of this opcode is to take a block of the form - // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and - // replace it on the stack with the result of properly - // invoking blockHelperMissing. - blockValue: function blockValue(name) { - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), - params = [this.contextName(0)]; - this.setupHelperArgs(name, 0, params); - - var blockName = this.popStack(); - params.splice(1, 0, blockName); - - this.push(this.source.functionCall(blockHelperMissing, 'call', params)); - }, - - // [ambiguousBlockValue] - // - // On stack, before: hash, inverse, program, value - // Compiler value, before: lastHelper=value of last found helper, if any - // On stack, after, if no lastHelper: same as [blockValue] - // On stack, after, if lastHelper: value - ambiguousBlockValue: function ambiguousBlockValue() { - // We're being a bit cheeky and reusing the options value from the prior exec - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), - params = [this.contextName(0)]; - this.setupHelperArgs('', 0, params, true); - - this.flushInline(); - - var current = this.topStack(); - params.splice(1, 0, current); - - this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']); - }, - - // [appendContent] - // - // On stack, before: ... - // On stack, after: ... - // - // Appends the string value of `content` to the current buffer - appendContent: function appendContent(content) { - if (this.pendingContent) { - content = this.pendingContent + content; - } else { - this.pendingLocation = this.source.currentLocation; - } - - this.pendingContent = content; - }, - - // [append] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Coerces `value` to a String and appends it to the current buffer. - // - // If `value` is truthy, or 0, it is coerced into a string and appended - // Otherwise, the empty string is appended - append: function append() { - if (this.isInline()) { - this.replaceStack(function (current) { - return [' != null ? ', current, ' : ""']; - }); - - this.pushSource(this.appendToBuffer(this.popStack())); - } else { - var local = this.popStack(); - this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); - if (this.environment.isSimple) { - this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); - } - } - }, - - // [appendEscaped] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Escape `value` and append it to the buffer - appendEscaped: function appendEscaped() { - this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')'])); - }, - - // [getContext] - // - // On stack, before: ... - // On stack, after: ... - // Compiler value, after: lastContext=depth - // - // Set the value of the `lastContext` compiler value to the depth - getContext: function getContext(depth) { - this.lastContext = depth; - }, - - // [pushContext] - // - // On stack, before: ... - // On stack, after: currentContext, ... - // - // Pushes the value of the current context onto the stack. - pushContext: function pushContext() { - this.pushStackLiteral(this.contextName(this.lastContext)); - }, - - // [lookupOnContext] - // - // On stack, before: ... - // On stack, after: currentContext[name], ... - // - // Looks up the value of `name` on the current context and pushes - // it onto the stack. - lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) { - var i = 0; - - if (!scoped && this.options.compat && !this.lastContext) { - // The depthed query is expected to handle the undefined logic for the root level that - // is implemented below, so we evaluate that directly in compat mode - this.push(this.depthedLookup(parts[i++])); - } else { - this.pushContext(); - } - - this.resolvePath('context', parts, i, falsy, strict); - }, - - // [lookupBlockParam] - // - // On stack, before: ... - // On stack, after: blockParam[name], ... - // - // Looks up the value of `parts` on the given block param and pushes - // it onto the stack. - lookupBlockParam: function lookupBlockParam(blockParamId, parts) { - this.useBlockParams = true; - - this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); - this.resolvePath('context', parts, 1); - }, - - // [lookupData] - // - // On stack, before: ... - // On stack, after: data, ... - // - // Push the data lookup operator - lookupData: function lookupData(depth, parts, strict) { - if (!depth) { - this.pushStackLiteral('data'); - } else { - this.pushStackLiteral('container.data(data, ' + depth + ')'); - } - - this.resolvePath('data', parts, 0, true, strict); - }, - - resolvePath: function resolvePath(type, parts, i, falsy, strict) { - // istanbul ignore next - - var _this = this; - - if (this.options.strict || this.options.assumeObjects) { - this.push(strictLookup(this.options.strict && strict, this, parts, type)); - return; - } - - var len = parts.length; - for (; i < len; i++) { - /* eslint-disable no-loop-func */ - this.replaceStack(function (current) { - var lookup = _this.nameLookup(current, parts[i], type); - // We want to ensure that zero and false are handled properly if the context (falsy flag) - // needs to have the special handling for these values. - if (!falsy) { - return [' != null ? ', lookup, ' : ', current]; - } else { - // Otherwise we can use generic falsy handling - return [' && ', lookup]; - } - }); - /* eslint-enable no-loop-func */ - } - }, - - // [resolvePossibleLambda] - // - // On stack, before: value, ... - // On stack, after: resolved value, ... - // - // If the `value` is a lambda, replace it on the stack by - // the return value of the lambda - resolvePossibleLambda: function resolvePossibleLambda() { - this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); - }, - - // [pushStringParam] - // - // On stack, before: ... - // On stack, after: string, currentContext, ... - // - // This opcode is designed for use in string mode, which - // provides the string value of a parameter along with its - // depth rather than resolving it immediately. - pushStringParam: function pushStringParam(string, type) { - this.pushContext(); - this.pushString(type); - - // If it's a subexpression, the string result - // will be pushed after this opcode. - if (type !== 'SubExpression') { - if (typeof string === 'string') { - this.pushString(string); - } else { - this.pushStackLiteral(string); - } - } - }, - - emptyHash: function emptyHash(omitEmpty) { - if (this.trackIds) { - this.push('{}'); // hashIds - } - if (this.stringParams) { - this.push('{}'); // hashContexts - this.push('{}'); // hashTypes - } - this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); - }, - pushHash: function pushHash() { - if (this.hash) { - this.hashes.push(this.hash); - } - this.hash = { values: [], types: [], contexts: [], ids: [] }; - }, - popHash: function popHash() { - var hash = this.hash; - this.hash = this.hashes.pop(); - - if (this.trackIds) { - this.push(this.objectLiteral(hash.ids)); - } - if (this.stringParams) { - this.push(this.objectLiteral(hash.contexts)); - this.push(this.objectLiteral(hash.types)); - } - - this.push(this.objectLiteral(hash.values)); - }, - - // [pushString] - // - // On stack, before: ... - // On stack, after: quotedString(string), ... - // - // Push a quoted version of `string` onto the stack - pushString: function pushString(string) { - this.pushStackLiteral(this.quotedString(string)); - }, - - // [pushLiteral] - // - // On stack, before: ... - // On stack, after: value, ... - // - // Pushes a value onto the stack. This operation prevents - // the compiler from creating a temporary variable to hold - // it. - pushLiteral: function pushLiteral(value) { - this.pushStackLiteral(value); - }, - - // [pushProgram] - // - // On stack, before: ... - // On stack, after: program(guid), ... - // - // Push a program expression onto the stack. This takes - // a compile-time guid and converts it into a runtime-accessible - // expression. - pushProgram: function pushProgram(guid) { - if (guid != null) { - this.pushStackLiteral(this.programExpression(guid)); - } else { - this.pushStackLiteral(null); - } - }, - - // [registerDecorator] - // - // On stack, before: hash, program, params..., ... - // On stack, after: ... - // - // Pops off the decorator's parameters, invokes the decorator, - // and inserts the decorator into the decorators list. - registerDecorator: function registerDecorator(paramSize, name) { - var foundDecorator = this.nameLookup('decorators', name, 'decorator'), - options = this.setupHelperArgs(name, paramSize); - - this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']); - }, - - // [invokeHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // Pops off the helper's parameters, invokes the helper, - // and pushes the helper's return value onto the stack. - // - // If the helper is not found, `helperMissing` is called. - invokeHelper: function invokeHelper(paramSize, name, isSimple) { - var nonHelper = this.popStack(), - helper = this.setupHelper(paramSize, name), - simple = isSimple ? [helper.name, ' || '] : ''; - - var lookup = ['('].concat(simple, nonHelper); - if (!this.options.strict) { - lookup.push(' || ', this.aliasable('helpers.helperMissing')); - } - lookup.push(')'); - - this.push(this.source.functionCall(lookup, 'call', helper.callParams)); - }, - - // [invokeKnownHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // This operation is used when the helper is known to exist, - // so a `helperMissing` fallback is not required. - invokeKnownHelper: function invokeKnownHelper(paramSize, name) { - var helper = this.setupHelper(paramSize, name); - this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); - }, - - // [invokeAmbiguous] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of disambiguation - // - // This operation is used when an expression like `{{foo}}` - // is provided, but we don't know at compile-time whether it - // is a helper or a path. - // - // This operation emits more code than the other options, - // and can be avoided by passing the `knownHelpers` and - // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function invokeAmbiguous(name, helperCall) { - this.useRegister('helper'); - - var nonHelper = this.popStack(); - - this.emptyHash(); - var helper = this.setupHelper(0, name, helperCall); - - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - - var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; - if (!this.options.strict) { - lookup[0] = '(helper = '; - lookup.push(' != null ? helper : ', this.aliasable('helpers.helperMissing')); - } - - this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']); - }, - - // [invokePartial] - // - // On stack, before: context, ... - // On stack after: result of partial invocation - // - // This operation pops off a context, invokes a partial with that context, - // and pushes the result of the invocation back. - invokePartial: function invokePartial(isDynamic, name, indent) { - var params = [], - options = this.setupParams(name, 1, params); - - if (isDynamic) { - name = this.popStack(); - delete options.name; - } - - if (indent) { - options.indent = JSON.stringify(indent); - } - options.helpers = 'helpers'; - options.partials = 'partials'; - options.decorators = 'container.decorators'; - - if (!isDynamic) { - params.unshift(this.nameLookup('partials', name, 'partial')); - } else { - params.unshift(name); - } - - if (this.options.compat) { - options.depths = 'depths'; - } - options = this.objectLiteral(options); - params.push(options); - - this.push(this.source.functionCall('container.invokePartial', '', params)); - }, - - // [assignToHash] - // - // On stack, before: value, ..., hash, ... - // On stack, after: ..., hash, ... - // - // Pops a value off the stack and assigns it to the current hash - assignToHash: function assignToHash(key) { - var value = this.popStack(), - context = undefined, - type = undefined, - id = undefined; - - if (this.trackIds) { - id = this.popStack(); - } - if (this.stringParams) { - type = this.popStack(); - context = this.popStack(); - } - - var hash = this.hash; - if (context) { - hash.contexts[key] = context; - } - if (type) { - hash.types[key] = type; - } - if (id) { - hash.ids[key] = id; - } - hash.values[key] = value; - }, - - pushId: function pushId(type, name, child) { - if (type === 'BlockParam') { - this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : '')); - } else if (type === 'PathExpression') { - this.pushString(name); - } else if (type === 'SubExpression') { - this.pushStackLiteral('true'); - } else { - this.pushStackLiteral('null'); - } - }, - - // HELPERS - - compiler: JavaScriptCompiler, - - compileChildren: function compileChildren(environment, options) { - var children = environment.children, - child = undefined, - compiler = undefined; - - for (var i = 0, l = children.length; i < l; i++) { - child = children[i]; - compiler = new this.compiler(); // eslint-disable-line new-cap - - var existing = this.matchExistingProgram(child); - - if (existing == null) { - this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - var index = this.context.programs.length; - child.index = index; - child.name = 'program' + index; - this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); - this.context.decorators[index] = compiler.decorators; - this.context.environments[index] = child; - - this.useDepths = this.useDepths || compiler.useDepths; - this.useBlockParams = this.useBlockParams || compiler.useBlockParams; - child.useDepths = this.useDepths; - child.useBlockParams = this.useBlockParams; - } else { - child.index = existing.index; - child.name = 'program' + existing.index; - - this.useDepths = this.useDepths || existing.useDepths; - this.useBlockParams = this.useBlockParams || existing.useBlockParams; - } - } - }, - matchExistingProgram: function matchExistingProgram(child) { - for (var i = 0, len = this.context.environments.length; i < len; i++) { - var environment = this.context.environments[i]; - if (environment && environment.equals(child)) { - return environment; - } - } - }, - - programExpression: function programExpression(guid) { - var child = this.environment.children[guid], - programParams = [child.index, 'data', child.blockParams]; - - if (this.useBlockParams || this.useDepths) { - programParams.push('blockParams'); - } - if (this.useDepths) { - programParams.push('depths'); - } - - return 'container.program(' + programParams.join(', ') + ')'; - }, - - useRegister: function useRegister(name) { - if (!this.registers[name]) { - this.registers[name] = true; - this.registers.list.push(name); - } - }, - - push: function push(expr) { - if (!(expr instanceof Literal)) { - expr = this.source.wrap(expr); - } - - this.inlineStack.push(expr); - return expr; - }, - - pushStackLiteral: function pushStackLiteral(item) { - this.push(new Literal(item)); - }, - - pushSource: function pushSource(source) { - if (this.pendingContent) { - this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); - this.pendingContent = undefined; - } - - if (source) { - this.source.push(source); - } - }, - - replaceStack: function replaceStack(callback) { - var prefix = ['('], - stack = undefined, - createdStack = undefined, - usedLiteral = undefined; - - /* istanbul ignore next */ - if (!this.isInline()) { - throw new _exception2['default']('replaceStack on non-inline'); - } - - // We want to merge the inline statement into the replacement statement via ',' - var top = this.popStack(true); - - if (top instanceof Literal) { - // Literals do not need to be inlined - stack = [top.value]; - prefix = ['(', stack]; - usedLiteral = true; - } else { - // Get or create the current stack name for use by the inline - createdStack = true; - var _name = this.incrStack(); - - prefix = ['((', this.push(_name), ' = ', top, ')']; - stack = this.topStack(); - } - - var item = callback.call(this, stack); - - if (!usedLiteral) { - this.popStack(); - } - if (createdStack) { - this.stackSlot--; - } - this.push(prefix.concat(item, ')')); - }, - - incrStack: function incrStack() { - this.stackSlot++; - if (this.stackSlot > this.stackVars.length) { - this.stackVars.push('stack' + this.stackSlot); - } - return this.topStackName(); - }, - topStackName: function topStackName() { - return 'stack' + this.stackSlot; - }, - flushInline: function flushInline() { - var inlineStack = this.inlineStack; - this.inlineStack = []; - for (var i = 0, len = inlineStack.length; i < len; i++) { - var entry = inlineStack[i]; - /* istanbul ignore if */ - if (entry instanceof Literal) { - this.compileStack.push(entry); - } else { - var stack = this.incrStack(); - this.pushSource([stack, ' = ', entry, ';']); - this.compileStack.push(stack); - } - } - }, - isInline: function isInline() { - return this.inlineStack.length; - }, - - popStack: function popStack(wrapped) { - var inline = this.isInline(), - item = (inline ? this.inlineStack : this.compileStack).pop(); - - if (!wrapped && item instanceof Literal) { - return item.value; - } else { - if (!inline) { - /* istanbul ignore next */ - if (!this.stackSlot) { - throw new _exception2['default']('Invalid stack pop'); - } - this.stackSlot--; - } - return item; - } - }, - - topStack: function topStack() { - var stack = this.isInline() ? this.inlineStack : this.compileStack, - item = stack[stack.length - 1]; - - /* istanbul ignore if */ - if (item instanceof Literal) { - return item.value; - } else { - return item; - } - }, - - contextName: function contextName(context) { - if (this.useDepths && context) { - return 'depths[' + context + ']'; - } else { - return 'depth' + context; - } - }, - - quotedString: function quotedString(str) { - return this.source.quotedString(str); - }, - - objectLiteral: function objectLiteral(obj) { - return this.source.objectLiteral(obj); - }, - - aliasable: function aliasable(name) { - var ret = this.aliases[name]; - if (ret) { - ret.referenceCount++; - return ret; - } - - ret = this.aliases[name] = this.source.wrap(name); - ret.aliasable = true; - ret.referenceCount = 1; - - return ret; - }, - - setupHelper: function setupHelper(paramSize, name, blockHelper) { - var params = [], - paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); - var foundHelper = this.nameLookup('helpers', name, 'helper'), - callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : (container.nullContext || {})'); - - return { - params: params, - paramsInit: paramsInit, - name: foundHelper, - callParams: [callContext].concat(params) - }; - }, - - setupParams: function setupParams(helper, paramSize, params) { - var options = {}, - contexts = [], - types = [], - ids = [], - objectArgs = !params, - param = undefined; - - if (objectArgs) { - params = []; - } - - options.name = this.quotedString(helper); - options.hash = this.popStack(); - - if (this.trackIds) { - options.hashIds = this.popStack(); - } - if (this.stringParams) { - options.hashTypes = this.popStack(); - options.hashContexts = this.popStack(); - } - - var inverse = this.popStack(), - program = this.popStack(); - - // Avoid setting fn and inverse if neither are set. This allows - // helpers to do a check for `if (options.fn)` - if (program || inverse) { - options.fn = program || 'container.noop'; - options.inverse = inverse || 'container.noop'; - } - - // The parameters go on to the stack in order (making sure that they are evaluated in order) - // so we need to pop them off the stack in reverse order - var i = paramSize; - while (i--) { - param = this.popStack(); - params[i] = param; - - if (this.trackIds) { - ids[i] = this.popStack(); - } - if (this.stringParams) { - types[i] = this.popStack(); - contexts[i] = this.popStack(); - } - } - - if (objectArgs) { - options.args = this.source.generateArray(params); - } - - if (this.trackIds) { - options.ids = this.source.generateArray(ids); - } - if (this.stringParams) { - options.types = this.source.generateArray(types); - options.contexts = this.source.generateArray(contexts); - } - - if (this.options.data) { - options.data = 'data'; - } - if (this.useBlockParams) { - options.blockParams = 'blockParams'; - } - return options; - }, - - setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) { - var options = this.setupParams(helper, paramSize, params); - options = this.objectLiteral(options); - if (useRegister) { - this.useRegister('options'); - params.push('options'); - return ['options=', options]; - } else if (params) { - params.push(options); - return ''; - } else { - return options; - } - } - }; - - (function () { - var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' '); - - var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; - - for (var i = 0, l = reservedWords.length; i < l; i++) { - compilerWords[reservedWords[i]] = true; - } - })(); - - JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { - return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); - }; - - function strictLookup(requireTerminal, compiler, parts, type) { - var stack = compiler.popStack(), - i = 0, - len = parts.length; - if (requireTerminal) { - len--; - } - - for (; i < len; i++) { - stack = compiler.nameLookup(stack, parts[i], type); - } - - if (requireTerminal) { - return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')']; - } else { - return stack; - } - } - - exports['default'] = JavaScriptCompiler; - module.exports = exports['default']; - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - - /* global define */ - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var SourceNode = undefined; - - try { - /* istanbul ignore next */ - if (false) { - // We don't support this in AMD environments. For these environments, we asusme that - // they are running on the browser and thus have no need for the source-map library. - var SourceMap = require('source-map'); - SourceNode = SourceMap.SourceNode; - } - } catch (err) {} - /* NOP */ - - /* istanbul ignore if: tested but not covered in istanbul due to dist build */ - if (!SourceNode) { - SourceNode = function (line, column, srcFile, chunks) { - this.src = ''; - if (chunks) { - this.add(chunks); - } - }; - /* istanbul ignore next */ - SourceNode.prototype = { - add: function add(chunks) { - if (_utils.isArray(chunks)) { - chunks = chunks.join(''); - } - this.src += chunks; - }, - prepend: function prepend(chunks) { - if (_utils.isArray(chunks)) { - chunks = chunks.join(''); - } - this.src = chunks + this.src; - }, - toStringWithSourceMap: function toStringWithSourceMap() { - return { code: this.toString() }; - }, - toString: function toString() { - return this.src; - } - }; - } - - function castChunk(chunk, codeGen, loc) { - if (_utils.isArray(chunk)) { - var ret = []; - - for (var i = 0, len = chunk.length; i < len; i++) { - ret.push(codeGen.wrap(chunk[i], loc)); - } - return ret; - } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { - // Handle primitives that the SourceNode will throw up on - return chunk + ''; - } - return chunk; - } - - function CodeGen(srcFile) { - this.srcFile = srcFile; - this.source = []; - } - - CodeGen.prototype = { - isEmpty: function isEmpty() { - return !this.source.length; - }, - prepend: function prepend(source, loc) { - this.source.unshift(this.wrap(source, loc)); - }, - push: function push(source, loc) { - this.source.push(this.wrap(source, loc)); - }, - - merge: function merge() { - var source = this.empty(); - this.each(function (line) { - source.add([' ', line, '\n']); - }); - return source; - }, - - each: function each(iter) { - for (var i = 0, len = this.source.length; i < len; i++) { - iter(this.source[i]); - } - }, - - empty: function empty() { - var loc = this.currentLocation || { start: {} }; - return new SourceNode(loc.start.line, loc.start.column, this.srcFile); - }, - wrap: function wrap(chunk) { - var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1]; - - if (chunk instanceof SourceNode) { - return chunk; - } - - chunk = castChunk(chunk, this, loc); - - return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); - }, - - functionCall: function functionCall(fn, type, params) { - params = this.generateList(params); - return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); - }, - - quotedString: function quotedString(str) { - return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 - .replace(/\u2029/g, '\\u2029') + '"'; - }, - - objectLiteral: function objectLiteral(obj) { - var pairs = []; - - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - var value = castChunk(obj[key], this); - if (value !== 'undefined') { - pairs.push([this.quotedString(key), ':', value]); - } - } - } - - var ret = this.generateList(pairs); - ret.prepend('{'); - ret.add('}'); - return ret; - }, - - generateList: function generateList(entries) { - var ret = this.empty(); - - for (var i = 0, len = entries.length; i < len; i++) { - if (i) { - ret.add(','); - } - - ret.add(castChunk(entries[i], this)); - } - - return ret; - }, - - generateArray: function generateArray(entries) { - var ret = this.generateList(entries); - ret.prepend('['); - ret.add(']'); - - return ret; - } - }; - - exports['default'] = CodeGen; - module.exports = exports['default']; - -/***/ }) -/******/ ]) -}); -; \ No newline at end of file diff -Nru pdns-recursor-5.2.13/html/js/handlebars-v4.7.8-min.js pdns-recursor-5.4.9/html/js/handlebars-v4.7.8-min.js --- pdns-recursor-5.2.13/html/js/handlebars-v4.7.8-min.js 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/html/js/handlebars-v4.7.8-min.js 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,29 @@ +/**! + + @license + handlebars v4.7.8 + +Copyright (C) 2011-2019 by Yehuda Katz + +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 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +!function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?exports.Handlebars=b():a.Handlebars=b()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){"use strict";function d(){var a=r();return a.compile=function(b,c){return k.compile(b,c,a)},a.precompile=function(b,c){return k.precompile(b,c,a)},a.AST=i["default"],a.Compiler=k.Compiler,a.JavaScriptCompiler=m["default"],a.Parser=j.parser,a.parse=j.parse,a.parseWithoutProcessing=j.parseWithoutProcessing,a}var e=c(1)["default"];b.__esModule=!0;var f=c(2),g=e(f),h=c(84),i=e(h),j=c(85),k=c(90),l=c(91),m=e(l),n=c(88),o=e(n),p=c(83),q=e(p),r=g["default"].create,s=d();s.create=d,q["default"](s),s.Visitor=o["default"],s["default"]=s,b["default"]=s,a.exports=b["default"]},function(a,b){"use strict";b["default"]=function(a){return a&&a.__esModule?a:{"default":a}},b.__esModule=!0},function(a,b,c){"use strict";function d(){var a=new h.HandlebarsEnvironment;return n.extend(a,h),a.SafeString=j["default"],a.Exception=l["default"],a.Utils=n,a.escapeExpression=n.escapeExpression,a.VM=p,a.template=function(b){return p.template(b,a)},a}var e=c(3)["default"],f=c(1)["default"];b.__esModule=!0;var g=c(4),h=e(g),i=c(77),j=f(i),k=c(6),l=f(k),m=c(5),n=e(m),o=c(78),p=e(o),q=c(83),r=f(q),s=d();s.create=d,r["default"](s),s["default"]=s,b["default"]=s,a.exports=b["default"]},function(a,b){"use strict";b["default"]=function(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b["default"]=a,b},b.__esModule=!0},function(a,b,c){"use strict";function d(a,b,c){this.helpers=a||{},this.partials=b||{},this.decorators=c||{},i.registerDefaultHelpers(this),j.registerDefaultDecorators(this)}var e=c(1)["default"];b.__esModule=!0,b.HandlebarsEnvironment=d;var f=c(5),g=c(6),h=e(g),i=c(10),j=c(70),k=c(72),l=e(k),m=c(73),n="4.7.8";b.VERSION=n;var o=8;b.COMPILER_REVISION=o;var p=7;b.LAST_COMPATIBLE_COMPILER_REVISION=p;var q={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:"== 1.x.x",5:"== 2.0.0-alpha.x",6:">= 2.0.0-beta.1",7:">= 4.0.0 <4.3.0",8:">= 4.3.0"};b.REVISION_CHANGES=q;var r="[object Object]";d.prototype={constructor:d,logger:l["default"],log:l["default"].log,registerHelper:function(a,b){if(f.toString.call(a)===r){if(b)throw new h["default"]("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(f.toString.call(a)===r)f.extend(this.partials,a);else{if("undefined"==typeof b)throw new h["default"]('Attempting to register a partial called "'+a+'" as undefined');this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]},registerDecorator:function(a,b){if(f.toString.call(a)===r){if(b)throw new h["default"]("Arg not supported with multiple decorators");f.extend(this.decorators,a)}else this.decorators[a]=b},unregisterDecorator:function(a){delete this.decorators[a]},resetLoggedPropertyAccesses:function(){m.resetLoggedProperties()}};var s=l["default"].log;b.log=s,b.createFrame=f.createFrame,b.logger=l["default"]},function(a,b){"use strict";function c(a){return k[a]}function d(a){for(var b=1;b":">",'"':""","'":"'","`":"`","=":"="},l=/[&<>"'`=]/g,m=/[&<>"'`=]/,n=Object.prototype.toString;b.toString=n;var o=function(a){return"function"==typeof a};o(/x/)&&(b.isFunction=o=function(a){return"function"==typeof a&&"[object Function]"===n.call(a)}),b.isFunction=o;var p=Array.isArray||function(a){return!(!a||"object"!=typeof a)&&"[object Array]"===n.call(a)};b.isArray=p},function(a,b,c){"use strict";function d(a,b){var c=b&&b.loc,g=void 0,h=void 0,i=void 0,j=void 0;c&&(g=c.start.line,h=c.end.line,i=c.start.column,j=c.end.column,a+=" - "+g+":"+i);for(var k=Error.prototype.constructor.call(this,a),l=0;l0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):e(this);if(c.data&&c.ids){var g=d.createFrame(c.data);g.contextPath=d.appendContextPath(c.data.contextPath,c.name),c={data:g}}return f(b,c)})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(13)["default"],e=c(43)["default"],f=c(55)["default"],g=c(60)["default"],h=c(1)["default"];b.__esModule=!0;var i=c(5),j=c(6),k=h(j);b["default"]=function(a){a.registerHelper("each",function(a,b){function c(b,c,d){n&&(n.key=b,n.index=c,n.first=0===c,n.last=!!d,o&&(n.contextPath=o+b)),m+=h(a[b],{data:n,blockParams:i.blockParams([a[b],b],[o+b,null])})}if(!b)throw new k["default"]("Must pass iterator to #each");var h=b.fn,j=b.inverse,l=0,m="",n=void 0,o=void 0;if(b.data&&b.ids&&(o=i.appendContextPath(b.data.contextPath,b.ids[0])+"."),i.isFunction(a)&&(a=a.call(this)),b.data&&(n=i.createFrame(b.data)),a&&"object"==typeof a)if(i.isArray(a))for(var p=a.length;le;)M(a,c=d[e++],b[c]);return a},O=function(a,b){return void 0===b?x(a):N(x(a),b)},P=function(a){var b=E.call(this,a);return!(b||!f(this,a)||!f(G,a)||f(this,D)&&this[D][a])||b},Q=function(a,b){var c=v(a=t(a),b);return!c||!f(G,b)||f(a,D)&&a[D][b]||(c.enumerable=!0),c},R=function(a){for(var b,c=y(t(a)),d=[],e=0;c.length>e;)f(G,b=c[e++])||b==D||d.push(b);return d},S=function(a){for(var b,c=y(t(a)),d=[],e=0;c.length>e;)f(G,b=c[e++])&&d.push(G[b]);return d},T=function(a){if(void 0!==a&&!L(a)){for(var b,c,d=[a],e=1,f=arguments;f.length>e;)d.push(f[e++]);return b=d[1],"function"==typeof b&&(c=b),!c&&r(b)||(b=function(a,b){if(c&&(b=c.call(this,a,b)),!L(b))return b}),d[1]=b,B.apply(A,d)}},U=j(function(){var a=z();return"[null]"!=B([a])||"{}"!=B({a:a})||"{}"!=B(Object(a))});H||(z=function(){if(L(this))throw TypeError("Symbol is not a constructor");return K(m(arguments.length>0?arguments[0]:void 0))},i(z.prototype,"toString",function(){return this._k}),L=function(a){return a instanceof z},d.create=O,d.isEnum=P,d.getDesc=Q,d.setDesc=M,d.setDescs=N,d.getNames=p.get=R,d.getSymbols=S,g&&!c(41)&&i(I,"propertyIsEnumerable",P,!0));var V={"for":function(a){return f(F,a+="")?F[a]:F[a]=z(a)},keyFor:function(a){return o(F,a)},useSetter:function(){C=!0},useSimple:function(){C=!1}};d.each.call("hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),function(a){var b=n(a);V[a]=H?b:K(b)}),C=!0,h(h.G+h.W,{Symbol:z}),h(h.S,"Symbol",V),h(h.S+h.F*!H,"Object",{create:O,defineProperty:M,defineProperties:N,getOwnPropertyDescriptor:Q,getOwnPropertyNames:R,getOwnPropertySymbols:S}),A&&h(h.S+h.F*(!H||U),"JSON",{stringify:T}),l(z,"Symbol"),l(Math,"Math",!0),l(e.JSON,"JSON",!0)},function(a,b){var c=a.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=c)},function(a,b){var c={}.hasOwnProperty;a.exports=function(a,b){return c.call(a,b)}},function(a,b,c){a.exports=!c(19)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(a,b){a.exports=function(a){try{return!!a()}catch(b){return!0}}},function(a,b,c){var d=c(16),e=c(21),f=c(22),g="prototype",h=function(a,b,c){var i,j,k,l=a&h.F,m=a&h.G,n=a&h.S,o=a&h.P,p=a&h.B,q=a&h.W,r=m?e:e[b]||(e[b]={}),s=m?d:n?d[b]:(d[b]||{})[g];m&&(c=b);for(i in c)j=!l&&s&&i in s,j&&i in r||(k=j?s[i]:c[i],r[i]=m&&"function"!=typeof s[i]?c[i]:p&&j?f(k,d):q&&s[i]==k?function(a){var b=function(b){return this instanceof a?new a(b):a(b)};return b[g]=a[g],b}(k):o&&"function"==typeof k?f(Function.call,k):k,o&&((r[g]||(r[g]={}))[i]=k))};h.F=1,h.G=2,h.S=4,h.P=8,h.B=16,h.W=32,a.exports=h},function(a,b){var c=a.exports={version:"1.2.6"};"number"==typeof __e&&(__e=c)},function(a,b,c){var d=c(23);a.exports=function(a,b,c){if(d(a),void 0===b)return a;switch(c){case 1:return function(c){return a.call(b,c)};case 2:return function(c,d){return a.call(b,c,d)};case 3:return function(c,d,e){return a.call(b,c,d,e)}}return function(){return a.apply(b,arguments)}}},function(a,b){a.exports=function(a){if("function"!=typeof a)throw TypeError(a+" is not a function!");return a}},function(a,b,c){a.exports=c(25)},function(a,b,c){var d=c(9),e=c(26);a.exports=c(18)?function(a,b,c){return d.setDesc(a,b,e(1,c))}:function(a,b,c){return a[b]=c,a}},function(a,b){a.exports=function(a,b){return{enumerable:!(1&a),configurable:!(2&a),writable:!(4&a),value:b}}},function(a,b,c){var d=c(16),e="__core-js_shared__",f=d[e]||(d[e]={});a.exports=function(a){return f[a]||(f[a]={})}},function(a,b,c){var d=c(9).setDesc,e=c(17),f=c(29)("toStringTag");a.exports=function(a,b,c){a&&!e(a=c?a:a.prototype,f)&&d(a,f,{configurable:!0,value:b})}},function(a,b,c){var d=c(27)("wks"),e=c(30),f=c(16).Symbol;a.exports=function(a){return d[a]||(d[a]=f&&f[a]||(f||e)("Symbol."+a))}},function(a,b){var c=0,d=Math.random();a.exports=function(a){return"Symbol(".concat(void 0===a?"":a,")_",(++c+d).toString(36))}},function(a,b,c){var d=c(9),e=c(32);a.exports=function(a,b){for(var c,f=e(a),g=d.getKeys(f),h=g.length,i=0;h>i;)if(f[c=g[i++]]===b)return c}},function(a,b,c){var d=c(33),e=c(35);a.exports=function(a){return d(e(a))}},function(a,b,c){var d=c(34);a.exports=Object("z").propertyIsEnumerable(0)?Object:function(a){return"String"==d(a)?a.split(""):Object(a)}},function(a,b){var c={}.toString;a.exports=function(a){return c.call(a).slice(8,-1)}},function(a,b){a.exports=function(a){if(void 0==a)throw TypeError("Can't call method on "+a);return a}},function(a,b,c){var d=c(32),e=c(9).getNames,f={}.toString,g="object"==typeof window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],h=function(a){try{return e(a)}catch(b){return g.slice()}};a.exports.get=function(a){return g&&"[object Window]"==f.call(a)?h(a):e(d(a))}},function(a,b,c){var d=c(9);a.exports=function(a){var b=d.getKeys(a),c=d.getSymbols;if(c)for(var e,f=c(a),g=d.isEnum,h=0;f.length>h;)g.call(a,e=f[h++])&&b.push(e);return b}},function(a,b,c){var d=c(34);a.exports=Array.isArray||function(a){return"Array"==d(a)}},function(a,b,c){var d=c(40);a.exports=function(a){if(!d(a))throw TypeError(a+" is not an object!");return a}},function(a,b){a.exports=function(a){return"object"==typeof a?null!==a:"function"==typeof a}},function(a,b){a.exports=!0},function(a,b){},function(a,b,c){a.exports={"default":c(44),__esModule:!0}},function(a,b,c){c(45),c(51),a.exports=c(29)("iterator")},function(a,b,c){"use strict";var d=c(46)(!0);c(48)(String,"String",function(a){this._t=String(a),this._i=0},function(){var a,b=this._t,c=this._i;return c>=b.length?{value:void 0,done:!0}:(a=d(b,c),this._i+=a.length,{value:a,done:!1})})},function(a,b,c){var d=c(47),e=c(35);a.exports=function(a){return function(b,c){var f,g,h=String(e(b)),i=d(c),j=h.length;return i<0||i>=j?a?"":void 0:(f=h.charCodeAt(i),f<55296||f>56319||i+1===j||(g=h.charCodeAt(i+1))<56320||g>57343?a?h.charAt(i):f:a?h.slice(i,i+2):(f-55296<<10)+(g-56320)+65536)}}},function(a,b){var c=Math.ceil,d=Math.floor;a.exports=function(a){return isNaN(a=+a)?0:(a>0?d:c)(a)}},function(a,b,c){"use strict";var d=c(41),e=c(20),f=c(24),g=c(25),h=c(17),i=c(49),j=c(50),k=c(28),l=c(9).getProto,m=c(29)("iterator"),n=!([].keys&&"next"in[].keys()),o="@@iterator",p="keys",q="values",r=function(){return this};a.exports=function(a,b,c,s,t,u,v){j(c,b,s);var w,x,y=function(a){if(!n&&a in C)return C[a];switch(a){case p:return function(){return new c(this,a)};case q:return function(){return new c(this,a)}}return function(){return new c(this,a)}},z=b+" Iterator",A=t==q,B=!1,C=a.prototype,D=C[m]||C[o]||t&&C[t],E=D||y(t);if(D){var F=l(E.call(new a));k(F,z,!0),!d&&h(C,o)&&g(F,m,r),A&&D.name!==q&&(B=!0,E=function(){return D.call(this)})}if(d&&!v||!n&&!B&&C[m]||g(C,m,E),i[b]=E,i[z]=r,t)if(w={values:A?E:y(q),keys:u?E:y(p),entries:A?y("entries"):E},v)for(x in w)x in C||f(C,x,w[x]);else e(e.P+e.F*(n||B),b,w);return w}},function(a,b){a.exports={}},function(a,b,c){"use strict";var d=c(9),e=c(26),f=c(28),g={};c(25)(g,c(29)("iterator"),function(){return this}),a.exports=function(a,b,c){a.prototype=d.create(g,{next:e(1,c)}),f(a,b+" Iterator")}},function(a,b,c){c(52);var d=c(49);d.NodeList=d.HTMLCollection=d.Array},function(a,b,c){"use strict";var d=c(53),e=c(54),f=c(49),g=c(32);a.exports=c(48)(Array,"Array",function(a,b){this._t=g(a),this._i=0,this._k=b},function(){var a=this._t,b=this._k,c=this._i++;return!a||c>=a.length?(this._t=void 0,e(1)):"keys"==b?e(0,c):"values"==b?e(0,a[c]):e(0,[c,a[c]])},"values"),f.Arguments=f.Array,d("keys"),d("values"),d("entries")},function(a,b){a.exports=function(){}},function(a,b){a.exports=function(a,b){return{value:b,done:!!a}}},function(a,b,c){a.exports={"default":c(56),__esModule:!0}},function(a,b,c){c(51),c(45),a.exports=c(57)},function(a,b,c){var d=c(39),e=c(58);a.exports=c(21).getIterator=function(a){var b=e(a);if("function"!=typeof b)throw TypeError(a+" is not iterable!");return d(b.call(a))}},function(a,b,c){var d=c(59),e=c(29)("iterator"),f=c(49);a.exports=c(21).getIteratorMethod=function(a){if(void 0!=a)return a[e]||a["@@iterator"]||f[d(a)]}},function(a,b,c){var d=c(34),e=c(29)("toStringTag"),f="Arguments"==d(function(){return arguments}());a.exports=function(a){var b,c,g;return void 0===a?"Undefined":null===a?"Null":"string"==typeof(c=(b=Object(a))[e])?c:f?d(b):"Object"==(g=d(b))&&"function"==typeof b.callee?"Arguments":g}},function(a,b,c){a.exports={"default":c(61),__esModule:!0}},function(a,b,c){c(62),a.exports=c(21).Object.keys},function(a,b,c){var d=c(63);c(64)("keys",function(a){return function(b){return a(d(b))}})},function(a,b,c){var d=c(35);a.exports=function(a){return Object(d(a))}},function(a,b,c){var d=c(20),e=c(21),f=c(19);a.exports=function(a,b){var c=(e.Object||{})[a]||Object[a],g={};g[a]=b(c),d(d.S+d.F*f(function(){c(1)}),"Object",g)}},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(6),f=d(e);b["default"]=function(a){a.registerHelper("helperMissing",function(){if(1!==arguments.length)throw new f["default"]('Missing helper: "'+arguments[arguments.length-1].name+'"')})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(5),f=c(6),g=d(f);b["default"]=function(a){a.registerHelper("if",function(a,b){if(2!=arguments.length)throw new g["default"]("#if requires exactly one argument");return e.isFunction(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||e.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){if(2!=arguments.length)throw new g["default"]("#unless requires exactly one argument");return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})})},a.exports=b["default"]},function(a,b){"use strict";b.__esModule=!0,b["default"]=function(a){a.registerHelper("log",function(){for(var b=[void 0],c=arguments[arguments.length-1],d=0;d=0?b:parseInt(a,10)}return a},log:function(a){if(a=e.lookupLevel(a),"undefined"!=typeof console&&e.lookupLevel(e.level)<=a){var b=e.methodMap[a];console[b]||(b="log");for(var c=arguments.length,d=Array(c>1?c-1:0),f=1;f=v.LAST_COMPATIBLE_COMPILER_REVISION&&b<=v.COMPILER_REVISION)){if(b2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;gb[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substring(a,b.yyleng-c+a)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 15;break;case 1:return 15;case 2:return this.popState(),15;case 3:return this.begin("raw"),15;case 4:return this.popState(),"raw"===this.conditionStack[this.conditionStack.length-1]?15:(e(5,9),"END_RAW_BLOCK");case 5:return 15;case 6:return this.popState(),14;case 7:return 65;case 8:return 68;case 9:return 19;case 10:return this.popState(),this.begin("raw"),23;case 11:return 55;case 12:return 60;case 13:return 29;case 14:return 47;case 15:return this.popState(),44;case 16:return this.popState(),44;case 17:return 34;case 18:return 39;case 19:return 51;case 20:return 48;case 21:this.unput(b.yytext),this.popState(),this.begin("com");break;case 22:return this.popState(),14;case 23:return 48;case 24:return 73;case 25:return 72;case 26:return 72;case 27:return 87;case 28:break;case 29:return this.popState(),54;case 30:return this.popState(),33;case 31:return b.yytext=e(1,2).replace(/\\"/g,'"'),80;case 32:return b.yytext=e(1,2).replace(/\\'/g,"'"),80;case 33:return 85;case 34:return 82;case 35:return 82;case 36:return 83;case 37:return 84;case 38:return 81;case 39:return 75;case 40:return 77;case 41:return 72;case 42:return b.yytext=b.yytext.replace(/\\([\\\]])/g,"$1"),72;case 43:return"INVALID";case 44:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{(?=[^/]))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]+?(?=(\{\{\{\{)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#>)/,/^(?:\{\{(~)?#\*?)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?\*?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[(\\\]|[^\]])*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[6],inclusive:!1},raw:{rules:[3,4,5],inclusive:!1},INITIAL:{rules:[0,1,44],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(){var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.options=a}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"ContentStatement"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"ContentStatement"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"ContentStatement"===d.type&&(c||!d.rightStripped)){var e=d.value;d.value=d.value.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.value!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"ContentStatement"===d.type&&(c||!d.leftStripped)){var e=d.value;return d.value=d.value.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.value!==e,d.leftStripped}}var i=c(1)["default"];b.__esModule=!0;var j=c(88),k=i(j);d.prototype=new k["default"],d.prototype.Program=function(a){var b=!this.options.ignoreStandalone,c=!this.isRootSeen;this.isRootSeen=!0;for(var d=a.body,i=0,j=d.length;i0)throw new q["default"]("Invalid path: "+d,{loc:c});".."===i&&f++}}return{type:"PathExpression",data:a,depth:f,parts:e,original:d,loc:c}}function j(a,b,c,d,e,f){var g=d.charAt(3)||d.charAt(2),h="{"!==g&&"&"!==g,i=/\*/.test(d);return{type:i?"Decorator":"MustacheStatement",path:a,params:b,hash:c,escaped:h,strip:e,loc:this.locInfo(f)}}function k(a,b,c,e){d(a,c),e=this.locInfo(e);var f={type:"Program",body:b,strip:{},loc:e};return{type:"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:f,openStrip:{},inverseStrip:{},closeStrip:{},loc:e}}function l(a,b,c,e,f,g){e&&e.path&&d(a,e);var h=/\*/.test(a.open);b.blockParams=a.blockParams;var i=void 0,j=void 0;if(c){if(h)throw new q["default"]("Unexpected inverse block on decorator",c);c.chain&&(c.program.body[0].closeStrip=e.strip),j=c.strip,i=c.program}return f&&(f=i,i=b,b=f),{type:h?"DecoratorBlock":"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:b,inverse:i,openStrip:a.strip,inverseStrip:j,closeStrip:e&&e.strip,loc:this.locInfo(g)}}function m(a,b){if(!b&&a.length){var c=a[0].loc,d=a[a.length-1].loc;c&&d&&(b={source:c.source,start:{line:c.start.line,column:c.start.column},end:{line:d.end.line,column:d.end.column}})}return{type:"Program",body:a,strip:{},loc:b}}function n(a,b,c,e){return d(a,c),{type:"PartialBlockStatement",name:a.path,params:a.params,hash:a.hash,program:b,openStrip:a.strip,closeStrip:c&&c.strip,loc:this.locInfo(e)}}var o=c(1)["default"];b.__esModule=!0,b.SourceLocation=e,b.id=f,b.stripFlags=g,b.stripComment=h,b.preparePath=i,b.prepareMustache=j,b.prepareRawBlock=k,b.prepareBlock=l,b.prepareProgram=m,b.preparePartialBlock=n;var p=c(6),q=o(p)},function(a,b,c){"use strict";function d(){}function e(a,b,c){if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new l["default"]("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a,b),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function f(a,b,c){function d(){var d=c.parse(a,b),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}function e(a,b){return f||(f=d()),f.call(this,a,b)}if(void 0===b&&(b={}),null==a||"string"!=typeof a&&"Program"!==a.type)throw new l["default"]("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);b=m.extend({},b),"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var f=void 0;return e._setup=function(a){return f||(f=d()),f._setup(a)},e._child=function(a,b,c,e){return f||(f=d()),f._child(a,b,c,e)},e}function g(a,b){if(a===b)return!0;if(m.isArray(a)&&m.isArray(b)&&a.length===b.length){for(var c=0;c1)throw new l["default"]("Unsupported number of partial arguments: "+c.length,a);c.length||(this.options.explicitPartialContext?this.opcode("pushLiteral","undefined"):c.push({type:"PathExpression",parts:[],depth:0}));var d=a.name.original,e="SubExpression"===a.name.type;e&&this.accept(a.name),this.setupFullMustacheParams(a,b,void 0,!0);var f=a.indent||"";this.options.preventIndent&&f&&(this.opcode("appendContent",f),f=""),this.opcode("invokePartial",e,d,f),this.opcode("append")},PartialBlockStatement:function(a){this.PartialStatement(a)},MustacheStatement:function(a){this.SubExpression(a),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},Decorator:function(a){this.DecoratorBlock(a)},ContentStatement:function(a){a.value&&this.opcode("appendContent",a.value)},CommentStatement:function(){},SubExpression:function(a){h(a);var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ambiguousSexpr:function(a,b,c){var d=a.path,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),d.strict=!0,this.accept(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.path;b.strict=!0,this.accept(b),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.path,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new l["default"]("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.strict=!0,e.falsy=!0,this.accept(e),this.opcode("invokeHelper",d.length,e.original,o["default"].helpers.simpleId(e))}},PathExpression:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0],c=o["default"].helpers.scopedId(a),d=!a.depth&&!c&&this.blockParamIndex(b);d?this.opcode("lookupBlockParam",d,a.parts):b?a.data?(this.options.data=!0,this.opcode("lookupData",a.depth,a.parts,a.strict)):this.opcode("lookupOnContext",a.parts,a.falsy,a.strict,c):this.opcode("pushContext")},StringLiteral:function(a){this.opcode("pushString",a.value)},NumberLiteral:function(a){this.opcode("pushLiteral",a.value)},BooleanLiteral:function(a){this.opcode("pushLiteral",a.value)},UndefinedLiteral:function(){this.opcode("pushLiteral","undefined")},NullLiteral:function(){this.opcode("pushLiteral","null")},Hash:function(a){var b=a.pairs,c=0,d=b.length;for(this.opcode("pushHash");c=0)return[b,e]}}}},function(a,b,c){"use strict";function d(a){this.value=a}function e(){}function f(a,b,c,d,e){var f=b.popStack(),g=c.length;for(a&&g--;d0&&(c+=", "+d.join(", "));var e=0;g(this.aliases).forEach(function(a){var d=b.aliases[a];d.children&&d.referenceCount>1&&(c+=", alias"+ ++e+"="+a,d.children[0]="alias"+e)}),this.lookupPropertyFunctionIsUsed&&(c+=", "+this.lookupPropertyFunctionVarDeclaration());var f=["container","depth0","helpers","partials","data"];(this.useBlockParams||this.useDepths)&&f.push("blockParams"),this.useDepths&&f.push("depths");var h=this.mergeSource(c);return a?(f.push(h),Function.apply(this,f)):this.source.wrap(["function(",f.join(","),") {\n ",h,"}"])},mergeSource:function(a){var b=this.environment.isSimple,c=!this.forceBuffer,d=void 0,e=void 0,f=void 0,g=void 0;return this.source.each(function(a){a.appendToBuffer?(f?a.prepend(" + "):f=a,g=a):(f&&(e?f.prepend("buffer += "):d=!0,g.add(";"),f=g=void 0),e=!0,b||(c=!1))}),c?f?(f.prepend("return "),g.add(";")):e||this.source.push('return "";'):(a+=", buffer = "+(d?"":this.initializeBuffer()),f?(f.prepend("return buffer + "),g.add(";")):this.source.push("return buffer;")),a&&this.source.prepend("var "+a.substring(2)+(d?"":";\n")),this.source.merge()},lookupPropertyFunctionVarDeclaration:function(){return"\n lookupProperty = container.lookupProperty || function(parent, propertyName) {\n if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {\n return parent[propertyName];\n }\n return undefined\n }\n ".trim()},blockValue:function(a){var b=this.aliasable("container.hooks.blockHelperMissing"),c=[this.contextName(0)];this.setupHelperArgs(a,0,c);var d=this.popStack();c.splice(1,0,d),this.push(this.source.functionCall(b,"call",c))},ambiguousBlockValue:function(){var a=this.aliasable("container.hooks.blockHelperMissing"),b=[this.contextName(0)];this.setupHelperArgs("",0,b,!0),this.flushInline();var c=this.topStack();b.splice(1,0,c),this.pushSource(["if (!",this.lastHelper,") { ",c," = ",this.source.functionCall(a,"call",b),"}"])},appendContent:function(a){this.pendingContent?a=this.pendingContent+a:this.pendingLocation=this.source.currentLocation,this.pendingContent=a},append:function(){if(this.isInline())this.replaceStack(function(a){return[" != null ? ",a,' : ""']}),this.pushSource(this.appendToBuffer(this.popStack()));else{var a=this.popStack();this.pushSource(["if (",a," != null) { ",this.appendToBuffer(a,void 0,!0)," }"]),this.environment.isSimple&&this.pushSource(["else { ",this.appendToBuffer("''",void 0,!0)," }"])}},appendEscaped:function(){this.pushSource(this.appendToBuffer([this.aliasable("container.escapeExpression"),"(",this.popStack(),")"]))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c,d){var e=0;d||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[e++])),this.resolvePath("context",a,e,b,c)},lookupBlockParam:function(a,b){this.useBlockParams=!0,this.push(["blockParams[",a[0],"][",a[1],"]"]),this.resolvePath("context",b,1)},lookupData:function(a,b,c){a?this.pushStackLiteral("container.data(data, "+a+")"):this.pushStackLiteral("data"),this.resolvePath("data",b,0,!0,c)},resolvePath:function(a,b,c,d,e){var g=this;if(this.options.strict||this.options.assumeObjects)return void this.push(f(this.options.strict&&e,this,b,c,a));for(var h=b.length;cthis.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;this.inlineStack=[];for(var b=0,c=a.length;b= 2.0.0-beta.1', + 7: '>= 4.0.0 <4.3.0', + 8: '>= 4.3.0' + }; + + exports.REVISION_CHANGES = REVISION_CHANGES; + var objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials, decorators) { + this.helpers = helpers || {}; + this.partials = partials || {}; + this.decorators = decorators || {}; + + _helpers.registerDefaultHelpers(this); + _decorators.registerDefaultDecorators(this); + } + + HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: _logger2['default'], + log: _logger2['default'].log, + + registerHelper: function registerHelper(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple helpers'); + } + _utils.extend(this.helpers, name); + } else { + this.helpers[name] = fn; + } + }, + unregisterHelper: function unregisterHelper(name) { + delete this.helpers[name]; + }, + + registerPartial: function registerPartial(name, partial) { + if (_utils.toString.call(name) === objectType) { + _utils.extend(this.partials, name); + } else { + if (typeof partial === 'undefined') { + throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); + } + this.partials[name] = partial; + } + }, + unregisterPartial: function unregisterPartial(name) { + delete this.partials[name]; + }, + + registerDecorator: function registerDecorator(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple decorators'); + } + _utils.extend(this.decorators, name); + } else { + this.decorators[name] = fn; + } + }, + unregisterDecorator: function unregisterDecorator(name) { + delete this.decorators[name]; + }, + /** + * Reset the memory of illegal property accesses that have already been logged. + * @deprecated should only be used in handlebars test-cases + */ + resetLoggedPropertyAccesses: function resetLoggedPropertyAccesses() { + _internalProtoAccess.resetLoggedProperties(); + } + }; + + var log = _logger2['default'].log; + + exports.log = log; + exports.createFrame = _utils.createFrame; + exports.logger = _logger2['default']; + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.extend = extend; + exports.indexOf = indexOf; + exports.escapeExpression = escapeExpression; + exports.isEmpty = isEmpty; + exports.createFrame = createFrame; + exports.blockParams = blockParams; + exports.appendContextPath = appendContextPath; + var escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', + '=': '=' + }; + + var badChars = /[&<>"'`=]/g, + possible = /[&<>"'`=]/; + + function escapeChar(chr) { + return escape[chr]; + } + + function extend(obj /* , ...source */) { + for (var i = 1; i < arguments.length; i++) { + for (var key in arguments[i]) { + if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { + obj[key] = arguments[i][key]; + } + } + } + + return obj; + } + + var toString = Object.prototype.toString; + + exports.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + /* eslint-disable func-style */ + var isFunction = function isFunction(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + /* istanbul ignore next */ + if (isFunction(/x/)) { + exports.isFunction = isFunction = function (value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + exports.isFunction = isFunction; + + /* eslint-enable func-style */ + + /* istanbul ignore next */ + var isArray = Array.isArray || function (value) { + return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; + }; + + exports.isArray = isArray; + // Older IE versions do not directly support indexOf so we must implement our own, sadly. + + function indexOf(array, value) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + return -1; + } + + function escapeExpression(string) { + if (typeof string !== 'string') { + // don't escape SafeStrings, since they're already safe + if (string && string.toHTML) { + return string.toHTML(); + } else if (string == null) { + return ''; + } else if (!string) { + return string + ''; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = '' + string; + } + + if (!possible.test(string)) { + return string; + } + return string.replace(badChars, escapeChar); + } + + function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + function createFrame(object) { + var frame = extend({}, object); + frame._parent = object; + return frame; + } + + function blockParams(params, ids) { + params.path = ids; + return params; + } + + function appendContextPath(contextPath, id) { + return (contextPath ? contextPath + '.' : '') + id; + } + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$defineProperty = __webpack_require__(7)['default']; + + exports.__esModule = true; + var errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var loc = node && node.loc, + line = undefined, + endLineNumber = undefined, + column = undefined, + endColumn = undefined; + + if (loc) { + line = loc.start.line; + endLineNumber = loc.end.line; + column = loc.start.column; + endColumn = loc.end.column; + + message += ' - ' + line + ':' + column; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + /* istanbul ignore else */ + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Exception); + } + + try { + if (loc) { + this.lineNumber = line; + this.endLineNumber = endLineNumber; + + // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ + if (_Object$defineProperty) { + Object.defineProperty(this, 'column', { + value: column, + enumerable: true + }); + Object.defineProperty(this, 'endColumn', { + value: endColumn, + enumerable: true + }); + } else { + this.column = column; + this.endColumn = endColumn; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ + } + } + + Exception.prototype = new Error(); + + exports['default'] = Exception; + module.exports = exports['default']; + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(8), __esModule: true }; + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9); + module.exports = function defineProperty(it, key, desc){ + return $.setDesc(it, key, desc); + }; + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + var $Object = Object; + module.exports = { + create: $Object.create, + getProto: $Object.getPrototypeOf, + isEnum: {}.propertyIsEnumerable, + getDesc: $Object.getOwnPropertyDescriptor, + setDesc: $Object.defineProperty, + setDescs: $Object.defineProperties, + getKeys: $Object.keys, + getNames: $Object.getOwnPropertyNames, + getSymbols: $Object.getOwnPropertySymbols, + each: [].forEach + }; + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultHelpers = registerDefaultHelpers; + exports.moveHelperToHooks = moveHelperToHooks; + + var _helpersBlockHelperMissing = __webpack_require__(11); + + var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); + + var _helpersEach = __webpack_require__(12); + + var _helpersEach2 = _interopRequireDefault(_helpersEach); + + var _helpersHelperMissing = __webpack_require__(65); + + var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); + + var _helpersIf = __webpack_require__(66); + + var _helpersIf2 = _interopRequireDefault(_helpersIf); + + var _helpersLog = __webpack_require__(67); + + var _helpersLog2 = _interopRequireDefault(_helpersLog); + + var _helpersLookup = __webpack_require__(68); + + var _helpersLookup2 = _interopRequireDefault(_helpersLookup); + + var _helpersWith = __webpack_require__(69); + + var _helpersWith2 = _interopRequireDefault(_helpersWith); + + function registerDefaultHelpers(instance) { + _helpersBlockHelperMissing2['default'](instance); + _helpersEach2['default'](instance); + _helpersHelperMissing2['default'](instance); + _helpersIf2['default'](instance); + _helpersLog2['default'](instance); + _helpersLookup2['default'](instance); + _helpersWith2['default'](instance); + } + + function moveHelperToHooks(instance, helperName, keepHelper) { + if (instance.helpers[helperName]) { + instance.hooks[helperName] = instance.helpers[helperName]; + if (!keepHelper) { + delete instance.helpers[helperName]; + } + } + } + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerHelper('blockHelperMissing', function (context, options) { + var inverse = options.inverse, + fn = options.fn; + + if (context === true) { + return fn(this); + } else if (context === false || context == null) { + return inverse(this); + } else if (_utils.isArray(context)) { + if (context.length > 0) { + if (options.ids) { + options.ids = [options.name]; + } + + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + if (options.data && options.ids) { + var data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); + options = { data: data }; + } + + return fn(context, options); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Symbol = __webpack_require__(13)['default']; + + var _Symbol$iterator = __webpack_require__(43)['default']; + + var _getIterator = __webpack_require__(55)['default']; + + var _Object$keys = __webpack_require__(60)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('each', function (context, options) { + if (!options) { + throw new _exception2['default']('Must pass iterator to #each'); + } + + var fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data = undefined, + contextPath = undefined; + + if (options.data && options.ids) { + contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; + } + + if (_utils.isFunction(context)) { + context = context.call(this); + } + + if (options.data) { + data = _utils.createFrame(options.data); + } + + function execIteration(field, index, last) { + if (data) { + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + field; + } + } + + ret = ret + fn(context[field], { + data: data, + blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) + }); + } + + if (context && typeof context === 'object') { + if (_utils.isArray(context)) { + for (var j = context.length; i < j; i++) { + if (i in context) { + execIteration(i, i, i === context.length - 1); + } + } + } else if (typeof _Symbol === 'function' && context[_Symbol$iterator]) { + var newContext = []; + var iterator = _getIterator(context); + for (var it = iterator.next(); !it.done; it = iterator.next()) { + newContext.push(it.value); + } + context = newContext; + for (var j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); + } + } else { + (function () { + var priorKey = undefined; + + _Object$keys(context).forEach(function (key) { + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey !== undefined) { + execIteration(priorKey, i - 1); + } + priorKey = key; + i++; + }); + if (priorKey !== undefined) { + execIteration(priorKey, i - 1, true); + } + })(); + } + } + + if (i === 0) { + ret = inverse(this); + } + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(14), __esModule: true }; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(15); + __webpack_require__(42); + module.exports = __webpack_require__(21).Symbol; + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + // ECMAScript 6 symbols shim + var $ = __webpack_require__(9) + , global = __webpack_require__(16) + , has = __webpack_require__(17) + , DESCRIPTORS = __webpack_require__(18) + , $export = __webpack_require__(20) + , redefine = __webpack_require__(24) + , $fails = __webpack_require__(19) + , shared = __webpack_require__(27) + , setToStringTag = __webpack_require__(28) + , uid = __webpack_require__(30) + , wks = __webpack_require__(29) + , keyOf = __webpack_require__(31) + , $names = __webpack_require__(36) + , enumKeys = __webpack_require__(37) + , isArray = __webpack_require__(38) + , anObject = __webpack_require__(39) + , toIObject = __webpack_require__(32) + , createDesc = __webpack_require__(26) + , getDesc = $.getDesc + , setDesc = $.setDesc + , _create = $.create + , getNames = $names.get + , $Symbol = global.Symbol + , $JSON = global.JSON + , _stringify = $JSON && $JSON.stringify + , setter = false + , HIDDEN = wks('_hidden') + , isEnum = $.isEnum + , SymbolRegistry = shared('symbol-registry') + , AllSymbols = shared('symbols') + , useNative = typeof $Symbol == 'function' + , ObjectProto = Object.prototype; + + // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 + var setSymbolDesc = DESCRIPTORS && $fails(function(){ + return _create(setDesc({}, 'a', { + get: function(){ return setDesc(this, 'a', {value: 7}).a; } + })).a != 7; + }) ? function(it, key, D){ + var protoDesc = getDesc(ObjectProto, key); + if(protoDesc)delete ObjectProto[key]; + setDesc(it, key, D); + if(protoDesc && it !== ObjectProto)setDesc(ObjectProto, key, protoDesc); + } : setDesc; + + var wrap = function(tag){ + var sym = AllSymbols[tag] = _create($Symbol.prototype); + sym._k = tag; + DESCRIPTORS && setter && setSymbolDesc(ObjectProto, tag, { + configurable: true, + set: function(value){ + if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false; + setSymbolDesc(this, tag, createDesc(1, value)); + } + }); + return sym; + }; + + var isSymbol = function(it){ + return typeof it == 'symbol'; + }; + + var $defineProperty = function defineProperty(it, key, D){ + if(D && has(AllSymbols, key)){ + if(!D.enumerable){ + if(!has(it, HIDDEN))setDesc(it, HIDDEN, createDesc(1, {})); + it[HIDDEN][key] = true; + } else { + if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false; + D = _create(D, {enumerable: createDesc(0, false)}); + } return setSymbolDesc(it, key, D); + } return setDesc(it, key, D); + }; + var $defineProperties = function defineProperties(it, P){ + anObject(it); + var keys = enumKeys(P = toIObject(P)) + , i = 0 + , l = keys.length + , key; + while(l > i)$defineProperty(it, key = keys[i++], P[key]); + return it; + }; + var $create = function create(it, P){ + return P === undefined ? _create(it) : $defineProperties(_create(it), P); + }; + var $propertyIsEnumerable = function propertyIsEnumerable(key){ + var E = isEnum.call(this, key); + return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] + ? E : true; + }; + var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){ + var D = getDesc(it = toIObject(it), key); + if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true; + return D; + }; + var $getOwnPropertyNames = function getOwnPropertyNames(it){ + var names = getNames(toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i)if(!has(AllSymbols, key = names[i++]) && key != HIDDEN)result.push(key); + return result; + }; + var $getOwnPropertySymbols = function getOwnPropertySymbols(it){ + var names = getNames(toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i)if(has(AllSymbols, key = names[i++]))result.push(AllSymbols[key]); + return result; + }; + var $stringify = function stringify(it){ + if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined + var args = [it] + , i = 1 + , $$ = arguments + , replacer, $replacer; + while($$.length > i)args.push($$[i++]); + replacer = args[1]; + if(typeof replacer == 'function')$replacer = replacer; + if($replacer || !isArray(replacer))replacer = function(key, value){ + if($replacer)value = $replacer.call(this, key, value); + if(!isSymbol(value))return value; + }; + args[1] = replacer; + return _stringify.apply($JSON, args); + }; + var buggyJSON = $fails(function(){ + var S = $Symbol(); + // MS Edge converts symbol values to JSON as {} + // WebKit converts symbol values to JSON as null + // V8 throws on boxed symbols + return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}'; + }); + + // 19.4.1.1 Symbol([description]) + if(!useNative){ + $Symbol = function Symbol(){ + if(isSymbol(this))throw TypeError('Symbol is not a constructor'); + return wrap(uid(arguments.length > 0 ? arguments[0] : undefined)); + }; + redefine($Symbol.prototype, 'toString', function toString(){ + return this._k; + }); + + isSymbol = function(it){ + return it instanceof $Symbol; + }; + + $.create = $create; + $.isEnum = $propertyIsEnumerable; + $.getDesc = $getOwnPropertyDescriptor; + $.setDesc = $defineProperty; + $.setDescs = $defineProperties; + $.getNames = $names.get = $getOwnPropertyNames; + $.getSymbols = $getOwnPropertySymbols; + + if(DESCRIPTORS && !__webpack_require__(41)){ + redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true); + } + } + + var symbolStatics = { + // 19.4.2.1 Symbol.for(key) + 'for': function(key){ + return has(SymbolRegistry, key += '') + ? SymbolRegistry[key] + : SymbolRegistry[key] = $Symbol(key); + }, + // 19.4.2.5 Symbol.keyFor(sym) + keyFor: function keyFor(key){ + return keyOf(SymbolRegistry, key); + }, + useSetter: function(){ setter = true; }, + useSimple: function(){ setter = false; } + }; + // 19.4.2.2 Symbol.hasInstance + // 19.4.2.3 Symbol.isConcatSpreadable + // 19.4.2.4 Symbol.iterator + // 19.4.2.6 Symbol.match + // 19.4.2.8 Symbol.replace + // 19.4.2.9 Symbol.search + // 19.4.2.10 Symbol.species + // 19.4.2.11 Symbol.split + // 19.4.2.12 Symbol.toPrimitive + // 19.4.2.13 Symbol.toStringTag + // 19.4.2.14 Symbol.unscopables + $.each.call(( + 'hasInstance,isConcatSpreadable,iterator,match,replace,search,' + + 'species,split,toPrimitive,toStringTag,unscopables' + ).split(','), function(it){ + var sym = wks(it); + symbolStatics[it] = useNative ? sym : wrap(sym); + }); + + setter = true; + + $export($export.G + $export.W, {Symbol: $Symbol}); + + $export($export.S, 'Symbol', symbolStatics); + + $export($export.S + $export.F * !useNative, 'Object', { + // 19.1.2.2 Object.create(O [, Properties]) + create: $create, + // 19.1.2.4 Object.defineProperty(O, P, Attributes) + defineProperty: $defineProperty, + // 19.1.2.3 Object.defineProperties(O, Properties) + defineProperties: $defineProperties, + // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) + getOwnPropertyDescriptor: $getOwnPropertyDescriptor, + // 19.1.2.7 Object.getOwnPropertyNames(O) + getOwnPropertyNames: $getOwnPropertyNames, + // 19.1.2.8 Object.getOwnPropertySymbols(O) + getOwnPropertySymbols: $getOwnPropertySymbols + }); + + // 24.3.2 JSON.stringify(value [, replacer [, space]]) + $JSON && $export($export.S + $export.F * (!useNative || buggyJSON), 'JSON', {stringify: $stringify}); + + // 19.4.3.5 Symbol.prototype[@@toStringTag] + setToStringTag($Symbol, 'Symbol'); + // 20.2.1.9 Math[@@toStringTag] + setToStringTag(Math, 'Math', true); + // 24.3.3 JSON[@@toStringTag] + setToStringTag(global.JSON, 'JSON', true); + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); + if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef + +/***/ }), +/* 17 */ +/***/ (function(module, exports) { + + var hasOwnProperty = {}.hasOwnProperty; + module.exports = function(it, key){ + return hasOwnProperty.call(it, key); + }; + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + + // Thank's IE8 for his funny defineProperty + module.exports = !__webpack_require__(19)(function(){ + return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; + }); + +/***/ }), +/* 19 */ +/***/ (function(module, exports) { + + module.exports = function(exec){ + try { + return !!exec(); + } catch(e){ + return true; + } + }; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(16) + , core = __webpack_require__(21) + , ctx = __webpack_require__(22) + , PROTOTYPE = 'prototype'; + + var $export = function(type, name, source){ + var IS_FORCED = type & $export.F + , IS_GLOBAL = type & $export.G + , IS_STATIC = type & $export.S + , IS_PROTO = type & $export.P + , IS_BIND = type & $export.B + , IS_WRAP = type & $export.W + , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) + , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] + , key, own, out; + if(IS_GLOBAL)source = name; + for(key in source){ + // contains in native + own = !IS_FORCED && target && key in target; + if(own && key in exports)continue; + // export native or passed + out = own ? target[key] : source[key]; + // prevent global pollution for namespaces + exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] + // bind timers to global for call from export context + : IS_BIND && own ? ctx(out, global) + // wrap global constructors for prevent change them in library + : IS_WRAP && target[key] == out ? (function(C){ + var F = function(param){ + return this instanceof C ? new C(param) : C(param); + }; + F[PROTOTYPE] = C[PROTOTYPE]; + return F; + // make static versions for prototype methods + })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; + } + }; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + module.exports = $export; + +/***/ }), +/* 21 */ +/***/ (function(module, exports) { + + var core = module.exports = {version: '1.2.6'}; + if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + + // optional / simple context binding + var aFunction = __webpack_require__(23); + module.exports = function(fn, that, length){ + aFunction(fn); + if(that === undefined)return fn; + switch(length){ + case 1: return function(a){ + return fn.call(that, a); + }; + case 2: return function(a, b){ + return fn.call(that, a, b); + }; + case 3: return function(a, b, c){ + return fn.call(that, a, b, c); + }; + } + return function(/* ...args */){ + return fn.apply(that, arguments); + }; + }; + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + if(typeof it != 'function')throw TypeError(it + ' is not a function!'); + return it; + }; + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(25); + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9) + , createDesc = __webpack_require__(26); + module.exports = __webpack_require__(18) ? function(object, key, value){ + return $.setDesc(object, key, createDesc(1, value)); + } : function(object, key, value){ + object[key] = value; + return object; + }; + +/***/ }), +/* 26 */ +/***/ (function(module, exports) { + + module.exports = function(bitmap, value){ + return { + enumerable : !(bitmap & 1), + configurable: !(bitmap & 2), + writable : !(bitmap & 4), + value : value + }; + }; + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(16) + , SHARED = '__core-js_shared__' + , store = global[SHARED] || (global[SHARED] = {}); + module.exports = function(key){ + return store[key] || (store[key] = {}); + }; + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + + var def = __webpack_require__(9).setDesc + , has = __webpack_require__(17) + , TAG = __webpack_require__(29)('toStringTag'); + + module.exports = function(it, tag, stat){ + if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); + }; + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + + var store = __webpack_require__(27)('wks') + , uid = __webpack_require__(30) + , Symbol = __webpack_require__(16).Symbol; + module.exports = function(name){ + return store[name] || (store[name] = + Symbol && Symbol[name] || (Symbol || uid)('Symbol.' + name)); + }; + +/***/ }), +/* 30 */ +/***/ (function(module, exports) { + + var id = 0 + , px = Math.random(); + module.exports = function(key){ + return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); + }; + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9) + , toIObject = __webpack_require__(32); + module.exports = function(object, el){ + var O = toIObject(object) + , keys = $.getKeys(O) + , length = keys.length + , index = 0 + , key; + while(length > index)if(O[key = keys[index++]] === el)return key; + }; + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + + // to indexed object, toObject with fallback for non-array-like ES3 strings + var IObject = __webpack_require__(33) + , defined = __webpack_require__(35); + module.exports = function(it){ + return IObject(defined(it)); + }; + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + + // fallback for non-array-like ES3 and non-enumerable old V8 strings + var cof = __webpack_require__(34); + module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ + return cof(it) == 'String' ? it.split('') : Object(it); + }; + +/***/ }), +/* 34 */ +/***/ (function(module, exports) { + + var toString = {}.toString; + + module.exports = function(it){ + return toString.call(it).slice(8, -1); + }; + +/***/ }), +/* 35 */ +/***/ (function(module, exports) { + + // 7.2.1 RequireObjectCoercible(argument) + module.exports = function(it){ + if(it == undefined)throw TypeError("Can't call method on " + it); + return it; + }; + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + + // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window + var toIObject = __webpack_require__(32) + , getNames = __webpack_require__(9).getNames + , toString = {}.toString; + + var windowNames = typeof window == 'object' && Object.getOwnPropertyNames + ? Object.getOwnPropertyNames(window) : []; + + var getWindowNames = function(it){ + try { + return getNames(it); + } catch(e){ + return windowNames.slice(); + } + }; + + module.exports.get = function getOwnPropertyNames(it){ + if(windowNames && toString.call(it) == '[object Window]')return getWindowNames(it); + return getNames(toIObject(it)); + }; + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + + // all enumerable object keys, includes symbols + var $ = __webpack_require__(9); + module.exports = function(it){ + var keys = $.getKeys(it) + , getSymbols = $.getSymbols; + if(getSymbols){ + var symbols = getSymbols(it) + , isEnum = $.isEnum + , i = 0 + , key; + while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))keys.push(key); + } + return keys; + }; + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + + // 7.2.2 IsArray(argument) + var cof = __webpack_require__(34); + module.exports = Array.isArray || function(arg){ + return cof(arg) == 'Array'; + }; + +/***/ }), +/* 39 */ +/***/ (function(module, exports, __webpack_require__) { + + var isObject = __webpack_require__(40); + module.exports = function(it){ + if(!isObject(it))throw TypeError(it + ' is not an object!'); + return it; + }; + +/***/ }), +/* 40 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + return typeof it === 'object' ? it !== null : typeof it === 'function'; + }; + +/***/ }), +/* 41 */ +/***/ (function(module, exports) { + + module.exports = true; + +/***/ }), +/* 42 */ +/***/ (function(module, exports) { + + + +/***/ }), +/* 43 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(44), __esModule: true }; + +/***/ }), +/* 44 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(45); + __webpack_require__(51); + module.exports = __webpack_require__(29)('iterator'); + +/***/ }), +/* 45 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var $at = __webpack_require__(46)(true); + + // 21.1.3.27 String.prototype[@@iterator]() + __webpack_require__(48)(String, 'String', function(iterated){ + this._t = String(iterated); // target + this._i = 0; // next index + // 21.1.5.2.1 %StringIteratorPrototype%.next() + }, function(){ + var O = this._t + , index = this._i + , point; + if(index >= O.length)return {value: undefined, done: true}; + point = $at(O, index); + this._i += point.length; + return {value: point, done: false}; + }); + +/***/ }), +/* 46 */ +/***/ (function(module, exports, __webpack_require__) { + + var toInteger = __webpack_require__(47) + , defined = __webpack_require__(35); + // true -> String#at + // false -> String#codePointAt + module.exports = function(TO_STRING){ + return function(that, pos){ + var s = String(defined(that)) + , i = toInteger(pos) + , l = s.length + , a, b; + if(i < 0 || i >= l)return TO_STRING ? '' : undefined; + a = s.charCodeAt(i); + return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff + ? TO_STRING ? s.charAt(i) : a + : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; + }; + }; + +/***/ }), +/* 47 */ +/***/ (function(module, exports) { + + // 7.1.4 ToInteger + var ceil = Math.ceil + , floor = Math.floor; + module.exports = function(it){ + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); + }; + +/***/ }), +/* 48 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var LIBRARY = __webpack_require__(41) + , $export = __webpack_require__(20) + , redefine = __webpack_require__(24) + , hide = __webpack_require__(25) + , has = __webpack_require__(17) + , Iterators = __webpack_require__(49) + , $iterCreate = __webpack_require__(50) + , setToStringTag = __webpack_require__(28) + , getProto = __webpack_require__(9).getProto + , ITERATOR = __webpack_require__(29)('iterator') + , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next` + , FF_ITERATOR = '@@iterator' + , KEYS = 'keys' + , VALUES = 'values'; + + var returnThis = function(){ return this; }; + + module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){ + $iterCreate(Constructor, NAME, next); + var getMethod = function(kind){ + if(!BUGGY && kind in proto)return proto[kind]; + switch(kind){ + case KEYS: return function keys(){ return new Constructor(this, kind); }; + case VALUES: return function values(){ return new Constructor(this, kind); }; + } return function entries(){ return new Constructor(this, kind); }; + }; + var TAG = NAME + ' Iterator' + , DEF_VALUES = DEFAULT == VALUES + , VALUES_BUG = false + , proto = Base.prototype + , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT] + , $default = $native || getMethod(DEFAULT) + , methods, key; + // Fix native + if($native){ + var IteratorPrototype = getProto($default.call(new Base)); + // Set @@toStringTag to native iterators + setToStringTag(IteratorPrototype, TAG, true); + // FF fix + if(!LIBRARY && has(proto, FF_ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis); + // fix Array#{values, @@iterator}.name in V8 / FF + if(DEF_VALUES && $native.name !== VALUES){ + VALUES_BUG = true; + $default = function values(){ return $native.call(this); }; + } + } + // Define iterator + if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){ + hide(proto, ITERATOR, $default); + } + // Plug for library + Iterators[NAME] = $default; + Iterators[TAG] = returnThis; + if(DEFAULT){ + methods = { + values: DEF_VALUES ? $default : getMethod(VALUES), + keys: IS_SET ? $default : getMethod(KEYS), + entries: !DEF_VALUES ? $default : getMethod('entries') + }; + if(FORCED)for(key in methods){ + if(!(key in proto))redefine(proto, key, methods[key]); + } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); + } + return methods; + }; + +/***/ }), +/* 49 */ +/***/ (function(module, exports) { + + module.exports = {}; + +/***/ }), +/* 50 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var $ = __webpack_require__(9) + , descriptor = __webpack_require__(26) + , setToStringTag = __webpack_require__(28) + , IteratorPrototype = {}; + + // 25.1.2.1.1 %IteratorPrototype%[@@iterator]() + __webpack_require__(25)(IteratorPrototype, __webpack_require__(29)('iterator'), function(){ return this; }); + + module.exports = function(Constructor, NAME, next){ + Constructor.prototype = $.create(IteratorPrototype, {next: descriptor(1, next)}); + setToStringTag(Constructor, NAME + ' Iterator'); + }; + +/***/ }), +/* 51 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(52); + var Iterators = __webpack_require__(49); + Iterators.NodeList = Iterators.HTMLCollection = Iterators.Array; + +/***/ }), +/* 52 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + var addToUnscopables = __webpack_require__(53) + , step = __webpack_require__(54) + , Iterators = __webpack_require__(49) + , toIObject = __webpack_require__(32); + + // 22.1.3.4 Array.prototype.entries() + // 22.1.3.13 Array.prototype.keys() + // 22.1.3.29 Array.prototype.values() + // 22.1.3.30 Array.prototype[@@iterator]() + module.exports = __webpack_require__(48)(Array, 'Array', function(iterated, kind){ + this._t = toIObject(iterated); // target + this._i = 0; // next index + this._k = kind; // kind + // 22.1.5.2.1 %ArrayIteratorPrototype%.next() + }, function(){ + var O = this._t + , kind = this._k + , index = this._i++; + if(!O || index >= O.length){ + this._t = undefined; + return step(1); + } + if(kind == 'keys' )return step(0, index); + if(kind == 'values')return step(0, O[index]); + return step(0, [index, O[index]]); + }, 'values'); + + // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) + Iterators.Arguments = Iterators.Array; + + addToUnscopables('keys'); + addToUnscopables('values'); + addToUnscopables('entries'); + +/***/ }), +/* 53 */ +/***/ (function(module, exports) { + + module.exports = function(){ /* empty */ }; + +/***/ }), +/* 54 */ +/***/ (function(module, exports) { + + module.exports = function(done, value){ + return {value: value, done: !!done}; + }; + +/***/ }), +/* 55 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(56), __esModule: true }; + +/***/ }), +/* 56 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(51); + __webpack_require__(45); + module.exports = __webpack_require__(57); + +/***/ }), +/* 57 */ +/***/ (function(module, exports, __webpack_require__) { + + var anObject = __webpack_require__(39) + , get = __webpack_require__(58); + module.exports = __webpack_require__(21).getIterator = function(it){ + var iterFn = get(it); + if(typeof iterFn != 'function')throw TypeError(it + ' is not iterable!'); + return anObject(iterFn.call(it)); + }; + +/***/ }), +/* 58 */ +/***/ (function(module, exports, __webpack_require__) { + + var classof = __webpack_require__(59) + , ITERATOR = __webpack_require__(29)('iterator') + , Iterators = __webpack_require__(49); + module.exports = __webpack_require__(21).getIteratorMethod = function(it){ + if(it != undefined)return it[ITERATOR] + || it['@@iterator'] + || Iterators[classof(it)]; + }; + +/***/ }), +/* 59 */ +/***/ (function(module, exports, __webpack_require__) { + + // getting tag from 19.1.3.6 Object.prototype.toString() + var cof = __webpack_require__(34) + , TAG = __webpack_require__(29)('toStringTag') + // ES3 wrong here + , ARG = cof(function(){ return arguments; }()) == 'Arguments'; + + module.exports = function(it){ + var O, T, B; + return it === undefined ? 'Undefined' : it === null ? 'Null' + // @@toStringTag case + : typeof (T = (O = Object(it))[TAG]) == 'string' ? T + // builtinTag case + : ARG ? cof(O) + // ES3 arguments fallback + : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; + }; + +/***/ }), +/* 60 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(61), __esModule: true }; + +/***/ }), +/* 61 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(62); + module.exports = __webpack_require__(21).Object.keys; + +/***/ }), +/* 62 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.14 Object.keys(O) + var toObject = __webpack_require__(63); + + __webpack_require__(64)('keys', function($keys){ + return function keys(it){ + return $keys(toObject(it)); + }; + }); + +/***/ }), +/* 63 */ +/***/ (function(module, exports, __webpack_require__) { + + // 7.1.13 ToObject(argument) + var defined = __webpack_require__(35); + module.exports = function(it){ + return Object(defined(it)); + }; + +/***/ }), +/* 64 */ +/***/ (function(module, exports, __webpack_require__) { + + // most Object methods by ES6 should accept primitives + var $export = __webpack_require__(20) + , core = __webpack_require__(21) + , fails = __webpack_require__(19); + module.exports = function(KEY, exec){ + var fn = (core.Object || {})[KEY] || Object[KEY] + , exp = {}; + exp[KEY] = exec(fn); + $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); + }; + +/***/ }), +/* 65 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('helperMissing', function () /* [args, ]options */{ + if (arguments.length === 1) { + // A missing field in a {{foo}} construct. + return undefined; + } else { + // Someone is actually trying to call something, blow up. + throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 66 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('if', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#if requires exactly one argument'); + } + if (_utils.isFunction(conditional)) { + conditional = conditional.call(this); + } + + // Default behavior is to render the positive path if the value is truthy and not empty. + // The `includeZero` option may be set to treat the condtional as purely not empty based on the + // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. + if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); + + instance.registerHelper('unless', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#unless requires exactly one argument'); + } + return instance.helpers['if'].call(this, conditional, { + fn: options.inverse, + inverse: options.fn, + hash: options.hash + }); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 67 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('log', function () /* message, options */{ + var args = [undefined], + options = arguments[arguments.length - 1]; + for (var i = 0; i < arguments.length - 1; i++) { + args.push(arguments[i]); + } + + var level = 1; + if (options.hash.level != null) { + level = options.hash.level; + } else if (options.data && options.data.level != null) { + level = options.data.level; + } + args[0] = level; + + instance.log.apply(instance, args); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 68 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('lookup', function (obj, field, options) { + if (!obj) { + // Note for 5.0: Change to "obj == null" in 5.0 + return obj; + } + return options.lookupProperty(obj, field); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 69 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('with', function (context, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#with requires exactly one argument'); + } + if (_utils.isFunction(context)) { + context = context.call(this); + } + + var fn = options.fn; + + if (!_utils.isEmpty(context)) { + var data = options.data; + if (options.data && options.ids) { + data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); + } + + return fn(context, { + data: data, + blockParams: _utils.blockParams([context], [data && data.contextPath]) + }); + } else { + return options.inverse(this); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 70 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultDecorators = registerDefaultDecorators; + + var _decoratorsInline = __webpack_require__(71); + + var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); + + function registerDefaultDecorators(instance) { + _decoratorsInline2['default'](instance); + } + +/***/ }), +/* 71 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerDecorator('inline', function (fn, props, container, options) { + var ret = fn; + if (!props.partials) { + props.partials = {}; + ret = function (context, options) { + // Create a new partials stack frame prior to exec. + var original = container.partials; + container.partials = _utils.extend({}, original, props.partials); + var ret = fn(context, options); + container.partials = original; + return ret; + }; + } + + props.partials[options.args[0]] = options.fn; + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 72 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var logger = { + methodMap: ['debug', 'info', 'warn', 'error'], + level: 'info', + + // Maps a given level value to the `methodMap` indexes above. + lookupLevel: function lookupLevel(level) { + if (typeof level === 'string') { + var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); + if (levelMap >= 0) { + level = levelMap; + } else { + level = parseInt(level, 10); + } + } + + return level; + }, + + // Can be overridden in the host environment + log: function log(level) { + level = logger.lookupLevel(level); + + if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { + var method = logger.methodMap[level]; + // eslint-disable-next-line no-console + if (!console[method]) { + method = 'log'; + } + + for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + message[_key - 1] = arguments[_key]; + } + + console[method].apply(console, message); // eslint-disable-line no-console + } + } + }; + + exports['default'] = logger; + module.exports = exports['default']; + +/***/ }), +/* 73 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(74)['default']; + + var _Object$keys = __webpack_require__(60)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.createProtoAccessControl = createProtoAccessControl; + exports.resultIsAllowed = resultIsAllowed; + exports.resetLoggedProperties = resetLoggedProperties; + + var _createNewLookupObject = __webpack_require__(76); + + var _logger = __webpack_require__(72); + + var _logger2 = _interopRequireDefault(_logger); + + var loggedProperties = _Object$create(null); + + function createProtoAccessControl(runtimeOptions) { + var defaultMethodWhiteList = _Object$create(null); + defaultMethodWhiteList['constructor'] = false; + defaultMethodWhiteList['__defineGetter__'] = false; + defaultMethodWhiteList['__defineSetter__'] = false; + defaultMethodWhiteList['__lookupGetter__'] = false; + + var defaultPropertyWhiteList = _Object$create(null); + // eslint-disable-next-line no-proto + defaultPropertyWhiteList['__proto__'] = false; + + return { + properties: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultPropertyWhiteList, runtimeOptions.allowedProtoProperties), + defaultValue: runtimeOptions.allowProtoPropertiesByDefault + }, + methods: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultMethodWhiteList, runtimeOptions.allowedProtoMethods), + defaultValue: runtimeOptions.allowProtoMethodsByDefault + } + }; + } + + function resultIsAllowed(result, protoAccessControl, propertyName) { + if (typeof result === 'function') { + return checkWhiteList(protoAccessControl.methods, propertyName); + } else { + return checkWhiteList(protoAccessControl.properties, propertyName); + } + } + + function checkWhiteList(protoAccessControlForType, propertyName) { + if (protoAccessControlForType.whitelist[propertyName] !== undefined) { + return protoAccessControlForType.whitelist[propertyName] === true; + } + if (protoAccessControlForType.defaultValue !== undefined) { + return protoAccessControlForType.defaultValue; + } + logUnexpecedPropertyAccessOnce(propertyName); + return false; + } + + function logUnexpecedPropertyAccessOnce(propertyName) { + if (loggedProperties[propertyName] !== true) { + loggedProperties[propertyName] = true; + _logger2['default'].log('error', 'Handlebars: Access has been denied to resolve the property "' + propertyName + '" because it is not an "own property" of its parent.\n' + 'You can add a runtime option to disable the check or this warning:\n' + 'See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details'); + } + } + + function resetLoggedProperties() { + _Object$keys(loggedProperties).forEach(function (propertyName) { + delete loggedProperties[propertyName]; + }); + } + +/***/ }), +/* 74 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(75), __esModule: true }; + +/***/ }), +/* 75 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9); + module.exports = function create(P, D){ + return $.create(P, D); + }; + +/***/ }), +/* 76 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(74)['default']; + + exports.__esModule = true; + exports.createNewLookupObject = createNewLookupObject; + + var _utils = __webpack_require__(5); + + /** + * Create a new object with "null"-prototype to avoid truthy results on prototype properties. + * The resulting object can be used with "object[property]" to check if a property exists + * @param {...object} sources a varargs parameter of source objects that will be merged + * @returns {object} + */ + + function createNewLookupObject() { + for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) { + sources[_key] = arguments[_key]; + } + + return _utils.extend.apply(undefined, [_Object$create(null)].concat(sources)); + } + +/***/ }), +/* 77 */ +/***/ (function(module, exports) { + + // Build out our basic SafeString type + 'use strict'; + + exports.__esModule = true; + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = SafeString.prototype.toHTML = function () { + return '' + this.string; + }; + + exports['default'] = SafeString; + module.exports = exports['default']; + +/***/ }), +/* 78 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$seal = __webpack_require__(79)['default']; + + var _Object$keys = __webpack_require__(60)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.checkRevision = checkRevision; + exports.template = template; + exports.wrapProgram = wrapProgram; + exports.resolvePartial = resolvePartial; + exports.invokePartial = invokePartial; + exports.noop = noop; + + var _utils = __webpack_require__(5); + + var Utils = _interopRequireWildcard(_utils); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _base = __webpack_require__(4); + + var _helpers = __webpack_require__(10); + + var _internalWrapHelper = __webpack_require__(82); + + var _internalProtoAccess = __webpack_require__(73); + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = _base.COMPILER_REVISION; + + if (compilerRevision >= _base.LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= _base.COMPILER_REVISION) { + return; + } + + if (compilerRevision < _base.LAST_COMPATIBLE_COMPILER_REVISION) { + var runtimeVersions = _base.REVISION_CHANGES[currentRevision], + compilerVersions = _base.REVISION_CHANGES[compilerRevision]; + throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); + } + } + + function template(templateSpec, env) { + /* istanbul ignore next */ + if (!env) { + throw new _exception2['default']('No environment passed to template'); + } + if (!templateSpec || !templateSpec.main) { + throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); + } + + templateSpec.main.decorator = templateSpec.main_d; + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as pseudo-supported APIs. + env.VM.checkRevision(templateSpec.compiler); + + // backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0) + var templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7; + + function invokePartialWrapper(partial, context, options) { + if (options.hash) { + context = Utils.extend({}, context, options.hash); + if (options.ids) { + options.ids[0] = true; + } + } + partial = env.VM.resolvePartial.call(this, partial, context, options); + + var extendedOptions = Utils.extend({}, options, { + hooks: this.hooks, + protoAccessControl: this.protoAccessControl + }); + + var result = env.VM.invokePartial.call(this, partial, context, extendedOptions); + + if (result == null && env.compile) { + options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); + result = options.partials[options.name](context, extendedOptions); + } + if (result != null) { + if (options.indent) { + var lines = result.split('\n'); + for (var i = 0, l = lines.length; i < l; i++) { + if (!lines[i] && i + 1 === l) { + break; + } + + lines[i] = options.indent + lines[i]; + } + result = lines.join('\n'); + } + return result; + } else { + throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); + } + } + + // Just add water + var container = { + strict: function strict(obj, name, loc) { + if (!obj || !(name in obj)) { + throw new _exception2['default']('"' + name + '" not defined in ' + obj, { + loc: loc + }); + } + return container.lookupProperty(obj, name); + }, + lookupProperty: function lookupProperty(parent, propertyName) { + var result = parent[propertyName]; + if (result == null) { + return result; + } + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return result; + } + + if (_internalProtoAccess.resultIsAllowed(result, container.protoAccessControl, propertyName)) { + return result; + } + return undefined; + }, + lookup: function lookup(depths, name) { + var len = depths.length; + for (var i = 0; i < len; i++) { + var result = depths[i] && container.lookupProperty(depths[i], name); + if (result != null) { + return depths[i][name]; + } + } + }, + lambda: function lambda(current, context) { + return typeof current === 'function' ? current.call(context) : current; + }, + + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + + fn: function fn(i) { + var ret = templateSpec[i]; + ret.decorator = templateSpec[i + '_d']; + return ret; + }, + + programs: [], + program: function program(i, data, declaredBlockParams, blockParams, depths) { + var programWrapper = this.programs[i], + fn = this.fn(i); + if (data || depths || blockParams || declaredBlockParams) { + programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); + } else if (!programWrapper) { + programWrapper = this.programs[i] = wrapProgram(this, i, fn); + } + return programWrapper; + }, + + data: function data(value, depth) { + while (value && depth--) { + value = value._parent; + } + return value; + }, + mergeIfNeeded: function mergeIfNeeded(param, common) { + var obj = param || common; + + if (param && common && param !== common) { + obj = Utils.extend({}, common, param); + } + + return obj; + }, + // An empty object to use as replacement for null-contexts + nullContext: _Object$seal({}), + + noop: env.VM.noop, + compilerInfo: templateSpec.compiler + }; + + function ret(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var data = options.data; + + ret._setup(options); + if (!options.partial && templateSpec.useData) { + data = initData(context, data); + } + var depths = undefined, + blockParams = templateSpec.useBlockParams ? [] : undefined; + if (templateSpec.useDepths) { + if (options.depths) { + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; + } else { + depths = [context]; + } + } + + function main(context /*, options*/) { + return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); + } + + main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); + return main(context, options); + } + + ret.isTop = true; + + ret._setup = function (options) { + if (!options.partial) { + var mergedHelpers = Utils.extend({}, env.helpers, options.helpers); + wrapHelpersToPassLookupProperty(mergedHelpers, container); + container.helpers = mergedHelpers; + + if (templateSpec.usePartial) { + // Use mergeIfNeeded here to prevent compiling global partials multiple times + container.partials = container.mergeIfNeeded(options.partials, env.partials); + } + if (templateSpec.usePartial || templateSpec.useDecorators) { + container.decorators = Utils.extend({}, env.decorators, options.decorators); + } + + container.hooks = {}; + container.protoAccessControl = _internalProtoAccess.createProtoAccessControl(options); + + var keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7; + _helpers.moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers); + _helpers.moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers); + } else { + container.protoAccessControl = options.protoAccessControl; // internal option + container.helpers = options.helpers; + container.partials = options.partials; + container.decorators = options.decorators; + container.hooks = options.hooks; + } + }; + + ret._child = function (i, data, blockParams, depths) { + if (templateSpec.useBlockParams && !blockParams) { + throw new _exception2['default']('must pass block params'); + } + if (templateSpec.useDepths && !depths) { + throw new _exception2['default']('must pass parent depths'); + } + + return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); + }; + return ret; + } + + function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { + function prog(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var currentDepths = depths; + if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { + currentDepths = [context].concat(depths); + } + + return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); + } + + prog = executeDecorators(fn, prog, container, depths, data, blockParams); + + prog.program = i; + prog.depth = depths ? depths.length : 0; + prog.blockParams = declaredBlockParams || 0; + return prog; + } + + /** + * This is currently part of the official API, therefore implementation details should not be changed. + */ + + function resolvePartial(partial, context, options) { + if (!partial) { + if (options.name === '@partial-block') { + partial = options.data['partial-block']; + } else { + partial = options.partials[options.name]; + } + } else if (!partial.call && !options.name) { + // This is a dynamic partial that returned a string + options.name = partial; + partial = options.partials[partial]; + } + return partial; + } + + function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + var currentPartialBlock = options.data && options.data['partial-block']; + options.partial = true; + if (options.ids) { + options.data.contextPath = options.ids[0] || options.data.contextPath; + } + + var partialBlock = undefined; + if (options.fn && options.fn !== noop) { + (function () { + options.data = _base.createFrame(options.data); + // Wrapper function to get access to currentPartialBlock from the closure + var fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = _base.createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); + } + })(); + } + + if (partial === undefined && partialBlock) { + partial = partialBlock; + } + + if (partial === undefined) { + throw new _exception2['default']('The partial ' + options.name + ' could not be found'); + } else if (partial instanceof Function) { + return partial(context, options); + } + } + + function noop() { + return ''; + } + + function initData(context, data) { + if (!data || !('root' in data)) { + data = data ? _base.createFrame(data) : {}; + data.root = context; + } + return data; + } + + function executeDecorators(fn, prog, container, depths, data, blockParams) { + if (fn.decorator) { + var props = {}; + prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); + Utils.extend(prog, props); + } + return prog; + } + + function wrapHelpersToPassLookupProperty(mergedHelpers, container) { + _Object$keys(mergedHelpers).forEach(function (helperName) { + var helper = mergedHelpers[helperName]; + mergedHelpers[helperName] = passLookupPropertyOption(helper, container); + }); + } + + function passLookupPropertyOption(helper, container) { + var lookupProperty = container.lookupProperty; + return _internalWrapHelper.wrapHelper(helper, function (options) { + return Utils.extend({ lookupProperty: lookupProperty }, options); + }); + } + +/***/ }), +/* 79 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(80), __esModule: true }; + +/***/ }), +/* 80 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(81); + module.exports = __webpack_require__(21).Object.seal; + +/***/ }), +/* 81 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.17 Object.seal(O) + var isObject = __webpack_require__(40); + + __webpack_require__(64)('seal', function($seal){ + return function seal(it){ + return $seal && isObject(it) ? $seal(it) : it; + }; + }); + +/***/ }), +/* 82 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.wrapHelper = wrapHelper; + + function wrapHelper(helper, transformOptionsFn) { + if (typeof helper !== 'function') { + // This should not happen, but apparently it does in https://github.com/wycats/handlebars.js/issues/1639 + // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. + return helper; + } + var wrapper = function wrapper() /* dynamic arguments */{ + var options = arguments[arguments.length - 1]; + arguments[arguments.length - 1] = transformOptionsFn(options); + return helper.apply(this, arguments); + }; + return wrapper; + } + +/***/ }), +/* 83 */ +/***/ (function(module, exports) { + + /* global globalThis */ + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (Handlebars) { + /* istanbul ignore next */ + // https://mathiasbynens.be/notes/globalthis + (function () { + if (typeof globalThis === 'object') return; + Object.prototype.__defineGetter__('__magic__', function () { + return this; + }); + __magic__.globalThis = __magic__; // eslint-disable-line no-undef + delete Object.prototype.__magic__; + })(); + + var $Handlebars = globalThis.Handlebars; + + /* istanbul ignore next */ + Handlebars.noConflict = function () { + if (globalThis.Handlebars === Handlebars) { + globalThis.Handlebars = $Handlebars; + } + return Handlebars; + }; + }; + + module.exports = exports['default']; + +/***/ }), +/* 84 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + var AST = { + // Public API used to evaluate derived attributes regarding AST nodes + helpers: { + // a mustache is definitely a helper if: + // * it is an eligible helper, and + // * it has at least one parameter or hash segment + helperExpression: function helperExpression(node) { + return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash); + }, + + scopedId: function scopedId(path) { + return (/^\.|this\b/.test(path.original) + ); + }, + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + simpleId: function simpleId(path) { + return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; + } + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // must modify the object to operate properly. + exports['default'] = AST; + module.exports = exports['default']; + +/***/ }), +/* 85 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + exports.__esModule = true; + exports.parseWithoutProcessing = parseWithoutProcessing; + exports.parse = parse; + + var _parser = __webpack_require__(86); + + var _parser2 = _interopRequireDefault(_parser); + + var _whitespaceControl = __webpack_require__(87); + + var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl); + + var _helpers = __webpack_require__(89); + + var Helpers = _interopRequireWildcard(_helpers); + + var _utils = __webpack_require__(5); + + exports.parser = _parser2['default']; + + var yy = {}; + _utils.extend(yy, Helpers); + + function parseWithoutProcessing(input, options) { + // Just return if an already-compiled AST was passed in. + if (input.type === 'Program') { + return input; + } + + _parser2['default'].yy = yy; + + // Altering the shared object here, but this is ok as parser is a sync operation + yy.locInfo = function (locInfo) { + return new yy.SourceLocation(options && options.srcName, locInfo); + }; + + var ast = _parser2['default'].parse(input); + + return ast; + } + + function parse(input, options) { + var ast = parseWithoutProcessing(input, options); + var strip = new _whitespaceControl2['default'](options); + + return strip.accept(ast); + } + +/***/ }), +/* 86 */ +/***/ (function(module, exports) { + + // File ignored in coverage tests via setting in .istanbul.yml + /* Jison generated parser */ + "use strict"; + + exports.__esModule = true; + var handlebars = (function () { + var parser = { trace: function trace() {}, + yy: {}, + symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 }, + terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" }, + productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 0], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) { + + var $0 = $$.length - 1; + switch (yystate) { + case 1: + return $$[$0 - 1]; + break; + case 2: + this.$ = yy.prepareProgram($$[$0]); + break; + case 3: + this.$ = $$[$0]; + break; + case 4: + this.$ = $$[$0]; + break; + case 5: + this.$ = $$[$0]; + break; + case 6: + this.$ = $$[$0]; + break; + case 7: + this.$ = $$[$0]; + break; + case 8: + this.$ = $$[$0]; + break; + case 9: + this.$ = { + type: 'CommentStatement', + value: yy.stripComment($$[$0]), + strip: yy.stripFlags($$[$0], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 10: + this.$ = { + type: 'ContentStatement', + original: $$[$0], + value: $$[$0], + loc: yy.locInfo(this._$) + }; + + break; + case 11: + this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 12: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] }; + break; + case 13: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$); + break; + case 14: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$); + break; + case 15: + this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 16: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 17: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 18: + this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] }; + break; + case 19: + var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$), + program = yy.prepareProgram([inverse], $$[$0 - 1].loc); + program.chained = true; + + this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true }; + + break; + case 20: + this.$ = $$[$0]; + break; + case 21: + this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) }; + break; + case 22: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 23: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 24: + this.$ = { + type: 'PartialStatement', + name: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + indent: '', + strip: yy.stripFlags($$[$0 - 4], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 25: + this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 26: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) }; + break; + case 27: + this.$ = $$[$0]; + break; + case 28: + this.$ = $$[$0]; + break; + case 29: + this.$ = { + type: 'SubExpression', + path: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + loc: yy.locInfo(this._$) + }; + + break; + case 30: + this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 31: + this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 32: + this.$ = yy.id($$[$0 - 1]); + break; + case 33: + this.$ = $$[$0]; + break; + case 34: + this.$ = $$[$0]; + break; + case 35: + this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 36: + this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) }; + break; + case 37: + this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) }; + break; + case 38: + this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) }; + break; + case 39: + this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) }; + break; + case 40: + this.$ = $$[$0]; + break; + case 41: + this.$ = $$[$0]; + break; + case 42: + this.$ = yy.preparePath(true, $$[$0], this._$); + break; + case 43: + this.$ = yy.preparePath(false, $$[$0], this._$); + break; + case 44: + $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2]; + break; + case 45: + this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }]; + break; + case 46: + this.$ = []; + break; + case 47: + $$[$0 - 1].push($$[$0]); + break; + case 48: + this.$ = []; + break; + case 49: + $$[$0 - 1].push($$[$0]); + break; + case 50: + this.$ = []; + break; + case 51: + $$[$0 - 1].push($$[$0]); + break; + case 58: + this.$ = []; + break; + case 59: + $$[$0 - 1].push($$[$0]); + break; + case 64: + this.$ = []; + break; + case 65: + $$[$0 - 1].push($$[$0]); + break; + case 70: + this.$ = []; + break; + case 71: + $$[$0 - 1].push($$[$0]); + break; + case 78: + this.$ = []; + break; + case 79: + $$[$0 - 1].push($$[$0]); + break; + case 82: + this.$ = []; + break; + case 83: + $$[$0 - 1].push($$[$0]); + break; + case 86: + this.$ = []; + break; + case 87: + $$[$0 - 1].push($$[$0]); + break; + case 90: + this.$ = []; + break; + case 91: + $$[$0 - 1].push($$[$0]); + break; + case 94: + this.$ = []; + break; + case 95: + $$[$0 - 1].push($$[$0]); + break; + case 98: + this.$ = [$$[$0]]; + break; + case 99: + $$[$0 - 1].push($$[$0]); + break; + case 100: + this.$ = [$$[$0]]; + break; + case 101: + $$[$0 - 1].push($$[$0]); + break; + } + }, + table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 15: [2, 48], 17: 39, 18: [2, 48] }, { 20: 41, 56: 40, 64: 42, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 44, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 45, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 41, 56: 48, 64: 42, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 49, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 50] }, { 72: [1, 35], 86: 51 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 52, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 53, 38: 55, 39: [1, 57], 43: 56, 44: [1, 58], 45: 54, 47: [2, 54] }, { 28: 59, 43: 60, 44: [1, 58], 47: [2, 56] }, { 13: 62, 15: [1, 20], 18: [1, 61] }, { 33: [2, 86], 57: 63, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 64, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 65, 47: [1, 66] }, { 30: 67, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 68, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 69, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 70, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 74, 33: [2, 80], 50: 71, 63: 72, 64: 75, 65: [1, 43], 69: 73, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 79] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 50] }, { 20: 74, 53: 80, 54: [2, 84], 63: 81, 64: 75, 65: [1, 43], 69: 82, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 83, 47: [1, 66] }, { 47: [2, 55] }, { 4: 84, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 85, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 86, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 87, 47: [1, 66] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 74, 33: [2, 88], 58: 88, 63: 89, 64: 75, 65: [1, 43], 69: 90, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 91, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 92, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 31: 93, 33: [2, 60], 63: 94, 64: 75, 65: [1, 43], 69: 95, 70: 76, 71: 77, 72: [1, 78], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 33: [2, 66], 36: 96, 63: 97, 64: 75, 65: [1, 43], 69: 98, 70: 76, 71: 77, 72: [1, 78], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 22: 99, 23: [2, 52], 63: 100, 64: 75, 65: [1, 43], 69: 101, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 33: [2, 92], 62: 102, 63: 103, 64: 75, 65: [1, 43], 69: 104, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 105] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 106, 72: [1, 107], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 108], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 109] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 55, 39: [1, 57], 43: 56, 44: [1, 58], 45: 111, 46: 110, 47: [2, 76] }, { 33: [2, 70], 40: 112, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 113] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 74, 63: 115, 64: 75, 65: [1, 43], 67: 114, 68: [2, 96], 69: 116, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 117] }, { 32: 118, 33: [2, 62], 74: 119, 75: [1, 120] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 121, 74: 122, 75: [1, 120] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 123] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 124] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 108] }, { 20: 74, 63: 125, 64: 75, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 74, 33: [2, 72], 41: 126, 63: 127, 64: 75, 65: [1, 43], 69: 128, 70: 76, 71: 77, 72: [1, 78], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 129] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 130] }, { 33: [2, 63] }, { 72: [1, 132], 76: 131 }, { 33: [1, 133] }, { 33: [2, 69] }, { 15: [2, 12], 18: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 134, 74: 135, 75: [1, 120] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 137], 77: [1, 136] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 138] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }], + defaultActions: { 4: [2, 1], 54: [2, 55], 56: [2, 20], 60: [2, 57], 73: [2, 81], 82: [2, 85], 86: [2, 18], 90: [2, 89], 101: [2, 53], 104: [2, 93], 110: [2, 19], 111: [2, 77], 116: [2, 97], 119: [2, 63], 122: [2, 69], 135: [2, 75], 136: [2, 32] }, + parseError: function parseError(str, hash) { + throw new Error(str); + }, + parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], + lstack = [], + table = this.table, + yytext = "", + yylineno = 0, + yyleng = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + this.yy.parser = this; + if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {}; + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + var ranges = this.lexer.options && this.lexer.options.ranges; + if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError; + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + function lex() { + var token; + token = self.lexer.lex() || 1; + if (typeof token !== "number") { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, + preErrorSymbol, + state, + action, + a, + r, + yyval = {}, + p, + len, + newState, + expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == "undefined") { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === "undefined" || !action.length || !action[0]) { + var errStr = ""; + if (!recovering) { + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected }); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column }; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + /* Jison generated lexer */ + var lexer = (function () { + var lexer = { EOF: 1, + parseError: function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput: function setInput(input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 }; + if (this.options.ranges) this.yylloc.range = [0, 0]; + this.offset = 0; + return this; + }, + input: function input() { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput: function unput(ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); + + if (lines.length - 1) this.yylineno -= lines.length - 1; + var r = this.yylloc.range; + + this.yylloc = { first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more: function more() { + this._more = true; + return this; + }, + less: function less(n) { + this.unput(this.match.slice(n)); + }, + pastInput: function pastInput() { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput: function upcomingInput() { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20 - next.length); + } + return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, + showPosition: function showPosition() { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, + next: function next() { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, match, tempMatch, index, col, lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = { first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) this.done = false; + if (token) return token;else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno }); + } + }, + lex: function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin: function begin(condition) { + this.conditionStack.push(condition); + }, + popState: function popState() { + return this.conditionStack.pop(); + }, + _currentRules: function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + }, + topState: function topState() { + return this.conditionStack[this.conditionStack.length - 2]; + }, + pushState: function begin(condition) { + this.begin(condition); + } }; + lexer.options = {}; + lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) { + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substring(start, yy_.yyleng - end + start); + } + + var YYSTATE = YY_START; + switch ($avoiding_name_collisions) { + case 0: + if (yy_.yytext.slice(-2) === "\\\\") { + strip(0, 1); + this.begin("mu"); + } else if (yy_.yytext.slice(-1) === "\\") { + strip(0, 1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if (yy_.yytext) return 15; + + break; + case 1: + return 15; + break; + case 2: + this.popState(); + return 15; + + break; + case 3: + this.begin('raw');return 15; + break; + case 4: + this.popState(); + // Should be using `this.topState()` below, but it currently + // returns the second top instead of the first top. Opened an + // issue about it at https://github.com/zaach/jison/issues/291 + if (this.conditionStack[this.conditionStack.length - 1] === 'raw') { + return 15; + } else { + strip(5, 9); + return 'END_RAW_BLOCK'; + } + + break; + case 5: + return 15; + break; + case 6: + this.popState(); + return 14; + + break; + case 7: + return 65; + break; + case 8: + return 68; + break; + case 9: + return 19; + break; + case 10: + this.popState(); + this.begin('raw'); + return 23; + + break; + case 11: + return 55; + break; + case 12: + return 60; + break; + case 13: + return 29; + break; + case 14: + return 47; + break; + case 15: + this.popState();return 44; + break; + case 16: + this.popState();return 44; + break; + case 17: + return 34; + break; + case 18: + return 39; + break; + case 19: + return 51; + break; + case 20: + return 48; + break; + case 21: + this.unput(yy_.yytext); + this.popState(); + this.begin('com'); + + break; + case 22: + this.popState(); + return 14; + + break; + case 23: + return 48; + break; + case 24: + return 73; + break; + case 25: + return 72; + break; + case 26: + return 72; + break; + case 27: + return 87; + break; + case 28: + // ignore whitespace + break; + case 29: + this.popState();return 54; + break; + case 30: + this.popState();return 33; + break; + case 31: + yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80; + break; + case 32: + yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80; + break; + case 33: + return 85; + break; + case 34: + return 82; + break; + case 35: + return 82; + break; + case 36: + return 83; + break; + case 37: + return 84; + break; + case 38: + return 81; + break; + case 39: + return 75; + break; + case 40: + return 77; + break; + case 41: + return 72; + break; + case 42: + yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72; + break; + case 43: + return 'INVALID'; + break; + case 44: + return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]+?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/]; + lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } }; + return lexer; + })(); + parser.lexer = lexer; + function Parser() { + this.yy = {}; + }Parser.prototype = parser;parser.Parser = Parser; + return new Parser(); + })();exports["default"] = handlebars; + module.exports = exports["default"]; + +/***/ }), +/* 87 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _visitor = __webpack_require__(88); + + var _visitor2 = _interopRequireDefault(_visitor); + + function WhitespaceControl() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + this.options = options; + } + WhitespaceControl.prototype = new _visitor2['default'](); + + WhitespaceControl.prototype.Program = function (program) { + var doStandalone = !this.options.ignoreStandalone; + + var isRoot = !this.isRootSeen; + this.isRootSeen = true; + + var body = program.body; + for (var i = 0, l = body.length; i < l; i++) { + var current = body[i], + strip = this.accept(current); + + if (!strip) { + continue; + } + + var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), + _isNextWhitespace = isNextWhitespace(body, i, isRoot), + openStandalone = strip.openStandalone && _isPrevWhitespace, + closeStandalone = strip.closeStandalone && _isNextWhitespace, + inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; + + if (strip.close) { + omitRight(body, i, true); + } + if (strip.open) { + omitLeft(body, i, true); + } + + if (doStandalone && inlineStandalone) { + omitRight(body, i); + + if (omitLeft(body, i)) { + // If we are on a standalone node, save the indent info for partials + if (current.type === 'PartialStatement') { + // Pull out the whitespace from the final line + current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1]; + } + } + } + if (doStandalone && openStandalone) { + omitRight((current.program || current.inverse).body); + + // Strip out the previous content node if it's whitespace only + omitLeft(body, i); + } + if (doStandalone && closeStandalone) { + // Always strip the next node + omitRight(body, i); + + omitLeft((current.inverse || current.program).body); + } + } + + return program; + }; + + WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) { + this.accept(block.program); + this.accept(block.inverse); + + // Find the inverse program that is involed with whitespace stripping. + var program = block.program || block.inverse, + inverse = block.program && block.inverse, + firstInverse = inverse, + lastInverse = inverse; + + if (inverse && inverse.chained) { + firstInverse = inverse.body[0].program; + + // Walk the inverse chain to find the last inverse that is actually in the chain. + while (lastInverse.chained) { + lastInverse = lastInverse.body[lastInverse.body.length - 1].program; + } + } + + var strip = { + open: block.openStrip.open, + close: block.closeStrip.close, + + // Determine the standalone candiacy. Basically flag our content as being possibly standalone + // so our parent can determine if we actually are standalone + openStandalone: isNextWhitespace(program.body), + closeStandalone: isPrevWhitespace((firstInverse || program).body) + }; + + if (block.openStrip.close) { + omitRight(program.body, null, true); + } + + if (inverse) { + var inverseStrip = block.inverseStrip; + + if (inverseStrip.open) { + omitLeft(program.body, null, true); + } + + if (inverseStrip.close) { + omitRight(firstInverse.body, null, true); + } + if (block.closeStrip.open) { + omitLeft(lastInverse.body, null, true); + } + + // Find standalone else statments + if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { + omitLeft(program.body); + omitRight(firstInverse.body); + } + } else if (block.closeStrip.open) { + omitLeft(program.body, null, true); + } + + return strip; + }; + + WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) { + return mustache.strip; + }; + + WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) { + /* istanbul ignore next */ + var strip = node.strip || {}; + return { + inlineStandalone: true, + open: strip.open, + close: strip.close + }; + }; + + function isPrevWhitespace(body, i, isRoot) { + if (i === undefined) { + i = body.length; + } + + // Nodes that end with newlines are considered whitespace (but are special + // cased for strip operations) + var prev = body[i - 1], + sibling = body[i - 2]; + if (!prev) { + return isRoot; + } + + if (prev.type === 'ContentStatement') { + return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original); + } + } + function isNextWhitespace(body, i, isRoot) { + if (i === undefined) { + i = -1; + } + + var next = body[i + 1], + sibling = body[i + 2]; + if (!next) { + return isRoot; + } + + if (next.type === 'ContentStatement') { + return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original); + } + } + + // Marks the node to the right of the position as omitted. + // I.e. {{foo}}' ' will mark the ' ' node as omitted. + // + // If i is undefined, then the first child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitRight(body, i, multiple) { + var current = body[i == null ? 0 : i + 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) { + return; + } + + var original = current.value; + current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, ''); + current.rightStripped = current.value !== original; + } + + // Marks the node to the left of the position as omitted. + // I.e. ' '{{foo}} will mark the ' ' node as omitted. + // + // If i is undefined then the last child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitLeft(body, i, multiple) { + var current = body[i == null ? body.length - 1 : i - 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) { + return; + } + + // We omit the last node if it's whitespace only and not preceded by a non-content node. + var original = current.value; + current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, ''); + current.leftStripped = current.value !== original; + return current.leftStripped; + } + + exports['default'] = WhitespaceControl; + module.exports = exports['default']; + +/***/ }), +/* 88 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function Visitor() { + this.parents = []; + } + + Visitor.prototype = { + constructor: Visitor, + mutating: false, + + // Visits a given value. If mutating, will replace the value if necessary. + acceptKey: function acceptKey(node, name) { + var value = this.accept(node[name]); + if (this.mutating) { + // Hacky sanity check: This may have a few false positives for type for the helper + // methods but will generally do the right thing without a lot of overhead. + if (value && !Visitor.prototype[value.type]) { + throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); + } + node[name] = value; + } + }, + + // Performs an accept operation with added sanity check to ensure + // required keys are not removed. + acceptRequired: function acceptRequired(node, name) { + this.acceptKey(node, name); + + if (!node[name]) { + throw new _exception2['default'](node.type + ' requires ' + name); + } + }, + + // Traverses a given array. If mutating, empty respnses will be removed + // for child elements. + acceptArray: function acceptArray(array) { + for (var i = 0, l = array.length; i < l; i++) { + this.acceptKey(array, i); + + if (!array[i]) { + array.splice(i, 1); + i--; + l--; + } + } + }, + + accept: function accept(object) { + if (!object) { + return; + } + + /* istanbul ignore next: Sanity code */ + if (!this[object.type]) { + throw new _exception2['default']('Unknown type: ' + object.type, object); + } + + if (this.current) { + this.parents.unshift(this.current); + } + this.current = object; + + var ret = this[object.type](object); + + this.current = this.parents.shift(); + + if (!this.mutating || ret) { + return ret; + } else if (ret !== false) { + return object; + } + }, + + Program: function Program(program) { + this.acceptArray(program.body); + }, + + MustacheStatement: visitSubExpression, + Decorator: visitSubExpression, + + BlockStatement: visitBlock, + DecoratorBlock: visitBlock, + + PartialStatement: visitPartial, + PartialBlockStatement: function PartialBlockStatement(partial) { + visitPartial.call(this, partial); + + this.acceptKey(partial, 'program'); + }, + + ContentStatement: function ContentStatement() /* content */{}, + CommentStatement: function CommentStatement() /* comment */{}, + + SubExpression: visitSubExpression, + + PathExpression: function PathExpression() /* path */{}, + + StringLiteral: function StringLiteral() /* string */{}, + NumberLiteral: function NumberLiteral() /* number */{}, + BooleanLiteral: function BooleanLiteral() /* bool */{}, + UndefinedLiteral: function UndefinedLiteral() /* literal */{}, + NullLiteral: function NullLiteral() /* literal */{}, + + Hash: function Hash(hash) { + this.acceptArray(hash.pairs); + }, + HashPair: function HashPair(pair) { + this.acceptRequired(pair, 'value'); + } + }; + + function visitSubExpression(mustache) { + this.acceptRequired(mustache, 'path'); + this.acceptArray(mustache.params); + this.acceptKey(mustache, 'hash'); + } + function visitBlock(block) { + visitSubExpression.call(this, block); + + this.acceptKey(block, 'program'); + this.acceptKey(block, 'inverse'); + } + function visitPartial(partial) { + this.acceptRequired(partial, 'name'); + this.acceptArray(partial.params); + this.acceptKey(partial, 'hash'); + } + + exports['default'] = Visitor; + module.exports = exports['default']; + +/***/ }), +/* 89 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.SourceLocation = SourceLocation; + exports.id = id; + exports.stripFlags = stripFlags; + exports.stripComment = stripComment; + exports.preparePath = preparePath; + exports.prepareMustache = prepareMustache; + exports.prepareRawBlock = prepareRawBlock; + exports.prepareBlock = prepareBlock; + exports.prepareProgram = prepareProgram; + exports.preparePartialBlock = preparePartialBlock; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function validateClose(open, close) { + close = close.path ? close.path.original : close; + + if (open.path.original !== close) { + var errorNode = { loc: open.path.loc }; + + throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode); + } + } + + function SourceLocation(source, locInfo) { + this.source = source; + this.start = { + line: locInfo.first_line, + column: locInfo.first_column + }; + this.end = { + line: locInfo.last_line, + column: locInfo.last_column + }; + } + + function id(token) { + if (/^\[.*\]$/.test(token)) { + return token.substring(1, token.length - 1); + } else { + return token; + } + } + + function stripFlags(open, close) { + return { + open: open.charAt(2) === '~', + close: close.charAt(close.length - 3) === '~' + }; + } + + function stripComment(comment) { + return comment.replace(/^\{\{~?!-?-?/, '').replace(/-?-?~?\}\}$/, ''); + } + + function preparePath(data, parts, loc) { + loc = this.locInfo(loc); + + var original = data ? '@' : '', + dig = [], + depth = 0; + + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i].part, + + // If we have [] syntax then we do not treat path references as operators, + // i.e. foo.[this] resolves to approximately context.foo['this'] + isLiteral = parts[i].original !== part; + original += (parts[i].separator || '') + part; + + if (!isLiteral && (part === '..' || part === '.' || part === 'this')) { + if (dig.length > 0) { + throw new _exception2['default']('Invalid path: ' + original, { loc: loc }); + } else if (part === '..') { + depth++; + } + } else { + dig.push(part); + } + } + + return { + type: 'PathExpression', + data: data, + depth: depth, + parts: dig, + original: original, + loc: loc + }; + } + + function prepareMustache(path, params, hash, open, strip, locInfo) { + // Must use charAt to support IE pre-10 + var escapeFlag = open.charAt(3) || open.charAt(2), + escaped = escapeFlag !== '{' && escapeFlag !== '&'; + + var decorator = /\*/.test(open); + return { + type: decorator ? 'Decorator' : 'MustacheStatement', + path: path, + params: params, + hash: hash, + escaped: escaped, + strip: strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareRawBlock(openRawBlock, contents, close, locInfo) { + validateClose(openRawBlock, close); + + locInfo = this.locInfo(locInfo); + var program = { + type: 'Program', + body: contents, + strip: {}, + loc: locInfo + }; + + return { + type: 'BlockStatement', + path: openRawBlock.path, + params: openRawBlock.params, + hash: openRawBlock.hash, + program: program, + openStrip: {}, + inverseStrip: {}, + closeStrip: {}, + loc: locInfo + }; + } + + function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { + if (close && close.path) { + validateClose(openBlock, close); + } + + var decorator = /\*/.test(openBlock.open); + + program.blockParams = openBlock.blockParams; + + var inverse = undefined, + inverseStrip = undefined; + + if (inverseAndProgram) { + if (decorator) { + throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram); + } + + if (inverseAndProgram.chain) { + inverseAndProgram.program.body[0].closeStrip = close.strip; + } + + inverseStrip = inverseAndProgram.strip; + inverse = inverseAndProgram.program; + } + + if (inverted) { + inverted = inverse; + inverse = program; + program = inverted; + } + + return { + type: decorator ? 'DecoratorBlock' : 'BlockStatement', + path: openBlock.path, + params: openBlock.params, + hash: openBlock.hash, + program: program, + inverse: inverse, + openStrip: openBlock.strip, + inverseStrip: inverseStrip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareProgram(statements, loc) { + if (!loc && statements.length) { + var firstLoc = statements[0].loc, + lastLoc = statements[statements.length - 1].loc; + + /* istanbul ignore else */ + if (firstLoc && lastLoc) { + loc = { + source: firstLoc.source, + start: { + line: firstLoc.start.line, + column: firstLoc.start.column + }, + end: { + line: lastLoc.end.line, + column: lastLoc.end.column + } + }; + } + } + + return { + type: 'Program', + body: statements, + strip: {}, + loc: loc + }; + } + + function preparePartialBlock(open, program, close, locInfo) { + validateClose(open, close); + + return { + type: 'PartialBlockStatement', + name: open.path, + params: open.params, + hash: open.hash, + program: program, + openStrip: open.strip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + +/***/ }), +/* 90 */ +/***/ (function(module, exports, __webpack_require__) { + + /* eslint-disable new-cap */ + + 'use strict'; + + var _Object$create = __webpack_require__(74)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.Compiler = Compiler; + exports.precompile = precompile; + exports.compile = compile; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _ast = __webpack_require__(84); + + var _ast2 = _interopRequireDefault(_ast); + + var slice = [].slice; + + function Compiler() {} + + // the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + equals: function equals(other) { + var len = this.opcodes.length; + if (other.opcodes.length !== len) { + return false; + } + + for (var i = 0; i < len; i++) { + var opcode = this.opcodes[i], + otherOpcode = other.opcodes[i]; + if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { + return false; + } + } + + // We know that length is the same between the two arrays because they are directly tied + // to the opcode behavior above. + len = this.children.length; + for (var i = 0; i < len; i++) { + if (!this.children[i].equals(other.children[i])) { + return false; + } + } + + return true; + }, + + guid: 0, + + compile: function compile(program, options) { + this.sourceNode = []; + this.opcodes = []; + this.children = []; + this.options = options; + this.stringParams = options.stringParams; + this.trackIds = options.trackIds; + + options.blockParams = options.blockParams || []; + + options.knownHelpers = _utils.extend(_Object$create(null), { + helperMissing: true, + blockHelperMissing: true, + each: true, + 'if': true, + unless: true, + 'with': true, + log: true, + lookup: true + }, options.knownHelpers); + + return this.accept(program); + }, + + compileProgram: function compileProgram(program) { + var childCompiler = new this.compiler(), + // eslint-disable-line new-cap + result = childCompiler.compile(program, this.options), + guid = this.guid++; + + this.usePartial = this.usePartial || result.usePartial; + + this.children[guid] = result; + this.useDepths = this.useDepths || result.useDepths; + + return guid; + }, + + accept: function accept(node) { + /* istanbul ignore next: Sanity code */ + if (!this[node.type]) { + throw new _exception2['default']('Unknown type: ' + node.type, node); + } + + this.sourceNode.unshift(node); + var ret = this[node.type](node); + this.sourceNode.shift(); + return ret; + }, + + Program: function Program(program) { + this.options.blockParams.unshift(program.blockParams); + + var body = program.body, + bodyLength = body.length; + for (var i = 0; i < bodyLength; i++) { + this.accept(body[i]); + } + + this.options.blockParams.shift(); + + this.isSimple = bodyLength === 1; + this.blockParams = program.blockParams ? program.blockParams.length : 0; + + return this; + }, + + BlockStatement: function BlockStatement(block) { + transformLiteralToPath(block); + + var program = block.program, + inverse = block.inverse; + + program = program && this.compileProgram(program); + inverse = inverse && this.compileProgram(inverse); + + var type = this.classifySexpr(block); + + if (type === 'helper') { + this.helperSexpr(block, program, inverse); + } else if (type === 'simple') { + this.simpleSexpr(block); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('blockValue', block.path.original); + } else { + this.ambiguousSexpr(block, program, inverse); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('ambiguousBlockValue'); + } + + this.opcode('append'); + }, + + DecoratorBlock: function DecoratorBlock(decorator) { + var program = decorator.program && this.compileProgram(decorator.program); + var params = this.setupFullMustacheParams(decorator, program, undefined), + path = decorator.path; + + this.useDecorators = true; + this.opcode('registerDecorator', params.length, path.original); + }, + + PartialStatement: function PartialStatement(partial) { + this.usePartial = true; + + var program = partial.program; + if (program) { + program = this.compileProgram(partial.program); + } + + var params = partial.params; + if (params.length > 1) { + throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial); + } else if (!params.length) { + if (this.options.explicitPartialContext) { + this.opcode('pushLiteral', 'undefined'); + } else { + params.push({ type: 'PathExpression', parts: [], depth: 0 }); + } + } + + var partialName = partial.name.original, + isDynamic = partial.name.type === 'SubExpression'; + if (isDynamic) { + this.accept(partial.name); + } + + this.setupFullMustacheParams(partial, program, undefined, true); + + var indent = partial.indent || ''; + if (this.options.preventIndent && indent) { + this.opcode('appendContent', indent); + indent = ''; + } + + this.opcode('invokePartial', isDynamic, partialName, indent); + this.opcode('append'); + }, + PartialBlockStatement: function PartialBlockStatement(partialBlock) { + this.PartialStatement(partialBlock); + }, + + MustacheStatement: function MustacheStatement(mustache) { + this.SubExpression(mustache); + + if (mustache.escaped && !this.options.noEscape) { + this.opcode('appendEscaped'); + } else { + this.opcode('append'); + } + }, + Decorator: function Decorator(decorator) { + this.DecoratorBlock(decorator); + }, + + ContentStatement: function ContentStatement(content) { + if (content.value) { + this.opcode('appendContent', content.value); + } + }, + + CommentStatement: function CommentStatement() {}, + + SubExpression: function SubExpression(sexpr) { + transformLiteralToPath(sexpr); + var type = this.classifySexpr(sexpr); + + if (type === 'simple') { + this.simpleSexpr(sexpr); + } else if (type === 'helper') { + this.helperSexpr(sexpr); + } else { + this.ambiguousSexpr(sexpr); + } + }, + ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) { + var path = sexpr.path, + name = path.parts[0], + isBlock = program != null || inverse != null; + + this.opcode('getContext', path.depth); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + path.strict = true; + this.accept(path); + + this.opcode('invokeAmbiguous', name, isBlock); + }, + + simpleSexpr: function simpleSexpr(sexpr) { + var path = sexpr.path; + path.strict = true; + this.accept(path); + this.opcode('resolvePossibleLambda'); + }, + + helperSexpr: function helperSexpr(sexpr, program, inverse) { + var params = this.setupFullMustacheParams(sexpr, program, inverse), + path = sexpr.path, + name = path.parts[0]; + + if (this.options.knownHelpers[name]) { + this.opcode('invokeKnownHelper', params.length, name); + } else if (this.options.knownHelpersOnly) { + throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); + } else { + path.strict = true; + path.falsy = true; + + this.accept(path); + this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path)); + } + }, + + PathExpression: function PathExpression(path) { + this.addDepth(path.depth); + this.opcode('getContext', path.depth); + + var name = path.parts[0], + scoped = _ast2['default'].helpers.scopedId(path), + blockParamId = !path.depth && !scoped && this.blockParamIndex(name); + + if (blockParamId) { + this.opcode('lookupBlockParam', blockParamId, path.parts); + } else if (!name) { + // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` + this.opcode('pushContext'); + } else if (path.data) { + this.options.data = true; + this.opcode('lookupData', path.depth, path.parts, path.strict); + } else { + this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped); + } + }, + + StringLiteral: function StringLiteral(string) { + this.opcode('pushString', string.value); + }, + + NumberLiteral: function NumberLiteral(number) { + this.opcode('pushLiteral', number.value); + }, + + BooleanLiteral: function BooleanLiteral(bool) { + this.opcode('pushLiteral', bool.value); + }, + + UndefinedLiteral: function UndefinedLiteral() { + this.opcode('pushLiteral', 'undefined'); + }, + + NullLiteral: function NullLiteral() { + this.opcode('pushLiteral', 'null'); + }, + + Hash: function Hash(hash) { + var pairs = hash.pairs, + i = 0, + l = pairs.length; + + this.opcode('pushHash'); + + for (; i < l; i++) { + this.pushParam(pairs[i].value); + } + while (i--) { + this.opcode('assignToHash', pairs[i].key); + } + this.opcode('popHash'); + }, + + // HELPERS + opcode: function opcode(name) { + this.opcodes.push({ + opcode: name, + args: slice.call(arguments, 1), + loc: this.sourceNode[0].loc + }); + }, + + addDepth: function addDepth(depth) { + if (!depth) { + return; + } + + this.useDepths = true; + }, + + classifySexpr: function classifySexpr(sexpr) { + var isSimple = _ast2['default'].helpers.simpleId(sexpr.path); + + var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); + + // a mustache is an eligible helper if: + // * its id is simple (a single part, not `this` or `..`) + var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr); + + // if a mustache is an eligible helper but not a definite + // helper, it is ambiguous, and will be resolved in a later + // pass or at runtime. + var isEligible = !isBlockParam && (isHelper || isSimple); + + // if ambiguous, we can possibly resolve the ambiguity now + // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. + if (isEligible && !isHelper) { + var _name = sexpr.path.parts[0], + options = this.options; + if (options.knownHelpers[_name]) { + isHelper = true; + } else if (options.knownHelpersOnly) { + isEligible = false; + } + } + + if (isHelper) { + return 'helper'; + } else if (isEligible) { + return 'ambiguous'; + } else { + return 'simple'; + } + }, + + pushParams: function pushParams(params) { + for (var i = 0, l = params.length; i < l; i++) { + this.pushParam(params[i]); + } + }, + + pushParam: function pushParam(val) { + var value = val.value != null ? val.value : val.original || ''; + + if (this.stringParams) { + if (value.replace) { + value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.'); + } + + if (val.depth) { + this.addDepth(val.depth); + } + this.opcode('getContext', val.depth || 0); + this.opcode('pushStringParam', value, val.type); + + if (val.type === 'SubExpression') { + // SubExpressions get evaluated and passed in + // in string params mode. + this.accept(val); + } + } else { + if (this.trackIds) { + var blockParamIndex = undefined; + if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) { + blockParamIndex = this.blockParamIndex(val.parts[0]); + } + if (blockParamIndex) { + var blockParamChild = val.parts.slice(1).join('.'); + this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); + } else { + value = val.original || value; + if (value.replace) { + value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, ''); + } + + this.opcode('pushId', val.type, value); + } + } + this.accept(val); + } + }, + + setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) { + var params = sexpr.params; + this.pushParams(params); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + if (sexpr.hash) { + this.accept(sexpr.hash); + } else { + this.opcode('emptyHash', omitEmpty); + } + + return params; + }, + + blockParamIndex: function blockParamIndex(name) { + for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { + var blockParams = this.options.blockParams[depth], + param = blockParams && _utils.indexOf(blockParams, name); + if (blockParams && param >= 0) { + return [depth, param]; + } + } + } + }; + + function precompile(input, options, env) { + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); + } + + options = options || {}; + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options); + return new env.JavaScriptCompiler().compile(environment, options); + } + + function compile(input, options, env) { + if (options === undefined) options = {}; + + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); + } + + options = _utils.extend({}, options); + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var compiled = undefined; + + function compileInput() { + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options), + templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); + return env.template(templateSpec); + } + + // Template is only compiled on first use and cached after that point. + function ret(context, execOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled.call(this, context, execOptions); + } + ret._setup = function (setupOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._setup(setupOptions); + }; + ret._child = function (i, data, blockParams, depths) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._child(i, data, blockParams, depths); + }; + return ret; + } + + function argEquals(a, b) { + if (a === b) { + return true; + } + + if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) { + for (var i = 0; i < a.length; i++) { + if (!argEquals(a[i], b[i])) { + return false; + } + } + return true; + } + } + + function transformLiteralToPath(sexpr) { + if (!sexpr.path.parts) { + var literal = sexpr.path; + // Casting to string here to make false and 0 literal values play nicely with the rest + // of the system. + sexpr.path = { + type: 'PathExpression', + data: false, + depth: 0, + parts: [literal.original + ''], + original: literal.original + '', + loc: literal.loc + }; + } + } + +/***/ }), +/* 91 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$keys = __webpack_require__(60)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _base = __webpack_require__(4); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _codeGen = __webpack_require__(92); + + var _codeGen2 = _interopRequireDefault(_codeGen); + + function Literal(value) { + this.value = value; + } + + function JavaScriptCompiler() {} + + JavaScriptCompiler.prototype = { + // PUBLIC API: You can override these methods in a subclass to provide + // alternative compiled forms for name lookup and buffering semantics + nameLookup: function nameLookup(parent, name /*, type */) { + return this.internalNameLookup(parent, name); + }, + depthedLookup: function depthedLookup(name) { + return [this.aliasable('container.lookup'), '(depths, ', JSON.stringify(name), ')']; + }, + + compilerInfo: function compilerInfo() { + var revision = _base.COMPILER_REVISION, + versions = _base.REVISION_CHANGES[revision]; + return [revision, versions]; + }, + + appendToBuffer: function appendToBuffer(source, location, explicit) { + // Force a source as this simplifies the merge logic. + if (!_utils.isArray(source)) { + source = [source]; + } + source = this.source.wrap(source, location); + + if (this.environment.isSimple) { + return ['return ', source, ';']; + } else if (explicit) { + // This is a case where the buffer operation occurs as a child of another + // construct, generally braces. We have to explicitly output these buffer + // operations to ensure that the emitted code goes in the correct location. + return ['buffer += ', source, ';']; + } else { + source.appendToBuffer = true; + return source; + } + }, + + initializeBuffer: function initializeBuffer() { + return this.quotedString(''); + }, + // END PUBLIC API + internalNameLookup: function internalNameLookup(parent, name) { + this.lookupPropertyFunctionIsUsed = true; + return ['lookupProperty(', parent, ',', JSON.stringify(name), ')']; + }, + + lookupPropertyFunctionIsUsed: false, + + compile: function compile(environment, options, context, asObject) { + this.environment = environment; + this.options = options; + this.stringParams = this.options.stringParams; + this.trackIds = this.options.trackIds; + this.precompile = !asObject; + + this.name = this.environment.name; + this.isChild = !!context; + this.context = context || { + decorators: [], + programs: [], + environments: [] + }; + + this.preamble(); + + this.stackSlot = 0; + this.stackVars = []; + this.aliases = {}; + this.registers = { list: [] }; + this.hashes = []; + this.compileStack = []; + this.inlineStack = []; + this.blockParams = []; + + this.compileChildren(environment, options); + + this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; + this.useBlockParams = this.useBlockParams || environment.useBlockParams; + + var opcodes = environment.opcodes, + opcode = undefined, + firstLoc = undefined, + i = undefined, + l = undefined; + + for (i = 0, l = opcodes.length; i < l; i++) { + opcode = opcodes[i]; + + this.source.currentLocation = opcode.loc; + firstLoc = firstLoc || opcode.loc; + this[opcode.opcode].apply(this, opcode.args); + } + + // Flush any trailing content that might be pending. + this.source.currentLocation = firstLoc; + this.pushSource(''); + + /* istanbul ignore next */ + if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { + throw new _exception2['default']('Compile completed with content left on stack'); + } + + if (!this.decorators.isEmpty()) { + this.useDecorators = true; + + this.decorators.prepend(['var decorators = container.decorators, ', this.lookupPropertyFunctionVarDeclaration(), ';\n']); + this.decorators.push('return fn;'); + + if (asObject) { + this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); + } else { + this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); + this.decorators.push('}\n'); + this.decorators = this.decorators.merge(); + } + } else { + this.decorators = undefined; + } + + var fn = this.createFunctionContext(asObject); + if (!this.isChild) { + var ret = { + compiler: this.compilerInfo(), + main: fn + }; + + if (this.decorators) { + ret.main_d = this.decorators; // eslint-disable-line camelcase + ret.useDecorators = true; + } + + var _context = this.context; + var programs = _context.programs; + var decorators = _context.decorators; + + for (i = 0, l = programs.length; i < l; i++) { + if (programs[i]) { + ret[i] = programs[i]; + if (decorators[i]) { + ret[i + '_d'] = decorators[i]; + ret.useDecorators = true; + } + } + } + + if (this.environment.usePartial) { + ret.usePartial = true; + } + if (this.options.data) { + ret.useData = true; + } + if (this.useDepths) { + ret.useDepths = true; + } + if (this.useBlockParams) { + ret.useBlockParams = true; + } + if (this.options.compat) { + ret.compat = true; + } + + if (!asObject) { + ret.compiler = JSON.stringify(ret.compiler); + + this.source.currentLocation = { start: { line: 1, column: 0 } }; + ret = this.objectLiteral(ret); + + if (options.srcName) { + ret = ret.toStringWithSourceMap({ file: options.destName }); + ret.map = ret.map && ret.map.toString(); + } else { + ret = ret.toString(); + } + } else { + ret.compilerOptions = this.options; + } + + return ret; + } else { + return fn; + } + }, + + preamble: function preamble() { + // track the last context pushed into place to allow skipping the + // getContext opcode when it would be a noop + this.lastContext = 0; + this.source = new _codeGen2['default'](this.options.srcName); + this.decorators = new _codeGen2['default'](this.options.srcName); + }, + + createFunctionContext: function createFunctionContext(asObject) { + // istanbul ignore next + + var _this = this; + + var varDeclarations = ''; + + var locals = this.stackVars.concat(this.registers.list); + if (locals.length > 0) { + varDeclarations += ', ' + locals.join(', '); + } + + // Generate minimizer alias mappings + // + // When using true SourceNodes, this will update all references to the given alias + // as the source nodes are reused in situ. For the non-source node compilation mode, + // aliases will not be used, but this case is already being run on the client and + // we aren't concern about minimizing the template size. + var aliasCount = 0; + _Object$keys(this.aliases).forEach(function (alias) { + var node = _this.aliases[alias]; + if (node.children && node.referenceCount > 1) { + varDeclarations += ', alias' + ++aliasCount + '=' + alias; + node.children[0] = 'alias' + aliasCount; + } + }); + + if (this.lookupPropertyFunctionIsUsed) { + varDeclarations += ', ' + this.lookupPropertyFunctionVarDeclaration(); + } + + var params = ['container', 'depth0', 'helpers', 'partials', 'data']; + + if (this.useBlockParams || this.useDepths) { + params.push('blockParams'); + } + if (this.useDepths) { + params.push('depths'); + } + + // Perform a second pass over the output to merge content when possible + var source = this.mergeSource(varDeclarations); + + if (asObject) { + params.push(source); + + return Function.apply(this, params); + } else { + return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); + } + }, + mergeSource: function mergeSource(varDeclarations) { + var isSimple = this.environment.isSimple, + appendOnly = !this.forceBuffer, + appendFirst = undefined, + sourceSeen = undefined, + bufferStart = undefined, + bufferEnd = undefined; + this.source.each(function (line) { + if (line.appendToBuffer) { + if (bufferStart) { + line.prepend(' + '); + } else { + bufferStart = line; + } + bufferEnd = line; + } else { + if (bufferStart) { + if (!sourceSeen) { + appendFirst = true; + } else { + bufferStart.prepend('buffer += '); + } + bufferEnd.add(';'); + bufferStart = bufferEnd = undefined; + } + + sourceSeen = true; + if (!isSimple) { + appendOnly = false; + } + } + }); + + if (appendOnly) { + if (bufferStart) { + bufferStart.prepend('return '); + bufferEnd.add(';'); + } else if (!sourceSeen) { + this.source.push('return "";'); + } + } else { + varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); + + if (bufferStart) { + bufferStart.prepend('return buffer + '); + bufferEnd.add(';'); + } else { + this.source.push('return buffer;'); + } + } + + if (varDeclarations) { + this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); + } + + return this.source.merge(); + }, + + lookupPropertyFunctionVarDeclaration: function lookupPropertyFunctionVarDeclaration() { + return '\n lookupProperty = container.lookupProperty || function(parent, propertyName) {\n if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {\n return parent[propertyName];\n }\n return undefined\n }\n '.trim(); + }, + + // [blockValue] + // + // On stack, before: hash, inverse, program, value + // On stack, after: return value of blockHelperMissing + // + // The purpose of this opcode is to take a block of the form + // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and + // replace it on the stack with the result of properly + // invoking blockHelperMissing. + blockValue: function blockValue(name) { + var blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs(name, 0, params); + + var blockName = this.popStack(); + params.splice(1, 0, blockName); + + this.push(this.source.functionCall(blockHelperMissing, 'call', params)); + }, + + // [ambiguousBlockValue] + // + // On stack, before: hash, inverse, program, value + // Compiler value, before: lastHelper=value of last found helper, if any + // On stack, after, if no lastHelper: same as [blockValue] + // On stack, after, if lastHelper: value + ambiguousBlockValue: function ambiguousBlockValue() { + // We're being a bit cheeky and reusing the options value from the prior exec + var blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs('', 0, params, true); + + this.flushInline(); + + var current = this.topStack(); + params.splice(1, 0, current); + + this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']); + }, + + // [appendContent] + // + // On stack, before: ... + // On stack, after: ... + // + // Appends the string value of `content` to the current buffer + appendContent: function appendContent(content) { + if (this.pendingContent) { + content = this.pendingContent + content; + } else { + this.pendingLocation = this.source.currentLocation; + } + + this.pendingContent = content; + }, + + // [append] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Coerces `value` to a String and appends it to the current buffer. + // + // If `value` is truthy, or 0, it is coerced into a string and appended + // Otherwise, the empty string is appended + append: function append() { + if (this.isInline()) { + this.replaceStack(function (current) { + return [' != null ? ', current, ' : ""']; + }); + + this.pushSource(this.appendToBuffer(this.popStack())); + } else { + var local = this.popStack(); + this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); + if (this.environment.isSimple) { + this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); + } + } + }, + + // [appendEscaped] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Escape `value` and append it to the buffer + appendEscaped: function appendEscaped() { + this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')'])); + }, + + // [getContext] + // + // On stack, before: ... + // On stack, after: ... + // Compiler value, after: lastContext=depth + // + // Set the value of the `lastContext` compiler value to the depth + getContext: function getContext(depth) { + this.lastContext = depth; + }, + + // [pushContext] + // + // On stack, before: ... + // On stack, after: currentContext, ... + // + // Pushes the value of the current context onto the stack. + pushContext: function pushContext() { + this.pushStackLiteral(this.contextName(this.lastContext)); + }, + + // [lookupOnContext] + // + // On stack, before: ... + // On stack, after: currentContext[name], ... + // + // Looks up the value of `name` on the current context and pushes + // it onto the stack. + lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) { + var i = 0; + + if (!scoped && this.options.compat && !this.lastContext) { + // The depthed query is expected to handle the undefined logic for the root level that + // is implemented below, so we evaluate that directly in compat mode + this.push(this.depthedLookup(parts[i++])); + } else { + this.pushContext(); + } + + this.resolvePath('context', parts, i, falsy, strict); + }, + + // [lookupBlockParam] + // + // On stack, before: ... + // On stack, after: blockParam[name], ... + // + // Looks up the value of `parts` on the given block param and pushes + // it onto the stack. + lookupBlockParam: function lookupBlockParam(blockParamId, parts) { + this.useBlockParams = true; + + this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); + this.resolvePath('context', parts, 1); + }, + + // [lookupData] + // + // On stack, before: ... + // On stack, after: data, ... + // + // Push the data lookup operator + lookupData: function lookupData(depth, parts, strict) { + if (!depth) { + this.pushStackLiteral('data'); + } else { + this.pushStackLiteral('container.data(data, ' + depth + ')'); + } + + this.resolvePath('data', parts, 0, true, strict); + }, + + resolvePath: function resolvePath(type, parts, i, falsy, strict) { + // istanbul ignore next + + var _this2 = this; + + if (this.options.strict || this.options.assumeObjects) { + this.push(strictLookup(this.options.strict && strict, this, parts, i, type)); + return; + } + + var len = parts.length; + for (; i < len; i++) { + /* eslint-disable no-loop-func */ + this.replaceStack(function (current) { + var lookup = _this2.nameLookup(current, parts[i], type); + // We want to ensure that zero and false are handled properly if the context (falsy flag) + // needs to have the special handling for these values. + if (!falsy) { + return [' != null ? ', lookup, ' : ', current]; + } else { + // Otherwise we can use generic falsy handling + return [' && ', lookup]; + } + }); + /* eslint-enable no-loop-func */ + } + }, + + // [resolvePossibleLambda] + // + // On stack, before: value, ... + // On stack, after: resolved value, ... + // + // If the `value` is a lambda, replace it on the stack by + // the return value of the lambda + resolvePossibleLambda: function resolvePossibleLambda() { + this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); + }, + + // [pushStringParam] + // + // On stack, before: ... + // On stack, after: string, currentContext, ... + // + // This opcode is designed for use in string mode, which + // provides the string value of a parameter along with its + // depth rather than resolving it immediately. + pushStringParam: function pushStringParam(string, type) { + this.pushContext(); + this.pushString(type); + + // If it's a subexpression, the string result + // will be pushed after this opcode. + if (type !== 'SubExpression') { + if (typeof string === 'string') { + this.pushString(string); + } else { + this.pushStackLiteral(string); + } + } + }, + + emptyHash: function emptyHash(omitEmpty) { + if (this.trackIds) { + this.push('{}'); // hashIds + } + if (this.stringParams) { + this.push('{}'); // hashContexts + this.push('{}'); // hashTypes + } + this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); + }, + pushHash: function pushHash() { + if (this.hash) { + this.hashes.push(this.hash); + } + this.hash = { values: {}, types: [], contexts: [], ids: [] }; + }, + popHash: function popHash() { + var hash = this.hash; + this.hash = this.hashes.pop(); + + if (this.trackIds) { + this.push(this.objectLiteral(hash.ids)); + } + if (this.stringParams) { + this.push(this.objectLiteral(hash.contexts)); + this.push(this.objectLiteral(hash.types)); + } + + this.push(this.objectLiteral(hash.values)); + }, + + // [pushString] + // + // On stack, before: ... + // On stack, after: quotedString(string), ... + // + // Push a quoted version of `string` onto the stack + pushString: function pushString(string) { + this.pushStackLiteral(this.quotedString(string)); + }, + + // [pushLiteral] + // + // On stack, before: ... + // On stack, after: value, ... + // + // Pushes a value onto the stack. This operation prevents + // the compiler from creating a temporary variable to hold + // it. + pushLiteral: function pushLiteral(value) { + this.pushStackLiteral(value); + }, + + // [pushProgram] + // + // On stack, before: ... + // On stack, after: program(guid), ... + // + // Push a program expression onto the stack. This takes + // a compile-time guid and converts it into a runtime-accessible + // expression. + pushProgram: function pushProgram(guid) { + if (guid != null) { + this.pushStackLiteral(this.programExpression(guid)); + } else { + this.pushStackLiteral(null); + } + }, + + // [registerDecorator] + // + // On stack, before: hash, program, params..., ... + // On stack, after: ... + // + // Pops off the decorator's parameters, invokes the decorator, + // and inserts the decorator into the decorators list. + registerDecorator: function registerDecorator(paramSize, name) { + var foundDecorator = this.nameLookup('decorators', name, 'decorator'), + options = this.setupHelperArgs(name, paramSize); + + this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']); + }, + + // [invokeHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // Pops off the helper's parameters, invokes the helper, + // and pushes the helper's return value onto the stack. + // + // If the helper is not found, `helperMissing` is called. + invokeHelper: function invokeHelper(paramSize, name, isSimple) { + var nonHelper = this.popStack(), + helper = this.setupHelper(paramSize, name); + + var possibleFunctionCalls = []; + + if (isSimple) { + // direct call to helper + possibleFunctionCalls.push(helper.name); + } + // call a function from the input object + possibleFunctionCalls.push(nonHelper); + if (!this.options.strict) { + possibleFunctionCalls.push(this.aliasable('container.hooks.helperMissing')); + } + + var functionLookupCode = ['(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), ')']; + var functionCall = this.source.functionCall(functionLookupCode, 'call', helper.callParams); + this.push(functionCall); + }, + + itemsSeparatedBy: function itemsSeparatedBy(items, separator) { + var result = []; + result.push(items[0]); + for (var i = 1; i < items.length; i++) { + result.push(separator, items[i]); + } + return result; + }, + // [invokeKnownHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // This operation is used when the helper is known to exist, + // so a `helperMissing` fallback is not required. + invokeKnownHelper: function invokeKnownHelper(paramSize, name) { + var helper = this.setupHelper(paramSize, name); + this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); + }, + + // [invokeAmbiguous] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of disambiguation + // + // This operation is used when an expression like `{{foo}}` + // is provided, but we don't know at compile-time whether it + // is a helper or a path. + // + // This operation emits more code than the other options, + // and can be avoided by passing the `knownHelpers` and + // `knownHelpersOnly` flags at compile-time. + invokeAmbiguous: function invokeAmbiguous(name, helperCall) { + this.useRegister('helper'); + + var nonHelper = this.popStack(); + + this.emptyHash(); + var helper = this.setupHelper(0, name, helperCall); + + var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); + + var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; + if (!this.options.strict) { + lookup[0] = '(helper = '; + lookup.push(' != null ? helper : ', this.aliasable('container.hooks.helperMissing')); + } + + this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']); + }, + + // [invokePartial] + // + // On stack, before: context, ... + // On stack after: result of partial invocation + // + // This operation pops off a context, invokes a partial with that context, + // and pushes the result of the invocation back. + invokePartial: function invokePartial(isDynamic, name, indent) { + var params = [], + options = this.setupParams(name, 1, params); + + if (isDynamic) { + name = this.popStack(); + delete options.name; + } + + if (indent) { + options.indent = JSON.stringify(indent); + } + options.helpers = 'helpers'; + options.partials = 'partials'; + options.decorators = 'container.decorators'; + + if (!isDynamic) { + params.unshift(this.nameLookup('partials', name, 'partial')); + } else { + params.unshift(name); + } + + if (this.options.compat) { + options.depths = 'depths'; + } + options = this.objectLiteral(options); + params.push(options); + + this.push(this.source.functionCall('container.invokePartial', '', params)); + }, + + // [assignToHash] + // + // On stack, before: value, ..., hash, ... + // On stack, after: ..., hash, ... + // + // Pops a value off the stack and assigns it to the current hash + assignToHash: function assignToHash(key) { + var value = this.popStack(), + context = undefined, + type = undefined, + id = undefined; + + if (this.trackIds) { + id = this.popStack(); + } + if (this.stringParams) { + type = this.popStack(); + context = this.popStack(); + } + + var hash = this.hash; + if (context) { + hash.contexts[key] = context; + } + if (type) { + hash.types[key] = type; + } + if (id) { + hash.ids[key] = id; + } + hash.values[key] = value; + }, + + pushId: function pushId(type, name, child) { + if (type === 'BlockParam') { + this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : '')); + } else if (type === 'PathExpression') { + this.pushString(name); + } else if (type === 'SubExpression') { + this.pushStackLiteral('true'); + } else { + this.pushStackLiteral('null'); + } + }, + + // HELPERS + + compiler: JavaScriptCompiler, + + compileChildren: function compileChildren(environment, options) { + var children = environment.children, + child = undefined, + compiler = undefined; + + for (var i = 0, l = children.length; i < l; i++) { + child = children[i]; + compiler = new this.compiler(); // eslint-disable-line new-cap + + var existing = this.matchExistingProgram(child); + + if (existing == null) { + this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children + var index = this.context.programs.length; + child.index = index; + child.name = 'program' + index; + this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); + this.context.decorators[index] = compiler.decorators; + this.context.environments[index] = child; + + this.useDepths = this.useDepths || compiler.useDepths; + this.useBlockParams = this.useBlockParams || compiler.useBlockParams; + child.useDepths = this.useDepths; + child.useBlockParams = this.useBlockParams; + } else { + child.index = existing.index; + child.name = 'program' + existing.index; + + this.useDepths = this.useDepths || existing.useDepths; + this.useBlockParams = this.useBlockParams || existing.useBlockParams; + } + } + }, + matchExistingProgram: function matchExistingProgram(child) { + for (var i = 0, len = this.context.environments.length; i < len; i++) { + var environment = this.context.environments[i]; + if (environment && environment.equals(child)) { + return environment; + } + } + }, + + programExpression: function programExpression(guid) { + var child = this.environment.children[guid], + programParams = [child.index, 'data', child.blockParams]; + + if (this.useBlockParams || this.useDepths) { + programParams.push('blockParams'); + } + if (this.useDepths) { + programParams.push('depths'); + } + + return 'container.program(' + programParams.join(', ') + ')'; + }, + + useRegister: function useRegister(name) { + if (!this.registers[name]) { + this.registers[name] = true; + this.registers.list.push(name); + } + }, + + push: function push(expr) { + if (!(expr instanceof Literal)) { + expr = this.source.wrap(expr); + } + + this.inlineStack.push(expr); + return expr; + }, + + pushStackLiteral: function pushStackLiteral(item) { + this.push(new Literal(item)); + }, + + pushSource: function pushSource(source) { + if (this.pendingContent) { + this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); + this.pendingContent = undefined; + } + + if (source) { + this.source.push(source); + } + }, + + replaceStack: function replaceStack(callback) { + var prefix = ['('], + stack = undefined, + createdStack = undefined, + usedLiteral = undefined; + + /* istanbul ignore next */ + if (!this.isInline()) { + throw new _exception2['default']('replaceStack on non-inline'); + } + + // We want to merge the inline statement into the replacement statement via ',' + var top = this.popStack(true); + + if (top instanceof Literal) { + // Literals do not need to be inlined + stack = [top.value]; + prefix = ['(', stack]; + usedLiteral = true; + } else { + // Get or create the current stack name for use by the inline + createdStack = true; + var _name = this.incrStack(); + + prefix = ['((', this.push(_name), ' = ', top, ')']; + stack = this.topStack(); + } + + var item = callback.call(this, stack); + + if (!usedLiteral) { + this.popStack(); + } + if (createdStack) { + this.stackSlot--; + } + this.push(prefix.concat(item, ')')); + }, + + incrStack: function incrStack() { + this.stackSlot++; + if (this.stackSlot > this.stackVars.length) { + this.stackVars.push('stack' + this.stackSlot); + } + return this.topStackName(); + }, + topStackName: function topStackName() { + return 'stack' + this.stackSlot; + }, + flushInline: function flushInline() { + var inlineStack = this.inlineStack; + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + /* istanbul ignore if */ + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + var stack = this.incrStack(); + this.pushSource([stack, ' = ', entry, ';']); + this.compileStack.push(stack); + } + } + }, + isInline: function isInline() { + return this.inlineStack.length; + }, + + popStack: function popStack(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && item instanceof Literal) { + return item.value; + } else { + if (!inline) { + /* istanbul ignore next */ + if (!this.stackSlot) { + throw new _exception2['default']('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function topStack() { + var stack = this.isInline() ? this.inlineStack : this.compileStack, + item = stack[stack.length - 1]; + + /* istanbul ignore if */ + if (item instanceof Literal) { + return item.value; + } else { + return item; + } + }, + + contextName: function contextName(context) { + if (this.useDepths && context) { + return 'depths[' + context + ']'; + } else { + return 'depth' + context; + } + }, + + quotedString: function quotedString(str) { + return this.source.quotedString(str); + }, + + objectLiteral: function objectLiteral(obj) { + return this.source.objectLiteral(obj); + }, + + aliasable: function aliasable(name) { + var ret = this.aliases[name]; + if (ret) { + ret.referenceCount++; + return ret; + } + + ret = this.aliases[name] = this.source.wrap(name); + ret.aliasable = true; + ret.referenceCount = 1; + + return ret; + }, + + setupHelper: function setupHelper(paramSize, name, blockHelper) { + var params = [], + paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); + var foundHelper = this.nameLookup('helpers', name, 'helper'), + callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : (container.nullContext || {})'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: [callContext].concat(params) + }; + }, + + setupParams: function setupParams(helper, paramSize, params) { + var options = {}, + contexts = [], + types = [], + ids = [], + objectArgs = !params, + param = undefined; + + if (objectArgs) { + params = []; + } + + options.name = this.quotedString(helper); + options.hash = this.popStack(); + + if (this.trackIds) { + options.hashIds = this.popStack(); + } + if (this.stringParams) { + options.hashTypes = this.popStack(); + options.hashContexts = this.popStack(); + } + + var inverse = this.popStack(), + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + options.fn = program || 'container.noop'; + options.inverse = inverse || 'container.noop'; + } + + // The parameters go on to the stack in order (making sure that they are evaluated in order) + // so we need to pop them off the stack in reverse order + var i = paramSize; + while (i--) { + param = this.popStack(); + params[i] = param; + + if (this.trackIds) { + ids[i] = this.popStack(); + } + if (this.stringParams) { + types[i] = this.popStack(); + contexts[i] = this.popStack(); + } + } + + if (objectArgs) { + options.args = this.source.generateArray(params); + } + + if (this.trackIds) { + options.ids = this.source.generateArray(ids); + } + if (this.stringParams) { + options.types = this.source.generateArray(types); + options.contexts = this.source.generateArray(contexts); + } + + if (this.options.data) { + options.data = 'data'; + } + if (this.useBlockParams) { + options.blockParams = 'blockParams'; + } + return options; + }, + + setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) { + var options = this.setupParams(helper, paramSize, params); + options.loc = JSON.stringify(this.source.currentLocation); + options = this.objectLiteral(options); + if (useRegister) { + this.useRegister('options'); + params.push('options'); + return ['options=', options]; + } else if (params) { + params.push(options); + return ''; + } else { + return options; + } + } + }; + + (function () { + var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' '); + + var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; + + for (var i = 0, l = reservedWords.length; i < l; i++) { + compilerWords[reservedWords[i]] = true; + } + })(); + + /** + * @deprecated May be removed in the next major version + */ + JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { + return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); + }; + + function strictLookup(requireTerminal, compiler, parts, i, type) { + var stack = compiler.popStack(), + len = parts.length; + if (requireTerminal) { + len--; + } + + for (; i < len; i++) { + stack = compiler.nameLookup(stack, parts[i], type); + } + + if (requireTerminal) { + return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ', ', JSON.stringify(compiler.source.currentLocation), ' )']; + } else { + return stack; + } + } + + exports['default'] = JavaScriptCompiler; + module.exports = exports['default']; + +/***/ }), +/* 92 */ +/***/ (function(module, exports, __webpack_require__) { + + /* global define, require */ + 'use strict'; + + var _Object$keys = __webpack_require__(60)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var SourceNode = undefined; + + try { + /* istanbul ignore next */ + if (false) { + // We don't support this in AMD environments. For these environments, we assume that + // they are running on the browser and thus have no need for the source-map library. + var SourceMap = require('source-map'); + SourceNode = SourceMap.SourceNode; + } + } catch (err) {} + /* NOP */ + + /* istanbul ignore if: tested but not covered in istanbul due to dist build */ + if (!SourceNode) { + SourceNode = function (line, column, srcFile, chunks) { + this.src = ''; + if (chunks) { + this.add(chunks); + } + }; + /* istanbul ignore next */ + SourceNode.prototype = { + add: function add(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src += chunks; + }, + prepend: function prepend(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src = chunks + this.src; + }, + toStringWithSourceMap: function toStringWithSourceMap() { + return { code: this.toString() }; + }, + toString: function toString() { + return this.src; + } + }; + } + + function castChunk(chunk, codeGen, loc) { + if (_utils.isArray(chunk)) { + var ret = []; + + for (var i = 0, len = chunk.length; i < len; i++) { + ret.push(codeGen.wrap(chunk[i], loc)); + } + return ret; + } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { + // Handle primitives that the SourceNode will throw up on + return chunk + ''; + } + return chunk; + } + + function CodeGen(srcFile) { + this.srcFile = srcFile; + this.source = []; + } + + CodeGen.prototype = { + isEmpty: function isEmpty() { + return !this.source.length; + }, + prepend: function prepend(source, loc) { + this.source.unshift(this.wrap(source, loc)); + }, + push: function push(source, loc) { + this.source.push(this.wrap(source, loc)); + }, + + merge: function merge() { + var source = this.empty(); + this.each(function (line) { + source.add([' ', line, '\n']); + }); + return source; + }, + + each: function each(iter) { + for (var i = 0, len = this.source.length; i < len; i++) { + iter(this.source[i]); + } + }, + + empty: function empty() { + var loc = this.currentLocation || { start: {} }; + return new SourceNode(loc.start.line, loc.start.column, this.srcFile); + }, + wrap: function wrap(chunk) { + var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1]; + + if (chunk instanceof SourceNode) { + return chunk; + } + + chunk = castChunk(chunk, this, loc); + + return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); + }, + + functionCall: function functionCall(fn, type, params) { + params = this.generateList(params); + return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); + }, + + quotedString: function quotedString(str) { + return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + objectLiteral: function objectLiteral(obj) { + // istanbul ignore next + + var _this = this; + + var pairs = []; + + _Object$keys(obj).forEach(function (key) { + var value = castChunk(obj[key], _this); + if (value !== 'undefined') { + pairs.push([_this.quotedString(key), ':', value]); + } + }); + + var ret = this.generateList(pairs); + ret.prepend('{'); + ret.add('}'); + return ret; + }, + + generateList: function generateList(entries) { + var ret = this.empty(); + + for (var i = 0, len = entries.length; i < len; i++) { + if (i) { + ret.add(','); + } + + ret.add(castChunk(entries[i], this)); + } + + return ret; + }, + + generateArray: function generateArray(entries) { + var ret = this.generateList(entries); + ret.prepend('['); + ret.add(']'); + + return ret; + } + }; + + exports['default'] = CodeGen; + module.exports = exports['default']; + +/***/ }) +/******/ ]) +}); +; \ No newline at end of file diff -Nru pdns-recursor-5.2.13/html/js/moment.js pdns-recursor-5.4.9/html/js/moment.js --- pdns-recursor-5.2.13/html/js/moment.js 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/html/js/moment.js 2026-10-26 08:26:51.000000000 +0000 @@ -1,5 +1,5 @@ //! moment.js -//! version : 2.29.2 +//! version : 2.30.1 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com @@ -155,24 +155,25 @@ } function isValid(m) { - if (m._isValid == null) { - var flags = getParsingFlags(m), - parsedParts = some.call(flags.parsedDateParts, function (i) { - return i != null; - }), - isNowValid = - !isNaN(m._d.getTime()) && - flags.overflow < 0 && - !flags.empty && - !flags.invalidEra && - !flags.invalidMonth && - !flags.invalidWeekday && - !flags.weekdayMismatch && - !flags.nullInput && - !flags.invalidFormat && - !flags.userInvalidated && - (!flags.meridiem || (flags.meridiem && parsedParts)); - + var flags = null, + parsedParts = false, + isNowValid = m._d && !isNaN(m._d.getTime()); + if (isNowValid) { + flags = getParsingFlags(m); + parsedParts = some.call(flags.parsedDateParts, function (i) { + return i != null; + }); + isNowValid = + flags.overflow < 0 && + !flags.empty && + !flags.invalidEra && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.weekdayMismatch && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated && + (!flags.meridiem || (flags.meridiem && parsedParts)); if (m._strict) { isNowValid = isNowValid && @@ -180,12 +181,11 @@ flags.unusedTokens.length === 0 && flags.bigHour === undefined; } - - if (Object.isFrozen == null || !Object.isFrozen(m)) { - m._isValid = isNowValid; - } else { - return isNowValid; - } + } + if (Object.isFrozen == null || !Object.isFrozen(m)) { + m._isValid = isNowValid; + } else { + return isNowValid; } return m._isValid; } @@ -630,12 +630,56 @@ return isFunction(format) ? format(output) : format.replace(/%s/i, output); } - var aliases = {}; - - function addUnitAlias(unit, shorthand) { - var lowerCase = unit.toLowerCase(); - aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; - } + var aliases = { + D: 'date', + dates: 'date', + date: 'date', + d: 'day', + days: 'day', + day: 'day', + e: 'weekday', + weekdays: 'weekday', + weekday: 'weekday', + E: 'isoWeekday', + isoweekdays: 'isoWeekday', + isoweekday: 'isoWeekday', + DDD: 'dayOfYear', + dayofyears: 'dayOfYear', + dayofyear: 'dayOfYear', + h: 'hour', + hours: 'hour', + hour: 'hour', + ms: 'millisecond', + milliseconds: 'millisecond', + millisecond: 'millisecond', + m: 'minute', + minutes: 'minute', + minute: 'minute', + M: 'month', + months: 'month', + month: 'month', + Q: 'quarter', + quarters: 'quarter', + quarter: 'quarter', + s: 'second', + seconds: 'second', + second: 'second', + gg: 'weekYear', + weekyears: 'weekYear', + weekyear: 'weekYear', + GG: 'isoWeekYear', + isoweekyears: 'isoWeekYear', + isoweekyear: 'isoWeekYear', + w: 'week', + weeks: 'week', + week: 'week', + W: 'isoWeek', + isoweeks: 'isoWeek', + isoweek: 'isoWeek', + y: 'year', + years: 'year', + year: 'year', + }; function normalizeUnits(units) { return typeof units === 'string' @@ -660,11 +704,24 @@ return normalizedInput; } - var priorities = {}; - - function addUnitPriority(unit, priority) { - priorities[unit] = priority; - } + var priorities = { + date: 9, + day: 11, + weekday: 11, + isoWeekday: 11, + dayOfYear: 4, + hour: 13, + millisecond: 16, + minute: 14, + month: 8, + quarter: 7, + second: 15, + weekYear: 1, + isoWeekYear: 1, + week: 5, + isoWeek: 5, + year: 1, + }; function getPrioritizedUnits(unitsObj) { var units = [], @@ -680,96 +737,6 @@ return units; } - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - function absFloor(number) { - if (number < 0) { - // -0 -> 0 - return Math.ceil(number) || 0; - } else { - return Math.floor(number); - } - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - value = absFloor(coercedNumber); - } - - return value; - } - - function makeGetSet(unit, keepTime) { - return function (value) { - if (value != null) { - set$1(this, unit, value); - hooks.updateOffset(this, keepTime); - return this; - } else { - return get(this, unit); - } - }; - } - - function get(mom, unit) { - return mom.isValid() - ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() - : NaN; - } - - function set$1(mom, unit, value) { - if (mom.isValid() && !isNaN(value)) { - if ( - unit === 'FullYear' && - isLeapYear(mom.year()) && - mom.month() === 1 && - mom.date() === 29 - ) { - value = toInt(value); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( - value, - mom.month(), - daysInMonth(value, mom.month()) - ); - } else { - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - } - - // MOMENTS - - function stringGet(units) { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](); - } - return this; - } - - function stringSet(units, value) { - if (typeof units === 'object') { - units = normalizeObjectUnits(units); - var prioritized = getPrioritizedUnits(units), - i, - prioritizedLen = prioritized.length; - for (i = 0; i < prioritizedLen; i++) { - this[prioritized[i].unit](units[prioritized[i].unit]); - } - } else { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](value); - } - } - return this; - } - var match1 = /\d/, // 0 - 9 match2 = /\d\d/, // 00 - 99 match3 = /\d{3}/, // 000 - 999 @@ -790,6 +757,8 @@ // includes scottish gaelic two word and hyphenated months matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, + match1to2NoLeadingZero = /^[1-9]\d?/, // 1-99 + match1to2HasZero = /^([1-9]\d|\d)/, // 0-99 regexes; regexes = {}; @@ -828,6 +797,26 @@ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } + function absFloor(number) { + if (number < 0) { + // -0 -> 0 + return Math.ceil(number) || 0; + } else { + return Math.floor(number); + } + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; + } + var tokens = {}; function addParseToken(token, callback) { @@ -861,6 +850,10 @@ } } + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + var YEAR = 0, MONTH = 1, DATE = 2, @@ -871,6 +864,173 @@ WEEK = 7, WEEKDAY = 8; + // FORMATTING + + addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? zeroFill(y, 4) : '+' + y; + }); + + addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; + }); + + addFormatToken(0, ['YYYY', 4], 0, 'year'); + addFormatToken(0, ['YYYYY', 5], 0, 'year'); + addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + + // PARSING + + addRegexToken('Y', matchSigned); + addRegexToken('YY', match1to2, match2); + addRegexToken('YYYY', match1to4, match4); + addRegexToken('YYYYY', match1to6, match6); + addRegexToken('YYYYYY', match1to6, match6); + + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = + input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); + }); + addParseToken('YY', function (input, array) { + array[YEAR] = hooks.parseTwoDigitYear(input); + }); + addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); + }); + + // HELPERS + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + // HOOKS + + hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + // MOMENTS + + var getSetYear = makeGetSet('FullYear', true); + + function getIsLeapYear() { + return isLeapYear(this.year()); + } + + function makeGetSet(unit, keepTime) { + return function (value) { + if (value != null) { + set$1(this, unit, value); + hooks.updateOffset(this, keepTime); + return this; + } else { + return get(this, unit); + } + }; + } + + function get(mom, unit) { + if (!mom.isValid()) { + return NaN; + } + + var d = mom._d, + isUTC = mom._isUTC; + + switch (unit) { + case 'Milliseconds': + return isUTC ? d.getUTCMilliseconds() : d.getMilliseconds(); + case 'Seconds': + return isUTC ? d.getUTCSeconds() : d.getSeconds(); + case 'Minutes': + return isUTC ? d.getUTCMinutes() : d.getMinutes(); + case 'Hours': + return isUTC ? d.getUTCHours() : d.getHours(); + case 'Date': + return isUTC ? d.getUTCDate() : d.getDate(); + case 'Day': + return isUTC ? d.getUTCDay() : d.getDay(); + case 'Month': + return isUTC ? d.getUTCMonth() : d.getMonth(); + case 'FullYear': + return isUTC ? d.getUTCFullYear() : d.getFullYear(); + default: + return NaN; // Just in case + } + } + + function set$1(mom, unit, value) { + var d, isUTC, year, month, date; + + if (!mom.isValid() || isNaN(value)) { + return; + } + + d = mom._d; + isUTC = mom._isUTC; + + switch (unit) { + case 'Milliseconds': + return void (isUTC + ? d.setUTCMilliseconds(value) + : d.setMilliseconds(value)); + case 'Seconds': + return void (isUTC ? d.setUTCSeconds(value) : d.setSeconds(value)); + case 'Minutes': + return void (isUTC ? d.setUTCMinutes(value) : d.setMinutes(value)); + case 'Hours': + return void (isUTC ? d.setUTCHours(value) : d.setHours(value)); + case 'Date': + return void (isUTC ? d.setUTCDate(value) : d.setDate(value)); + // case 'Day': // Not real + // return void (isUTC ? d.setUTCDay(value) : d.setDay(value)); + // case 'Month': // Not used because we need to pass two variables + // return void (isUTC ? d.setUTCMonth(value) : d.setMonth(value)); + case 'FullYear': + break; // See below ... + default: + return; // Just in case + } + + year = value; + month = mom.month(); + date = mom.date(); + date = date === 29 && month === 1 && !isLeapYear(year) ? 28 : date; + void (isUTC + ? d.setUTCFullYear(year, month, date) + : d.setFullYear(year, month, date)); + } + + // MOMENTS + + function stringGet(units) { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](); + } + return this; + } + + function stringSet(units, value) { + if (typeof units === 'object') { + units = normalizeObjectUnits(units); + var prioritized = getPrioritizedUnits(units), + i, + prioritizedLen = prioritized.length; + for (i = 0; i < prioritizedLen; i++) { + this[prioritized[i].unit](units[prioritized[i].unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; + } + function mod(n, x) { return ((n % x) + x) % x; } @@ -919,17 +1079,9 @@ return this.localeData().months(this, format); }); - // ALIASES - - addUnitAlias('month', 'M'); - - // PRIORITY - - addUnitPriority('month', 8); - // PARSING - addRegexToken('M', match1to2); + addRegexToken('M', match1to2, match1to2NoLeadingZero); addRegexToken('MM', match1to2, match2); addRegexToken('MMM', function (isStrict, locale) { return locale.monthsShortRegex(isStrict); @@ -1095,8 +1247,6 @@ // MOMENTS function setMonth(mom, value) { - var dayOfMonth; - if (!mom.isValid()) { // No op return mom; @@ -1114,8 +1264,13 @@ } } - dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + var month = value, + date = mom.date(); + + date = date < 29 ? date : Math.min(date, daysInMonth(mom.year(), month)); + void (mom._isUTC + ? mom._d.setUTCMonth(month, date) + : mom._d.setMonth(month, date)); return mom; } @@ -1182,27 +1337,24 @@ longPieces = [], mixedPieces = [], i, - mom; + mom, + shortP, + longP; for (i = 0; i < 12; i++) { // make the regex if we don't have it already mom = createUTC([2000, i]); - shortPieces.push(this.monthsShort(mom, '')); - longPieces.push(this.months(mom, '')); - mixedPieces.push(this.months(mom, '')); - mixedPieces.push(this.monthsShort(mom, '')); + shortP = regexEscape(this.monthsShort(mom, '')); + longP = regexEscape(this.months(mom, '')); + shortPieces.push(shortP); + longPieces.push(longP); + mixedPieces.push(longP); + mixedPieces.push(shortP); } // Sorting makes sure if one month (or abbr) is a prefix of another it // will match the longer piece. shortPieces.sort(cmpLenRev); longPieces.sort(cmpLenRev); mixedPieces.sort(cmpLenRev); - for (i = 0; i < 12; i++) { - shortPieces[i] = regexEscape(shortPieces[i]); - longPieces[i] = regexEscape(longPieces[i]); - } - for (i = 0; i < 24; i++) { - mixedPieces[i] = regexEscape(mixedPieces[i]); - } this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); this._monthsShortRegex = this._monthsRegex; @@ -1216,69 +1368,6 @@ ); } - // FORMATTING - - addFormatToken('Y', 0, 0, function () { - var y = this.year(); - return y <= 9999 ? zeroFill(y, 4) : '+' + y; - }); - - addFormatToken(0, ['YY', 2], 0, function () { - return this.year() % 100; - }); - - addFormatToken(0, ['YYYY', 4], 0, 'year'); - addFormatToken(0, ['YYYYY', 5], 0, 'year'); - addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); - - // ALIASES - - addUnitAlias('year', 'y'); - - // PRIORITIES - - addUnitPriority('year', 1); - - // PARSING - - addRegexToken('Y', matchSigned); - addRegexToken('YY', match1to2, match2); - addRegexToken('YYYY', match1to4, match4); - addRegexToken('YYYYY', match1to6, match6); - addRegexToken('YYYYYY', match1to6, match6); - - addParseToken(['YYYYY', 'YYYYYY'], YEAR); - addParseToken('YYYY', function (input, array) { - array[YEAR] = - input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); - }); - addParseToken('YY', function (input, array) { - array[YEAR] = hooks.parseTwoDigitYear(input); - }); - addParseToken('Y', function (input, array) { - array[YEAR] = parseInt(input, 10); - }); - - // HELPERS - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - // HOOKS - - hooks.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - // MOMENTS - - var getSetYear = makeGetSet('FullYear', true); - - function getIsLeapYear() { - return isLeapYear(this.year()); - } - function createDate(y, m, d, h, M, s, ms) { // can't just apply() to create a date: // https://stackoverflow.com/q/181348 @@ -1384,21 +1473,11 @@ addFormatToken('w', ['ww', 2], 'wo', 'week'); addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); - // ALIASES - - addUnitAlias('week', 'w'); - addUnitAlias('isoWeek', 'W'); - - // PRIORITIES - - addUnitPriority('week', 5); - addUnitPriority('isoWeek', 5); - // PARSING - addRegexToken('w', match1to2); + addRegexToken('w', match1to2, match1to2NoLeadingZero); addRegexToken('ww', match1to2, match2); - addRegexToken('W', match1to2); + addRegexToken('W', match1to2, match1to2NoLeadingZero); addRegexToken('WW', match1to2, match2); addWeekParseToken( @@ -1460,17 +1539,6 @@ addFormatToken('e', 0, 0, 'weekday'); addFormatToken('E', 0, 0, 'isoWeekday'); - // ALIASES - - addUnitAlias('day', 'd'); - addUnitAlias('weekday', 'e'); - addUnitAlias('isoWeekday', 'E'); - - // PRIORITY - addUnitPriority('day', 11); - addUnitPriority('weekday', 11); - addUnitPriority('isoWeekday', 11); - // PARSING addRegexToken('d', match1to2); @@ -1550,24 +1618,24 @@ return m === true ? shiftWeekdays(weekdays, this._week.dow) : m - ? weekdays[m.day()] - : weekdays; + ? weekdays[m.day()] + : weekdays; } function localeWeekdaysShort(m) { return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m - ? this._weekdaysShort[m.day()] - : this._weekdaysShort; + ? this._weekdaysShort[m.day()] + : this._weekdaysShort; } function localeWeekdaysMin(m) { return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m - ? this._weekdaysMin[m.day()] - : this._weekdaysMin; + ? this._weekdaysMin[m.day()] + : this._weekdaysMin; } function handleStrictParse$1(weekdayName, format, strict) { @@ -1716,7 +1784,8 @@ if (!this.isValid()) { return input != null ? this : NaN; } - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + + var day = get(this, 'Day'); if (input != null) { input = parseWeekday(input, this.localeData()); return this.add(input - day, 'd'); @@ -1915,13 +1984,6 @@ meridiem('a', true); meridiem('A', false); - // ALIASES - - addUnitAlias('hour', 'h'); - - // PRIORITY - addUnitPriority('hour', 13); - // PARSING function matchMeridiem(isStrict, locale) { @@ -1930,9 +1992,9 @@ addRegexToken('a', matchMeridiem); addRegexToken('A', matchMeridiem); - addRegexToken('H', match1to2); - addRegexToken('h', match1to2); - addRegexToken('k', match1to2); + addRegexToken('H', match1to2, match1to2HasZero); + addRegexToken('h', match1to2, match1to2NoLeadingZero); + addRegexToken('k', match1to2, match1to2NoLeadingZero); addRegexToken('HH', match1to2, match2); addRegexToken('hh', match1to2, match2); addRegexToken('kk', match1to2, match2); @@ -2082,7 +2144,8 @@ function isLocaleNameSane(name) { // Prevent names that look like filesystem paths, i.e contain '/' or '\' - return name.match('^[^/\\\\]*$') != null; + // Ensure name is available and function returns boolean + return !!(name && name.match('^[^/\\\\]*$')); } function loadLocale(name) { @@ -2274,21 +2337,21 @@ a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) - ? DATE - : a[HOUR] < 0 || - a[HOUR] > 24 || - (a[HOUR] === 24 && - (a[MINUTE] !== 0 || - a[SECOND] !== 0 || - a[MILLISECOND] !== 0)) - ? HOUR - : a[MINUTE] < 0 || a[MINUTE] > 59 - ? MINUTE - : a[SECOND] < 0 || a[SECOND] > 59 - ? SECOND - : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 - ? MILLISECOND - : -1; + ? DATE + : a[HOUR] < 0 || + a[HOUR] > 24 || + (a[HOUR] === 24 && + (a[MINUTE] !== 0 || + a[SECOND] !== 0 || + a[MILLISECOND] !== 0)) + ? HOUR + : a[MINUTE] < 0 || a[MINUTE] > 59 + ? MINUTE + : a[SECOND] < 0 || a[SECOND] > 59 + ? SECOND + : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 + ? MILLISECOND + : -1; if ( getParsingFlags(m)._overflowDayOfYear && @@ -2454,7 +2517,7 @@ function preprocessRFC2822(s) { // Remove comments and folding whitespace and replace multiple-spaces with a single space return s - .replace(/\([^)]*\)|[\n\t]/g, ' ') + .replace(/\([^()]*\)|[\n\t]/g, ' ') .replace(/(\s\s+)/g, ' ') .replace(/^\s\s*/, '') .replace(/\s\s*$/, ''); @@ -3729,16 +3792,16 @@ return diff < -6 ? 'sameElse' : diff < -1 - ? 'lastWeek' - : diff < 0 - ? 'lastDay' - : diff < 1 - ? 'sameDay' - : diff < 2 - ? 'nextDay' - : diff < 7 - ? 'nextWeek' - : 'sameElse'; + ? 'lastWeek' + : diff < 0 + ? 'lastDay' + : diff < 1 + ? 'sameDay' + : diff < 2 + ? 'nextDay' + : diff < 7 + ? 'nextWeek' + : 'sameElse'; } function calendar$1(time, formats) { @@ -4546,16 +4609,22 @@ mixedPieces = [], i, l, + erasName, + erasAbbr, + erasNarrow, eras = this.eras(); for (i = 0, l = eras.length; i < l; ++i) { - namePieces.push(regexEscape(eras[i].name)); - abbrPieces.push(regexEscape(eras[i].abbr)); - narrowPieces.push(regexEscape(eras[i].narrow)); - - mixedPieces.push(regexEscape(eras[i].name)); - mixedPieces.push(regexEscape(eras[i].abbr)); - mixedPieces.push(regexEscape(eras[i].narrow)); + erasName = regexEscape(eras[i].name); + erasAbbr = regexEscape(eras[i].abbr); + erasNarrow = regexEscape(eras[i].narrow); + + namePieces.push(erasName); + abbrPieces.push(erasAbbr); + narrowPieces.push(erasNarrow); + mixedPieces.push(erasName); + mixedPieces.push(erasAbbr); + mixedPieces.push(erasNarrow); } this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); @@ -4588,14 +4657,6 @@ // ALIASES - addUnitAlias('weekYear', 'gg'); - addUnitAlias('isoWeekYear', 'GG'); - - // PRIORITY - - addUnitPriority('weekYear', 1); - addUnitPriority('isoWeekYear', 1); - // PARSING addRegexToken('G', matchSigned); @@ -4625,7 +4686,7 @@ this, input, this.week(), - this.weekday(), + this.weekday() + this.localeData()._week.dow, this.localeData()._week.dow, this.localeData()._week.doy ); @@ -4687,14 +4748,6 @@ addFormatToken('Q', 0, 'Qo', 'quarter'); - // ALIASES - - addUnitAlias('quarter', 'Q'); - - // PRIORITY - - addUnitPriority('quarter', 7); - // PARSING addRegexToken('Q', match1); @@ -4714,16 +4767,9 @@ addFormatToken('D', ['DD', 2], 'Do', 'date'); - // ALIASES - - addUnitAlias('date', 'D'); - - // PRIORITY - addUnitPriority('date', 9); - // PARSING - addRegexToken('D', match1to2); + addRegexToken('D', match1to2, match1to2NoLeadingZero); addRegexToken('DD', match1to2, match2); addRegexToken('Do', function (isStrict, locale) { // TODO: Remove "ordinalParse" fallback in next major release. @@ -4745,13 +4791,6 @@ addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); - // ALIASES - - addUnitAlias('dayOfYear', 'DDD'); - - // PRIORITY - addUnitPriority('dayOfYear', 4); - // PARSING addRegexToken('DDD', match1to3); @@ -4776,17 +4815,9 @@ addFormatToken('m', ['mm', 2], 0, 'minute'); - // ALIASES - - addUnitAlias('minute', 'm'); - - // PRIORITY - - addUnitPriority('minute', 14); - // PARSING - addRegexToken('m', match1to2); + addRegexToken('m', match1to2, match1to2HasZero); addRegexToken('mm', match1to2, match2); addParseToken(['m', 'mm'], MINUTE); @@ -4798,17 +4829,9 @@ addFormatToken('s', ['ss', 2], 0, 'second'); - // ALIASES - - addUnitAlias('second', 's'); - - // PRIORITY - - addUnitPriority('second', 15); - // PARSING - addRegexToken('s', match1to2); + addRegexToken('s', match1to2, match1to2HasZero); addRegexToken('ss', match1to2, match2); addParseToken(['s', 'ss'], SECOND); @@ -4846,14 +4869,6 @@ return this.millisecond() * 1000000; }); - // ALIASES - - addUnitAlias('millisecond', 'ms'); - - // PRIORITY - - addUnitPriority('millisecond', 16); - // PARSING addRegexToken('S', match1to3, match1); @@ -5161,12 +5176,12 @@ toInt((number % 100) / 10) === 1 ? 'th' : b === 1 - ? 'st' - : b === 2 - ? 'nd' - : b === 3 - ? 'rd' - : 'th'; + ? 'st' + : b === 2 + ? 'nd' + : b === 3 + ? 'rd' + : 'th'; return number + output; }, }); @@ -5339,19 +5354,6 @@ } } - // TODO: Use this.as('ms')? - function valueOf$1() { - if (!this.isValid()) { - return NaN; - } - return ( - this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6 - ); - } - function makeAs(alias) { return function () { return this.as(alias); @@ -5366,7 +5368,8 @@ asWeeks = makeAs('w'), asMonths = makeAs('M'), asQuarters = makeAs('Q'), - asYears = makeAs('y'); + asYears = makeAs('y'), + valueOf$1 = asMilliseconds; function clone$1() { return createDuration(this); @@ -5635,7 +5638,7 @@ //! moment.js - hooks.version = '2.29.2'; + hooks.version = '2.30.1'; setHookCallback(createLocal); diff -Nru pdns-recursor-5.2.13/html/js/moment.min.js pdns-recursor-5.4.9/html/js/moment.min.js --- pdns-recursor-5.2.13/html/js/moment.min.js 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/html/js/moment.min.js 2026-10-26 08:26:51.000000000 +0000 @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var H;function f(){return H.apply(null,arguments)}function a(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function F(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function c(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function L(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;for(var t in e)if(c(e,t))return;return 1}function o(e){return void 0===e}function u(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function V(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function G(e,t){for(var n=[],s=e.length,i=0;i>>0,s=0;sAe(e)?(r=e+1,t-Ae(e)):(r=e,t);return{year:r,dayOfYear:n}}function qe(e,t,n){var s,i,r=ze(e.year(),t,n),r=Math.floor((e.dayOfYear()-r-1)/7)+1;return r<1?s=r+P(i=e.year()-1,t,n):r>P(e.year(),t,n)?(s=r-P(e.year(),t,n),i=e.year()+1):(i=e.year(),s=r),{week:s,year:i}}function P(e,t,n){var s=ze(e,t,n),t=ze(e+1,t,n);return(Ae(e)-s+t)/7}s("w",["ww",2],"wo","week"),s("W",["WW",2],"Wo","isoWeek"),t("week","w"),t("isoWeek","W"),n("week",5),n("isoWeek",5),v("w",p),v("ww",p,w),v("W",p),v("WW",p,w),Te(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=g(e)});function Be(e,t){return e.slice(t,7).concat(e.slice(0,t))}s("d",0,"do","day"),s("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),s("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),s("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),s("e",0,0,"weekday"),s("E",0,0,"isoWeekday"),t("day","d"),t("weekday","e"),t("isoWeekday","E"),n("day",11),n("weekday",11),n("isoWeekday",11),v("d",p),v("e",p),v("E",p),v("dd",function(e,t){return t.weekdaysMinRegex(e)}),v("ddd",function(e,t){return t.weekdaysShortRegex(e)}),v("dddd",function(e,t){return t.weekdaysRegex(e)}),Te(["dd","ddd","dddd"],function(e,t,n,s){s=n._locale.weekdaysParse(e,s,n._strict);null!=s?t.d=s:m(n).invalidWeekday=e}),Te(["d","e","E"],function(e,t,n,s){t[s]=g(e)});var Je="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Qe="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Xe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Ke=k,et=k,tt=k;function nt(){function e(e,t){return t.length-e.length}for(var t,n,s,i=[],r=[],a=[],o=[],u=0;u<7;u++)s=l([2e3,1]).day(u),t=M(this.weekdaysMin(s,"")),n=M(this.weekdaysShort(s,"")),s=M(this.weekdays(s,"")),i.push(t),r.push(n),a.push(s),o.push(t),o.push(n),o.push(s);i.sort(e),r.sort(e),a.sort(e),o.sort(e),this._weekdaysRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+r.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function st(){return this.hours()%12||12}function it(e,t){s(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function rt(e,t){return t._meridiemParse}s("H",["HH",2],0,"hour"),s("h",["hh",2],0,st),s("k",["kk",2],0,function(){return this.hours()||24}),s("hmm",0,0,function(){return""+st.apply(this)+r(this.minutes(),2)}),s("hmmss",0,0,function(){return""+st.apply(this)+r(this.minutes(),2)+r(this.seconds(),2)}),s("Hmm",0,0,function(){return""+this.hours()+r(this.minutes(),2)}),s("Hmmss",0,0,function(){return""+this.hours()+r(this.minutes(),2)+r(this.seconds(),2)}),it("a",!0),it("A",!1),t("hour","h"),n("hour",13),v("a",rt),v("A",rt),v("H",p),v("h",p),v("k",p),v("HH",p,w),v("hh",p,w),v("kk",p,w),v("hmm",ge),v("hmmss",we),v("Hmm",ge),v("Hmmss",we),D(["H","HH"],x),D(["k","kk"],function(e,t,n){e=g(e);t[x]=24===e?0:e}),D(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),D(["h","hh"],function(e,t,n){t[x]=g(e),m(n).bigHour=!0}),D("hmm",function(e,t,n){var s=e.length-2;t[x]=g(e.substr(0,s)),t[T]=g(e.substr(s)),m(n).bigHour=!0}),D("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[x]=g(e.substr(0,s)),t[T]=g(e.substr(s,2)),t[N]=g(e.substr(i)),m(n).bigHour=!0}),D("Hmm",function(e,t,n){var s=e.length-2;t[x]=g(e.substr(0,s)),t[T]=g(e.substr(s))}),D("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[x]=g(e.substr(0,s)),t[T]=g(e.substr(s,2)),t[N]=g(e.substr(i))});k=de("Hours",!0);var at,ot={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Ce,monthsShort:Ue,week:{dow:0,doy:6},weekdays:Je,weekdaysMin:Xe,weekdaysShort:Qe,meridiemParse:/[ap]\.?m?\.?/i},R={},ut={};function lt(e){return e&&e.toLowerCase().replace("_","-")}function ht(e){for(var t,n,s,i,r=0;r=t&&function(e,t){for(var n=Math.min(e.length,t.length),s=0;s=t-1)break;t--}r++}return at}function dt(t){var e;if(void 0===R[t]&&"undefined"!=typeof module&&module&&module.exports&&null!=t.match("^[^/\\\\]*$"))try{e=at._abbr,require("./locale/"+t),ct(e)}catch(e){R[t]=null}return R[t]}function ct(e,t){return e&&((t=o(t)?mt(e):ft(e,t))?at=t:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),at._abbr}function ft(e,t){if(null===t)return delete R[e],null;var n,s=ot;if(t.abbr=e,null!=R[e])Q("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=R[e]._config;else if(null!=t.parentLocale)if(null!=R[t.parentLocale])s=R[t.parentLocale]._config;else{if(null==(n=dt(t.parentLocale)))return ut[t.parentLocale]||(ut[t.parentLocale]=[]),ut[t.parentLocale].push({name:e,config:t}),null;s=n._config}return R[e]=new K(X(s,t)),ut[e]&&ut[e].forEach(function(e){ft(e.name,e.config)}),ct(e),R[e]}function mt(e){var t;if(!(e=e&&e._locale&&e._locale._abbr?e._locale._abbr:e))return at;if(!a(e)){if(t=dt(e))return t;e=[e]}return ht(e)}function _t(e){var t=e._a;return t&&-2===m(e).overflow&&(t=t[O]<0||11We(t[Y],t[O])?b:t[x]<0||24P(r,u,l)?m(s)._overflowWeeks=!0:null!=h?m(s)._overflowWeekday=!0:(d=$e(r,a,o,u,l),s._a[Y]=d.year,s._dayOfYear=d.dayOfYear)),null!=e._dayOfYear&&(i=bt(e._a[Y],n[Y]),(e._dayOfYear>Ae(i)||0===e._dayOfYear)&&(m(e)._overflowDayOfYear=!0),h=Ze(i,0,e._dayOfYear),e._a[O]=h.getUTCMonth(),e._a[b]=h.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=c[t]=n[t];for(;t<7;t++)e._a[t]=c[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[x]&&0===e._a[T]&&0===e._a[N]&&0===e._a[Ne]&&(e._nextDay=!0,e._a[x]=0),e._d=(e._useUTC?Ze:je).apply(null,c),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[x]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(m(e).weekdayMismatch=!0)}}function Tt(e){if(e._f===f.ISO_8601)St(e);else if(e._f===f.RFC_2822)Ot(e);else{e._a=[],m(e).empty=!0;for(var t,n,s,i,r,a=""+e._i,o=a.length,u=0,l=ae(e._f,e._locale).match(te)||[],h=l.length,d=0;de.valueOf():e.valueOf()"}),i.toJSON=function(){return this.isValid()?this.toISOString():null},i.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},i.unix=function(){return Math.floor(this.valueOf()/1e3)},i.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},i.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},i.eraName=function(){for(var e,t=this.localeData().eras(),n=0,s=t.length;nthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},i.isLocal=function(){return!!this.isValid()&&!this._isUTC},i.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},i.isUtc=At,i.isUTC=At,i.zoneAbbr=function(){return this._isUTC?"UTC":""},i.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},i.dates=e("dates accessor is deprecated. Use date instead.",ke),i.months=e("months accessor is deprecated. Use month instead",Ge),i.years=e("years accessor is deprecated. Use year instead",Ie),i.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?(this.utcOffset(e="string"!=typeof e?-e:e,t),this):-this.utcOffset()}),i.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!o(this._isDSTShifted))return this._isDSTShifted;var e,t={};return $(t,this),(t=Nt(t))._a?(e=(t._isUTC?l:W)(t._a),this._isDSTShifted=this.isValid()&&0>>0,s=0;sWe(e)?(r=e+1,t-We(e)):(r=e,t);return{year:r,dayOfYear:n}}function Be(e,t,n){var s,i,r=qe(e.year(),t,n),r=Math.floor((e.dayOfYear()-r-1)/7)+1;return r<1?s=r+N(i=e.year()-1,t,n):r>N(e.year(),t,n)?(s=r-N(e.year(),t,n),i=e.year()+1):(i=e.year(),s=r),{week:s,year:i}}function N(e,t,n){var s=qe(e,t,n),t=qe(e+1,t,n);return(We(e)-s+t)/7}s("w",["ww",2],"wo","week"),s("W",["WW",2],"Wo","isoWeek"),h("w",n,u),h("ww",n,t),h("W",n,u),h("WW",n,t),Oe(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=M(e)});function Je(e,t){return e.slice(t,7).concat(e.slice(0,t))}s("d",0,"do","day"),s("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),s("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),s("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),s("e",0,0,"weekday"),s("E",0,0,"isoWeekday"),h("d",n),h("e",n),h("E",n),h("dd",function(e,t){return t.weekdaysMinRegex(e)}),h("ddd",function(e,t){return t.weekdaysShortRegex(e)}),h("dddd",function(e,t){return t.weekdaysRegex(e)}),Oe(["dd","ddd","dddd"],function(e,t,n,s){s=n._locale.weekdaysParse(e,s,n._strict);null!=s?t.d=s:p(n).invalidWeekday=e}),Oe(["d","e","E"],function(e,t,n,s){t[s]=M(e)});var Qe="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Xe="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ke="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),et=i,tt=i,nt=i;function st(){function e(e,t){return t.length-e.length}for(var t,n,s,i=[],r=[],a=[],o=[],u=0;u<7;u++)s=l([2e3,1]).day(u),t=f(this.weekdaysMin(s,"")),n=f(this.weekdaysShort(s,"")),s=f(this.weekdays(s,"")),i.push(t),r.push(n),a.push(s),o.push(t),o.push(n),o.push(s);i.sort(e),r.sort(e),a.sort(e),o.sort(e),this._weekdaysRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+r.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function it(){return this.hours()%12||12}function rt(e,t){s(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function at(e,t){return t._meridiemParse}s("H",["HH",2],0,"hour"),s("h",["hh",2],0,it),s("k",["kk",2],0,function(){return this.hours()||24}),s("hmm",0,0,function(){return""+it.apply(this)+r(this.minutes(),2)}),s("hmmss",0,0,function(){return""+it.apply(this)+r(this.minutes(),2)+r(this.seconds(),2)}),s("Hmm",0,0,function(){return""+this.hours()+r(this.minutes(),2)}),s("Hmmss",0,0,function(){return""+this.hours()+r(this.minutes(),2)+r(this.seconds(),2)}),rt("a",!0),rt("A",!1),h("a",at),h("A",at),h("H",n,d),h("h",n,u),h("k",n,u),h("HH",n,t),h("hh",n,t),h("kk",n,t),h("hmm",me),h("hmmss",_e),h("Hmm",me),h("Hmmss",_e),v(["H","HH"],O),v(["k","kk"],function(e,t,n){e=M(e);t[O]=24===e?0:e}),v(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),v(["h","hh"],function(e,t,n){t[O]=M(e),p(n).bigHour=!0}),v("hmm",function(e,t,n){var s=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s)),p(n).bigHour=!0}),v("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s,2)),t[T]=M(e.substr(i)),p(n).bigHour=!0}),v("Hmm",function(e,t,n){var s=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s))}),v("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s,2)),t[T]=M(e.substr(i))});i=Re("Hours",!0);var ot,ut={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Fe,monthsShort:Le,week:{dow:0,doy:6},weekdays:Qe,weekdaysMin:Ke,weekdaysShort:Xe,meridiemParse:/[ap]\.?m?\.?/i},W={},lt={};function dt(e){return e&&e.toLowerCase().replace("_","-")}function ht(e){for(var t,n,s,i,r=0;r=t&&function(e,t){for(var n=Math.min(e.length,t.length),s=0;s=t-1)break;t--}r++}return ot}function ct(t){var e,n;if(void 0===W[t]&&"undefined"!=typeof module&&module&&module.exports&&(n=t)&&n.match("^[^/\\\\]*$"))try{e=ot._abbr,require("./locale/"+t),ft(e)}catch(e){W[t]=null}return W[t]}function ft(e,t){return e&&((t=g(t)?P(e):mt(e,t))?ot=t:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),ot._abbr}function mt(e,t){if(null===t)return delete W[e],null;var n,s=ut;if(t.abbr=e,null!=W[e])Q("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=W[e]._config;else if(null!=t.parentLocale)if(null!=W[t.parentLocale])s=W[t.parentLocale]._config;else{if(null==(n=ct(t.parentLocale)))return lt[t.parentLocale]||(lt[t.parentLocale]=[]),lt[t.parentLocale].push({name:e,config:t}),null;s=n._config}return W[e]=new K(X(s,t)),lt[e]&<[e].forEach(function(e){mt(e.name,e.config)}),ft(e),W[e]}function P(e){var t;if(!(e=e&&e._locale&&e._locale._abbr?e._locale._abbr:e))return ot;if(!y(e)){if(t=ct(e))return t;e=[e]}return ht(e)}function _t(e){var t=e._a;return t&&-2===p(e).overflow&&(t=t[Y]<0||11He(t[D],t[Y])?S:t[O]<0||24N(r,u,l)?p(s)._overflowWeeks=!0:null!=d?p(s)._overflowWeekday=!0:(h=$e(r,a,o,u,l),s._a[D]=h.year,s._dayOfYear=h.dayOfYear)),null!=e._dayOfYear&&(i=bt(e._a[D],n[D]),(e._dayOfYear>We(i)||0===e._dayOfYear)&&(p(e)._overflowDayOfYear=!0),d=ze(i,0,e._dayOfYear),e._a[Y]=d.getUTCMonth(),e._a[S]=d.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=c[t]=n[t];for(;t<7;t++)e._a[t]=c[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[O]&&0===e._a[b]&&0===e._a[T]&&0===e._a[Te]&&(e._nextDay=!0,e._a[O]=0),e._d=(e._useUTC?ze:Ze).apply(null,c),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[O]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(p(e).weekdayMismatch=!0)}}function xt(e){if(e._f===_.ISO_8601)Yt(e);else if(e._f===_.RFC_2822)Ot(e);else{e._a=[],p(e).empty=!0;for(var t,n,s,i,r,a=""+e._i,o=a.length,u=0,l=ae(e._f,e._locale).match(te)||[],d=l.length,h=0;he.valueOf():e.valueOf()"}),u.toJSON=function(){return this.isValid()?this.toISOString():null},u.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},u.unix=function(){return Math.floor(this.valueOf()/1e3)},u.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},u.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},u.eraName=function(){for(var e,t=this.localeData().eras(),n=0,s=t.length;nthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},u.isLocal=function(){return!!this.isValid()&&!this._isUTC},u.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},u.isUtc=At,u.isUTC=At,u.zoneAbbr=function(){return this._isUTC?"UTC":""},u.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},u.dates=e("dates accessor is deprecated. Use date instead.",ge),u.months=e("months accessor is deprecated. Use month instead",Ie),u.years=e("years accessor is deprecated. Use year instead",Pe),u.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?(this.utcOffset(e="string"!=typeof e?-e:e,t),this):-this.utcOffset()}),u.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){var e,t;return g(this._isDSTShifted)&&(q(e={},this),(e=Nt(e))._a?(t=(e._isUTC?l:R)(e._a),this._isDSTShifted=this.isValid()&&0 0) { + var x = s.data[0].x; + var y = s.data[0].y; + + if (typeof x != 'number' || ( typeof y != 'number' && y !== null ) ) { + throw "x and y properties of points should be numbers instead of " + + (typeof x) + " and " + (typeof y); + } } if (s.data.length >= 3) { @@ -472,6 +480,12 @@ }, this ); }; + this.setSeries = function(series) { + this.validateSeries(series); + this.series = series; + this.series.active = function() { return self.series.filter( function(s) { return !s.disabled } ) }; + }; + this.dataDomain = function() { var data = this.series.map( function(s) { return s.data } ); @@ -486,8 +500,17 @@ var domain = this.renderer.domain(); - this.x = (this.xScale || d3.scale.linear()).domain(domain.x).range([0, this.width]); - this.y = (this.yScale || d3.scale.linear()).domain(domain.y).range([this.height, 0]); + // this.*Scale is coming from the configuration dictionary + // which may be referenced by the Graph creator, or shared + // with other Graphs. We need to ensure we copy the scale + // so that our mutations do not change the object given to us. + // Hence the .copy() + this.x = (this.xScale || d3.scale.linear()).copy().domain(domain.x).range([0, this.width]); + this.y = (this.yScale || d3.scale.linear()).copy().domain(domain.y).range([this.height, 0]); + + this.x.magnitude = d3.scale.linear() + .domain([domain.x[0] - domain.x[0], domain.x[1] - domain.x[0]]) + .range([0, this.width]); this.y.magnitude = d3.scale.linear() .domain([domain.y[0] - domain.y[0], domain.y[1] - domain.y[0]]) @@ -643,6 +666,8 @@ this[k] = this.config[k]; }, this ); + if ('stack' in args) args.unstack = !args.stack; + var renderer = args.renderer || (this.renderer && this.renderer.name) || 'stack'; this.setRenderer(renderer, args); @@ -671,14 +696,21 @@ args = args || {}; - if (typeof window !== undefined) { - var style = window.getComputedStyle(this.element, null); - var elementWidth = parseInt(style.getPropertyValue('width'), 10); - var elementHeight = parseInt(style.getPropertyValue('height'), 10); - } + if (args.width && args.height) { + // use explicitly specified size + this.width = args.width; + this.height = args.height; + } else { + // calc size (will cause layout reflow) + if (typeof window !== 'undefined') { + var style = window.getComputedStyle(this.element, null); + var elementWidth = parseInt(style.getPropertyValue('width'), 10); + var elementHeight = parseInt(style.getPropertyValue('height'), 10); + } - this.width = args.width || elementWidth || 400; - this.height = args.height || elementHeight || 250; + this.width = args.width || elementWidth || 400; + this.height = args.height || elementHeight || 250; + } this.vis && this.vis .attr('width', this.width) @@ -929,7 +961,7 @@ }, { name: 'minute', seconds: 60, - formatter: function(d) { return d.getUTCMinutes() } + formatter: function(d) { return d.getUTCMinutes() + 'm' } }, { name: '15 second', seconds: 15, @@ -1078,20 +1110,20 @@ this.ceil = function(time, unit) { - var date, floor, year; + var date, floor, year, offset; if (unit.name == 'day') { var nearFuture = new Date((time + unit.seconds - 1) * 1000); var rounded = new Date(0); + rounded.setFullYear(nearFuture.getFullYear()); + rounded.setMonth(nearFuture.getMonth()); + rounded.setDate(nearFuture.getDate()); rounded.setMilliseconds(0); rounded.setSeconds(0); rounded.setMinutes(0); rounded.setHours(0); - rounded.setDate(nearFuture.getDate()); - rounded.setMonth(nearFuture.getMonth()); - rounded.setFullYear(nearFuture.getFullYear()); return rounded.getTime() / 1000; } @@ -1127,33 +1159,33 @@ return new Date(year, 0).getTime() / 1000; } - - return Math.ceil(time / unit.seconds) * unit.seconds; + offset = new Date(time * 1000).getTimezoneOffset() * 60; + return Math.ceil((time - offset) / unit.seconds) * unit.seconds + offset; }; }; Rickshaw.namespace('Rickshaw.Fixtures.Number'); Rickshaw.Fixtures.Number.formatKMBT = function(y) { var abs_y = Math.abs(y); - if (abs_y >= 1000000000000) { return y / 1000000000000 + "T" } - else if (abs_y >= 1000000000) { return y / 1000000000 + "B" } - else if (abs_y >= 1000000) { return y / 1000000 + "M" } - else if (abs_y >= 1000) { return y / 1000 + "K" } - else if (abs_y < 1 && y > 0) { return y.toFixed(2) } - else if (abs_y === 0) { return '' } - else { return y } + if (abs_y >= 1000000000000) { return (y / 1000000000000).toFixed(2) + "T" } + else if (abs_y >= 1000000000) { return (y / 1000000000).toFixed(2) + "B" } + else if (abs_y >= 1000000) { return (y / 1000000).toFixed(2) + "M" } + else if (abs_y >= 1000) { return (y / 1000).toFixed(2) + "K" } + else if (abs_y < 1 && abs_y > 0) { return y.toFixed(2) } + else if (abs_y === 0) { return '0' } + else { return y } }; Rickshaw.Fixtures.Number.formatBase1024KMGTP = function(y) { - var abs_y = Math.abs(y); - if (abs_y >= 1125899906842624) { return y / 1125899906842624 + "P" } - else if (abs_y >= 1099511627776){ return y / 1099511627776 + "T" } - else if (abs_y >= 1073741824) { return y / 1073741824 + "G" } - else if (abs_y >= 1048576) { return y / 1048576 + "M" } - else if (abs_y >= 1024) { return y / 1024 + "K" } - else if (abs_y < 1 && y > 0) { return y.toFixed(2) } - else if (abs_y === 0) { return '' } - else { return y } + var abs_y = Math.abs(y); + if (abs_y >= 1125899906842624) { return (y / 1125899906842624).toFixed(2) + "P" } + else if (abs_y >= 1099511627776) { return (y / 1099511627776).toFixed(2) + "T" } + else if (abs_y >= 1073741824) { return (y / 1073741824).toFixed(2) + "G" } + else if (abs_y >= 1048576) { return (y / 1048576).toFixed(2) + "M" } + else if (abs_y >= 1024) { return (y / 1024).toFixed(2) + "K" } + else if (abs_y < 1 && abs_y > 0) { return y.toFixed(2) } + else if (abs_y === 0) { return '0' } + else { return y } }; Rickshaw.namespace("Rickshaw.Color.Palette"); @@ -1222,7 +1254,7 @@ request: function() { - $.ajax( { + jQuery.ajax( { url: this.dataURL, dataType: 'json', success: this.success.bind(this), @@ -1478,6 +1510,7 @@ this.graph = args.graph; this.orientation = args.orientation || 'top'; + this.color = args.color || "#000000"; this.pixelsPerTick = args.pixelsPerTick || 75; if (args.ticks) this.staticTicks = args.ticks; @@ -1495,6 +1528,7 @@ .append("svg:svg") .attr('height', this.height) .attr('width', this.width) + .attr('stroke', this.color) .attr('class', 'rickshaw_graph x_axis_d3'); this.element = this.vis[0][0]; @@ -1535,13 +1569,15 @@ this.ticks = this.staticTicks || Math.floor(this.graph.width / this.pixelsPerTick); var berth = Math.floor(this.width * berthRate / 2) || 0; + var bar_offset = this.graph.renderer.name == "bar" && Math.ceil(this.graph.width * 0.95 / this.graph.series[0].data.length / 2) || 0; + var transform; if (this.orientation == 'top') { var yOffset = this.height || this.graph.height; - transform = 'translate(' + berth + ',' + yOffset + ')'; + transform = 'translate(' + (berth + bar_offset) + ',' + yOffset + ')'; } else { - transform = 'translate(' + berth + ', 0)'; + transform = 'translate(' + (berth + bar_offset) + ', 0)'; } if (this.element) { @@ -1593,6 +1629,7 @@ this.graph = args.graph; this.orientation = args.orientation || 'right'; + this.color = args.color || "#000000"; this.pixelsPerTick = args.pixelsPerTick || 75; if (args.ticks) this.staticTicks = args.ticks; @@ -1610,6 +1647,7 @@ this.element = args.element; this.vis = d3.select(args.element) .append("svg:svg") + .attr('stroke', this.color) .attr('class', 'rickshaw_graph y_axis'); this.element = this.vis[0][0]; @@ -1771,13 +1809,23 @@ var self = this; - var colorSafe = {}; + var propertiesSafe = {}; var activeLine = null; var disabledColor = args.disabledColor || function(seriesColor) { return d3.interpolateRgb(seriesColor, d3.rgb('#d8d8d8'))(0.8).toString(); }; + var transformFn = args.transform || function(isActive, series) { + var newProperties = {}; + if (!isActive) { + // backwards compability + newProperties.color = disabledColor(series.color); + } + return newProperties; + }; + + this.addHighlightEvents = function (l) { l.element.addEventListener( 'mouseover', function(e) { @@ -1786,8 +1834,11 @@ else activeLine = l; self.legend.lines.forEach( function(line) { + var newProperties; + var isActive = false; if (l === line) { + isActive = true; // if we're not in a stacked renderer bring active line to the top if (self.graph.renderer.unstack && (line.series.renderer ? line.series.renderer.unstack : true)) { @@ -1798,11 +1849,21 @@ var series = self.graph.series.splice(seriesIndex, 1)[0]; self.graph.series.push(series); } - return; } - colorSafe[line.series.name] = colorSafe[line.series.name] || line.series.color; - line.series.color = disabledColor(line.series.color); + newProperties = transformFn(isActive, line.series); + + propertiesSafe[line.series.name] = propertiesSafe[line.series.name] || { + color : line.series.color, + stroke : line.series.stroke + }; + + if (newProperties.color) { + line.series.color = newProperties.color; + } + if (newProperties.stroke) { + line.series.stroke = newProperties.stroke; + } } ); @@ -1825,8 +1886,10 @@ delete line.originalIndex; } - if (colorSafe[line.series.name]) { - line.series.color = colorSafe[line.series.name]; + var lineProperties = propertiesSafe[line.series.name]; + if (lineProperties) { + line.series.color = lineProperties.color; + line.series.stroke = lineProperties.stroke; } } ); @@ -1851,21 +1914,21 @@ var self = this; - if (typeof window.$ == 'undefined') { - throw "couldn't find jQuery at window.$"; + if (typeof window.jQuery == 'undefined') { + throw "couldn't find jQuery at window.jQuery"; } - if (typeof window.$.ui == 'undefined') { - throw "couldn't find jQuery UI at window.$.ui"; + if (typeof window.jQuery.ui == 'undefined') { + throw "couldn't find jQuery UI at window.jQuery.ui"; } - $(function() { - $(self.legend.list).sortable( { + jQuery(function() { + jQuery(self.legend.list).sortable( { containment: 'parent', tolerance: 'pointer', update: function( event, ui ) { var series = []; - $(self.legend.list).find('li').each( function(index, item) { + jQuery(self.legend.list).find('li').each( function(index, item) { if (!item.series) return; series.push(item.series); } ); @@ -1877,7 +1940,7 @@ self.graph.update(); } } ); - $(self.legend.list).disableSelection(); + jQuery(self.legend.list).disableSelection(); }); //hack to make jquery-ui sortable behave @@ -1896,6 +1959,7 @@ var self = this; this.addAnchor = function(line) { + var anchor = document.createElement('a'); anchor.innerHTML = '✔'; anchor.classList.add('action'); @@ -1911,6 +1975,8 @@ line.element.classList.add('disabled'); } + self.graph.update(); + }.bind(this); var label = line.element.getElementsByTagName('span')[0]; @@ -1956,15 +2022,16 @@ } + self.graph.update(); + }; }; if (this.legend) { - if (typeof $ != 'undefined' && $(this.legend.list).sortable) { - - $(this.legend.list).sortable( { + if (typeof jQuery != 'undefined' && jQuery(this.legend.list).sortable) { + jQuery(this.legend.list).sortable( { start: function(event, ui) { ui.item.bind('no.onclick', function(event) { @@ -1996,12 +2063,10 @@ } s.disabled = true; - self.graph.update(); }; s.enable = function() { s.disabled = false; - self.graph.update(); }; } ); }; @@ -2010,6 +2075,125 @@ this.updateBehaviour = function () { this._addBehavior() }; }; +Rickshaw.namespace('Rickshaw.Graph.DragZoom'); + +Rickshaw.Graph.DragZoom = Rickshaw.Class.create({ + + initialize: function(args) { + if (!args || !args.graph) { + throw new Error("Rickshaw.Graph.DragZoom needs a reference to a graph"); + } + var defaults = { + opacity: 0.5, + fill: 'steelblue', + minimumTimeSelection: 60, + callback: function() {} + }; + + this.graph = args.graph; + this.svg = d3.select(this.graph.element).select("svg"); + this.svgWidth = parseInt(this.svg.attr("width"), 10); + this.opacity = args.opacity || defaults.opacity; + this.fill = args.fill || defaults.fill; + this.minimumTimeSelection = args.minimumTimeSelection || defaults.minimumTimeSelection; + this.callback = args.callback || defaults.callback; + + this.registerMouseEvents(); + }, + + registerMouseEvents: function() { + var self = this; + var ESCAPE_KEYCODE = 27; + var rectangle; + + var drag = { + startDt: null, + stopDt: null, + startPX: null, + stopPX: null + }; + + this.svg.on("mousedown", onMousedown); + + function onMouseup(datum, index) { + drag.stopDt = pointAsDate(d3.event); + var windowAfterDrag = [ + drag.startDt, + drag.stopDt + ].sort(compareNumbers); + + self.graph.window.xMin = windowAfterDrag[0]; + self.graph.window.xMax = windowAfterDrag[1]; + + var endTime = self.graph.window.xMax; + var range = self.graph.window.xMax - self.graph.window.xMin; + + reset(this); + + if (range < self.minimumTimeSelection || isNaN(range)) { + return; + } + self.graph.update(); + self.callback({range: range, endTime: endTime}); + } + + function onMousemove() { + var offset = drag.stopPX = (d3.event.offsetX || d3.event.layerX); + if (offset > (self.svgWidth - 1) || offset < 1) { + return; + } + + var limits = [drag.startPX, offset].sort(compareNumbers); + var selectionWidth = limits[1]-limits[0]; + if (isNaN(selectionWidth)) { + return reset(this); + } + rectangle.attr("fill", self.fill) + .attr("x", limits[0]) + .attr("width", selectionWidth); + } + + function onMousedown() { + var el = d3.select(this); + rectangle = el.append("rect") + .style("opacity", self.opacity) + .attr("y", 0) + .attr("height", "100%"); + + if(d3.event.preventDefault) { + d3.event.preventDefault(); + } else { + d3.event.returnValue = false; + } + drag.target = d3.event.target; + drag.startDt = pointAsDate(d3.event); + drag.startPX = d3.event.offsetX || d3.event.layerX; + el.on("mousemove", onMousemove); + d3.select(document).on("mouseup", onMouseup); + d3.select(document).on("keyup", function() { + if (d3.event.keyCode === ESCAPE_KEYCODE) { + reset(this); + } + }); + } + + function reset(el) { + var s = d3.select(el); + s.on("mousemove", null); + d3.select(document).on("mouseup", null); + drag = {}; + rectangle.remove(); + } + + function compareNumbers(a, b) { + return a - b; + } + + function pointAsDate(e) { + return Math.floor(self.graph.x.invert(e.offsetX || e.layerX)); + } + } +}); Rickshaw.namespace('Rickshaw.Graph.HoverDetail'); Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({ @@ -2027,7 +2211,7 @@ }; var element = this.element = document.createElement('div'); - element.className = 'detail'; + element.className = 'detail inactive'; this.visible = true; graph.element.appendChild(element); @@ -2057,8 +2241,9 @@ var graph = this.graph; - var eventX = e.offsetX || e.layerX; - var eventY = e.offsetY || e.layerY; + var rect = graph.element.getBoundingClientRect(); + var eventX = e.clientX - rect.left; + var eventY = e.clientY - rect.top; var j = 0; var points = []; @@ -2265,26 +2450,43 @@ _addListeners: function() { + // Keep reference for later removal. + this.mousemoveListener = function(e) { + this.visible = true; + this.update(e); + }.bind(this); + + // Add listener. this.graph.element.addEventListener( 'mousemove', - function(e) { - this.visible = true; - this.update(e); - }.bind(this), + this.mousemoveListener, false ); this.graph.onUpdate( function() { this.update() }.bind(this) ); + // Keep reference for later removal. + this.mouseoutListener = function(e) { + if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) { + this.hide(); + } + }.bind(this); + + // Add listener. this.graph.element.addEventListener( 'mouseout', - function(e) { - if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) { - this.hide(); - } - }.bind(this), + this.mouseoutListener, false ); + }, + + _removeListeners: function() { + if (this.mousemoveListener) { + this.graph.element.removeEventListener('mousemove', this.mousemoveListener, false); + } + if (this.mouseoutListener) { + this.graph.element.removeEventListener('mouseout', this.mouseoutListener, false); + } } }); Rickshaw.namespace('Rickshaw.Graph.JSONP'); @@ -2293,7 +2495,7 @@ request: function() { - $.ajax( { + jQuery.ajax( { url: this.dataURL, dataType: 'jsonp', success: this.success.bind(this), @@ -2311,6 +2513,7 @@ this.element = args.element; this.graph = args.graph; this.naturalOrder = args.naturalOrder; + this.colorKey = args.colorKey || 'color'; this.element.classList.add(this.className); @@ -2358,7 +2561,7 @@ } var swatch = document.createElement('div'); swatch.className = 'swatch'; - swatch.style.backgroundColor = series.color; + swatch.style.backgroundColor = series[this.colorKey]; line.appendChild(swatch); @@ -2387,59 +2590,93 @@ return line; } } ); - Rickshaw.namespace('Rickshaw.Graph.RangeSlider'); Rickshaw.Graph.RangeSlider = Rickshaw.Class.create({ initialize: function(args) { + var $ = jQuery; + var self = this; var element = this.element = args.element; - var graph = this.graph = args.graph; + var graphs = this.graphs = args.graphs; + if (!graphs) { + graphs = this.graph = args.graph; + } + if (graphs.constructor !== Array) { + graphs = [graphs]; + } + this.graph = graphs[0]; + + this.slideCallbacks = []; this.build(); - graph.onUpdate( function() { this.update() }.bind(this) ); + for (var i = 0; i < graphs.length; i++) { + graphs[i].onUpdate(function() { + self.update(); + }.bind(self)); + + (function(idx){ + graphs[idx].onConfigure(function() { + $(this.element)[0].style.width = graphs[idx].width + 'px'; + }.bind(self)); + })(i); + } + }, build: function() { + var domain; var element = this.element; - var graph = this.graph; + var $ = jQuery; + var self = this; + var graphs = this.graphs || this.graph; - var domain = graph.dataDomain(); + if (graphs.constructor !== Array) { + graphs = [graphs]; + } - $( function() { - $(element).slider( { + // base the slider's min/max on the first graph + this.graph = graphs[0]; + domain = graphs[0].dataDomain(); + + $(function() { + $(element).slider({ range: true, min: domain[0], max: domain[1], - values: [ + values: [ domain[0], domain[1] ], - slide: function( event, ui ) { + start: function(event, ui) { + self.slideStarted({ event: event, ui: ui }); + }, + stop: function(event, ui) { + self.slideFinished({ event: event, ui: ui }); + }, + slide: function(event, ui) { + if (!self.slideShouldUpdate(event, ui)) + return; if (ui.values[1] <= ui.values[0]) return; - graph.window.xMin = ui.values[0]; - graph.window.xMax = ui.values[1]; - graph.update(); - - var domain = graph.dataDomain(); - - // if we're at an extreme, stick there - if (domain[0] == ui.values[0]) { - graph.window.xMin = undefined; - } - if (domain[1] == ui.values[1]) { - graph.window.xMax = undefined; + for (var i = 0; i < graphs.length; i++) { + self.processSlideChange({ + event: event, + ui: ui, + graph: graphs[i] + }); } } } ); } ); - $(element)[0].style.width = graph.width + 'px'; + graphs[0].onConfigure(function() { + $(this.element)[0].style.width = graphs[0].width + 'px'; + }.bind(this)); }, @@ -2447,6 +2684,7 @@ var element = this.element; var graph = this.graph; + var $ = jQuery; var values = $(element).slider('option', 'values'); @@ -2463,6 +2701,49 @@ } $(element).slider('option', 'values', values); + }, + + onSlide: function(callback) { + this.slideCallbacks.push(callback); + }, + + processSlideChange: function(args) { + var event = args.event; + var ui = args.ui; + var graph = args.graph; + + graph.window.xMin = ui.values[0]; + graph.window.xMax = ui.values[1]; + graph.update(); + + var domain = graph.dataDomain(); + + // if we're at an extreme, stick there + if (domain[0] == ui.values[0]) { + graph.window.xMin = undefined; + } + + if (domain[1] == ui.values[1]) { + graph.window.xMax = undefined; + } + + this.slideCallbacks.forEach(function(callback) { + callback(graph, graph.window.xMin, graph.window.xMax); + }); + + }, + + // allows the slide updates to bail out if sliding is not permitted + slideShouldUpdate: function() { + return true; + }, + + slideStarted: function() { + return; + }, + + slideFinished: function() { + return; } }); @@ -2476,6 +2757,8 @@ if (!args.graph && !args.graphs) throw "Rickshaw.Graph.RangeSlider.Preview needs a reference to an graph or an array of graphs"; this.element = args.element; + this.element.style.position = 'relative'; + this.graphs = args.graph ? [ args.graph ] : args.graphs; this.defaults = { @@ -2486,28 +2769,45 @@ frameHandleThickness: 10, frameColor: "#d4d4d4", frameOpacity: 1, - minimumFrameWidth: 0 + minimumFrameWidth: 0, + heightRatio: 0.2 }; + this.heightRatio = args.heightRatio || this.defaults.heightRatio; this.defaults.gripperColor = d3.rgb(this.defaults.frameColor).darker().toString(); this.configureCallbacks = []; + this.slideCallbacks = []; + this.previews = []; + if (!args.width) this.widthFromGraph = true; + if (!args.height) this.heightFromGraph = true; + + if (this.widthFromGraph || this.heightFromGraph) { + this.graphs[0].onConfigure(function () { + this.configure(args); this.render(); + }.bind(this)); + } + args.width = args.width || this.graphs[0].width || this.defaults.width; - args.height = args.height || this.graphs[0].height / 5 || this.defaults.height; + args.height = args.height || this.graphs[0].height * this.heightRatio || this.defaults.height; this.configure(args); this.render(); }, + onSlide: function(callback) { + this.slideCallbacks.push(callback); + }, + onConfigure: function(callback) { this.configureCallbacks.push(callback); }, configure: function(args) { - this.config = {}; + this.config = this.config || {}; this.configureCallbacks.forEach(function(callback) { callback(args); @@ -2519,17 +2819,29 @@ : this.defaults[k]; }, this); - if (args.width) { - this.previews.forEach(function(preview) { - var width = args.width - this.config.frameHandleThickness * 2; - preview.setSize({ width: width }); - }, this); - } + if ('width' in args || 'height' in args) { + + if (this.widthFromGraph) { + this.config.width = this.graphs[0].width; + } + + if (this.heightFromGraph) { + this.config.height = this.graphs[0].height * this.heightRatio; + this.previewHeight = this.config.height; + } - if (args.height) { this.previews.forEach(function(preview) { - var height = this.previewHeight / this.graphs.length; - preview.setSize({ height: height }); + + var height = this.previewHeight / this.graphs.length - this.config.frameTopThickness * 2; + var width = this.config.width - this.config.frameHandleThickness * 2; + preview.setSize({ width: width, height: height }); + + if (this.svg) { + var svgHeight = height + this.config.frameHandleThickness * 2; + var svgWidth = width + this.config.frameHandleThickness * 2; + this.svg.style("width", svgWidth + "px"); + this.svg.style("height", svgHeight + "px"); + } }, this); } }, @@ -2551,12 +2863,14 @@ var graphArgs = Rickshaw.extend({}, parent.config); var height = self.previewHeight / self.graphs.length; + var renderer = parent.renderer.name; Rickshaw.extend(graphArgs, { element: this.appendChild(document.createElement("div")), height: height, width: self.previewWidth, - series: parent.series + series: parent.series, + renderer: renderer }); var graph = new Rickshaw.Graph(graphArgs); @@ -2567,6 +2881,7 @@ parent.onConfigure(function(args) { // don't propagate height delete args.height; + args.width = args.width - self.config.frameHandleThickness * 2; graph.configure(args); graph.render(); }); @@ -2620,8 +2935,8 @@ .classed("rickshaw_range_slider_preview", true) .style("height", this.config.height + "px") .style("width", this.config.width + "px") - .style("position", "relative") - .style("top", -this.previewHeight + "px"); + .style("position", "absolute") + .style("top", 0); this._renderDimming(); this._renderFrame(); @@ -2721,12 +3036,13 @@ leftHandle.enter() .append("rect") .attr('width', this.config.frameHandleThickness) - .attr('height', this.config.height) .style("cursor", "ew-resize") .style("fill-opacity", "0") .classed("left_handle", true); - leftHandle.attr('x', this.currentFrame[0]); + leftHandle + .attr('x', this.currentFrame[0]) + .attr('height', this.config.height); var rightHandle = this.svg.selectAll("rect.right_handle") .data([null]); @@ -2734,12 +3050,13 @@ rightHandle.enter() .append("rect") .attr('width', this.config.frameHandleThickness) - .attr('height', this.config.height) .style("cursor", "ew-resize") .style("fill-opacity", "0") .classed("right_handle", true); - rightHandle.attr('x', this.currentFrame[1] + this.config.frameHandleThickness); + rightHandle + .attr('x', this.currentFrame[1] + this.config.frameHandleThickness) + .attr('height', this.config.height); }, _renderMiddle: function() { @@ -2749,14 +3066,14 @@ middleHandle.enter() .append("rect") - .attr('height', this.config.height) .style("cursor", "move") .style("fill-opacity", "0") .classed("middle_handle", true); middleHandle .attr('width', Math.max(0, this.currentFrame[1] - this.currentFrame[0])) - .attr('x', this.currentFrame[0] + this.config.frameHandleThickness); + .attr('x', this.currentFrame[0] + this.config.frameHandleThickness) + .attr('height', this.config.height); }, _registerMouseEvents: function() { @@ -2814,7 +3131,7 @@ self.graphs.forEach(function(graph) { var domainScale = d3.scale.linear() - .interpolate(d3.interpolateRound) + .interpolate(d3.interpolateNumber) .domain([0, self.previewWidth]) .range(graph.dataDomain()); @@ -2823,6 +3140,10 @@ domainScale(frameAfterDrag[1]) ]; + self.slideCallbacks.forEach(function(callback) { + callback(graph, windowAfterDrag[0], windowAfterDrag[1]); + }); + if (frameAfterDrag[0] === 0) { windowAfterDrag[0] = undefined; } @@ -2831,7 +3152,7 @@ } graph.window.xMin = windowAfterDrag[0]; graph.window.xMax = windowAfterDrag[1]; - + graph.update(); }); } @@ -2931,24 +3252,23 @@ unstack: true, padding: { top: 0.01, right: 0, bottom: 0.01, left: 0 }, stroke: false, - fill: false + fill: false, + opacity: 1 }; }, domain: function(data) { - + // Requires that at least one series contains some data var stackedData = data || this.graph.stackedData || this.graph.stackData(); - var firstPoint = stackedData[0][0]; - if (firstPoint === undefined) { - return { x: [null, null], y: [null, null] }; - } + // filter out any series that may be empty in the current x-domain + stackedData = stackedData.filter(function (a) { return a && a.length !== 0; }); - var xMin = firstPoint.x; - var xMax = firstPoint.x; + var xMin = +Infinity; + var xMax = -Infinity; - var yMin = firstPoint.y + firstPoint.y0; - var yMax = firstPoint.y + firstPoint.y0; + var yMin = +Infinity; + var yMax = -Infinity; stackedData.forEach( function(series) { @@ -3028,10 +3348,13 @@ var fill = this.fill ? series.color : 'none'; var stroke = this.stroke ? series.color : 'none'; + var strokeWidth = series.strokeWidth ? series.strokeWidth : this.strokeWidth; + var opacity = series.opacity === undefined ? this.opacity : series.opacity; series.path.setAttribute('fill', fill); series.path.setAttribute('stroke', stroke); - series.path.setAttribute('stroke-width', this.strokeWidth); + series.path.setAttribute('stroke-width', strokeWidth); + series.path.setAttribute('opacity', opacity); if (series.className) { d3.select(series.path).classed(series.className, true); @@ -3085,7 +3408,6 @@ } } } ); - Rickshaw.namespace('Rickshaw.Graph.Renderer.Line'); Rickshaw.Graph.Renderer.Line = Rickshaw.Class.create( Rickshaw.Graph.Renderer, { @@ -3155,7 +3477,8 @@ var defaults = Rickshaw.extend( $super(), { gapSize: 0.05, - unstack: false + unstack: false, + opacity: 1.0 } ); delete defaults.tension; @@ -3181,7 +3504,7 @@ barWidth: function(series) { var frequentInterval = this._frequentInterval(series.stack); - var barWidth = this.graph.x(series.stack[0].x + frequentInterval.magnitude * (1 - this.gapSize)); + var barWidth = this.graph.x.magnitude(frequentInterval.magnitude) * (1 - this.gapSize); return barWidth; }, @@ -3221,6 +3544,7 @@ .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) }) .attr("width", seriesBarWidth) .attr("height", function(d) { return graph.y.magnitude(Math.abs(d.y)) }) + .attr("opacity", series.opacity) .attr("transform", transform); Array.prototype.forEach.call(nodes[0], function(n) { @@ -3243,8 +3567,13 @@ } var frequentInterval = { count: 0, magnitude: 1 }; - - Rickshaw.keys(intervalCounts).forEach( function(i) { + + // Sorting object's keys returned to guarantee consistency when iterating over + // Keys order in `for .. in` loop is not specified and browsers behave differently here + // This results with different invterval value being calculated for different browsers + // See last but one section here: http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4 + var keysSorted = Rickshaw.keys(intervalCounts).sort(function asc(a, b) { return Number(a) - Number(b); }); + keysSorted.forEach( function(i) { if (frequentInterval.count < intervalCounts[i]) { frequentInterval = { count: intervalCounts[i], @@ -3395,17 +3724,19 @@ series.forEach( function(series) { if (series.disabled) return; + var opacity = series.opacity === undefined ? 1 : series.opacity; var nodes = vis.selectAll("path") .data(series.stack.filter( function(d) { return d.y !== null } )) .enter().append("svg:circle") .attr("cx", function(d) { return graph.x(d.x) }) .attr("cy", function(d) { return graph.y(d.y) }) - .attr("r", function(d) { return ("r" in d) ? d.r : dotSize}); + .attr("r", function(d) { return ("r" in d) ? d.r : dotSize}) + .attr("opacity", function(d) { return ("opacity" in d) ? d.opacity : opacity}); if (series.className) { nodes.classed(series.className, true); } - + Array.prototype.forEach.call(nodes[0], function(n) { n.setAttribute('fill', series.color); } ); @@ -3456,8 +3787,14 @@ .map( function(s) { return s.stack }); if (!data.length) return; - - var domain = $super(data); + + var domain = null; + if (group.renderer && group.renderer.domain) { + domain = group.renderer.domain(data); + } + else { + domain = $super(data); + } domains.push(domain); }); @@ -3586,10 +3923,6 @@ } ); }, - initialize: function($super, args) { - $super(args); - }, - seriesPathFactory: function() { var graph = this.graph; @@ -3603,20 +3936,45 @@ return factory; }, - _renderDots: function() { + render: function(args) { + + args = args || {}; var graph = this.graph; - graph.series.forEach(function(series) { + var series = args.series || graph.series; + var vis = args.vis || graph.vis; + + var dotSize = this.dotSize; + + vis.selectAll('*').remove(); + + var data = series + .filter(function(s) { return !s.disabled }) + .map(function(s) { return s.stack }); + + var nodes = vis.selectAll("path") + .data(data) + .enter().append("svg:path") + .attr("d", this.seriesPathFactory()); + + var i = 0; + series.forEach(function(series) { + if (series.disabled) return; + series.path = nodes[0][i++]; + this._styleSeries(series); + }, this); + + series.forEach(function(series) { if (series.disabled) return; - var nodes = graph.vis.selectAll("x") + var nodes = vis.selectAll("x") .data(series.stack.filter( function(d) { return d.y !== null } )) .enter().append("svg:circle") .attr("cx", function(d) { return graph.x(d.x) }) .attr("cy", function(d) { return graph.y(d.y) }) - .attr("r", function(d) { return ("r" in d) ? d.r : graph.renderer.dotSize}); + .attr("r", function(d) { return ("r" in d) ? d.r : dotSize}); Array.prototype.forEach.call(nodes[0], function(n) { if (!n) return; @@ -3628,33 +3986,6 @@ }.bind(this)); }, this); - }, - - _renderLines: function() { - - var graph = this.graph; - - var nodes = graph.vis.selectAll("path") - .data(this.graph.stackedData) - .enter().append("svg:path") - .attr("d", this.seriesPathFactory()); - - var i = 0; - graph.series.forEach(function(series) { - if (series.disabled) return; - series.path = nodes[0][i++]; - this._styleSeries(series); - }, this); - }, - - render: function() { - - var graph = this.graph; - - graph.vis.selectAll('*').remove(); - - this._renderLines(); - this._renderDots(); } } ); @@ -3680,6 +4011,7 @@ build: function() { var self = this; + var $ = jQuery; if (this.element) { $( function() { @@ -3688,7 +4020,6 @@ max: 100, slide: function( event, ui ) { self.setScale(ui.value); - self.graph.update(); } } ); } ); @@ -3992,3 +4323,5 @@ } } ); + return Rickshaw; +})); diff -Nru pdns-recursor-5.2.13/html/js/rickshaw.min.js pdns-recursor-5.4.9/html/js/rickshaw.min.js --- pdns-recursor-5.2.13/html/js/rickshaw.min.js 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/html/js/rickshaw.min.js 2026-10-26 08:26:51.000000000 +0000 @@ -1,3 +1,3 @@ -var Rickshaw={namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i=3){if(s.data[2].xthis.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.onConfigure=function(callback){this.configureCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){this.config=this.config||{};if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);Rickshaw.keys(this.config).forEach(function(k){this[k]=this.config[k]},this);var renderer=args.renderer||this.renderer&&this.renderer.name||"stack";this.setRenderer(renderer,args);this.configureCallbacks.forEach(function(callback){callback(args)})};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(typeof window!==undefined){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250;this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter++ +(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getUTCMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getUTCMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="month"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),date.getUTCMonth())/1e3;if(floor==time)return time;year=date.getUTCFullYear();var month=date.getUTCMonth();if(month==11){month=0;year=year+1}else{month+=1}return Date.UTC(year,month)/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),0)/1e3;if(floor==time)return time;year=date.getUTCFullYear()+1;return Date.UTC(year,0)/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="day"){var nearFuture=new Date((time+unit.seconds-1)*1e3);var rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(nearFuture.getDate());rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="month"){date=new Date(time*1e3);floor=new Date(date.getFullYear(),date.getMonth()).getTime()/1e3;if(floor==time)return time;year=date.getFullYear();var month=date.getMonth();if(month==11){month=0;year=year+1}else{month+=1}return new Date(year,month).getTime()/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=new Date(date.getUTCFullYear(),0).getTime()/1e3;if(floor==time)return time;year=date.getFullYear()+1;return new Date(year,0).getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return y/1e12+"T"}else if(abs_y>=1e9){return y/1e9+"B"}else if(abs_y>=1e6){return y/1e6+"M"}else if(abs_y>=1e3){return y/1e3+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return y/0x4000000000000+"P"}else if(abs_y>=1099511627776){return y/1099511627776+"T"}else if(abs_y>=1073741824){return y/1073741824+"G"}else if(abs_y>=1048576){return y/1048576+"M"}else if(abs_y>=1024){return y/1024+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;iself.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;iself.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this._renderWidth!==undefined&&this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+berth+","+yOffset+")"}else{transform="translate("+berth+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-x-value",this.textContent)});this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this._renderHeight!==undefined&&this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat);if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-y-value",this.textContent)})}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true -}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var domain=this.scale.domain();var renderDomain=this.graph.renderer.domain().y;var extents=[Math.min.apply(Math,domain),Math.max.apply(Math,domain)];var extentMap=d3.scale.linear().domain([0,1]).range(extents);var adjExtents=[extentMap(renderDomain[0]),extentMap(renderDomain[1])];var adjustment=d3.scale.linear().domain(extents).range(adjExtents);var adjustedScale=this.scale.copy().domain(domain.map(adjustment)).range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var colorSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line){if(l===line){if(self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.indexOf(line.series);line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}return}colorSafe[line.series.name]=colorSafe[line.series.name]||line.series.color;line.series.color=disabledColor(line.series.color)});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}if(colorSafe[line.series.name]){line.series.color=colorSafe[line.series.name]}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.$=="undefined"){throw"couldn't find jQuery at window.$"}if(typeof window.$.ui=="undefined"){throw"couldn't find jQuery UI at window.$.ui"}$(function(){$(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];$(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});$(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="✔";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;idomainX){dataIndex=Math.abs(domainX-data[i].x)0){alignables.forEach(function(el){el.classList.remove("left");el.classList.add("right")});var rightAlignError=this._calcLayoutError(alignables);if(rightAlignError>leftAlignError){alignables.forEach(function(el){el.classList.remove("right");el.classList.add("left")})}}if(typeof this.onRender=="function"){this.onRender(args)}},_calcLayoutError:function(alignables){var parentRect=this.element.parentNode.getBoundingClientRect();var error=0;var alignRight=alignables.forEach(function(el){var rect=el.getBoundingClientRect();if(!rect.width){return}if(rect.right>parentRect.right){error+=rect.right-parentRect.right}if(rect.left=self.previewWidth){frameAfterDrag[0]-=frameAfterDrag[1]-self.previewWidth;frameAfterDrag[1]=self.previewWidth}}self.graphs.forEach(function(graph){var domainScale=d3.scale.linear().interpolate(d3.interpolateRound).domain([0,self.previewWidth]).range(graph.dataDomain());var windowAfterDrag=[domainScale(frameAfterDrag[0]),domainScale(frameAfterDrag[1])];if(frameAfterDrag[0]===0){windowAfterDrag[0]=undefined}if(frameAfterDrag[1]===self.previewWidth){windowAfterDrag[1]=undefined}graph.window.xMin=windowAfterDrag[0];graph.window.xMax=windowAfterDrag[1];graph.update()})}function onMousedown(){drag.target=d3.event.target;drag.start=self._getClientXFromEvent(d3.event,drag);self.frameBeforeDrag=self.currentFrame.slice();d3.event.preventDefault?d3.event.preventDefault():d3.event.returnValue=false;d3.select(document).on("mousemove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("mouseup.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchmove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("touchend.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",onMouseup)}function onMousedownLeftHandle(datum,index){drag.left=true;onMousedown()}function onMousedownRightHandle(datum,index){drag.right=true;onMousedown()}function onMousedownMiddleHandle(datum,index){drag.left=true;drag.right=true;drag.rigid=true;onMousedown()}function onMouseup(datum,index){d3.select(document).on("mousemove.rickshaw_range_slider_preview",null);d3.select(document).on("mouseup.rickshaw_range_slider_preview",null);d3.select(document).on("touchmove.rickshaw_range_slider_preview",null);d3.select(document).on("touchend.rickshaw_range_slider_preview",null);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",null);delete self.frameBeforeDrag;drag.left=false;drag.right=false;drag.rigid=false}element.select("rect.left_handle").on("mousedown",onMousedownLeftHandle);element.select("rect.right_handle").on("mousedown",onMousedownRightHandle);element.select("rect.middle_handle").on("mousedown",onMousedownMiddleHandle);element.select("rect.left_handle").on("touchstart",onMousedownLeftHandle);element.select("rect.right_handle").on("touchstart",onMousedownRightHandle);element.select("rect.middle_handle").on("touchstart",onMousedownMiddleHandle)},_getClientXFromEvent:function(event,drag){switch(event.type){case"touchstart":case"touchmove":var touchList=event.changedTouches;var touch=null;for(var touchIndex=0;touchIndexyMax)yMax=y});if(!series.length)return;if(series[0].xxMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var pathNodes=vis.selectAll("path.path").data(data).enter().append("svg:path").classed("path",true).attr("d",this.seriesPathFactory());if(this.stroke){var strokeNodes=vis.selectAll("path.stroke").data(data).enter().append("svg:path").classed("stroke",true).attr("d",this.seriesStrokeFactory())}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=pathNodes[0][i];if(this.stroke)series.stroke=strokeNodes[0][i];this._styleSeries(series);i++},this)},_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",this.strokeWidth);if(series.className){d3.select(series.path).classed(series.className,true)}if(series.className&&this.stroke){d3.select(series.stroke).classed(series.className,true)}},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x(series.stack[0].x+frequentInterval.magnitude*(1-this.gapSize));return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}}); \ No newline at end of file +(function(root,factory){if(typeof define==="function"&&define.amd){define(["d3"],function(d3){return root.Rickshaw=factory(d3)})}else if(typeof exports==="object"){module.exports=factory(require("d3"))}else{root.Rickshaw=factory(d3)}})(this,function(d3){var Rickshaw={version:"1.7.0",namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i0){var x=s.data[0].x;var y=s.data[0].y;if(typeof x!="number"||typeof y!="number"&&y!==null){throw"x and y properties of points should be numbers instead of "+typeof x+" and "+typeof y}}if(s.data.length>=3){if(s.data[2].xthis.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.onConfigure=function(callback){this.configureCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){this.config=this.config||{};if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);Rickshaw.keys(this.config).forEach(function(k){this[k]=this.config[k]},this);if("stack"in args)args.unstack=!args.stack;var renderer=args.renderer||this.renderer&&this.renderer.name||"stack";this.setRenderer(renderer,args);this.configureCallbacks.forEach(function(callback){callback(args)})};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(args.width&&args.height){this.width=args.width;this.height=args.height}else{if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250}this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter+++(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()+"m"}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getUTCMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getUTCMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="month"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),date.getUTCMonth())/1e3;if(floor==time)return time;year=date.getUTCFullYear();var month=date.getUTCMonth();if(month==11){month=0;year=year+1}else{month+=1}return Date.UTC(year,month)/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),0)/1e3;if(floor==time)return time;year=date.getUTCFullYear()+1;return Date.UTC(year,0)/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year,offset;if(unit.name=="day"){var nearFuture=new Date((time+unit.seconds-1)*1e3);var rounded=new Date(0);rounded.setFullYear(nearFuture.getFullYear());rounded.setMonth(nearFuture.getMonth());rounded.setDate(nearFuture.getDate());rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);return rounded.getTime()/1e3}if(unit.name=="month"){date=new Date(time*1e3);floor=new Date(date.getFullYear(),date.getMonth()).getTime()/1e3;if(floor==time)return time;year=date.getFullYear();var month=date.getMonth();if(month==11){month=0;year=year+1}else{month+=1}return new Date(year,month).getTime()/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=new Date(date.getUTCFullYear(),0).getTime()/1e3;if(floor==time)return time;year=date.getFullYear()+1;return new Date(year,0).getTime()/1e3}offset=new Date(time*1e3).getTimezoneOffset()*60;return Math.ceil((time-offset)/unit.seconds)*unit.seconds+offset}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return(y/1e12).toFixed(2)+"T"}else if(abs_y>=1e9){return(y/1e9).toFixed(2)+"B"}else if(abs_y>=1e6){return(y/1e6).toFixed(2)+"M"}else if(abs_y>=1e3){return(y/1e3).toFixed(2)+"K"}else if(abs_y<1&&abs_y>0){return y.toFixed(2)}else if(abs_y===0){return"0"}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return(y/0x4000000000000).toFixed(2)+"P"}else if(abs_y>=1099511627776){return(y/1099511627776).toFixed(2)+"T"}else if(abs_y>=1073741824){return(y/1073741824).toFixed(2)+"G"}else if(abs_y>=1048576){return(y/1048576).toFixed(2)+"M"}else if(abs_y>=1024){return(y/1024).toFixed(2)+"K"}else if(abs_y<1&&abs_y>0){return y.toFixed(2)}else if(abs_y===0){return"0"}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;iself.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;iself.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.color=args.color||"#000000";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("stroke",this.color).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this._renderWidth!==undefined&&this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var bar_offset=this.graph.renderer.name=="bar"&&Math.ceil(this.graph.width*.95/this.graph.series[0].data.length/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+(berth+bar_offset)+","+yOffset+")"}else{transform="translate("+(berth+bar_offset)+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-x-value",this.textContent)});this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.color=args.color||"#000000";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("stroke",this.color).attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this._renderHeight!==undefined&&this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat) +;if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-y-value",this.textContent)})}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var domain=this.scale.domain();var renderDomain=this.graph.renderer.domain().y;var extents=[Math.min.apply(Math,domain),Math.max.apply(Math,domain)];var extentMap=d3.scale.linear().domain([0,1]).range(extents);var adjExtents=[extentMap(renderDomain[0]),extentMap(renderDomain[1])];var adjustment=d3.scale.linear().domain(extents).range(adjExtents);var adjustedScale=this.scale.copy().domain(domain.map(adjustment)).range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var propertiesSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};var transformFn=args.transform||function(isActive,series){var newProperties={};if(!isActive){newProperties.color=disabledColor(series.color)}return newProperties};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line){var newProperties;var isActive=false;if(l===line){isActive=true;if(self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.indexOf(line.series);line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}}newProperties=transformFn(isActive,line.series);propertiesSafe[line.series.name]=propertiesSafe[line.series.name]||{color:line.series.color,stroke:line.series.stroke};if(newProperties.color){line.series.color=newProperties.color}if(newProperties.stroke){line.series.stroke=newProperties.stroke}});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}var lineProperties=propertiesSafe[line.series.name];if(lineProperties){line.series.color=lineProperties.color;line.series.stroke=lineProperties.stroke}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.jQuery=="undefined"){throw"couldn't find jQuery at window.jQuery"}if(typeof window.jQuery.ui=="undefined"){throw"couldn't find jQuery UI at window.jQuery.ui"}jQuery(function(){jQuery(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];jQuery(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});jQuery(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="✔";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}self.graph.update()}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;iself.svgWidth-1||offset<1){return}var limits=[drag.startPX,offset].sort(compareNumbers);var selectionWidth=limits[1]-limits[0];if(isNaN(selectionWidth)){return reset(this)}rectangle.attr("fill",self.fill).attr("x",limits[0]).attr("width",selectionWidth)}function onMousedown(){var el=d3.select(this);rectangle=el.append("rect").style("opacity",self.opacity).attr("y",0).attr("height","100%");if(d3.event.preventDefault){d3.event.preventDefault()}else{d3.event.returnValue=false}drag.target=d3.event.target;drag.startDt=pointAsDate(d3.event);drag.startPX=d3.event.offsetX||d3.event.layerX;el.on("mousemove",onMousemove);d3.select(document).on("mouseup",onMouseup);d3.select(document).on("keyup",function(){if(d3.event.keyCode===ESCAPE_KEYCODE){reset(this)}})}function reset(el){var s=d3.select(el);s.on("mousemove",null);d3.select(document).on("mouseup",null);drag={};rectangle.remove()}function compareNumbers(a,b){return a-b}function pointAsDate(e){return Math.floor(self.graph.x.invert(e.offsetX||e.layerX))}}});Rickshaw.namespace("Rickshaw.Graph.HoverDetail");Rickshaw.Graph.HoverDetail=Rickshaw.Class.create({initialize:function(args){var graph=this.graph=args.graph;this.xFormatter=args.xFormatter||function(x){return new Date(x*1e3).toUTCString()};this.yFormatter=args.yFormatter||function(y){return y===null?y:y.toFixed(2)};var element=this.element=document.createElement("div");element.className="detail inactive";this.visible=true;graph.element.appendChild(element);this.lastEvent=null;this._addListeners();this.onShow=args.onShow;this.onHide=args.onHide;this.onRender=args.onRender;this.formatter=args.formatter||this.formatter},formatter:function(series,x,y,formattedX,formattedY,d){return series.name+": "+formattedY},update:function(e){e=e||this.lastEvent;if(!e)return;this.lastEvent=e;if(!e.target.nodeName.match(/^(path|svg|rect|circle)$/))return;var graph=this.graph;var rect=graph.element.getBoundingClientRect();var eventX=e.clientX-rect.left;var eventY=e.clientY-rect.top;var j=0;var points=[];var nearestPoint;this.graph.series.active().forEach(function(series){var data=this.graph.stackedData[j++];if(!data.length)return;var domainX=graph.x.invert(eventX);var domainIndexScale=d3.scale.linear().domain([data[0].x,data.slice(-1)[0].x]).range([0,data.length-1]);var approximateIndex=Math.round(domainIndexScale(domainX));if(approximateIndex==data.length-1)approximateIndex--;var dataIndex=Math.min(approximateIndex||0,data.length-1);for(var i=approximateIndex;idomainX){dataIndex=Math.abs(domainX-data[i].x)0){alignables.forEach(function(el){el.classList.remove("left");el.classList.add("right")});var rightAlignError=this._calcLayoutError(alignables);if(rightAlignError>leftAlignError){alignables.forEach(function(el){el.classList.remove("right");el.classList.add("left")})}}if(typeof this.onRender=="function"){this.onRender(args)}},_calcLayoutError:function(alignables){var parentRect=this.element.parentNode.getBoundingClientRect();var error=0;var alignRight=alignables.forEach(function(el){var rect=el.getBoundingClientRect();if(!rect.width){return}if(rect.right>parentRect.right){error+=rect.right-parentRect.right}if(rect.left=self.previewWidth){frameAfterDrag[0]-=frameAfterDrag[1]-self.previewWidth;frameAfterDrag[1]=self.previewWidth}}self.graphs.forEach(function(graph){var domainScale=d3.scale.linear().interpolate(d3.interpolateNumber).domain([0,self.previewWidth]).range(graph.dataDomain());var windowAfterDrag=[domainScale(frameAfterDrag[0]),domainScale(frameAfterDrag[1])];self.slideCallbacks.forEach(function(callback){callback(graph,windowAfterDrag[0],windowAfterDrag[1])});if(frameAfterDrag[0]===0){windowAfterDrag[0]=undefined}if(frameAfterDrag[1]===self.previewWidth){windowAfterDrag[1]=undefined}graph.window.xMin=windowAfterDrag[0];graph.window.xMax=windowAfterDrag[1];graph.update()})}function onMousedown(){drag.target=d3.event.target;drag.start=self._getClientXFromEvent(d3.event,drag);self.frameBeforeDrag=self.currentFrame.slice();d3.event.preventDefault?d3.event.preventDefault():d3.event.returnValue=false;d3.select(document).on("mousemove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("mouseup.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchmove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("touchend.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",onMouseup)}function onMousedownLeftHandle(datum,index){drag.left=true;onMousedown()}function onMousedownRightHandle(datum,index){drag.right=true;onMousedown()}function onMousedownMiddleHandle(datum,index){drag.left=true;drag.right=true;drag.rigid=true;onMousedown()}function onMouseup(datum,index){d3.select(document).on("mousemove.rickshaw_range_slider_preview",null);d3.select(document).on("mouseup.rickshaw_range_slider_preview",null);d3.select(document).on("touchmove.rickshaw_range_slider_preview",null);d3.select(document).on("touchend.rickshaw_range_slider_preview",null);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",null);delete self.frameBeforeDrag;drag.left=false;drag.right=false;drag.rigid=false}element.select("rect.left_handle").on("mousedown",onMousedownLeftHandle);element.select("rect.right_handle").on("mousedown",onMousedownRightHandle);element.select("rect.middle_handle").on("mousedown",onMousedownMiddleHandle);element.select("rect.left_handle").on("touchstart",onMousedownLeftHandle);element.select("rect.right_handle").on("touchstart",onMousedownRightHandle);element.select("rect.middle_handle").on("touchstart",onMousedownMiddleHandle)},_getClientXFromEvent:function(event,drag){switch(event.type){case"touchstart":case"touchmove":var touchList=event.changedTouches;var touch=null;for(var touchIndex=0;touchIndexyMax)yMax=y});if(!series.length)return;if(series[0].xxMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var pathNodes=vis.selectAll("path.path").data(data).enter().append("svg:path").classed("path",true).attr("d",this.seriesPathFactory());if(this.stroke){var strokeNodes=vis.selectAll("path.stroke").data(data).enter().append("svg:path").classed("stroke",true).attr("d",this.seriesStrokeFactory())}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=pathNodes[0][i];if(this.stroke)series.stroke=strokeNodes[0][i];this._styleSeries(series);i++},this)}, +_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";var strokeWidth=series.strokeWidth?series.strokeWidth:this.strokeWidth;var opacity=series.opacity===undefined?this.opacity:series.opacity;series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",strokeWidth);series.path.setAttribute("opacity",opacity);if(series.className){d3.select(series.path).classed(series.className,true)}if(series.className&&this.stroke){d3.select(series.stroke).classed(series.className,true)}},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false,opacity:1});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x.magnitude(frequentInterval.magnitude)*(1-this.gapSize);return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("opacity",series.opacity).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}});return Rickshaw}); diff -Nru pdns-recursor-5.2.13/iputils.cc pdns-recursor-5.4.9/iputils.cc --- pdns-recursor-5.2.13/iputils.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/iputils.cc 2026-10-26 09:46:36.000000000 +0000 @@ -54,9 +54,29 @@ return ret; } -int SConnect(int sockfd, const ComboAddress& remote) +static int doConnect(int sockfd, [[maybe_unused]] bool fastopen, const ComboAddress& remote) { - int ret = connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) +#ifdef CONNECTX_FASTOPEN + if (fastopen) { + sa_endpoints_t endpoints{}; + + endpoints.sae_dstaddr = reinterpret_cast(&remote); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + endpoints.sae_dstaddrlen = remote.getSocklen(); + + int flags = CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE; + return connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, flags, nullptr, 0, nullptr, nullptr); + } + else { +#endif + return connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) +#ifdef CONNECTX_FASTOPEN + } +#endif +} + +int SConnect(int sockfd, bool fastopen, const ComboAddress& remote) +{ + int ret = doConnect(sockfd, fastopen, remote); if (ret < 0) { int savederrno = errno; RuntimeError("connecting socket to " + remote.toStringWithPort() + ": " + stringerror(savederrno)); @@ -64,9 +84,9 @@ return ret; } -int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout) +int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout) { - int ret = connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + int ret = doConnect(sockfd, fastopen, remote); if (ret < 0) { int savederrno = errno; if (savederrno == EINPROGRESS) { @@ -77,7 +97,7 @@ /* we wait until the connection has been established */ bool error = false; bool disconnected = false; - int res = waitForRWData(sockfd, false, static_cast(timeout.tv_sec), static_cast(timeout.tv_usec), &error, &disconnected); + int res = waitForRWData(sockfd, false, timeout, &error, &disconnected); if (res == 1) { if (error) { savederrno = 0; diff -Nru pdns-recursor-5.2.13/iputils.hh pdns-recursor-5.4.9/iputils.hh --- pdns-recursor-5.2.13/iputils.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/iputils.hh 2026-10-26 09:46:36.000000000 +0000 @@ -27,11 +27,11 @@ #include #include #include -#include #include "pdnsexception.hh" #include "misc.hh" #include #include +#include #include "namespaces.hh" @@ -52,6 +52,11 @@ #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) + +#if defined(CONNECT_DATA_IDEMPOTENT) && defined(CONNECT_RESUME_ON_READ_WRITE) +#define CONNECTX_FASTOPEN 1 +#endif + #endif #ifdef __sun @@ -284,6 +289,14 @@ return true; } + [[nodiscard]] bool isUnspecified() const + { + static const ComboAddress unspecifiedV4("0.0.0.0:0"); + static const ComboAddress unspecifiedV6("[::]:0"); + const auto compare = ComboAddress::addressOnlyEqual(); + return compare(*this, unspecifiedV4) || compare(*this, unspecifiedV6); + } + [[nodiscard]] ComboAddress mapToIPv4() const { if (!isMappedIPv4()) { @@ -330,6 +343,9 @@ return host.data(); } } + else { + return "invalid"; + } return "invalid " + stringerror(); } @@ -413,7 +429,6 @@ void reset() { - memset(&sin4, 0, sizeof(sin4)); memset(&sin6, 0, sizeof(sin6)); } @@ -490,6 +505,134 @@ }; }; +union SockaddrWrapper +{ + sockaddr_in sin4{}; + sockaddr_in6 sin6; + sockaddr_un sinun; + + [[nodiscard]] socklen_t getSocklen() const + { + if (sin4.sin_family == AF_INET) { + return sizeof(sin4); + } + if (sin6.sin6_family == AF_INET6) { + return sizeof(sin6); + } + if (sinun.sun_family == AF_UNIX) { + return sizeof(sinun); + } + return 0; + } + + SockaddrWrapper() + { + sin4.sin_family = AF_INET; + sin4.sin_addr.s_addr = 0; + sin4.sin_port = 0; + } + + SockaddrWrapper(const struct sockaddr* socketAddress, socklen_t salen) + { + setSockaddr(socketAddress, salen); + }; + + SockaddrWrapper(const struct sockaddr_in6* socketAddress) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + setSockaddr(reinterpret_cast(socketAddress), sizeof(struct sockaddr_in6)); + }; + + SockaddrWrapper(const struct sockaddr_in* socketAddress) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + setSockaddr(reinterpret_cast(socketAddress), sizeof(struct sockaddr_in)); + }; + + SockaddrWrapper(const struct sockaddr_un* socketAddress) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + setSockaddr(reinterpret_cast(socketAddress), sizeof(struct sockaddr_un)); + }; + + void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen) + { + if (salen > sizeof(struct sockaddr_un)) { + throw PDNSException("ComboAddress can't handle other than sockaddr_in, sockaddr_in6 or sockaddr_un"); + } + memcpy(this, socketAddress, salen); + } + + explicit SockaddrWrapper(const string& str, uint16_t port = 0) + { + memset(&sinun, 0, sizeof(sinun)); + sin4.sin_family = AF_INET; + sin4.sin_port = 0; + if (str == "\"\"" || str == "''") { + throw PDNSException("Stray quotation marks in address."); + } + if (makeIPv4sockaddr(str, &sin4) != 0) { + sin6.sin6_family = AF_INET6; + if (makeIPv6sockaddr(str, &sin6) < 0) { + sinun.sun_family = AF_UNIX; + // only attempt Unix socket address if address candidate does not contain a port + if (str.find(':') != string::npos || makeUNsockaddr(str, &sinun) < 0) { + throw PDNSException("Unable to convert presentation address '" + str + "'"); + } + } + } + if (sinun.sun_family != AF_UNIX && sin4.sin_port == 0) { // 'str' overrides port! + sin4.sin_port = htons(port); + } + } + + [[nodiscard]] bool isIPv6() const + { + return sin4.sin_family == AF_INET6; + } + [[nodiscard]] bool isIPv4() const + { + return sin4.sin_family == AF_INET; + } + [[nodiscard]] bool isUnixSocket() const + { + return sin4.sin_family == AF_UNIX; + } + + [[nodiscard]] string toString() const + { + if (sinun.sun_family == AF_UNIX) { + return sinun.sun_path; + } + std::array host{}; + if (sin4.sin_family != 0) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + int retval = getnameinfo(reinterpret_cast(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST); + if (retval == 0) { + return host.data(); + } + return "invalid " + string(gai_strerror(retval)); + } + return "invalid"; + } + + [[nodiscard]] string toStringWithPort() const + { + if (sinun.sun_family == AF_UNIX) { + return toString(); + } + if (sin4.sin_family == AF_INET) { + return toString() + ":" + std::to_string(ntohs(sin4.sin_port)); + } + return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port)); + } + + void reset() + { + memset(&sinun, 0, sizeof(sinun)); + } +}; + /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */ class NetmaskException : public PDNSException { @@ -602,20 +745,36 @@ } } + enum stringType + { + humanString, + byteString, + }; //! Constructor supplies the mask, which cannot be changed - Netmask(const string& mask) + Netmask(const string& mask, stringType type = humanString) { - pair split = splitField(mask, '/'); - d_network = makeComboAddress(split.first); + if (type == byteString) { + uint8_t afi = mask.at(0); + size_t len = afi == 4 ? 4 : 16; + uint8_t bits = mask.at(len + 1); - if (!split.second.empty()) { - setBits(pdns::checked_stoi(split.second)); - } - else if (d_network.sin4.sin_family == AF_INET) { - setBits(32); + d_network = makeComboAddressFromRaw(afi, mask.substr(1, len)); + + setBits(bits); } else { - setBits(128); + pair split = splitField(mask, '/'); + d_network = makeComboAddress(split.first); + + if (!split.second.empty()) { + setBits(pdns::checked_stoi(split.second)); + } + else if (d_network.sin4.sin_family == AF_INET) { + setBits(32); + } + else { + setBits(128); + } } } @@ -685,6 +844,17 @@ return d_network.toStringNoInterface(); } + [[nodiscard]] string toByteString() const + { + ostringstream tmp; + + tmp << (d_network.isIPv4() ? "\x04" : "\x06") + << d_network.toByteString() + << getBits(); + + return tmp.str(); + } + [[nodiscard]] const ComboAddress& getNetwork() const { return d_network; @@ -740,7 +910,7 @@ bool operator!=(const Netmask& rhs) const { - return !(*this == rhs); + return !operator==(rhs); } [[nodiscard]] bool empty() const @@ -818,7 +988,7 @@ /** Binary tree map implementation with pair. * - * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes. + * This is a binary tree implementation for storing attributes for IPv4 and IPv6 prefixes. * The most simple use case is simple NetmaskTree used by NetmaskGroup, which only * wants to know if given IP address is matched in the prefixes stored. * @@ -1140,11 +1310,11 @@ return &d_node->node; } - bool operator==(const Iterator& rhs) + bool operator==(const Iterator& rhs) const { return (d_tree == rhs.d_tree && d_node == rhs.d_node); } - bool operator!=(const Iterator& rhs) + bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } @@ -1592,7 +1762,7 @@ tree.insert(netmask).second = positive; } - void addMasks(const NetmaskGroup& group, boost::optional positive) + void addMasks(const NetmaskGroup& group, std::optional positive) { for (const auto& entry : group.tree) { addMask(entry.first, positive ? *positive : entry.second); @@ -1881,12 +2051,12 @@ }; int SSocket(int family, int type, int flags); -int SConnect(int sockfd, const ComboAddress& remote); +int SConnect(int sockfd, bool fastopen, const ComboAddress& remote); /* tries to connect to remote for a maximum of timeout seconds. sockfd should be set to non-blocking beforehand. returns 0 on success (the socket is writable), throw a runtime_error otherwise */ -int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout); +int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout); int SBind(int sockfd, const ComboAddress& local); int SAccept(int sockfd, ComboAddress& remote); int SListen(int sockfd, int limit); diff -Nru pdns-recursor-5.2.13/libssl.cc pdns-recursor-5.4.9/libssl.cc --- pdns-recursor-5.2.13/libssl.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/libssl.cc 2026-10-26 09:46:36.000000000 +0000 @@ -28,6 +28,7 @@ #endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ #include #include +#include #include #if OPENSSL_VERSION_MAJOR >= 3 @@ -203,7 +204,7 @@ } #endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */ -#if defined(HAVE_LIBSSL) && !HAVE_TLS_PROVIDERS +#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS) std::pair libssl_load_engine([[maybe_unused]] const std::string& engineName, [[maybe_unused]] const std::optional& defaultString) { #if defined(OPENSSL_NO_ENGINE) @@ -353,10 +354,10 @@ } } -void libssl_set_error_counters_callback(std::unique_ptr& ctx, TLSErrorCounters* counters) +void libssl_set_error_counters_callback(SSL_CTX& ctx, TLSErrorCounters* counters) { - SSL_CTX_set_ex_data(ctx.get(), s_countersIndex, counters); - SSL_CTX_set_info_callback(ctx.get(), libssl_info_callback); + SSL_CTX_set_ex_data(&ctx, s_countersIndex, counters); + SSL_CTX_set_info_callback(&ctx, libssl_info_callback); } #ifndef DISABLE_OCSP_STAPLING @@ -373,14 +374,23 @@ return SSL_TLSEXT_ERR_NOACK; } + const auto ocsp_resp_size = data->second.size(); + /* the behaviour is alas different in 3.6.0 because of a regression introduced in b1b4b154fd389ac6254d49cfb11aee36c1c51b84: + the value passed to SSL_set_tlsext_status_ocsp_resp() is not freed in 3.6.0 as it is in all other OpenSSL versions. + See https://github.com/openssl/openssl/issues/28888 */ +#if OPENSSL_VERSION_NUMBER != 0x30600000L /* we need to allocate a copy because OpenSSL will free the pointer passed to SSL_set_tlsext_status_ocsp_resp() */ - void* copy = OPENSSL_malloc(data->second.size()); - if (copy == nullptr) { + void* ocsp_resp = OPENSSL_malloc(ocsp_resp_size); + if (ocsp_resp == nullptr) { return SSL_TLSEXT_ERR_NOACK; } - memcpy(copy, data->second.data(), data->second.size()); - SSL_set_tlsext_status_ocsp_resp(ssl, copy, data->second.size()); + memcpy(ocsp_resp, data->second.data(), ocsp_resp_size); +#else + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): the parameter is not freed in this version (3.6.0, see above) but the parameter is not marked const. + void* ocsp_resp = const_cast(data->second.data()); +#endif + SSL_set_tlsext_status_ocsp_resp(ssl, ocsp_resp, ocsp_resp_size); return SSL_TLSEXT_ERR_OK; } @@ -442,29 +452,29 @@ size_t count = 0; for (const auto& filename : ocspFiles) { + const size_t idx = count++; std::ifstream file(filename, std::ios::binary); std::string content; while (file) { - char buffer[4096]; - file.read(buffer, sizeof(buffer)); + std::array buffer{}; + file.read(buffer.data(), buffer.size()); if (file.bad()) { file.close(); warnings.push_back("Unable to load OCSP response from " + filename); continue; } - content.append(buffer, file.gcount()); + content.append(buffer.data(), file.gcount()); } file.close(); try { libssl_validate_ocsp_response(content); - ocspResponses.insert({keyTypes.at(count), std::move(content)}); + ocspResponses.insert({keyTypes.at(idx), std::move(content)}); } catch (const std::exception& e) { warnings.push_back("Error checking the validity of OCSP response from '" + filename + "': " + e.what()); continue; } - ++count; } return ocspResponses; @@ -518,12 +528,12 @@ #endif /* HAVE_OCSP_BASIC_SIGN */ #endif /* DISABLE_OCSP_STAPLING */ -static int libssl_get_last_key_type(std::unique_ptr& ctx) +static int libssl_get_last_key_type(SSL_CTX& ctx) { #ifdef HAVE_SSL_CTX_GET0_PRIVATEKEY - auto pkey = SSL_CTX_get0_privatekey(ctx.get()); + auto* pkey = SSL_CTX_get0_privatekey(&ctx); #else - auto temp = std::unique_ptr(SSL_new(ctx.get()), SSL_free); + auto temp = std::unique_ptr(SSL_new(&ctx), SSL_free); if (!temp) { return -1; } @@ -537,6 +547,70 @@ return EVP_PKEY_base_id(pkey); } +struct StackOfNamesDeleter +{ + void operator()(STACK_OF(GENERAL_NAME)* ptr) const noexcept { + sk_GENERAL_NAME_pop_free(ptr, GENERAL_NAME_free); + } +}; + +#if defined(OPENSSL_IS_BORINGSSL) +/* return type of OpenSSL's sk_XXX_num() */ +using SSLStackIndex = size_t; +#else +using SSLStackIndex = int; +#endif + +static std::unordered_set get_names_from_certificate(const X509* certificate) +{ + std::unordered_set result; + auto names = std::unique_ptr(static_cast(X509_get_ext_d2i(certificate, NID_subject_alt_name, nullptr, nullptr))); + if (names) { + for (SSLStackIndex idx = 0; idx < sk_GENERAL_NAME_num(names.get()); idx++) { + const auto* name = sk_GENERAL_NAME_value(names.get(), idx); + if (name->type != GEN_DNS) { + /* ignore GEN_IPADD / name->d.iPAddress (raw IP address bytes), it cannot be used in SNI anyway */ + continue; + } + unsigned char* str = nullptr; + if (ASN1_STRING_to_UTF8(&str, name->d.dNSName) < 0) { + continue; + } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API + result.emplace(reinterpret_cast(str)); + OPENSSL_free(str); + } + } + + auto* name = X509_get_subject_name(certificate); + if (name != nullptr) { + int idx = -1; + while ((idx = X509_NAME_get_index_by_NID(name, NID_commonName, idx)) != -1) { + const auto* entry = X509_NAME_get_entry(name, idx); + const auto* value = X509_NAME_ENTRY_get_data(entry); + unsigned char* str = nullptr; + if (ASN1_STRING_to_UTF8(&str, value) < 0) { + continue; + } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API + result.emplace(reinterpret_cast(str)); + OPENSSL_free(str); + } + } + + return result; +} + +static std::unordered_set get_names_from_last_certificate(const SSL_CTX& ctx) +{ + const auto* cert = SSL_CTX_get0_certificate(&ctx); + if (cert == nullptr) { + return {}; + } + + return get_names_from_certificate(cert); +} + LibsslTLSVersion libssl_tls_version_from_string(const std::string& str) { if (str == "tls1.0") { @@ -551,7 +625,7 @@ if (str == "tls1.3") { return LibsslTLSVersion::TLS13; } - throw std::runtime_error("Unknown TLS version '" + str); + throw std::runtime_error("Unknown TLS version '" + str + "'"); } const std::string& libssl_tls_version_to_string(LibsslTLSVersion version) @@ -570,7 +644,7 @@ return it->second; } -bool libssl_set_min_tls_version(std::unique_ptr& ctx, LibsslTLSVersion version) +static bool libssl_set_min_tls_version(SSL_CTX& ctx, LibsslTLSVersion version) { #if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) || defined(SSL_CTX_set_min_proto_version) /* These functions have been introduced in 1.1.0, and the use of SSL_OP_NO_* is deprecated @@ -597,7 +671,7 @@ return false; } - if (SSL_CTX_set_min_proto_version(ctx.get(), vers) != 1) { + if (SSL_CTX_set_min_proto_version(&ctx, vers) != 1) { return false; } return true; @@ -619,8 +693,8 @@ return false; } - long options = SSL_CTX_get_options(ctx.get()); - SSL_CTX_set_options(ctx.get(), options | vers); + long options = SSL_CTX_get_options(&ctx); + SSL_CTX_set_options(&ctx, options | vers); return true; #endif } @@ -894,10 +968,8 @@ return true; } -std::pair, std::vector> libssl_init_server_context(const TLSConfig& config, - std::map& ocspResponses) +static std::unique_ptr getNewServerContext(const TLSConfig& config, [[maybe_unused]] std::vector& warnings) { - std::vector warnings; auto ctx = std::unique_ptr(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free); if (!ctx) { @@ -952,7 +1024,7 @@ #endif SSL_CTX_set_options(ctx.get(), sslOptions); - if (!libssl_set_min_tls_version(ctx, config.d_minTLSVersion)) { + if (!libssl_set_min_tls_version(*ctx, config.d_minTLSVersion)) { throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(config.d_minTLSVersion)); } @@ -992,6 +1064,29 @@ session is resumed, causing SSL_get_servername to return nullptr */ SSL_CTX_set_tlsext_servername_callback(ctx.get(), &libssl_server_name_callback); + return ctx; +} + +static void mergeNewCertificateAndKey(pdns::libssl::ServerContext& serverContext, pdns::libssl::ServerContext::SharedContext newContext, std::unordered_set& names, const std::function& existingContextCallback) +{ + for (const auto& name : names) { + auto [existingEntry, inserted] = serverContext.d_sniMap.emplace(name, newContext); + if (!inserted) { + auto& existingContext = existingEntry->second; + existingContextCallback(existingContext); + } + else if (serverContext.d_sniMap.size() == 1) { + serverContext.d_defaultContext = newContext; + } + } +} + +std::pair, std::vector> libssl_init_server_context_no_sni(const TLSConfig& config, + [[maybe_unused]] std::map& ocspResponses) +{ + std::vector warnings; + auto ctx = getNewServerContext(config, warnings); + std::vector keyTypes; /* load certificate and private key */ for (const auto& pair : config.d_certKeyPairs) { @@ -1029,7 +1124,7 @@ if (failed) { #endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occured while parsing PKCS12 file " + pair.d_cert); + throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 } #endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ @@ -1055,12 +1150,13 @@ throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); } } + if (SSL_CTX_check_private_key(ctx.get()) != 1) { ERR_print_errors_fp(stderr); throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); } /* store the type of the new key, we might need it later to select the right OCSP stapling response */ - auto keyType = libssl_get_last_key_type(ctx); + auto keyType = libssl_get_last_key_type(*ctx); if (keyType < 0) { throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); } @@ -1091,6 +1187,138 @@ return {std::move(ctx), std::move(warnings)}; } +std::pair> libssl_init_server_context(const TLSConfig& config) +{ + std::vector warnings; + pdns::libssl::ServerContext serverContext; + + std::vector keyTypes; + /* load certificate and private key */ + for (const auto& pair : config.d_certKeyPairs) { + auto uniqueCtx = getNewServerContext(config, warnings); + auto ctx = std::shared_ptr(uniqueCtx.release(), SSL_CTX_free); + if (!pair.d_key) { +#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY) + // If no separate key is given, treat it as a pkcs12 file + auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r")); + if (!filePtr) { + throw std::runtime_error("Unable to open file " + pair.d_cert); + } + auto p12 = std::unique_ptr(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free); + if (!p12) { + throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert); + } + EVP_PKEY *keyptr = nullptr; + X509 *certptr = nullptr; + STACK_OF(X509) *captr = nullptr; + if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) != 1) { +#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 + bool failed = true; + /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */ + auto* libCtx = OSSL_LIB_CTX_get0_global_default(); + /* check whether the legacy provider is already loaded */ + if (OSSL_PROVIDER_available(libCtx, "legacy") == 0) { + /* it's not */ + auto* provider = OSSL_PROVIDER_load(libCtx, "legacy"); + if (provider != nullptr) { + if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) == 1) { + failed = false; + } + /* we do not want to keep that provider around after that */ + OSSL_PROVIDER_unload(provider); + } + } + if (failed) { +#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); +#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 + } +#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ + } + auto key = std::unique_ptr(keyptr, EVP_PKEY_free); + auto cert = std::unique_ptr(certptr, X509_free); + auto caList = std::unique_ptr(captr, [](STACK_OF(X509)* stack){ sk_X509_free(stack); }); + + auto addCertificateAndKey = [&pair, &key, &cert, &caList](std::shared_ptr& tlsContext) { + if (SSL_CTX_use_cert_and_key(tlsContext.get(), cert.get(), key.get(), caList.get(), 1) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert); + } + }; + + addCertificateAndKey(ctx); + auto names = get_names_from_last_certificate(*ctx); + if (!names.empty()) { + mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); + } + else if (!serverContext.d_defaultContext) { + serverContext.d_defaultContext = ctx; + } +#else + throw std::runtime_error("PKCS12 files are not supported by your openssl version"); +#endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */ + } else { + auto addCertificateAndKey = [&pair](std::shared_ptr& tlsContext) { + if (SSL_CTX_use_certificate_chain_file(tlsContext.get(), pair.d_cert.c_str()) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert); + } + if (SSL_CTX_use_PrivateKey_file(tlsContext.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); + } + }; + + addCertificateAndKey(ctx); + auto names = get_names_from_last_certificate(*ctx); + if (!names.empty()) { + mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); + } + else if (!serverContext.d_defaultContext) { + serverContext.d_defaultContext = ctx; + } + } + + if (SSL_CTX_check_private_key(ctx.get()) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); + } + /* store the type of the new key, we might need it later to select the right OCSP stapling response */ + auto keyType = libssl_get_last_key_type(*ctx); + if (keyType < 0) { + throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); + } + keyTypes.push_back(keyType); + } + +#ifndef DISABLE_OCSP_STAPLING + if (!config.d_ocspFiles.empty()) { + try { + serverContext.d_ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, std::move(keyTypes), warnings); + } + catch(const std::exception& e) { + throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what())); + } + } +#endif /* DISABLE_OCSP_STAPLING */ + + for (auto& entry : serverContext.d_sniMap) { + auto& ctx = entry.second; + if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) { + throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers); + } + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) { + throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13); + } +#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */ + } + + return {std::move(serverContext), std::move(warnings)}; +} + #ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK static void libssl_key_log_file_callback(const SSL* ssl, const char* line) { @@ -1110,7 +1338,7 @@ } #endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */ -pdns::UniqueFilePtr libssl_set_key_log_file(SSL_CTX* ctx, const std::string& logFile) +pdns::UniqueFilePtr libssl_set_key_log_file([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] const std::string& logFile) { #ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK auto filePtr = pdns::openFileForWriting(logFile, 0600, false, true); @@ -1127,14 +1355,14 @@ } /* 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) +void libssl_set_alpn_select_callback([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] int (*callback)(SSL* ssl, const unsigned char** out, unsigned char* outlen, const unsigned char* inPtr, unsigned int inlen, void* arg), [[maybe_unused]] void* arg) { #ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB - SSL_CTX_set_alpn_select_cb(ctx, cb, arg); + SSL_CTX_set_alpn_select_cb(ctx, callback, arg); #endif } -bool libssl_set_alpn_protos(SSL_CTX* ctx, const std::vector>& protos) +bool libssl_set_alpn_protos([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] const std::vector>& protos) { #ifdef HAVE_SSL_CTX_SET_ALPN_PROTOS std::vector wire; @@ -1161,7 +1389,7 @@ size_t len = BIO_get_mem_data(mem, &p); std::string msg(p, len); // replace newlines by / - if (msg.back() == '\n') { + if (!msg.empty() && msg.back() == '\n') { msg.pop_back(); } std::replace(msg.begin(), msg.end(), '\n', '/'); diff -Nru pdns-recursor-5.2.13/libssl.hh pdns-recursor-5.4.9/libssl.hh --- pdns-recursor-5.2.13/libssl.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/libssl.hh 2026-10-26 09:46:36.000000000 +0000 @@ -147,21 +147,35 @@ #endif #endif /* DISABLE_OCSP_STAPLING */ -void libssl_set_error_counters_callback(std::unique_ptr& ctx, TLSErrorCounters* counters); +void libssl_set_error_counters_callback(SSL_CTX& ctx, TLSErrorCounters* counters); LibsslTLSVersion libssl_tls_version_from_string(const std::string& str); const std::string& libssl_tls_version_to_string(LibsslTLSVersion version); -bool libssl_set_min_tls_version(std::unique_ptr& ctx, LibsslTLSVersion version); + + +namespace pdns::libssl { +class ServerContext +{ +public: + using SharedContext = std::shared_ptr; + using SNIToContextMap = std::map>; + + SharedContext d_defaultContext; + SNIToContextMap d_sniMap; + std::map d_ocspResponses; +}; +} /* return the created context, and a list of warning messages for issues not severe enough to trigger raising an exception, like failing to load an OCSP response file */ -std::pair, std::vector> libssl_init_server_context(const TLSConfig& config, - std::map& ocspResponses); +std::pair, std::vector> libssl_init_server_context_no_sni(const TLSConfig& config, + std::map& ocspResponses); +std::pair> libssl_init_server_context(const TLSConfig& config); pdns::UniqueFilePtr libssl_set_key_log_file(SSL_CTX* ctx, const std::string& logFile); /* 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); +void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*callback)(SSL* ssl, const unsigned char** out, unsigned char* outlen, const unsigned char* inPtr, unsigned int inlen, void* arg), void* arg); /* set the supported ALPN protos in client context */ bool libssl_set_alpn_protos(SSL_CTX* ctx, const std::vector>& protos); diff -Nru pdns-recursor-5.2.13/lock.hh pdns-recursor-5.4.9/lock.hh --- pdns-recursor-5.2.13/lock.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lock.hh 2026-10-26 09:46:36.000000000 +0000 @@ -65,7 +65,7 @@ - ReadLock, WriteLock, TryReadLock and TryWriteLock are there as RAII objects allowing to take a lock and be sure that it will always be unlocked - when we exit the block, even with a unforeseen exception. + when we exit the block, even with an unforeseen exception. They are light wrappers around std::unique_lock and std::shared_lock since C++17. @@ -248,7 +248,7 @@ } private: - std::lock_guard d_lock; + std::scoped_lock d_lock; T& d_value; }; @@ -353,7 +353,7 @@ } private: - std::lock_guard d_lock; + std::scoped_lock d_lock; T& d_value; }; @@ -458,7 +458,7 @@ } private: - std::lock_guard d_lock; + std::scoped_lock d_lock; T& d_value; }; diff -Nru pdns-recursor-5.2.13/logger.cc pdns-recursor-5.4.9/logger.cc --- pdns-recursor-5.2.13/logger.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/logger.cc 2026-10-26 09:46:36.000000000 +0000 @@ -104,7 +104,7 @@ } static std::mutex mutex; - std::lock_guard lock(mutex); // the C++-2011 spec says we need this, and OSX actually does + auto lock = std::scoped_lock(mutex); // the C++-2011 spec says we need this, and macOS actually does // To avoid issuing multiple syscalls, we write the complete line to clog with a single << call. // For that we need a buffer allocated, we might want to use writev(2) one day to avoid that. @@ -165,7 +165,7 @@ } Logger::Logger(string n, int facility) : - name(std::move(n)), flags(LOG_PID | LOG_NDELAY), d_facility(facility), d_loglevel(Logger::None), consoleUrgency(Error), opened(false), d_disableSyslog(false) + name(std::move(n)), flags(LOG_PID | LOG_NDELAY), d_facility(facility) { open(); } @@ -211,12 +211,27 @@ return *this; } +#if defined(PDNS_AUTH) +Logger& Logger::operator<<(const ZoneName& zone) +{ + *this << zone.toLogString(); + + return *this; +} +#endif + Logger& Logger::operator<<(const ComboAddress& ca) { *this << ca.toLogString(); return *this; } +Logger& Logger::operator<<(const SockaddrWrapper& sockaddr) +{ + *this << sockaddr.toString(); + return *this; +} + void addTraceTS(const timeval& start, ostringstream& str) { const auto& content = str.str(); diff -Nru pdns-recursor-5.2.13/logger.hh pdns-recursor-5.4.9/logger.hh --- pdns-recursor-5.2.13/logger.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/logger.hh 2026-10-26 09:46:36.000000000 +0000 @@ -108,7 +108,11 @@ Logger& operator<<(const char* s); Logger& operator<<(const string& s); //!< log a string Logger& operator<<(const DNSName&); +#if defined(PDNS_AUTH) + Logger& operator<<(const ZoneName&); +#endif Logger& operator<<(const ComboAddress&); //!< log an address + Logger& operator<<(const SockaddrWrapper&); //!< log an address Logger& operator<<(Urgency); //!< set the urgency, << style Logger& operator<<(const QType& qtype) @@ -138,11 +142,8 @@ private: struct PerThread { - PerThread() : - d_urgency(Info) - {} string d_output; - Urgency d_urgency; + Urgency d_urgency{Info}; }; PerThread& getPerThread(); void open(); @@ -151,10 +152,10 @@ string name; int flags; int d_facility; - Urgency d_loglevel; - Urgency consoleUrgency; - bool opened; - bool d_disableSyslog; + Urgency d_loglevel{Logger::None}; + Urgency consoleUrgency{Error}; + bool opened{false}; + bool d_disableSyslog{false}; bool d_timestamps{true}; bool d_prefixed{false}; // this used to prefix the loglevel, but now causes formatting like structured logging }; diff -Nru pdns-recursor-5.2.13/logging.cc pdns-recursor-5.4.9/logging.cc --- pdns-recursor-5.2.13/logging.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/logging.cc 2026-10-26 09:46:36.000000000 +0000 @@ -23,7 +23,6 @@ #include "logging.hh" #include #include -#include "utility.hh" namespace Logging { @@ -33,38 +32,38 @@ return shared_from_this(); } -bool Logger::enabled(Logr::Priority p) const +bool Logger::enabled(Logr::Priority prio) const { - return _level <= _verbosity || p != Logr::Absent; + return _level <= _verbosity || prio != Logr::Absent; } void Logger::info(const std::string& msg) const { - logMessage(msg, Logr::Absent, boost::none); + logMessage(msg, Logr::Absent, std::nullopt); } -void Logger::info(Logr::Priority p, const std::string& msg) const +void Logger::info(Logr::Priority prio, const std::string& msg) const { - logMessage(msg, p, boost::none); + logMessage(msg, prio, std::nullopt); } -void Logger::logMessage(const std::string& msg, boost::optional err) const +void Logger::logMessage(const std::string& msg, const std::optional& err) const { - return logMessage(msg, Logr::Absent, std::move(err)); + logMessage(msg, Logr::Absent, err); } -void Logger::logMessage(const std::string& msg, Logr::Priority p, boost::optional err) const +void Logger::logMessage(const std::string& msg, Logr::Priority prio, const std::optional& err) const { - if (!enabled(p)) { + if (!enabled(prio)) { return; } Entry entry; entry.level = _level; - entry.d_priority = p; - Utility::gettimeofday(&entry.d_timestamp); + entry.d_priority = prio; + ::gettimeofday(&entry.d_timestamp, nullptr); entry.name = _name; entry.message = msg; - entry.error = std::move(err); + entry.error = err; auto parent = _parent; entry.values.insert(_values.begin(), _values.end()); while (parent) { @@ -74,19 +73,19 @@ _callback(entry); } -void Logger::error(Logr::Priority p, int err, const std::string& msg) const +void Logger::error(Logr::Priority prio, int err, const std::string& msg) const { - logMessage(msg, p, std::string(std::strerror(err))); + logMessage(msg, prio, std::string(stringerror(err))); } -void Logger::error(Logr::Priority p, const std::string& err, const std::string& msg) const +void Logger::error(Logr::Priority prio, const std::string& err, const std::string& msg) const { - logMessage(msg, p, err); + logMessage(msg, prio, err); } void Logger::error(int err, const std::string& msg) const { - logMessage(msg, Logr::Absent, std::string(std::strerror(err))); + logMessage(msg, Logr::Absent, std::string(stringerror(err))); } void Logger::error(const std::string& err, const std::string& msg) const @@ -111,7 +110,7 @@ { std::shared_ptr res; if (_name) { - res = std::make_shared(getptr(), _name.get() + "." + name, getVerbosity(), _level, _callback); + res = std::make_shared(getptr(), _name.value() + "." + name, getVerbosity(), _level, _callback); } else { res = std::make_shared(getptr(), name, getVerbosity(), _level, _callback); @@ -142,18 +141,16 @@ _callback(callback) { } -Logger::Logger(EntryLogger callback, boost::optional name) : +Logger::Logger(EntryLogger callback, std::optional name) : _callback(callback), _name(std::move(name)) { } -Logger::Logger(std::shared_ptr parent, boost::optional name, size_t verbosity, size_t lvl, EntryLogger callback) : +Logger::Logger(std::shared_ptr parent, std::optional name, size_t verbosity, size_t lvl, EntryLogger callback) : _parent(std::move(parent)), _callback(callback), _name(std::move(name)), _level(lvl), _verbosity(verbosity) { } -Logger::~Logger() -{ -} +Logger::~Logger() = default; }; std::shared_ptr g_slog{nullptr}; @@ -164,10 +161,9 @@ if (format != "%s") { // strftime is not thread safe, it can access locale information static std::mutex mutex; - auto lock = std::lock_guard(mutex); + auto lock = std::scoped_lock(mutex); struct tm theTime // clang-format insists on formatting it like this - { - }; + {}; len = strftime(buf.data(), buf.size(), format.c_str(), localtime_r(&tval.tv_sec, &theTime)); } if (len == 0) { diff -Nru pdns-recursor-5.2.13/logging.hh pdns-recursor-5.4.9/logging.hh --- pdns-recursor-5.2.13/logging.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/logging.hh 2026-10-26 09:46:36.000000000 +0000 @@ -24,13 +24,12 @@ #include "config.h" -#ifdef RECURSOR +#if defined(RECURSOR) || defined(DNSDIST) #include #include #include #include -#include #include "logr.hh" #include "dnsname.hh" @@ -41,9 +40,9 @@ struct Entry { - boost::optional name; // name parts joined with '.' + std::optional name; // name parts joined with '.' std::string message; // message as send to log call - boost::optional error; // error if .Error() was called + std::optional error; // error if .Error() was called struct timeval d_timestamp; // time of entry generation std::map values; // key-value pairs size_t level; // level at which this was logged @@ -53,7 +52,7 @@ // Warning: some meta-programming is going on. We define helper // templates that can be used to see if specific string output // functions are available. If so, we use those instead of << into an -// ostringstream. Note that this decision happpens compile time. +// ostringstream. Note that this decision happens compile time. // Some hints taken from https://www.cppstories.com/2019/07/detect-overload-from-chars/ // (I could not get function templates with enabled_if<> to work in this case) // @@ -161,7 +160,7 @@ } }; -typedef void (*EntryLogger)(const Entry&); +using EntryLogger = void (*)(const Entry&); class Logger : public Logr::Logger, public std::enable_shared_from_this { @@ -177,27 +176,27 @@ std::shared_ptr v(size_t level) const override; std::shared_ptr withValues(const std::map& values) const override; - virtual std::shared_ptr withName(const std::string& name) const override; + std::shared_ptr withName(const std::string& name) const override; static std::shared_ptr create(EntryLogger callback); static std::shared_ptr create(EntryLogger callback, const std::string& name); Logger(EntryLogger callback); - Logger(EntryLogger callback, boost::optional name); - Logger(std::shared_ptr parent, boost::optional name, size_t verbosity, size_t lvl, EntryLogger callback); - virtual ~Logger(); + Logger(EntryLogger callback, std::optional name); + Logger(std::shared_ptr parent, std::optional name, size_t verbosity, size_t lvl, EntryLogger callback); + ~Logger() override; size_t getVerbosity() const; void setVerbosity(size_t verbosity); private: - void logMessage(const std::string& msg, boost::optional err) const; - void logMessage(const std::string& msg, Logr::Priority p, boost::optional err) const; + void logMessage(const std::string& msg, const std::optional& err) const; + void logMessage(const std::string& msg, Logr::Priority prio, const std::optional& err) const; std::shared_ptr getptr() const; std::shared_ptr _parent{nullptr}; EntryLogger _callback; - boost::optional _name; + std::optional _name; std::map _values; // current Logger's level. the higher the more verbose. size_t _level{0}; @@ -206,6 +205,7 @@ }; } +#if !defined(DNSDIST) extern std::shared_ptr g_slog; // Prefer structured logging? Since Recursor 5.1.0, we always do. We keep a const, to allow for @@ -225,10 +225,40 @@ slogCall; \ } while (0) -#else // No structured logging (e.g. auth) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERBOSESLOG(nonStructured, structured) + +#else // DNSdist +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SLOG(nonStructured, structured) \ + do { \ + if (dnsdist::logging::doStructuredLogging()) { \ + structured; \ + } \ + else { \ + nonStructured; \ + } \ + } while (0) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERBOSESLOG(nonStructured, structured) \ + do { \ + if (dnsdist::logging::doVerboseLogging()) { \ + SLOG(nonStructured, structured); \ + } \ + } while (0) + +#endif /* ! DNSDIST */ + +#else // !RECURSOR && !DNSDIST + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SLOG(oldStyle, slogCall) \ do { \ oldStyle; \ } while (0) -#endif // RECURSOR + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERBOSESLOG(nonStructured, structured) + +#endif // !RECURSOR && !DNSDIST diff -Nru pdns-recursor-5.2.13/logr.hh pdns-recursor-5.4.9/logr.hh --- pdns-recursor-5.2.13/logr.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/logr.hh 2026-10-26 09:46:36.000000000 +0000 @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include #include @@ -33,7 +34,13 @@ { struct Loggable { - virtual std::string to_string() const = 0; + Loggable() = default; + Loggable(const Loggable&) = delete; + Loggable(Loggable&&) = delete; + Loggable& operator=(const Loggable&) = delete; + Loggable& operator=(Loggable&&) = delete; + virtual ~Loggable() = default; + [[nodiscard]] virtual std::string to_string() const = 0; }; // In addition to level which specifies the amount of detail and is @@ -60,19 +67,26 @@ class Logger { public: + Logger() = default; + Logger(const Logger&) = delete; + Logger(Logger&&) = delete; + Logger& operator=(const Logger&) = delete; + Logger& operator=(Logger&&) = delete; + virtual ~Logger() = default; + // Enabled tests whether this Logger is enabled. For example, commandline // flags might be used to set the logging verbosity and disable some info // logs. - virtual bool enabled(Priority) const = 0; + [[nodiscard]] virtual bool enabled(Priority) const = 0; static std::string toString(Priority arg) { const std::array names = {"Absent", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"}; - auto p = static_cast(arg); - if (p >= names.size()) { + auto prio = static_cast(arg); + if (prio >= names.size()) { return "?"; } - return names.at(p); + return names.at(prio); } // Info logs a non-error message with the given key/value pairs as context. // @@ -91,10 +105,10 @@ } template - void info(Priority p, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const + void info(Priority prio, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const { auto logger = this->withValues(key, value, args...); - logger->info(p, msg); + logger->info(prio, msg); } // Error logs an error, with the given message and key/value pairs as context. @@ -125,24 +139,24 @@ } template - void error(Priority p, const std::string& err, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const + void error(Priority prio, const std::string& err, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const { auto logger = this->withValues(key, value, args...); - logger->error(p, err, msg); + logger->error(prio, err, msg); } template - void error(Priority p, int err, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const + void error(Priority prio, int err, const std::string& msg, const std::string& key, const Loggable& value, const Args&... args) const { auto logger = this->withValues(key, value, args...); - logger->error(p, err, msg); + logger->error(prio, err, msg); } // V returns an Logger value for a specific verbosity level, relative to // this Logger. In other words, V values are additive. V higher verbosity // level means a log message is less important. It's illegal to pass a log // level less than zero. - virtual std::shared_ptr v(size_t level) const = 0; + [[nodiscard]] virtual std::shared_ptr v(size_t level) const = 0; template std::shared_ptr withValues(const std::string& key, const Loggable& value, const Args&... args) const @@ -154,14 +168,14 @@ // WithValues adds some key-value pairs of context to a logger. // See Info for documentation on how key/value pairs work. - virtual std::shared_ptr withValues(const std::map& values) const = 0; + [[nodiscard]] virtual std::shared_ptr withValues(const std::map& values) const = 0; // WithName adds a new element to the logger's name. // Successive calls with WithName continue to append // suffixes to the logger's name. It's strongly recommended // that name segments contain only letters, digits, and hyphens // (see the package documentation for more information). - virtual std::shared_ptr withName(const std::string& name) const = 0; + [[nodiscard]] virtual std::shared_ptr withName(const std::string& name) const = 0; private: template diff -Nru pdns-recursor-5.2.13/lua-base4.cc pdns-recursor-5.4.9/lua-base4.cc --- pdns-recursor-5.2.13/lua-base4.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lua-base4.cc 2026-10-26 09:46:36.000000000 +0000 @@ -52,7 +52,7 @@ 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); + throw PDNSException(std::move(msg)); } vec.emplace_back(fullName); } @@ -63,7 +63,7 @@ int err = errno; string msg = directory + " is not accessible: " + stringerror(err); g_log << Logger::Error << msg << std::endl; - throw PDNSException(msg); + throw PDNSException(std::move(msg)); } std::sort(vec.begin(), vec.end(), CIStringComparePOSIX()); @@ -102,9 +102,9 @@ // DNSName d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); }); d_lw->registerFunction("__lt", &DNSName::operator<); - d_lw->registerFunction("canonCompare", &DNSName::canonCompare); - d_lw->registerFunction("makeRelative", &DNSName::makeRelative); - d_lw->registerFunction("isPartOf", &DNSName::isPartOf); + d_lw->registerFunction("canonCompare", [](const DNSName& name, const DNSName& rhs) { return name.canonCompare(rhs); }); + d_lw->registerFunction("makeRelative", [](const DNSName& name, const DNSName& zone) { return name.makeRelative(zone); }); + d_lw->registerFunction("isPartOf", [](const DNSName& name, const DNSName& rhs) { return name.isPartOf(rhs); }); d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels); d_lw->registerFunction("countLabels", [](const DNSName& name) { return name.countLabels(); }); d_lw->registerFunction("wireLength", [](const DNSName& name) { return name.wirelength(); }); @@ -147,22 +147,16 @@ d_lw->registerFunction("disabled", [](DNSResourceRecord& rec) { return rec.disabled; }); // ComboAddress - d_lw->registerFunction("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; }); - d_lw->registerFunction("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; }); - d_lw->registerFunction("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); - d_lw->registerFunction("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); }); - d_lw->registerFunction("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); }); - d_lw->registerFunction("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); }); - d_lw->registerFunction("toString", [](const ComboAddress& ca) { return ca.toString(); }); - d_lw->registerToStringFunction([](const ComboAddress& ca) { return ca.toString(); }); - d_lw->registerFunction("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); - d_lw->registerFunction("getRaw", [](const ComboAddress& ca) { - if(ca.sin4.sin_family == AF_INET) { - auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4); - } - else - return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16); - } ); + d_lw->registerFunction("isIPv4", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET; }); + d_lw->registerFunction("isIPv6", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET6; }); + d_lw->registerFunction("getPort", [](const ComboAddress& addr) { return ntohs(addr.sin4.sin_port); } ); + d_lw->registerFunction("isMappedIPv4", [](const ComboAddress& addr) { return addr.isMappedIPv4(); }); + d_lw->registerFunction("mapToIPv4", [](const ComboAddress& addr) { return addr.mapToIPv4(); }); + d_lw->registerFunction("truncate", [](ComboAddress& addr, unsigned int bits) { addr.truncate(bits); }); + d_lw->registerFunction("toString", [](const ComboAddress& addr) { return addr.toString(); }); + d_lw->registerToStringFunction([](const ComboAddress& addr) { return addr.toString(); }); + d_lw->registerFunction("toStringWithPort", [](const ComboAddress& addr) { return addr.toStringWithPort(); }); + d_lw->registerFunction("getRaw", [](const ComboAddress& addr) { return addr.toByteString(); }); d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); }); d_lw->writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional port) { diff -Nru pdns-recursor-5.2.13/lua-base4.hh pdns-recursor-5.4.9/lua-base4.hh --- pdns-recursor-5.2.13/lua-base4.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lua-base4.hh 2026-10-26 09:46:36.000000000 +0000 @@ -1,6 +1,7 @@ #pragma once #include "namespaces.hh" #include +#include #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -13,7 +14,8 @@ std::string d_include_path; // path where scripts to include at postLoad are public: - BaseLua4(const std::string &includePath) : d_include_path(includePath) {}; + BaseLua4(std::string includePath) : + d_include_path(std::move(includePath)) {}; void loadFile(const std::string &fname, bool doPostLoad=true); void loadString(const std::string &script); void loadStream(std::istream &stream, bool doPostLoad=true); diff -Nru pdns-recursor-5.2.13/lua-recursor4.cc pdns-recursor-5.4.9/lua-recursor4.cc --- pdns-recursor-5.2.13/lua-recursor4.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lua-recursor4.cc 2026-10-26 08:26:51.000000000 +0000 @@ -35,7 +35,7 @@ #include "rec-main.hh" #include "arguments.hh" -boost::optional RecursorLua4::DNSQuestion::getDH() const +std::optional RecursorLua4::DNSQuestion::getDH() const { if (dh != nullptr) { return *dh; @@ -72,7 +72,7 @@ return {}; } -boost::optional RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const +std::optional RecursorLua4::DNSQuestion::getEDNSOption(uint16_t code) const { if (ednsOptions != nullptr) { for (const auto& option : *ednsOptions) { @@ -84,14 +84,14 @@ return {}; } -boost::optional RecursorLua4::DNSQuestion::getEDNSSubnet() const +std::optional RecursorLua4::DNSQuestion::getEDNSSubnet() const { if (ednsOptions != nullptr) { for (const auto& option : *ednsOptions) { if (option.first == EDNSOptionCode::ECS) { EDNSSubnetOpts eso; - if (getEDNSSubnetOptsFromString(option.second, &eso)) { - return eso.source; + if (EDNSSubnetOpts::getFromString(option.second, &eso)) { + return eso.getSource(); } break; } @@ -132,18 +132,18 @@ } } -void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional ttl, boost::optional name) +void RecursorLua4::DNSQuestion::addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, std::optional ttl, std::optional name) { DNSRecord dnsRecord; dnsRecord.d_name = name ? DNSName(*name) : qname; - dnsRecord.d_ttl = ttl.get_value_or(3600); + dnsRecord.d_ttl = ttl.value_or(3600); dnsRecord.d_type = type; dnsRecord.d_place = place; dnsRecord.setContent(DNSRecordContent::make(type, QClass::IN, content)); - records.push_back(dnsRecord); + records.push_back(std::move(dnsRecord)); } -void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, boost::optional ttl, boost::optional name) +void RecursorLua4::DNSQuestion::addAnswer(uint16_t type, const std::string& content, std::optional ttl, std::optional name) { addRecord(type, content, DNSResourceRecord::ANSWER, ttl, std::move(name)); } @@ -163,7 +163,7 @@ { d_lw->registerMember("qname", [](const DNSQuestion& dnsQuestion) -> const DNSName& { return dnsQuestion.qname; }, [](DNSQuestion& /* dnsQuestion */, const DNSName& newName) { (void) newName; }); d_lw->registerMember("qtype", [](const DNSQuestion& dnsQuestion) -> uint16_t { return dnsQuestion.qtype; }, [](DNSQuestion& /* dnsQuestion */, uint16_t newType) { (void) newType; }); - d_lw->registerMember("isTcp", [](const DNSQuestion& dnsQuestion) -> bool { return dnsQuestion.isTcp; }, [](DNSQuestion& /* dnsQuestion */, bool newTcp) { (void) newTcp; }); + d_lw->registerMember("isTcp", [](const DNSQuestion& dnsQuestion) -> bool { return dnsQuestion.isTcp; }, [](DNSQuestion& dnsQuestion, bool newTcp) { dnsQuestion.isTcp = newTcp; }); d_lw->registerMember("localaddr", [](const DNSQuestion& dnsQuestion) -> const ComboAddress& { return dnsQuestion.local; }, [](DNSQuestion& /* dnsQuestion */, const ComboAddress& newLocal) { (void) newLocal; }); d_lw->registerMember("remoteaddr", [](const DNSQuestion& dnsQuestion) -> const ComboAddress& { return dnsQuestion.remote; }, [](DNSQuestion& /* dnsQuestion */, const ComboAddress& newRemote) { (void) newRemote; }); d_lw->registerMember("interface_localaddr", [](const DNSQuestion& dnsQuestion) -> const ComboAddress& { return dnsQuestion.interface_local; }, [](DNSQuestion& /* dnsQuestion */, const ComboAddress& newLocal) { (void) newLocal; }); @@ -304,8 +304,8 @@ return std::string(option.values.at(0).content, option.values.at(0).size); }); d_lw->registerFunction("getContent", [](const DNSRecord& dnsRecord) { return dnsRecord.getContent()->getZoneRepresentation(); }); - d_lw->registerFunction(DNSRecord::*)()>("getCA", [](const DNSRecord& dnsRecord) { - boost::optional ret; + d_lw->registerFunction(DNSRecord::*)()>("getCA", [](const DNSRecord& dnsRecord) { + std::optional ret; if (auto rec = getRR(dnsRecord)) { ret = rec->getCA(53); @@ -371,8 +371,7 @@ } } catch(std::exception& e) { - SLOG(g_log <withName("lua")->error(Logr::Error, e.what(), "Error in call to DNSSuffixMatchGroup:add")); + g_slog->withName("lua")->error(Logr::Error, e.what(), "Error in call to DNSSuffixMatchGroup:add"); } } ); @@ -380,29 +379,29 @@ d_lw->registerFunction("check",(bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check); d_lw->registerFunction("toString",(string (SuffixMatchNode::*)() const) &SuffixMatchNode::toString); - d_pd.push_back({"policykinds", in_t { + d_pd.emplace_back("policykinds", in_t { {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction}, {"Drop", (int)DNSFilterEngine::PolicyKind::Drop }, {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN}, {"NODATA", (int)DNSFilterEngine::PolicyKind::NODATA }, {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate}, {"Custom", (int)DNSFilterEngine::PolicyKind::Custom } - }}); + }); - d_pd.push_back({"policytypes", in_t { + d_pd.emplace_back("policytypes", in_t { {"None", (int)DNSFilterEngine::PolicyType::None }, {"QName", (int)DNSFilterEngine::PolicyType::QName }, {"ClientIP", (int)DNSFilterEngine::PolicyType::ClientIP }, {"ResponseIP", (int)DNSFilterEngine::PolicyType::ResponseIP }, {"NSDName", (int)DNSFilterEngine::PolicyType::NSDName }, {"NSIP", (int)DNSFilterEngine::PolicyType::NSIP } - }}); + }); for(const auto& name : QType::names) { d_pd.emplace_back(name.first, name.second); } - d_pd.push_back({"validationstates", in_t{ + d_pd.emplace_back("validationstates", in_t{ {"Indeterminate", static_cast(vState::Indeterminate) }, {"BogusNoValidDNSKEY", static_cast(vState::BogusNoValidDNSKEY) }, {"BogusInvalidDenial", static_cast(vState::BogusInvalidDenial) }, @@ -423,7 +422,7 @@ {"Secure", static_cast(vState::Secure) }, /* in order not to break compatibility with older scripts: */ {"Bogus", static_cast(255) }, - }}); + }); d_lw->writeFunction("isValidationStateBogus", [](vState state) { return vStateIsBogus(state); @@ -431,8 +430,25 @@ d_pd.emplace_back("now", &g_now); - d_lw->writeFunction("getMetric", [](const std::string& str, boost::optional prometheusName) { - return DynMetric{getDynMetric(str, prometheusName ? *prometheusName : "")}; + d_lw->writeFunction("getMetric", [](const std::string& str, std::optional>> opts){ + std::string prometheusName; + std::string prometheusTypeName; + std::string prometheusDescr; + + if (opts) { + if (const auto* optPrometheusName = boost::get(&*opts); optPrometheusName != nullptr) { + prometheusName = *optPrometheusName; + } else if (auto* vars = boost::get>(&*opts); vars != nullptr) { + prometheusName = (*vars)["prometheusName"]; + prometheusTypeName = (*vars)["type"]; + prometheusDescr = (*vars)["description"]; + } + } + + if (prometheusDescr.empty()) { + prometheusDescr = "N/A"; + } + return DynMetric{getDynMetric(str, prometheusName, prometheusTypeName, prometheusDescr)}; }); d_lw->registerFunction("inc", &DynMetric::inc); @@ -450,7 +466,7 @@ }); d_lw->writeFunction("getRecursorThreadId", []() { - return RecThreadInfo::id(); + return RecThreadInfo::thread_local_id(); }); d_lw->writeFunction("sendCustomSNMPTrap", [](const std::string& str) { @@ -523,6 +539,15 @@ return {dir, name}; }); + d_lw->writeFunction("getNSSpeedTable", [](size_t maxSize) { + std::string ret; + auto number = SyncRes::getNSSpeedTable(maxSize, ret); + return std::tuple{ret, number}; + }); + + d_lw->writeFunction("putIntoNSSpeedTable", [](const string& data) { + return SyncRes::putIntoNSSpeedTable(data); + }); if (!d_include_path.empty()) { includePath(d_include_path); @@ -533,20 +558,20 @@ void RecursorLua4::postLoad() { - d_prerpz = d_lw->readVariable>("prerpz").get_value_or(nullptr); - d_preresolve = d_lw->readVariable>("preresolve").get_value_or(nullptr); - d_nodata = d_lw->readVariable>("nodata").get_value_or(nullptr); - d_nxdomain = d_lw->readVariable>("nxdomain").get_value_or(nullptr); - d_postresolve = d_lw->readVariable>("postresolve").get_value_or(nullptr); - d_preoutquery = d_lw->readVariable>("preoutquery").get_value_or(nullptr); - d_maintenance = d_lw->readVariable>("maintenance").get_value_or(nullptr); - - d_ipfilter = d_lw->readVariable>("ipfilter").get_value_or(nullptr); - d_gettag = d_lw->readVariable>("gettag").get_value_or(nullptr); - d_gettag_ffi = d_lw->readVariable>("gettag_ffi").get_value_or(nullptr); - d_postresolve_ffi = d_lw->readVariable>("postresolve_ffi").get_value_or(nullptr); + d_prerpz = d_lw->readVariable>("prerpz").value_or(nullptr); + d_preresolve = d_lw->readVariable>("preresolve").value_or(nullptr); + d_nodata = d_lw->readVariable>("nodata").value_or(nullptr); + d_nxdomain = d_lw->readVariable>("nxdomain").value_or(nullptr); + d_postresolve = d_lw->readVariable>("postresolve").value_or(nullptr); + d_preoutquery = d_lw->readVariable>("preoutquery").value_or(nullptr); + d_maintenance = d_lw->readVariable>("maintenance").value_or(nullptr); + + d_ipfilter = d_lw->readVariable>("ipfilter").value_or(nullptr); + d_gettag = d_lw->readVariable>("gettag").value_or(nullptr); + d_gettag_ffi = d_lw->readVariable>("gettag_ffi").value_or(nullptr); + d_postresolve_ffi = d_lw->readVariable>("postresolve_ffi").value_or(nullptr); - d_policyHitEventFilter = d_lw->readVariable>("policyEventFilter").get_value_or(nullptr); + d_policyHitEventFilter = d_lw->readVariable>("policyEventFilter").value_or(nullptr); } void RecursorLua4::getFeatures(Features& features) @@ -564,7 +589,7 @@ auto mylog = log->withValues("script", Logging::Loggable(script), "function", Logging::Loggable(func)); loadFile(script); // coverity[auto_causes_copy] does not work with &, despite what coverity thinks - const auto call = d_lw->readVariable>>(func).get_value_or(nullptr); + const auto call = d_lw->readVariable>>(func).value_or(nullptr); if (call) { mylog->info(Logr::Info, "Starting Lua function"); call(); @@ -578,8 +603,7 @@ static void warnDrop(const RecursorLua4::DNSQuestion& dnsQuestion) { if (dnsQuestion.rcode == -2) { - SLOG(g_log << Logger::Error << "Returning -2 (pdns.DROP) is not supported anymore, see https://docs.powerdns.com/recursor/lua-scripting/hooks.html#hooksemantics" << endl, - g_slog->withName("lua")->info(Logr::Error, "Returning -2 (pdns.DROP) is not supported anymore, see https://docs.powerdns.com/recursor/lua-scripting/hooks.html#hooksemantics")); + g_slog->withName("lua")->info(Logr::Error, "Returning -2 (pdns.DROP) is not supported anymore, see https://docs.powerdns.com/recursor/lua-scripting/hooks.html#hooksemantics"); // We *could* set policy here, but that would also mean interfering with rcode and the return code of the hook. // So leave it at the error message. } @@ -597,9 +621,9 @@ if (!d_prerpz) { return false; } - eventTrace.add(RecEventTrace::LuaPreRPZ); + auto match = eventTrace.add(RecEventTrace::LuaPreRPZ); bool isOK = genhook(d_prerpz, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaPreRPZ, isOK, false); + eventTrace.add(RecEventTrace::LuaPreRPZ, isOK, false, match); warnDrop(dnsQuestion); return isOK; } @@ -609,9 +633,9 @@ if (!d_preresolve) { return false; } - eventTrace.add(RecEventTrace::LuaPreResolve); + auto match = eventTrace.add(RecEventTrace::LuaPreResolve); bool isOK = genhook(d_preresolve, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaPreResolve, isOK, false); + eventTrace.add(RecEventTrace::LuaPreResolve, isOK, false, match); warnDrop(dnsQuestion); return isOK; } @@ -621,9 +645,9 @@ if (!d_nxdomain) { return false; } - eventTrace.add(RecEventTrace::LuaNXDomain); + auto match = eventTrace.add(RecEventTrace::LuaNXDomain); bool isOK = genhook(d_nxdomain, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaNXDomain, isOK, false); + eventTrace.add(RecEventTrace::LuaNXDomain, isOK, false, match); warnDrop(dnsQuestion); return isOK; } @@ -633,9 +657,9 @@ if (!d_nodata) { return false; } - eventTrace.add(RecEventTrace::LuaNoData); + auto match = eventTrace.add(RecEventTrace::LuaNoData); bool isOK = genhook(d_nodata, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaNoData, isOK, false); + eventTrace.add(RecEventTrace::LuaNoData, isOK, false, match); warnDrop(dnsQuestion); return isOK; } @@ -645,14 +669,14 @@ if (!d_postresolve) { return false; } - eventTrace.add(RecEventTrace::LuaPostResolve); + auto match = eventTrace.add(RecEventTrace::LuaPostResolve); bool isOK = genhook(d_postresolve, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaPostResolve, isOK, false); + eventTrace.add(RecEventTrace::LuaPostResolve, isOK, false, match); warnDrop(dnsQuestion); return isOK; } -bool RecursorLua4::preoutquery(const ComboAddress& nameserver, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector& res, int& ret, RecEventTrace& eventTrace, const struct timeval& theTime) const +bool RecursorLua4::preoutquery(const ComboAddress& nameserver, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool& isTcp, vector& res, int& ret, RecEventTrace& eventTrace, const struct timeval& theTime) const { if (!d_preoutquery) { return false; @@ -663,10 +687,13 @@ bool addPaddingToResponse = false; RecursorLua4::DNSQuestion dnsQuestion(nameserver, requestor, nameserver, requestor, query, qtype.getCode(), isTcp, variableAnswer, wantsRPZ, logQuery, addPaddingToResponse, theTime); dnsQuestion.currentRecords = &res; - eventTrace.add(RecEventTrace::LuaPreOutQuery); + auto match = eventTrace.add(RecEventTrace::LuaPreOutQuery); bool isOK = genhook(d_preoutquery, dnsQuestion, ret); - eventTrace.add(RecEventTrace::LuaPreOutQuery, isOK, false); + eventTrace.add(RecEventTrace::LuaPreOutQuery, isOK, false, match); warnDrop(dnsQuestion); + + isTcp = dnsQuestion.isTcp; + return isOK; } @@ -675,9 +702,9 @@ if (!d_ipfilter) { return false; // Do not block } - eventTrace.add(RecEventTrace::LuaIPFilter); + auto match = eventTrace.add(RecEventTrace::LuaIPFilter); bool isOK = d_ipfilter(remote, local, header); - eventTrace.add(RecEventTrace::LuaIPFilter, isOK, false); + eventTrace.add(RecEventTrace::LuaIPFilter, isOK, false, match); return isOK; } @@ -823,10 +850,9 @@ PacketBuffer packetBuffer = GenUDPQueryResponse(dnsQuestion.udpQueryDest, dnsQuestion.udpQuery); dnsQuestion.udpAnswer = std::string(reinterpret_cast(packetBuffer.data()), packetBuffer.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) // coverity[auto_causes_copy] not copying produces a dangling ref - const auto cbFunc = d_lw->readVariable>(dnsQuestion.udpCallback).get_value_or(nullptr); + const auto cbFunc = d_lw->readVariable>(dnsQuestion.udpCallback).value_or(nullptr); if (!cbFunc) { - SLOG(g_log << Logger::Error << "Attempted callback for Lua UDP Query/Response which could not be found" << endl, - g_slog->withName("lua")->info(Logr::Error, "Attempted callback for Lua UDP Query/Response which could not be found")); + g_slog->withName("lua")->info(Logr::Error, "Attempted callback for Lua UDP Query/Response which could not be found"); return false; } bool result = cbFunc(&dnsQuestion); @@ -1344,5 +1370,5 @@ void pdns_postresolve_ffi_handle_get_authip_raw(pdns_postresolve_ffi_handle_t* ref, const void** addr, size_t* addrSize) { - return pdns_ffi_comboaddress_to_raw(*ref->getHandle().d_dq.fromAuthIP, addr, addrSize); + pdns_ffi_comboaddress_to_raw(*ref->getHandle().d_dq.fromAuthIP, addr, addrSize); } diff -Nru pdns-recursor-5.2.13/lua-recursor4.hh pdns-recursor-5.4.9/lua-recursor4.hh --- pdns-recursor-5.2.13/lua-recursor4.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lua-recursor4.hh 2026-10-26 08:26:51.000000000 +0000 @@ -21,20 +21,16 @@ */ #pragma once -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include "iputils.hh" #include "dnsname.hh" #include "namespaces.hh" -#include "dnsrecords.hh" #include "filterpo.hh" #include "ednsoptions.hh" #include "validate.hh" #include "lua-base4.hh" #include "proxy-protocol.hh" -#include "noinitvector.hh" #include "rec-eventtrace.hh" #include @@ -110,7 +106,7 @@ const std::vector* proxyProtocolValues{nullptr}; std::unordered_map* discardedPolicies{nullptr}; std::string* extendedErrorExtra{nullptr}; - boost::optional* extendedErrorCode{nullptr}; + std::optional* extendedErrorCode{nullptr}; std::string requestorId; std::string deviceId; std::string deviceName; @@ -137,16 +133,16 @@ unsigned int tag{0}; int rcode{0}; const uint16_t qtype; - const bool isTcp; + bool isTcp; vState validationState{vState::Indeterminate}; - void addAnswer(uint16_t type, const std::string& content, boost::optional ttl, boost::optional name); - void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional ttl, boost::optional name); + void addAnswer(uint16_t type, const std::string& content, std::optional ttl, std::optional name); + void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, std::optional ttl, std::optional name); [[nodiscard]] vector> getRecords() const; - [[nodiscard]] boost::optional getDH() const; + [[nodiscard]] std::optional getDH() const; [[nodiscard]] vector> getEDNSOptions() const; - [[nodiscard]] boost::optional getEDNSOption(uint16_t code) const; - [[nodiscard]] boost::optional getEDNSSubnet() const; + [[nodiscard]] std::optional getEDNSOption(uint16_t code) const; + [[nodiscard]] std::optional getEDNSSubnet() const; [[nodiscard]] std::vector> getProxyProtocolValues() const; [[nodiscard]] vector getEDNSFlags() const; [[nodiscard]] bool getEDNSFlag(const string& flag) const; @@ -172,7 +168,7 @@ { public: // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - FFIParams(const DNSName& qname_, uint16_t qtype_, const ComboAddress& plocal_, const ComboAddress& premote_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, LuaContext::LuaObject& data_, std::unordered_set& policyTags_, std::vector& records_, const EDNSOptionViewMap& ednsOptions_, const std::vector& proxyProtocolValues_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, std::string& routingTag_, boost::optional& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& logResponse_, bool& followCNAMERecords_, boost::optional& extendedErrorCode_, std::string& extendedErrorExtra_, bool& disablePadding_, std::map& meta_) : + FFIParams(const DNSName& qname_, uint16_t qtype_, const ComboAddress& plocal_, const ComboAddress& premote_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, LuaContext::LuaObject& data_, std::unordered_set& policyTags_, std::vector& records_, const EDNSOptionViewMap& ednsOptions_, const std::vector& proxyProtocolValues_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, std::string& routingTag_, std::optional& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& logResponse_, bool& followCNAMERecords_, std::optional& extendedErrorCode_, std::string& extendedErrorExtra_, bool& disablePadding_, std::map& meta_) : data(data_), qname(qname_), interface_local(plocal_), interface_remote(premote_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), records(records_), ednsOptions(ednsOptions_), proxyProtocolValues(proxyProtocolValues_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), routingTag(routingTag_), extendedErrorExtra(extendedErrorExtra_), rcode(rcode_), extendedErrorCode(extendedErrorCode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), logResponse(logResponse_), followCNAMERecords(followCNAMERecords_), disablePadding(disablePadding_), qtype(qtype_), tcp(tcp_), meta(meta_) { } @@ -193,8 +189,8 @@ std::string& deviceName; std::string& routingTag; std::string& extendedErrorExtra; - boost::optional& rcode; - boost::optional& extendedErrorCode; + std::optional& rcode; + std::optional& extendedErrorCode; uint32_t& ttlCap; bool& variable; bool& logQuery; @@ -219,7 +215,7 @@ bool nodata(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const; bool postresolve(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const; - bool preoutquery(const ComboAddress& nameserver, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector& res, int& ret, RecEventTrace& eventTrace, const struct timeval& theTime) const; + bool preoutquery(const ComboAddress& nameserver, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool& isTcp, vector& res, int& ret, RecEventTrace& eventTrace, const struct timeval& theTime) const; bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&, RecEventTrace&) const; bool policyHitEventFilter(const ComboAddress& remote, const DNSName& qname, const QType& qtype, bool tcp, DNSFilterEngine::Policy& policy, std::unordered_set& tags, std::unordered_map& discardedPolicies) const; @@ -261,10 +257,10 @@ void getFeatures(Features& features) override; private: - using gettag_t = std::function>, boost::optional, boost::optional, boost::optional, boost::optional, boost::optional>(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool, const std::vector>&)>; + using gettag_t = std::function>, std::optional, std::optional, std::optional, std::optional, std::optional>(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool, const std::vector>&)>; gettag_t d_gettag; // public so you can query if we have this hooked - using gettag_ffi_t = std::function(pdns_ffi_param_t*)>; + using gettag_ffi_t = std::function(pdns_ffi_param_t*)>; gettag_ffi_t d_gettag_ffi; using postresolve_ffi_t = std::function; diff -Nru pdns-recursor-5.2.13/lwres.cc pdns-recursor-5.4.9/lwres.cc --- pdns-recursor-5.2.13/lwres.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lwres.cc 2026-10-26 08:26:51.000000000 +0000 @@ -54,12 +54,100 @@ #include "rec-protozero.hh" #include "uuid-utils.hh" #include "rec-tcpout.hh" +#include "rec-cookiestore.hh" + +static bool g_cookies = false; + +std::string enableOutgoingCookies(bool flag, const string& unsupported) +{ + g_cookies = flag; + if (g_cookies) { + std::vector parts; + stringtok(parts, unsupported, ", "); + std::string errors; + addCookiesUnsupported(parts.begin(), parts.end(), errors); + return errors; + } + return {}; +} thread_local TCPOutConnectionManager t_tcp_manager; std::shared_ptr g_slogout; bool g_paddingOutgoing; bool g_ECSHardening; +static LockGuarded s_cookiestore; + +uint64_t addCookiesUnsupported(vector::iterator begin, vector::iterator end, string& errors) +{ + auto lock = s_cookiestore.lock(); + uint64_t count = 0; + while (begin != end) { + try { + CookieEntry entry; + entry.d_address = ComboAddress(*begin, 53); + entry.setSupport(CookieEntry::Support::Unsupported, std::numeric_limits::max()); + auto [iter, inserted] = lock->insert(entry); + if (!inserted) { + lock->replace(iter, entry); + } + ++count; + } + catch (const PDNSException& error) { + if (!errors.empty()) { + errors += ", "; + } + errors += error.reason; + } + ++begin; + } + return count; +} + +uint64_t clearCookies(vector::iterator begin, vector::iterator end, string& errors) +{ + auto lock = s_cookiestore.lock(); + uint64_t count = 0; + if (begin == end) { + return 0; + } + if (*begin == "*") { + count = lock->size(); + lock->clear(); + } + else { + while (begin != end) { + try { + count += lock->erase(ComboAddress(*begin, 53)); + } + catch (const PDNSException& error) { + if (!errors.empty()) { + errors += ", "; + } + errors += error.reason; + } + ++begin; + } + } + return count; +} + +void pruneCookies(time_t cutoff) +{ + auto lock = s_cookiestore.lock(); + lock->prune(cutoff); +} + +uint64_t dumpCookies(int fileDesc) +{ + CookieStore copy; + { + auto lock = s_cookiestore.lock(); + copy = *lock; + } + return copy.dump(fileDesc); +} + void remoteLoggerQueueData(RemoteLoggerInterface& rli, const std::string& data) { auto ret = rli.queueData(data); @@ -69,27 +157,25 @@ break; case RemoteLoggerInterface::Result::PipeFull: { const auto& msg = RemoteLoggerInterface::toErrorString(ret); - SLOG(g_log << Logger::Debug << rli.name() << ": " << msg << std::endl, - g_slog->withName(rli.name())->info(Logr::Debug, msg)); + g_slog->withName(rli.name())->info(Logr::Debug, msg); break; } case RemoteLoggerInterface::Result::TooLarge: { const auto& msg = RemoteLoggerInterface::toErrorString(ret); - SLOG(g_log << Logger::Notice << rli.name() << ": " << msg << endl, - g_slog->withName(rli.name())->info(Logr::Debug, msg)); + g_slog->withName(rli.name())->info(Logr::Debug, msg); break; } case RemoteLoggerInterface::Result::OtherError: { const auto& msg = RemoteLoggerInterface::toErrorString(ret); - SLOG(g_log << Logger::Warning << rli.name() << ": " << msg << std::endl, - g_slog->withName(rli.name())->info(Logr::Warning, msg)); + g_slog->withName(rli.name())->info(Logr::Warning, msg); break; } } } -#ifdef HAVE_FSTRM #include "dnstap.hh" + +#ifdef HAVE_FSTRM #include "fstrm_logger.hh" static bool isEnabledForQueries(const std::shared_ptr>>& fstreamLoggers) @@ -105,7 +191,7 @@ return false; } -static void logFstreamQuery(const std::shared_ptr>>& fstreamLoggers, const struct timeval& queryTime, const ComboAddress& localip, const ComboAddress& address, DnstapMessage::ProtocolType protocol, const boost::optional& auth, const vector& packet) +static void logFstreamQuery(const std::shared_ptr>>& fstreamLoggers, const struct timeval& queryTime, const ComboAddress& localip, const ComboAddress& address, DnstapMessage::ProtocolType protocol, const DNSName& auth, const vector& packet) { if (fstreamLoggers == nullptr) return; @@ -135,7 +221,7 @@ return false; } -static void logFstreamResponse(const std::shared_ptr>>& fstreamLoggers, const ComboAddress& localip, const ComboAddress& address, DnstapMessage::ProtocolType protocol, const boost::optional& auth, const PacketBuffer& packet, const struct timeval& queryTime, const struct timeval& replyTime) +static void logFstreamResponse(const std::shared_ptr>>& fstreamLoggers, const ComboAddress& localip, const ComboAddress& address, DnstapMessage::ProtocolType protocol, const DNSName& auth, const PacketBuffer& packet, const struct timeval& queryTime, const struct timeval& replyTime) { if (fstreamLoggers == nullptr) return; @@ -155,7 +241,7 @@ #endif // HAVE_FSTRM -static void logOutgoingQuery(const std::shared_ptr>>& outgoingLoggers, const boost::optional& 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& srcmask, const std::string& nsName) +static void logOutgoingQuery(const std::shared_ptr>>& outgoingLoggers, const boost::optional& 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 std::optional& srcmask, const std::string& nsName) { if (!outgoingLoggers) { return; @@ -215,7 +301,7 @@ } } -static void logIncomingResponse(const std::shared_ptr>>& outgoingLoggers, const boost::optional& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const boost::optional& srcmask, size_t bytes, int rcode, const std::vector& records, const struct timeval& queryTime, const std::set& exportTypes, const std::string& nsName) +static void logIncomingResponse(const std::shared_ptr>>& outgoingLoggers, const boost::optional& initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& address, const DNSName& domain, int type, uint16_t qid, bool doTCP, bool tls, const std::optional& srcmask, size_t bytes, int rcode, const std::vector& records, const struct timeval& queryTime, const std::set& exportTypes, const std::string& nsName) { if (!outgoingLoggers) { return; @@ -288,47 +374,86 @@ } } -static bool tcpconnect(const ComboAddress& ip, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName) +class BindError { - dnsOverTLS = SyncRes::s_dot_to_port_853 && ip.getPort() == 853; +}; - connection = t_tcp_manager.get(ip); +static bool tcpconnect(const OptLog& log, const ComboAddress& remote, const std::optional localBind, TCPOutConnectionManager::Connection& connection, bool& dnsOverTLS, const std::string& nsName, std::string& subjectName) +{ + dnsOverTLS = SyncRes::s_dot_to_port_853 && remote.getPort() == 853; + + connection = t_tcp_manager.get({remote, localBind}); if (connection.d_handler) { return false; } - const struct timeval timeout - { - g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000 - }; - Socket s(ip.sin4.sin_family, SOCK_STREAM); - s.setNonBlocking(); - setTCPNoDelay(s.getHandle()); - ComboAddress localip = pdns::getQueryLocalAddress(ip.sin4.sin_family, 0); - s.bind(localip); + const struct timeval timeout{ + g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000}; + Socket sock(remote.sin4.sin_family, SOCK_STREAM); + sock.setNonBlocking(); + setTCPNoDelay(sock.getHandle()); + // Bind to the same address the cookie is associated with (RFC 9018 section 3 last paragraph) + ComboAddress localip = localBind ? *localBind : pdns::getQueryLocalAddress(remote.sin4.sin_family, 0); + if (localBind) { + VLOG(log, "Connecting TCP to " << remote.toStringWithPortExcept(53) << " with specific local address " << localip.toString() << endl); + } + else { + VLOG(log, "Connecting TCP to " << remote.toStringWithPortExcept(53) << " with no specific local address" << endl); + } + + try { +#ifdef IP_BIND_ADDRESS_NO_PORT + int one = 1; + setsockopt(sock.getHandle(), SOL_IP, IP_BIND_ADDRESS_NO_PORT, &one, sizeof(one)); // failure ignored on purpose +#endif + sock.bind(localip); + } + catch (const NetworkError& e) { + if (localBind) { + throw BindError(); + } + throw; + } std::shared_ptr tlsCtx{nullptr}; + bool subjectIsAddress = false; if (dnsOverTLS) { - TLSContextParameters tlsParams; - tlsParams.d_provider = "openssl"; - tlsParams.d_validateCertificates = false; - // tlsParams.d_caStore - tlsCtx = getTLSContext(tlsParams); + subjectName = nsName; + std::string subjectAddress; + std::string configName; + tlsCtx = TCPOutConnectionManager::getTLSContext(nsName, remote, connection.d_verboseLogging, subjectName, subjectAddress, configName); if (tlsCtx == nullptr) { - SLOG(g_log << Logger::Error << "DoT to " << ip << " requested but not available" << endl, - g_slogout->info(Logr::Error, "DoT requested but not available", "server", Logging::Loggable(ip))); + g_slogout->info(Logr::Error, "DoT requested but not available", "server", Logging::Loggable(remote)); dnsOverTLS = false; } + else { + if (subjectName.empty() && !subjectAddress.empty()) { + subjectName = std::move(subjectAddress); + subjectIsAddress = true; + } + if (subjectName.empty()) { + subjectName = remote.toString(); + subjectIsAddress = true; + } + } + if (dnsOverTLS && connection.d_verboseLogging) { + g_slogout->info(Logr::Debug, "Connecting with DoT", "server", Logging::Loggable(remote), + "subjectName", Logging::Loggable(subjectName), + "subjectIsAddress", Logging::Loggable(subjectIsAddress), + "configName", Logging::Loggable(configName)); + } } - connection.d_handler = std::make_shared(nsName, false, s.releaseHandle(), timeout, tlsCtx); + connection.d_handler = std::make_shared(subjectName, subjectIsAddress, sock.releaseHandle(), timeout, tlsCtx); + connection.d_local = localBind; // Returned state ignored // This can throw an exception, retry will need to happen at higher level - connection.d_handler->tryConnect(SyncRes::s_tcp_fast_open_connect, ip); + connection.d_handler->tryConnect(SyncRes::s_tcp_fast_open_connect, remote); return true; } static LWResult::Result tcpsendrecv(const ComboAddress& ip, TCPOutConnectionManager::Connection& connection, - ComboAddress& localip, const vector& vpacket, size_t& len, PacketBuffer& buf) + ComboAddress& localip, const vector& vpacket, size_t& len, PacketBuffer& buf, + const std::string& nsName, const std::string& subjectName) { socklen_t slen = ip.getSocklen(); uint16_t tlen = htons(vpacket.size()); @@ -347,6 +472,15 @@ LWResult::Result ret = asendtcp(packet, connection.d_handler); if (ret != LWResult::Result::Success) { + if (connection.d_handler->isTLS() && connection.d_verboseLogging) { + auto result = connection.d_handler->getVerifyResult(); + g_slogout->info(Logr::Error, "Failed to setup TLS connection", + "errorcode", Logging::Loggable(result.first), + "remote", Logging::Loggable(ip), + "nsname", Logging::Loggable(nsName), + "subjectName", Logging::Loggable(subjectName), + "tlsmessage", Logging::Loggable(result.second)); + } return ret; } @@ -388,11 +522,105 @@ } } +static void outgoingCookie(const OptLog& log, const ComboAddress& address, const timeval& now, DNSPacketWriter::optvect_t& opts, std::optional& cookieSentOut, std::optional& addressToBindTo) +{ + auto lock = s_cookiestore.lock(); + if (auto found = lock->find(address); found != lock->end()) { + switch (found->getSupport()) { + case CookieEntry::Support::Supported: + case CookieEntry::Support::Probing: + cookieSentOut = found->d_cookie; + addressToBindTo = found->d_localaddress; + opts.emplace_back(EDNSOptionCode::COOKIE, cookieSentOut->makeOptString()); + found->d_lastused = now.tv_sec; + VLOG(log, "Sending stored cookie info to " << address.toString() << ": " << found->d_cookie.toDisplayString() << endl); + break; + case CookieEntry::Support::Unsupported: + VLOG(log, "Server " << address.toString() << " does not support cookies" << endl); + break; + } + return; + } + // Server not in table, it's either new or was purged + CookieEntry entry; + entry.d_address = address; + entry.d_cookie.makeClientCookie(); + cookieSentOut = entry.d_cookie; + entry.setSupport(CookieEntry::Support::Probing, now.tv_sec); + lock->emplace(entry); + opts.emplace_back(EDNSOptionCode::COOKIE, cookieSentOut->makeOptString()); + VLOG(log, "Sending new client cookie info to " << address.toString() << ": " << entry.d_cookie.toDisplayString() << endl); +} + +static std::pair incomingCookie(const OptLog& log, const ComboAddress& address, const ComboAddress& localip, const timeval& now, const std::optional& cookieSentOut, const EDNSOpts& edo, bool doTCP, LWResult& lwr, bool& cookieFoundInReply) +{ + auto lock = s_cookiestore.lock(); + auto found = lock->find(address); + + if (found == lock->end()) { + // We received cookie (we might have sent one out) but the server is not in the table? + // This is a case of cannot happen, unless rec_control clear-cookies was called + VLOG(log, "Cookie from " << address.toString() << " not found back in table" << endl); + lwr.d_rcode = RCode::FormErr; + lwr.d_validpacket = false; + return {true, LWResult::Result::Success}; // success - oddly enough + } + + // We have stored cookie info, scan for COOKIE option in EDNS + if (const auto opt = edo.getFirstOption(EDNSOptionCode::COOKIE); opt != edo.d_options.end()) { + if (EDNSCookiesOpt received; received.makeFromString(opt->second)) { + cookieFoundInReply = true; + VLOG(log, "Received cookie info back from " << address.toString() << ": " << received.toDisplayString() << endl); + if (cookieSentOut && received.getClient() == cookieSentOut->getClient()) { + VLOG(log, "Client cookie from " << address.toString() << " matched! Storing with localAddress " << localip.toString() << endl); + ++t_Counters.at(rec::Counter::cookieMatched); + found->d_localaddress = localip; + found->d_localaddress.setPort(0); + found->d_cookie = std::move(received); + if (found->getSupport() == CookieEntry::Support::Probing) { + ++t_Counters.at(rec::Counter::cookieProbeSupported); + } + found->setSupport(CookieEntry::Support::Supported, now.tv_sec); + // check extended error code + uint16_t ercode = edo.getCombinedERCode(lwr.d_rcode); + if (ercode == ERCode::BADCOOKIE) { + lwr.d_validpacket = true; + ++t_Counters.at(rec::Counter::cookieRetry); + VLOG(log, "Server " << localip.toString() << " returned BADCOOKIE " << endl); + return {true, LWResult::Result::BadCookie}; // We did update the entry, retry should succeed + } + } + else { + if (!doTCP) { + // Server responded with a wrong client cookie, fall back to TCP, RFC 7873 5.3 + VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie, fall back to TCP" << endl); + lwr.d_validpacket = true; + ++t_Counters.at(rec::Counter::cookieMismatchedOverUDP); + return {true, LWResult::Result::Spoofed}; + } + // mismatched cookie when already doing TCP, ignore that + VLOG(log, "Server " << localip.toString() << " responded with wrong client cookie over TCP, ignoring that" << endl); + ++t_Counters.at(rec::Counter::cookieMismatchedOverTCP); + } + } + else { + VLOG(log, "Malformed cookie in reply from " << address.toString() << ", dropping as if was a timeout" << endl); + // Do something special if we get malformed repeatedly? And/or consider current status? + lwr.d_validpacket = false; + ++t_Counters.at(rec::Counter::cookieMalformed); + return {true, LWResult::Result::Timeout}; + } + } // COOKIE option found + + // The cases where something special needs to be done have been handled above + return {false, LWResult::Result::Success}; +} + /** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors Never throws! */ // NOLINTNEXTLINE(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791 -static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, [[maybe_unused]] const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained, TCPOutConnectionManager::Connection& connection) +static LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, std::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, [[maybe_unused]] const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained, TCPOutConnectionManager::Connection& connection) { size_t len; size_t bufsize = g_outgoingEDNSBufsize; @@ -422,14 +650,20 @@ */ pw.getHeader()->cd = (sendRDQuery && g_dnssecmode != DNSSECMode::Off); - string ping; std::optional subnetOpts = std::nullopt; + std::optional addressToBindTo; + std::optional cookieSentOut; + if (EDNS0Level > 0) { DNSPacketWriter::optvect_t opts; if (srcmask) { subnetOpts = EDNSSubnetOpts{}; - subnetOpts->source = *srcmask; - opts.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(*subnetOpts)); + subnetOpts->setSource(*srcmask); + opts.emplace_back(EDNSOptionCode::ECS, subnetOpts->makeOptString()); + } + + if (g_cookies) { + outgoingCookie(log, address, *now, opts, cookieSentOut, addressToBindTo); } if (dnsOverTLS && g_paddingOutgoing) { @@ -455,14 +689,14 @@ 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 + srcmask = std::nullopt; // this is also our return value, even if EDNS0Level == 0 - // We only store the localip if needed for fstrm logging + // We only store the localip if needed for fstrm logging or cookie support ComboAddress localip; -#ifdef HAVE_FSTRM bool fstrmQEnabled = false; bool fstrmREnabled = false; +#ifdef HAVE_FSTRM if (isEnabledForQueries(fstrmLoggers)) { fstrmQEnabled = true; } @@ -473,9 +707,18 @@ if (!doTCP) { int queryfd; - - ret = asendto(vpacket.data(), vpacket.size(), 0, address, qid, domain, type, subnetOpts, &queryfd, *now); - + try { + ret = asendto(vpacket.data(), vpacket.size(), 0, address, addressToBindTo, qid, domain, type, subnetOpts, &queryfd, *now); + } + catch (const PDNSException& e) { + if (addressToBindTo) { + // Cookie info already has been added to packet, so we must retry from a higher level: SyncRes::asyncresolveWrapper + auto lock = s_cookiestore.lock(); + lock->erase(address); + return LWResult::Result::BindError; + } + throw; + } if (ret != LWResult::Result::Success) { return ret; } @@ -484,24 +727,24 @@ *chained = true; } -#ifdef HAVE_FSTRM if (!*chained) { - if (fstrmQEnabled || fstrmREnabled) { + if (cookieSentOut || fstrmQEnabled || fstrmREnabled) { localip.sin4.sin_family = address.sin4.sin_family; socklen_t slen = address.getSocklen(); (void)getsockname(queryfd, reinterpret_cast(&localip), &slen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)) } +#ifdef HAVE_FSTRM if (fstrmQEnabled) { - logFstreamQuery(fstrmLoggers, queryTime, localip, address, DnstapMessage::ProtocolType::DoUDP, context.d_auth ? context.d_auth : boost::none, vpacket); + logFstreamQuery(fstrmLoggers, queryTime, localip, address, DnstapMessage::ProtocolType::DoUDP, context.d_auth, vpacket); } +#endif } -#endif /* HAVE_FSTRM */ // sleep until we see an answer to this, interface to mtasker ret = arecvfrom(buf, 0, address, len, qid, domain, type, queryfd, subnetOpts, *now); } else { - bool isNew; + bool isNew{}; do { try { // If we get a new (not re-used) TCP connection that does not @@ -509,8 +752,9 @@ // 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 - isNew = tcpconnect(address, connection, dnsOverTLS, nsName); - ret = tcpsendrecv(address, connection, localip, vpacket, len, buf); + std::string subjectName; + isNew = tcpconnect(log, address, addressToBindTo, connection, dnsOverTLS, nsName, subjectName); + ret = tcpsendrecv(address, connection, localip, vpacket, len, buf, nsName, subjectName); #ifdef HAVE_FSTRM if (fstrmQEnabled) { logFstreamQuery(fstrmLoggers, queryTime, localip, address, !dnsOverTLS ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoT, context.d_auth, vpacket); @@ -521,10 +765,19 @@ } connection.d_handler->close(); } - catch (const NetworkError&) { + catch (const BindError&) { + // Cookie info already has been added to packet, so we must retry from a higher level + auto lock = s_cookiestore.lock(); + lock->erase(address); + VLOG(log, "BindError remote: " << address.toString() << " localAddress: " << (addressToBindTo ? addressToBindTo->toString() : "none") << endl); + return LWResult::Result::BindError; + } + catch (const NetworkError& nwe) { + VLOG(log, "NetworkException: " << address.toString() << ": " << nwe.what() << endl); ret = LWResult::Result::OSLimitError; // OS limits error } - catch (const runtime_error&) { + catch (const runtime_error& rte) { + VLOG(log, "runtime_error: " << address.toString() << ": " << rte.what() << endl); ret = LWResult::Result::OSLimitError; // OS limits error (PermanentError is transport related) } } while (!isNew); @@ -568,6 +821,15 @@ try { lwr->d_tcbit = 0; MOADNSParser mdp(false, reinterpret_cast(buf.data()), buf.size()); + + // RFC 1035 Section 4.1.1: QR must be 1 for responses + if (!mdp.d_header.qr) { + lwr->d_rcode = RCode::ServFail; + lwr->d_validpacket = false; + t_Counters.at(rec::Counter::serverParseError)++; + return LWResult::Result::PermanentError; + } + lwr->d_aabit = mdp.d_header.aa; lwr->d_tcbit = mdp.d_header.tc; lwr->d_rcode = mdp.d_header.rcode; @@ -582,11 +844,10 @@ if (domain != mdp.d_qname) { if (!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) { // embedded nulls are too noisy, plus empty domains are too - SLOG(g_log << Logger::Notice << "Packet purporting to come from remote server " << address.toString() << " contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl, - g_slogout->info(Logr::Notice, "Packet purporting to come from remote server contained wrong answer", - "server", Logging::Loggable(address), - "qname", Logging::Loggable(domain), - "onwire", Logging::Loggable(mdp.d_qname))); + g_slogout->info(Logr::Notice, "Packet purporting to come from remote server contained wrong answer", + "server", Logging::Loggable(address), + "qname", Logging::Loggable(domain), + "onwire", Logging::Loggable(mdp.d_qname)); } // unexpected count has already been done @ pdns_recursor.cc goto out; @@ -597,6 +858,7 @@ lwr->d_records.push_back(answer); } + bool cookieFoundInReply = false; if (EDNSOpts edo; EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) { lwr->d_haveEDNS = true; @@ -610,28 +872,63 @@ // THE RFC is not clear about the case of having multiple ECS options. We only look at the first. if (const auto opt = edo.getFirstOption(EDNSOptionCode::ECS); opt != edo.d_options.end()) { EDNSSubnetOpts reso; - if (getEDNSSubnetOptsFromString(opt->second, &reso)) { - if (!doTCP && reso.source != subnetOpts->source) { + if (EDNSSubnetOpts::getFromString(opt->second, &reso)) { + if (!doTCP && reso.getSource() != subnetOpts->getSource()) { g_slogout->info(Logr::Notice, "Incoming ECS does not match outgoing", "server", Logging::Loggable(address), "qname", Logging::Loggable(domain), - "outgoing", Logging::Loggable(subnetOpts->source), - "incoming", Logging::Loggable(reso.source)); + "outgoing", Logging::Loggable(subnetOpts->getSource()), + "incoming", Logging::Loggable(reso.getSource())); return LWResult::Result::Spoofed; } /* rfc7871 states that 0 "indicate[s] that the answer is suitable for all addresses in FAMILY", so we might want to still pass the information along to be able to differentiate between IPv4 and IPv6. Still I'm pretty sure it doesn't matter in real life, so let's not duplicate entries in our cache. */ - if (reso.scope.getBits() != 0) { - uint8_t bits = std::min(reso.scope.getBits(), subnetOpts->source.getBits()); - auto outgoingECSAddr = subnetOpts->source.getNetwork(); + if (reso.getScopePrefixLength() != 0) { + uint8_t bits = std::min(reso.getScopePrefixLength(), subnetOpts->getSourcePrefixLength()); + auto outgoingECSAddr = subnetOpts->getSource().getNetwork(); outgoingECSAddr.truncate(bits); srcmask = Netmask(outgoingECSAddr, bits); } } } } + if (g_cookies && cookieSentOut && !*chained) { + auto [done, result] = incomingCookie(log, address, localip, *now, cookieSentOut, edo, doTCP, *lwr, cookieFoundInReply); + if (done) { + return result; + } + } + } + + // Case: we sent out a cookie but did not get one back + if (cookieSentOut && !cookieFoundInReply && !*chained) { + ++t_Counters.at(rec::Counter::cookieNotInReply); + auto lock = s_cookiestore.lock(); + auto found = lock->find(address); + if (found != lock->end()) { + switch (found->getSupport()) { + case CookieEntry::Support::Probing: + VLOG(log, "No cookie in reply from " << address.toString() << ", was probing, setting support to Unsupported" << endl); + found->setSupport(CookieEntry::Support::Unsupported, now->tv_sec); + ++t_Counters.at(rec::Counter::cookieProbeUnsupported); + break; + case CookieEntry::Support::Unsupported: + // We could have detected the server does not support cookies in the meantime + VLOG(log, "No cookie in reply from " << address.toString() << ", cookie state is Unsupported, fine" << endl); + break; + case CookieEntry::Support::Supported: + // RFC says: ignore replies not containing any cookie info, equivalent to timeout + VLOG(log, "No cookie in reply from " << address.toString() << ", cookie state is Supported, dropping packet as if it timed out)" << endl); + return LWResult::Result::Timeout; + break; + } + } + else { + VLOG(log, "No cookie in reply from " << address.toString() << ", cookie state is Unknown, dropping packet as if it timed out" << endl); + return LWResult::Result::Timeout; + } } if (outgoingLoggers) { @@ -643,9 +940,10 @@ } catch (const std::exception& mde) { if (::arg().mustDo("log-common-errors")) { - SLOG(g_log << Logger::Notice << "Unable to parse packet from remote server " << address.toString() << ": " << mde.what() << endl, - g_slogout->error(Logr::Notice, mde.what(), "Unable to parse packet from remote server", "server", Logging::Loggable(address), - "exception", Logging::Loggable("std::exception"))); + g_slogout->error(Logr::Notice, mde.what(), "Unable to parse packet from remote server", "server", Logging::Loggable(address), + "exception", Logging::Loggable("std::exception"), + "qname", Logging::Loggable(domain), + "qtype", Logging::Loggable(QType(type))); } lwr->d_rcode = RCode::FormErr; @@ -659,8 +957,7 @@ return LWResult::Result::Success; // success - oddly enough } catch (...) { - SLOG(g_log << Logger::Notice << "Unknown error parsing packet from remote server" << endl, - g_slogout->info(Logr::Notice, "Unknown error parsing packet from remote server", "server", Logging::Loggable(address))); + g_slogout->info(Logr::Notice, "Unknown error parsing packet from remote server", "server", Logging::Loggable(address)); } t_Counters.at(rec::Counter::serverParseError)++; @@ -673,14 +970,14 @@ return LWResult::Result::PermanentError; } -LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained) +LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, std::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained) { TCPOutConnectionManager::Connection connection; - auto ret = asyncresolve(address, domain, type, doTCP, sendRDQuery, EDNS0Level, now, srcmask, context, outgoingLoggers, fstrmLoggers, exportTypes, lwr, chained, connection); + auto ret = asyncresolve(log, address, domain, type, doTCP, sendRDQuery, EDNS0Level, now, srcmask, context, outgoingLoggers, fstrmLoggers, exportTypes, lwr, chained, connection); if (doTCP) { if (connection.d_handler && lwr->d_validpacket) { - t_tcp_manager.store(*now, address, std::move(connection)); + t_tcp_manager.store(*now, std::make_pair(address, connection.d_local), std::move(connection)); } } return ret; diff -Nru pdns-recursor-5.2.13/lwres.hh pdns-recursor-5.4.9/lwres.hh --- pdns-recursor-5.2.13/lwres.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/lwres.hh 2026-10-26 08:26:51.000000000 +0000 @@ -43,8 +43,8 @@ #include "fstrm_logger.hh" #include "resolve-context.hh" #include "noinitvector.hh" - -#include "logging.hh" +#include "logger.hh" +#include "logr.hh" // Helper to be defined by main program: queue data and log based on return value of queueData() void remoteLoggerQueueData(RemoteLoggerInterface&, const std::string&); @@ -73,6 +73,8 @@ Spoofed = 4, /* Spoofing attempt (too many near-misses) */ ChainLimitError = 5, ECSMissing = 6, + BadCookie = 7, + BindError = 8, }; [[nodiscard]] static bool isLimitError(Result res) @@ -81,19 +83,25 @@ } vector d_records; + uint32_t d_usec{0}; uint32_t d_bytesReceived{0}; int d_rcode{0}; bool d_validpacket{false}; bool d_aabit{false}, d_tcbit{false}; - uint32_t d_usec{0}; bool d_haveEDNS{false}; }; -struct EDNSSubnetOpts; +class EDNSSubnetOpts; -LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, uint16_t qid, +LWResult::Result asendto(const void* data, size_t len, int flags, const ComboAddress& toAddress, + std::optional& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional& 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 std::optional& ecs, const struct timeval& now); -LWResult::Result asyncresolve(const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained); +LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, std::optional& srcmask, const ResolveContext& context, const std::shared_ptr>>& outgoingLoggers, const std::shared_ptr>>& fstrmLoggers, const std::set& exportTypes, LWResult* lwr, bool* chained); +uint64_t dumpCookies(int fileDesc); +uint64_t clearCookies(vector::iterator begin, vector::iterator end, string& errors); +uint64_t addCookiesUnsupported(vector::iterator begin, vector::iterator end, string& errors); +void pruneCookies(time_t cutoff); +std::string enableOutgoingCookies(bool flag, const std::string& unsupported); diff -Nru pdns-recursor-5.2.13/m4/ax_cxx_compile_stdcxx.m4 pdns-recursor-5.4.9/m4/ax_cxx_compile_stdcxx.m4 --- pdns-recursor-5.2.13/m4/ax_cxx_compile_stdcxx.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/ax_cxx_compile_stdcxx.m4 2026-10-26 09:46:36.000000000 +0000 @@ -10,13 +10,13 @@ # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). +# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for +# the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. +# preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -35,13 +35,15 @@ # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# Copyright (c) 2021 Jörn Heusipp # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 11 +#serial 18 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -50,6 +52,7 @@ m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [$1], [20], [ax_cxx_compile_alternatives="20"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], @@ -62,6 +65,16 @@ AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) + m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do @@ -91,9 +104,18 @@ dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" + dnl MSVC needs -std:c++NN for C++17 and later (default is C++14) for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do + if test x"$switch" = xMSVC; then + dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide + dnl with -std=c++17. We suffix the cache variable name with _MSVC to + dnl avoid this. + switch=-std:c++${alternative} + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC]) + else + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + fi AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" @@ -140,7 +162,6 @@ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) - dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], @@ -148,12 +169,24 @@ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) +dnl Test body for checking C++17 support + m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 +) + + dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ @@ -165,7 +198,11 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" @@ -456,7 +493,7 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201402L +#elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" @@ -580,7 +617,7 @@ #error "This is not a C++ compiler" -#elif __cplusplus < 201703L +#elif __cplusplus < 201703L && !defined _MSC_VER #error "This is not a C++17 compiler" @@ -595,7 +632,8 @@ namespace test_constexpr_lambdas { - [[maybe_unused]] constexpr int foo = [](){return 42;}(); + + constexpr int foo = [](){return 42;}(); } @@ -945,6 +983,36 @@ } // namespace cxx17 -#endif // __cplusplus < 201703L +#endif // __cplusplus < 201703L && !defined _MSC_VER + +]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER ]]) diff -Nru pdns-recursor-5.2.13/m4/ax_cxx_compile_stdcxx_20.m4 pdns-recursor-5.4.9/m4/ax_cxx_compile_stdcxx_20.m4 --- pdns-recursor-5.2.13/m4/ax_cxx_compile_stdcxx_20.m4 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/m4/ax_cxx_compile_stdcxx_20.m4 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,4 @@ +#serial 2 + +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_20], [AX_CXX_COMPILE_STDCXX([20], [$1], [$2])]) diff -Nru pdns-recursor-5.2.13/m4/pdns_check_curl.m4 pdns-recursor-5.4.9/m4/pdns_check_curl.m4 --- pdns-recursor-5.2.13/m4/pdns_check_curl.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_check_curl.m4 2026-10-26 08:26:51.000000000 +0000 @@ -1,8 +1,8 @@ AC_DEFUN([PDNS_CHECK_CURL], [ AC_CHECK_PROG([CURL], [curl], [curl]) if test "x$CURL" = "x"; then - if test ! -f "${srcdir}/effective_tld_names.dat"; then - AC_MSG_ERROR([curl is missing and you don't have ${srcdir}//effective_tld_names.dat. Install curl or download sources from www.powerdns.com]) + if test ! -f "${srcdir}/pubsuffix.cc"; then + AC_MSG_ERROR([curl is missing and you don't have ${srcdir}//pubsuffix.cc. Install curl or download sources from www.powerdns.com]) fi fi ]) diff -Nru pdns-recursor-5.2.13/m4/pdns_check_libcrypto.m4 pdns-recursor-5.4.9/m4/pdns_check_libcrypto.m4 --- pdns-recursor-5.2.13/m4/pdns_check_libcrypto.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_check_libcrypto.m4 2026-10-26 09:46:36.000000000 +0000 @@ -55,6 +55,7 @@ LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null` LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null` ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null` + sslincdir=`$PKG_CONFIG libcrypto --variable=includedir 2>/dev/null` found=true fi fi @@ -78,6 +79,7 @@ LIBCRYPTO_INCLUDES="-I$ssldir/include" LIBCRYPTO_LDFLAGS="-L$ssldir/lib" LIBCRYPTO_LIBS="-lcrypto" + sslincdir="$ssldir/include" found=true AC_MSG_RESULT([yes]) break diff -Nru pdns-recursor-5.2.13/m4/pdns_check_libcrypto_ecdsa.m4 pdns-recursor-5.4.9/m4/pdns_check_libcrypto_ecdsa.m4 --- pdns-recursor-5.2.13/m4/pdns_check_libcrypto_ecdsa.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_check_libcrypto_ecdsa.m4 2026-10-26 09:46:36.000000000 +0000 @@ -12,11 +12,11 @@ # Find the headers we need for ECDSA libcrypto_ecdsa=yes - AC_CHECK_HEADER([$ssldir/include/openssl/ecdsa.h], [ + AC_CHECK_HEADER([$sslincdir/openssl/ecdsa.h], [ AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [ : ], [ libcrypto_ecdsa=no ], [AC_INCLUDES_DEFAULT -#include <$ssldir/include/openssl/evp.h> +#include <$sslincdir/openssl/evp.h> ]) ], [ libcrypto_ecdsa=no diff -Nru pdns-recursor-5.2.13/m4/pdns_check_libcrypto_eddsa.m4 pdns-recursor-5.4.9/m4/pdns_check_libcrypto_eddsa.m4 --- pdns-recursor-5.2.13/m4/pdns_check_libcrypto_eddsa.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_check_libcrypto_eddsa.m4 2026-10-26 09:46:36.000000000 +0000 @@ -17,13 +17,13 @@ AC_DEFINE([HAVE_LIBCRYPTO_ED25519], [1], [define to 1 if OpenSSL ed25519 support is available.]) ], [ : ], [AC_INCLUDES_DEFAULT - #include <$ssldir/include/openssl/evp.h>]) + #include <$sslincdir/openssl/evp.h>]) AC_CHECK_DECLS([NID_ED448], [ libcrypto_ed448=yes AC_DEFINE([HAVE_LIBCRYPTO_ED448], [1], [define to 1 if OpenSSL ed448 support is available.]) ], [ : ], [AC_INCLUDES_DEFAULT - #include <$ssldir/include/openssl/evp.h>]) + #include <$sslincdir/openssl/evp.h>]) AS_IF([test "$libcrypto_ed25519" = "yes" -o "$libcrypto_ed448" = "yes"], [ AC_DEFINE([HAVE_LIBCRYPTO_EDDSA], [1], [define to 1 if OpenSSL EDDSA support is available.]) diff -Nru pdns-recursor-5.2.13/m4/pdns_enable_p11kit.m4 pdns-recursor-5.4.9/m4/pdns_enable_p11kit.m4 --- pdns-recursor-5.2.13/m4/pdns_enable_p11kit.m4 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_enable_p11kit.m4 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +AC_DEFUN([PDNS_ENABLE_PKCS11],[ + AC_MSG_CHECKING([whether to enable PKCS11 support]) + AC_ARG_ENABLE([experimental-pkcs11], + [AS_HELP_STRING([--enable-experimental-pkcs11],[enable experimental PKCS11 support @<:@default=no@:>@])], + [enable_pkcs11=$enableval], + [enable_pkcs11=no] + ) + AC_MSG_RESULT([$enable_pkcs11]) + AM_CONDITIONAL([PKCS11], [test "x$enable_pkcs11" != "xno"]) + + AS_IF([test "x$enable_pkcs11" != "xno"], [ + PKG_CHECK_MODULES([P11KIT1], [p11-kit-1], + [ + AC_DEFINE([HAVE_P11KIT1],[1],[Define to 1 if you have p11-kit-1]) + AC_CHECK_LIB([p11-kit], [p11_kit_module_for_name], [AC_DEFINE([HAVE_P11KIT1_V2],[1],[Define to 1 if you have 0.20 or newer P11-kit])], [], [$P11KIT1_LIBS]) + ], + [AC_MSG_ERROR([Could not find p11-kit-1])] + )] + ) + +]) diff -Nru pdns-recursor-5.2.13/m4/pdns_with_gnutls.m4 pdns-recursor-5.4.9/m4/pdns_with_gnutls.m4 --- pdns-recursor-5.2.13/m4/pdns_with_gnutls.m4 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_with_gnutls.m4 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,34 @@ +AC_DEFUN([PDNS_WITH_GNUTLS], [ + AC_MSG_CHECKING([whether we will be linking in GnuTLS]) + HAVE_GNUTLS=0 + AC_ARG_WITH([gnutls], + AS_HELP_STRING([--with-gnutls],[use GnuTLS @<:@default=auto@:>@]), + [with_gnutls=$withval], + [with_gnutls=auto], + ) + AC_MSG_RESULT([$with_gnutls]) + + AS_IF([test "x$with_gnutls" != "xno"], [ + AS_IF([test "x$with_gnutls" = "xyes" -o "x$with_gnutls" = "xauto"], [ + # we require gnutls_certificate_set_x509_key_file, added in 3.1.11 + PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.1.11], [ + [HAVE_GNUTLS=1] + AC_DEFINE([HAVE_GNUTLS], [1], [Define to 1 if you have GnuTLS]) + save_CFLAGS=$CFLAGS + save_LIBS=$LIBS + CFLAGS="$GNUTLS_CFLAGS $CFLAGS" + LIBS="$GNUTLS_LIBS $LIBS" + AC_CHECK_FUNCS([gnutls_memset gnutls_session_set_verify_cert gnutls_session_get_verify_cert_status gnutls_alpn_set_protocols]) + CFLAGS=$save_CFLAGS + LIBS=$save_LIBS + + ], [ : ]) + ]) + ]) + AM_CONDITIONAL([HAVE_GNUTLS], [test "x$GNUTLS_LIBS" != "x"]) + AS_IF([test "x$with_gnutls" = "xyes"], [ + AS_IF([test x"$GNUTLS_LIBS" = "x"], [ + AC_MSG_ERROR([GnuTLS requested but libraries were not found]) + ]) + ]) +]) diff -Nru pdns-recursor-5.2.13/m4/pdns_with_lua.m4 pdns-recursor-5.4.9/m4/pdns_with_lua.m4 --- pdns-recursor-5.2.13/m4/pdns_with_lua.m4 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/m4/pdns_with_lua.m4 2026-10-26 09:46:36.000000000 +0000 @@ -16,7 +16,7 @@ AC_MSG_RESULT([$with_lua]) - AS_IF([test "x$with_lua" = "xno" -a "$1" = "mandatory"], [ + AS_IF([test "x$with_lua" = "xno"], [ AC_MSG_ERROR([--without-lua specified, but Lua is not optional]) ]) @@ -24,37 +24,35 @@ luajit_min_version='2.0.2' lua_min_version='5.1' - AS_IF([test "x$with_lua" != "xno"], [ - AS_IF([test "x$with_lua" != "xauto"], [ - with_lua_version=${lua_min_version} - AS_IF([echo "x$with_lua" | ${GREP} 'jit' >/dev/null 2>&1], [with_lua_version=${luajit_min_version}]) - PKG_CHECK_MODULES([LUA], $with_lua >= $with_lua_version, [ - AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have Lua]) - LUAPC=$with_lua - ], [ - AC_MSG_ERROR([Selected Lua ($with_lua) not found]) - ]) + AS_IF([test "x$with_lua" != "xauto"], [ + with_lua_version=${lua_min_version} + AS_IF([echo "x$with_lua" | ${GREP} 'jit' >/dev/null 2>&1], [with_lua_version=${luajit_min_version}]) + PKG_CHECK_MODULES([LUA], $with_lua >= $with_lua_version, [ + AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have Lua]) + LUAPC=$with_lua ], [ - PKG_CHECK_MODULES([LUA], [luajit >= ${luajit_min_version}], [ - LUAPC=luajit - AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have Lua]) - ], [ : ]) - AS_IF([test -z "$LUAPC"], [ - found_lua=n - m4_foreach_w([luapc], [lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua], [ - AS_IF([test "$found_lua" != "y"], [ - PKG_CHECK_MODULES([LUA], [luapc >= ${lua_min_version}], [ - AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua]) - found_lua=y - LUAPC=luapc - ], [ : ]) - ]) + AC_MSG_ERROR([Selected Lua ($with_lua) not found]) + ]) + ], [ + PKG_CHECK_MODULES([LUA], [luajit >= ${luajit_min_version}], [ + LUAPC=luajit + AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have Lua]) + ], [ : ]) + AS_IF([test -z "$LUAPC"], [ + found_lua=n + m4_foreach_w([luapc], [lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua], [ + AS_IF([test "$found_lua" != "y"], [ + PKG_CHECK_MODULES([LUA], [luapc >= ${lua_min_version}], [ + AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua]) + found_lua=y + LUAPC=luapc + ], [ : ]) ]) ]) ]) ]) - AS_IF([test -z "$LUAPC" -a "$1" = "mandatory"], [ + AS_IF([test -z "$LUAPC"], [ AC_MSG_ERROR([No Lua not found, but is mandatory]) ]) diff -Nru pdns-recursor-5.2.13/malloctrace.cc pdns-recursor-5.4.9/malloctrace.cc --- pdns-recursor-5.2.13/malloctrace.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/malloctrace.cc 2026-10-26 09:46:36.000000000 +0000 @@ -73,7 +73,7 @@ d_totAllocated += size; - std::lock_guard lock(d_mut); + auto lock = std::scoped_lock(d_mut); auto& ent=d_stats[makeBacktrace()]; ent.count++; ent.sizes[size]++; @@ -89,7 +89,7 @@ __libc_free(ptr); if(!l_active) { l_active=true; - std::lock_guard lock(d_mut); + auto lock = std::scoped_lock(d_mut); auto f = d_sizes.find(ptr); if(f != d_sizes.end()) { d_totAllocated -= f->second; @@ -144,7 +144,7 @@ void MallocTracer::clearAllocators() { l_active=true; - std::lock_guard lock(d_mut); + auto lock = std::scoped_lock(d_mut); d_stats.clear(); l_active=false; } diff -Nru pdns-recursor-5.2.13/malloctrace.hh pdns-recursor-5.4.9/malloctrace.hh --- pdns-recursor-5.2.13/malloctrace.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/malloctrace.hh 2026-10-26 09:46:36.000000000 +0000 @@ -40,7 +40,7 @@ uint64_t getAllocs(const std::string& = std::string()) const { return d_allocs; } uint64_t getAllocFlux(const std::string& = std::string()) const { return d_allocflux; } uint64_t getTotAllocated(const std::string& = std::string()) const { return d_totAllocated; } - uint64_t getNumOut() { std::lock_guard lock(d_mut); return d_sizes.size(); } + uint64_t getNumOut() { std::scoped_lock lock(d_mut); return d_sizes.size(); } struct AllocStats { int count; diff -Nru pdns-recursor-5.2.13/meson/atomics/atomic_add_fetch.cc pdns-recursor-5.4.9/meson/atomics/atomic_add_fetch.cc --- pdns-recursor-5.2.13/meson/atomics/atomic_add_fetch.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/atomics/atomic_add_fetch.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +#include + +int main() +{ + uint64_t val = 0; + __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/atomics/meson.build pdns-recursor-5.4.9/meson/atomics/meson.build --- pdns-recursor-5.2.13/meson/atomics/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/atomics/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,23 @@ +dep_atomics = dependency('', required: false) +need_latomic = false + +fs = import('fs') +prog = fs.read('atomic_add_fetch.cc') +if not cxx.links(prog, name: '-latomic is not needed for using __atomic builtins') + lib_atomic = cxx.find_library('atomic', disabler: true, required: false) + if lib_atomic.found() + if cxx.links(prog, name: '-latomic is needed for using __atomic builtins', dependencies: lib_atomic) + need_latomic = true + dep_atomics = declare_dependency(dependencies: lib_atomic) + summary('Atomics Library', lib_atomic, section: 'System') + else + error('libatomic is needed and was found, but linking with it failed') + endif + else + error('libatomic is needed but could not be found') + endif +else + dep_atomics = declare_dependency() +endif + +summary('Need -latomic', need_latomic, bool_yn: true, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/auto-var-init/meson.build pdns-recursor-5.4.9/meson/auto-var-init/meson.build --- pdns-recursor-5.2.13/meson/auto-var-init/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/auto-var-init/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,13 @@ +auto_var_init = get_option('auto-var-init') + +if auto_var_init != 'disabled' + arg = '-ftrivial-auto-var-init=' + auto_var_init + 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 +endif + +summary('Auto Var Init', auto_var_init, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/boost/meson.build pdns-recursor-5.4.9/meson/boost/meson.build --- pdns-recursor-5.2.13/meson/boost/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +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') +summary('Version', dep_boost.version(), section: 'Boost') diff -Nru pdns-recursor-5.2.13/meson/boost-context/meson.build pdns-recursor-5.4.9/meson/boost-context/meson.build --- pdns-recursor-5.2.13/meson/boost-context/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost-context/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +dep_boost_context = dependency('boost', modules: ['context'], required: true) + diff -Nru pdns-recursor-5.2.13/meson/boost-filesystem/meson.build pdns-recursor-5.4.9/meson/boost-filesystem/meson.build --- pdns-recursor-5.2.13/meson/boost-filesystem/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost-filesystem/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +dep_boost_filesystem = dependency('boost', modules: ['filesystem'], required: false) +summary('Filesystem', dep_boost_filesystem.found(), bool_yn: true, section: 'Boost') diff -Nru pdns-recursor-5.2.13/meson/boost-program-options/meson.build pdns-recursor-5.4.9/meson/boost-program-options/meson.build --- pdns-recursor-5.2.13/meson/boost-program-options/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost-program-options/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +dep_boost_program_options = dependency('boost', modules: ['program_options'], required: true) +summary('Program Options', dep_boost_program_options.found(), bool_yn: true, section: 'Boost') diff -Nru pdns-recursor-5.2.13/meson/boost-serialization/meson.build pdns-recursor-5.4.9/meson/boost-serialization/meson.build --- pdns-recursor-5.2.13/meson/boost-serialization/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost-serialization/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +dep_boost_serialization = dependency('', required: false) + +if get_option('module-lmdb') != 'disabled' + dep_boost_serialization = dependency('boost', modules: ['serialization'], required: true) +endif + +summary('Serialization (LMDB)', dep_boost_serialization.found(), bool_yn: true, section: 'Boost') diff -Nru pdns-recursor-5.2.13/meson/boost-test/meson.build pdns-recursor-5.4.9/meson/boost-test/meson.build --- pdns-recursor-5.2.13/meson/boost-test/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/boost-test/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +dep_boost_test = dependency('', required: false) +if get_option('unit-tests') or get_option('unit-tests-backends') + dep_boost_test = dependency('boost', modules: ['unit_test_framework'], required: true) + summary('Test', dep_boost_test.found(), bool_yn: true, section: 'Boost') +endif diff -Nru pdns-recursor-5.2.13/meson/cdb/meson.build pdns-recursor-5.4.9/meson/cdb/meson.build --- pdns-recursor-5.2.13/meson/cdb/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/cdb/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +dep_cdb = dependency('', required: false) + +if get_option('module-tinydns') != 'disabled' + dep_cdb = dependency('libcdb', required: false) + + if not dep_cdb.found() + if cxx.has_header('cdb.h', required: true) + if cxx.has_function('cdb_find', args: ['-lcdb']) + dep_cdb = declare_dependency(link_args: ['-lcdb']) + endif + endif + endif +endif + +conf.set('HAVE_CDB', dep_cdb.found(), description: 'Whether we have CDB') + +summary('CDB', dep_cdb.found(), bool_yn: true, section: 'CDB') + +if dep_cdb.found() + summary('Version', dep_cdb.version(), bool_yn: true, section: 'CDB') +endif diff -Nru pdns-recursor-5.2.13/meson/clock-gettime/meson.build pdns-recursor-5.4.9/meson/clock-gettime/meson.build --- pdns-recursor-5.2.13/meson/clock-gettime/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/clock-gettime/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,15 @@ +found = cxx.has_function('clock_gettime') +dep_rt = dependency('', required: false) + +if not found + dep_rt = cxx.find_library('rt', required: true) + found = cxx.has_function('clock_gettime', dependencies: dep_rt) +endif + +conf.set('HAVE_CLOCK_GETTIME', found, description: 'Have clock_gettime') +summary('clock_gettime', true, bool_yn: true, section: 'System') + +if dep_rt.found() + summary('rt library', dep_rt.name(), bool_yn: true, section: 'System') + summary('rt library version', dep_rt.version(), bool_yn: true, section: 'System') +endif diff -Nru pdns-recursor-5.2.13/meson/code-coverage/meson.build pdns-recursor-5.4.9/meson/code-coverage/meson.build --- pdns-recursor-5.2.13/meson/code-coverage/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/code-coverage/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,31 @@ +coverage = get_option('b_coverage') +clang_coverage = get_option('clang-coverage-format') + +if coverage or clang_coverage + add_project_arguments('-DCOVERAGE', language: ['c', 'cpp']) + + if get_option('buildtype') != 'debug' + warning('Coverage is enabled, using `builtype=debug` would produce better reports') + endif + + if cxx.has_argument('-U_FORTIFY_SOURCE') + add_project_arguments('-U_FORTIFY_SOURCE', language: ['c', 'cpp']) + endif + +endif + +if coverage + if get_option('clang-coverage-format') + error('b_coverage and clang-coverage-format cannot be enabled at the same time') + endif + summary('Code Coverage', coverage, bool_yn: true, section: 'Configuration') +else + if get_option('clang-coverage-format') + # let's see if the clang++ specific format is supported, + # as it has a much lower overhead and is more accurate, + # see https://clang.llvm.org/docs/SourceBasedCodeCoverage.html + add_project_arguments('-DCLANG_COVERAGE', '-fprofile-instr-generate', '-fcoverage-mapping', language: ['c', 'cpp']) + add_project_link_arguments('-fprofile-instr-generate', '-fcoverage-mapping', language: ['c', 'cpp']) + summary('Code Coverage (clang format)', true, bool_yn: true, section: 'Configuration') + endif +endif diff -Nru pdns-recursor-5.2.13/meson/compiler-setup/meson.build pdns-recursor-5.4.9/meson/compiler-setup/meson.build --- pdns-recursor-5.2.13/meson/compiler-setup/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/compiler-setup/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,22 @@ +# Don't limit the number of errors when using clang. This is useful to not cut out the +# error output when using an LSP server like clangd. +if meson.get_compiler('cpp').get_id() == 'clang' + add_project_arguments('-ferror-limit=0', language: ['c', 'cpp']) +endif + +add_project_arguments( + '-Wshadow', + '-Wmissing-declarations', + '-Wredundant-decls', + '-Wno-ignored-attributes', + language: ['c', 'cpp'], +) + +cxx = meson.get_compiler('cpp') +system = target_machine.system() + +link_no_warn_duplicate_libraries = cxx.get_supported_link_arguments([ + '-Wl,-no_warn_duplicate_libraries', +]) + +add_project_link_arguments(link_no_warn_duplicate_libraries, language: ['c', 'cpp']) diff -Nru pdns-recursor-5.2.13/meson/config/meson.build pdns-recursor-5.4.9/meson/config/meson.build --- pdns-recursor-5.2.13/meson/config/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/config/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp']) +conf.set_quoted('PDNS_CONFIG_ARGS', meson.build_options(), description: 'Build options') diff -Nru pdns-recursor-5.2.13/meson/cxx-fs/cxx-fs.cc pdns-recursor-5.4.9/meson/cxx-fs/cxx-fs.cc --- pdns-recursor-5.2.13/meson/cxx-fs/cxx-fs.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/cxx-fs/cxx-fs.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +#include + +int main() +{ + std::filesystem::path path("."); + [[maybe_unused]] std::filesystem::file_status status = std::filesystem::status(path); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/cxx-fs/meson.build pdns-recursor-5.4.9/meson/cxx-fs/meson.build --- pdns-recursor-5.2.13/meson/cxx-fs/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/cxx-fs/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,36 @@ +dep_cxx_fs = dependency('', required: false) + +if get_option('module-geoip') != 'disabled' + need_cxx_fs = false + + prog = fs.read('cxx-fs.cc') + if not cxx.links(prog, name: '-lstdc++fs and -lc++fs are not needed') + 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 = true + dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs) + summary('Filesystem library', lib_cxx_fs, section: 'System') + endif + endif + + if need_cxx_fs == false + 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 = true + dep_cxx_fs = declare_dependency(dependencies: lib_cxx_fs) + summary('Filesystem library', lib_cxx_fs, section: 'System') + else + error('C++ Filesystem library was found but linking against it failed') + endif + else + error('C++ Filesystem library is needed but could not be found') + endif + endif + else + dep_cxx_fs = declare_dependency() + endif + + summary('Need -lstdc++fs/-lc++fs', need_cxx_fs, bool_yn: true, section: 'System') +endif diff -Nru pdns-recursor-5.2.13/meson/dlopen/meson.build pdns-recursor-5.4.9/meson/dlopen/meson.build --- pdns-recursor-5.2.13/meson/dlopen/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/dlopen/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,15 @@ +dep_dlopen = declare_dependency() + +if not cxx.has_function('dlopen') + dep_dlopen = dependency('dl', required: false) + + if not dep_dlopen.found() + dep_dlopen = cxx.find_library('dl', required: true) + + if not cxx.has_function('dlopen', dependencies: dep_dlopen) + error('Your system does not support dlopen') + endif + endif +endif + +summary('dlopen', dep_dlopen.found(), bool_yn: true, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/dnstap/meson.build pdns-recursor-5.4.9/meson/dnstap/meson.build --- pdns-recursor-5.2.13/meson/dnstap/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/dnstap/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,16 @@ +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 -Nru pdns-recursor-5.2.13/meson/dot/meson.build pdns-recursor-5.4.9/meson/dot/meson.build --- pdns-recursor-5.2.13/meson/dot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/dot/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +opt_dot = get_option('dns-over-tls') + +if opt_dot.enabled() and not dep_libssl.found() and not dep_gnutls.found() + error('DNS over TLS support was requested but neither OpenSSL libssl nor GnuTLS support is enabled') +endif + +conf.set('HAVE_DNS_OVER_TLS', opt_dot.allowed() and (dep_libssl.found() or dep_gnutls.found()), description: 'DNS over TLS (DoT)') +summary('DNS over TLS', opt_dot.allowed() and (dep_libssl.found() or dep_gnutls.found()), bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/geoip/meson.build pdns-recursor-5.4.9/meson/geoip/meson.build --- pdns-recursor-5.2.13/meson/geoip/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/geoip/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,14 @@ +dep_geoip = dependency('', required: false) + +if get_option('module-geoip') != 'disabled' +dep_geoip = dependency('geoip', required: false) +endif + +conf.set('HAVE_GEOIP', dep_geoip.found(), description: 'GeoIP') + +summary('GeoIP', dep_geoip.found(), bool_yn: true, section: 'GeoIP Backend') + +if dep_geoip.found() + summary('GeoIP Name', dep_geoip.name(), section: 'GeoIP Backend') + summary('GeoIP Version', dep_geoip.version(), section: 'GeoIP Backend') +endif diff -Nru pdns-recursor-5.2.13/meson/gnutls/meson.build pdns-recursor-5.4.9/meson/gnutls/meson.build --- pdns-recursor-5.2.13/meson/gnutls/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/gnutls/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,19 @@ +opt_gnutls = get_option('tls-gnutls') +dep_gnutls = dependency('gnutls', version: '>= 3.1.11', required: opt_gnutls) + +if dep_gnutls.found() + funcs = [ + 'gnutls_memset', + 'gnutls_session_set_verify_cert', + 'gnutls_session_get_verify_cert_status', + 'gnutls_alpn_set_protocols', + ] + + foreach func: funcs + has = cxx.has_function(func, dependencies: dep_gnutls) + conf.set('HAVE_' + func.to_upper(), has, description: 'Have GnuTLS ' + func) + endforeach +endif + +conf.set('HAVE_GNUTLS', dep_gnutls.found(), description: 'GnuTLS') +summary('GnuTLS', dep_gnutls.found(), bool_yn: true, section: 'Crypto') diff -Nru pdns-recursor-5.2.13/meson/gss-tsig/meson.build pdns-recursor-5.4.9/meson/gss-tsig/meson.build --- pdns-recursor-5.2.13/meson/gss-tsig/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/gss-tsig/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +opt = get_option('experimental-gss-tsig') + +dep_krb5 = dependency('krb5', required: opt) +dep_krb5_gssapi = dependency('krb5-gssapi', required: opt) + +found = dep_krb5.found() and dep_krb5_gssapi.found() +conf.set('ENABLE_GSS_TSIG', found, description: 'GSS-TSIG') + +summary('GSS-TSIG', found, bool_yn: true, section: 'GSS-TSIG') +summary('Krb5', dep_krb5.version(), section: 'GSS-TSIG') +summary('Krb5 GSSAPI', dep_krb5_gssapi.version(), section: 'GSS-TSIG') + +dep_gss_tsig = dependency('', required: false) +if found + dep_gss_tsig = declare_dependency( + dependencies: [ + dep_krb5, + dep_krb5_gssapi, + ] + ) +endif diff -Nru pdns-recursor-5.2.13/meson/hardening/control-flow/meson.build pdns-recursor-5.4.9/meson/hardening/control-flow/meson.build --- pdns-recursor-5.2.13/meson/hardening/control-flow/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/control-flow/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +opt_cf = get_option('hardening-experimental-cf') + +support_cf_prot = opt_cf != 'disabled' and cxx.has_argument('-fcf-protection=' + opt_cf) +if support_cf_prot + add_project_arguments('-fcf-protection=' + opt_cf, language: ['c', 'cpp']) +elif opt_cf != 'disabled' + error('Control Flow Protection was explicitly requested but is not supported by the compiler') +endif + +summary('Control Flow Protection', support_cf_prot, bool_yn: true, section: 'Hardening') diff -Nru pdns-recursor-5.2.13/meson/hardening/fortify-source/meson.build pdns-recursor-5.4.9/meson/hardening/fortify-source/meson.build --- pdns-recursor-5.2.13/meson/hardening/fortify-source/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/fortify-source/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,37 @@ +fortify_source_opt = get_option('hardening-fortify-source') +fortify_source = fortify_source_opt != 'disabled' +fortify_source_level = 0 + +if fortify_source and get_option('buildtype') == 'debug' + error('Source fortification was requested but it requires compiling with optimization. ' + + 'A debug buildtype was requested, try setting buildtype=debugoptimized instead') +endif + +if fortify_source + fortify_source_level = 2 + if fortify_source_opt == 'auto' + fortify_source_level = 3 + else + fortify_source_level = fortify_source_opt.to_int() + endif + + variants = [3, 2, 1] + foreach variant: variants + variant_str = variant.to_string() + if fortify_source_level == variant + if cxx.has_argument('-D_FORTIFY_SOURCE=' + variant_str) + add_project_arguments('-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=' + variant_str, language: ['c', 'cpp']) + break + else + fortify_source_level = fortify_source_level - 1 + endif + endif + endforeach +endif + +fortify_source = fortify_source and fortify_source_level != 0 +summary('Source Fortification', fortify_source, bool_yn: true, section: 'Hardening') + +if fortify_source + summary('Source Fortification Level', fortify_source_level, section: 'Hardening') +endif diff -Nru pdns-recursor-5.2.13/meson/hardening/meson.build pdns-recursor-5.4.9/meson/hardening/meson.build --- pdns-recursor-5.2.13/meson/hardening/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,34 @@ +opt_hardening = get_option('hardening') +if opt_hardening.allowed() + hardening_features = [] + + # PIE + opt_pie = get_option('b_pie') + if not opt_pie and opt_hardening.enabled() + error('Hardening was requested but building position independent executables is disabled') + endif + hardening_features += [[opt_pie, 'Building position independent executables (PIEs)']] + conf.set('PIE', opt_pie, description: 'Build a Position Independent Executable (PIE)') + summary('PIE', opt_pie, bool_yn: true, section: 'Hardening') + + subdir('stack-prot') # Stack Protector + subdir('stack-smashing-prot') # Stack-Smashing Protection + subdir('relro') # RELRO + + foreach feature: hardening_features + available = feature[0] + name = feature[1] + + if not available + if opt_hardening.auto() + warning(name + ' is disabled or not supported') + else + error('Failing because ' + name + ' is not supported but hardening was requested') + endif + endif + endforeach +endif + +subdir('fortify-source') # Fortify Source +subdir('control-flow') # Control Flow Protection +subdir('stack-clash-prot') # Stack Clash Protection diff -Nru pdns-recursor-5.2.13/meson/hardening/relro/meson.build pdns-recursor-5.4.9/meson/hardening/relro/meson.build --- pdns-recursor-5.2.13/meson/hardening/relro/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/relro/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,16 @@ +have_relro = true +variants = [ + '-Wl,-z,relro', + '-Wl,-z,now', +] + +foreach variant: variants + if cxx.has_link_argument(variant) + hardening_features += [[true, 'RELRO (' + variant + ')']] + add_project_link_arguments(variant, language: ['c', 'cpp']) + else + have_relro = false + endif +endforeach + +summary('RELRO', have_relro, bool_yn: true, section: 'Hardening') diff -Nru pdns-recursor-5.2.13/meson/hardening/stack-clash-prot/meson.build pdns-recursor-5.4.9/meson/hardening/stack-clash-prot/meson.build --- pdns-recursor-5.2.13/meson/hardening/stack-clash-prot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/stack-clash-prot/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +opt_scp = get_option('hardening-experimental-scp') + +support_scp = not opt_scp.disabled() and cxx.has_argument('-fstack-clash-protection') +if support_scp + add_project_arguments('-fstack-clash-protection', language: ['c', 'cpp']) +elif opt_scp.enabled() + error('Stack Clash Protection was explicitly requested but is not supported by the compiler') +endif + +summary('Stack Clash Protection', support_scp, bool_yn: true, section: 'Hardening') diff -Nru pdns-recursor-5.2.13/meson/hardening/stack-prot/meson.build pdns-recursor-5.4.9/meson/hardening/stack-prot/meson.build --- pdns-recursor-5.2.13/meson/hardening/stack-prot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/stack-prot/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +support_stack_protector = cxx.has_argument('-fstack-protector') + +if support_stack_protector + add_project_arguments('-fstack-protector', language: ['c', 'cpp']) +endif + +hardening_features += [[support_stack_protector, 'Stack Protector']] +summary('Stack Protector', support_stack_protector, bool_yn: true, section: 'Hardening') diff -Nru pdns-recursor-5.2.13/meson/hardening/stack-smashing-prot/meson.build pdns-recursor-5.4.9/meson/hardening/stack-smashing-prot/meson.build --- pdns-recursor-5.2.13/meson/hardening/stack-smashing-prot/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/hardening/stack-smashing-prot/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +support_stack_smashing_protector = cxx.has_argument('--param=ssp-buffer-size=4') +if support_stack_smashing_protector + add_project_arguments('--param=ssp-buffer-size=4', language: ['c', 'cpp']) +endif + +hardening_features += [[support_stack_smashing_protector, 'Stack Smashing Protection']] +summary('Stack Smashing Protection', support_stack_smashing_protector, bool_yn: true, section: 'Hardening') +if support_stack_smashing_protector + summary('SSP Buffer Size', 4, section: 'Hardening') +endif diff -Nru pdns-recursor-5.2.13/meson/ipcipher/meson.build pdns-recursor-5.4.9/meson/ipcipher/meson.build --- pdns-recursor-5.2.13/meson/ipcipher/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/ipcipher/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +opt_ipcipher = get_option('ipcipher') + +if not dep_libcrypto.found() and opt_ipcipher.enabled() + error('ipcipher support was requested but libcrypto is not available') +endif + +enable_ipcipher = dep_libcrypto.found() and not opt_ipcipher.disabled() +conf.set('HAVE_IPCIPHER', enable_ipcipher, description: 'ipcipher support') +summary('ipcipher', enable_ipcipher, bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/ldap/meson.build pdns-recursor-5.4.9/meson/ldap/meson.build --- pdns-recursor-5.2.13/meson/ldap/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/ldap/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,68 @@ +dep_ldap = dependency('', required: false) + +if get_option('module-ldap') != 'disabled' + dep_ldap_internal = dependency('ldap', required: false) + dep_lber_internal = dependency('lber', required: false) + dep_krb5_internal = dependency('krb5', required: true) + + if not dep_ldap_internal.found() + lib_ldap_internal = cxx.find_library('ldap', disabler: true, required: true) + dep_ldap_internal = declare_dependency(dependencies: lib_ldap_internal) + endif + if not dep_lber_internal.found() + lib_lber_internal = cxx.find_library('lber', disabler: true, required: true) + dep_lber_internal = declare_dependency(dependencies: lib_lber_internal) + endif + + conf.set('HAVE_LIBLDAP', dep_ldap_internal.found(), description: 'Have libldap') + + have_ldap_initialize = cxx.has_function('ldap_initialize', dependencies: dep_ldap_internal) + conf.set( + 'HAVE_LDAP_INITIALIZE', + have_ldap_initialize, + description: 'Have ldap_initialize', + ) + + have_ldap_sasl_bind = cxx.has_function('ldap_sasl_bind', dependencies: dep_ldap_internal) + conf.set( + 'HAVE_LDAP_SASL_BIND', + have_ldap_initialize, + description: 'Have ldap_sasl_bind', + ) + + have_krb5_get_init_creds_opt_set_default_flags = cxx.has_function( + 'krb5_get_init_creds_opt_set_default_flags', + dependencies: dep_krb5_internal, + ) + conf.set( + 'HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS', + have_krb5_get_init_creds_opt_set_default_flags, + description: 'Have krb5_get_init_creds_opt_set_default_flags', + ) + + dep_ldap = declare_dependency( + dependencies: [ + dep_ldap_internal, + dep_lber_internal, + dep_krb5_internal, + ], + ) + + summary('LDAP', dep_ldap_internal.found(), bool_yn: true, section: 'LDAP') + if dep_ldap_internal.found() + summary('LDAP Name', dep_ldap_internal.name(), section: 'LDAP') + summary('LDAP Version', dep_ldap_internal.version(), section: 'LDAP') + endif + + summary('LBER', dep_lber_internal.found(), bool_yn: true, section: 'LDAP') + if dep_lber_internal.found() + summary('LBER Name', dep_lber_internal.name(), section: 'LDAP') + summary('LBER Version', dep_lber_internal.version(), section: 'LDAP') + endif + + summary('Krb5', dep_krb5_internal.found(), bool_yn: true, section: 'LDAP') + if dep_krb5_internal.found() + summary('Krb5 Name', dep_krb5_internal.name(), section: 'LDAP') + summary('Krb5 Version', dep_krb5_internal.version(), section: 'LDAP') + endif +endif diff -Nru pdns-recursor-5.2.13/meson/libcap/meson.build pdns-recursor-5.4.9/meson/libcap/meson.build --- pdns-recursor-5.2.13/meson/libcap/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcap/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +opt_libcap = get_option('libcap') +dep_libcap = dependency('libcap', required: opt_libcap) + +conf.set('HAVE_LIBCAP', dep_libcap.found(), description: 'libcap support') +summary('libcap support', dep_libcap.found(), bool_yn: true, section: 'Capabilities') diff -Nru pdns-recursor-5.2.13/meson/libcrypto/bn_new.cc pdns-recursor-5.4.9/meson/libcrypto/bn_new.cc --- pdns-recursor-5.2.13/meson/libcrypto/bn_new.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcrypto/bn_new.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +#include + +int main() +{ + BN_new(); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/libcrypto/ecdsa/meson.build pdns-recursor-5.4.9/meson/libcrypto/ecdsa/meson.build --- pdns-recursor-5.2.13/meson/libcrypto/ecdsa/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcrypto/ecdsa/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,33 @@ +prefix = ''' +#include +#include +''' +found = cxx.has_header( + 'openssl/ecdsa.h', + dependencies: dep_libcrypto, + prefix: prefix, + required: false +) + +if found + syms = [ + 'NID_X9_62_prime256v1', + 'NID_secp384r1', + ] + + foreach sym: syms + found = cxx.has_header_symbol( + 'openssl/evp.h', + sym, + dependencies: dep_libcrypto, + required: false + ) + + if not found + break + endif + endforeach +endif + +conf.set('HAVE_LIBCRYPTO_ECDSA', found, description: 'OpenSSL libcrypto ECDSA') +summary('OpenSSL libcrypto ECDSA', found, bool_yn: true, section: 'Crypto') diff -Nru pdns-recursor-5.2.13/meson/libcrypto/eddsa/meson.build pdns-recursor-5.4.9/meson/libcrypto/eddsa/meson.build --- pdns-recursor-5.2.13/meson/libcrypto/eddsa/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcrypto/eddsa/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,24 @@ +syms = [ + 'ED25519', + 'ED448', +] + +found = false +foreach sym: syms + has = cxx.has_header_symbol( + 'openssl/evp.h', + 'NID_' + sym, + dependencies: dep_libcrypto, + required: false, + ) + + conf.set('HAVE_LIBCRYPTO_' + sym, has, description: 'OpenSSL libcrypto ' + sym) + summary('OpenSSL libcrypto ' + sym, has, bool_yn: true, section: 'Crypto') + + if has + found = true + endif +endforeach + +conf.set('HAVE_LIBCRYPTO_EDDSA', found, description: 'OpenSSL EdDSA support') +summary('OpenSSL libcrypto EdDSA', found, bool_yn: true, section: 'Crypto') diff -Nru pdns-recursor-5.2.13/meson/libcrypto/meson.build pdns-recursor-5.4.9/meson/libcrypto/meson.build --- pdns-recursor-5.2.13/meson/libcrypto/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcrypto/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,118 @@ +opt_libcrypto = get_option('signers-libcrypto') +opt_libcrypto_path = get_option('signers-libcrypto-path') +dep_libcrypto = dependency('', required: false) + +ssldirs = [] + +if opt_libcrypto.disabled() + if opt_libcrypto_path != '' + warning('The signers-libcrypto option is set to `disabled` ' + + 'but a path (' + opt_libcrypto_path + ') was given ' + + 'for signers-libcrypto-path: It is going to be ignored.') + endif + + summary('OpenSSL libcrypto', false, bool_yn: true, section: 'Crypto') + subdir_done() +endif + +# Give precedence to the custom path passed in by the user. If not, the try to find +# libcrypto using the mechanisms provided by meson (e.g. pkg-config). If that cannot be +# found, then look in some hard-coded paths below. +if opt_libcrypto_path == '' + dep_libcrypto = dependency('libcrypto', required: false) +else + ssldirs = [opt_libcrypto_path] +endif + +if not dep_libcrypto.found() + warning('Could not find the libcrypto dependency, going to try to find it manually') + + if ssldirs.length() == 0 + # Could not find libcrypto through pkg-config and no custom directory was passed to + # find the library and its headers, so try to find it in some default locations. + ssldirs = [ + '/usr/local/ssl', + '/usr/lib/ssl', + '/usr/ssl', + '/usr/pkg', + '/usr/local', + '/usr' + ] + endif + + foreach dir: ssldirs + have = cxx.has_header(dir / 'include/openssl/crypto.h') + if have + dep_libcrypto = declare_dependency( + link_args: ['-L' + dir / 'lib', '-lcrypto'], + include_directories: include_directories(dir / 'include', is_system: false), + ) + break + endif + endforeach +endif + +if not dep_libcrypto.found() + err_msg = 'Could not find libcrypto in ' + ', '.join(ssldirs) + + if opt_libcrypto == 'auto' + # We could not find libcrypto anywhere, and the user did not require it. + warning(err_msg) + summary('OpenSSL libcrypto', false, bool_yn: true, section: 'Crypto') + subdir_done() + endif + + error(err_msg) +endif + +if not cxx.links(fs.read('bn_new.cc'), name: 'libcrypto test program', dependencies: dep_libcrypto) + err_msg = 'Cannot link against libcrypto' + + if opt_libcrypto == 'auto' + # We could not link against libcrypto, and the user did not require it. + warning(err_msg) + summary('OpenSSL libcrypto', false, bool_yn: true, section: 'Crypto') + subdir_done() + endif + + error(err_msg) +endif + +funcs = [ + 'RAND_bytes', + 'RAND_pseudo_bytes', + 'CRYPTO_memcmp', + 'OPENSSL_init_crypto', + 'EVP_MD_CTX_new', + 'EVP_MD_CTX_free', + 'RSA_get0_key', + 'OCSP_basic_sign', +] + +foreach func: funcs + has = cxx.has_function(func, dependencies: dep_libcrypto) + conf.set('HAVE_' + func.to_upper(), has, description: 'Have libcrypto ' + func) +endforeach + +prefix = ''' +#include +#include +''' +has = cxx.has_header_symbol( + 'openssl/kdf.h', + 'EVP_PKEY_CTX_set1_scrypt_salt', + dependencies: dep_libcrypto, + prefix: prefix, + required: false, +) +conf.set( + 'HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT', + has, + description: 'Have libcrypto EVP_PKEY_CTX_set1_scrypt_salt', +) + +conf.set('HAVE_LIBCRYPTO', dep_libcrypto.found(), description: 'OpenSSL libcrypto-based signers') +summary('OpenSSL libcrypto', dep_libcrypto.found(), bool_yn: true, section: 'Crypto') + +subdir('ecdsa') # ECDSA signers +subdir('eddsa') # EDDSA signers diff -Nru pdns-recursor-5.2.13/meson/libcurl/meson.build pdns-recursor-5.4.9/meson/libcurl/meson.build --- pdns-recursor-5.2.13/meson/libcurl/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libcurl/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -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 -Nru pdns-recursor-5.2.13/meson/libdir/meson.build pdns-recursor-5.4.9/meson/libdir/meson.build --- pdns-recursor-5.2.13/meson/libdir/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libdir/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1 @@ +conf.set_quoted('PKGLIBDIR', get_option('libdir'), description: 'Modules directory') diff -Nru pdns-recursor-5.2.13/meson/libresolv/meson.build pdns-recursor-5.4.9/meson/libresolv/meson.build --- pdns-recursor-5.2.13/meson/libresolv/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libresolv/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,22 @@ +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 + else + lib_resolv = cxx.find_library('resolv', disabler: true, required: false) + if lib_resolv.found() + if cxx.links(prog, name: '-lresolv is needed', dependencies: lib_resolv) + need = true + dep_libresolv = declare_dependency(dependencies: lib_resolv) + endif + endif + endif +else + need = true +endif + +summary('Need -lresolv', need, bool_yn: true, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/libsnmp/meson.build pdns-recursor-5.4.9/meson/libsnmp/meson.build --- pdns-recursor-5.2.13/meson/libsnmp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libsnmp/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,40 @@ +opt_libsnmp = get_option('snmp') +dep_libsnmp = dependency('', required: false) + +if opt_libsnmp.allowed() + snmp_config = find_program('net-snmp-config', required: opt_libsnmp) + if snmp_config.found() + snmp_ldflags_res = run_command(snmp_config, '--netsnmp-agent-libs', check: false) + if snmp_ldflags_res.returncode() == 0 + snmp_ldflags = snmp_ldflags_res.stdout().strip().split() + + dep_libsnmp = declare_dependency( + link_args: snmp_ldflags, + ) + + 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, prefix: '''#include + #include + #include + #include + #include + #include ''') + conf.set(define, have_func, description: 'Have libsnmp ' + func) + endforeach + endif + endif + endif +endif + +if opt_libsnmp.enabled() and not dep_libsnmp.found() + error('SNMP support enabled but not available') +endif + +conf.set('HAVE_NET_SNMP', dep_libsnmp.found(), description: 'libsnmp') +summary('SNMP', dep_libsnmp.found(), bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/libsodium/meson.build pdns-recursor-5.4.9/meson/libsodium/meson.build --- pdns-recursor-5.2.13/meson/libsodium/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libsodium/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +opt_libsodium = get_option('signers-libsodium') +dep_libsodium = dependency('libsodium', required: opt_libsodium) + +if dep_libsodium.found() + funcs = [ + 'crypto_box_easy_afternm', + 'crypto_box_curve25519xchacha20poly1305_easy', + 'randombytes_stir', + 'sodium_memcmp', + 'crypto_shorthash' + ] + + foreach func: funcs + define = 'HAVE_' + func.to_upper() + have_func = cxx.has_function(func, dependencies: dep_libsodium) + conf.set(define, have_func, description: 'Have libsodium ' + func) + endforeach +endif + +conf.set('HAVE_LIBSODIUM', dep_libsodium.found(), description: 'libsodium-based signers') +summary('libsodium signers', dep_libsodium.found(), bool_yn: true, section: 'Crypto') diff -Nru pdns-recursor-5.2.13/meson/libssl/meson.build pdns-recursor-5.4.9/meson/libssl/meson.build --- pdns-recursor-5.2.13/meson/libssl/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libssl/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,48 @@ +opt_libssl = get_option('tls-libssl') +opt_libssl_dir = get_option('tls-libssl-dir') + + +if opt_libssl_dir != '' + dep_libssl = declare_dependency( + dependencies: [dep_libcrypto], + include_directories: [opt_libssl_dir / 'include'], + link_args: ['-L' + opt_libssl_dir / 'lib', '-lssl'], + ) +else + dep_libssl = dependency('libssl', required: opt_libssl) +endif + +if dep_libssl.found() + funcs = [ + 'SSL_CTX_set_ciphersuites', + 'SSL_CTX_set_num_tickets', + 'SSL_CTX_set_keylog_callback', + 'SSL_CTX_get0_privatekey', + 'SSL_set_hostflags', + 'SSL_CTX_set_alpn_protos', + 'SSL_CTX_set_next_proto_select_cb', + 'SSL_get0_alpn_selected', + 'SSL_get0_next_proto_negotiated', + 'SSL_CTX_set_alpn_select_cb', + 'SSL_CTX_use_cert_and_key', + ] + + foreach func: funcs + has = cxx.has_function(func, dependencies: dep_libssl) + conf.set('HAVE_' + func.to_upper(), has, description: 'Have OpenSSL libssl ' + func) + endforeach + + has = cxx.has_header_symbol( + 'openssl/ssl.h', + 'SSL_CTX_set_min_proto_version', + dependencies: dep_libssl, + ) + conf.set( + 'HAVE_SSL_CTX_SET_MIN_PROTO_VERSION', + has, + description: 'Have OpenSSL libssl SSL_CTX_set_min_proto_version', + ) +endif + +conf.set('HAVE_LIBSSL', dep_libssl.found(), description: 'OpenSSL libssl') +summary('OpenSSL libssl', dep_libssl.found(), bool_yn: true, section: 'Crypto') diff -Nru pdns-recursor-5.2.13/meson/libssl-engines/meson.build pdns-recursor-5.4.9/meson/libssl-engines/meson.build --- pdns-recursor-5.2.13/meson/libssl-engines/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libssl-engines/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +conf.set( + 'OPENSSL_NO_ENGINE', + true, + description: 'Disable engine support in libssl.cc', +) diff -Nru pdns-recursor-5.2.13/meson/libsystemd/meson.build pdns-recursor-5.4.9/meson/libsystemd/meson.build --- pdns-recursor-5.2.13/meson/libsystemd/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/libsystemd/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,14 @@ +opt_systemd = get_option('systemd-service') + +if opt_systemd.allowed() + dep_libsystemd = dependency('libsystemd', required: opt_systemd) +else + dep_libsystemd = dependency('', required: false) +endif + +conf.set('HAVE_SYSTEMD', dep_libsystemd.found(), description: 'libsystemd') +if dep_libsystemd.found() + summary('Lib Version', dep_libsystemd.version(), section: 'Systemd') +endif + +summary('libsystemd', dep_libsystemd.found(), bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/lmdb/meson.build pdns-recursor-5.4.9/meson/lmdb/meson.build --- pdns-recursor-5.2.13/meson/lmdb/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/lmdb/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,11 @@ +dep_lmdb = dependency('', required: false) + +if get_option('module-lmdb') != 'disabled' + dep_lmdb = dependency('lmdb', required: true) +endif + +conf.set('HAVE_LMDB', dep_lmdb.found(), description: 'Whether we have LMDB') +summary('LMDB', dep_lmdb.found(), bool_yn: true, section: 'LMDB') +if dep_lmdb.found() + summary('Version', dep_lmdb.version(), bool_yn: true, section: 'LMDB') +endif diff -Nru pdns-recursor-5.2.13/meson/lua/meson.build pdns-recursor-5.4.9/meson/lua/meson.build --- pdns-recursor-5.2.13/meson/lua/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/lua/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,54 @@ +opt_lua = get_option('lua') +dep_lua = dependency('', required: false) + +if opt_lua == 'auto' or opt_lua == 'luajit' + dep_lua = dependency( + 'luajit', + version: '>= 2.0.2', + required: opt_lua == 'luajit', + not_found_message: 'LuaJIT not found', + ) +endif + +if not dep_lua.found() and (opt_lua == 'auto' or opt_lua == 'lua') + variants = [ + 'lua5.4', + 'lua-5.4', + 'lua54', + 'lua5.3', + 'lua-5.3', + 'lua53', + 'lua5.2', + 'lua-5.2', + 'lua52', + 'lua5.1', + 'lua-5.1', + 'lua51', + 'lua', + ] + + foreach variant: variants + dep_lua = dependency(variant, version: '>= 5.1', required: false) + if dep_lua.found() + break + endif + endforeach +endif + +if not dep_lua.found() and opt_lua != 'lua' and opt_lua.startswith('lua') + dep_lua = dependency(opt_lua, version: '>= 5.1', required: false) +endif + +if not dep_lua.found() + error('No Lua implementation was found') +endif + +have_luahpp = cxx.has_header('lua.hpp', dependencies: dep_lua) + +conf.set('HAVE_LUA', dep_lua.found(), description: 'Lua') +conf.set('HAVE_LUA_HPP', have_luahpp, description: 'Have ') + +summary('Lua', dep_lua.found(), bool_yn: true, section: 'Lua') +summary('Implementation', dep_lua.name(), section: 'Lua') +summary('Version', dep_lua.version(), section: 'Lua') +summary('Have ', have_luahpp, bool_yn: true, section: 'Lua') diff -Nru pdns-recursor-5.2.13/meson/lua-records/meson.build pdns-recursor-5.4.9/meson/lua-records/meson.build --- pdns-recursor-5.2.13/meson/lua-records/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/lua-records/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,32 @@ +opt_lua_records = get_option('lua-records') + +dep_libcurl = dependency('libcurl', version: '>= 7.21.3', required: opt_lua_records) +conf.set('HAVE_LIBCURL', dep_libcurl.found(), description: 'Whether we have libcurl') + +opt_lua_enabled = opt_lua in ['auto', 'luajit', 'lua', 'lua51', 'lua-5.1', 'lua5.1', 'lua52', 'lua-5.2', 'lua5.2', 'lua53', 'lua-5.3', 'lua5.3', 'lua54', 'lua-5.4', 'lua5.4'] + +if not opt_lua_enabled + error('Lua records require Lua, make sure it is enabled') +endif + +if not dep_lua.found() + error('Lua records require Lua, make sure it is detected on your system') +endif + +have_lua_records = opt_lua_records and \ + opt_lua_enabled and \ + dep_lua.found() and \ + dep_libcurl.found() + +dep_lua_records = dependency('', required: false) +if have_lua_records + dep_lua_records = declare_dependency( + dependencies: [ + dep_lua, + dep_libcurl, + ], + ) +endif + +conf.set('HAVE_LUA_RECORDS', have_lua_records, description: 'Lua-based records') +summary('Lua-based Records', have_lua_records, bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/malloc-trace/meson.build pdns-recursor-5.4.9/meson/malloc-trace/meson.build --- pdns-recursor-5.2.13/meson/malloc-trace/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/malloc-trace/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +opt_malloc_trace = get_option('malloc-trace') +conf.set('MALLOC_TRACE', opt_malloc_trace, description: 'malloc-trace') diff -Nru pdns-recursor-5.2.13/meson/mmap/meson.build pdns-recursor-5.4.9/meson/mmap/meson.build --- pdns-recursor-5.2.13/meson/mmap/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/mmap/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +mman_h = cxx.has_header('sys/mman.h', required: false) +have_mmap = mman_h and cxx.has_function('mmap', prefix: '''#include ''') + +conf.set('HAVE_MMAP', have_mmap, description: 'Have mmap') + +summary('Have ', mman_h, bool_yn: true, section: 'Function mmap') +summary('mmap', have_mmap, bool_yn: true, section: 'Function mmap') diff -Nru pdns-recursor-5.2.13/meson/mmdb/meson.build pdns-recursor-5.4.9/meson/mmdb/meson.build --- pdns-recursor-5.2.13/meson/mmdb/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/mmdb/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,14 @@ +dep_mmdb = dependency('', required: false) + +if get_option('module-geoip') != 'disabled' + dep_mmdb = dependency('libmaxminddb', required: false) +endif + +conf.set('HAVE_MMDB', dep_mmdb.found(), description: 'MaxMindDB') + +summary('MaxMindDB', dep_mmdb.found(), bool_yn: true, section: 'GeoIP Backend') + +if dep_mmdb.found() + summary('MaxMindDB Name', dep_mmdb.name(), section: 'GeoIP Backend') + summary('MaxMindDB Version', dep_mmdb.version(), section: 'GeoIP Backend') +endif diff -Nru pdns-recursor-5.2.13/meson/mysql/meson.build pdns-recursor-5.4.9/meson/mysql/meson.build --- pdns-recursor-5.2.13/meson/mysql/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/mysql/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,36 @@ +dep_mysql = dependency('', required: false) + +if get_option('module-gmysql') != 'disabled' + dep_mysql = dependency('libmysql', required: false) + if not dep_mysql.found() + dep_mysql = dependency('libmariadb', required: false) + endif + + if not dep_mysql.found() + mysql_config = find_program('mysql_config', required: false) + if not mysql_config.found() + mysql_config = find_program('mariadb_config', required: true) + endif + + mysql_cflags_res = run_command(mysql_config, '--cflags', check: true) + mysql_cflags = mysql_cflags_res.stdout().strip().split() + + mysql_ldflags_res = run_command(mysql_config, '--libs', check: true) + mysql_ldflags = mysql_ldflags_res.stdout().strip().split() + + mysql_version_res = run_command(mysql_config, '--version', check: false) + mysql_version = mysql_version_res.stdout().strip() + + dep_mysql = declare_dependency( + compile_args: mysql_cflags, + link_args: mysql_ldflags, + version: mysql_version, + ) + endif +endif + +summary('MySQL/MariaDB', dep_mysql.found(), bool_yn: true, section: 'MySQL') + +if dep_mysql.found() + summary('Version', dep_mysql.version(), section: 'MySQL') +endif diff -Nru pdns-recursor-5.2.13/meson/net-libs/meson.build pdns-recursor-5.4.9/meson/net-libs/meson.build --- pdns-recursor-5.2.13/meson/net-libs/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/net-libs/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,44 @@ +netlib_deps = [] + +variants = [ + ['inet_aton', 'resolv'], + ['gethostbyname', 'nsl'], + ['socket', 'socket'], + ['gethostent', 'nsl'], +] + +foreach variant: variants + func_name = variant[0] + lib_name = variant[1] + + found = cxx.has_function(func_name) + if not found + lib = cxx.find_library(lib_name, required: true) + if not cxx.has_function(func_name, dependencies: lib) + error('Cannot find function ' + func_name + ', searched library `' + lib_name + '`') + endif + netlib_deps += lib + found = lib.name() + ' ' + lib.version() + endif + + summary(func_name, found, bool_yn: true, section: 'Networking Functions') +endforeach + +dep_netlibs = declare_dependency(dependencies: netlib_deps) + +variants = [ + 'recvmmsg', + 'sendmmsg', + 'accept4', +] + +foreach variant: variants + found = cxx.has_function(variant) + define = 'HAVE_' + variant.to_upper() + conf.set(define, found, description: 'Have ' + variant) + summary(variant, found, bool_yn: true, section: 'Networking Functions') +endforeach + +declared = cxx.has_header_symbol('ifaddrs.h', 'getifaddrs') +conf.set('HAVE_GETIFADDRS', declared, description: 'Have getifaddrs') +summary('getifaddrs', declared, bool_yn: true, section: 'Networking Functions') diff -Nru pdns-recursor-5.2.13/meson/nod/meson.build pdns-recursor-5.4.9/meson/nod/meson.build --- pdns-recursor-5.2.13/meson/nod/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/nod/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,22 @@ +opt_nod = get_option('nod') + +if opt_nod.enabled() + if not dep_boost_filesystem.found() + error('NOD support was requested but boost filesystem module not found') + endif + if not dep_probds.found() + error('NOD support was requested but probds not found') + endif +endif + +enable_nod = opt_nod.allowed() and dep_boost_filesystem.found() and dep_probds.found() +if enable_nod + dep_nod = declare_dependency( + dependencies: [dep_boost_filesystem, dep_probds], + ) +else + dep_nod = dependency('', required: false) +endif + +conf.set('NOD_ENABLED', enable_nod, description: 'NOD') +summary('NOD', enable_nod, bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/odbc/meson.build pdns-recursor-5.4.9/meson/odbc/meson.build --- pdns-recursor-5.2.13/meson/odbc/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/odbc/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,30 @@ +dep_odbc = dependency('', required: false) + +if get_option('module-godbc') != 'disabled' + dep_odbc = dependency('odbc', required: false) + + if not dep_odbc.found() + odbc_config = find_program('odbc_config', required: true) + + odbc_cflags_res = run_command(odbc_config, '--cflags', check: true) + odbc_cflags = odbc_cflags_res.stdout().strip().split() + + odbc_ldflags_res = run_command(odbc_config, '--libs', check: true) + odbc_ldflags = odbc_ldflags_res.stdout().strip().split() + + odbc_version_res = run_command(odbc_config, '--version', check: true) + odbc_version = odbc_version_res.stdout().strip() + + dep_odbc = declare_dependency( + compile_args: odbc_cflags, + link_args: odbc_ldflags, + version: odbc_version, + ) + endif +endif + +summary('ODBC', dep_odbc.found(), bool_yn: true, section: 'ODBC') + +if dep_odbc.found() + summary('Version', dep_odbc.version(), section: 'ODBC') +endif diff -Nru pdns-recursor-5.2.13/meson/pgsql/meson.build pdns-recursor-5.4.9/meson/pgsql/meson.build --- pdns-recursor-5.2.13/meson/pgsql/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pgsql/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,44 @@ +dep_pgsql = dependency('', required: false) + +if get_option('module-gpgsql') != 'disabled' + dep_pgsql = dependency('libpq', required: false) + + if not dep_pgsql.found() + pg_config = find_program('pg_config', required: true) + + pg_includedir_res = run_command(pg_config, '--includedir', check: true) + pg_includedir = include_directories(pg_includedir_res.stdout().strip()) + + # pg_cflags_res = run_command(pg_config, '--cflags', check: true) + # pg_cflags = pg_cflags_res.stdout().strip().split() + + # pg_cppflags_res = run_command(pg_config, '--cppflags', check: true) + # pg_cppflags = pg_cppflags_res.stdout().strip().split() + + # pg_ldflags_res = run_command(pg_config, '--libs', check: true) + # pg_ldflags = pg_ldflags_res.stdout().strip().split() + + pg_libdir_res = run_command(pg_config, '--libdir', check: true) + pg_libdir = pg_libdir_res.stdout().strip() + + # pg_libs_res = run_command(pg_config, '--libs', check: true) + # pg_libs = pg_libs_res.stdout().strip().split() + + pg_version_res = run_command(pg_config, '--version', check: true) + pg_version = pg_version_res.stdout().strip().split()[1] + + dep_pgsql = declare_dependency( + # compile_args: pg_cflags + pg_cppflags, + # link_args: pg_ldflags, + include_directories: pg_includedir, + link_args: ['-L' + pg_libdir, '-lpq'], + version: pg_version, + ) + endif +endif + +summary('PostgreSQL', dep_pgsql.found(), bool_yn: true, section: 'PostgreSQL') + +if dep_pgsql.found() + summary('Version', dep_pgsql.version(), section: 'PostgreSQL') +endif diff -Nru pdns-recursor-5.2.13/meson/pkcs11/meson.build pdns-recursor-5.4.9/meson/pkcs11/meson.build --- pdns-recursor-5.2.13/meson/pkcs11/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pkcs11/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,15 @@ +opt_pkcs11 = get_option('experimental-pkcs11') +dep_pkcs11 = dependency('', required: false) +have_p11kit1 = false +have_p11kit1_v2 = false + +if opt_pkcs11.enabled() or opt_pkcs11.auto() + dep_pkcs11 = dependency('p11-kit-1', required: opt_pkcs11) + have_p11kit1 = dep_pkcs11.found() + + prog = fs.read('p11_kit_module_for_name.cc') + have_p11kit1_v2 = cxx.links(prog, dependencies: dep_pkcs11, name: 'we can link to p11kit1') +endif + +conf.set('HAVE_P11KIT1', have_p11kit1, description: 'Have p11-kit-1') +conf.set('HAVE_P11KIT1_V2', have_p11kit1_v2, description: 'Have p11-kit-1 0.20 or newer') diff -Nru pdns-recursor-5.2.13/meson/pkcs11/p11_kit_module_for_name.cc pdns-recursor-5.4.9/meson/pkcs11/p11_kit_module_for_name.cc --- pdns-recursor-5.2.13/meson/pkcs11/p11_kit_module_for_name.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pkcs11/p11_kit_module_for_name.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +#include + +int main() +{ + __attribute__((unused)) void* foo = p11_kit_module_for_name(nullptr, nullptr); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/platform/meson.build pdns-recursor-5.4.9/meson/platform/meson.build --- pdns-recursor-5.2.13/meson/platform/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/platform/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,64 @@ +platforms = [ + { + 'name': 'linux', + 'config-defines': [{ 'name': 'HAVE_LINUX', 'description': 'On Linux' }], + }, + { + 'name': 'darwin', + 'config-defines': [{ 'name': 'HAVE_DARWIN', 'description': 'On Darwin/MacOS' }], + 'cmdline-defines': ['__APPLE_USE_RFC_3542', '_XOPEN_SOURCE', '_DARWIN_C_SOURCE'], + }, + { + 'name': 'openbsd', + 'config-defines': [{ 'name': 'HAVE_OPENBSD', 'description': 'On OpenBSD' }], + }, + { + 'name': 'freebsd', + 'config-defines': [{ 'name': 'HAVE_FREEBSD', 'description': 'On FreeBSD' }], + }, + { + 'name': 'sunos', + 'config-defines': [ + { 'name': 'HAVE_SOLARIS', 'description': 'On Solaris/SunOS' }, + { 'name': 'NEED_POSIX_TYPEDEF', 'description': 'POSIX typedefs need to be defined' }, + { 'name': 'NEED_INET_NTOP_PROTO', 'description': 'OS is so broken that it needs an additional prototype' }, + ], + 'cmdline-defines': ['_REENTRANT'], + 'libraries': ['posix4'], + }, +] + +platform_deps = [] + +foreach platform: platforms + name = platform['name'] + set_variable('have_' + name, system == name) + + config_defines = 'config-defines' in platform ? platform['config-defines'] : [] + cmdline_defines = 'cmdline-defines' in platform ? platform['cmdline-defines'] : [] + libraries = 'libraries' in platform ? platform['libraries'] : [] + + if system == name + platform_defines = [] + foreach define: config_defines + define_name = define['name'] + define_desc = define['description'] + conf.set(define_name, true, description: define_desc) + platform_defines += define_name + endforeach + + foreach cmdline_define: cmdline_defines + add_project_arguments('-D' + cmdline_define, language: ['c', 'cpp']) + endforeach + + foreach library: libraries + platform_deps += cxx.find_library(library, required: true) + endforeach + + summary('Platform Defines', platform_defines, section: 'System') + endif +endforeach + +dep_platform = declare_dependency( + dependencies: platform_deps, +) diff -Nru pdns-recursor-5.2.13/meson/prog-curl/meson.build pdns-recursor-5.4.9/meson/prog-curl/meson.build --- pdns-recursor-5.2.13/meson/prog-curl/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/prog-curl/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,3 @@ +require_curl = get_option('module-remote') != 'disabled' and get_option('unit-tests-backends') +curl = find_program('curl', required: require_curl) +summary('cURL', curl.found(), bool_yn: true, section: 'Programs') diff -Nru pdns-recursor-5.2.13/meson/pthread-headers/meson.build pdns-recursor-5.4.9/meson/pthread-headers/meson.build --- pdns-recursor-5.2.13/meson/pthread-headers/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-headers/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,18 @@ +dep_threads = dependency('threads') + +have_pthread_h = cxx.check_header( + 'pthread.h', + dependencies: dep_threads, + required: true, +) +have_pthread_np_h = cxx.check_header( + 'pthread_np.h', + dependencies: dep_threads, + prefix: '#include ', +) + +conf.set('HAVE_PTHREAD_NP_H', have_pthread_np_h, description: 'Have ') + +summary('Threads', dep_threads.found(), bool_yn: true, section: 'POSIX Threads') +summary('Have ', have_pthread_h, bool_yn: true, section: 'POSIX Threads') +summary('Have ', have_pthread_np_h, bool_yn: true, section: 'POSIX Threads') diff -Nru pdns-recursor-5.2.13/meson/pthread-np/meson.build pdns-recursor-5.4.9/meson/pthread-np/meson.build --- pdns-recursor-5.2.13/meson/pthread-np/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-np/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -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 diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/meson.build pdns-recursor-5.4.9/meson/pthread-setname/meson.build --- pdns-recursor-5.2.13/meson/pthread-setname/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,57 @@ +variants = [ + [ + '2-arg pthread_setname_np', + 'HAVE_PTHREAD_SETNAME_NP_2', + 'pthread_setname_np takes 2 arguments (Linux/glibc, QNX, IBM)', + fs.read('pthread_setname_np_2args.cc'), + ], + [ + '2-arg pthread_set_name_np', + 'HAVE_PTHREAD_SET_NAME_NP_2', + 'pthread_set_name_np takes 2 arguments and does not return void (FreeBSD, OpenBSD)', + fs.read('pthread_set_name_np_2args.cc'), + ], + [ + '2-arg void pthread_set_name_np', + 'HAVE_PTHREAD_SET_NAME_NP_2_VOID', + 'pthread_set_name_np takes 2 arguments and returns void (FreeBSD, OpenBSD)', + fs.read('pthread_set_name_np_void_2args.cc'), + ], + [ + '1-arg pthread_setname_np', + 'HAVE_PTHREAD_SETNAME_NP_1', + 'pthread_setname_np takes 1 argument (Darwin, MacOS)', + fs.read('pthread_setname_np_1arg.cc'), + ], + [ + '3-arg pthread_setname_np', + 'HAVE_PTHREAD_SETNAME_NP_3', + 'pthread_setname_np takes 3 arguments (NetBSD)', + fs.read('pthread_setname_np_3args.cc'), + ], +] + +found = false +foreach variant: variants + variant_name = variant[0] + variant_define = variant[1] + variant_description = variant[2] + variant_program = variant[3] + + if cxx.links( + variant_program, + name: variant_name, + dependencies: dep_threads, + args: have_pthread_np_h ? ['-DHAVE_PTHREAD_NP_H'] : [] + ) + found = true + conf.set(variant_define, true, description: variant_description) + summary('pthread_setname Variant', variant_define, section: 'POSIX Threads') + summary('Description', variant_description, section: 'POSIX Threads') + break + endif +endforeach + +if not found + error('Could not find a suitable pthread_setname function') +endif diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/pthread_set_name_np_2args.cc pdns-recursor-5.4.9/meson/pthread-setname/pthread_set_name_np_2args.cc --- pdns-recursor-5.2.13/meson/pthread-setname/pthread_set_name_np_2args.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/pthread_set_name_np_2args.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +#include +#if HAVE_PTHREAD_NP_H +#include +#endif + +int main() +{ + return pthread_set_name_np(pthread_self(), "foo"); +} diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/pthread_set_name_np_void_2args.cc pdns-recursor-5.4.9/meson/pthread-setname/pthread_set_name_np_void_2args.cc --- pdns-recursor-5.2.13/meson/pthread-setname/pthread_set_name_np_void_2args.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/pthread_set_name_np_void_2args.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +#include +#if HAVE_PTHREAD_NP_H +#include +#endif + +int main() +{ + pthread_set_name_np(pthread_self(), "foo"); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_1arg.cc pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_1arg.cc --- pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_1arg.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_1arg.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +#include +#if HAVE_PTHREAD_NP_H +#include +#endif + +int main() +{ + return pthread_setname_np("foo"); +} diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_2args.cc pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_2args.cc --- pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_2args.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_2args.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +#include +#if HAVE_PTHREAD_NP_H +#include +#endif + +int main() +{ + pthread_setname_np(pthread_self(), "foo"); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_3args.cc pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_3args.cc --- pdns-recursor-5.2.13/meson/pthread-setname/pthread_setname_np_3args.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/pthread-setname/pthread_setname_np_3args.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +#include +#if HAVE_PTHREAD_NP_H +#include +#endif + +int main() +{ + return pthread_setname_np(pthread_self(), "foo", NULL); +} diff -Nru pdns-recursor-5.2.13/meson/reproducible/meson.build pdns-recursor-5.4.9/meson/reproducible/meson.build --- pdns-recursor-5.2.13/meson/reproducible/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/reproducible/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,48 @@ +opt_repro = get_option('reproducible') +conf.set('REPRODUCIBLE', opt_repro, description: 'Reproducible builds') +summary('Reproducible Builds', opt_repro, bool_yn: true, section: 'Reproducible Builds') + +if not opt_repro + id_prog = find_program('id', required: opt_repro) + id_prog_res = run_command(id_prog, '-u', '-n', check: true) + build_user = id_prog_res.stdout().strip() + + build_host = '' + hostname_prog = find_program('hostname', required: opt_repro) + build_system = build_machine.system() + if build_system == 'sunos' or build_system == 'openbsd' + domainname_prog = find_program('domainname', required: opt_repro) + + hostname_prog_res = run_command(hostname_prog, check: true) + domainname_prog_res = run_command(domainname_prog, check: true) + + build_host_hostname = hostname_prog_res.stdout().strip() + build_host_domainname = domainname_prog_res.stdout().strip() + + build_host = build_host_hostname + '.' + build_host_domainname + else + cmds = [ + [hostname_prog, '-f'], + [hostname_prog], + ['echo', '\'localhost\''], + ] + + found = false + foreach cmd: cmds + res = run_command(cmd, check: false) + if res.returncode() == 0 + build_host = res.stdout().strip() + found = true + break + endif + endforeach + + if not found + error('Reproducible builds requested but could not figure out a build host string on ' + build_system) + endif + endif + + build_host = build_user + '@' + build_host + conf.set_quoted('BUILD_HOST', build_host, description: 'User and host who built PowerDNS') + summary('Build Host', build_host, section: 'Reproducible Builds') +endif diff -Nru pdns-recursor-5.2.13/meson/requirements.in pdns-recursor-5.4.9/meson/requirements.in --- pdns-recursor-5.2.13/meson/requirements.in 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/requirements.in 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +# To generate requirements.txt, install pip-tools and run: +# pip-compile --generate-hashes -U requirements.in + +pyyaml==6.0.1 +meson +ninja +invoke +requests==2.32.4 +setuptools<82 diff -Nru pdns-recursor-5.2.13/meson/requirements.txt pdns-recursor-5.4.9/meson/requirements.txt --- pdns-recursor-5.2.13/meson/requirements.txt 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/requirements.txt 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,225 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --generate-hashes requirements.in +# +certifi==2026.1.4 \ + --hash=sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c \ + --hash=sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120 + # via requests +charset-normalizer==3.4.4 \ + --hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \ + --hash=sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93 \ + --hash=sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 \ + --hash=sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89 \ + --hash=sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc \ + --hash=sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 \ + --hash=sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63 \ + --hash=sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d \ + --hash=sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f \ + --hash=sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8 \ + --hash=sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0 \ + --hash=sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505 \ + --hash=sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161 \ + --hash=sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af \ + --hash=sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152 \ + --hash=sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318 \ + --hash=sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72 \ + --hash=sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4 \ + --hash=sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e \ + --hash=sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3 \ + --hash=sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576 \ + --hash=sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c \ + --hash=sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1 \ + --hash=sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8 \ + --hash=sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1 \ + --hash=sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2 \ + --hash=sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44 \ + --hash=sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26 \ + --hash=sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88 \ + --hash=sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016 \ + --hash=sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede \ + --hash=sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf \ + --hash=sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a \ + --hash=sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc \ + --hash=sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0 \ + --hash=sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84 \ + --hash=sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db \ + --hash=sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1 \ + --hash=sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7 \ + --hash=sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed \ + --hash=sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8 \ + --hash=sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133 \ + --hash=sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e \ + --hash=sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef \ + --hash=sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14 \ + --hash=sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2 \ + --hash=sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0 \ + --hash=sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d \ + --hash=sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828 \ + --hash=sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f \ + --hash=sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf \ + --hash=sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6 \ + --hash=sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328 \ + --hash=sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090 \ + --hash=sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa \ + --hash=sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381 \ + --hash=sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c \ + --hash=sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb \ + --hash=sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc \ + --hash=sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a \ + --hash=sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec \ + --hash=sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc \ + --hash=sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac \ + --hash=sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e \ + --hash=sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313 \ + --hash=sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569 \ + --hash=sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3 \ + --hash=sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d \ + --hash=sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525 \ + --hash=sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894 \ + --hash=sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3 \ + --hash=sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9 \ + --hash=sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a \ + --hash=sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9 \ + --hash=sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14 \ + --hash=sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25 \ + --hash=sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50 \ + --hash=sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf \ + --hash=sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1 \ + --hash=sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3 \ + --hash=sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac \ + --hash=sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e \ + --hash=sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815 \ + --hash=sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c \ + --hash=sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6 \ + --hash=sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6 \ + --hash=sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e \ + --hash=sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4 \ + --hash=sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84 \ + --hash=sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69 \ + --hash=sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15 \ + --hash=sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191 \ + --hash=sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0 \ + --hash=sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897 \ + --hash=sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd \ + --hash=sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2 \ + --hash=sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794 \ + --hash=sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d \ + --hash=sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074 \ + --hash=sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3 \ + --hash=sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224 \ + --hash=sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838 \ + --hash=sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a \ + --hash=sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d \ + --hash=sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d \ + --hash=sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f \ + --hash=sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8 \ + --hash=sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490 \ + --hash=sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966 \ + --hash=sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9 \ + --hash=sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3 \ + --hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \ + --hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608 + # via requests +idna==3.11 \ + --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \ + --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902 + # via requests +invoke==2.2.1 \ + --hash=sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8 \ + --hash=sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707 + # via -r requirements.in +meson==1.10.1 \ + --hash=sha256:c42296f12db316a4515b9375a5df330f2e751ccdd4f608430d41d7d6210e4317 \ + --hash=sha256:fe43d1cc2e6de146fbea78f3a062194bcc0e779efc8a0f0d7c35544dfb86731f + # via -r requirements.in +ninja==1.13.0 \ + --hash=sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f \ + --hash=sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988 \ + --hash=sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9 \ + --hash=sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630 \ + --hash=sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db \ + --hash=sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978 \ + --hash=sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1 \ + --hash=sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72 \ + --hash=sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e \ + --hash=sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2 \ + --hash=sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9 \ + --hash=sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714 \ + --hash=sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200 \ + --hash=sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c \ + --hash=sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5 \ + --hash=sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96 \ + --hash=sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1 \ + --hash=sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa \ + --hash=sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e + # via -r requirements.in +pyyaml==6.0.1 \ + --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ + --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ + --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ + --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ + --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ + --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ + --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ + --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ + --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ + --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ + --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ + --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ + --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ + --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ + --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ + --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ + --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ + --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ + --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ + --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ + --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ + --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ + --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ + --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ + --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ + --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ + --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ + --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ + --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ + --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ + --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ + --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ + --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ + --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ + --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ + --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ + --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ + --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ + --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ + --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ + --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ + --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ + --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ + --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ + --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ + --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ + --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ + --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ + --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ + --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ + --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f + # via -r requirements.in +requests==2.32.4 \ + --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ + --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 + # via -r requirements.in +urllib3==2.6.3 \ + --hash=sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed \ + --hash=sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4 + # via requests + +# The following packages are considered to be unsafe in a requirements file: +setuptools==81.0.0 \ + --hash=sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a \ + --hash=sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6 + # via -r requirements.in diff -Nru pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/meson.build pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/meson.build --- pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,44 @@ +prog_single_pointer = fs.read('sanitizer_finish_switch_fiber_1ptr.cc') +prog_three_pointers = fs.read('sanitizer_finish_switch_fiber_3ptrs.cc') + +single_pointer = false +three_pointers = false + +if cxx.check_header('sanitizer/common_interface_defs.h', required: false) + if cxx.has_header_symbol('sanitizer/common_interface_defs.h', '__sanitizer_start_switch_fiber', required: false) + if cxx.compiles(prog_single_pointer, name: '__sanitizer_finish_switch_fiber with a single pointer') + single_pointer = true + endif + + if cxx.compiles(prog_three_pointers, name: '__sanitizer_finish_switch_fiber with three pointers') + three_pointers = true + endif + else + warning('Address Sanitizer fiber switching is not available') + endif + +else + warning('Address Sanitizer requested but `sanitizer/common_interface_defs.h` ' + + 'is invalid or cannot be found. Address Sanitizer fiber switching is ' + + 'not available') +endif + +if not single_pointer and not three_pointers + warning('Address Sanitizer fiber switching is not available due to an unknown API version') +endif + +conf.set( + 'HAVE_FIBER_SANITIZER', + single_pointer or three_pointers, + description: 'Address Sanitizer fiber annotation interface is available', +) +conf.set( + 'HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR', + single_pointer, + description: 'Address Sanitizer: __sanitizer_finish_switch_fiber takes only a pointer', +) +conf.set( + 'HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS', + three_pointers, + description: 'Address Sanitizer: __sanitizer_finish_switch_fiber takes three pointers', +) diff -Nru pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_1ptr.cc pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_1ptr.cc --- pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_1ptr.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_1ptr.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +#include + +int main() +{ + __sanitizer_finish_switch_fiber(nullptr); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_3ptrs.cc pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_3ptrs.cc --- pdns-recursor-5.2.13/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_3ptrs.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sanitizers/address-sanitizer-fiber-switching/sanitizer_finish_switch_fiber_3ptrs.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,7 @@ +#include + +int main() +{ + __sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr); + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/sanitizers/meson.build pdns-recursor-5.4.9/meson/sanitizers/meson.build --- pdns-recursor-5.2.13/meson/sanitizers/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sanitizers/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,25 @@ +opt_sanitize = get_option('b_sanitize') +leak_detection = false + +if opt_sanitize == 'address' or opt_sanitize == 'address,undefined' + subdir('address-sanitizer-fiber-switching') + leak_detection = true +endif + +if opt_sanitize == 'leak' + leak_detection = true +endif + +if leak_detection + conf.set( + 'HAVE_LEAK_SANITIZER_INTERFACE', + cxx.has_header('sanitizer/lsan_interface.h'), + description: 'Have leak sanitizer inteface', + ) +endif + +if opt_sanitize != 'none' + add_project_arguments('-fno-omit-frame-pointer', language: ['c', 'cpp']) +endif + +summary('Sanitizers', opt_sanitize, bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/socket-dir/meson.build pdns-recursor-5.4.9/meson/socket-dir/meson.build --- pdns-recursor-5.2.13/meson/socket-dir/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/socket-dir/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +opt_socket_dir = get_option('socket-dir') +conf.set_quoted('LOCALSTATEDIR', opt_socket_dir, description: 'Local state/socket directory') diff -Nru pdns-recursor-5.2.13/meson/sqlite3/meson.build pdns-recursor-5.4.9/meson/sqlite3/meson.build --- pdns-recursor-5.2.13/meson/sqlite3/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sqlite3/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,13 @@ +dep_sqlite3 = dependency('', required: false) + +if get_option('module-gsqlite3') != 'disabled' + dep_sqlite3 = dependency('sqlite3', required: true) +endif + +conf.set('HAVE_SQLITE3', dep_sqlite3.found(), description: 'Sqlite3') +conf.set('SQLITE3', dep_sqlite3.found(), description: 'Sqlite3') + +summary('SQLite3', dep_sqlite3.found(), bool_yn: true, section: 'SQLite3') +if dep_sqlite3.found() + summary('Version', dep_sqlite3.version(), section: 'SQLite3') +endif diff -Nru pdns-recursor-5.2.13/meson/strerror/meson.build pdns-recursor-5.4.9/meson/strerror/meson.build --- pdns-recursor-5.2.13/meson/strerror/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/strerror/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,13 @@ +prog = fs.read('strerror_r.c') + +have_strerror_r_decl = cxx.has_header_symbol('string.h', 'strerror_r') +have_strerror_r = cxx.has_function('strerror_r', prefix: '#include ') +strerror_r_returns_charp = have_strerror_r and cxx.compiles(prog, name: 'strerror_r() returns char *') + +conf.set('HAVE_DECL_STRERROR_R', have_strerror_r_decl, description: 'Whether strerror_r is declared') +conf.set('HAVE_STRERROR_R', have_strerror_r, description: 'Whether strerror_r is available') +conf.set('STRERROR_R_CHAR_P', strerror_r_returns_charp, description: 'Whether strerror_r returns char *') + +summary('Symbol', have_strerror_r_decl, bool_yn: true, section: 'Function strerror_r') +summary('Declaration', have_strerror_r, bool_yn: true, section: 'Function strerror_r') +summary('Returns char *', strerror_r_returns_charp, bool_yn: true, section: 'Function strerror_r') diff -Nru pdns-recursor-5.2.13/meson/strerror/strerror_r.c pdns-recursor-5.4.9/meson/strerror/strerror_r.c --- pdns-recursor-5.2.13/meson/strerror/strerror_r.c 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/strerror/strerror_r.c 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +#include + +int main () { + char error_string[256]; + char *ptr = strerror_r(-2, error_string, 256); + char c = *strerror_r(-2, error_string, 256); + return c != 0 && ptr != (void*) 0L; +} diff -Nru pdns-recursor-5.2.13/meson/summary/meson.build pdns-recursor-5.4.9/meson/summary/meson.build --- pdns-recursor-5.2.13/meson/summary/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/summary/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +summary('System', system, section: 'System') +summary('C++ Compiler', cxx.get_id(), section: 'System') +summary('C++ Compiler Version', cxx.version(), section: 'System') +summary('C++ Compiler Command', ' '.join(cxx.cmd_array()), section: 'System') +summary('Linker', cxx.get_linker_id(), section: 'System') diff -Nru pdns-recursor-5.2.13/meson/sysconfdir/meson.build pdns-recursor-5.4.9/meson/sysconfdir/meson.build --- pdns-recursor-5.2.13/meson/sysconfdir/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/sysconfdir/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1 @@ +conf.set_quoted('SYSCONFDIR', get_option('sysconfdir'), description: 'Configuration data directory') diff -Nru pdns-recursor-5.2.13/meson/systemd/meson.build pdns-recursor-5.4.9/meson/systemd/meson.build --- pdns-recursor-5.2.13/meson/systemd/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/systemd/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,60 @@ +opt_systemd = get_option('systemd-service') + + +if opt_systemd.allowed() + dep_systemd_prog = dependency('systemd', required: opt_systemd) +else + dep_systemd_prog = dependency('', required: false) +endif + +if dep_systemd_prog.found() + # Map systemd features to systemd/systemctl version. + systemd_features = { + 'private_tmp': 183, + 'system_call_architectures': 209, + 'private_devices': 209, + 'restrict_address_families': 211, + 'protect_system': 214, + 'protect_home': 214, + 'restrict_realtime': 231, + 'memory_deny_write_execute': 231, + 'protect_control_groups': 232, + 'protect_kernel_modules': 232, + 'protect_kernel_tunables': 232, + 'remove_ipc': 232, + 'dynamic_user': 232, + 'private_users': 232, + 'protect_system_strict': 232, + 'restrict_namespaces': 233, + 'lock_personality': 235, + # while SystemCallFilter is technically available starting with 187, + # we use the pre-defined call filter sets that have been introduced later. + # Initial support for these landed in 231 + # @filesystem @reboot @swap in 233 + # @aio, @sync, @chown, @setuid, @memlock, @signal and @timer in 235 + 'system_call_filter': 235, + 'percent_t': 236, + 'private_mounts': 239, + 'with_runtime_dir_env': 240, + 'protect_hostname': 242, + 'restrict_suidsgid': 242, + 'protect_kernel_logs': 244, + 'protect_clock': 245, + 'protect_proc': 247, + 'private_ipc': 248, + } + + systemd_version = dep_systemd_prog.version() + foreach feature, version: systemd_features + feature_name = 'have_systemd_' + feature + feature_value = systemd_version.version_compare('>=' + version.to_string()) + set_variable(feature_name, feature_value) + conf.set(feature_name.to_upper(), feature_value, description: 'systemd feature: ' + feature) + endforeach + + if dep_systemd_prog.found() + summary('Version', dep_systemd_prog.version(), section: 'Systemd') + endif +endif + +summary('Systemd', dep_systemd_prog.found(), bool_yn: true, section: 'Configuration') diff -Nru pdns-recursor-5.2.13/meson/timet-sign/meson.build pdns-recursor-5.4.9/meson/timet-sign/meson.build --- pdns-recursor-5.2.13/meson/timet-sign/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/timet-sign/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,10 @@ +fs = import('fs') + +prog = fs.read('timet_sign.cc') +timet_signed = cxx.compiles(prog, name: 'time_t is signed') + +if not timet_signed + error('time_t is unsigned, PowerDNS code relies on it being signed') +endif + +summary('Signed time_t', timet_signed, bool_yn: true, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/timet-sign/timet_sign.cc pdns-recursor-5.4.9/meson/timet-sign/timet_sign.cc --- pdns-recursor-5.2.13/meson/timet-sign/timet_sign.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/timet-sign/timet_sign.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +#include + +int main() +{ + int foo[1 - 2 * !(((time_t)-1) < 0)]; + (void)foo[0]; + return 0; +} diff -Nru pdns-recursor-5.2.13/meson/timet-size/meson.build pdns-recursor-5.4.9/meson/timet-size/meson.build --- pdns-recursor-5.2.13/meson/timet-size/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/timet-size/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,9 @@ +timet_size = cxx.sizeof('time_t', prefix: '#include ') + +if timet_size < 8 + error('size of time_t is ' + + timet_size.to_string() + + ' which is not large enough to fix the y2k38 bug') +endif + +summary('Size of time_t', timet_size, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/tm-gmtoff/meson.build pdns-recursor-5.4.9/meson/tm-gmtoff/meson.build --- pdns-recursor-5.2.13/meson/tm-gmtoff/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/tm-gmtoff/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,8 @@ +prefix = ''' +#include +#include +''' + +has = cxx.has_member('struct tm', 'tm_gmtoff', prefix: prefix) +conf.set('HAVE_TM_GMTOFF', has, description: 'Whether tm_gmtoff is available') +summary('tm_gmtoff', has, bool_yn: true, section: 'System') diff -Nru pdns-recursor-5.2.13/meson/various-functions/meson.build pdns-recursor-5.4.9/meson/various-functions/meson.build --- pdns-recursor-5.2.13/meson/various-functions/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/various-functions/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +funcs = [ + 'localtime_r', + 'gmtime_r', + 'recvmmsg', + 'sched_setscheduler', + 'getrandom', + 'arc4random', + 'getentropy', + 'arc4random_uniform', + 'arc4random_buf', + 'explicit_bzero', + 'explicit_memset', + 'memset_s', +] + +foreach func: funcs + found = cxx.has_function(func) + define = 'HAVE_' + func.to_upper() + conf.set(define, found, description: 'Have ' + func) + summary(func, found, bool_yn: true, section: 'Various Functions') +endforeach diff -Nru pdns-recursor-5.2.13/meson/various-headers/meson.build pdns-recursor-5.4.9/meson/various-headers/meson.build --- pdns-recursor-5.2.13/meson/various-headers/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/various-headers/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,5 @@ +conf.set( + 'HAVE_SYS_RANDOM_H', + cxx.has_header('sys/random.h'), + description: 'Have sys/random.h', +) diff -Nru pdns-recursor-5.2.13/meson/verbose-logging/meson.build pdns-recursor-5.4.9/meson/verbose-logging/meson.build --- pdns-recursor-5.2.13/meson/verbose-logging/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/verbose-logging/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +opt_verbose_logging = get_option('verbose-logging') +conf.set('VERBOSELOG', opt_verbose_logging, description: 'Verbose logging') diff -Nru pdns-recursor-5.2.13/meson/version/meson.build pdns-recursor-5.4.9/meson/version/meson.build --- pdns-recursor-5.2.13/meson/version/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/version/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,2 @@ +product_version = meson.project_version() +conf.set_quoted('VERSION', product_version, description: 'Version') diff -Nru pdns-recursor-5.2.13/meson/yaml-cpp/meson.build pdns-recursor-5.4.9/meson/yaml-cpp/meson.build --- pdns-recursor-5.2.13/meson/yaml-cpp/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/yaml-cpp/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,21 @@ +dep_yaml_cpp = dependency('', required: false) + +if get_option('module-geoip') != 'disabled' or get_option('tools-ixfrdist') + dep_yaml_cpp = dependency('yaml-cpp', version: '>= 0.5', required: true) +endif + +if get_option('module-geoip') != 'disabled' + summary('YAML-CPP', dep_yaml_cpp.found(), bool_yn: true, section: 'GeoIP Backend') + if dep_yaml_cpp.found() + summary('YAML-CPP Name', dep_yaml_cpp.name(), section: 'GeoIP Backend') + summary('YAML-CPP Version', dep_yaml_cpp.version(), section: 'GeoIP Backend') + endif +endif + +if get_option('tools-ixfrdist') + summary('YAML-CPP', dep_yaml_cpp.found(), bool_yn: true, section: 'IXFRDist') + if dep_yaml_cpp.found() + summary('YAML-CPP Name', dep_yaml_cpp.name(), section: 'IXFRDist') + summary('YAML-CPP Version', dep_yaml_cpp.version(), section: 'IXFRDist') + endif +endif diff -Nru pdns-recursor-5.2.13/meson/zeromq/meson.build pdns-recursor-5.4.9/meson/zeromq/meson.build --- pdns-recursor-5.2.13/meson/zeromq/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson/zeromq/meson.build 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,17 @@ +dep_zeromq = dependency('', required: false) + +if get_option('module-remote') != 'disabled' and get_option('module-remote-zeromq') + dep_zeromq = dependency('libzmq', required: true) +endif + +conf.set('HAVE_LIBZMQ', dep_zeromq.found(), description: 'Have libzmq') +conf.set('REMOTEBACKEND_ZEROMQ', dep_zeromq.found(), description: 'Have ZeroMQ connector') + +have_zmq_msg_send = cxx.has_function('zmq_msg_send', dependencies: dep_zeromq) +conf.set('HAVE_ZMQ_MSG_SEND', have_zmq_msg_send, description: 'Have zmq_msg_send') + +summary('ZeroMQ', dep_zeromq.found(), bool_yn: true, section: 'ZeroMQ') + +if dep_zeromq.found() + summary('Version', dep_zeromq.version(), bool_yn: true, section: 'ZeroMQ') +endif diff -Nru pdns-recursor-5.2.13/meson-dist-script.sh pdns-recursor-5.4.9/meson-dist-script.sh --- pdns-recursor-5.2.13/meson-dist-script.sh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson-dist-script.sh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,72 @@ +#!/bin/sh -e + +echo Running meson-dist-script +export CARGO="${CARGO:-$_defaultCARGO}" + +echo PWD=$(pwd) +echo MESON_SOURCE_ROOT=$MESON_SOURCE_ROOT +echo MESON_PROJECT_DIST_ROOT=$MESON_PROJECT_DIST_ROOT +echo CARGO=$CARGO + +if [ -z "${BUILDER_VERSION}" ]; then + echo "BUILDER_VERSION is not set" >&2 + exit 1 +fi + +if [ -z "${CARGO}" ]; then + echo PATH=$PATH + ls -l /usr/bin/cargo + export CARGO=/usr/bin/cargo + #exit 1 +fi + +cd "$MESON_PROJECT_DIST_ROOT" + +# Get all symlinks +symlinks=$(find . -type l) + +# If these two get out-of-sync, fix it! It used to be a symlink but that can no longer be as we are +# working with a partial checkout in the dist root dir. +cmp "$MESON_SOURCE_ROOT"/../../builder-support/gen-version "$MESON_PROJECT_DIST_ROOT"/builder-support/gen-version + +# Get the dereffed symbolic links (the actual files being pointed to) from the source dir +# Extract them over the existing symbolic links +tar -C "$MESON_SOURCE_ROOT" -hcf - $symlinks | tar -xf - -C "$MESON_PROJECT_DIST_ROOT" + +# Run autoconf for people using autotools to build, this creates a configure script with VERSION set +# set the proper version in configure.ac +"$MESON_SOURCE_ROOT"/../../builder/helpers/set-configure-ac-version.sh +echo Running autoreconf -vi so distfile is still usable for autotools building +# Run autoconf for people using autotools to build, this creates a configure sc +autoreconf -vi +rm -rf "$MESON_PROJECT_DIST_ROOT"/autom4te.cache + +cd "$MESON_PROJECT_BUILD_ROOT" + +# Generate a few files to reduce build dependencies +echo 'If the below command generates an error, remove dnslabeltext.cc from source dir (remains of an autotools build?) and start again with a clean meson setup' +ninja librec-dnslabeltext.a.p/dnslabeltext.cc +cp -vp librec-dnslabeltext.a.p/dnslabeltext.cc "$MESON_PROJECT_DIST_ROOT" +echo 'If the below command generates an error, remove effective_tld_names.dat and pubsuffix.cc from source dir (remains of an autotools build?) and start again with a clean meson setup' +ninja pubsuffix.cc +cp -vp pubsuffix.cc "$MESON_PROJECT_DIST_ROOT" + +# Generate the sources for our Rust-based library, lib.rs is needed by a pre-configure step on some build systems +meson compile rec-rust-sources +cp -vp "$MESON_SOURCE_ROOT"/rec-rust-lib/rust/src/lib.rs "$MESON_PROJECT_DIST_ROOT"/rec-rust-lib/rust/src/ + +echo Updating the version of the Rust library to ${BUILDER_VERSION} +"$MESON_SOURCE_ROOT"/../../builder-support/helpers/update-rust-library-version.py "$MESON_PROJECT_DIST_ROOT"/rec-rust-lib/rust/Cargo.toml recrust ${BUILDER_VERSION} +# Update the version of the Rust library in Cargo.lock as well, +# This needs to be done AFTER the sources of the Rust library have been generated +# Unfortunately we cannot use --offline because for some reason cargo-update wants +# to check all dependencies even though we are telling it exactly what to update +cd "$MESON_PROJECT_DIST_ROOT"/rec-rust-lib/rust/ +ls -l /usr/bin/cargo +echo $CARGO update --verbose --precise ${BUILDER_VERSION} recrust +$CARGO update --verbose --precise ${BUILDER_VERSION} recrust +cd "$MESON_PROJECT_BUILD_ROOT" + +# Generate man pages +meson compile man-pages +cp -vp *.1 "$MESON_PROJECT_DIST_ROOT" diff -Nru pdns-recursor-5.2.13/meson.build pdns-recursor-5.4.9/meson.build --- pdns-recursor-5.2.13/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson.build 2026-10-26 09:47:32.752236100 +0000 @@ -0,0 +1,821 @@ +project( + 'pdns-recursor', + ['c', 'cpp'], +version : '5.4.9', + license : 'GPLv2', + license_files : 'NOTICE', + meson_version : '>= 1.2.1', + default_options : ['buildtype=debugoptimized', 'warning_level=2', 'cpp_std=c++17'] +) + +env = environment() +cargo = find_program('cargo') +env.set('_defaultCARGO', cargo.full_path()) +meson.add_dist_script('meson-dist-script.sh') + +# When running meson dist, the command below produces multiple lines on stderr: +# Unable to evaluate subdir([]) in AstInterpreter --> Skipping +meson.add_dist_script('version.sh', 'set-dist', meson.project_version()) + +add_project_arguments('-DRECURSOR', language: 'cpp') +add_project_arguments( + '-fvisibility=hidden', + language: ['c', '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' / 'libcrypto') # OpenSSL-based signers +subdir('meson' / 'libssl') # OpenSSL libssl +subdir('meson' / 'libssl-engines') # OpenSSL libssl engines +subdir('meson' / 'gnutls') # GNUTLS +subdir('meson' / 'dot') # DNS over TLS +subdir('meson' / 'libsnmp') # SNMP +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('meson' / 'libcap') # Capabilities +subdir('meson' / 'dlopen') # our Rust static library needs dlopen + +subdir('rec-rust-lib') + +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 / 'ednscookies.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 / 'misc.cc', + src_dir / 'mtasker_context.cc', + src_dir / 'negcache.cc', + src_dir / 'nsecrecords.cc', + src_dir / 'protozero.cc', + src_dir / 'protozero-trace.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-nsspeeds.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 / 'rec-cookiestore.cc', + src_dir / 'rec-xfr.cc', + src_dir / 'rec-xfrtracker.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 absence 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.7.8.js', + src_dir / 'html/js/handlebars-v4.7.8-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], +) + +metric_sources = [ + src_dir / 'metrics.py', + src_dir / 'metrics_table.py', + src_dir / 'RECURSOR-MIB.in', +] + +py = import('python') +python = py.find_installation('python3', required: true) +if python.language_version().version_compare('<3.8') + error('Python version is ' + python.language_version() + '; should be at least 3.8 for generate.py script') +endif + +metricfiles = custom_target( + command: [python, '@INPUT0@', '@SOURCE_ROOT@', '@BUILD_ROOT@'], + input: metric_sources, + output: [ + 'rec-metrics-gen.h', + 'rec-prometheus-gen.h', + 'rec-snmp-gen.h', + 'rec-oids-gen.h', + 'RECURSOR-MIB.txt', + ], + capture: false, +) + +dep_metrics = declare_dependency( + sources: [metricfiles], +) + +deps = [ + dep_pdns, + dep_no_config_in_source, + dep_rust_recrust, + dep_dlopen, + dep_boost, + dep_boost_context, + dep_threads, + dep_arc4random, + dep_json11, + dep_libcrypto, + dep_libresolv, + dep_libsnmp, + dep_libsodium, + dep_libssl, + dep_gnutls, + dep_lua, + dep_protozero, + dep_yahttp_header_only, + dep_htmlfiles, + dep_dnstap, + dep_libcurl, + dep_metrics, + dep_libcap, +] + +# 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_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 data and build it in the build dir. +if fs.is_file(src_dir / 'pubsuffix.cc') + cp_command = find_program('cp') + pubsuffix_cc = custom_target( + 'cp-pubsuffix', + command: [cp_command, '-pv', '@INPUT@', '@OUTPUT@'], + input: src_dir / 'pubsuffix.cc', + output: 'pubsuffix.cc', + ) +else + mkpubsuffix_command = find_program('mkpubsuffixcc', required: true) + pubsuffix_cc = custom_target( + 'pubsuffix-cc', + command: [mkpubsuffix_command, '@OUTPUT@'], + 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_recrust_ch, + librec_dnslabeltext, + ], + ) +) + + +if target_machine.system() != 'darwin' + rec_link_args = [ + '-Wl,--export-dynamic-symbol=pdns_ffi_*', + '-Wl,--export-dynamic-symbol=pdns_postresolve_ffi_*', + ] +else + rec_link_args = ['-rdynamic'] +endif + +tools = { + 'pdns_recursor': { + 'main': src_dir / 'rec-main.cc', + 'link-args': rec_link_args, + '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', + src_dir / 'lwres.cc', + mplexer_sources, + ], + 'manpages': ['pdns_recursor.1'], + 'deps-extra': [ + dep_boost, + dep_nod, + dep_lua, + dep_protozero, + dep_yahttp_header_only, + dep_json11, + dep_recrust, + dep_rust_recrust, + dep_libsystemd, + librec_signers_openssl, + librec_signers_sodium, + dep_pubsuffix, + ], + 'install': true, + 'install_dir': get_option('sbindir'), + }, + 'rec_control': { + 'main': src_dir / 'rec_control.cc', + 'manpages': ['rec_control.1'], + 'deps-extra': [ + dep_boost, + dep_recrust, + dep_rust_recrust, + ], + 'install': true, + }, +} + +test_sources = [] +test_sources += files( + 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-ednscookie_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-protozero-trace.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-shuffle_cc.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_protozero, + dep_recrust, + dep_rust_recrust, + librec_signers_openssl, + 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 + link_args = 'link-args' in info ? info['link-args'] : [] + files_extra = 'files-extra' in info ? info['files-extra'] : [] + deps_extra = 'deps-extra' in info ? info['deps-extra'] : [] + install = 'install' in info ? info['install'] : false + install_dir = 'install_dir' in info ? info['install_dir'] : get_option('bindir') + + set_variable( + var_name, + executable( + tool, + main, + config_h, + files_extra, + export_dynamic: export_dynamic, + link_args: link_args, + dependencies: [ + librec_common, + deps_extra, + ], + install: install, + install_dir: install_dir, + ) + ) + + if 'manpages' in info + foreach man_page: info['manpages'] + man_pages += docs_dir / 'manpages' / (man_page + '.rst') + endforeach + endif +endforeach + +if get_option('unit-tests') + # default timeout of 30s is too short for some ubicloud targets. Unknown *why* they are so slow. + test('testrunner', testrunner, timeout: 120) +endif + +# 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() + generated_man_pages = [] + foreach tool, info: tools + if 'manpages' in info + foreach man_page: info['manpages'] + if not fs.is_file(man_page) + generated_man_pages += man_page + else + install_man( + man_page, + install_dir: join_paths(get_option('mandir'), 'man1'), + ) + endif + endforeach + endif + endforeach + if generated_man_pages.length() != 0 + summary('Generating man pages', true, section: 'Manual Pages') + custom_target( + 'man-pages', + input: man_pages, + output: generated_man_pages, + install: true, + install_dir: join_paths(get_option('mandir'), 'man1'), + command: [ + python, + product_source_dir / docs_dir / 'generate-man-pages.py', + '--build-root', '@BUILD_ROOT@', + '--source-root', '@SOURCE_ROOT@', + '--venv-name', 'venv-rec-man-pages', + '--requirements-file', docs_dir / 'requirements.txt', + '--source-directory', docs_dir, + '--target-directory', '@BUILD_ROOT@', + ] + man_pages, + ) + else + summary('Generating man pages', false, section: 'Manual Pages') + endif +endif + +if dep_systemd_prog.found() + systemd_system_unit_dir = dep_systemd_prog.get_variable( + 'systemdsystemunitdir', + ) + + systemd_service_conf = configuration_data() + 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) + systemd_service_conf.set('ServiceGroup', systemd_service_group) + summary('Service User', systemd_service_user, section: 'Systemd') + summary('Service Group', systemd_service_group, section: 'Systemd') + + # ProtectSystem=full will disallow write access to /etc and /usr, possibly not being + # able to write RPZ dumps or API related files. + systemd_service_conf.set( + 'ProtectSystem', have_systemd_protect_system ? 'ProtectSystem=full' : '', + ) + systemd_service_conf.set( + 'SystemCallArchitectures', + have_systemd_system_call_architectures ? 'SystemCallArchitectures=native' : '', + ) + systemd_system_call_filter = '~ @clock @debug @module @mount @raw-io @reboot @swap @cpu-emulation @obsolete' + systemd_service_conf.set( + 'SystemCallFilter', + have_systemd_system_call_filter ? 'SystemCallFilter=' + systemd_system_call_filter : '', + ) + systemd_service_conf.set( + 'ProtectProc', + have_systemd_protect_proc ? 'ProtectProc=invisible' : '', + ) + + systemd_features = { + 'LockPersonality': have_systemd_lock_personality, + 'PrivateDevices': have_systemd_private_devices, + 'PrivateTmp': have_systemd_private_tmp, + 'PrivateUsers': false, # Setting it to true prevents us from opening our sockets. + 'ProtectClock': have_systemd_protect_clock, + 'ProtectControlGroups': have_systemd_protect_control_groups, + 'ProtectHome': have_systemd_protect_home, + 'ProtectHostname': have_systemd_protect_hostname, + 'ProtectKernelLogs': have_systemd_protect_kernel_logs, + 'ProtectKernelModules': have_systemd_protect_kernel_modules, + 'ProtectKernelTunables': have_systemd_protect_kernel_tunables, + 'RestrictNamespaces': have_systemd_restrict_namespaces, + 'RestrictRealtime': have_systemd_restrict_realtime, + 'RestrictSUIDSGID': have_systemd_restrict_suidsgid, + 'PrivateIPC': have_systemd_private_ipc, + 'RemoveIPC': have_systemd_remove_ipc, + } + + foreach feature, enable_it: systemd_features + systemd_service_conf.set(feature, enable_it ? feature + '=true': '') + endforeach + + rec_service_conf = configuration_data() + rec_service_conf.merge_from(systemd_service_conf) + # Disabled, it breaks LuaJIT. + rec_service_conf.set( + 'MemoryDenyWriteExecute', + have_systemd_memory_deny_write_execute ? 'MemoryDenyWriteExecute=false' : '', + ) + rec_service_conf.set( + 'RestrictAddressFamilies', + have_systemd_restrict_address_families ? 'RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6' : '', + ) + + enable_socket_dir = (not have_systemd_with_runtime_dir_env) and have_systemd_percent_t + + rec_service_conf_general = configuration_data() + rec_service_conf_general.merge_from(rec_service_conf) + rec_service_conf_general.set('Description', 'PowerDNS Recursor') + rec_service_conf_general.set('ConfigName', '') + rec_service_conf_general.set('SocketDir', enable_socket_dir ? '--socket-dir=%t/pdns-recursor' : '') + rec_service_conf_general.set('RecControlSocketDir', '--socket-dir=%t/pdns-recursor') + rec_service_conf_general.set('SyslogIdentifier', 'pdns-recursor') + rec_service_conf_general.set('RuntimeDirectory', 'pdns-recursor') + + configure_file( + input: 'pdns-recursor.service.meson.in', + output: 'pdns-recursor.service', + configuration: rec_service_conf_general, + install: true, + install_dir: systemd_system_unit_dir, + ) + + rec_service_conf_instance = configuration_data() + rec_service_conf_instance.merge_from(rec_service_conf) + rec_service_conf_instance.set('Description', 'PowerDNS Recursor %i') + rec_service_conf_instance.set('ConfigName', '--config-name=%i') + rec_service_conf_instance.set('SocketDir', enable_socket_dir ? '--socket-dir=%t/pdns-recursor-%i' : '') + rec_service_conf_instance.set('RecControlSocketDir', '--socket-dir=%t/pdns-recursor-%i') + rec_service_conf_instance.set('SyslogIdentifier', 'pdns-recursor-%i') + rec_service_conf_instance.set('RuntimeDirectory', have_systemd_percent_t ? 'pdns-recursor-%i' : 'pdns-recursor') + + configure_file( + input: 'pdns-recursor.service.meson.in', + output: 'pdns-recursor@.service', + configuration: rec_service_conf_instance, + install: true, + install_dir: systemd_system_unit_dir, + ) +endif + + +dep_conf_distfile = custom_target( + 'gen-conf-distfile', + command: [pdns_recursor, '--config=default'], + output: 'recursor.yml-dist', + capture: true, + install: true, + install_dir: get_option('sysconfdir'), +) + +if python.found() + + html_docs = custom_target( + 'html-docs', + command: [ + python, + product_source_dir / docs_dir / 'generate-docs.py', + '--build-root', '@BUILD_ROOT@', + '--source-root', '@SOURCE_ROOT@', + '--venv-name', 'venv-docs', + '--requirements-file', docs_dir / 'requirements.txt', + '--source-directory', docs_dir, + '--target-directory', '@BUILD_ROOT@' / 'html-docs', + ], + output: 'sphinx.stamp', + console: true, + depfile: 'sphinx.d', + depends: [ metricfiles, recrust ], # for generated .rst files + ) + + docs_tarball = custom_target( + 'html-docs.tar.bz2', + command: ['tar', 'cjf', 'html-docs.tar.bz2', html_docs], + output: 'html-docs.tar.bz2', + ) + + pdf_docs = custom_target( + command: [ + python, + product_source_dir / docs_dir / 'generate-docs.py', + '--build-root', '@BUILD_ROOT@', + '--source-root', '@SOURCE_ROOT@', + '--venv-name', 'venv-docs', + '--requirements-file', docs_dir / 'requirements.txt', + '--source-directory', docs_dir, + '--target-directory', '@BUILD_ROOT@', + '--pdf-name', 'PowerDNS-Recursor.pdf', + ], + output: 'PowerDNS-Recursor.pdf', + console: true, + depfile: 'sphinx.d', + depends: [ metricfiles, recrust ], # for generated .rst files + ) + + run_target( + 'all-docs', + # args mentioned in command line become auto-dependency + command: ['echo', 'Generated', html_docs, docs_tarball, pdf_docs], + ) +endif diff -Nru pdns-recursor-5.2.13/meson_options.txt pdns-recursor-5.4.9/meson_options.txt --- pdns-recursor-5.2.13/meson_options.txt 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/meson_options.txt 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,27 @@ +option('lua', type: 'combo', choices: ['auto', 'luajit', 'lua', 'lua51', 'lua-5.1', 'lua5.1', 'lua52', 'lua-5.2', 'lua5.2', 'lua53', 'lua-5.3', 'lua5.3', 'lua54', 'lua-5.4', 'lua5.4'], 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: 'auto', description: 'Source fortification level') +option('signers-libsodium', type: 'feature', value: 'auto', description: 'Enable libsodium-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('tls-libssl-dir', type: 'string', value: '', description: 'Alternate OpenSSL location') +option('dns-over-tls', type: 'feature', value: 'auto', description: 'DNS over TLS (requires GnuTLS or OpenSSL)') +option('unit-tests', type: 'boolean', value: false, description: 'Build and run unit tests') +option('unit-tests-backends', type: 'boolean', value: false, description: 'Not relevant for recursor') +option('reproducible', type: 'boolean', value: false, description: 'Reproducible builds (for distro maintainers, makes debugging difficult)') +option('systemd-service', type: 'feature', value: 'auto', description: 'Systemd integration (requires libsystemd)') +option('systemd-service-user', type: 'string', value: 'pdns-recursor', description: 'Systemd service user (setuid and unit file; user is not created)') +option('systemd-service-group', type: 'string', value: 'pdns-recursor', 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: 'feature', value: 'disabled', 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: 'feature', value: 'enabled', description: 'Enable Newly Observed Domains') +option('libcap', type: 'feature', value: 'auto', description: 'Enable libcap for capabilities handling') +option('clang-coverage-format', type: 'boolean', value: false, description: 'Whether to generate coverage data in clang format') +option('tls-gnutls', type: 'feature', value: 'auto', description: 'GnuTLS-based TLS') diff -Nru pdns-recursor-5.2.13/metrics.py pdns-recursor-5.4.9/metrics.py --- pdns-recursor-5.2.13/metrics.py 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/metrics.py 2026-10-26 08:26:51.000000000 +0000 @@ -1,6 +1,7 @@ import os import sys import shutil +import metrics_table # default: 'type': uint64 # ptype: "'counter' (vs gauge') @@ -31,9 +32,7 @@ ret = ret.replace('Nsec', 'NSEC') return ret -# read table -with open(srcdir + '/metrics_table.py', mode='r', encoding="utf-8") as file: - table = eval(file.read()) +table = metrics_table.table # # We create various files in the srcdir but copy them into the builddir if needed to satisfy meson diff -Nru pdns-recursor-5.2.13/metrics_table.py pdns-recursor-5.4.9/metrics_table.py --- pdns-recursor-5.2.13/metrics_table.py 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/metrics_table.py 2026-10-26 08:26:51.000000000 +0000 @@ -1,4 +1,4 @@ -# From this table all metrics related files are generated by the metric.py script: +# From this table all metrics related files are generated by the metrics.py script: # # - RECURSOR-MIB.txt # - docs/rec-metrics-gen.rst @@ -17,14 +17,14 @@ # 'longdesc': Extra description added to docs entry. Optional. A dot is added at the end if absent. # 'snmp': 1 SNMP OID count, must be unique. If absent, no SNMP entry is generated # 'snmpname': Override of SNMP name (if legacy name did not follow convention) -# 'ptype': The promethheus type, default counter. Can also be gauge, histogram, multicounter. Also determines SNMP type. +# 'ptype': The prometheus type, default counter. Can also be gauge, histogram, multicounter. Also determines SNMP type. # 'pdesc': Override of Prometheus HELP text, if empty, no Prometheus entry is generated. # 'if': rec_control metrics conditionalized on expression # 'ifdef': rec_control and snmp metrics conditionalized #ifdef name # } # -[ +table = [ { 'name': 'questions', 'lambda': '[] { return g_Counters.sum(rec::Counter::qcounter); }', @@ -85,7 +85,7 @@ 'lambda': 'doGetCacheBytes', 'ptype': 'gauge', 'desc': 'Size of the cache in bytes', - 'longdesc': '''Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. This metric is currently broken, it always is 0.''', + 'longdesc': '''Since version 5.3.0 this metric computes a rough estimate of the number of bytes allocated by the record cache. Older versions return a number that cannot be relied upon. Disabled by default, as computing this number is CPU intensive, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`.''', 'snmp': 7, }, { @@ -112,7 +112,7 @@ 'lambda': '[] { return g_packetCache ? g_packetCache->bytes() : 0; }', 'ptype': 'gauge', 'desc': 'Size of the packetcache in bytes', - 'longdesc': '''Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. This metric is currently broken, it always is 0.''', + 'longdesc': '''Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. This metric is currently broken, it always is 0.''', 'snmp': 11, }, { @@ -569,7 +569,7 @@ 'name': 'noping-outqueries', # XXX obsolete? 'lambda': '[] { return g_Counters.sum(rec::Counter::noPingOutQueries); }', 'snmp': 73, - 'desc': 'Number of outgoing queries without ping', + 'desc': 'Number of outgoing queries without ping', }, { 'name': 'noedns-outqueries', @@ -1020,121 +1020,121 @@ return total; }''', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-no-valid-dnskey', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-invalid-denial', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-unable-to-get-dss', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-unable-to-get-dnskeys', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-self-signed-ds', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-no-rrsig', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-no-valid-rrsig', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-missing-negative-indication', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-signature-not-yet-valid', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-signature-expired', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-unsupported-dnskey-algo', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-unsupported-ds-digest-type', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-no-zone-key-bit-set', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-revoked-dnskey', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-bogus-invalid-dnskey-protocol', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-indeterminate', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-nta', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-insecure', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'x-dnssec-result-secure', 'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); }', 'if': '::arg()["x-dnssec-names"].length() > 0', - 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.' + 'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-yaml-dnssec.x_dnssec_names`.' }, { 'name': 'idle-tcpout-connections', @@ -1357,6 +1357,60 @@ 'snmp': 152, }, { + 'name': 'ecs-missing', + 'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }', + 'desc': 'Number of answers where ECS info was missing', + 'snmp': 153, + }, + { + 'name': 'cookie-malformed', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMalformed); }', + 'desc': 'Number of malformed cookies received', + 'snmp': 154, + }, + { + 'name': 'cookie-matched', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMatched); }', + 'desc': 'Number of matching cookies received', + 'snmp': 155, + }, + { + 'name': 'cookie-mismatch-tcp', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverTCP); }', + 'desc': 'Number of mismatched cookies received over TCP', + 'snmp': 156, + }, + { + 'name': 'cookie-mismatch-udp', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieMismatchedOverUDP); }', + 'desc': 'Number of mismatched cookies received over UDP', + 'snmp': 157, + }, + { + 'name': 'cookie-not-in-reply', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieNotInReply); }', + 'desc': 'Number of times an authoritative server sent a reply without a cookie', + 'snmp': 158, + }, + { + 'name': 'cookie-retry', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieRetry); }', + 'desc': 'Number of retries because authoritative server sent a BADCOOKIE reply', + 'snmp': 159, + }, + { + 'name': 'cookies-supported', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieProbeSupported); }', + 'desc': 'Number of authoritative server cookie probes resulting in success', + 'snmp': 160, + }, + { + 'name': 'cookies-unsupported', + 'lambda': '[] { return g_Counters.sum(rec::Counter::cookieProbeUnsupported); }', + 'desc': 'Number of authoritative server cookie probes not resulting in success', + 'snmp': 161, + }, + { 'name': 'remote-logger-count', 'lambda': '''[]() { return toRemoteLoggerStatsMap("remote-logger-count"); @@ -1370,7 +1424,7 @@ 'name': 'cumul-clientanswers-x', # No lambda 'desc': 'Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.', - 'longdesc': 'Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. These metrics are useful for Prometheus and not listed in other outputs by default.', + 'longdesc': 'Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.', 'ptype': 'histogram', 'pname': 'cumul-clientanswers-count', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec # No SNMP @@ -1379,7 +1433,7 @@ 'name': 'cumul-authanswers-x', # No lambda 'desc': 'Cumulative counts of answer times to clients in buckets less than x microseconds.', - 'longdesc': 'Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. These metrics are useful for Prometheus and not listed in other outputs by default.', + 'longdesc': 'Disabled by default, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`. These metrics are useful for Prometheus and not listed in other outputs by default.', 'ptype': 'histogram', 'pname': 'cumul-authanswers-count4', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec # No SNMP @@ -1401,10 +1455,4 @@ 'pname': 'proxy-mapping-total-n-0', # For multicounters, state the first # No SNMP }, - { - 'name': 'ecs-missing', - 'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }', - 'desc': 'Number of answers where ECS info was missing', - 'snmp': 153, - }, ] diff -Nru pdns-recursor-5.2.13/minicurl.cc pdns-recursor-5.4.9/minicurl.cc --- pdns-recursor-5.2.13/minicurl.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/minicurl.cc 2026-10-26 09:46:36.000000000 +0000 @@ -47,7 +47,7 @@ } } -MiniCurl::MiniCurl(const string& useragent) +MiniCurl::MiniCurl(const string& useragent, bool failonerror) : d_failonerror(failonerror) { #ifdef CURL_STRICTER d_curl = std::unique_ptr(curl_easy_init(), curl_easy_cleanup); @@ -170,7 +170,7 @@ curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_SSL_VERIFYPEER, verify); curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_SSL_VERIFYHOST, verify ? 2 : 0); - curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_FAILONERROR, true); + curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_FAILONERROR, d_failonerror); curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_URL, str.c_str()); curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(getCURLPtr(d_curl), CURLOPT_WRITEDATA, this); @@ -198,14 +198,14 @@ d_data.clear(); } -std::string MiniCurl::getURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, [[maybe_unused]] bool fastopen, bool verify, size_t byteslimit) +std::string MiniCurl::getURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, [[maybe_unused]] bool fastopen, bool verify, size_t byteslimit, int http_status) { setupURL(str, rem, src, timeout, byteslimit, fastopen, verify); auto res = curl_easy_perform(getCURLPtr(d_curl)); long http_code = 0; curl_easy_getinfo(getCURLPtr(d_curl), CURLINFO_RESPONSE_CODE, &http_code); - if ((res != CURLE_OK && res != CURLE_ABORTED_BY_CALLBACK) || http_code != 200) { + if ((res != CURLE_OK && res != CURLE_ABORTED_BY_CALLBACK) || http_code != http_status) { throw std::runtime_error("Unable to retrieve URL ("+std::to_string(http_code)+"): "+string(curl_easy_strerror(res))); } std::string ret = d_data; diff -Nru pdns-recursor-5.2.13/minicurl.hh pdns-recursor-5.4.9/minicurl.hh --- pdns-recursor-5.2.13/minicurl.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/minicurl.hh 2026-10-26 09:46:36.000000000 +0000 @@ -43,11 +43,11 @@ static void init(); - MiniCurl(const string& useragent="MiniCurl/0.0"); + MiniCurl(const string& useragent="MiniCurl/0.0", bool failonerror=true); ~MiniCurl(); MiniCurl& operator=(const MiniCurl&) = delete; - std::string getURL(const std::string& str, const ComboAddress* rem=nullptr, const ComboAddress* src=nullptr, int timeout = 2, bool fastopen = false, bool verify = false, size_t byteslimit = 0); + std::string getURL(const std::string& str, const ComboAddress* rem=nullptr, const ComboAddress* src=nullptr, int timeout = 2, bool fastopen = false, bool verify = false, size_t byteslimit = 0, int http_status = 200); std::string postURL(const std::string& str, const std::string& postdata, MiniCurlHeaders& headers, int timeout = 2, bool fastopen = false, bool verify = false); private: @@ -70,6 +70,7 @@ std::string d_data; size_t d_byteslimit{}; bool d_fresh{true}; + bool d_failonerror; void setupURL(const std::string& str, const ComboAddress* rem, const ComboAddress* src, int timeout, size_t byteslimit, bool fastopen, bool verify); void setHeaders(const MiniCurlHeaders& headers); diff -Nru pdns-recursor-5.2.13/misc.cc pdns-recursor-5.4.9/misc.cc --- pdns-recursor-5.2.13/misc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/misc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include #ifdef __FreeBSD__ # include #endif @@ -142,7 +144,7 @@ else { if (errno == EAGAIN) { struct timeval w = ((totalTimeout.tv_sec == 0 && totalTimeout.tv_usec == 0) || idleTimeout <= remainingTime) ? idleTimeout : remainingTime; - int res = waitForData(fd, w.tv_sec, w.tv_usec); + int res = waitForData(fd, w); if (res > 0) { /* there is data available */ } @@ -186,7 +188,7 @@ throw runtime_error("EOF while writing message"); else { if (errno == EAGAIN) { - int res = waitForRWData(fd, false, timeout.tv_sec, timeout.tv_usec); + int res = waitForRWData(fd, false, timeout); if (res > 0) { /* there is room available */ } @@ -307,76 +309,18 @@ return {buffer.data()}; } -static bool ciEqual(const string& lhs, const string& rhs) -{ - if (lhs.size() != rhs.size()) { - return false; - } - - string::size_type pos = 0; - const string::size_type epos = lhs.size(); - for (; pos < epos; ++pos) { - if (dns_tolower(lhs[pos]) != dns_tolower(rhs[pos])) { - return false; - } - } - return true; -} - -/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */ -static bool endsOn(const string &domain, const string &suffix) -{ - if( suffix.empty() || ciEqual(domain, suffix) ) { - return true; - } - - if(domain.size() <= suffix.size()) { - return false; - } - - string::size_type dpos = domain.size() - suffix.size() - 1; - string::size_type spos = 0; - - if (domain[dpos++] != '.') { - return false; - } - - for(; dpos < domain.size(); ++dpos, ++spos) { - if (dns_tolower(domain[dpos]) != dns_tolower(suffix[spos])) { - return false; - } - } - - return true; -} - -/** strips a domain suffix from a domain, returns true if it stripped */ -bool stripDomainSuffix(string *qname, const string &domain) +// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitForData(int fileDesc, int seconds, int mseconds) { - if (!endsOn(*qname, domain)) { - return false; - } - - if (toLower(*qname) == toLower(domain)) { - *qname="@"; - } - else { - if ((*qname)[qname->size() - domain.size() - 1] != '.') { - return false; - } - - qname->resize(qname->size() - domain.size()-1); - } - return true; + return waitForRWData(fileDesc, true, seconds, mseconds); } -// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set -int waitForData(int fileDesc, int seconds, int useconds) +int waitForData(int fileDesc, struct timeval timeout) { - return waitForRWData(fileDesc, true, seconds, useconds); + return waitForRWData(fileDesc, true, timeout); } -int waitForRWData(int fileDesc, bool waitForRead, int seconds, int useconds, bool* error, bool* disconnected) +int waitForRWData(int fileDesc, bool waitForRead, int seconds, int mseconds, bool* error, bool* disconnected) { struct pollfd pfd{}; memset(&pfd, 0, sizeof(pfd)); @@ -389,7 +333,7 @@ pfd.events = POLLOUT; } - int ret = poll(&pfd, 1, seconds * 1000 + useconds/1000); + int ret = poll(&pfd, 1, seconds * 1000 + mseconds); if (ret > 0) { if ((error != nullptr) && (pfd.revents & POLLERR) != 0) { *error = true; @@ -402,8 +346,13 @@ return ret; } +int waitForRWData(int fileDesc, bool waitForRead, struct timeval timeout, bool* error, bool* disconnected) +{ + return waitForRWData(fileDesc, waitForRead, static_cast(timeout.tv_sec), static_cast(timeout.tv_usec / 1000), error, disconnected); +} + // returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set -int waitForMultiData(const set& fds, const int seconds, const int useconds, int* fdOut) { +int waitForMultiData(const set& fds, const int seconds, const int mseconds, int* fdOut) { set realFDs; for (const auto& fd : fds) { if (fd >= 0 && realFDs.count(fd) == 0) { @@ -422,7 +371,7 @@ int ret; if(seconds >= 0) - ret = poll(pfds.data(), realFDs.size(), seconds * 1000 + useconds/1000); + ret = poll(pfds.data(), realFDs.size(), seconds * 1000 + mseconds); else ret = poll(pfds.data(), realFDs.size(), -1); if(ret <= 0) @@ -440,46 +389,6 @@ return 1; } -// returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set -int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fdPtr) -{ - std::array pfds{}; - memset(pfds.data(), 0, pfds.size() * sizeof(struct pollfd)); - pfds[0].fd = fd1; - pfds[1].fd = fd2; - - pfds[0].events= pfds[1].events = POLLIN; - - int nsocks = 1 + static_cast(fd2 >= 0); // fd2 can optionally be -1 - - int ret{}; - if (seconds >= 0) { - ret = poll(pfds.data(), nsocks, seconds * 1000 + useconds / 1000); - } - else { - ret = poll(pfds.data(), nsocks, -1); - } - if (ret <= 0) { - return ret; - } - - if ((pfds[0].revents & POLLIN) != 0 && (pfds[1].revents & POLLIN) == 0) { - *fdPtr = pfds[0].fd; - } - else if ((pfds[1].revents & POLLIN) != 0 && (pfds[0].revents & POLLIN) == 0) { - *fdPtr = pfds[1].fd; - } - else if(ret == 2) { - *fdPtr = pfds.at(dns_random_uint32() % 2).fd; - } - else { - *fdPtr = -1; // should never happen - } - - return 1; -} - - string humanDuration(time_t passed) { ostringstream ret; @@ -568,20 +477,10 @@ throw std::runtime_error(stringerror()); } - boost::replace_all(*hostname, ".", "_"); + std::replace(hostname->begin(), hostname->end(), '.', '_'); return *hostname; } -string bitFlip(const string &str) -{ - string::size_type pos=0, epos=str.size(); - string ret; - ret.reserve(epos); - for(;pos < epos; ++pos) - ret.append(1, ~str[pos]); - return ret; -} - void cleanSlashes(string &str) { string out; @@ -630,15 +529,16 @@ } -string makeHexDump(const string& str) +string makeHexDump(const string& str, const string& sep) { std::array tmp; string ret; - ret.reserve(static_cast(str.size()*2.2)); + ret.reserve(static_cast(str.size() * (2 + sep.size()))); for (char n : str) { - snprintf(tmp.data(), tmp.size(), "%02x ", static_cast(n)); + snprintf(tmp.data(), tmp.size(), "%02x", static_cast(n)); ret += tmp.data(); + ret += sep; } return ret; } @@ -729,6 +629,62 @@ } } +std::optional logFacilityFromString(std::string facilityStr) +{ + static std::unordered_map const s_facilities = { + {"local0", LOG_LOCAL0}, + {"log_local0", LOG_LOCAL0}, + {"local1", LOG_LOCAL1}, + {"log_local1", LOG_LOCAL1}, + {"local2", LOG_LOCAL2}, + {"log_local2", LOG_LOCAL2}, + {"local3", LOG_LOCAL3}, + {"log_local3", LOG_LOCAL3}, + {"local4", LOG_LOCAL4}, + {"log_local4", LOG_LOCAL4}, + {"local5", LOG_LOCAL5}, + {"log_local5", LOG_LOCAL5}, + {"local6", LOG_LOCAL6}, + {"log_local6", LOG_LOCAL6}, + {"local7", LOG_LOCAL7}, + {"log_local7", LOG_LOCAL7}, + /* most of these likely make very little sense + for us, but why not? */ + {"kern", LOG_KERN}, + {"log_kern", LOG_KERN}, + {"user", LOG_USER}, + {"log_user", LOG_USER}, + {"mail", LOG_MAIL}, + {"log_mail", LOG_MAIL}, + {"daemon", LOG_DAEMON}, + {"log_daemon", LOG_DAEMON}, + {"auth", LOG_AUTH}, + {"log_auth", LOG_AUTH}, + {"syslog", LOG_SYSLOG}, + {"log_syslog", LOG_SYSLOG}, + {"lpr", LOG_LPR}, + {"log_lpr", LOG_LPR}, + {"news", LOG_NEWS}, + {"log_news", LOG_NEWS}, + {"uucp", LOG_UUCP}, + {"log_uucp", LOG_UUCP}, + {"cron", LOG_CRON}, + {"log_cron", LOG_CRON}, + {"authpriv", LOG_AUTHPRIV}, + {"log_authpriv", LOG_AUTHPRIV}, + {"ftp", LOG_FTP}, + {"log_ftp", LOG_FTP} + }; + + toLowerInPlace(facilityStr); + auto facilityIt = s_facilities.find(facilityStr); + if (facilityIt == s_facilities.end()) { + return std::nullopt; + } + + return facilityIt->second; +} + string stripDot(const string& dom) { if(dom.empty()) @@ -870,10 +826,27 @@ return stringfgets(filePtr.get(), *line); } -Regex::Regex(const string &expr) +Regex::Regex(const string& expr): + d_preg(new regex_t) +{ + if (auto ret = regcomp(d_preg.get(), expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED); ret != 0) { + std::array errorBuffer{}; + if (regerror(ret, d_preg.get(), errorBuffer.data(), errorBuffer.size()) > 0) { + throw PDNSException("Regular expression " + expr + " did not compile: " + errorBuffer.data()); + } + throw PDNSException("Regular expression " + expr + " did not compile"); + } +} + +/** call this to find out if 'line' matches your expression */ +bool Regex::match(const string &line) const { - if(regcomp(&d_preg, expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED)) - throw PDNSException("Regular expression did not compile"); + return regexec(d_preg.get(), line.c_str(), 0, nullptr, 0) == 0; +} + +bool Regex::match(const DNSName& name) const +{ + return match(name.toStringNoDot()); } // if you end up here because valgrind told you were are doing something wrong @@ -1024,6 +997,36 @@ return true; } +void setDscp(int sock, unsigned short family, uint8_t dscp) +{ + int val = 0; + unsigned int len = 0; + + if (dscp == 0 || dscp > 63) { + // No DSCP marking + return; + } + + if (family == AF_INET) { + if (getsockopt(sock, IPPROTO_IP, IP_TOS, &val, &len)<0) { + throw std::runtime_error(string("Set DSCP failed: ")+stringerror()); + } + val = (dscp<<2) | (val&0x3); + if (setsockopt(sock, IPPROTO_IP, IP_TOS, &val, sizeof(val))<0) { + throw std::runtime_error(string("Set DSCP failed: ")+stringerror()); + } + } + else if (family == AF_INET6) { + if (getsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, &len)<0) { + throw std::runtime_error(string("Set DSCP failed: ")+stringerror()); + } + val = (dscp<<2) | (val&0x3); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val))<0) { + throw std::runtime_error(string("Set DSCP failed: ")+stringerror()); + } + } +} + bool isNonBlocking(int sock) { int flags=fcntl(sock,F_GETFL,0); @@ -1350,20 +1353,27 @@ bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum) { - if (algoName == DNSName("hmac-md5.sig-alg.reg.int") || algoName == DNSName("hmac-md5")) + if (algoName == g_hmacmd5dnsname_long || algoName == g_hmacmd5dnsname) { algoEnum = TSIG_MD5; - else if (algoName == DNSName("hmac-sha1")) + } + else if (algoName == g_hmacsha1dnsname) { algoEnum = TSIG_SHA1; - else if (algoName == DNSName("hmac-sha224")) + } + else if (algoName == g_hmacsha224dnsname) { algoEnum = TSIG_SHA224; - else if (algoName == DNSName("hmac-sha256")) + } + else if (algoName == g_hmacsha256dnsname) { algoEnum = TSIG_SHA256; - else if (algoName == DNSName("hmac-sha384")) + } + else if (algoName == g_hmacsha384dnsname) { algoEnum = TSIG_SHA384; - else if (algoName == DNSName("hmac-sha512")) + } + else if (algoName == g_hmacsha512dnsname) { algoEnum = TSIG_SHA512; - else if (algoName == DNSName("gss-tsig")) + } + else if (algoName == g_gsstsigdnsname) { algoEnum = TSIG_GSS; + } else { return false; } @@ -1373,13 +1383,13 @@ DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum) { switch(algoEnum) { - case TSIG_MD5: return DNSName("hmac-md5.sig-alg.reg.int."); - case TSIG_SHA1: return DNSName("hmac-sha1."); - case TSIG_SHA224: return DNSName("hmac-sha224."); - case TSIG_SHA256: return DNSName("hmac-sha256."); - case TSIG_SHA384: return DNSName("hmac-sha384."); - case TSIG_SHA512: return DNSName("hmac-sha512."); - case TSIG_GSS: return DNSName("gss-tsig."); + case TSIG_MD5: return g_hmacmd5dnsname_long; + case TSIG_SHA1: return g_hmacsha1dnsname; + case TSIG_SHA224: return g_hmacsha224dnsname; + case TSIG_SHA256: return g_hmacsha256dnsname; + case TSIG_SHA384: return g_hmacsha384dnsname; + case TSIG_SHA512: return g_hmacsha512dnsname; + case TSIG_GSS: return g_gsstsigdnsname; } throw PDNSException("getTSIGAlgoName does not understand given algorithm, please fix!"); } @@ -1387,17 +1397,29 @@ uint64_t getOpenFileDescriptors(const std::string&) { #ifdef __linux__ + const auto* const dirName = "/proc/self/fd"; + struct stat status; // NOLINT(cppcoreguidelines-pro-type-member-init) + auto ret = stat(dirName, &status); + if (ret != 0) { + return 0; + } + if (status.st_size != 0) { // Until linux 6.1, this would return 0 + return status.st_size; + } + + // This can lead to performance issues with *many* open fds uint64_t nbFileDescriptors = 0; - const auto dirName = "/proc/" + std::to_string(getpid()) + "/fd/"; auto directoryError = pdns::visit_directory(dirName, [&nbFileDescriptors]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) { - uint32_t num; + uint32_t num{}; try { pdns::checked_stoi_into(num, std::string(name)); if (std::to_string(num) == name) { nbFileDescriptors++; } - } catch (...) { + } + catch (...) { // was not a number. + ; } return true; }); @@ -1804,3 +1826,17 @@ } } + +const char* timestamp(time_t arg, timebuf_t& buf) +{ + const std::string s_timestampFormat = "%Y-%m-%dT%T"; + struct tm tmval{}; + size_t len = strftime(buf.data(), buf.size(), s_timestampFormat.c_str(), localtime_r(&arg, &tmval)); + if (len == 0) { + int ret = snprintf(buf.data(), buf.size(), "%lld", static_cast(arg)); + if (ret < 0 || static_cast(ret) >= buf.size()) { + buf[0] = '\0'; + } + } + return buf.data(); +} diff -Nru pdns-recursor-5.2.13/misc.hh pdns-recursor-5.4.9/misc.hh --- pdns-recursor-5.2.13/misc.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/misc.hh 2026-10-26 09:46:36.000000000 +0000 @@ -38,12 +38,19 @@ #include #include #include +#include #include +#include #include #include "namespaces.hh" class DNSName; +#if defined(PDNS_AUTH) +class ZoneName; +#else +using ZoneName = DNSName; +#endif // Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it typedef enum @@ -96,19 +103,20 @@ string nowTime(); string unquotify(const string &item); string humanDuration(time_t passed); -bool stripDomainSuffix(string *qname, const string &domain); void stripLine(string &line); std::optional getHostname(); std::string getCarbonHostName(); string urlEncode(const string &text); -int waitForData(int fileDesc, int seconds, int useconds = 0); -int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd); -int waitForMultiData(const set& fds, const int seconds, const int useconds, int* fd); -int waitForRWData(int fileDesc, bool waitForRead, int seconds, int useconds, bool* error = nullptr, bool* disconnected = nullptr); +int waitForData(int fileDesc, int seconds, int mseconds = 0); +int waitForData(int fileDesc, struct timeval timeout); +int waitForMultiData(const set& fds, const int seconds, const int mseconds, int* fd); +int waitForRWData(int fileDesc, bool waitForRead, int seconds, int mseconds, bool* error = nullptr, bool* disconnected = nullptr); +int waitForRWData(int fileDesc, bool waitForRead, struct timeval timeout, bool* error = nullptr, bool* disconnected = nullptr); bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum); DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum); int logFacilityToLOG(unsigned int facility); +std::optional logFacilityFromString(std::string facilityStr); template void @@ -139,10 +147,16 @@ } } -template bool rfc1982LessThan(T a, T b) +template bool rfc1982LessThan(T lhs, T rhs) { static_assert(std::is_unsigned_v, "rfc1982LessThan only works for unsigned types"); - return std::make_signed_t(a - b) < 0; + return static_cast>(lhs - rhs) < 0; +} + +template bool rfc1982LessThanOrEqual(T lhs, T rhs) +{ + static_assert(std::is_unsigned_v, "rfc1982LessThanOrEqual only works for unsigned types"); + return static_cast>(lhs - rhs) <= 0; } // fills container with ranges, so {posbegin,posend} @@ -192,8 +206,6 @@ return pdns::getMessageFromErrno(err); } -string bitFlip(const string &str); - void dropPrivs(int uid, int gid); void cleanSlashes(string &str); @@ -294,31 +306,24 @@ inline const string toLowerCanonic(const string &upper) { string reply(upper); - if(!upper.empty()) { - unsigned int i, limit= ( unsigned int ) reply.length(); - unsigned char c; - for(i = 0; i < limit ; i++) { - c = dns_tolower(upper[i]); - if(c != upper[i]) - reply[i] = c; + if (!reply.empty()) { + const auto length = reply.length(); + if (reply[length - 1] == '.') { + reply.resize(length - 1); } - if(upper[i-1]=='.') - reply.resize(i-1); + toLowerInPlace(reply); } - return reply; } - - // Make s uppercase: inline string toUpper( const string& s ) { - string r(s); - for( unsigned int i = 0; i < s.length(); i++ ) { - r[i] = dns_toupper(r[i]); - } - return r; + string r(s); + for (size_t i = 0; i < s.length(); ++i) { + r[i] = dns_toupper(r[i]); + } + return r; } inline double getTime() @@ -334,8 +339,8 @@ throw runtime_error(why + ": " + stringerror(errno)); } -string makeHexDump(const string& str); -//! Convert the hexstring in to a byte string +string makeHexDump(const string& str, const string& sep = " "); +//! Convert the hexstring to a byte string string makeBytesFromHex(const string &in); void normalizeTV(struct timeval& tv); @@ -366,20 +371,38 @@ } -inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure)); -inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) +inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b) __attribute__((pure)); +inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b) { - const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str(); + const unsigned char *aPtr = (const unsigned char*)a.data(), *bPtr = (const unsigned char*)b.data(); const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length(); while(aPtr != aEptr && bPtr != bEptr) { - if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr))) - return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0; + if (*aPtr != *bPtr) { + if (int rc = dns_tolower(*aPtr) - dns_tolower(*bPtr); rc != 0) { + return rc; + } + } aPtr++; bPtr++; } - if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length) - return false; - return aPtr == aEptr; // true if first string was shorter + // At this point, one of the strings has been completely processed. + // Either both have the same length, and they are equal, or one of them + // is larger, and compares as higher. + if (aPtr == aEptr) { + if (bPtr != bEptr) { + return -1; // a < b + } + } + else { + return 1; // a > b + } + return 0; // a == b +} + +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure)); +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) +{ + return pdns_ilexicographical_compare_three_way(a, b) < 0; } inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure)); @@ -388,15 +411,7 @@ if (a.length() != b.length()) return false; - const char *aPtr = a.c_str(), *bPtr = b.c_str(); - const char *aEptr = aPtr + a.length(); - while(aPtr != aEptr) { - if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr))) - return false; - aPtr++; - bPtr++; - } - return true; + return pdns_ilexicographical_compare_three_way(a, b) == 0; } inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure)); @@ -467,20 +482,18 @@ pair splitField(const string& inp, char sepa); -inline bool isCanonical(const string& qname) +inline bool isCanonical(std::string_view qname) { - if(qname.empty()) - return false; - return qname[qname.size()-1]=='.'; + return boost::ends_with(qname, "."); } -inline DNSName toCanonic(const DNSName& zone, const string& qname) +inline DNSName toCanonic(const ZoneName& zone, const string& qname) { if(qname.size()==1 && qname[0]=='@') - return zone; + return DNSName(zone); if(isCanonical(qname)) return DNSName(qname); - return DNSName(qname) += zone; + return DNSName(qname) += DNSName(zone); } string stripDot(const string& dom); @@ -505,29 +518,32 @@ public: /** constructor that accepts the expression to regex */ Regex(const string &expr); - - ~Regex() - { - regfree(&d_preg); - } + Regex(const Regex&) = delete; + Regex& operator=(const Regex&) = delete; + Regex(Regex&& rhs) = default; + Regex& operator=(Regex&& rhs) = default; + ~Regex() = default; /** call this to find out if 'line' matches your expression */ - bool match(const string &line) const - { - return regexec(&d_preg,line.c_str(),0,0,0)==0; - } - bool match(const DNSName& name) const - { - return match(name.toStringNoDot()); - } + bool match(const string &line) const; + bool match(const DNSName& name) const; private: - regex_t d_preg; + struct Deleter + { + void operator()(regex_t* ptr) const noexcept { + regfree(ptr); + delete ptr; + } + }; + + std::unique_ptr d_preg; }; class SimpleMatch { public: - SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold) + SimpleMatch(string mask, bool caseFold = false) : + d_mask(std::move(mask)), d_fold(caseFold) { } @@ -568,6 +584,12 @@ return match(name.toStringNoDot()); } +#if defined(PDNS_AUTH) // [ + bool match(const ZoneName& name) const { + return match(name.toStringNoDot()); + } +#endif // ] + private: const string d_mask; const bool d_fold; @@ -589,6 +611,8 @@ //! Sets the socket into blocking mode. bool setBlocking( int sock ); +void setDscp(int sock, unsigned short family, uint8_t dscp); + //! Sets the socket into non-blocking mode. bool setNonBlocking( int sock ); bool setTCPNoDelay(int sock); @@ -782,7 +806,7 @@ DNSName reverseNameFromIP(const ComboAddress& ip); -size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel +size_t parseRFC1035CharString(std::string_view in, std::string &val); // from ragel size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector &val); // from ragel size_t parseSVCBValueList(const std::string &in, vector &val); @@ -834,13 +858,20 @@ int reset() { int ret = 0; - if (d_fd >= 0) { + if (d_fd >= 0) { // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult): obvious false positive ret = close(d_fd); } d_fd = -1; return ret; } + int release() + { + auto ret = d_fd; + d_fd = -1; + return ret; + } + private: int d_fd{-1}; }; @@ -867,3 +898,6 @@ UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false); } + +using timebuf_t = std::array; +const char* timestamp(time_t arg, timebuf_t& buf); diff -Nru pdns-recursor-5.2.13/mkpubsuffixcc pdns-recursor-5.4.9/mkpubsuffixcc --- pdns-recursor-5.2.13/mkpubsuffixcc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/mkpubsuffixcc 2026-10-26 08:26:51.000000000 +0000 @@ -1,12 +1,18 @@ #!/bin/sh -if [ -z "$1" ] || [ -z "$2" ]; then - echo "Usage: $0 effective_tld_names.dat pubsuffix.cc" +if [ -z "$1" ]; then + echo "Usage: $0 pubsuffix.cc" exit 1 fi set -e -(echo "const char* g_pubsuffix[]={"; - for a in $(grep -v "//" "$1" | grep \\. | egrep "^[.0-9a-z-]*$") - do - echo \"$a\", - done -echo "0};") > "$2" +echo "Downloading public suffix data and generating $1" +temp=$(mktemp pubsuffixXXXXXX) +trap "rm -f $temp" 0 1 2 3 15 +set -e +curl -o $temp -s -S https://publicsuffix.org/list/public_suffix_list.dat +(echo "#include \"pubsuffix.hh\"" + echo "const std::string g_pubsuffix = "; + for a in $(grep -v "//" "$temp" | grep \\. | egrep "^[.0-9a-z-]*$") + do + echo \"$a\\\\n\" + done +echo ";") > "$1" diff -Nru pdns-recursor-5.2.13/mplexer.hh pdns-recursor-5.4.9/mplexer.hh --- pdns-recursor-5.2.13/mplexer.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/mplexer.hh 2026-10-26 09:46:36.000000000 +0000 @@ -42,7 +42,7 @@ }; /** Very simple FD multiplexer, based on callbacks and boost::any parameters - As a special service, this parameter is kept around and can be modified, + As a special service, this parameter is kept around and can be modified, allowing for state to be stored inside the multiplexer. It has some "interesting" semantics @@ -70,9 +70,6 @@ }; public: - FDMultiplexer() : - d_inrun(false) - {} virtual ~FDMultiplexer() = default; // The maximum number of events processed in a single run, not the maximum of watched descriptors @@ -221,11 +218,11 @@ const auto tied = std::tie(tv.tv_sec, tv.tv_usec); auto& idx = writes ? d_writeCallbacks.get() : d_readCallbacks.get(); - for (auto it = idx.begin(); it != idx.end(); ++it) { - if (it->d_ttd.tv_sec == 0 || tied <= std::tie(it->d_ttd.tv_sec, it->d_ttd.tv_usec)) { + for (const auto& t : idx) { + if (t.d_ttd.tv_sec == 0 || tied <= std::tie(t.d_ttd.tv_sec, t.d_ttd.tv_usec)) { break; } - ret.emplace_back(it->d_fd, it->d_parameter); + ret.emplace_back(t.d_fd, t.d_parameter); } return ret; @@ -296,7 +293,7 @@ callbackmap_t; callbackmap_t d_readCallbacks, d_writeCallbacks; - bool d_inrun; + bool d_inrun{false}; void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd) { diff -Nru pdns-recursor-5.2.13/mtasker.hh pdns-recursor-5.4.9/mtasker.hh --- pdns-recursor-5.2.13/mtasker.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/mtasker.hh 2026-10-26 08:26:51.000000000 +0000 @@ -50,9 +50,7 @@ { EventKey key; std::shared_ptr context; - struct timeval ttd - { - }; + struct timeval ttd{}; int tid{}; }; struct KeyTag @@ -266,18 +264,14 @@ waiter.ttd.tv_sec = 0; waiter.ttd.tv_usec = 0; if (timeoutMsec != 0) { - struct timeval increment - { - }; + struct timeval increment{}; increment.tv_sec = timeoutMsec / 1000; increment.tv_usec = static_cast(1000 * (timeoutMsec % 1000)); if (now != nullptr) { waiter.ttd = increment + *now; } else { - struct timeval realnow - { - }; + struct timeval realnow{}; gettimeofday(&realnow, nullptr); waiter.ttd = increment + realnow; } diff -Nru pdns-recursor-5.2.13/mtasker_context.cc pdns-recursor-5.4.9/mtasker_context.cc --- pdns-recursor-5.2.13/mtasker_context.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/mtasker_context.cc 2026-10-26 08:26:51.000000000 +0000 @@ -95,7 +95,7 @@ using boost::context::detail::transfer_t; #endif /* BOOST_VERSION < 106100 */ -static_assert(std::is_pointer::value, +static_assert(std::is_pointer_v, "Boost Context has changed the fcontext_t type again :-("); #endif @@ -118,6 +118,11 @@ threadWrapper(intptr_t const xargs) { #else + // If you see asan trouble in this function, run with + // ASAN_OPTIONS=detect_stack_use_after_return=0 or completely disable it by compiling with + // -fsanitize-address-use-after-return=never. On debian clang versions up and including 14 do + // not seem to trigger a problem here, but starting from version 15 they do. + // Attempts at using function attributes to silence the error did not work. threadWrapper(transfer_t const theThread) { #endif @@ -155,12 +160,13 @@ *ptr = res.fctx; } #endif + auto start = std::move(*work); notifyStackSwitchDone(); args = nullptr; try { - auto start = std::move(*work); - start(); + auto localstart = std::move(start); + localstart(); } catch (...) { ctx->exception = std::current_exception(); @@ -218,7 +224,7 @@ if (origctx && origctx->exception) std::rethrow_exception(origctx->exception); #else - transfer_t res = jump_fcontext(static_cast(ctx.uc_mcontext), &octx.uc_mcontext); + transfer_t res = jump_fcontext(static_cast(ctx.uc_mcontext), static_cast(&octx.uc_mcontext)); CET_ENDBR; if (res.data != nullptr) { /* if res.data is not a nullptr, it holds a pointer to the context diff -Nru pdns-recursor-5.2.13/namespaces.hh pdns-recursor-5.4.9/namespaces.hh --- pdns-recursor-5.2.13/namespaces.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/namespaces.hh 2026-10-26 09:46:36.000000000 +0000 @@ -21,7 +21,6 @@ */ #pragma once -#include #include #include #include diff -Nru pdns-recursor-5.2.13/negcache.cc pdns-recursor-5.4.9/negcache.cc --- pdns-recursor-5.2.13/negcache.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/negcache.cc 2026-10-26 08:26:51.000000000 +0000 @@ -24,7 +24,6 @@ #include "negcache.hh" #include "misc.hh" #include "cachecleaner.hh" -#include "utility.hh" #include "rec-taskqueue.hh" // For a description on how ServeStale works, see recursor_cache.cc, the general structure is the same. @@ -50,8 +49,8 @@ auto ret = sizeof(NegCacheEntry); ret += authoritySOA.sizeEstimate(); ret += DNSSECRecords.sizeEstimate(); - ret += d_name.wirelength(); - ret += d_auth.wirelength(); + ret += d_name.sizeEstimate(); + ret += d_auth.sizeEstimate(); return ret; } @@ -85,12 +84,12 @@ void NegCache::updateStaleEntry(time_t now, negcache_t::iterator& entry, QType qtype) { - // We need to take care a infrequently access stale item cannot be extended past + // We need to take care an infrequently access stale item cannot be extended past // s_maxServedStaleExtension * s_serveStaleExtensionPeriod // We we look how old the entry is, and increase d_servedStale accordingly, taking care not to overflow const time_t howlong = std::max(static_cast(1), now - entry->d_ttd); const uint32_t extension = std::max(1U, std::min(entry->d_orig_ttl, s_serveStaleExtensionPeriod)); - entry->d_servedStale = std::min(entry->d_servedStale + 1 + howlong / extension, static_cast(s_maxServedStaleExtensions)); + entry->d_servedStale = std::min(entry->d_servedStale + 1 + (howlong / extension), static_cast(s_maxServedStaleExtensions)); entry->d_ttd = now + std::min(entry->d_orig_ttl, s_serveStaleExtensionPeriod); if (qtype == QType::ENT) { @@ -109,7 +108,7 @@ * \param ne A NegCacheEntry that is filled when there is a cache entry * \return true if ne was filled out, false otherwise */ -bool NegCache::get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch, bool serveStale, bool refresh) +bool NegCache::get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& negEntry, bool typeMustMatch, bool serveStale, bool refresh) { auto& map = getMap(qname); auto content = map.lock(); @@ -136,10 +135,10 @@ } if (now.tv_sec < ni->d_ttd) { // Not expired - ne = *ni; + negEntry = *ni; moveCacheItemToBack(content->d_map, firstIndexIterator); // when refreshing, we consider served-stale entries outdated - return !(refresh && ni->d_servedStale > 0); + return !refresh || ni->d_servedStale <= 0; } } } @@ -172,10 +171,9 @@ * \param qtype The type of the entry to replace * \param newState The new validation state */ -void NegCache::updateValidationStatus(const DNSName& qname, const QType qtype, const vState newState, boost::optional capTTD) +void NegCache::updateValidationStatus(const DNSName& qname, const QType qtype, const vState newState, std::optional capTTD) { - auto& mc = getMap(qname); - auto map = mc.lock(); + auto map = getMap(qname).lock(); auto range = map->d_map.equal_range(std::tie(qname, qtype)); if (range.first != range.second) { @@ -223,11 +221,12 @@ size_t ret = 0; if (subtree) { for (auto& map : d_maps) { - auto m = map.lock(); - for (auto i = m->d_map.lower_bound(std::tie(name)); i != m->d_map.end();) { - if (!i->d_name.isPartOf(name)) + auto lockedMap = map.lock(); + for (auto i = lockedMap->d_map.lower_bound(std::tie(name)); i != lockedMap->d_map.end();) { + if (!i->d_name.isPartOf(name)) { break; - i = m->d_map.erase(i); + } + i = lockedMap->d_map.erase(i); ret++; map.decEntriesCount(); } @@ -238,9 +237,9 @@ auto& map = getMap(name); auto content = map.lock(); auto range = content->d_map.equal_range(std::tie(name)); - auto i = range.first; - while (i != range.second) { - i = content->d_map.erase(i); + auto iter = range.first; + while (iter != range.second) { + iter = content->d_map.erase(iter); ret++; map.decEntriesCount(); } @@ -253,15 +252,15 @@ auto& map = getMap(qname); auto content = map.lock(); auto range = content->d_map.equal_range(std::tie(qname)); - auto i = range.first; - while (i != range.second) { - if (i->d_qtype == QType::ENT || i->d_qtype == qtype) { - i = content->d_map.erase(i); + auto iter = range.first; + while (iter != range.second) { + if (iter->d_qtype == QType::ENT || iter->d_qtype == qtype) { + iter = content->d_map.erase(iter); ++ret; map.decEntriesCount(); } else { - ++i; + ++iter; } } return ret; @@ -273,8 +272,8 @@ void NegCache::clear() { for (auto& map : d_maps) { - auto m = map.lock(); - m->d_map.clear(); + auto lockedMap = map.lock(); + lockedMap->d_map.clear(); map.clearEntriesCount(); } } @@ -295,9 +294,9 @@ * * \param fd A pointer to an open FILE object */ -size_t NegCache::doDump(int fd, size_t maxCacheEntries, time_t now) +size_t NegCache::doDump(int fileDesc, size_t maxCacheEntries, time_t now) { - int newfd = dup(fd); + int newfd = dup(fileDesc); if (newfd == -1) { return 0; } @@ -313,28 +312,28 @@ size_t shard = 0; size_t min = std::numeric_limits::max(); size_t max = 0; - for (auto& mc : d_maps) { - auto m = mc.lock(); - const auto shardSize = m->d_map.size(); + for (auto& map : d_maps) { + auto lockedMap = map.lock(); + const auto shardSize = lockedMap->d_map.size(); fprintf(filePtr.get(), "; negcache shard %zu; size %zu\n", shard, shardSize); min = std::min(min, shardSize); max = std::max(max, shardSize); shard++; - auto& sidx = m->d_map.get(); - for (const NegCacheEntry& ne : sidx) { + auto& sidx = lockedMap->d_map.get(); + for (const NegCacheEntry& negEntry : sidx) { ret++; - int64_t ttl = ne.d_ttd - now; - fprintf(filePtr.get(), "%s %" PRId64 " IN %s VIA %s ; (%s) origttl=%" PRIu32 " ss=%hu\n", ne.d_name.toString().c_str(), ttl, ne.d_qtype.toString().c_str(), ne.d_auth.toString().c_str(), vStateToString(ne.d_validationState).c_str(), ne.d_orig_ttl, ne.d_servedStale); - for (const auto& rec : ne.authoritySOA.records) { - fprintf(filePtr.get(), "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), ttl, DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.getContent()->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str()); + int64_t ttl = negEntry.d_ttd - now; + fprintf(filePtr.get(), "%s %" PRId64 " IN %s VIA %s ; (%s) origttl=%" PRIu32 " ss=%hu\n", negEntry.d_name.toString().c_str(), ttl, negEntry.d_qtype.toString().c_str(), negEntry.d_auth.toString().c_str(), vStateToString(negEntry.d_validationState).c_str(), negEntry.d_orig_ttl, negEntry.d_servedStale); + for (const auto& rec : negEntry.authoritySOA.records) { + fprintf(filePtr.get(), "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), ttl, DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.getContent()->getZoneRepresentation().c_str(), vStateToString(negEntry.d_validationState).c_str()); } - for (const auto& sig : ne.authoritySOA.signatures) { + for (const auto& sig : negEntry.authoritySOA.signatures) { fprintf(filePtr.get(), "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), ttl, sig.getContent()->getZoneRepresentation().c_str()); } - for (const auto& rec : ne.DNSSECRecords.records) { - fprintf(filePtr.get(), "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), ttl, DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.getContent()->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str()); + for (const auto& rec : negEntry.DNSSECRecords.records) { + fprintf(filePtr.get(), "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), ttl, DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.getContent()->getZoneRepresentation().c_str(), vStateToString(negEntry.d_validationState).c_str()); } - for (const auto& sig : ne.DNSSECRecords.signatures) { + for (const auto& sig : negEntry.DNSSECRecords.signatures) { fprintf(filePtr.get(), "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), ttl, sig.getContent()->getZoneRepresentation().c_str()); } } diff -Nru pdns-recursor-5.2.13/negcache.hh pdns-recursor-5.4.9/negcache.hh --- pdns-recursor-5.2.13/negcache.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/negcache.hh 2026-10-26 08:26:51.000000000 +0000 @@ -21,13 +21,11 @@ */ #pragma once -#include #include #include #include #include #include -#include #include "dnsparser.hh" #include "dnsname.hh" #include "dns.hh" @@ -54,14 +52,10 @@ { size_t ret = sizeof(recordsAndSignatures); for (const auto& entry : records) { - ret += sizeof(DNSRecord); - ret += entry.d_name.wirelength(); - ret += entry.getContent()->serialize(entry.d_name, true).size(); + ret += entry.sizeEstimate(); } for (const auto& entry : signatures) { - ret += sizeof(DNSRecord); - ret += entry.d_name.wirelength(); - ret += entry.getContent()->serialize(entry.d_name, true).size(); + ret += entry.sizeEstimate(); } return ret; } @@ -97,9 +91,7 @@ if (s_maxServedStaleExtensions > 0) { return d_ttd + static_cast(s_maxServedStaleExtensions) * std::min(s_serveStaleExtensionPeriod, d_orig_ttl) < now; } - else { - return d_ttd < now; - } + return d_ttd < now; }; bool isEntryUsable(time_t now, bool serveStale) const @@ -110,18 +102,18 @@ [[nodiscard]] size_t sizeEstimate() const; }; - void add(const NegCacheEntry& ne); - void updateValidationStatus(const DNSName& qname, QType qtype, vState newState, boost::optional capTTD); - bool get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch = false, bool serverStale = false, bool refresh = false); + void add(const NegCacheEntry& negEntry); + void updateValidationStatus(const DNSName& qname, QType qtype, vState newState, std::optional capTTD); + bool get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& negEntry, bool typeMustMatch = false, bool serveStale = false, bool refresh = false); bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& negEntry, bool serveStale, bool refresh); size_t count(const DNSName& qname); size_t count(const DNSName& qname, QType qtype); void prune(time_t now, size_t maxEntries); void clear(); - size_t doDump(int fd, size_t maxCacheEntries, time_t now = time(nullptr)); + size_t doDump(int fileDesc, size_t maxCacheEntries, time_t now = time(nullptr)); size_t wipe(const DNSName& name, bool subtree = false); size_t wipeTyped(const DNSName& name, QType qtype); - size_t size() const; + [[nodiscard]] size_t size() const; private: struct CompositeKey @@ -130,7 +122,7 @@ struct SequenceTag { }; - typedef boost::multi_index_container< + using negcache_t = boost::multi_index_container< NegCacheEntry, indexed_by< ordered_unique, @@ -139,19 +131,21 @@ member, member>, composite_key_compare< - CanonDNSNameCompare, std::less>>, + CanonDNSNameCompare, std::less<>>>, sequenced>, hashed_non_unique, - member>>> - negcache_t; + member>>>; - void updateStaleEntry(time_t now, negcache_t::iterator& entry, QType qtype); + static void updateStaleEntry(time_t now, negcache_t::iterator& entry, QType qtype); struct MapCombo { - MapCombo() {} + MapCombo() = default; MapCombo(const MapCombo&) = delete; MapCombo& operator=(const MapCombo&) = delete; + ~MapCombo() = default; + MapCombo(MapCombo&&) = delete; + MapCombo& operator=(MapCombo&&) = delete; struct LockedContent { negcache_t d_map; @@ -203,7 +197,7 @@ { return d_maps.at(qname.hash() % d_maps.size()); } - const MapCombo& getMap(const DNSName& qname) const + [[nodiscard]] const MapCombo& getMap(const DNSName& qname) const { return d_maps.at(qname.hash() % d_maps.size()); } diff -Nru pdns-recursor-5.2.13/nod.cc pdns-recursor-5.4.9/nod.cc --- pdns-recursor-5.2.13/nod.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/nod.cc 2026-10-26 08:26:51.000000000 +0000 @@ -24,12 +24,10 @@ #include #include "pdnsexception.hh" #include -#include #include #include #include "threadname.hh" #include -#include "logger.hh" #include "logging.hh" #include "misc.hh" @@ -40,7 +38,7 @@ std::mutex PersistentSBF::d_cachedir_mutex; -void PersistentSBF::remove_tmp_files(const filesystem::path& path, std::lock_guard& /* lock */) +void PersistentSBF::remove_tmp_files(const filesystem::path& path, std::scoped_lock& /* lock */) { Regex file_regex(d_prefix + ".*\\." + bf_suffix + "\\..{8}$"); for (const auto& file : filesystem::directory_iterator(path)) { @@ -58,7 +56,7 @@ bool PersistentSBF::init(bool ignore_pid) { auto log = g_slog->withName("nod"); - std::lock_guard lock(d_cachedir_mutex); + std::scoped_lock lock(d_cachedir_mutex); if (d_cachedir.length() != 0) { filesystem::path path(d_cachedir); try { @@ -83,8 +81,7 @@ std::ifstream infile; try { infile.open(filename, std::ios::in | std::ios::binary); - SLOG(g_log << Logger::Warning << "Found SBF file " << filename << endl, - log->info(Logr::Warning, "Found SBF File", "file", Logging::Loggable(filename))); + log->info(Logr::Warning, "Found SBF File", "file", Logging::Loggable(filename)); // read the file into the sbf d_sbf.lock()->restore(infile); infile.close(); @@ -96,15 +93,13 @@ catch (const std::runtime_error& e) { infile.close(); filesystem::remove(newest_file); - SLOG(g_log << Logger::Warning << "NODDB init: Cannot parse file: " << filename << ": " << e.what() << "; removed" << endl, - log->error(Logr::Warning, e.what(), "NODDB init: Cannot parse file, removed", "file", Logging::Loggable(filename))); + log->error(Logr::Warning, e.what(), "NODDB init: Cannot parse file, removed", "file", Logging::Loggable(filename)); } } } } catch (const filesystem::filesystem_error& e) { - SLOG(g_log << Logger::Warning << "NODDB init failed: " << e.what() << endl, - log->error(Logr::Warning, e.what(), "NODDB init failed", "exception", Logging::Loggable("filesystem::filesystem_error"))); + log->error(Logr::Warning, e.what(), "NODDB init failed", "exception", Logging::Loggable("filesystem::filesystem_error")); return false; } } @@ -163,21 +158,18 @@ filesystem::rename(ftmp, file); } catch (const std::runtime_error& e) { - SLOG(g_log << Logger::Warning << "NODDB snapshot: Cannot rename file: " << e.what() << endl, - log->error(Logr::Warning, e.what(), "NODDB snapshot: Cannot rename file", "exception", Logging::Loggable("std::runtime_error"))); + log->error(Logr::Warning, e.what(), "NODDB snapshot: Cannot rename file", "exception", Logging::Loggable("std::runtime_error")); filesystem::remove(ftmp); throw; } return true; } catch (const std::runtime_error& e) { - SLOG(g_log << Logger::Warning << "NODDB snapshot: Cannot write file: " << e.what() << endl, - log->error(Logr::Warning, e.what(), "NODDB snapshot: Cannot write file", "exception", Logging::Loggable("std::runtime_error"))); + log->error(Logr::Warning, e.what(), "NODDB snapshot: Cannot write file", "exception", Logging::Loggable("std::runtime_error")); } } else { - SLOG(g_log << Logger::Warning << "NODDB snapshot: Cannot write file: " << file.string() << endl, - log->info(Logr::Warning, "NODDB snapshot: Cannot write file", "file", Logging::Loggable(file.string()))); + log->info(Logr::Warning, "NODDB snapshot: Cannot write file", "file", Logging::Loggable(file.string())); } } return false; diff -Nru pdns-recursor-5.2.13/nod.hh pdns-recursor-5.4.9/nod.hh --- pdns-recursor-5.2.13/nod.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/nod.hh 2026-10-26 08:26:51.000000000 +0000 @@ -20,10 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once -#include + #include #include #include + #include "dnsname.hh" #include "lock.hh" #include "stable-bloom.hh" @@ -64,7 +65,7 @@ } private: - void remove_tmp_files(const boost::filesystem::path&, std::lock_guard&); + void remove_tmp_files(const boost::filesystem::path&, std::scoped_lock&); LockGuarded d_sbf; // Stable Bloom Filter std::string d_cachedir; diff -Nru pdns-recursor-5.2.13/noinitvector.hh pdns-recursor-5.4.9/noinitvector.hh --- pdns-recursor-5.2.13/noinitvector.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/noinitvector.hh 2026-10-26 09:46:36.000000000 +0000 @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff -Nru pdns-recursor-5.2.13/nsecrecords.cc pdns-recursor-5.4.9/nsecrecords.cc --- pdns-recursor-5.2.13/nsecrecords.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/nsecrecords.cc 2026-10-26 09:46:36.000000000 +0000 @@ -174,7 +174,7 @@ return std::make_shared(content); } -NSECRecordContent::NSECRecordContent(const string& content, const DNSName& zone) +NSECRecordContent::NSECRecordContent(const string& content, const ZoneName& zone) { RecordTextReader rtr(content, zone); rtr.xfrName(d_next); @@ -223,7 +223,7 @@ return std::make_shared(content); } -NSEC3RecordContent::NSEC3RecordContent(const string& content, const DNSName& zone) +NSEC3RecordContent::NSEC3RecordContent(const string& content, const ZoneName& zone) { RecordTextReader rtr(content, zone); rtr.xfr8BitInt(d_algorithm); @@ -297,7 +297,7 @@ return std::make_shared(content); } -NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const DNSName& zone) +NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const ZoneName& zone) { RecordTextReader rtr(content, zone); rtr.xfr8BitInt(d_algorithm); @@ -353,7 +353,7 @@ return std::make_shared(content); } -CSYNCRecordContent::CSYNCRecordContent(const string& content, const DNSName& zone) +CSYNCRecordContent::CSYNCRecordContent(const string& content, const ZoneName& zone) { RecordTextReader rtr(content, zone); rtr.xfr32BitInt(d_serial); diff -Nru pdns-recursor-5.2.13/opensslsigners.cc pdns-recursor-5.4.9/opensslsigners.cc --- pdns-recursor-5.2.13/opensslsigners.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/opensslsigners.cc 2026-10-26 09:46:36.000000000 +0000 @@ -48,7 +48,7 @@ #include #include "opensslsigners.hh" #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.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. */ @@ -315,15 +315,15 @@ void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits) { // When changing the bitsizes, also edit them in ::checkKey - if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) && (bits < 512 || bits > 4096)) { + if ((d_algorithm == DNSSEC::RSASHA1 || d_algorithm == DNSSEC::RSASHA1NSEC3SHA1) && (bits < 512 || bits > 4096)) { /* RFC3110 */ throw runtime_error(getName() + " RSASHA1 key generation failed for invalid bits size " + std::to_string(bits)); } - if (d_algorithm == DNSSECKeeper::RSASHA256 && (bits < 512 || bits > 4096)) { + if (d_algorithm == DNSSEC::RSASHA256 && (bits < 512 || bits > 4096)) { /* RFC5702 */ throw runtime_error(getName() + " RSASHA256 key generation failed for invalid bits size " + std::to_string(bits)); } - if (d_algorithm == DNSSECKeeper::RSASHA512 && (bits < 1024 || bits > 4096)) { + if (d_algorithm == DNSSEC::RSASHA512 && (bits < 1024 || bits > 4096)) { /* RFC5702 */ throw runtime_error(getName() + " RSASHA512 key generation failed for invalid bits size " + std::to_string(bits)); } @@ -594,14 +594,14 @@ string algorithm = std::to_string(d_algorithm); switch (d_algorithm) { - case DNSSECKeeper::RSASHA1: - case DNSSECKeeper::RSASHA1NSEC3SHA1: + case DNSSEC::RSASHA1: + case DNSSEC::RSASHA1NSEC3SHA1: algorithm += " (RSASHA1)"; break; - case DNSSECKeeper::RSASHA256: + case DNSSEC::RSASHA256: algorithm += " (RSASHA256)"; break; - case DNSSECKeeper::RSASHA512: + case DNSSEC::RSASHA512: algorithm += " (RSASHA512)"; break; default: @@ -626,12 +626,12 @@ std::size_t OpenSSLRSADNSCryptoKeyEngine::hashSize() const { switch (d_algorithm) { - case DNSSECKeeper::RSASHA1: - case DNSSECKeeper::RSASHA1NSEC3SHA1: + case DNSSEC::RSASHA1: + case DNSSEC::RSASHA1NSEC3SHA1: return SHA_DIGEST_LENGTH; - case DNSSECKeeper::RSASHA256: + case DNSSEC::RSASHA256: return SHA256_DIGEST_LENGTH; - case DNSSECKeeper::RSASHA512: + case DNSSEC::RSASHA512: return SHA512_DIGEST_LENGTH; default: throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm)); @@ -643,14 +643,14 @@ const EVP_MD* messageDigest = nullptr; switch (d_algorithm) { - case DNSSECKeeper::RSASHA1: - case DNSSECKeeper::RSASHA1NSEC3SHA1: + case DNSSEC::RSASHA1: + case DNSSEC::RSASHA1NSEC3SHA1: messageDigest = EVP_sha1(); break; - case DNSSECKeeper::RSASHA256: + case DNSSEC::RSASHA256: messageDigest = EVP_sha256(); break; - case DNSSECKeeper::RSASHA512: + case DNSSEC::RSASHA512: messageDigest = EVP_sha512(); break; default: @@ -666,7 +666,7 @@ std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& message) const { - if (d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) { + if (d_algorithm == DNSSEC::RSASHA1 || d_algorithm == DNSSEC::RSASHA1NSEC3SHA1) { std::string l_hash{}; l_hash.resize(SHA_DIGEST_LENGTH); // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs. @@ -674,7 +674,7 @@ return l_hash; } - if (d_algorithm == DNSSECKeeper::RSASHA256) { + if (d_algorithm == DNSSEC::RSASHA256) { std::string l_hash{}; l_hash.resize(SHA256_DIGEST_LENGTH); // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs. @@ -682,7 +682,7 @@ return l_hash; } - if (d_algorithm == DNSSECKeeper::RSASHA512) { + if (d_algorithm == DNSSEC::RSASHA512) { std::string l_hash{}; l_hash.resize(SHA512_DIGEST_LENGTH); // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs. @@ -881,13 +881,13 @@ { bool retval = true; // When changing the bitsizes, also edit them in ::create - if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1 || d_algorithm == DNSSECKeeper::RSASHA256) && (getBits() < 512 || getBits() > 4096)) { + if ((d_algorithm == DNSSEC::RSASHA1 || d_algorithm == DNSSEC::RSASHA1NSEC3SHA1 || d_algorithm == DNSSEC::RSASHA256) && (getBits() < 512 || getBits() > 4096)) { retval = false; if (errorMessages.has_value()) { errorMessages->get().push_back("key is " + std::to_string(getBits()) + " bytes, should be between 512 and 4096"); } } - if (d_algorithm == DNSSECKeeper::RSASHA512 && (getBits() < 1024 || getBits() > 4096)) { + if (d_algorithm == DNSSEC::RSASHA512 && (getBits() < 1024 || getBits() > 4096)) { retval = false; if (errorMessages.has_value()) { errorMessages->get().push_back("key is " + std::to_string(getBits()) + " bytes, should be between 1024 and 4096"); @@ -941,7 +941,7 @@ if (contentLen < 3) { throw runtime_error(getName() + " invalid input size for the public key"); } - const size_t exponentSize = raw[1] * 0xff + raw[2]; + const size_t exponentSize = (static_cast(raw[1])) * 0x100 + raw[2]; if (contentLen < (exponentSize + 4)) { throw runtime_error(getName() + " invalid input size for the public key"); } @@ -1313,10 +1313,10 @@ const EVP_MD* messageDigest = nullptr; switch (d_algorithm) { - case DNSSECKeeper::ECDSA256: + case DNSSEC::ECDSA256: messageDigest = EVP_sha256(); break; - case DNSSECKeeper::ECDSA384: + case DNSSEC::ECDSA384: messageDigest = EVP_sha384(); break; default: @@ -1333,9 +1333,9 @@ std::size_t OpenSSLECDSADNSCryptoKeyEngine::hashSize() const { switch (d_algorithm) { - case DNSSECKeeper::ECDSA256: + case DNSSEC::ECDSA256: return SHA256_DIGEST_LENGTH; - case DNSSECKeeper::ECDSA384: + case DNSSEC::ECDSA384: return SHA384_DIGEST_LENGTH; default: throw runtime_error(getName() + " does not support hash operations for algorithm " + std::to_string(d_algorithm)); @@ -2053,19 +2053,19 @@ { LoaderStruct() { - DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA1, &OpenSSLRSADNSCryptoKeyEngine::maker); - DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA1NSEC3SHA1, &OpenSSLRSADNSCryptoKeyEngine::maker); - DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA256, &OpenSSLRSADNSCryptoKeyEngine::maker); - DNSCryptoKeyEngine::report(DNSSECKeeper::RSASHA512, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::RSASHA1, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::RSASHA1NSEC3SHA1, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::RSASHA256, &OpenSSLRSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::RSASHA512, &OpenSSLRSADNSCryptoKeyEngine::maker); #ifdef HAVE_LIBCRYPTO_ECDSA - DNSCryptoKeyEngine::report(DNSSECKeeper::ECDSA256, &OpenSSLECDSADNSCryptoKeyEngine::maker); - DNSCryptoKeyEngine::report(DNSSECKeeper::ECDSA384, &OpenSSLECDSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::ECDSA256, &OpenSSLECDSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::ECDSA384, &OpenSSLECDSADNSCryptoKeyEngine::maker); #endif #ifdef HAVE_LIBCRYPTO_ED25519 - DNSCryptoKeyEngine::report(DNSSECKeeper::ED25519, &OpenSSLEDDSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::ED25519, &OpenSSLEDDSADNSCryptoKeyEngine::maker); #endif #ifdef HAVE_LIBCRYPTO_ED448 - DNSCryptoKeyEngine::report(DNSSECKeeper::ED448, &OpenSSLEDDSADNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::ED448, &OpenSSLEDDSADNSCryptoKeyEngine::maker); #endif } } loaderOpenSSL; diff -Nru pdns-recursor-5.2.13/packetcache.hh pdns-recursor-5.4.9/packetcache.hh --- pdns-recursor-5.2.13/packetcache.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/packetcache.hh 2026-10-26 09:46:36.000000000 +0000 @@ -33,7 +33,7 @@ - EDNS Cookie options, if any ; - Any given option code present in optionsToSkip */ - static uint32_t hashAfterQname(const std::string_view& packet, uint32_t currentHash, size_t pos, const std::unordered_set& optionsToSkip = {EDNSOptionCode::COOKIE}) + static uint32_t hashAfterQname(const std::string_view& packet, uint32_t currentHash, size_t pos, const std::unordered_set& optionsToSkip = {EDNSOptionCode::COOKIE}, const std::vector& payloadRanks = {}) { const size_t packetSize = packet.size(); assert(packetSize >= sizeof(dnsheader)); @@ -46,14 +46,31 @@ */ const dnsheader_aligned dnsheaderdata(packet.data()); const struct dnsheader *dh = dnsheaderdata.get(); - if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || ntohs(dh->arcount) != 1 || (pos + 15) >= packetSize) { + if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || ntohs(dh->arcount) != 1 || (pos + 15) > packetSize) { if (packetSize > pos) { currentHash = burtle(reinterpret_cast(&packet.at(pos)), packetSize - pos, currentHash); } return currentHash; } - currentHash = burtle(reinterpret_cast(&packet.at(pos)), 15, currentHash); + if (payloadRanks.empty()) { + currentHash = burtle(reinterpret_cast(&packet.at(pos)), 15, currentHash); + } + else { + std::vector optrr(packet.begin() + pos, packet.begin() + pos + 15); + uint16_t bufSize = optrr.at(7) * 256 + optrr.at(8); + auto it = std::upper_bound(payloadRanks.begin(), payloadRanks.end(), bufSize); + if (it != payloadRanks.begin()) { + it--; + optrr[7] = (*it) >> 8; + optrr[8] = (*it) & 0xff; + } + currentHash = burtle(reinterpret_cast(&optrr.at(0)), 15, currentHash); + } + if ( (pos + 15) == packetSize ) { + return currentHash; + } + /* skip the qtype (2), qclass (2) */ /* root label (1), type (2), class (2) and ttl (4) */ /* already hashed above */ diff -Nru pdns-recursor-5.2.13/pdns-recursor.service.in pdns-recursor-5.4.9/pdns-recursor.service.in --- pdns-recursor-5.2.13/pdns-recursor.service.in 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/pdns-recursor.service.in 2026-10-26 08:26:51.000000000 +0000 @@ -7,6 +7,7 @@ [Service] ExecStart=@sbindir@/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no +ExecStop=@bindir@/rec_control --socket-dir=%t/pdns-recursor quit-nicely User=@service_user@ Group=@service_group@ Type=notify diff -Nru pdns-recursor-5.2.13/pdns-recursor.service.meson.in pdns-recursor-5.4.9/pdns-recursor.service.meson.in --- pdns-recursor-5.2.13/pdns-recursor.service.meson.in 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/pdns-recursor.service.meson.in 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,53 @@ +[Unit] +Description=@Description@ +Documentation=man:pdns_recursor(1) +Documentation=man:rec_control(1) +Documentation=https://doc.powerdns.com +Wants=network-online.target +After=network-online.target time-sync.target + +[Service] +ExecStart=@StaticBinDir@/pdns_recursor @ConfigName@ @SocketDir@ --daemon=no --write-pid=no --disable-syslog --log-timestamp=no +ExecStop=@BinDir@/rec_control @ConfigName@ @RecControlSocketDir@ quit-nicely +User=@ServiceUser@ +Group=@ServiceGroup@ +Type=notify +Restart=on-failure +StartLimitInterval=0 +RuntimeDirectory=@RuntimeDirectory@ +SyslogIdentifier=@SyslogIdentifier@ + +# Tuning +LimitNOFILE=16384 + +# Sandboxing +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN +@LockPersonality@ +NoNewPrivileges=true +@PrivateDevices@ +@PrivateTmp@ +# Setting PrivateUsers=true prevents us from opening our sockets +@ProtectClock@ +@ProtectControlGroups@ +@ProtectHome@ +@ProtectHostname@ +@ProtectKernelLogs@ +@ProtectKernelModules@ +@ProtectKernelTunables@ +@ProtectSystem@ +@RestrictAddressFamilies@ +@RestrictNamespaces@ +@RestrictRealtime@ +@RestrictSUIDSGID@ +@SystemCallArchitectures@ +@SystemCallFilter@ +@ProtectProc@ +@PrivateIPC@ +@RemoveIPC@ +DevicePolicy=closed +# Not enabled by default because it does not play well with LuaJIT +@MemoryDenyWriteExecute@ + +[Install] +WantedBy=multi-user.target diff -Nru pdns-recursor-5.2.13/pdns_recursor.1 pdns-recursor-5.4.9/pdns_recursor.1 --- pdns-recursor-5.2.13/pdns_recursor.1 2026-08-05 12:02:34.000000000 +0000 +++ pdns-recursor-5.4.9/pdns_recursor.1 2026-10-26 09:47:32.000000000 +0000 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "PDNS_RECURSOR" "1" "Aug 05, 2026" "" "PowerDNS Recursor" +.TH "PDNS_RECURSOR" "1" "Oct 26, 2026" "" "PowerDNS Recursor" .SH NAME pdns_recursor \- The PowerDNS Recursor binary .SH SYNOPSIS @@ -64,7 +64,7 @@ .sp .nf .ft C -# rec_control quit +# rec_control quit\-nicely .ft P .fi .UNINDENT @@ -108,9 +108,6 @@ .B \-\-daemon Operate as a daemon. .TP -.BI \-\-entropy\-source\fB= -Read new entropy from \fIfile\fP, defaults to /dev/urandom. -.TP .B \-\-export\-etc\-hosts If set, this flag will export the hostnames and IP addresses mentioned in /etc/hosts. diff -Nru pdns-recursor-5.2.13/pdns_recursor.cc pdns-recursor-5.4.9/pdns_recursor.cc --- pdns-recursor-5.2.13/pdns_recursor.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/pdns_recursor.cc 2026-10-26 08:26:51.000000000 +0000 @@ -59,6 +59,9 @@ thread_local std::shared_ptr t_allowFrom; thread_local std::shared_ptr t_allowNotifyFrom; thread_local std::shared_ptr t_allowNotifyFor; +thread_local std::shared_ptr t_proxyProtocolACL; +thread_local std::shared_ptr> t_proxyProtocolExceptions; + __thread struct timeval g_now; // timestamp, updated (too) frequently using listenSocketsAddresses_t = map; // is shared across all threads right now @@ -79,7 +82,7 @@ bool g_gettagNeedsEDNSOptions{false}; bool g_useKernelTimestamp; std::atomic g_maxCacheEntries, g_maxPacketCacheEntries; -boost::container::flat_set g_avoidUdpSourcePorts; +std::vector g_avoidUdpSourcePorts; uint16_t g_minUdpSourcePort; uint16_t g_maxUdpSourcePort; double g_balancingFactor; @@ -96,9 +99,9 @@ GlobalStateHolder g_DoTToAuthNames; uint64_t g_latencyStatSize; -LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, int* fileDesc) +LWResult::Result UDPClientSocks::getSocket(const ComboAddress& toaddr, const std::optional& localAddress, int* fileDesc) { - *fileDesc = makeClientSocket(toaddr.sin4.sin_family); + *fileDesc = makeClientSocket(toaddr.sin4.sin_family, localAddress); if (*fileDesc < 0) { // temporary error - receive exception otherwise return LWResult::Result::OSLimitError; } @@ -109,8 +112,7 @@ closesocket(*fileDesc); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error closing UDP socket after connect() failed: " << e.reason << endl, - g_slogout->error(Logr::Error, e.reason, "Error closing UDP socket after connect() failed", "exception", Logging::Loggable("PDNSException"))); + g_slogout->error(Logr::Error, e.reason, "Error closing UDP socket after connect() failed", "exception", Logging::Loggable("PDNSException")); } if (err == ENETUNREACH) { // Seth "My Interfaces Are Like A Yo Yo" Arnold special @@ -138,15 +140,14 @@ closesocket(fileDesc); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error closing returned UDP socket: " << e.reason << endl, - g_slogout->error(Logr::Error, e.reason, "Error closing returned UDP socket", "exception", Logging::Loggable("PDNSException"))); + g_slogout->error(Logr::Error, e.reason, "Error closing returned UDP socket", "exception", Logging::Loggable("PDNSException")); } --d_numsocks; } // returns -1 for errors which might go away, throws for ones that won't -int UDPClientSocks::makeClientSocket(int family) +int UDPClientSocks::makeClientSocket(int family, const std::optional& localAddress) { int ret = socket(family, SOCK_DGRAM, 0); // turns out that setting CLO_EXEC and NONBLOCK from here is not a performance win on Linux (oddly enough) @@ -175,10 +176,18 @@ else { do { port = g_minUdpSourcePort + dns_random(g_maxUdpSourcePort - g_minUdpSourcePort + 1); - } while (g_avoidUdpSourcePorts.count(port) != 0); + } while (g_avoidUdpSourcePorts[port]); } - sin = pdns::getQueryLocalAddress(family, port); // does htons for us + // localAddress is set if a cookie was involved, bind to the same address the cookie is + // associated with (RFC 9018 section 3 last paragraph) + if (localAddress) { + sin = *localAddress; + sin.setPort(port); + } + else { + sin = pdns::getQueryLocalAddress(family, port); // does htons for us + } if (::bind(ret, reinterpret_cast(&sin), sin.getSocklen()) >= 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) break; } @@ -212,8 +221,7 @@ ssize_t ret = recvfrom(fileDesc, resp.data(), resp.size(), 0, reinterpret_cast(&fromaddr), &addrlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) if (fromaddr != pident->remote) { - SLOG(g_log << Logger::Notice << "Response received from the wrong remote host (" << fromaddr.toStringWithPort() << " instead of " << pident->remote.toStringWithPort() << "), discarding" << endl, - g_slog->withName("lua")->info(Logr::Notice, "Response received from the wrong remote host. discarding", "method", Logging::Loggable("GenUDPQueryResponse"), "fromaddr", Logging::Loggable(fromaddr), "expected", Logging::Loggable(pident->remote))); + g_slog->withName("lua")->info(Logr::Notice, "Response received from the wrong remote host. discarding", "method", Logging::Loggable("GenUDPQueryResponse"), "fromaddr", Logging::Loggable(fromaddr), "expected", Logging::Loggable(pident->remote)); } t_fdm->removeReadFD(fileDesc); @@ -276,7 +284,7 @@ /* 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, const std::optional& ecs, int* fileDesc, timeval& now) + const ComboAddress& toAddress, std::optional& localAddress, uint16_t qid, const DNSName& domain, uint16_t qtype, const std::optional& ecs, int* fileDesc, timeval& now) { auto pident = std::make_shared(); @@ -284,7 +292,7 @@ pident->remote = toAddress; pident->type = qtype; if (ecs) { - pident->ecsSubnet = ecs->source; + pident->ecsSubnet = ecs->getSource(); } // See if there is an existing outstanding request we can chain on to, using partial equivalence @@ -316,7 +324,7 @@ } } - auto ret = t_udpclientsocks->getSocket(toAddress, fileDesc); + auto ret = t_udpclientsocks->getSocket(toAddress, localAddress, fileDesc); if (ret != LWResult::Result::Success) { return ret; } @@ -357,7 +365,7 @@ // We expect incoming source ECS to match, see https://www.rfc-editor.org/rfc/rfc7871#section-7.3 // But there's also section 11-2, which says we should treat absent incoming ecs as scope zero // We fill in the search key with the ecs we sent out, so both cases are covered and accepted here. - pident->ecsSubnet = ecs->source; + pident->ecsSubnet = ecs->getSource(); } int ret = g_multiTasker->waitEvent(pident, &packet, authWaitTimeMSec(g_multiTasker), &now); len = 0; @@ -380,12 +388,11 @@ if (nearMissLimit > 0 && pident->nearMisses > nearMissLimit) { /* we have received more than nearMissLimit answers on the right IP and port, from the right source (we are using connected sockets), for the correct qname and qtype, but with an unexpected message ID. That looks like a spoofing attempt. */ - SLOG(g_log << Logger::Error << "Too many (" << pident->nearMisses << " > " << nearMissLimit << ") answers with a wrong message ID for '" << domain << "' from " << fromAddr.toString() << ", assuming spoof attempt." << endl, - g_slogudpin->info(Logr::Error, "Too many answers with a wrong message ID, assuming spoofing attempt", - "nearmisses", Logging::Loggable(pident->nearMisses), - "nearmisslimit", Logging::Loggable(nearMissLimit), - "qname", Logging::Loggable(domain), - "from", Logging::Loggable(fromAddr))); + g_slogudpin->info(Logr::Error, "Too many answers with a wrong message ID, assuming spoofing attempt", + "nearmisses", Logging::Loggable(pident->nearMisses), + "nearmisslimit", Logging::Loggable(nearMissLimit), + "qname", Logging::Loggable(domain), + "from", Logging::Loggable(fromAddr)); t_Counters.at(rec::Counter::spoofCount)++; return LWResult::Result::Spoofed; } @@ -538,8 +545,7 @@ } if (resolver.doLog() && appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) { - SLOG(g_log << Logger::Warning << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << appliedPolicy.getLogString() << endl, - appliedPolicy.info(Logr::Warning, resolver.d_slog)); + appliedPolicy.info(Logr::Warning, resolver.d_slog); } if (appliedPolicy.d_zoneData && appliedPolicy.d_zoneData->d_extendedErrorCode) { @@ -590,27 +596,24 @@ } catch (const ImmediateServFailException& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during resolve of the custom filter policy '" << appliedPolicy.getName() << "' while resolving '" << comboWriter->d_mdp.d_qname << "' because: " << e.reason << endl, - resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during resolve of the custom filter policy", - "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("ImmediateServFailException"))); + resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during resolve of the custom filter policy", + "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("ImmediateServFailException")); } res = RCode::ServFail; break; } catch (const pdns::validation::TooManySEC3IterationsException& e) { if (g_logCommonErrors || (g_dnssecLogBogus && resolver.getDNSSECLimitHit())) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during resolve of the custom filter policy '" << appliedPolicy.getName() << "' while resolving '" << comboWriter->d_mdp.d_qname << "' because: " << e.what() << endl, - resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during resolve of the custom filter policy", - "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("TooManySEC3IterationsException"), "dnsseclimithit", Logging::Loggable(resolver.getDNSSECLimitHit()))); + resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during resolve of the custom filter policy", + "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("TooManySEC3IterationsException"), "dnsseclimithit", Logging::Loggable(resolver.getDNSSECLimitHit())); } res = RCode::ServFail; break; } catch (const PolicyHitException& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during resolve of the custom filter policy '" << appliedPolicy.getName() << "' while resolving '" << comboWriter->d_mdp.d_qname << "' because another RPZ policy was hit" << endl, - resolver.d_slog->info(Logr::Notice, "Sending SERVFAIL during resolve of the custom filter policy because another RPZ policy was hit", - "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("PolicyHitException"))); + resolver.d_slog->info(Logr::Notice, "Sending SERVFAIL during resolve of the custom filter policy because another RPZ policy was hit", + "policyName", Logging::Loggable(appliedPolicy.getName()), "exception", Logging::Loggable("PolicyHitException")); } res = RCode::ServFail; break; @@ -637,8 +640,7 @@ 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")); + nodlogger->info(Logr::Notice, "New domain observed"); } t_Counters.at(rec::Counter::nodCount)++; ret = true; @@ -681,12 +683,11 @@ if (g_udrDBp && g_udrDBp->isUniqueResponse(strStream.str())) { if (g_udrLog) { // This should also probably log to a dedicated file. - SLOG(g_log << Logger::Notice << "Unique response observed: qname=" << dname << " qtype=" << QType(qtype) << " rrtype=" << QType(record.d_type) << " rrname=" << record.d_name << " rrcontent=" << record.getContent()->getZoneRepresentation() << endl, - nodlogger->info(Logr::Notice, "New response observed", - "qtype", Logging::Loggable(QType(qtype)), - "rrtype", Logging::Loggable(QType(record.d_type)), - "rrname", Logging::Loggable(record.d_name), - "rrcontent", Logging::Loggable(record.getContent()->getZoneRepresentation()));); + nodlogger->info(Logr::Notice, "New response observed", + "qtype", Logging::Loggable(QType(qtype)), + "rrtype", Logging::Loggable(QType(record.d_type)), + "rrname", Logging::Loggable(record.d_name), + "rrcontent", Logging::Loggable(record.getContent()->getZoneRepresentation())); } t_Counters.at(rec::Counter::udrCount)++; ret = true; @@ -791,22 +792,7 @@ ret.end()); } else { - // Remove double SOA records - std::set 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()); + pdns::dedupRecords(ret); } t_Counters.at(rec::Counter::dns64prefixanswers)++; return rcode; @@ -840,7 +826,7 @@ record.setContent(std::make_shared(newquery)); // Copy the TTL of the synthesized CNAME from the actual answer record.d_ttl = (rcode == RCode::NoError && !answers.empty()) ? answers.at(0).d_ttl : SyncRes::s_minimumTTL; - ret.push_back(record); + ret.push_back(std::move(record)); ret.insert(ret.end(), answers.begin(), answers.end()); @@ -922,16 +908,14 @@ int traceFd = dup(t_tracefd); if (traceFd == -1) { int err = errno; - SLOG(g_log << Logger::Error << "Could not dup trace file: " << stringerror(err) << endl, - g_slog->withName("trace")->error(Logr::Error, err, "Could not dup trace file")); + g_slog->withName("trace")->error(Logr::Error, err, "Could not dup trace file"); return; } setNonBlocking(traceFd); auto filep = pdns::UniqueFilePtr(fdopen(traceFd, "a")); if (!filep) { int err = errno; - SLOG(g_log << Logger::Error << "Could not write to trace file: " << stringerror(err) << endl, - g_slog->withName("trace")->error(Logr::Error, err, "Could not write to trace file")); + g_slog->withName("trace")->error(Logr::Error, err, "Could not write to trace file"); close(traceFd); return; } @@ -942,8 +926,7 @@ isoDateTimeMillis(now, timebuf); if (ferror(filep.get()) != 0) { int err = errno; - SLOG(g_log << Logger::Error << "Problems writing to trace file: " << stringerror(err) << endl, - g_slog->withName("trace")->error(Logr::Error, err, "Problems writing to trace file")); + g_slog->withName("trace")->error(Logr::Error, err, "Problems writing to trace file"); // There's no guarantee the message below will end up in the stream, but we try our best clearerr(filep.get()); fprintf(filep.get(), "=== TRACE %s TRUNCATED; USE FILE ARGUMENT INSTEAD OF `-' ===\n", timebuf.data()); @@ -982,6 +965,64 @@ } } +static RecursorPacketCache::ECSInfo findScopeZero(const std::vector& response) +{ + uint16_t optRR{}; + size_t optLen{}; + bool last{}; + auto ret = locateEDNSOptRR(response, &optRR, &optLen, &last); + if (ret != 0) { + return {0, 0}; + } + + // Root + EDNS record fixed part + ttl + optRR += 1 + sizeof(EDNS0Record) + DNS_TTL_SIZE; + + if (optRR >= response.size()) { + return {0, 0}; + } + size_t pos{}; + size_t size{}; + ret = getEDNSOption(reinterpret_cast(&response.at(optRR)), response.size() - optRR, EDNSOptionCode::ECS, &pos, &size); + if (ret != 0) { + return {0, 0}; + } + // pos is relative to optRR + pos += optRR; + // skip option code; + pos += 2; + + //cerr << "Found " << size << ' ' << makeHexDump(string(&response.at(pos), size)) << endl; + // Size includes optioncode and length, total 4 bytes + if (size < 4) { + return {0, 0}; + } + size_t ecsLen = size - 4; + + return {pos, ecsLen}; +} + +static void substituteScopeZero(std::string& response, RecursorPacketCache::ECSInfo ecsInfo, const std::string& ecsPayload) +{ + auto [pos, ecsLen] = ecsInfo; + // We only do the case where the substitute is exactly the same size as the original stored in the PC + if (ecsLen != ecsPayload.size()) { + return; + } + // Skip option length + pos += 2; + // Belt plus suspenders + if (pos + ecsLen > response.size()) { + //cerr << "Y " << pos << ' ' << ecsLen << ' ' << response.size() << endl; + return; + } + // XXX Do we need to check family? + //cerr << "Foun2 " << ecsLen << ' ' << makeHexDump(string(&response.at(pos), ecsLen)) << endl; + //cerr << "Paylo " << ecsPayload.size() << ' ' << makeHexDump(ecsPayload) << endl; + response.replace(pos, ecsLen, ecsPayload); + //cerr << "After " << ecsLen << ' ' << makeHexDump(string(&response.at(pos), ecsLen)) << endl; +} + void startDoResolve(void* arg) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791 { auto comboWriter = std::unique_ptr(static_cast(arg)); @@ -1031,7 +1072,7 @@ for (const auto& option : edo.d_options) { if (option.first == EDNSOptionCode::ECS && g_useIncomingECS && !comboWriter->d_ecsParsed) { - comboWriter->d_ecsFound = getEDNSSubnetOptsFromString(option.second, &comboWriter->d_ednssubnet); + comboWriter->d_ecsFound = EDNSSubnetOpts::getFromString(option.second, &comboWriter->d_ednssubnet); } else if (option.first == EDNSOptionCode::NSID) { const static string mode_server_id = ::arg()["server-id"]; @@ -1095,6 +1136,7 @@ bool seenAuthSOA = false; resolver.d_eventTrace = std::move(comboWriter->d_eventTrace); + resolver.d_otTrace = std::move(comboWriter->d_otTrace); resolver.setId(g_multiTasker->getTid()); bool DNSSECOK = false; @@ -1155,7 +1197,7 @@ } // lookup failing cannot happen as dc->d_source != dc->d_mappedSource } - resolver.setQuerySource(useMapped ? comboWriter->d_mappedSource : comboWriter->d_source, g_useIncomingECS && !comboWriter->d_ednssubnet.source.empty() ? boost::optional(comboWriter->d_ednssubnet) : boost::none); + resolver.setQuerySource(useMapped ? comboWriter->d_mappedSource : comboWriter->d_source, g_useIncomingECS && !comboWriter->d_ednssubnet.getSource().empty() ? boost::optional(comboWriter->d_ednssubnet) : boost::none); resolver.setQueryReceivedOverTCP(comboWriter->d_tcp); @@ -1189,7 +1231,7 @@ "qtype", Logging::Loggable(QType(comboWriter->d_mdp.d_qtype)), "remote", Logging::Loggable(comboWriter->getRemote()), "proto", Logging::Loggable(comboWriter->d_tcp ? "tcp" : "udp"), - "ecs", Logging::Loggable(comboWriter->d_ednssubnet.source.empty() ? "" : comboWriter->d_ednssubnet.source.toString()), + "ecs", Logging::Loggable(comboWriter->d_ednssubnet.getSource().empty() ? "" : comboWriter->d_ednssubnet.getSource().toString()), "mtid", Logging::Loggable(g_multiTasker->getTid())); RunningResolveGuard tcpGuard(comboWriter); @@ -1210,17 +1252,7 @@ } if (!g_quiet || tracedQuery) { - if (!g_slogStructured) { - g_log << Logger::Warning << RecThreadInfo::id() << " [" << g_multiTasker->getTid() << "/" << g_multiTasker->numProcesses() << "] " << (comboWriter->d_tcp ? "TCP " : "") << "question for '" << comboWriter->d_mdp.d_qname << "|" - << QType(comboWriter->d_mdp.d_qtype) << "' from " << comboWriter->getRemote(); - if (!comboWriter->d_ednssubnet.source.empty()) { - g_log << " (ecs " << comboWriter->d_ednssubnet.source.toString() << ")"; - } - g_log << endl; - } - else { - resolver.d_slog->info(Logr::Info, "Question"); - } + resolver.d_slog->info(Logr::Info, "Question"); } if (!comboWriter->d_mdp.d_header.rd) { @@ -1248,7 +1280,7 @@ /* If we already have an answer generated from gettag_ffi, let's see if the filtering policies should be applied to it */ - if (comboWriter->d_rcode != boost::none) { + if (comboWriter->d_rcode != std::nullopt) { bool policyOverride = false; /* Unless we already matched on the client IP, time to check the qname. @@ -1328,21 +1360,18 @@ catch (const ImmediateQueryDropException& e) { // XXX We need to export a protobuf message (and do a NOD lookup) if requested! t_Counters.at(rec::Counter::policyDrops)++; - SLOG(g_log << Logger::Debug << "Dropping query because of a filtering policy " << makeLoginfo(comboWriter) << endl, - resolver.d_slog->info(Logr::Debug, "Dropping query because of a filtering policy")); + resolver.d_slog->info(Logr::Debug, "Dropping query because of a filtering policy"); return; } catch (const ImmediateServFailException& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during resolve of '" << comboWriter->d_mdp.d_qname << "' because: " << e.reason << endl, - resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during resolve")); + resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during resolve"); } res = RCode::ServFail; } catch (const pdns::validation::TooManySEC3IterationsException& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during resolve of '" << comboWriter->d_mdp.d_qname << "' because: " << e.what() << endl, - resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during resolve", "dnsseclimithit", Logging::Loggable(true))); + resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during resolve", "dnsseclimithit", Logging::Loggable(true)); } res = RCode::ServFail; } @@ -1410,9 +1439,9 @@ PolicyResult policyResult = PolicyResult::NoAction; if (comboWriter->d_luaContext->hasPostResolveFFIfunc()) { RecursorLua4::PostResolveFFIHandle handle(dnsQuestion); - resolver.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI); + auto match = resolver.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI); bool prResult = comboWriter->d_luaContext->postresolve_ffi(handle); - resolver.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI, prResult, false); + resolver.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI, prResult, false, match); if (prResult) { shouldNotValidate = true; policyResult = handlePolicyHit(appliedPolicy, comboWriter, resolver, res, ret, packetWriter, tcpGuard); @@ -1474,8 +1503,7 @@ } if (state == vState::Secure) { if (resolver.doLog()) { - SLOG(g_log << Logger::Warning << "Answer to " << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << x_marker << " for " << comboWriter->getRemote() << " validates correctly" << endl, - log->info(Logr::Info, "Validates Correctly")); + log->info(Logr::Info, "Validates Correctly"); } // Is the query source interested in the value of the ad-bit? @@ -1485,8 +1513,7 @@ } else if (state == vState::Insecure) { if (resolver.doLog()) { - SLOG(g_log << Logger::Warning << "Answer to " << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << x_marker << " for " << comboWriter->getRemote() << " validates as Insecure" << endl, - log->info(Logr::Info, "Validates as Insecure")); + log->info(Logr::Info, "Validates as Insecure"); } packetWriter.getHeader()->ad = 0; @@ -1499,15 +1526,13 @@ t_bogusqueryring->push_back({comboWriter->d_mdp.d_qname, comboWriter->d_mdp.d_qtype}); } if (g_dnssecLogBogus || resolver.doLog() || g_dnssecmode == DNSSECMode::ValidateForLog) { - SLOG(g_log << Logger::Warning << "Answer to " << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << x_marker << " for " << comboWriter->getRemote() << " validates as " << vStateToString(state) << endl, - log->info(Logr::Notice, "Validates as Bogus")); + log->info(Logr::Notice, "Validates as Bogus"); } // Does the query or validation mode sending out a SERVFAIL on validation errors? if (!packetWriter.getHeader()->cd && (g_dnssecmode == DNSSECMode::ValidateAll || comboWriter->d_mdp.d_header.ad || DNSSECOK)) { if (resolver.doLog()) { - SLOG(g_log << Logger::Warning << "Sending out SERVFAIL for " << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << " because recursor or query demands it for Bogus results" << endl, - log->info(Logr::Notice, "Sending out SERVFAIL because recursor or query demands it for Bogus results")); + log->info(Logr::Notice, "Sending out SERVFAIL because recursor or query demands it for Bogus results"); } packetWriter.getHeader()->rcode = RCode::ServFail; @@ -1515,29 +1540,32 @@ } else { if (resolver.doLog()) { - SLOG(g_log << Logger::Warning << "Not sending out SERVFAIL for " << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << x_marker << " Bogus validation since neither config nor query demands this" << endl, - log->info(Logr::Notice, "Sending out SERVFAIL because recursor or query demands it for Bogus results")); + log->info(Logr::Notice, "Sending out SERVFAIL because recursor or query demands it for Bogus results"); } } } } catch (const ImmediateServFailException& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during validation of '" << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << "' because: " << e.reason << endl, - resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during validation", "exception", Logging::Loggable("ImmediateServFailException"))); + resolver.d_slog->error(Logr::Notice, e.reason, "Sending SERVFAIL during validation", "exception", Logging::Loggable("ImmediateServFailException")); } goto sendit; // NOLINT(cppcoreguidelines-avoid-goto) } catch (const pdns::validation::TooManySEC3IterationsException& e) { if (g_logCommonErrors || (g_dnssecLogBogus && resolver.getDNSSECLimitHit())) { - SLOG(g_log << Logger::Notice << "Sending SERVFAIL to " << comboWriter->getRemote() << " during validation of '" << comboWriter->d_mdp.d_qname << "|" << QType(comboWriter->d_mdp.d_qtype) << "' because: " << e.what() << endl, - resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during validation", "exception", Logging::Loggable("TooManySEC3IterationsException"), "dnsseclimithit", Logging::Loggable(resolver.getDNSSECLimitHit()))); + resolver.d_slog->error(Logr::Notice, e.what(), "Sending SERVFAIL during validation", "exception", Logging::Loggable("TooManySEC3IterationsException"), "dnsseclimithit", Logging::Loggable(resolver.getDNSSECLimitHit())); } goto sendit; // NOLINT(cppcoreguidelines-avoid-goto) } } if (!ret.empty()) { +#ifdef notyet + // As dedupping is relatively expensive do not dedup in general. We do have a few cases + // where we call dedup explicitly, e.g. when doing NAT64 or when adding NSEC records in + // doCNAMECacheCheck + pdns::dedupRecords(ret); +#endif pdns::orderAndShuffle(ret, false); if (auto listToSort = luaconfsLocal->sortlist.getOrderCmp(comboWriter->d_source)) { stable_sort(ret.begin(), ret.end(), *listToSort); @@ -1583,9 +1611,7 @@ #ifdef HAVE_FSTRM if (hasUDR) { if (isEnabledForUDRs(t_nodFrameStreamServersInfo.servers)) { - struct timespec timeSpec - { - }; + struct timespec timeSpec{}; std::string str; if (g_useKernelTimestamp && comboWriter->d_kernelTimestamp.tv_sec != 0) { TIMEVAL_TO_TIMESPEC(&comboWriter->d_kernelTimestamp, &timeSpec); // NOLINT @@ -1608,17 +1634,16 @@ sendit:; if (g_useIncomingECS && comboWriter->d_ecsFound && !resolver.wasVariable() && !variableAnswer) { - // The moment we add an ECS option we should no longer packet cache this. An alternative is to - // overwrite the ECS info after retrieval from the packet cache, but that is much more - // complicated. - variableAnswer = true; + // Later we remember the offset and size of the ECS option added in the packet cache, so we + // can more easily subsititute the then current client specific ECS data after retrieval from + // the packet cache. EDNSSubnetOpts ednsOptions; - ednsOptions.source = comboWriter->d_ednssubnet.source; + ednsOptions.setSource(comboWriter->d_ednssubnet.getSource()); ComboAddress sourceAddr; sourceAddr.reset(); - sourceAddr.sin4.sin_family = ednsOptions.source.getNetwork().sin4.sin_family; - ednsOptions.scope = Netmask(sourceAddr, 0); - auto ecsPayload = makeEDNSSubnetOptsString(ednsOptions); + sourceAddr.sin4.sin_family = ednsOptions.getFamily(); + ednsOptions.setScopePrefixLength(0); + auto ecsPayload = ednsOptions.makeOptString(); // if we don't have enough space available let's just not set that scope of zero, // it will prevent some caching, mostly from dnsdist, but that's fine @@ -1654,6 +1679,7 @@ } } + std::optional eee; if (haveEDNS) { auto state = resolver.getValidationState(); if (comboWriter->d_extendedErrorCode || resolver.d_extendedError || (SyncRes::s_addExtendedResolutionDNSErrors && vStateIsBogus(state))) { @@ -1717,13 +1743,10 @@ throw std::runtime_error("Bogus validation state not handled: " + vStateToString(state)); } } + eee.emplace(EDNSExtendedError{static_cast(code), std::move(extra)}); - EDNSExtendedError eee; - eee.infoCode = static_cast(code); - eee.extraText = std::move(extra); - - if (packetWriter.size() < maxanswersize && (maxanswersize - packetWriter.size()) >= (EDNSOptionCodeSize + EDNSOptionLengthSize + sizeof(eee.infoCode) + eee.extraText.size())) { - returnedEdnsOptions.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(eee)); + if (packetWriter.size() < maxanswersize && (maxanswersize - packetWriter.size()) >= (EDNSOptionCodeSize + EDNSOptionLengthSize + sizeof(EDNSExtendedError::code) + eee->extraText.size())) { + returnedEdnsOptions.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(*eee)); } } @@ -1746,9 +1769,7 @@ nod = true; #ifdef HAVE_FSTRM if (isEnabledForNODs(t_nodFrameStreamServersInfo.servers)) { - struct timespec timeSpec - { - }; + struct timespec timeSpec{}; std::string str; if (g_useKernelTimestamp && comboWriter->d_kernelTimestamp.tv_sec != 0) { TIMEVAL_TO_TIMESPEC(&comboWriter->d_kernelTimestamp, &timeSpec); // NOLINT @@ -1788,9 +1809,13 @@ pbMessage.setValidationState(resolver.getValidationState()); // See if we want to store the policyTags into the PC addPolicyTagsToPBMessageIfNeeded(*comboWriter, pbMessage); + if (eee) { + pbMessage.setEDE(eee->infoCode); + pbMessage.setEDEText(eee->extraText); + } // Take s snap of the current protobuf buffer state to store in the PC - pbDataForCache = boost::make_optional(RecursorPacketCache::PBData{ + pbDataForCache = std::make_optional(RecursorPacketCache::PBData{ pbMessage.getMessageBuf(), pbMessage.getResponseBuf(), !appliedPolicy.getName().empty() || !comboWriter->d_policyTags.empty()}); @@ -1803,26 +1828,29 @@ const bool intoPC = g_packetCache && !variableAnswer && !resolver.wasVariable() && (RecursorPacketCache::s_maxEntrySize == 0 || packet.size() <= RecursorPacketCache::s_maxEntrySize); if (intoPC) { minTTL = capPacketCacheTTL(*packetWriter.getHeader(), minTTL, seenAuthSOA); + // If we are adding ECS info, remember the offset and size in the PC + RecursorPacketCache::ECSInfo ecsInfo{}; + if (g_useIncomingECS && comboWriter->d_ecsFound) { + ecsInfo = findScopeZero(packet); + } + g_packetCache->insertResponsePacket(comboWriter->d_tag, comboWriter->d_qhash, std::move(comboWriter->d_query), comboWriter->d_mdp.d_qname, comboWriter->d_mdp.d_qtype, comboWriter->d_mdp.d_qclass, string(reinterpret_cast(&*packet.begin()), packet.size()), // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) g_now.tv_sec, minTTL, dnsQuestion.validationState, - std::move(pbDataForCache), comboWriter->d_tcp); + std::move(pbDataForCache), comboWriter->d_tcp, ecsInfo); } if (g_regressionTestMode) { t_Counters.updateSnap(g_regressionTestMode); } + auto match = resolver.d_eventTrace.add(RecEventTrace::AnswerSent); if (!comboWriter->d_tcp) { - struct msghdr msgh - { - }; - struct iovec iov - { - }; + struct msghdr msgh{}; + struct iovec iov{}; cmsgbuf_aligned cbuf{}; fillMSGHdr(&msgh, &iov, &cbuf, 0, reinterpret_cast(&*packet.begin()), packet.size(), &comboWriter->d_remote); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) msgh.msg_control = nullptr; @@ -1832,9 +1860,7 @@ } int sendErr = sendOnNBSocket(comboWriter->d_socket, &msgh); if (sendErr != 0 && g_logCommonErrors) { - SLOG(g_log << Logger::Warning << "Sending UDP reply to client " << comboWriter->getRemote() << " failed with: " - << stringerror(sendErr) << endl, - g_slogudpin->error(Logr::Warning, sendErr, "Sending UDP reply to client failed")); + g_slogudpin->error(Logr::Warning, sendErr, "Sending UDP reply to client failed"); } } else { @@ -1843,7 +1869,7 @@ tcpGuard.setHandled(); } - resolver.d_eventTrace.add(RecEventTrace::AnswerSent); + resolver.d_eventTrace.add(RecEventTrace::AnswerSent, 0, false, match); // Now do the per query changing part of the protobuf message if (t_protobufServers.servers && !(luaconfsLocal->protobufExportConfig.taggedOnly && appliedPolicy.getName().empty() && comboWriter->d_policyTags.empty())) { @@ -1876,13 +1902,13 @@ pbMessage.setId(comboWriter->d_mdp.d_header.id); pbMessage.setTime(); - pbMessage.setEDNSSubnet(comboWriter->d_ednssubnet.source, comboWriter->d_ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + pbMessage.setEDNSSubnet(comboWriter->d_ednssubnet.getSource(), comboWriter->d_ednssubnet.getSource().isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); pbMessage.setRequestorId(dnsQuestion.requestorId); pbMessage.setDeviceId(dnsQuestion.deviceId); pbMessage.setDeviceName(dnsQuestion.deviceName); pbMessage.setToPort(comboWriter->d_destination.getPort()); pbMessage.addPolicyTags(comboWriter->d_gettagPolicyTags); - pbMessage.setWorkerId(RecThreadInfo::id()); + pbMessage.setWorkerId(RecThreadInfo::thread_local_id()); pbMessage.setPacketCacheHit(false); pbMessage.setOutgoingQueries(resolver.d_outqueries); for (const auto& metaValue : dnsQuestion.meta) { @@ -1899,52 +1925,54 @@ } } #endif /* NOD_ENABLED */ - if (resolver.d_eventTrace.enabled() && (SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_pb) != 0) { + if (resolver.d_eventTrace.enabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_pb)) { pbMessage.addEvents(resolver.d_eventTrace); } + + if (resolver.d_eventTrace.enabled() && resolver.d_eventTrace.getThisOTTraceEnabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + resolver.d_otTrace.setIDsIfNotSet(); + auto otTrace = pdns::trace::TracesData::boilerPlate("rec", resolver.d_eventTrace.convertToOT(resolver.d_otTrace), { + {"query.qname", {comboWriter->d_mdp.d_qname.toLogString()}}, + {"query.qtype", {QType(comboWriter->d_mdp.d_qtype).toString()}}, + }, + SyncRes::s_serverID); + string otData = otTrace.encode(); + pbMessage.setOpenTelemetryData(otData); + } + // It can be set even if no OT Trace data was generated + if (resolver.d_otTrace.trace_id != pdns::trace::s_emptyTraceID) { + pbMessage.setOpenTelemetryTraceID(resolver.d_otTrace.trace_id); + } if (comboWriter->d_logResponse) { protobufLogResponse(pbMessage); } } - if (resolver.d_eventTrace.enabled() && (SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_log) != 0) { - SLOG(g_log << Logger::Info << resolver.d_eventTrace.toString() << endl, - resolver.d_slog->info(Logr::Info, resolver.d_eventTrace.toString())); // Maybe we want it to be more fancy? + if (resolver.d_eventTrace.enabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_log)) { + resolver.d_slog->info(Logr::Info, resolver.d_eventTrace.toString()); // Maybe we want it to be more fancy? } // Originally this code used a mix of floats, doubles, uint64_t with different units. // Now it always uses an integral number of microseconds, except for averages, which use doubles uint64_t spentUsec = uSec(resolver.getNow() - comboWriter->d_now); if (!g_quiet) { - if (!g_slogStructured) { - g_log << Logger::Error << RecThreadInfo::id() << " [" << g_multiTasker->getTid() << "/" << g_multiTasker->numProcesses() << "] answer to " << (comboWriter->d_mdp.d_header.rd ? "" : "non-rd ") << "question '" << comboWriter->d_mdp.d_qname << "|" << DNSRecordContent::NumberToType(comboWriter->d_mdp.d_qtype); - g_log << "': " << ntohs(packetWriter.getHeader()->ancount) << " answers, " << ntohs(packetWriter.getHeader()->arcount) << " additional, took " << resolver.d_outqueries << " packets, " << resolver.d_totUsec / 1000.0 << " netw ms, " << static_cast(spentUsec) / 1000.0 << " tot ms, " << resolver.d_throttledqueries << " throttled, " << resolver.d_timeouts << " timeouts, " << resolver.d_tcpoutqueries << "/" << resolver.d_dotoutqueries << " tcp/dot connections, rcode=" << res; - - if (!shouldNotValidate && resolver.isDNSSECValidationRequested()) { - g_log << ", dnssec=" << resolver.getValidationState(); - } - g_log << " answer-is-variable=" << resolver.wasVariable() << ", into-packetcache=" << intoPC; - g_log << " maxdepth=" << resolver.d_maxdepth; - g_log << endl; - } - else { - resolver.d_slog->info(Logr::Info, "Answer", "rd", Logging::Loggable(comboWriter->d_mdp.d_header.rd), - "answers", Logging::Loggable(ntohs(packetWriter.getHeader()->ancount)), - "additional", Logging::Loggable(ntohs(packetWriter.getHeader()->arcount)), - "outqueries", Logging::Loggable(resolver.d_outqueries), - "received", Logging::Loggable(resolver.d_bytesReceived), - "netms", Logging::Loggable(resolver.d_totUsec / 1000.0), - "totms", Logging::Loggable(static_cast(spentUsec) / 1000.0), - "throttled", Logging::Loggable(resolver.d_throttledqueries), - "timeouts", Logging::Loggable(resolver.d_timeouts), - "tcpout", Logging::Loggable(resolver.d_tcpoutqueries), - "dotout", Logging::Loggable(resolver.d_dotoutqueries), - "rcode", Logging::Loggable(res), - "validationState", Logging::Loggable(resolver.getValidationState()), - "answer-is-variable", Logging::Loggable(resolver.wasVariable()), - "into-packetcache", Logging::Loggable(intoPC), - "maxdepth", Logging::Loggable(resolver.d_maxdepth)); - } + resolver.d_slog->info(Logr::Info, "Answer", "rd", Logging::Loggable(comboWriter->d_mdp.d_header.rd), + "tc", Logging::Loggable(packetWriter.getHeader()->tc), + "answers", Logging::Loggable(ntohs(packetWriter.getHeader()->ancount)), + "additional", Logging::Loggable(ntohs(packetWriter.getHeader()->arcount)), + "outqueries", Logging::Loggable(resolver.d_outqueries), + "received", Logging::Loggable(resolver.d_bytesReceived), + "netms", Logging::Loggable(resolver.d_totUsec / 1000.0), + "totms", Logging::Loggable(static_cast(spentUsec) / 1000.0), + "throttled", Logging::Loggable(resolver.d_throttledqueries), + "timeouts", Logging::Loggable(resolver.d_timeouts), + "tcpout", Logging::Loggable(resolver.d_tcpoutqueries), + "dotout", Logging::Loggable(resolver.d_dotoutqueries), + "rcode", Logging::Loggable(res), + "validationState", Logging::Loggable(resolver.getValidationState()), + "answer-is-variable", Logging::Loggable(resolver.wasVariable()), + "into-packetcache", Logging::Loggable(intoPC), + "maxdepth", Logging::Loggable(resolver.d_maxdepth)); } if (comboWriter->d_mdp.d_header.opcode == static_cast(Opcode::Query)) { @@ -1980,57 +2008,49 @@ // cout<d_mdp.d_qname<<"\t"<getUsec()<<"\t"<error(Logr::Error, ae.reason, "startDoResolve problem", "exception", Logging::Loggable("PDNSException"))); + resolver.d_slog->error(Logr::Error, ae.reason, "startDoResolve problem", "exception", Logging::Loggable("PDNSException")); } catch (const MOADNSException& mde) { - SLOG(g_log << Logger::Error << "DNS parser error " << makeLoginfo(comboWriter) << ": " << comboWriter->d_mdp.d_qname << ", " << mde.what() << endl, - resolver.d_slog->error(Logr::Error, mde.what(), "DNS parser error")); + resolver.d_slog->error(Logr::Error, mde.what(), "DNS parser error"); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "STL error " << makeLoginfo(comboWriter) << ": " << e.what(), - resolver.d_slog->error(Logr::Error, e.what(), "Exception in resolver context", "exception", Logging::Loggable("std::exception"))); + resolver.d_slog->error(Logr::Error, e.what(), "Exception in resolver context", "exception", Logging::Loggable("std::exception")); // Luawrapper nests the exception from Lua, so we unnest it here try { std::rethrow_if_nested(e); } catch (const std::exception& ne) { - SLOG(g_log << ". Extra info: " << ne.what(), - resolver.d_slog->error(Logr::Error, ne.what(), "Nested exception in resolver context", Logging::Loggable("std::exception"))); + resolver.d_slog->error(Logr::Error, ne.what(), "Nested exception in resolver context", Logging::Loggable("std::exception")); } catch (...) { - } - if (!g_slogStructured) { - g_log << endl; + ; } } catch (...) { - SLOG(g_log << Logger::Error << "Any other exception in a resolver context " << makeLoginfo(comboWriter) << endl, - resolver.d_slog->info(Logr::Error, "Any other exception in a resolver context")); + resolver.d_slog->info(Logr::Error, "Any other exception in a resolver context"); } runTaskOnce(g_logCommonErrors); static const size_t stackSizeThreshold = 9 * ::arg().asNum("stack-size") / 10; if (g_multiTasker->getMaxStackUsage() >= stackSizeThreshold) { - SLOG(g_log << Logger::Error << "Reached mthread stack usage of 90%: " << g_multiTasker->getMaxStackUsage() << " " << makeLoginfo(comboWriter) << " after " << resolver.d_outqueries << " out queries, " << resolver.d_tcpoutqueries << " TCP out queries, " << resolver.d_dotoutqueries << " DoT out queries" << endl, - resolver.d_slog->info(Logr::Error, "Reached mthread stack usage of 90%", - "stackUsage", Logging::Loggable(g_multiTasker->getMaxStackUsage()), - "outqueries", Logging::Loggable(resolver.d_outqueries), - "netms", Logging::Loggable(resolver.d_totUsec / 1000.0), - "throttled", Logging::Loggable(resolver.d_throttledqueries), - "timeouts", Logging::Loggable(resolver.d_timeouts), - "tcpout", Logging::Loggable(resolver.d_tcpoutqueries), - "dotout", Logging::Loggable(resolver.d_dotoutqueries), - "validationState", Logging::Loggable(resolver.getValidationState()))); + resolver.d_slog->info(Logr::Error, "Reached mthread stack usage of 90%", + "stackUsage", Logging::Loggable(g_multiTasker->getMaxStackUsage()), + "outqueries", Logging::Loggable(resolver.d_outqueries), + "netms", Logging::Loggable(resolver.d_totUsec / 1000.0), + "throttled", Logging::Loggable(resolver.d_throttledqueries), + "timeouts", Logging::Loggable(resolver.d_timeouts), + "tcpout", Logging::Loggable(resolver.d_tcpoutqueries), + "dotout", Logging::Loggable(resolver.d_dotoutqueries), + "validationState", Logging::Loggable(resolver.getValidationState())); } t_Counters.at(rec::Counter::maxMThreadStackUsage) = max(g_multiTasker->getMaxStackUsage(), t_Counters.at(rec::Counter::maxMThreadStackUsage)); t_Counters.updateSnap(g_regressionTestMode); } void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, - bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options, boost::optional& ednsVersion) + bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options, std::optional& ednsVersion) { const dnsheader_aligned dnshead(question.data()); const dnsheader* dhPointer = dnshead.get(); @@ -2052,7 +2072,7 @@ const auto* drh = reinterpret_cast(&question.at(pos)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) if (ntohs(drh->d_type) == QType::OPT) { uint32_t edns{}; - memcpy(&edns, &drh->d_ttl, sizeof(edns)); // drh is not neccesarily aligned, so no uint32 assignment can be done + memcpy(&edns, &drh->d_ttl, sizeof(edns)); // drh is not necessarily aligned, so no uint32 assignment can be done ednsVersion = edns; } pos += sizeof(dnsrecordheader); @@ -2070,7 +2090,7 @@ int res = getEDNSOption(reinterpret_cast(&question.at(pos - sizeof(drh->d_clen))), questionLen - pos + sizeof(drh->d_clen), EDNSOptionCode::ECS, &ecsStartPosition, &ecsLen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) if (res == 0 && ecsLen > 4) { EDNSSubnetOpts eso; - if (getEDNSSubnetOptsFromString(&question.at(pos - sizeof(drh->d_clen) + ecsStartPosition + 4), ecsLen - 4, &eso)) { + if (EDNSSubnetOpts::getFromString(&question.at(pos - sizeof(drh->d_clen) + ecsStartPosition + 4), ecsLen - 4, &eso)) { *ednssubnet = eso; foundECS = true; } @@ -2083,7 +2103,7 @@ const auto iter = options->find(EDNSOptionCode::ECS); if (iter != options->end() && !iter->second.values.empty() && iter->second.values.at(0).content != nullptr && iter->second.values.at(0).size > 0) { EDNSSubnetOpts eso; - if (getEDNSSubnetOptsFromString(iter->second.values.at(0).content, iter->second.values.at(0).size, &eso)) { + if (EDNSSubnetOpts::getFromString(iter->second.values.at(0).content, iter->second.values.at(0).size, &eso)) { *ednssubnet = eso; foundECS = true; } @@ -2100,7 +2120,7 @@ DNSName& qname, uint16_t& qtype, uint16_t& qclass, const struct timeval& now, string& response, uint32_t& qhash, - RecursorPacketCache::OptPBData& pbData, bool tcp, const ComboAddress& source, const ComboAddress& mappedSource) + RecursorPacketCache::OptPBData& pbData, bool tcp, const ComboAddress& source, const ComboAddress& mappedSource, bool ecsFound, const EDNSSubnetOpts& edns) { if (!g_packetCache) { return false; @@ -2109,14 +2129,25 @@ uint32_t age = 0; vState valState = vState::Indeterminate; + RecursorPacketCache::ECSInfo ecsInfo; if (qnameParsed) { - cacheHit = g_packetCache->getResponsePacket(tag, data, qname, qtype, qclass, now.tv_sec, &response, &age, &valState, &qhash, &pbData, tcp); + cacheHit = g_packetCache->getResponsePacket(tag, data, qname, qtype, qclass, now.tv_sec, &response, &age, &valState, &qhash, &pbData, tcp, ecsInfo); } else { - cacheHit = g_packetCache->getResponsePacket(tag, data, qname, &qtype, &qclass, now.tv_sec, &response, &age, &valState, &qhash, &pbData, tcp); + cacheHit = g_packetCache->getResponsePacket(tag, data, qname, &qtype, &qclass, now.tv_sec, &response, &age, &valState, &qhash, &pbData, tcp, ecsInfo); } if (cacheHit) { + if (g_useIncomingECS && ecsFound && ecsInfo.second != 0) { + // We need to patch the packet so it contains the ECS data for the current client, not the + // one that caused insertion into the packe cache originally. + EDNSSubnetOpts ednsOptions; + ednsOptions.setSource(edns.getSource()); + ednsOptions.setScopePrefixLength(0); + auto ecsPayload = ednsOptions.makeOptString(); + substituteScopeZero(response, ecsInfo, ecsPayload); + } + if (vStateIsBogus(valState)) { if (t_bogusremotes) { t_bogusremotes->push_back(source); @@ -2161,8 +2192,7 @@ static void* pleaseWipeCaches(const DNSName& canon, bool subtree, uint16_t qtype) { auto res = wipeCaches(canon, subtree, qtype); - SLOG(g_log << Logger::Info << "Wiped caches for " << canon << ": " << res.record_count << " records; " << res.negative_record_count << " negative records; " << res.packet_count << " packets" << endl, - g_slog->withName("runtime")->info(Logr::Info, "Wiped cache", "qname", Logging::Loggable(canon), "records", Logging::Loggable(res.record_count), "negrecords", Logging::Loggable(res.negative_record_count), "packets", Logging::Loggable(res.packet_count))); + g_slog->withName("runtime")->info(Logr::Info, "Wiped cache", "qname", Logging::Loggable(canon), "records", Logging::Loggable(res.record_count), "negrecords", Logging::Loggable(res.negative_record_count), "packets", Logging::Loggable(res.packet_count)); return nullptr; } @@ -2173,7 +2203,10 @@ ThreadMSG* tmsg = new ThreadMSG(); // NOLINT: pointer owner tmsg->func = [=] { return pleaseWipeCaches(canon, true, 0xffff); }; tmsg->wantAnswer = false; + __tsan_release(tmsg); + if (write(RecThreadInfo::info(0).getPipes().writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // NOLINT: correct sizeof + __tsan_acquire(tmsg); delete tmsg; // NOLINT: pointer owner unixDie("write to thread pipe returned wrong size or error"); @@ -2183,16 +2216,72 @@ bool expectProxyProtocol(const ComboAddress& from, const ComboAddress& listenAddress) { - return g_proxyProtocolACL.match(from) && g_proxyProtocolExceptions.count(listenAddress) == 0; + if (!t_proxyProtocolACL) { + return false; + } + if (t_proxyProtocolACL->match(from)) { + if (!t_proxyProtocolExceptions) { + return true; + } + return t_proxyProtocolExceptions->count(listenAddress) == 0; + } + return false; +} + +bool matchOTConditions(const std::unique_ptr& conditions, const ComboAddress& source) +{ + if (conditions == nullptr || conditions->empty()) { + return false; + } + if (auto const* match = conditions->lookup(source); match != nullptr) { + const auto& condition = match->second; + if (condition.d_traceid_only) { + return false; + } + return true; + } + return false; +} + +bool matchOTConditions(RecEventTrace& eventTrace, const std::unique_ptr& conditions, const ComboAddress& source, const DNSName& qname, QType qtype, uint16_t qid, bool edns_option_present) +{ + if (conditions == nullptr || conditions->empty()) { + return false; + } + if (auto const* match = conditions->lookup(source); match != nullptr) { + const auto& condition = match->second; + if (condition.d_traceid_only) { + return false; + } + if (condition.d_edns_option_required && !edns_option_present) { + return false; + } + if (condition.d_qid && condition.d_qid != qid) { + return false; + } + if (condition.d_qtypes && condition.d_qtypes->count(qtype) == 0) { + return false; + } + if (condition.d_qnames && !condition.d_qnames->check(qname)) { + return false; + } + eventTrace.setThisOTTraceEnabled(); + return true; + } + + return false; } -// fromaddr: the address the query is coming from -// destaddr: the address the query was received on +// fromaddr: the address from which the query is coming +// destaddr: the address on which the query was received // source: the address we assume the query is coming from, might be set by proxy protocol // destination: the address we assume the query was sent to, might be set by proxy protocol // mappedSource: the address we assume the query is coming from. Differs from source if table based mapping has been applied -static string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, ComboAddress source, ComboAddress destination, const ComboAddress& mappedSource, struct timeval tval, int fileDesc, std::vector& proxyProtocolValues, RecEventTrace& eventTrace) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791 +static string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, ComboAddress source, ComboAddress destination, const ComboAddress& mappedSource, struct timeval tval, int fileDesc, std::vector& proxyProtocolValues, RecEventTrace& eventTrace, pdns::trace::InitialSpanInfo& otTrace) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791 { + auto newParent = eventTrace.add(RecEventTrace::ProcessUDP); + auto oldParent = eventTrace.setParent(newParent); + RecEventTrace::EventScope traceScope(oldParent, eventTrace); RecThreadInfo::self().incNumberOfDistributedQueries(); gettimeofday(&g_now, nullptr); if (tval.tv_sec != 0) { @@ -2216,7 +2305,7 @@ const dnsheader* dnsheader = headerdata.get(); unsigned int ctag = 0; uint32_t qhash = 0; - bool needEDNSParse = false; + bool needEDNSParse = g_useIncomingECS; std::unordered_set policyTags; std::map meta; LuaContext::LuaObject data; @@ -2246,9 +2335,9 @@ bool ecsParsed = false; std::vector records; std::string extendedErrorExtra; - boost::optional rcode = boost::none; - boost::optional extendedErrorCode{boost::none}; - boost::optional ednsVersion{boost::none}; + std::optional rcode = std::nullopt; + std::optional extendedErrorCode{std::nullopt}; + std::optional ednsVersion{std::nullopt}; uint32_t ttlCap = std::numeric_limits::max(); bool variable = false; bool followCNAMEs = false; @@ -2273,34 +2362,45 @@ // We do not have a SyncRes specific Lua context at this point yet, so ok to use t_pdl if (needEDNSParse || (t_pdl && (t_pdl->hasGettagFunc() || t_pdl->hasGettagFFIFunc())) || dnsheader->opcode == static_cast(Opcode::Notify)) { try { + auto parseMatch = eventTrace.add(RecEventTrace::PacketParse); EDNSOptionViewMap ednsOptions; ecsFound = false; getQNameAndSubnet(question, &qname, &qtype, &qclass, - ecsFound, &ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr, ednsVersion); + ecsFound, &ednssubnet, + (g_gettagNeedsEDNSOptions || SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) ? &ednsOptions : nullptr, + ednsVersion); + eventTrace.add(RecEventTrace::PacketParse, 0, false, parseMatch); qnameParsed = true; ecsParsed = true; + if (SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + bool ednsFound = pdns::trace::extractOTraceIDs(ednsOptions, EDNSOptionCode::TRACEPARENT, otTrace); + if (!matchOTConditions(eventTrace, t_OTConditions, mappedSource, qname, qtype, ntohs(headerdata->id), ednsFound) && SyncRes::eventTraceEnabledOnly(SyncRes::event_trace_to_ot)) { + eventTrace.setEnabled(false); + } + } + if (t_pdl) { try { if (t_pdl->hasGettagFFIFunc()) { - RecursorLua4::FFIParams params(qname, qtype, destaddr, fromaddr, destination, source, ednssubnet.source, data, policyTags, records, ednsOptions, proxyProtocolValues, requestorId, deviceId, deviceName, routingTag, rcode, ttlCap, variable, false, logQuery, logResponse, followCNAMEs, extendedErrorCode, extendedErrorExtra, responsePaddingDisabled, meta); + RecursorLua4::FFIParams params(qname, qtype, destaddr, fromaddr, destination, source, ednssubnet.getSource(), data, policyTags, records, ednsOptions, proxyProtocolValues, requestorId, deviceId, deviceName, routingTag, rcode, ttlCap, variable, false, logQuery, logResponse, followCNAMEs, extendedErrorCode, extendedErrorExtra, responsePaddingDisabled, meta); - eventTrace.add(RecEventTrace::LuaGetTagFFI); + auto match = eventTrace.add(RecEventTrace::LuaGetTagFFI); ctag = t_pdl->gettag_ffi(params); - eventTrace.add(RecEventTrace::LuaGetTagFFI, ctag, false); + eventTrace.add(RecEventTrace::LuaGetTagFFI, ctag, false, match); } else if (t_pdl->hasGettagFunc()) { - eventTrace.add(RecEventTrace::LuaGetTag); - ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName, routingTag, proxyProtocolValues); - eventTrace.add(RecEventTrace::LuaGetTag, ctag, false); + auto match = eventTrace.add(RecEventTrace::LuaGetTag); + ctag = t_pdl->gettag(source, ednssubnet.getSource(), destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName, routingTag, proxyProtocolValues); + eventTrace.add(RecEventTrace::LuaGetTag, ctag, false, match); } } catch (const MOADNSException& moadnsexception) { if (g_logCommonErrors) { - g_slogudpin->error(moadnsexception.what(), "Error parsing a query packet for tag determination", "qname", Logging::Loggable(qname), "excepion", Logging::Loggable("MOADNSException")); + g_slogudpin->error(moadnsexception.what(), "Error parsing a query packet for tag determination", "qname", Logging::Loggable(qname), "exception", Logging::Loggable("MOADNSException")); } } catch (const std::exception& stdException) { @@ -2313,10 +2413,10 @@ } } - RecursorPacketCache::OptPBData pbData{boost::none}; + RecursorPacketCache::OptPBData pbData{std::nullopt}; if (t_protobufServers.servers) { if (logQuery && !(luaconfsLocal->protobufExportConfig.taggedOnly && policyTags.empty())) { - protobufLogQuery(luaconfsLocal, uniqueId, source, destination, mappedSource, ednssubnet.source, false, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId, deviceName, meta, ednsVersion, *dnsheader); + protobufLogQuery(luaconfsLocal, uniqueId, source, destination, mappedSource, ednssubnet.getSource(), false, question.size(), qname, qtype, qclass, policyTags, requestorId, deviceId, deviceName, meta, ednsVersion, *dnsheader, otTrace.trace_id); } } @@ -2328,22 +2428,18 @@ /* It might seem like a good idea to skip the packet cache lookup if we know that the answer is not cacheable, but it means that the hash would not be computed. If some script decides at a later time to mark back the answer as cacheable we would cache it with a wrong tag, so better safe than sorry. */ - eventTrace.add(RecEventTrace::PCacheCheck); - bool cacheHit = checkForCacheHit(qnameParsed, ctag, question, qname, qtype, qclass, g_now, response, qhash, pbData, false, source, mappedSource); - eventTrace.add(RecEventTrace::PCacheCheck, cacheHit, false); + auto match = eventTrace.add(RecEventTrace::PCacheCheck); + bool cacheHit = checkForCacheHit(qnameParsed, ctag, question, qname, qtype, qclass, g_now, response, qhash, pbData, false, source, mappedSource, ecsFound, ednssubnet); + eventTrace.add(RecEventTrace::PCacheCheck, cacheHit, false, match); if (cacheHit) { if (!g_quiet) { - SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " question answered from packet cache tag=" << ctag << " from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << endl, - g_slogudpin->info(Logr::Notice, "Question answered from packet cache", "tag", Logging::Loggable(ctag), - "qname", Logging::Loggable(qname), "qtype", Logging::Loggable(QType(qtype)), - "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr))); - } - struct msghdr msgh - { - }; - struct iovec iov - { - }; + g_slogudpin->info(Logr::Notice, "Question answered from packet cache", "tag", Logging::Loggable(ctag), + "qname", Logging::Loggable(qname), "qtype", Logging::Loggable(QType(qtype)), + "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)); + } + match = eventTrace.add(RecEventTrace::AnswerSent); + struct msghdr msgh{}; + struct iovec iov{}; cmsgbuf_aligned cbuf{}; fillMSGHdr(&msgh, &iov, &cbuf, 0, reinterpret_cast(response.data()), response.length(), const_cast(&fromaddr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-type-const-cast) msgh.msg_control = nullptr; @@ -2352,25 +2448,19 @@ addCMsgSrcAddr(&msgh, &cbuf, &destaddr, 0); } int sendErr = sendOnNBSocket(fileDesc, &msgh); - eventTrace.add(RecEventTrace::AnswerSent); - + eventTrace.add(RecEventTrace::AnswerSent, sendErr, false, match); + traceScope.close(0); if (t_protobufServers.servers && logResponse && (!luaconfsLocal->protobufExportConfig.taggedOnly || (pbData && pbData->d_tagged))) { - protobufLogResponse(dnsheader, luaconfsLocal, pbData, tval, false, source, destination, mappedSource, ednssubnet, uniqueId, requestorId, deviceId, deviceName, meta, eventTrace, policyTags); + protobufLogResponse(qname, qtype, dnsheader, luaconfsLocal, pbData, tval, false, source, destination, mappedSource, ednssubnet, uniqueId, requestorId, deviceId, deviceName, meta, eventTrace, otTrace, policyTags); } - if (eventTrace.enabled() && (SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_log) != 0) { - SLOG(g_log << Logger::Info << eventTrace.toString() << endl, - g_slogudpin->info(Logr::Info, eventTrace.toString())); // Do we want more fancy logging here? + if (eventTrace.enabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_log)) { + g_slogudpin->info(Logr::Info, eventTrace.toString()); // Do we want more fancy logging here? } if (sendErr != 0 && g_logCommonErrors) { - SLOG(g_log << Logger::Warning << "Sending UDP reply to client " << source.toStringWithPort() - << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << " failed with: " - << stringerror(sendErr) << endl, - g_slogudpin->error(Logr::Error, sendErr, "Sending UDP reply to client failed", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr))); - } - struct timeval now - { - }; + g_slogudpin->error(Logr::Error, sendErr, "Sending UDP reply to client failed", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)); + } + struct timeval now{}; Utility::gettimeofday(&now, nullptr); uint64_t spentUsec = uSec(now - tval); t_Counters.at(rec::Histogram::cumulativeAnswers)(spentUsec); @@ -2381,8 +2471,7 @@ } catch (const std::exception& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Error processing or aging answer packet: " << e.what() << endl, - g_slogudpin->error(Logr::Error, e.what(), "Error processing or aging answer packet", "exception", Logging::Loggable("std::exception"))); + g_slogudpin->error(Logr::Error, e.what(), "Error processing or aging answer packet", "exception", Logging::Loggable("std::exception")); } return nullptr; } @@ -2391,8 +2480,7 @@ bool ipf = t_pdl->ipfilter(source, destination, *dnsheader, eventTrace); if (ipf) { 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() + ")" : "") << " based on policy" << endl, - g_slogudpin->info(Logr::Notice, "Dropped question based on policy", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Notice, "Dropped question based on policy", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)); } t_Counters.at(rec::Counter::policyDrops)++; return nullptr; @@ -2402,8 +2490,7 @@ if (dnsheader->opcode == static_cast(Opcode::Notify)) { if (!isAllowNotifyForZone(qname)) { if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping UDP NOTIFY from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << ", for " << qname.toLogString() << ", zone not matched by allow-notify-for" << endl, - g_slogudpin->info(Logr::Notice, "Dropping UDP NOTIFY, zone not matched by allow-notify-for", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Notice, "Dropping UDP NOTIFY, zone not matched by allow-notify-for", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)); } t_Counters.at(rec::Counter::zoneDisallowedNotify)++; @@ -2411,8 +2498,7 @@ } if (!g_quiet) { - SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " got NOTIFY for " << qname.toLogString() << " from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << endl, - g_slogudpin->info(Logr::Notice, "Got NOTIFY", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr), "qname", Logging::Loggable(qname))); + g_slogudpin->info(Logr::Notice, "Got NOTIFY", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr), "qname", Logging::Loggable(qname)); } if (!ZoneXFR::notifyZoneTracker(qname)) { // It wasn't an RPZ @@ -2428,8 +2514,7 @@ 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))); + g_slogudpin->info(Logr::Notice, "Dropped question, over capacity", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr)); } t_Counters.at(rec::Counter::overCapacityDrops)++; return nullptr; @@ -2440,9 +2525,9 @@ comboWriter->setSocket(fileDesc); comboWriter->d_tag = ctag; comboWriter->d_qhash = qhash; - comboWriter->setRemote(fromaddr); // the address the query is coming from + comboWriter->setRemote(fromaddr); // the address from which the query is coming comboWriter->setSource(source); // the address we assume the query is coming from, might be set by proxy protocol - comboWriter->setLocal(destaddr); // the address the query was received on + comboWriter->setLocal(destaddr); // the address on which the query was received comboWriter->setDestination(destination); // the address we assume the query is sent to, might be set by proxy protocol comboWriter->setMappedSource(mappedSource); // the address we assume the query is coming from. Differs from source if table-based mapping has been applied comboWriter->d_tcp = false; @@ -2468,7 +2553,10 @@ comboWriter->d_responsePaddingDisabled = responsePaddingDisabled; comboWriter->d_meta = std::move(meta); + traceScope.close(0); comboWriter->d_eventTrace = std::move(eventTrace); + comboWriter->d_otTrace = std::move(otTrace); + g_multiTasker->makeThread(startDoResolve, (void*)comboWriter.release()); // deletes dc return nullptr; @@ -2476,21 +2564,19 @@ static void handleNewUDPQuestion(int fileDesc, FDMultiplexer::funcparam_t& /* var */) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791 { - static const size_t maxIncomingQuerySize = g_proxyProtocolACL.empty() ? 512 : (512 + g_proxyProtocolMaximumSize); + const bool proxyActive = t_proxyProtocolACL && !t_proxyProtocolACL->empty(); + static const size_t maxIncomingQuerySize = !proxyActive ? 512 : (512 + g_proxyProtocolMaximumSize); static thread_local std::string data; - ComboAddress fromaddr; // the address the query is coming from + ComboAddress fromaddr; // the address from which the query is coming ComboAddress source; // the address we assume the query is coming from, might be set by proxy protocol ComboAddress destination; // the address we assume the query was sent to, might be set by proxy protocol - struct msghdr msgh - { - }; - struct iovec iov - { - }; + struct msghdr msgh{}; + struct iovec iov{}; cmsgbuf_aligned cbuf; bool firstQuery = true; std::vector proxyProtocolValues; RecEventTrace eventTrace; + pdns::trace::InitialSpanInfo otTrace; for (size_t queriesCounter = 0; queriesCounter < g_maxUDPQueriesPerRound; queriesCounter++) { bool proxyProto = false; @@ -2502,22 +2588,28 @@ if (ssize_t len = recvmsg(fileDesc, &msgh, 0); len >= 0) { eventTrace.clear(); eventTrace.setEnabled(SyncRes::s_event_trace_enabled != 0); - eventTrace.add(RecEventTrace::ReqRecv); - + // eventTrace uses monotonic time, while OpenTelemetry uses absolute time. setEnabled() + // established the reference point, get an absolute TS as close as possible to the + // eventTrace start of trace time. + auto traceTS = pdns::trace::timestamp(); + auto match = eventTrace.add(RecEventTrace::ReqRecv); + if (SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + otTrace.clear(); + otTrace.start_time_unix_nano = traceTS; + } firstQuery = false; if ((msgh.msg_flags & MSG_TRUNC) != 0) { t_Counters.at(rec::Counter::truncatedDrops)++; if (!g_quiet) { - SLOG(g_log << Logger::Error << "Ignoring truncated query from " << fromaddr.toString() << endl, - g_slogudpin->info(Logr::Error, "Ignoring truncated query", "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring truncated query", "remote", Logging::Loggable(fromaddr)); } return; } data.resize(static_cast(len)); - ComboAddress destaddr; // the address the query was sent to to + ComboAddress destaddr; // the address where the query was sent destaddr.reset(); // this makes sure we ignore this address if not explictly set below const auto* loc = rplookup(g_listenSocketsAddresses, fileDesc); if (HarvestDestinationAddress(&msgh, &destaddr)) { @@ -2542,17 +2634,15 @@ if (used <= 0) { ++t_Counters.at(rec::Counter::proxyProtocolInvalidCount); if (!g_quiet) { - SLOG(g_log << Logger::Error << "Ignoring invalid proxy protocol (" << std::to_string(len) << ", " << std::to_string(used) << ") query from " << fromaddr.toStringWithPort() << endl, - g_slogudpin->info(Logr::Error, "Ignoring invalid proxy protocol query", "length", Logging::Loggable(len), - "used", Logging::Loggable(used), "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring invalid proxy protocol query", "length", Logging::Loggable(len), + "used", Logging::Loggable(used), "remote", Logging::Loggable(fromaddr)); } return; } if (static_cast(used) > g_proxyProtocolMaximumSize) { if (g_quiet) { - SLOG(g_log << Logger::Error << "Proxy protocol header in UDP packet from " << fromaddr.toStringWithPort() << " is larger than proxy-protocol-maximum-size (" << used << "), dropping" << endl, - g_slogudpin->info(Logr::Error, "Proxy protocol header in UDP packet is larger than proxy-protocol-maximum-size", - "used", Logging::Loggable(used), "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Proxy protocol header in UDP packet is larger than proxy-protocol-maximum-size", + "used", Logging::Loggable(used), "remote", Logging::Loggable(fromaddr)); } ++t_Counters.at(rec::Counter::proxyProtocolInvalidCount); return; @@ -2564,8 +2654,7 @@ /* we only allow UDP packets larger than 512 for those with a proxy protocol header */ t_Counters.at(rec::Counter::truncatedDrops)++; if (!g_quiet) { - SLOG(g_log << Logger::Error << "Ignoring truncated query from " << fromaddr.toStringWithPort() << endl, - g_slogudpin->info(Logr::Error, "Ignoring truncated query", "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring truncated query", "remote", Logging::Loggable(fromaddr)); } return; } @@ -2573,9 +2662,8 @@ if (data.size() < sizeof(dnsheader)) { t_Counters.at(rec::Counter::ignoredCount)++; if (!g_quiet) { - SLOG(g_log << Logger::Error << "Ignoring too-short (" << std::to_string(data.size()) << ") query from " << fromaddr.toString() << endl, - g_slogudpin->info(Logr::Error, "Ignoring too-short query", "length", Logging::Loggable(data.size()), - "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring too-short query", "length", Logging::Loggable(data.size()), + "remote", Logging::Loggable(fromaddr)); } return; } @@ -2596,8 +2684,7 @@ if (t_allowFrom && !t_allowFrom->match(&mappedSource)) { if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping UDP query from " << mappedSource.toString() << ", address not matched by allow-from" << endl, - g_slogudpin->info(Logr::Error, "Dropping UDP query, address not matched by allow-from", "source", Logging::Loggable(mappedSource))); + g_slogudpin->info(Logr::Error, "Dropping UDP query, address not matched by allow-from", "source", Logging::Loggable(mappedSource)); } t_Counters.at(rec::Counter::unauthorizedUDP)++; @@ -2607,8 +2694,7 @@ BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port)); if (fromaddr.sin4.sin_port == 0) { // also works for IPv6 if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping UDP query from " << fromaddr.toStringWithPort() << ", can't deal with port 0" << endl, - g_slogudpin->info(Logr::Error, "Dropping UDP query can't deal with port 0", "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Dropping UDP query can't deal with port 0", "remote", Logging::Loggable(fromaddr)); } t_Counters.at(rec::Counter::clientParseError)++; // not quite the best place to put it, but needs to go somewhere @@ -2622,31 +2708,27 @@ if (dnsheader->qr) { t_Counters.at(rec::Counter::ignoredCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring answer from " << fromaddr.toString() << " on server socket!" << endl, - g_slogudpin->info(Logr::Error, "Ignoring answer on server socket", "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring answer on server socket", "remote", Logging::Loggable(fromaddr)); } } else if (dnsheader->opcode != static_cast(Opcode::Query) && dnsheader->opcode != static_cast(Opcode::Notify)) { t_Counters.at(rec::Counter::ignoredCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring unsupported opcode " << Opcode::to_s(dnsheader->opcode) << " from " << fromaddr.toString() << " on server socket!" << endl, - g_slogudpin->info(Logr::Error, "Ignoring unsupported opcode server socket", "remote", Logging::Loggable(fromaddr), "opcode", Logging::Loggable(Opcode::to_s(dnsheader->opcode)))); + g_slogudpin->info(Logr::Error, "Ignoring unsupported opcode server socket", "remote", Logging::Loggable(fromaddr), "opcode", Logging::Loggable(Opcode::to_s(dnsheader->opcode))); } } else if (dnsheader->qdcount == 0U) { t_Counters.at(rec::Counter::emptyQueriesCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring empty (qdcount == 0) query from " << fromaddr.toString() << " on server socket!" << endl, - g_slogudpin->info(Logr::Error, "Ignoring empty (qdcount == 0) query on server socket!", "remote", Logging::Loggable(fromaddr))); + g_slogudpin->info(Logr::Error, "Ignoring empty (qdcount == 0) query on server socket!", "remote", Logging::Loggable(fromaddr)); } } else { if (dnsheader->opcode == static_cast(Opcode::Notify)) { if (!t_allowNotifyFrom || !t_allowNotifyFrom->match(&mappedSource)) { if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping UDP NOTIFY from " << mappedSource.toString() << ", address not matched by allow-notify-from" << endl, - g_slogudpin->info(Logr::Error, "Dropping UDP NOTIFY from address not matched by allow-notify-from", - "source", Logging::Loggable(mappedSource))); + g_slogudpin->info(Logr::Error, "Dropping UDP NOTIFY from address not matched by allow-notify-from", + "source", Logging::Loggable(mappedSource)); } t_Counters.at(rec::Counter::sourceDisallowedNotify)++; @@ -2660,29 +2742,31 @@ destination = destaddr; } + if (eventTrace.enabled() && !matchOTConditions(t_OTConditions, mappedSource) && SyncRes::eventTraceEnabledOnly(SyncRes::event_trace_to_ot)) { + eventTrace.setEnabled(false); + } + eventTrace.add(RecEventTrace::ReqRecv, 0, false, match); if (RecThreadInfo::weDistributeQueries()) { std::string localdata = data; - distributeAsyncFunction(data, [localdata = std::move(localdata), fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace]() mutable { - return doProcessUDPQuestion(localdata, fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace); + distributeAsyncFunction(data, [localdata = std::move(localdata), fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace, otTrace]() mutable { + return doProcessUDPQuestion(localdata, fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace, otTrace); }); } else { - doProcessUDPQuestion(data, fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace); + doProcessUDPQuestion(data, fromaddr, destaddr, source, destination, mappedSource, tval, fileDesc, proxyProtocolValues, eventTrace, otTrace); } } } catch (const MOADNSException& mde) { t_Counters.at(rec::Counter::clientParseError)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to parse packet from remote UDP client " << fromaddr.toString() << ": " << mde.what() << endl, - g_slogudpin->error(Logr::Error, mde.what(), "Unable to parse packet from remote UDP client", "remote", Logging::Loggable(fromaddr), "exception", Logging::Loggable("MOADNSException"))); + g_slogudpin->error(Logr::Error, mde.what(), "Unable to parse packet from remote UDP client", "remote", Logging::Loggable(fromaddr), "exception", Logging::Loggable("MOADNSException")); } } catch (const std::runtime_error& e) { t_Counters.at(rec::Counter::clientParseError)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to parse packet from remote UDP client " << fromaddr.toString() << ": " << e.what() << endl, - g_slogudpin->error(Logr::Error, e.what(), "Unable to parse packet from remote UDP client", "remote", Logging::Loggable(fromaddr), "exception", Logging::Loggable("std::runtime_error"))); + g_slogudpin->error(Logr::Error, e.what(), "Unable to parse packet from remote UDP client", "remote", Logging::Loggable(fromaddr), "exception", Logging::Loggable("std::runtime_error")); } } } @@ -2710,16 +2794,18 @@ } const uint16_t defaultLocalPort = ::arg().asNum("local-port"); + const vector defaultVector = {"127.0.0.1", "::1"}; + const auto configIsDefault = localAddresses == defaultVector; + for (const auto& localAddress : localAddresses) { ComboAddress address{localAddress, defaultLocalPort}; - const int socketFd = socket(address.sin4.sin_family, SOCK_DGRAM, 0); + auto socketFd = FDWrapper(socket(address.sin4.sin_family, SOCK_DGRAM, 0)); if (socketFd < 0) { throw PDNSException("Making a UDP server socket for resolver: " + stringerror()); } - logVec.emplace_back(address.toStringWithPort()); + if (!setSocketTimestamps(socketFd)) { - SLOG(g_log << Logger::Warning << "Unable to enable timestamp reporting for socket" << endl, - log->info(Logr::Warning, "Unable to enable timestamp reporting for socket")); + log->info(Logr::Warning, "Unable to enable timestamp reporting for socket"); } if (IsAnyAddress(address)) { if (address.sin4.sin_family == AF_INET) { @@ -2736,8 +2822,7 @@ #endif if (address.sin6.sin6_family == AF_INET6 && setsockopt(socketFd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) { int err = errno; - SLOG(g_log << Logger::Warning << "Failed to set IPv6 socket to IPv6 only, continuing anyhow: " << stringerror(err) << endl, - log->error(Logr::Warning, err, "Failed to set IPv6 socket to IPv6 only, continuing anyhow")); + log->error(Logr::Warning, err, "Failed to set IPv6 socket to IPv6 only, continuing anyhow"); } } if (::arg().mustDo("non-local-bind")) { @@ -2750,8 +2835,7 @@ setSocketReceiveBuffer(socketFd, 250000); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while setting socket buffer size")); + log->error(Logr::Error, e.what(), "Exception while setting socket buffer size"); } if (g_reusePort) { @@ -2776,19 +2860,25 @@ setSocketIgnorePMTU(socketFd, address.sin4.sin_family); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Failed to set IP_MTU_DISCOVER on UDP server socket: " << e.what() << endl, - log->error(Logr::Warning, e.what(), "Failed to set IP_MTU_DISCOVER on UDP server socket")); + log->error(Logr::Warning, e.what(), "Failed to set IP_MTU_DISCOVER on UDP server socket"); } socklen_t socklen = address.getSocklen(); if (::bind(socketFd, reinterpret_cast(&address), socklen) < 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - throw PDNSException("Resolver binding to server socket on " + address.toStringWithPort() + ": " + stringerror()); + int err = errno; + if (!configIsDefault || address != ComboAddress{"::1", defaultLocalPort}) { + throw PDNSException("Resolver binding to server socket on " + address.toStringWithPort() + ": " + stringerror(err)); + } + log->info(Logr::Warning, "Cannot listen on this address, skipping", "proto", Logging::Loggable("UDP"), "address", Logging::Loggable(address), "error", Logging::Loggable(stringerror(err))); + continue; } setNonBlocking(socketFd); deferredAdds.emplace_back(socketFd, handleNewUDPQuestion); g_listenSocketsAddresses[socketFd] = address; // this is written to only from the startup thread, not from the workers + logVec.emplace_back(address.toStringWithPort()); + socketFd.release(); // to avoid auto-close by FDWrapper } if (doLog) { log->info(Logr::Info, "Listening for queries", "proto", Logging::Loggable("UDP"), "addresses", Logging::IterLoggable(logVec.cbegin(), logVec.cend()), "socketInstances", Logging::Loggable(instances), "reuseport", Logging::Loggable(g_reusePort)); @@ -2800,8 +2890,7 @@ { auto& targetInfo = RecThreadInfo::info(target); if (!targetInfo.isWorker()) { - SLOG(g_log << Logger::Error << "distributeAsyncFunction() tried to assign a query to a non-worker thread" << endl, - g_slog->withName("runtime")->info(Logr::Error, "distributeAsyncFunction() tried to assign a query to a non-worker thread")); + g_slog->withName("runtime")->info(Logr::Error, "distributeAsyncFunction() tried to assign a query to a non-worker thread"); _exit(1); } @@ -2868,8 +2957,7 @@ void distributeAsyncFunction(const string& packet, const pipefunc_t& func) { if (!RecThreadInfo::self().isDistributor()) { - SLOG(g_log << Logger::Error << "distributeAsyncFunction() has been called by a worker (" << RecThreadInfo::id() << ")" << endl, - g_slog->withName("runtime")->info(Logr::Error, "distributeAsyncFunction() has been called by a worker")); // tid will be added + g_slog->withName("runtime")->info(Logr::Error, "distributeAsyncFunction() has been called by a worker"); // tid will be added _exit(1); } @@ -2885,6 +2973,7 @@ ThreadMSG* tmsg = new ThreadMSG(); // NOLINT: pointer ownership tmsg->func = func; tmsg->wantAnswer = false; + __tsan_release(tmsg); if (!trySendingQueryToWorker(target, tmsg)) { /* if this function failed but did not raise an exception, it means that the pipe @@ -2896,6 +2985,7 @@ if (!trySendingQueryToWorker(newTarget, tmsg)) { t_Counters.at(rec::Counter::queryPipeFullDrops)++; + __tsan_acquire(tmsg); delete tmsg; // NOLINT: pointer ownership } } @@ -2951,8 +3041,8 @@ // found an ECS option EDNSSubnetOpts ecs; for (const auto& value : option->second.values) { - if (getEDNSSubnetOptsFromString(value.content, value.size, &ecs)) { - if (ecs.source == subnet) { + if (EDNSSubnetOpts::getFromString(value.content, value.size, &ecs)) { + if (ecs.getSource() == subnet) { foundMatchingECS = true; } } @@ -2994,8 +3084,7 @@ // Drop it, but continue to wait for other packets t_Counters.at(rec::Counter::serverParseError)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to parse too short packet from remote UDP server " << fromaddr.toString() << ": packet smaller than DNS header" << endl, - g_slogout->info(Logr::Error, "Unable to parse too short packet from remote UDP server", "from", Logging::Loggable(fromaddr))); + g_slogout->info(Logr::Error, "Unable to parse too short packet from remote UDP server", "from", Logging::Loggable(fromaddr)); } return; } @@ -3010,36 +3099,38 @@ pident->id = dnsheader.id; pident->fd = fileDesc; - if (!dnsheader.qr && g_logCommonErrors) { - SLOG(g_log << Logger::Notice << "Not taking data from question on outgoing socket from " << fromaddr.toStringWithPort() << endl, - g_slogout->info(Logr::Error, "Not taking data from question on outgoing socket", "from", Logging::Loggable(fromaddr))); + if (!dnsheader.qr) { + // RFC 1035 Section 4.1.1: QR=0 means query, not response. Discard. + if (g_logCommonErrors) { + g_slogout->info(Logr::Error, "Not taking data from question on outgoing socket", "from", Logging::Loggable(fromaddr)); + } + t_Counters.at(rec::Counter::unexpectedCount)++; + return; } - if (dnsheader.qdcount == 0U || // UPC, Nominum, very old BIND on FormErr, NSD - dnsheader.qr == 0U) { // one weird server - pident->domain.clear(); - pident->type = 0; + if (ntohs(dnsheader.qdcount) != 1 && (ntohs(dnsheader.ancount) > 0 || ntohs(dnsheader.nscount) > 0 || ntohs(dnsheader.arcount) > 0)) { + g_slogout->info(Logr::Error, "Invalid qdcount in answer", "from", Logging::Loggable(fromaddr)); + t_Counters.at(rec::Counter::unexpectedCount)++; + return; } - else { - try { - if (len > signed_sizeof_sdnsheader) { - pident->domain = DNSName(reinterpret_cast(packet.data()), static_cast(len), static_cast(sizeof(dnsheader)), false, &pident->type); // don't copy this from above - we need to do the actual read // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - } - else { - // len == sizeof(dnsheader), only header case - // We will do a full scan search later to see if we can match this reply even without a domain - pident->domain.clear(); - pident->type = 0; - } + + try { + if (len > signed_sizeof_sdnsheader) { + pident->domain = DNSName(reinterpret_cast(packet.data()), static_cast(len), static_cast(sizeof(dnsheader)), false, &pident->type); // don't copy this from above - we need to do the actual read // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) } - catch (std::exception& e) { - // Parse error, continue waiting for other packets - t_Counters.at(rec::Counter::serverParseError)++; // won't be fed to lwres.cc, so we have to increment - SLOG(g_log << Logger::Warning << "Error in packet from remote nameserver " << fromaddr.toStringWithPort() << ": " << e.what() << endl, - g_slogudpin->error(Logr::Warning, e.what(), "Error in packet from remote nameserver", "from", Logging::Loggable(fromaddr))); - return; + else { + // len == sizeof(dnsheader), only header case + // We will do a full scan search later to see if we can match this reply even without a domain + pident->domain.clear(); + pident->type = 0; } } + catch (std::exception& e) { + // Parse error, continue waiting for other packets + t_Counters.at(rec::Counter::serverParseError)++; // won't be fed to lwres.cc, so we have to increment + g_slogudpin->error(Logr::Warning, e.what(), "Error in packet from remote nameserver", "from", Logging::Loggable(fromaddr)); + return; + } if (!pident->domain.empty()) { auto iter = g_multiTasker->getWaiters().find(pident); @@ -3066,16 +3157,15 @@ if (pident->domain.empty() && !d_waiter.key->domain.empty() && pident->type == 0 && d_waiter.key->type != 0 && pident->id == d_waiter.key->id && d_waiter.key->remote == pident->remote) { pident->domain = d_waiter.key->domain; pident->type = d_waiter.key->type; - goto retryWithName; // note that this only passes on an error, lwres will still reject the packet NOLINT(cppcoreguidelines-avoid-goto) + goto retryWithName; // note that this only passes on an error, lwres still should reject the packet NOLINT(cppcoreguidelines-avoid-goto) } } t_Counters.at(rec::Counter::unexpectedCount)++; // if we made it here, it really is an unexpected answer if (g_logCommonErrors) { - SLOG(g_log << Logger::Warning << "Discarding unexpected packet from " << fromaddr.toStringWithPort() << ": " << (pident->domain.empty() ? "" : pident->domain.toString()) << ", " << pident->type << ", " << g_multiTasker->getWaiters().size() << " waiters" << endl, - g_slogudpin->info(Logr::Warning, "Discarding unexpected packet", "from", Logging::Loggable(fromaddr), - "qname", Logging::Loggable(pident->domain), - "qtype", Logging::Loggable(QType(pident->type)), - "waiters", Logging::Loggable(g_multiTasker->getWaiters().size()))); + g_slogudpin->info(Logr::Warning, "Discarding unexpected packet", "from", Logging::Loggable(fromaddr), + "qname", Logging::Loggable(pident->domain), + "qtype", Logging::Loggable(QType(pident->type)), + "waiters", Logging::Loggable(g_multiTasker->getWaiters().size())); } } else if (fileDesc >= 0) { diff -Nru pdns-recursor-5.2.13/pdnsexception.hh pdns-recursor-5.4.9/pdnsexception.hh --- pdns-recursor-5.2.13/pdnsexception.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/pdnsexception.hh 2026-10-26 09:46:36.000000000 +0000 @@ -21,6 +21,7 @@ */ #pragma once #include +#include #include "namespaces.hh" @@ -29,8 +30,9 @@ { public: PDNSException() : reason("Unspecified") {}; - PDNSException(const string& r) : reason(r) {}; - + PDNSException(string r) : + reason(std::move(r)) {}; + string reason; //! Print this to tell the user what went wrong }; diff -Nru pdns-recursor-5.2.13/protozero-helpers.hh pdns-recursor-5.4.9/protozero-helpers.hh --- pdns-recursor-5.2.13/protozero-helpers.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/protozero-helpers.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,98 @@ +/* + * 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 +#include + +#include "iputils.hh" + +enum class PBComboAddress : protozero::pbf_tag_type +{ + required_uint32_port = 1, + required_bytes_address = 2, // family implicit +}; + +template +void encodeComboAddress(protozero::pbf_builder& writer, T type, const ComboAddress& address) +{ + protozero::pbf_builder message(writer, type); + + // Skip all parts except address and port + message.add_uint32(PBComboAddress::required_uint32_port, address.getPort()); + if (address.sin4.sin_family == AF_INET) { + message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast(&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 (address.sin4.sin_family == AF_INET6) { + message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API + } +} + +template +void decodeComboAddress(protozero::pbf_message& reader, ComboAddress& address) +{ + address.reset(); + protozero::pbf_message message(reader.get_message()); + + // Skip all parts except address and port + if (message.next(PBComboAddress::required_uint32_port)) { + address.setPort(message.get_uint32()); + } + else { + throw std::runtime_error("expected port in protobuf data"); + } + constexpr auto inet4size = sizeof(address.sin4.sin_addr); + constexpr auto inet6size = sizeof(address.sin6.sin6_addr); + if (message.next(PBComboAddress::required_bytes_address)) { + auto data = message.get_bytes(); + address.sin4.sin_family = data.size() == inet4size ? AF_INET : AF_INET6; + if (data.size() == inet4size) { + address.sin4.sin_family = AF_INET; + memcpy(&address.sin4.sin_addr, data.data(), data.size()); + } + else if (data.size() == inet6size) { + address.sin6.sin6_family = AF_INET6; + memcpy(&address.sin6.sin6_addr, data.data(), data.size()); + } + else { + throw std::runtime_error("unexpected address family in protobuf data"); + } + } + else { + throw std::runtime_error("expected address bytes in protobuf data"); + } +} + +template +void encodeNetmask(protozero::pbf_builder& writer, T type, const Netmask& subnet) +{ + if (!subnet.empty()) { + writer.add_bytes(type, reinterpret_cast(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API + } +} + +template +void decodeNetmask(protozero::pbf_message& message, Netmask& subnet) +{ + auto data = message.get_bytes(); + memcpy(&subnet, data.data(), std::min(sizeof(subnet), data.size())); +} diff -Nru pdns-recursor-5.2.13/protozero-trace.cc pdns-recursor-5.4.9/protozero-trace.cc --- pdns-recursor-5.2.13/protozero-trace.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/protozero-trace.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,605 @@ +/* + * 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 "protozero-trace.hh" +#include "base64.hh" +#include "ednsoptions.hh" +#include "misc.hh" +#include +#include + +namespace pdns::trace +{ + +void AnyValue::encode(protozero::pbf_writer& writer) const +{ + if (std::holds_alternative(*this)) { + pdns::trace::encode(writer, 1, std::get(*this), true); + } + else if (std::holds_alternative(*this)) { + pdns::trace::encode(writer, 2, std::get(*this), true); + } + else if (std::holds_alternative(*this)) { + pdns::trace::encode(writer, 3, std::get(*this), true); + } + else if (std::holds_alternative(*this)) { + pdns::trace::encode(writer, 4, std::get(*this), true); + } + else if (std::holds_alternative(*this)) { + protozero::pbf_writer sub{writer, 5}; + std::get(*this).encode(sub); + } + else if (std::holds_alternative(*this)) { + protozero::pbf_writer sub{writer, 6}; + std::get(*this).encode(sub); + } + else if (std::holds_alternative>(*this)) { + pdns::trace::encode(writer, 7, std::get>(*this), true); + } +} + +AnyValue AnyValue::decode(protozero::pbf_reader& reader) +{ + while (reader.next()) { + switch (reader.tag()) { + case 1: + return AnyValue{reader.get_string()}; + break; + case 2: + return AnyValue{reader.get_bool()}; + break; + case 3: + return AnyValue{reader.get_int64()}; + break; + case 4: + return AnyValue{reader.get_double()}; + break; + case 5: { + protozero::pbf_reader arrayvalue = reader.get_message(); + return AnyValue{ArrayValue::decode(arrayvalue)}; + break; + } + case 6: { + protozero::pbf_reader kvlist = reader.get_message(); + return AnyValue{KeyValueList::decode(kvlist)}; + break; + } + case 7: { + auto value = reader.get_view(); + std::vector data{}; + data.reserve(value.size()); + for (size_t i = 0; i < value.size(); ++i) { + data.push_back(static_cast(value.data()[i])); + } + return AnyValue{std::move(data)}; + break; + } + default: + break; + } + } + + return {}; +} + +std::string AnyValue::toLogString() const +{ + if (std::holds_alternative(*this)) { + return "\"" + std::get(*this) + "\""; + } + if (std::holds_alternative(*this)) { + if (std::get(*this)) { + return "true"; + } + return "false"; + } + if (std::holds_alternative(*this)) { + return std::to_string(std::get(*this)); + } + if (std::holds_alternative(*this)) { + return std::to_string(std::get(*this)); + } + if (std::holds_alternative(*this)) { + std::string tmp = "["; + for (auto const& val : std::get(*this).values) { + tmp += val.toLogString() + ", "; + } + tmp.resize(tmp.size() - 2); // Strip ", " + return tmp += "]"; + } + if (std::holds_alternative(*this)) { + std::string tmp = "{"; + for (auto const& val : std::get(*this).values) { + tmp += val.key + ": " + val.value.toLogString() + ", "; + } + if (tmp.size() > 2) { + tmp.resize(tmp.size() - 2); // Strip ", " + } + return tmp += "}"; + } + if (std::holds_alternative>(*this)) { + auto val = std::get>(*this); + return Base64Encode(std::string(val.begin(), val.end())); + } + return "UNSUPPORTED TYPE"; +} + +void EntityRef::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, schema_url); + pdns::trace::encode(writer, 2, type); + for (auto const& element : id_keys) { + pdns::trace::encode(writer, 3, element); + } + for (auto const& element : description_keys) { + pdns::trace::encode(writer, 4, element); + } +} + +EntityRef EntityRef::decode(protozero::pbf_reader& reader) +{ + EntityRef ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: + ret.schema_url = reader.get_string(); + break; + case 2: + ret.type = reader.get_string(); + break; + case 3: + ret.id_keys.emplace_back(reader.get_string()); + break; + case 4: + ret.description_keys.emplace_back(reader.get_string()); + break; + default: + break; + } + } + return ret; +} + +void KeyValue::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, key); + { + protozero::pbf_writer val_sub{writer, 2}; + value.encode(val_sub); + } +} + +void Resource::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, attributes); + pdns::trace::encode(writer, 2, dropped_attributes_count); + pdns::trace::encode(writer, 3, entity_refs); +} + +Resource Resource::decode(protozero::pbf_reader& reader) +{ + Resource ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: { + auto sub = reader.get_message(); + ret.attributes.emplace_back(KeyValue::decode(sub)); + break; + } + case 2: + ret.dropped_attributes_count = reader.get_uint32(); + break; + case 3: { + auto sub = reader.get_message(); + ret.entity_refs.emplace_back(EntityRef::decode(sub)); + break; + } + default: + break; + } + } + return ret; +} + +void InstrumentationScope::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, name); + pdns::trace::encode(writer, 2, version); + pdns::trace::encode(writer, 3, attributes); + pdns::trace::encode(writer, 4, dropped_attributes_count); +} + +InstrumentationScope InstrumentationScope::decode(protozero::pbf_reader& reader) +{ + InstrumentationScope ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: + ret.name = reader.get_string(); + break; + case 2: + ret.version = reader.get_string(); + break; + case 3: { + auto sub = reader.get_message(); + ret.attributes.emplace_back(KeyValue::decode(sub)); + break; + } + case 4: + ret.dropped_attributes_count = reader.get_uint32(); + break; + default: + break; + } + } + return ret; +} + +void Status::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 2, message); + pdns::trace::encode(writer, 3, uint32_t(code)); +} + +Status Status::decode(protozero::pbf_reader& reader) +{ + Status ret; + while (reader.next()) { + switch (reader.tag()) { + case 2: + ret.message = reader.get_string(); + break; + case 3: + ret.code = static_cast(reader.get_uint32()); + break; + default: + break; + } + } + return ret; +} + +void Span::Event::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encodeFixed(writer, 1, time_unix_nano); + pdns::trace::encode(writer, 2, name); + pdns::trace::encode(writer, 3, attributes); + pdns::trace::encode(writer, 4, dropped_attributes_count); +} + +Span::Event Span::Event::decode(protozero::pbf_reader& reader) +{ + Span::Event ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: + ret.time_unix_nano = reader.get_fixed64(); + break; + case 2: + ret.name = reader.get_string(); + break; + case 3: { + auto sub = reader.get_message(); + ret.attributes.emplace_back(KeyValue::decode(sub)); + break; + } + case 4: + ret.dropped_attributes_count = reader.get_uint32(); + default: + break; + } + } + return ret; +} + +void Span::Link::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, trace_id); + pdns::trace::encode(writer, 2, span_id); + pdns::trace::encode(writer, 3, trace_state); + pdns::trace::encode(writer, 4, attributes); + pdns::trace::encode(writer, 5, dropped_attributes_count); + pdns::trace::encodeFixed(writer, 6, flags); +} + +Span::Link Span::Link::decode(protozero::pbf_reader& reader) +{ + Link ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: + ret.trace_id = decodeTraceID(reader); + break; + case 2: + ret.span_id = decodeSpanID(reader); + break; + case 3: + ret.trace_state = reader.get_string(); + break; + case 4: { + auto sub = reader.get_message(); + ret.attributes.emplace_back(KeyValue::decode(sub)); + break; + } + case 5: + ret.dropped_attributes_count = reader.get_uint32(); + break; + case 6: + ret.flags = reader.get_fixed32(); + default: + break; + } + } + return ret; +} + +void Span::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, trace_id); + pdns::trace::encode(writer, 2, span_id); + pdns::trace::encode(writer, 3, trace_state); + pdns::trace::encode(writer, 4, parent_span_id); + pdns::trace::encode(writer, 5, name); + pdns::trace::encode(writer, 6, uint32_t(kind)); + pdns::trace::encodeFixed(writer, 7, start_time_unix_nano); + pdns::trace::encodeFixed(writer, 8, end_time_unix_nano); + pdns::trace::encode(writer, 9, attributes); + pdns::trace::encode(writer, 10, dropped_attributes_count); + pdns::trace::encode(writer, 11, events); + pdns::trace::encode(writer, 12, dropped_events_count); + pdns::trace::encode(writer, 13, links); + pdns::trace::encode(writer, 14, dropped_links_count); + if (status.code != Status::StatusCode::STATUS_CODE_UNSET || !status.message.empty()) { + protozero::pbf_writer sub{writer, 15}; + status.encode(sub); + } + pdns::trace::encodeFixed(writer, 16, flags); +} + +Span Span::decode(protozero::pbf_reader& reader) +{ + Span ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: + ret.trace_id = decodeTraceID(reader); + break; + case 2: + ret.span_id = decodeSpanID(reader); + break; + case 3: + ret.trace_state = reader.get_string(); + break; + case 4: + ret.parent_span_id = decodeSpanID(reader); + break; + case 5: + ret.name = reader.get_string(); + break; + case 6: + ret.kind = static_cast(reader.get_uint32()); + break; + case 7: + ret.start_time_unix_nano = reader.get_fixed64(); + break; + case 8: + ret.end_time_unix_nano = reader.get_fixed64(); + break; + case 9: { + auto sub = reader.get_message(); + ret.attributes.emplace_back(KeyValue::decode(sub)); + break; + } + case 10: + ret.dropped_attributes_count = reader.get_uint32(); + break; + case 11: { + auto sub = reader.get_message(); + ret.events.emplace_back(Span::Event::decode(sub)); + break; + } + case 12: + ret.dropped_events_count = reader.get_uint32(); + break; + case 13: { + auto sub = reader.get_message(); + ret.links.emplace_back(Span::Link::decode(sub)); + break; + } + case 14: + ret.dropped_links_count = reader.get_uint32(); + break; + case 15: { + auto sub = reader.get_message(); + ret.status = Status::decode(sub); + break; + } + case 16: + ret.flags = reader.get_fixed32(); + break; + default: + break; + } + } + return ret; +} + +void ScopeSpans::encode(protozero::pbf_writer& writer) const +{ + { + protozero::pbf_writer sub{writer, 1}; + scope.encode(sub); + } + pdns::trace::encode(writer, 2, spans); + pdns::trace::encode(writer, 3, schema_url); +} + +ScopeSpans ScopeSpans::decode(protozero::pbf_reader& reader) +{ + ScopeSpans ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: { + auto sub = reader.get_message(); + ret.scope = InstrumentationScope::decode(sub); + break; + } + case 2: { + auto sub = reader.get_message(); + ret.spans.emplace_back(Span::decode(sub)); + break; + } + case 3: + ret.schema_url = reader.get_string(); + default: + break; + } + } + return ret; +} + +void ResourceSpans::encode(protozero::pbf_writer& writer) const +{ + { + protozero::pbf_writer sub{writer, 1}; + resource.encode(sub); + } + pdns::trace::encode(writer, 2, scope_spans); + pdns::trace::encode(writer, 3, schema_url); +} + +ResourceSpans ResourceSpans::decode(protozero::pbf_reader& reader) +{ + ResourceSpans ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: { + protozero::pbf_reader sub = reader.get_message(); + ret.resource = Resource::decode(sub); + break; + } + case 2: { + protozero::pbf_reader sub = reader.get_message(); + ret.scope_spans.emplace_back(ScopeSpans::decode(sub)); + break; + } + case 3: + ret.schema_url = reader.get_string(); + default: + break; + } + } + return ret; +} + +void TracesData::encode(protozero::pbf_writer& writer) const +{ + pdns::trace::encode(writer, 1, resource_spans); +} + +TracesData TracesData::decode(protozero::pbf_reader& reader) +{ + TracesData ret; + while (reader.next()) { + switch (reader.tag()) { + case 1: { + auto sub = reader.get_message(); + ret.resource_spans.emplace_back(ResourceSpans::decode(sub)); + break; + } + default: + break; + } + } + return ret; +} + +KeyValue KeyValue::decode(protozero::pbf_reader& reader) +{ + KeyValue value; + while (reader.next()) { + switch (reader.tag()) { + case 1: + value.key = reader.get_string(); + break; + case 2: { + protozero::pbf_reader sub = reader.get_message(); + value.value = AnyValue::decode(sub); + break; + } + default: + break; + } + } + return value; +} + +bool extractOTraceIDs(const EDNSOptionViewMap& map, EDNSOptionCode::EDNSOptionCodeEnum eoc, pdns::trace::InitialSpanInfo& span) +{ + // traceid gets set from edns options (if available and well-formed) + // parent_span_id gets set from edns options (if available and well-formed) + auto traceidset = extractOTraceIDs(map, eoc, span.trace_id, span.parent_span_id); + return traceidset; +} + +/** + * @brief Extract the Trace and Span IDs from + * + * @param map an EDNSOptionViewMap where a TraceID option might be + * @param eoc the EDNS option code where the TraceID might be, OTTRACEIDS by default + * @param traceID will be set to the TraceID in the EDNS option, untouched otherwise + * @param spanID will be set to the SpanID in the EDNS options, untouched otherwise + * @return true if a traceid was found in the EDNS options + */ +bool extractOTraceIDs(const EDNSOptionViewMap& map, EDNSOptionCode::EDNSOptionCodeEnum eoc, pdns::trace::TraceID& traceID, pdns::trace::SpanID& spanID) +{ + EDNSOptionCode::EDNSOptionCodeEnum realEOC = eoc; + if (realEOC == 0) { + realEOC = EDNSOptionCode::TRACEPARENT; + } + bool traceidset = false; + if (const auto& option = map.find(realEOC); option != map.end()) { + const auto& value = option->second.values.at(0); + const EDNSOTTraceRecordView data{reinterpret_cast(value.content), value.size}; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + // 1 byte version, then tracid then optional spanid + uint8_t version{}; + if (data.getVersion(version) && version == 0) { + if (data.getTraceID(traceID)) { + traceidset = true; + } + (void)data.getSpanID(spanID); + } + } + return traceidset; +} + +std::string SpanID::toLogString() const +{ + return makeHexDump(std::string(this->begin(), this->end()), ""); +} + +std::string TraceID::toLogString() const +{ + return makeHexDump(std::string(this->begin(), this->end()), ""); +} + +} // namespace pdns::trace diff -Nru pdns-recursor-5.2.13/protozero-trace.hh pdns-recursor-5.4.9/protozero-trace.hh --- pdns-recursor-5.2.13/protozero-trace.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/protozero-trace.hh 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,884 @@ +/* + * 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 +#include +#include + +#include +#include + +#include "dns_random.hh" +#include "ednsoptions.hh" +#include "misc.hh" + +// See https://github.com/open-telemetry/opentelemetry-proto/tree/main/opentelemetry/proto + +namespace pdns::trace +{ + +// https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/common/v1/common.proto + +struct AnyValue; +struct ArrayValue; +struct KeyValue; +struct KeyValueList; + +inline void encode(protozero::pbf_writer& writer, uint8_t field, bool value, bool always = false) +{ + if (always || value) { + writer.add_bool(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, uint32_t value, bool always = false) +{ + if (always || value != 0) { + writer.add_uint32(field, value); + } +} + +inline void encodeFixed(protozero::pbf_writer& writer, uint8_t field, uint32_t value) +{ + if (value != 0) { + writer.add_fixed32(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, int64_t value, bool always = false) +{ + if (always || value != 0) { + writer.add_int64(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, uint64_t value, bool always = false) +{ + if (always || value != 0) { + writer.add_uint64(field, value); + } +} + +inline void encodeFixed(protozero::pbf_writer& writer, uint8_t field, uint64_t value) +{ + if (value != 0) { + writer.add_fixed64(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, double value, bool always = false) +{ + if (always || value != 0.0) { + writer.add_double(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, const std::string& value, bool always = false) +{ + if (always || !value.empty()) { + writer.add_string(field, value); + } +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, const std::vector& value, bool always = false) +{ + if (always || !value.empty()) { + writer.add_bytes(field, reinterpret_cast(value.data()), value.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) it's the API + } +} + +template +void encode(protozero::pbf_writer& writer, const std::vector& vec) +{ + for (auto const& element : vec) { + element.encode(writer); + } +} + +template +void encode(protozero::pbf_writer& writer, uint8_t field, const std::vector& vec) +{ + for (auto const& element : vec) { + protozero::pbf_writer sub{writer, field}; + element.encode(sub); + } +} + +template +T decode(protozero::pbf_reader& reader) +{ + std::vector vec; + while (reader.next()) { + if (reader.tag() == 1) { + protozero::pbf_reader sub = reader.get_message(); + vec.emplace_back(E::decode(sub)); + } + } + return {std::move(vec)}; +} + +struct ArrayValue +{ + std::vector values; // = 1 + + void encode(protozero::pbf_writer& writer) const + { + pdns::trace::encode(writer, 1, values); + } + + static ArrayValue decode(protozero::pbf_reader& reader); + + bool operator==(const ArrayValue& rhs) const; +}; + +struct KeyValueList +{ + std::vector values; // = 1 + + void encode(protozero::pbf_writer& writer) const + { + pdns::trace::encode(writer, 1, values); + } + + static KeyValueList decode(protozero::pbf_reader& reader); + + bool operator==(const KeyValueList& rhs) const; +}; + +using NoValue = char; +struct AnyValue : public std::variant> +{ + void encode(protozero::pbf_writer& writer) const; + static AnyValue decode(protozero::pbf_reader& reader); + [[nodiscard]] std::string toLogString() const; + friend std::ostream& operator<<(std::ostream& ostrm, const AnyValue& val) + { + return ostrm << val.toLogString(); + } +}; + +struct EntityRef +{ + std::string schema_url{}; // == 1 + std::string type{}; // == 2 + std::vector id_keys{}; // == 3 + std::vector description_keys{}; // == 4 + + void encode(protozero::pbf_writer& writer) const; + static EntityRef decode(protozero::pbf_reader& reader); +}; + +struct KeyValue +{ + std::string key{}; // = 1 + AnyValue value{}; // = 2 + void encode(protozero::pbf_writer& writer) const; + static KeyValue decode(protozero::pbf_reader& reader); + + bool operator==(const KeyValue& rhs) const; +}; + +struct Resource +{ + std::vector attributes{}; // = 1 + uint32_t dropped_attributes_count{0}; // = 2; + std::vector entity_refs{}; // = 3 + + void encode(protozero::pbf_writer& writer) const; + static Resource decode(protozero::pbf_reader& reader); +}; + +struct InstrumentationScope +{ + std::string name{}; // = 1 + std::string version{}; // = 2 + std::vector attributes{}; // = 3 + uint32_t dropped_attributes_count{0}; // = 4 + + void encode(protozero::pbf_writer& writer) const; + static InstrumentationScope decode(protozero::pbf_reader& reader); +}; + +struct TraceID : public std::array +{ + constexpr TraceID() : + array{} {}; + TraceID(const std::initializer_list& arg) : + array{} + { + std::copy(arg.begin(), arg.end(), begin()); + } + + [[nodiscard]] std::string toLogString() const; + friend std::ostream& operator<<(std::ostream& ostrm, const TraceID& val) + { + return ostrm << val.toLogString(); + } + + static TraceID getRandomTraceID() + { + TraceID ret; + ret.makeRandom(); + return ret; + } + + void makeRandom() + { + dns_random(this->data(), this->size()); + } + + void clear() + { + this->fill(0); + } +}; +constexpr TraceID s_emptyTraceID = {}; + +struct SpanID : public std::array +{ + constexpr SpanID() : + array{} {}; + SpanID(const std::initializer_list& arg) : + array{} + { + std::copy(arg.begin(), arg.end(), begin()); + } + + [[nodiscard]] std::string toLogString() const; + friend std::ostream& operator<<(std::ostream& ostrm, const SpanID& val) + { + return ostrm << val.toLogString(); + } + + static SpanID getRandomSpanID() + { + SpanID ret; + ret.makeRandom(); + return ret; + } + + void makeRandom() + { + dns_random(this->data(), this->size()); + } + + void clear() + { + this->fill(0); + } +}; +constexpr SpanID s_emptySpanID = {}; + +inline void fill(TraceID& trace, const std::string& data) +{ + if (data.size() != trace.size()) { + throw std::runtime_error("TraceID size mismatch"); + } + std::copy(data.begin(), data.end(), trace.begin()); +} + +inline void fill(SpanID& span, const std::string& data) +{ + if (data.size() != span.size()) { + throw std::runtime_error("SpanID size mismatch"); + } + std::copy(data.begin(), data.end(), span.begin()); +} + +inline void fill(TraceID& trace, const char* data, size_t size) +{ + fill(trace, std::string(data, size)); +} + +inline void fill(SpanID& span, const char* data, size_t size) +{ + fill(span, std::string(data, size)); +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, const TraceID& value) +{ + writer.add_bytes(field, reinterpret_cast(value.data()), value.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) it's the API +} + +inline TraceID decodeTraceID(protozero::pbf_reader& reader) +{ + TraceID bytes; + const auto data = reader.get_view(); + const auto len = std::min(bytes.size(), data.size()); + std::copy(data.data(), data.data() + len, bytes.begin()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return bytes; +} + +inline void encode(protozero::pbf_writer& writer, uint8_t field, const SpanID& value) +{ + writer.add_bytes(field, reinterpret_cast(value.data()), value.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) it's the API +} + +inline SpanID decodeSpanID(protozero::pbf_reader& reader) +{ + SpanID bytes; + const auto data = reader.get_view(); + const auto len = std::min(bytes.size(), data.size()); + std::copy(data.data(), data.data() + len, bytes.begin()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return bytes; +} + +// The Status type defines a logical error model that is suitable for different +// programming environments, including REST APIs and RPC APIs. +struct Status +{ + // A developer-facing human readable error message. + std::string message{}; // = 2; + + // For the semantics of status codes see + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status + enum class StatusCode : uint8_t + { + // The default status. + STATUS_CODE_UNSET = 0, + // The Span has been validated by an Application developer or Operator to + // have completed successfully. + STATUS_CODE_OK = 1, + // The Span contains an error. + STATUS_CODE_ERROR = 2, + }; + + // The status code. + StatusCode code{StatusCode::STATUS_CODE_UNSET}; // = 3; + + void clear() + { + message.clear(); + code = StatusCode::STATUS_CODE_UNSET; + } + void encode(protozero::pbf_writer& writer) const; + static Status decode(protozero::pbf_reader& reader); +}; + +inline uint64_t timestamp() +{ + timespec now{}; + clock_gettime(CLOCK_REALTIME, &now); + return (1000000000ULL * now.tv_sec) + now.tv_nsec; +} + +// This struct is used to store the info of the initial span. As it is passed around resolving +// queries, it needs to be as small as possible, hence no full Span. +struct InitialSpanInfo +{ + TraceID trace_id{}; + SpanID span_id{}; + SpanID parent_span_id{}; + uint64_t start_time_unix_nano{0}; + + void clear() + { + trace_id.clear(); + span_id.clear(); + parent_span_id.clear(); + start_time_unix_nano = 0; + } + + void setIDsIfNotSet() + { + if (trace_id == s_emptyTraceID) { + trace_id.makeRandom(); + } + if (span_id == s_emptySpanID) { + span_id.makeRandom(); + } + } +}; + +struct Span +{ + // A unique identifier for a trace. All spans from the same trace share + // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes OR + // of length other than 16 bytes is considered invalid (empty string in OTLP/JSON + // is zero-length and thus is also invalid). + // + // This field is required. + TraceID trace_id{}; // = 1 + // A unique identifier for a span within a trace, assigned when the span + // is created. The ID is an 8-byte array. An ID with all zeroes OR of length + // other than 8 bytes is considered invalid (empty string in OTLP/JSON + // is zero-length and thus is also invalid). + // + // This field is required. + SpanID span_id{}; // = 2 + // trace_state conveys information about request position in multiple distributed tracing graphs. + // It is a trace_state in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header + // See also https://github.com/w3c/distributed-tracing for more details about this field. + std::string trace_state{}; // = 3 + // The `span_id` of this span's parent span. If this is a root span, then this + // field must be empty. The ID is an 8-byte array. + SpanID parent_span_id{}; // = 4 + // A description of the span's operation. + // + // For example, the name can be a qualified method name or a file name + // and a line number where the operation is called. A best practice is to use + // the same display name at the same call point in an application. + // This makes it easier to correlate spans in different traces. + // + // This field is semantically required to be set to non-empty string. + // Empty value is equivalent to an unknown span name. + // + // This field is required. + std::string name{}; // = 5 + + // SpanKind is the type of span. Can be used to specify additional relationships between spans + // in addition to a parent/child relationship. + enum class SpanKind : uint8_t + { + // Unspecified. Do NOT use as default. + // Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED. + SPAN_KIND_UNSPECIFIED = 0, + // Indicates that the span represents an internal operation within an application, + // as opposed to an operation happening at the boundaries. Default value. + SPAN_KIND_INTERNAL = 1, + // Indicates that the span covers server-side handling of an RPC or other + // remote network request. + SPAN_KIND_SERVER = 2, + // Indicates that the span describes a request to some remote service. + SPAN_KIND_CLIENT = 3, + // Indicates that the span describes a producer sending a message to a broker. + // Unlike CLIENT and SERVER, there is often no direct critical path latency relationship + // between producer and consumer spans. A PRODUCER span ends when the message was accepted + // by the broker while the logical processing of the message might span a much longer time. + SPAN_KIND_PRODUCER = 4, + // Indicates that the span describes consumer receiving a message from a broker. + // Like the PRODUCER kind, there is often no direct critical path latency relationship + // between producer and consumer spans. + SPAN_KINCONSUMER = 5, + }; + // Distinguishes between spans generated in a particular context. For example, + // two spans with the same name may be distinguished using `CLIENT` (caller) + // and `SERVER` (callee) to identify queueing latency associated with the span. + SpanKind kind{Span::SpanKind::SPAN_KIND_UNSPECIFIED}; // = 6 + // start_time_unix_nano is the start time of the span. On the client side, this is the time + // kept by the local machine where the span execution starts. On the server side, this + // is the time when the server's application handler starts running. + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + // + // This field is semantically required and it is expected that end_time >= start_time. + uint64_t start_time_unix_nano{0}; // = 7 + // end_time_unix_nano is the end time of the span. On the client side, this is the time + // kept by the local machine where the span execution ends. On the server side, this + // is the time when the server application handler stops running. + // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970. + // + // This field is semantically required and it is expected that end_time >= start_time. + uint64_t end_time_unix_nano{0}; // = 8 + // attributes is a collection of key/value pairs. Note, global attributes + // like server name can be set using the resource API. Examples of attributes: + // + // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" + // "/http/server_latency": 300 + // "example.com/myattribute": true + // "example.com/score": 10.239 + // + // The OpenTelemetry API specification further restricts the allowed value types: + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md#attribute + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + std::vector attributes{}; // = 9 + // dropped_attributes_count is the number of attributes that were discarded. Attributes + // can be discarded because their keys are too long or because there are too many + // attributes. If this value is 0, then no attributes were dropped. + uint32_t dropped_attributes_count{0}; // = 10 + + // Event is a time-stamped annotation of the span, consisting of user-supplied + // text description and key-value pairs.x + struct Event + { + // time_unix_nano is the time the event occurred. + uint64_t time_unix_nano; // = 1 + // name of the event. + // This field is semantically required to be set to non-empty string. + std::string name; // = 2 + // attributes is a collection of attribute key/value pairs on the event. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + std::vector attributes; // = 3 + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. + uint32_t dropped_attributes_count{0}; // = 4 + + void encode(protozero::pbf_writer& writer) const; + static Event decode(protozero::pbf_reader& reader); + }; + // events is a collection of Event items. + std::vector events{}; // = 11 + // dropped_events_count is the number of dropped events. If the value is 0, then no + // events were dropped. + uint32_t dropped_events_count{0}; // = 12 + + // A pointer from the current span to another span in the same trace or in a + // different trace. For example, this can be used in batching operations, + // where a single batch handler processes multiple requests from different + // traces or when the handler receives a request from a different project. + struct Link + { + // A unique identifier of a trace that this linked span is part of. The ID is a + // 16-byte array. + TraceID trace_id; // = 1 + // A unique identifier for the linked span. The ID is an 8-byte array. + SpanID span_id; // = 2 + // The trace_state associated with the link. + std::string trace_state; // = 3 + // attributes is a collection of attribute key/value pairs on the link. + // Attribute keys MUST be unique (it is not allowed to have more than one + // attribute with the same key). + std::vector attributes; // = 4 + // dropped_attributes_count is the number of dropped attributes. If the value is 0, + // then no attributes were dropped. + uint32_t dropped_attributes_count{0}; // = 5 + // Flags, a bit field. + // + // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + // Context specification. To read the 8-bit W3C trace flag, use + // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + // + // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. + // + // Bits 8 and 9 represent the 3 states of whether the link is remote. + // The states are (unknown, is not remote, is remote). + // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + // To read whether the link is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + // + // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + // When creating new spans, bits 10-31 (most-significant 22-bits) MUST be zero. + // + // [Optional]. + uint32_t flags{0}; // = 6 + + void encode(protozero::pbf_writer& writer) const; + static Link decode(protozero::pbf_reader& reader); + }; + std::vector links{}; // = 13 + uint32_t dropped_links_count{0}; // = 14 + Status status{}; // = 15 + + // Flags, a bit field. + // + // Bits 0-7 (8 least significant bits) are the trace flags as defined in W3C Trace + // Context specification. To read the 8-bit W3C trace flag, use + // `flags & SPAN_FLAGS_TRACE_FLAGS_MASK`. + // + // See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. + // + // Bits 8 and 9 represent the 3 states of whether a span's parent + // is remote. The states are (unknown, is not remote, is remote). + // To read whether the value is known, use `(flags & SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK) != 0`. + // To read whether the span is remote, use `(flags & SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK) != 0`. + // + // When creating span messages, if the message is logically forwarded from another source + // with an equivalent flags fields (i.e., usually another OTLP span message), the field SHOULD + // be copied as-is. If creating from a source that does not have an equivalent flags field + // (such as a runtime representation of an OpenTelemetry span), the high 22 bits MUST + // be set to zero. + // Readers MUST NOT assume that bits 10-31 (22 most significant bits) will be zero. + // + // [Optional]. + uint32_t flags{0}; // = 16; + + void close() + { + end_time_unix_nano = timestamp(); + } + + void clear() + { + trace_id.clear(); // 1 + span_id.clear(); // 2 + trace_state.clear(); // 3 + parent_span_id.clear(); // 4 + name.clear(); // 5 + kind = SpanKind::SPAN_KIND_UNSPECIFIED; // 6 + start_time_unix_nano = 0; // 7 + end_time_unix_nano = 0; // 8 + attributes.clear(); // 9 + dropped_attributes_count = 0; // 10 + events.clear(); // 11 + dropped_events_count = 0; // 12 + links.clear(); // 13 + dropped_links_count = 0; //14 + status.clear(); // 15 + flags = 0; // 16 + } + void encode(protozero::pbf_writer& writer) const; + static Span decode(protozero::pbf_reader& reader); +}; + +// SpanFlags represents constants used to interpret the +// Span.flags field, which is protobuf 'fixed32' type and is to +// be used as bit-fields. Each non-zero value defined in this enum is +// a bit-mask. To extract the bit-field, for example, use an +// expression like: +// +// (span.flags & SPAN_FLAGS_TRACE_FLAGS_MASK) +// +// See https://www.w3.org/TR/trace-context-2/#trace-flags for the flag definitions. +// +// Note that Span flags were introduced in version 1.1 of the +// OpenTelemetry protocol. Older Span producers do not set this +// field, consequently consumers should not rely on the absence of a +// particular flag bit to indicate the presence of a particular feature. +enum class SpanFlags : uint16_t +{ + // The zero value for the enum. Should not be used for comparisons. + // Instead use bitwise "and" with the appropriate mask as shown above. + SPAN_FLAGS_DO_NOT_USE = 0, + // Bits 0-7 are used for trace flags. + SPAN_FLAGS_TRACE_FLAGS_MASK = 0x000000FF, + // Bits 8 and 9 are used to indicate that the parent span or link span is remote. + // Bit 8 (`HAS_IS_REMOTE`) indicates whether the value is known. + // Bit 9 (`IS_REMOTE`) indicates whether the span or link is remote. + SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK = 0x00000100, + SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK = 0x00000200, + // Bits 10-31 are reserved for future use. +}; + +// A collection of Spans produced by an InstrumentationScope. +struct ScopeSpans +{ + // The instrumentation scope information for the spans in this message. + // Semantically when InstrumentationScope isn't set, it is equivalent with + // an empty instrumentation scope name (unknown). + InstrumentationScope scope{}; // = 1 + // A list of Spans that originate from an instrumentation scope. + std::vector spans{}; // = 2 + // The Schema URL, if known. This is the identifier of the Schema that the span data + // is recorded in. Notably, the last part of the URL path is the version number of the + // schema: http[s]://server[:port]/path/. To learn more about Schema URL see + // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url + // This schema_url applies to all spans and span events in the "spans" field. + std::string schema_url{}; // = 3 + + void close() + { + for (auto& element : spans) { + element.close(); + } + } + void encode(protozero::pbf_writer& writer) const; + static ScopeSpans decode(protozero::pbf_reader& reader); +}; + +// A collection of ScopeSpans from a Resource. +struct ResourceSpans +{ + // The resource for the spans in this message. + // If this field is not set then no resource info is known. + Resource resource; // = 1 + // A list of ScopeSpans that originate from a resource. + std::vector scope_spans; // = 2 + // The Schema URL, if known. This is the identifier of the Schema that the resource data + // is recorded in. Notably, the last part of the URL path is the version number of the + // schema: http[s]://server[:port]/path/. To learn more about Schema URL see + // https://opentelemetry.io/docs/specs/otel/schemas/#schema-url + // This schema_url applies to the data in the "resource" field. It does not apply + // to the data in the "scope_spans" field which have their own schema_url field. + std::string schema_url{}; // = 3 + + void close() + { + for (auto& element : scope_spans) { + element.close(); + } + } + void encode(protozero::pbf_writer& writer) const; + static ResourceSpans decode(protozero::pbf_reader& reader); +}; + +// TracesData represents the traces data that can be stored in a persistent storage, +// OR can be embedded by other protocols that transfer OTLP traces data but do +// not implement the OTLP protocol. +// +// The main difference between this message and collector protocol is that +// in this message there will not be any "control" or "metadata" specific to +// OTLP protocol. +// +// When new fields are added into this message, the OTLP request MUST be updated +// as well. +struct TracesData +{ + // An array of ResourceSpans. + // For data coming from a single resource this array will typically contain + // one element. Intermediary nodes that receive data from multiple origins + // typically batch the data before forwarding further and in that case this + // array will contain multiple elements. + std::vector resource_spans; // = 1 + + void close() + { + for (auto& element : resource_spans) { + element.close(); + } + } + void encode(protozero::pbf_writer& writer) const; + static TracesData decode(protozero::pbf_reader& reader); + + [[nodiscard]] std::string encode() const + { + std::string data; + protozero::pbf_writer writer{data}; + encode(writer); + return data; + } + + static TracesData boilerPlate(std::string&& service, std::vector&& spans, const std::vector& attributes, const std::string& serverID) + { + auto& spanAttrs = spans.at(0).attributes; + spanAttrs.insert(spanAttrs.end(), attributes.begin(), attributes.end()); + InstrumentationScope scope{ + .name = "rec", .version = VERSION}; + return TracesData{ + .resource_spans = {pdns::trace::ResourceSpans{ + .resource = { + .attributes = { + {"service.name", {{std::move(service)}}}, + {"instance", {serverID}}}}, + .scope_spans = {{.scope = std::move(scope), .spans = std::move(spans)}}}}}; + } +}; + +inline ArrayValue ArrayValue::decode(protozero::pbf_reader& reader) +{ + return pdns::trace::decode(reader); +} + +inline KeyValueList KeyValueList::decode(protozero::pbf_reader& reader) +{ + return pdns::trace::decode(reader); +} + +struct EDNSOTTraceRecord +{ + // 1 byte version, 1 byte reserved, 16 bytes traceid, 8 bytes spanid, 1 byte flags + static constexpr size_t fullSize = 1 + 1 + 16 + 8 + 1; + static constexpr size_t traceIDOffset = 1 + 1; + static constexpr size_t spanIDOffset = traceIDOffset + 16; + static constexpr size_t flagsOffset = spanIDOffset + 8; + + EDNSOTTraceRecord(uint8_t* arg) : + data(arg) {} + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + void setVersion(uint8_t version) + { + data[0] = version; + } + void setReserved(uint8_t reserved) + { + data[1] = reserved; + } + void setTraceID(const TraceID& traceid) + { + std::copy(traceid.begin(), traceid.end(), &data[traceIDOffset]); + } + void setSpanID(const SpanID& spanid) + { + std::copy(spanid.begin(), spanid.end(), &data[spanIDOffset]); + } + void setFlags(const uint8_t flags) + { + data[flagsOffset] = flags; + } + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) +private: + uint8_t* data; +}; + +struct EDNSOTTraceRecordView +{ + EDNSOTTraceRecordView(const uint8_t* arg, size_t argsize) : + data(arg), size(argsize) {} + + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + [[nodiscard]] bool getVersion(uint8_t& version) const + { + if (size > 0) { + version = data[0]; + return true; + } + return false; + } + [[nodiscard]] bool getReserved(uint8_t& reserved) const + { + if (size > 1) { + reserved = data[1]; + return true; + } + return false; + } + [[nodiscard]] bool getTraceID(TraceID& traceid) const + { + if (size == pdns::trace::EDNSOTTraceRecord::fullSize) { + std::copy(&data[EDNSOTTraceRecord::traceIDOffset], &data[EDNSOTTraceRecord::traceIDOffset + traceid.size()], traceid.begin()); + return true; + } + return false; + } + [[nodiscard]] bool getSpanID(SpanID& spanid) const + { + if (size == pdns::trace::EDNSOTTraceRecord::fullSize) { + std::string x((char*)&data[EDNSOTTraceRecord::spanIDOffset], spanid.size()); + std::copy(&data[EDNSOTTraceRecord::spanIDOffset], &data[EDNSOTTraceRecord::spanIDOffset + spanid.size()], spanid.begin()); + return true; + } + return false; + } + [[nodiscard]] bool getFlags(uint8_t& flags) const + { + if (size == pdns::trace::EDNSOTTraceRecord::fullSize) { + flags = data[EDNSOTTraceRecord::flagsOffset]; + return true; + } + return false; + } + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) +private: + const uint8_t* const data; + const size_t size; +}; + +bool extractOTraceIDs(const EDNSOptionViewMap& map, EDNSOptionCode::EDNSOptionCodeEnum eoc, pdns::trace::InitialSpanInfo& span); +bool extractOTraceIDs(const EDNSOptionViewMap& map, EDNSOptionCode::EDNSOptionCodeEnum eoc, pdns::trace::TraceID& traceID, pdns::trace::SpanID& spanID); + +inline bool ArrayValue::operator==(const ArrayValue& rhs) const +{ + return values == rhs.values; +} + +inline bool KeyValueList::operator==(const KeyValueList& rhs) const +{ + return values == rhs.values; +} + +inline bool KeyValue::operator==(const KeyValue& rhs) const +{ + return key == rhs.key && value == rhs.value; +} + +} // namespace pdns::trace diff -Nru pdns-recursor-5.2.13/protozero.hh pdns-recursor-5.4.9/protozero.hh --- pdns-recursor-5.2.13/protozero.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/protozero.hh 2026-10-26 09:46:36.000000000 +0000 @@ -103,6 +103,10 @@ outgoingQueries = 27, headerFlags = 28, ednsVersion = 29, + openTelemetryData = 30, + ede = 31, + edeText = 32, + openTelemetryTraceID = 33, }; enum class QuestionField : protozero::pbf_tag_type { @@ -314,6 +318,30 @@ add_uint32(d_message, Field::ednsVersion, version); } + void setOpenTelemetryData(const std::string& data) + { + if (!data.empty()) { + add_string(d_message, Field::openTelemetryData, data); + } + } + + void setEDE(const uint16_t ede) + { + add_uint32(d_message, Field::ede, ede); + } + + void setEDEText(const std::string edeText) + { + if (!edeText.empty()) { + add_string(d_message, Field::edeText, edeText); + } + } + + void setOpenTelemetryTraceID(const std::array& traceID) + { + add_bytes(d_message, Field::openTelemetryTraceID, reinterpret_cast(traceID.data()), traceID.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API + } + void startResponse() { d_response = protozero::pbf_writer{d_message, static_cast(Field::response)}; diff -Nru pdns-recursor-5.2.13/pubsuffix.cc pdns-recursor-5.4.9/pubsuffix.cc --- pdns-recursor-5.2.13/pubsuffix.cc 2026-08-05 12:02:34.000000000 +0000 +++ pdns-recursor-5.4.9/pubsuffix.cc 2026-10-26 09:47:09.000000000 +0000 @@ -1,8212 +1,8341 @@ -const char* g_pubsuffix[]={ -"com.ac", -"edu.ac", -"gov.ac", -"mil.ac", -"net.ac", -"org.ac", -"ac.ae", -"co.ae", -"gov.ae", -"mil.ae", -"net.ae", -"org.ae", -"sch.ae", -"airline.aero", -"airport.aero", -"accident-investigation.aero", -"accident-prevention.aero", -"aerobatic.aero", -"aeroclub.aero", -"aerodrome.aero", -"agents.aero", -"air-surveillance.aero", -"air-traffic-control.aero", -"aircraft.aero", -"airtraffic.aero", -"ambulance.aero", -"association.aero", -"author.aero", -"ballooning.aero", -"broker.aero", -"caa.aero", -"cargo.aero", -"catering.aero", -"certification.aero", -"championship.aero", -"charter.aero", -"civilaviation.aero", -"club.aero", -"conference.aero", -"consultant.aero", -"consulting.aero", -"control.aero", -"council.aero", -"crew.aero", -"design.aero", -"dgca.aero", -"educator.aero", -"emergency.aero", -"engine.aero", -"engineer.aero", -"entertainment.aero", -"equipment.aero", -"exchange.aero", -"express.aero", -"federation.aero", -"flight.aero", -"freight.aero", -"fuel.aero", -"gliding.aero", -"government.aero", -"groundhandling.aero", -"group.aero", -"hanggliding.aero", -"homebuilt.aero", -"insurance.aero", -"journal.aero", -"journalist.aero", -"leasing.aero", -"logistics.aero", -"magazine.aero", -"maintenance.aero", -"marketplace.aero", -"media.aero", -"microlight.aero", -"modelling.aero", -"navigation.aero", -"parachuting.aero", -"paragliding.aero", -"passenger-association.aero", -"pilot.aero", -"press.aero", -"production.aero", -"recreation.aero", -"repbody.aero", -"res.aero", -"research.aero", -"rotorcraft.aero", -"safety.aero", -"scientist.aero", -"services.aero", -"show.aero", -"skydiving.aero", -"software.aero", -"student.aero", -"taxi.aero", -"trader.aero", -"trading.aero", -"trainer.aero", -"union.aero", -"workinggroup.aero", -"works.aero", -"com.af", -"edu.af", -"gov.af", -"net.af", -"org.af", -"co.ag", -"com.ag", -"net.ag", -"nom.ag", -"org.ag", -"com.ai", -"net.ai", -"off.ai", -"org.ai", -"com.al", -"edu.al", -"gov.al", -"mil.al", -"net.al", -"org.al", -"co.am", -"com.am", -"commune.am", -"net.am", -"org.am", -"co.ao", -"ed.ao", -"edu.ao", -"gov.ao", -"gv.ao", -"it.ao", -"og.ao", -"org.ao", -"pb.ao", -"bet.ar", -"com.ar", -"coop.ar", -"edu.ar", -"gob.ar", -"gov.ar", -"int.ar", -"mil.ar", -"musica.ar", -"mutual.ar", -"net.ar", -"org.ar", -"seg.ar", -"senasa.ar", -"tur.ar", -"e164.arpa", -"home.arpa", -"in-addr.arpa", -"ip6.arpa", -"iris.arpa", -"uri.arpa", -"urn.arpa", -"gov.as", -"ac.at", -"sth.ac.at", -"co.at", -"gv.at", -"or.at", -"asn.au", -"com.au", -"edu.au", -"gov.au", -"id.au", -"net.au", -"org.au", -"conf.au", -"oz.au", -"act.au", -"nsw.au", -"nt.au", -"qld.au", -"sa.au", -"tas.au", -"vic.au", -"wa.au", -"act.edu.au", -"catholic.edu.au", -"nsw.edu.au", -"nt.edu.au", -"qld.edu.au", -"sa.edu.au", -"tas.edu.au", -"vic.edu.au", -"wa.edu.au", -"qld.gov.au", -"sa.gov.au", -"tas.gov.au", -"vic.gov.au", -"wa.gov.au", -"com.aw", -"biz.az", -"co.az", -"com.az", -"edu.az", -"gov.az", -"info.az", -"int.az", -"mil.az", -"name.az", -"net.az", -"org.az", -"pp.az", -"pro.az", -"com.ba", -"edu.ba", -"gov.ba", -"mil.ba", -"net.ba", -"org.ba", -"biz.bb", -"co.bb", -"com.bb", -"edu.bb", -"gov.bb", -"info.bb", -"net.bb", -"org.bb", -"store.bb", -"tv.bb", -"ac.bd", -"ai.bd", -"co.bd", -"com.bd", -"edu.bd", -"gov.bd", -"id.bd", -"info.bd", -"it.bd", -"mil.bd", -"net.bd", -"org.bd", -"sch.bd", -"tv.bd", -"ac.be", -"gov.bf", -"0.bg", -"1.bg", -"2.bg", -"3.bg", -"4.bg", -"5.bg", -"6.bg", -"7.bg", -"8.bg", -"9.bg", -"a.bg", -"b.bg", -"c.bg", -"d.bg", -"e.bg", -"f.bg", -"g.bg", -"h.bg", -"i.bg", -"j.bg", -"k.bg", -"l.bg", -"m.bg", -"n.bg", -"o.bg", -"p.bg", -"q.bg", -"r.bg", -"s.bg", -"t.bg", -"u.bg", -"v.bg", -"w.bg", -"x.bg", -"y.bg", -"z.bg", -"com.bh", -"edu.bh", -"gov.bh", -"net.bh", -"org.bh", -"co.bi", -"com.bi", -"edu.bi", -"or.bi", -"org.bi", -"africa.bj", -"agro.bj", -"architectes.bj", -"assur.bj", -"avocats.bj", -"co.bj", -"com.bj", -"eco.bj", -"econo.bj", -"edu.bj", -"info.bj", -"loisirs.bj", -"money.bj", -"net.bj", -"org.bj", -"ote.bj", -"restaurant.bj", -"resto.bj", -"tourism.bj", -"univ.bj", -"com.bm", -"edu.bm", -"gov.bm", -"net.bm", -"org.bm", -"com.bn", -"edu.bn", -"gov.bn", -"net.bn", -"org.bn", -"com.bo", -"edu.bo", -"gob.bo", -"int.bo", -"mil.bo", -"net.bo", -"org.bo", -"tv.bo", -"web.bo", -"academia.bo", -"agro.bo", -"arte.bo", -"blog.bo", -"bolivia.bo", -"ciencia.bo", -"cooperativa.bo", -"democracia.bo", -"deporte.bo", -"ecologia.bo", -"economia.bo", -"empresa.bo", -"indigena.bo", -"industria.bo", -"info.bo", -"medicina.bo", -"movimiento.bo", -"musica.bo", -"natural.bo", -"nombre.bo", -"noticias.bo", -"patria.bo", -"plurinacional.bo", -"politica.bo", -"profesional.bo", -"pueblo.bo", -"revista.bo", -"salud.bo", -"tecnologia.bo", -"tksat.bo", -"transporte.bo", -"wiki.bo", -"9guacu.br", -"abc.br", -"adm.br", -"adv.br", -"agr.br", -"aju.br", -"am.br", -"anani.br", -"aparecida.br", -"api.br", -"app.br", -"arq.br", -"art.br", -"ato.br", -"b.br", -"barueri.br", -"belem.br", -"bet.br", -"bhz.br", -"bib.br", -"bio.br", -"blog.br", -"bmd.br", -"boavista.br", -"bsb.br", -"campinagrande.br", -"campinas.br", -"caxias.br", -"cim.br", -"cng.br", -"cnt.br", -"com.br", -"contagem.br", -"coop.br", -"coz.br", -"cri.br", -"cuiaba.br", -"curitiba.br", -"def.br", -"des.br", -"det.br", -"dev.br", -"ecn.br", -"eco.br", -"edu.br", -"emp.br", -"enf.br", -"eng.br", -"esp.br", -"etc.br", -"eti.br", -"far.br", -"feira.br", -"flog.br", -"floripa.br", -"fm.br", -"fnd.br", -"fortal.br", -"fot.br", -"foz.br", -"fst.br", -"g12.br", -"geo.br", -"ggf.br", -"goiania.br", -"gov.br", -"ac.gov.br", -"al.gov.br", -"am.gov.br", -"ap.gov.br", -"ba.gov.br", -"ce.gov.br", -"df.gov.br", -"es.gov.br", -"go.gov.br", -"ma.gov.br", -"mg.gov.br", -"ms.gov.br", -"mt.gov.br", -"pa.gov.br", -"pb.gov.br", -"pe.gov.br", -"pi.gov.br", -"pr.gov.br", -"rj.gov.br", -"rn.gov.br", -"ro.gov.br", -"rr.gov.br", -"rs.gov.br", -"sc.gov.br", -"se.gov.br", -"sp.gov.br", -"to.gov.br", -"gru.br", -"ia.br", -"imb.br", -"ind.br", -"inf.br", -"jab.br", -"jampa.br", -"jdf.br", -"joinville.br", -"jor.br", -"jus.br", -"leg.br", -"leilao.br", -"lel.br", -"log.br", -"londrina.br", -"macapa.br", -"maceio.br", -"manaus.br", -"maringa.br", -"mat.br", -"med.br", -"mil.br", -"morena.br", -"mp.br", -"mus.br", -"natal.br", -"net.br", -"niteroi.br", -"not.br", -"ntr.br", -"odo.br", -"ong.br", -"org.br", -"osasco.br", -"palmas.br", -"poa.br", -"ppg.br", -"pro.br", -"psc.br", -"psi.br", -"pvh.br", -"qsl.br", -"radio.br", -"rec.br", -"recife.br", -"rep.br", -"ribeirao.br", -"rio.br", -"riobranco.br", -"riopreto.br", -"salvador.br", -"sampa.br", -"santamaria.br", -"santoandre.br", -"saobernardo.br", -"saogonca.br", -"seg.br", -"sjc.br", -"slg.br", -"slz.br", -"social.br", -"sorocaba.br", -"srv.br", -"taxi.br", -"tc.br", -"tec.br", -"teo.br", -"the.br", -"tmp.br", -"trd.br", -"tur.br", -"tv.br", -"udi.br", -"vet.br", -"vix.br", -"vlog.br", -"wiki.br", -"xyz.br", -"zlg.br", -"com.bs", -"edu.bs", -"gov.bs", -"net.bs", -"org.bs", -"com.bt", -"edu.bt", -"gov.bt", -"net.bt", -"org.bt", -"ac.bw", -"co.bw", -"gov.bw", -"net.bw", -"org.bw", -"gov.by", -"mil.by", -"com.by", -"of.by", -"co.bz", -"com.bz", -"edu.bz", -"gov.bz", -"net.bz", -"org.bz", -"ab.ca", -"bc.ca", -"mb.ca", -"nb.ca", -"nf.ca", -"nl.ca", -"ns.ca", -"nt.ca", -"nu.ca", -"on.ca", -"pe.ca", -"qc.ca", -"sk.ca", -"yk.ca", -"gc.ca", -"gov.cd", -"ac.ci", -"asso.ci", -"co.ci", -"com.ci", -"ed.ci", -"edu.ci", -"go.ci", -"gouv.ci", -"int.ci", -"net.ci", -"or.ci", -"org.ci", -"co.cl", -"gob.cl", -"gov.cl", -"mil.cl", -"co.cm", -"com.cm", -"gov.cm", -"net.cm", -"ac.cn", -"com.cn", -"edu.cn", -"gov.cn", -"mil.cn", -"net.cn", -"org.cn", -"ah.cn", -"bj.cn", -"cq.cn", -"fj.cn", -"gd.cn", -"gs.cn", -"gx.cn", -"gz.cn", -"ha.cn", -"hb.cn", -"he.cn", -"hi.cn", -"hk.cn", -"hl.cn", -"hn.cn", -"jl.cn", -"js.cn", -"jx.cn", -"ln.cn", -"mo.cn", -"nm.cn", -"nx.cn", -"qh.cn", -"sc.cn", -"sd.cn", -"sh.cn", -"sn.cn", -"sx.cn", -"tj.cn", -"tw.cn", -"xj.cn", -"xz.cn", -"yn.cn", -"zj.cn", -"com.co", -"edu.co", -"gov.co", -"mil.co", -"net.co", -"nom.co", -"org.co", -"ac.cr", -"co.cr", -"ed.cr", -"fi.cr", -"go.cr", -"or.cr", -"sa.cr", -"com.cu", -"edu.cu", -"gob.cu", -"inf.cu", -"nat.cu", -"net.cu", -"org.cu", -"com.cv", -"edu.cv", -"id.cv", -"int.cv", -"net.cv", -"nome.cv", -"org.cv", -"publ.cv", -"com.cw", -"edu.cw", -"net.cw", -"org.cw", -"gov.cx", -"ac.cy", -"biz.cy", -"com.cy", -"ekloges.cy", -"gov.cy", -"ltd.cy", -"mil.cy", -"net.cy", -"org.cy", -"press.cy", -"pro.cy", -"tm.cy", -"gov.cz", -"co.dm", -"com.dm", -"edu.dm", -"gov.dm", -"net.dm", -"org.dm", -"art.do", -"com.do", -"edu.do", -"gob.do", -"gov.do", -"mil.do", -"net.do", -"org.do", -"sld.do", -"web.do", -"art.dz", -"asso.dz", -"com.dz", -"edu.dz", -"gov.dz", -"net.dz", -"org.dz", -"pol.dz", -"soc.dz", -"tm.dz", -"abg.ec", -"adm.ec", -"agron.ec", -"arqt.ec", -"art.ec", -"bar.ec", -"chef.ec", -"com.ec", -"cont.ec", -"cpa.ec", -"cue.ec", -"dent.ec", -"dgn.ec", -"disco.ec", -"doc.ec", -"edu.ec", -"eng.ec", -"esm.ec", -"fin.ec", -"fot.ec", -"gal.ec", -"gob.ec", -"gov.ec", -"gye.ec", -"ibr.ec", -"info.ec", -"k12.ec", -"lat.ec", -"loj.ec", -"med.ec", -"mil.ec", -"mktg.ec", -"mon.ec", -"net.ec", -"ntr.ec", -"odont.ec", -"org.ec", -"pro.ec", -"prof.ec", -"psic.ec", -"psiq.ec", -"pub.ec", -"rio.ec", -"rrpp.ec", -"sal.ec", -"tech.ec", -"tul.ec", -"tur.ec", -"uio.ec", -"vet.ec", -"xxx.ec", -"aip.ee", -"com.ee", -"edu.ee", -"fie.ee", -"gov.ee", -"lib.ee", -"med.ee", -"org.ee", -"pri.ee", -"riik.ee", -"ac.eg", -"com.eg", -"edu.eg", -"eun.eg", -"gov.eg", -"info.eg", -"me.eg", -"mil.eg", -"name.eg", -"net.eg", -"org.eg", -"sci.eg", -"sport.eg", -"tv.eg", -"com.es", -"edu.es", -"gob.es", -"nom.es", -"org.es", -"biz.et", -"com.et", -"edu.et", -"gov.et", -"info.et", -"name.et", -"net.et", -"org.et", -"aland.fi", -"ac.fj", -"biz.fj", -"com.fj", -"edu.fj", -"gov.fj", -"id.fj", -"info.fj", -"mil.fj", -"name.fj", -"net.fj", -"org.fj", -"pro.fj", -"com.fm", -"edu.fm", -"net.fm", -"org.fm", -"asso.fr", -"com.fr", -"gouv.fr", -"nom.fr", -"prd.fr", -"tm.fr", -"avoues.fr", -"cci.fr", -"greta.fr", -"huissier-justice.fr", -"edu.gd", -"gov.gd", -"com.ge", -"cyb.ge", -"edu.ge", -"gov.ge", -"llc.ge", -"net.ge", -"online.ge", -"org.ge", -"pvt.ge", -"school.ge", -"tnx.ge", -"co.gg", -"net.gg", -"org.gg", -"biz.gh", -"com.gh", -"edu.gh", -"gov.gh", -"mil.gh", -"net.gh", -"org.gh", -"com.gi", -"edu.gi", -"gov.gi", -"ltd.gi", -"mod.gi", -"org.gi", -"co.gl", -"com.gl", -"edu.gl", -"net.gl", -"org.gl", -"ac.gn", -"com.gn", -"edu.gn", -"gov.gn", -"net.gn", -"org.gn", -"asso.gp", -"com.gp", -"edu.gp", -"mobi.gp", -"net.gp", -"org.gp", -"com.gr", -"edu.gr", -"gov.gr", -"net.gr", -"org.gr", -"com.gt", -"edu.gt", -"gob.gt", -"ind.gt", -"mil.gt", -"net.gt", -"org.gt", -"com.gu", -"edu.gu", -"gov.gu", -"guam.gu", -"info.gu", -"net.gu", -"org.gu", -"web.gu", -"co.gy", -"com.gy", -"edu.gy", -"gov.gy", -"net.gy", -"org.gy", -"com.hk", -"edu.hk", -"gov.hk", -"idv.hk", -"net.hk", -"org.hk", -"com.hn", -"edu.hn", -"gob.hn", -"mil.hn", -"net.hn", -"org.hn", -"com.hr", -"from.hr", -"iz.hr", -"name.hr", -"adult.ht", -"art.ht", -"asso.ht", -"com.ht", -"coop.ht", -"edu.ht", -"firm.ht", -"gouv.ht", -"info.ht", -"med.ht", -"net.ht", -"org.ht", -"perso.ht", -"pol.ht", -"pro.ht", -"rel.ht", -"shop.ht", -"2000.hu", -"agrar.hu", -"bolt.hu", -"casino.hu", -"city.hu", -"co.hu", -"erotica.hu", -"erotika.hu", -"film.hu", -"forum.hu", -"games.hu", -"hotel.hu", -"info.hu", -"ingatlan.hu", -"jogasz.hu", -"konyvelo.hu", -"lakas.hu", -"media.hu", -"news.hu", -"org.hu", -"priv.hu", -"reklam.hu", -"sex.hu", -"shop.hu", -"sport.hu", -"suli.hu", -"szex.hu", -"tm.hu", -"tozsde.hu", -"utazas.hu", -"video.hu", -"ac.id", -"ai.id", -"biz.id", -"co.id", -"desa.id", -"go.id", -"kop.id", -"mil.id", -"my.id", -"net.id", -"or.id", -"ponpes.id", -"sch.id", -"web.id", -"gov.ie", -"ac.il", -"co.il", -"gov.il", -"idf.il", -"k12.il", -"muni.il", -"net.il", -"org.il", -"ac.im", -"co.im", -"ltd.co.im", -"plc.co.im", -"com.im", -"net.im", -"org.im", -"tt.im", -"tv.im", -"5g.in", -"6g.in", -"ac.in", -"aero.in", -"ai.in", -"alumni.in", -"am.in", -"bank.in", -"bihar.in", -"biz.in", -"business.in", -"ca.in", -"cn.in", -"co.in", -"com.in", -"coop.in", -"cs.in", -"delhi.in", -"dr.in", -"edu.in", -"er.in", -"fin.in", -"firm.in", -"gen.in", -"gov.in", -"gujarat.in", -"ind.in", -"info.in", -"int.in", -"internet.in", -"io.in", -"me.in", -"mil.in", -"net.in", -"nic.in", -"org.in", -"pg.in", -"post.in", -"pro.in", -"res.in", -"school.in", -"travel.in", -"tv.in", -"ub.in", -"uk.in", -"up.in", -"us.in", -"eu.int", -"co.io", -"com.io", -"edu.io", -"gov.io", -"mil.io", -"net.io", -"nom.io", -"org.io", -"com.iq", -"edu.iq", -"gov.iq", -"mil.iq", -"net.iq", -"org.iq", -"ac.ir", -"co.ir", -"gov.ir", -"id.ir", -"net.ir", -"org.ir", -"sch.ir", -"edu.it", -"gov.it", -"abr.it", -"abruzzo.it", -"aosta-valley.it", -"aostavalley.it", -"bas.it", -"basilicata.it", -"cal.it", -"calabria.it", -"cam.it", -"campania.it", -"emilia-romagna.it", -"emiliaromagna.it", -"emr.it", -"friuli-v-giulia.it", -"friuli-ve-giulia.it", -"friuli-vegiulia.it", -"friuli-venezia-giulia.it", -"friuli-veneziagiulia.it", -"friuli-vgiulia.it", -"friuliv-giulia.it", -"friulive-giulia.it", -"friulivegiulia.it", -"friulivenezia-giulia.it", -"friuliveneziagiulia.it", -"friulivgiulia.it", -"fvg.it", -"laz.it", -"lazio.it", -"lig.it", -"liguria.it", -"lom.it", -"lombardia.it", -"lombardy.it", -"lucania.it", -"mar.it", -"marche.it", -"mol.it", -"molise.it", -"piedmont.it", -"piemonte.it", -"pmn.it", -"pug.it", -"puglia.it", -"sar.it", -"sardegna.it", -"sardinia.it", -"sic.it", -"sicilia.it", -"sicily.it", -"taa.it", -"tos.it", -"toscana.it", -"trentin-sud-tirol.it", -"trentin-sudtirol.it", -"trentin-sued-tirol.it", -"trentin-suedtirol.it", -"trentino-a-adige.it", -"trentino-aadige.it", -"trentino-alto-adige.it", -"trentino-altoadige.it", -"trentino-s-tirol.it", -"trentino-stirol.it", -"trentino-sud-tirol.it", -"trentino-sudtirol.it", -"trentino-sued-tirol.it", -"trentino-suedtirol.it", -"trentinoa-adige.it", -"trentinoaadige.it", -"trentinoalto-adige.it", -"trentinoaltoadige.it", -"trentinos-tirol.it", -"trentinostirol.it", -"trentinosud-tirol.it", -"trentinosued-tirol.it", -"trentinosuedtirol.it", -"trentinsud-tirol.it", -"trentinsudtirol.it", -"trentinsued-tirol.it", -"trentinsuedtirol.it", -"tuscany.it", -"umb.it", -"umbria.it", -"val-d-aosta.it", -"val-daosta.it", -"vald-aosta.it", -"valle-aosta.it", -"valle-d-aosta.it", -"valle-daosta.it", -"valleaosta.it", -"valled-aosta.it", -"valledaosta.it", -"vallee-aoste.it", -"vallee-d-aoste.it", -"valleeaoste.it", -"valleedaoste.it", -"vao.it", -"vda.it", -"ven.it", -"veneto.it", -"ag.it", -"agrigento.it", -"al.it", -"alessandria.it", -"alto-adige.it", -"altoadige.it", -"an.it", -"ancona.it", -"andria-barletta-trani.it", -"andria-trani-barletta.it", -"andriabarlettatrani.it", -"andriatranibarletta.it", -"ao.it", -"aosta.it", -"aoste.it", -"ap.it", -"aq.it", -"ar.it", -"arezzo.it", -"ascoli-piceno.it", -"ascolipiceno.it", -"asti.it", -"at.it", -"av.it", -"avellino.it", -"ba.it", -"balsan.it", -"balsan-sudtirol.it", -"balsan-suedtirol.it", -"bari.it", -"barletta-trani-andria.it", -"barlettatraniandria.it", -"belluno.it", -"benevento.it", -"bergamo.it", -"bg.it", -"bi.it", -"biella.it", -"bl.it", -"bn.it", -"bo.it", -"bologna.it", -"bolzano.it", -"bolzano-altoadige.it", -"bozen.it", -"bozen-sudtirol.it", -"bozen-suedtirol.it", -"br.it", -"brescia.it", -"brindisi.it", -"bs.it", -"bt.it", -"bulsan.it", -"bulsan-sudtirol.it", -"bulsan-suedtirol.it", -"bz.it", -"ca.it", -"cagliari.it", -"caltanissetta.it", -"campidano-medio.it", -"campidanomedio.it", -"campobasso.it", -"carbonia-iglesias.it", -"carboniaiglesias.it", -"carrara-massa.it", -"carraramassa.it", -"caserta.it", -"catania.it", -"catanzaro.it", -"cb.it", -"ce.it", -"cesena-forli.it", -"cesenaforli.it", -"ch.it", -"chieti.it", -"ci.it", -"cl.it", -"cn.it", -"co.it", -"como.it", -"cosenza.it", -"cr.it", -"cremona.it", -"crotone.it", -"cs.it", -"ct.it", -"cuneo.it", -"cz.it", -"dell-ogliastra.it", -"dellogliastra.it", -"en.it", -"enna.it", -"fc.it", -"fe.it", -"fermo.it", -"ferrara.it", -"fg.it", -"fi.it", -"firenze.it", -"florence.it", -"fm.it", -"foggia.it", -"forli-cesena.it", -"forlicesena.it", -"fr.it", -"frosinone.it", -"ge.it", -"genoa.it", -"genova.it", -"go.it", -"gorizia.it", -"gr.it", -"grosseto.it", -"iglesias-carbonia.it", -"iglesiascarbonia.it", -"im.it", -"imperia.it", -"is.it", -"isernia.it", -"kr.it", -"la-spezia.it", -"laquila.it", -"laspezia.it", -"latina.it", -"lc.it", -"le.it", -"lecce.it", -"lecco.it", -"li.it", -"livorno.it", -"lo.it", -"lodi.it", -"lt.it", -"lu.it", -"lucca.it", -"macerata.it", -"mantova.it", -"massa-carrara.it", -"massacarrara.it", -"matera.it", -"mb.it", -"mc.it", -"me.it", -"medio-campidano.it", -"mediocampidano.it", -"messina.it", -"mi.it", -"milan.it", -"milano.it", -"mn.it", -"mo.it", -"modena.it", -"monza.it", -"monza-brianza.it", -"monza-e-della-brianza.it", -"monzabrianza.it", -"monzaebrianza.it", -"monzaedellabrianza.it", -"ms.it", -"mt.it", -"na.it", -"naples.it", -"napoli.it", -"no.it", -"novara.it", -"nu.it", -"nuoro.it", -"og.it", -"ogliastra.it", -"olbia-tempio.it", -"olbiatempio.it", -"or.it", -"oristano.it", -"ot.it", -"pa.it", -"padova.it", -"padua.it", -"palermo.it", -"parma.it", -"pavia.it", -"pc.it", -"pd.it", -"pe.it", -"perugia.it", -"pesaro-urbino.it", -"pesarourbino.it", -"pescara.it", -"pg.it", -"pi.it", -"piacenza.it", -"pisa.it", -"pistoia.it", -"pn.it", -"po.it", -"pordenone.it", -"potenza.it", -"pr.it", -"prato.it", -"pt.it", -"pu.it", -"pv.it", -"pz.it", -"ra.it", -"ragusa.it", -"ravenna.it", -"rc.it", -"re.it", -"reggio-calabria.it", -"reggio-emilia.it", -"reggiocalabria.it", -"reggioemilia.it", -"rg.it", -"ri.it", -"rieti.it", -"rimini.it", -"rm.it", -"rn.it", -"ro.it", -"roma.it", -"rome.it", -"rovigo.it", -"sa.it", -"salerno.it", -"sassari.it", -"savona.it", -"si.it", -"siena.it", -"siracusa.it", -"so.it", -"sondrio.it", -"sp.it", -"sr.it", -"ss.it", -"su.it", -"sud-sardegna.it", -"sudsardegna.it", -"suedtirol.it", -"sv.it", -"ta.it", -"taranto.it", -"te.it", -"tempio-olbia.it", -"tempioolbia.it", -"teramo.it", -"terni.it", -"tn.it", -"to.it", -"torino.it", -"tp.it", -"tr.it", -"trani-andria-barletta.it", -"trani-barletta-andria.it", -"traniandriabarletta.it", -"tranibarlettaandria.it", -"trapani.it", -"trentino.it", -"trento.it", -"treviso.it", -"trieste.it", -"ts.it", -"turin.it", -"tv.it", -"ud.it", -"udine.it", -"urbino-pesaro.it", -"urbinopesaro.it", -"va.it", -"varese.it", -"vb.it", -"vc.it", -"ve.it", -"venezia.it", -"venice.it", -"verbania.it", -"verbano-cusio-ossola.it", -"vercelli.it", -"verona.it", -"vi.it", -"vibo-valentia.it", -"vibovalentia.it", -"vicenza.it", -"viterbo.it", -"vr.it", -"vs.it", -"vt.it", -"vv.it", -"co.je", -"net.je", -"org.je", -"agri.jo", -"ai.jo", -"com.jo", -"edu.jo", -"eng.jo", -"fm.jo", -"gov.jo", -"mil.jo", -"net.jo", -"org.jo", -"per.jo", -"phd.jo", -"sch.jo", -"tv.jo", -"ac.jp", -"ad.jp", -"co.jp", -"ed.jp", -"go.jp", -"gr.jp", -"lg.jp", -"ne.jp", -"or.jp", -"aichi.jp", -"akita.jp", -"aomori.jp", -"chiba.jp", -"ehime.jp", -"fukui.jp", -"fukuoka.jp", -"fukushima.jp", -"gifu.jp", -"gunma.jp", -"hiroshima.jp", -"hokkaido.jp", -"hyogo.jp", -"ibaraki.jp", -"ishikawa.jp", -"iwate.jp", -"kagawa.jp", -"kagoshima.jp", -"kanagawa.jp", -"kochi.jp", -"kumamoto.jp", -"kyoto.jp", -"mie.jp", -"miyagi.jp", -"miyazaki.jp", -"nagano.jp", -"nagasaki.jp", -"nara.jp", -"niigata.jp", -"oita.jp", -"okayama.jp", -"okinawa.jp", -"osaka.jp", -"saga.jp", -"saitama.jp", -"shiga.jp", -"shimane.jp", -"shizuoka.jp", -"tochigi.jp", -"tokushima.jp", -"tokyo.jp", -"tottori.jp", -"toyama.jp", -"wakayama.jp", -"yamagata.jp", -"yamaguchi.jp", -"yamanashi.jp", -"aisai.aichi.jp", -"ama.aichi.jp", -"anjo.aichi.jp", -"asuke.aichi.jp", -"chiryu.aichi.jp", -"chita.aichi.jp", -"fuso.aichi.jp", -"gamagori.aichi.jp", -"handa.aichi.jp", -"hazu.aichi.jp", -"hekinan.aichi.jp", -"higashiura.aichi.jp", -"ichinomiya.aichi.jp", -"inazawa.aichi.jp", -"inuyama.aichi.jp", -"isshiki.aichi.jp", -"iwakura.aichi.jp", -"kanie.aichi.jp", -"kariya.aichi.jp", -"kasugai.aichi.jp", -"kira.aichi.jp", -"kiyosu.aichi.jp", -"komaki.aichi.jp", -"konan.aichi.jp", -"kota.aichi.jp", -"mihama.aichi.jp", -"miyoshi.aichi.jp", -"nishio.aichi.jp", -"nisshin.aichi.jp", -"obu.aichi.jp", -"oguchi.aichi.jp", -"oharu.aichi.jp", -"okazaki.aichi.jp", -"owariasahi.aichi.jp", -"seto.aichi.jp", -"shikatsu.aichi.jp", -"shinshiro.aichi.jp", -"shitara.aichi.jp", -"tahara.aichi.jp", -"takahama.aichi.jp", -"tobishima.aichi.jp", -"toei.aichi.jp", -"togo.aichi.jp", -"tokai.aichi.jp", -"tokoname.aichi.jp", -"toyoake.aichi.jp", -"toyohashi.aichi.jp", -"toyokawa.aichi.jp", -"toyone.aichi.jp", -"toyota.aichi.jp", -"tsushima.aichi.jp", -"yatomi.aichi.jp", -"akita.akita.jp", -"daisen.akita.jp", -"fujisato.akita.jp", -"gojome.akita.jp", -"hachirogata.akita.jp", -"happou.akita.jp", -"higashinaruse.akita.jp", -"honjo.akita.jp", -"honjyo.akita.jp", -"ikawa.akita.jp", -"kamikoani.akita.jp", -"kamioka.akita.jp", -"katagami.akita.jp", -"kazuno.akita.jp", -"kitaakita.akita.jp", -"kosaka.akita.jp", -"kyowa.akita.jp", -"misato.akita.jp", -"mitane.akita.jp", -"moriyoshi.akita.jp", -"nikaho.akita.jp", -"noshiro.akita.jp", -"odate.akita.jp", -"oga.akita.jp", -"ogata.akita.jp", -"semboku.akita.jp", -"yokote.akita.jp", -"yurihonjo.akita.jp", -"aomori.aomori.jp", -"gonohe.aomori.jp", -"hachinohe.aomori.jp", -"hashikami.aomori.jp", -"hiranai.aomori.jp", -"hirosaki.aomori.jp", -"itayanagi.aomori.jp", -"kuroishi.aomori.jp", -"misawa.aomori.jp", -"mutsu.aomori.jp", -"nakadomari.aomori.jp", -"noheji.aomori.jp", -"oirase.aomori.jp", -"owani.aomori.jp", -"rokunohe.aomori.jp", -"sannohe.aomori.jp", -"shichinohe.aomori.jp", -"shingo.aomori.jp", -"takko.aomori.jp", -"towada.aomori.jp", -"tsugaru.aomori.jp", -"tsuruta.aomori.jp", -"abiko.chiba.jp", -"asahi.chiba.jp", -"chonan.chiba.jp", -"chosei.chiba.jp", -"choshi.chiba.jp", -"chuo.chiba.jp", -"funabashi.chiba.jp", -"futtsu.chiba.jp", -"hanamigawa.chiba.jp", -"ichihara.chiba.jp", -"ichikawa.chiba.jp", -"ichinomiya.chiba.jp", -"inzai.chiba.jp", -"isumi.chiba.jp", -"kamagaya.chiba.jp", -"kamogawa.chiba.jp", -"kashiwa.chiba.jp", -"katori.chiba.jp", -"katsuura.chiba.jp", -"kimitsu.chiba.jp", -"kisarazu.chiba.jp", -"kozaki.chiba.jp", -"kujukuri.chiba.jp", -"kyonan.chiba.jp", -"matsudo.chiba.jp", -"midori.chiba.jp", -"mihama.chiba.jp", -"minamiboso.chiba.jp", -"mobara.chiba.jp", -"mutsuzawa.chiba.jp", -"nagara.chiba.jp", -"nagareyama.chiba.jp", -"narashino.chiba.jp", -"narita.chiba.jp", -"noda.chiba.jp", -"oamishirasato.chiba.jp", -"omigawa.chiba.jp", -"onjuku.chiba.jp", -"otaki.chiba.jp", -"sakae.chiba.jp", -"sakura.chiba.jp", -"shimofusa.chiba.jp", -"shirako.chiba.jp", -"shiroi.chiba.jp", -"shisui.chiba.jp", -"sodegaura.chiba.jp", -"sosa.chiba.jp", -"tako.chiba.jp", -"tateyama.chiba.jp", -"togane.chiba.jp", -"tohnosho.chiba.jp", -"tomisato.chiba.jp", -"urayasu.chiba.jp", -"yachimata.chiba.jp", -"yachiyo.chiba.jp", -"yokaichiba.chiba.jp", -"yokoshibahikari.chiba.jp", -"yotsukaido.chiba.jp", -"ainan.ehime.jp", -"honai.ehime.jp", -"ikata.ehime.jp", -"imabari.ehime.jp", -"iyo.ehime.jp", -"kamijima.ehime.jp", -"kihoku.ehime.jp", -"kumakogen.ehime.jp", -"masaki.ehime.jp", -"matsuno.ehime.jp", -"matsuyama.ehime.jp", -"namikata.ehime.jp", -"niihama.ehime.jp", -"ozu.ehime.jp", -"saijo.ehime.jp", -"seiyo.ehime.jp", -"shikokuchuo.ehime.jp", -"tobe.ehime.jp", -"toon.ehime.jp", -"uchiko.ehime.jp", -"uwajima.ehime.jp", -"yawatahama.ehime.jp", -"echizen.fukui.jp", -"eiheiji.fukui.jp", -"fukui.fukui.jp", -"ikeda.fukui.jp", -"katsuyama.fukui.jp", -"mihama.fukui.jp", -"minamiechizen.fukui.jp", -"obama.fukui.jp", -"ohi.fukui.jp", -"ono.fukui.jp", -"sabae.fukui.jp", -"sakai.fukui.jp", -"takahama.fukui.jp", -"tsuruga.fukui.jp", -"wakasa.fukui.jp", -"ashiya.fukuoka.jp", -"buzen.fukuoka.jp", -"chikugo.fukuoka.jp", -"chikuho.fukuoka.jp", -"chikujo.fukuoka.jp", -"chikushino.fukuoka.jp", -"chikuzen.fukuoka.jp", -"chuo.fukuoka.jp", -"dazaifu.fukuoka.jp", -"fukuchi.fukuoka.jp", -"hakata.fukuoka.jp", -"higashi.fukuoka.jp", -"hirokawa.fukuoka.jp", -"hisayama.fukuoka.jp", -"iizuka.fukuoka.jp", -"inatsuki.fukuoka.jp", -"kaho.fukuoka.jp", -"kasuga.fukuoka.jp", -"kasuya.fukuoka.jp", -"kawara.fukuoka.jp", -"keisen.fukuoka.jp", -"koga.fukuoka.jp", -"kurate.fukuoka.jp", -"kurogi.fukuoka.jp", -"kurume.fukuoka.jp", -"minami.fukuoka.jp", -"miyako.fukuoka.jp", -"miyama.fukuoka.jp", -"miyawaka.fukuoka.jp", -"mizumaki.fukuoka.jp", -"munakata.fukuoka.jp", -"nakagawa.fukuoka.jp", -"nakama.fukuoka.jp", -"nishi.fukuoka.jp", -"nogata.fukuoka.jp", -"ogori.fukuoka.jp", -"okagaki.fukuoka.jp", -"okawa.fukuoka.jp", -"oki.fukuoka.jp", -"omuta.fukuoka.jp", -"onga.fukuoka.jp", -"onojo.fukuoka.jp", -"oto.fukuoka.jp", -"saigawa.fukuoka.jp", -"sasaguri.fukuoka.jp", -"shingu.fukuoka.jp", -"shinyoshitomi.fukuoka.jp", -"shonai.fukuoka.jp", -"soeda.fukuoka.jp", -"sue.fukuoka.jp", -"tachiarai.fukuoka.jp", -"tagawa.fukuoka.jp", -"takata.fukuoka.jp", -"toho.fukuoka.jp", -"toyotsu.fukuoka.jp", -"tsuiki.fukuoka.jp", -"ukiha.fukuoka.jp", -"umi.fukuoka.jp", -"usui.fukuoka.jp", -"yamada.fukuoka.jp", -"yame.fukuoka.jp", -"yanagawa.fukuoka.jp", -"yukuhashi.fukuoka.jp", -"aizubange.fukushima.jp", -"aizumisato.fukushima.jp", -"aizuwakamatsu.fukushima.jp", -"asakawa.fukushima.jp", -"bandai.fukushima.jp", -"date.fukushima.jp", -"fukushima.fukushima.jp", -"furudono.fukushima.jp", -"futaba.fukushima.jp", -"hanawa.fukushima.jp", -"higashi.fukushima.jp", -"hirata.fukushima.jp", -"hirono.fukushima.jp", -"iitate.fukushima.jp", -"inawashiro.fukushima.jp", -"ishikawa.fukushima.jp", -"iwaki.fukushima.jp", -"izumizaki.fukushima.jp", -"kagamiishi.fukushima.jp", -"kaneyama.fukushima.jp", -"kawamata.fukushima.jp", -"kitakata.fukushima.jp", -"kitashiobara.fukushima.jp", -"koori.fukushima.jp", -"koriyama.fukushima.jp", -"kunimi.fukushima.jp", -"miharu.fukushima.jp", -"mishima.fukushima.jp", -"namie.fukushima.jp", -"nango.fukushima.jp", -"nishiaizu.fukushima.jp", -"nishigo.fukushima.jp", -"okuma.fukushima.jp", -"omotego.fukushima.jp", -"ono.fukushima.jp", -"otama.fukushima.jp", -"samegawa.fukushima.jp", -"shimogo.fukushima.jp", -"shirakawa.fukushima.jp", -"showa.fukushima.jp", -"soma.fukushima.jp", -"sukagawa.fukushima.jp", -"taishin.fukushima.jp", -"tamakawa.fukushima.jp", -"tanagura.fukushima.jp", -"tenei.fukushima.jp", -"yabuki.fukushima.jp", -"yamato.fukushima.jp", -"yamatsuri.fukushima.jp", -"yanaizu.fukushima.jp", -"yugawa.fukushima.jp", -"anpachi.gifu.jp", -"ena.gifu.jp", -"gifu.gifu.jp", -"ginan.gifu.jp", -"godo.gifu.jp", -"gujo.gifu.jp", -"hashima.gifu.jp", -"hichiso.gifu.jp", -"hida.gifu.jp", -"higashishirakawa.gifu.jp", -"ibigawa.gifu.jp", -"ikeda.gifu.jp", -"kakamigahara.gifu.jp", -"kani.gifu.jp", -"kasahara.gifu.jp", -"kasamatsu.gifu.jp", -"kawaue.gifu.jp", -"kitagata.gifu.jp", -"mino.gifu.jp", -"minokamo.gifu.jp", -"mitake.gifu.jp", -"mizunami.gifu.jp", -"motosu.gifu.jp", -"nakatsugawa.gifu.jp", -"ogaki.gifu.jp", -"sakahogi.gifu.jp", -"seki.gifu.jp", -"sekigahara.gifu.jp", -"shirakawa.gifu.jp", -"tajimi.gifu.jp", -"takayama.gifu.jp", -"tarui.gifu.jp", -"toki.gifu.jp", -"tomika.gifu.jp", -"wanouchi.gifu.jp", -"yamagata.gifu.jp", -"yaotsu.gifu.jp", -"yoro.gifu.jp", -"annaka.gunma.jp", -"chiyoda.gunma.jp", -"fujioka.gunma.jp", -"higashiagatsuma.gunma.jp", -"isesaki.gunma.jp", -"itakura.gunma.jp", -"kanna.gunma.jp", -"kanra.gunma.jp", -"katashina.gunma.jp", -"kawaba.gunma.jp", -"kiryu.gunma.jp", -"kusatsu.gunma.jp", -"maebashi.gunma.jp", -"meiwa.gunma.jp", -"midori.gunma.jp", -"minakami.gunma.jp", -"naganohara.gunma.jp", -"nakanojo.gunma.jp", -"nanmoku.gunma.jp", -"numata.gunma.jp", -"oizumi.gunma.jp", -"ora.gunma.jp", -"ota.gunma.jp", -"shibukawa.gunma.jp", -"shimonita.gunma.jp", -"shinto.gunma.jp", -"showa.gunma.jp", -"takasaki.gunma.jp", -"takayama.gunma.jp", -"tamamura.gunma.jp", -"tatebayashi.gunma.jp", -"tomioka.gunma.jp", -"tsukiyono.gunma.jp", -"tsumagoi.gunma.jp", -"ueno.gunma.jp", -"yoshioka.gunma.jp", -"asaminami.hiroshima.jp", -"daiwa.hiroshima.jp", -"etajima.hiroshima.jp", -"fuchu.hiroshima.jp", -"fukuyama.hiroshima.jp", -"hatsukaichi.hiroshima.jp", -"higashihiroshima.hiroshima.jp", -"hongo.hiroshima.jp", -"jinsekikogen.hiroshima.jp", -"kaita.hiroshima.jp", -"kui.hiroshima.jp", -"kumano.hiroshima.jp", -"kure.hiroshima.jp", -"mihara.hiroshima.jp", -"miyoshi.hiroshima.jp", -"naka.hiroshima.jp", -"onomichi.hiroshima.jp", -"osakikamijima.hiroshima.jp", -"otake.hiroshima.jp", -"saka.hiroshima.jp", -"sera.hiroshima.jp", -"seranishi.hiroshima.jp", -"shinichi.hiroshima.jp", -"shobara.hiroshima.jp", -"takehara.hiroshima.jp", -"abashiri.hokkaido.jp", -"abira.hokkaido.jp", -"aibetsu.hokkaido.jp", -"akabira.hokkaido.jp", -"akkeshi.hokkaido.jp", -"asahikawa.hokkaido.jp", -"ashibetsu.hokkaido.jp", -"ashoro.hokkaido.jp", -"assabu.hokkaido.jp", -"atsuma.hokkaido.jp", -"bibai.hokkaido.jp", -"biei.hokkaido.jp", -"bifuka.hokkaido.jp", -"bihoro.hokkaido.jp", -"biratori.hokkaido.jp", -"chippubetsu.hokkaido.jp", -"chitose.hokkaido.jp", -"date.hokkaido.jp", -"ebetsu.hokkaido.jp", -"embetsu.hokkaido.jp", -"eniwa.hokkaido.jp", -"erimo.hokkaido.jp", -"esan.hokkaido.jp", -"esashi.hokkaido.jp", -"fukagawa.hokkaido.jp", -"fukushima.hokkaido.jp", -"furano.hokkaido.jp", -"furubira.hokkaido.jp", -"haboro.hokkaido.jp", -"hakodate.hokkaido.jp", -"hamatonbetsu.hokkaido.jp", -"hidaka.hokkaido.jp", -"higashikagura.hokkaido.jp", -"higashikawa.hokkaido.jp", -"hiroo.hokkaido.jp", -"hokuryu.hokkaido.jp", -"hokuto.hokkaido.jp", -"honbetsu.hokkaido.jp", -"horokanai.hokkaido.jp", -"horonobe.hokkaido.jp", -"ikeda.hokkaido.jp", -"imakane.hokkaido.jp", -"ishikari.hokkaido.jp", -"iwamizawa.hokkaido.jp", -"iwanai.hokkaido.jp", -"kamifurano.hokkaido.jp", -"kamikawa.hokkaido.jp", -"kamishihoro.hokkaido.jp", -"kamisunagawa.hokkaido.jp", -"kamoenai.hokkaido.jp", -"kayabe.hokkaido.jp", -"kembuchi.hokkaido.jp", -"kikonai.hokkaido.jp", -"kimobetsu.hokkaido.jp", -"kitahiroshima.hokkaido.jp", -"kitami.hokkaido.jp", -"kiyosato.hokkaido.jp", -"koshimizu.hokkaido.jp", -"kunneppu.hokkaido.jp", -"kuriyama.hokkaido.jp", -"kuromatsunai.hokkaido.jp", -"kushiro.hokkaido.jp", -"kutchan.hokkaido.jp", -"kyowa.hokkaido.jp", -"mashike.hokkaido.jp", -"matsumae.hokkaido.jp", -"mikasa.hokkaido.jp", -"minamifurano.hokkaido.jp", -"mombetsu.hokkaido.jp", -"moseushi.hokkaido.jp", -"mukawa.hokkaido.jp", -"muroran.hokkaido.jp", -"naie.hokkaido.jp", -"nakagawa.hokkaido.jp", -"nakasatsunai.hokkaido.jp", -"nakatombetsu.hokkaido.jp", -"nanae.hokkaido.jp", -"nanporo.hokkaido.jp", -"nayoro.hokkaido.jp", -"nemuro.hokkaido.jp", -"niikappu.hokkaido.jp", -"niki.hokkaido.jp", -"nishiokoppe.hokkaido.jp", -"noboribetsu.hokkaido.jp", -"numata.hokkaido.jp", -"obihiro.hokkaido.jp", -"obira.hokkaido.jp", -"oketo.hokkaido.jp", -"okoppe.hokkaido.jp", -"otaru.hokkaido.jp", -"otobe.hokkaido.jp", -"otofuke.hokkaido.jp", -"otoineppu.hokkaido.jp", -"oumu.hokkaido.jp", -"ozora.hokkaido.jp", -"pippu.hokkaido.jp", -"rankoshi.hokkaido.jp", -"rebun.hokkaido.jp", -"rikubetsu.hokkaido.jp", -"rishiri.hokkaido.jp", -"rishirifuji.hokkaido.jp", -"saroma.hokkaido.jp", -"sarufutsu.hokkaido.jp", -"shakotan.hokkaido.jp", -"shari.hokkaido.jp", -"shibecha.hokkaido.jp", -"shibetsu.hokkaido.jp", -"shikabe.hokkaido.jp", -"shikaoi.hokkaido.jp", -"shimamaki.hokkaido.jp", -"shimizu.hokkaido.jp", -"shimokawa.hokkaido.jp", -"shinshinotsu.hokkaido.jp", -"shintoku.hokkaido.jp", -"shiranuka.hokkaido.jp", -"shiraoi.hokkaido.jp", -"shiriuchi.hokkaido.jp", -"sobetsu.hokkaido.jp", -"sunagawa.hokkaido.jp", -"taiki.hokkaido.jp", -"takasu.hokkaido.jp", -"takikawa.hokkaido.jp", -"takinoue.hokkaido.jp", -"teshikaga.hokkaido.jp", -"tobetsu.hokkaido.jp", -"tohma.hokkaido.jp", -"tomakomai.hokkaido.jp", -"tomari.hokkaido.jp", -"toya.hokkaido.jp", -"toyako.hokkaido.jp", -"toyotomi.hokkaido.jp", -"toyoura.hokkaido.jp", -"tsubetsu.hokkaido.jp", -"tsukigata.hokkaido.jp", -"urakawa.hokkaido.jp", -"urausu.hokkaido.jp", -"uryu.hokkaido.jp", -"utashinai.hokkaido.jp", -"wakkanai.hokkaido.jp", -"wassamu.hokkaido.jp", -"yakumo.hokkaido.jp", -"yoichi.hokkaido.jp", -"aioi.hyogo.jp", -"akashi.hyogo.jp", -"ako.hyogo.jp", -"amagasaki.hyogo.jp", -"aogaki.hyogo.jp", -"asago.hyogo.jp", -"ashiya.hyogo.jp", -"awaji.hyogo.jp", -"fukusaki.hyogo.jp", -"goshiki.hyogo.jp", -"harima.hyogo.jp", -"himeji.hyogo.jp", -"ichikawa.hyogo.jp", -"inagawa.hyogo.jp", -"itami.hyogo.jp", -"kakogawa.hyogo.jp", -"kamigori.hyogo.jp", -"kamikawa.hyogo.jp", -"kasai.hyogo.jp", -"kasuga.hyogo.jp", -"kawanishi.hyogo.jp", -"miki.hyogo.jp", -"minamiawaji.hyogo.jp", -"nishinomiya.hyogo.jp", -"nishiwaki.hyogo.jp", -"ono.hyogo.jp", -"sanda.hyogo.jp", -"sannan.hyogo.jp", -"sasayama.hyogo.jp", -"sayo.hyogo.jp", -"shingu.hyogo.jp", -"shinonsen.hyogo.jp", -"shiso.hyogo.jp", -"sumoto.hyogo.jp", -"taishi.hyogo.jp", -"taka.hyogo.jp", -"takarazuka.hyogo.jp", -"takasago.hyogo.jp", -"takino.hyogo.jp", -"tamba.hyogo.jp", -"tatsuno.hyogo.jp", -"toyooka.hyogo.jp", -"yabu.hyogo.jp", -"yashiro.hyogo.jp", -"yoka.hyogo.jp", -"yokawa.hyogo.jp", -"ami.ibaraki.jp", -"asahi.ibaraki.jp", -"bando.ibaraki.jp", -"chikusei.ibaraki.jp", -"daigo.ibaraki.jp", -"fujishiro.ibaraki.jp", -"hitachi.ibaraki.jp", -"hitachinaka.ibaraki.jp", -"hitachiomiya.ibaraki.jp", -"hitachiota.ibaraki.jp", -"ibaraki.ibaraki.jp", -"ina.ibaraki.jp", -"inashiki.ibaraki.jp", -"itako.ibaraki.jp", -"iwama.ibaraki.jp", -"joso.ibaraki.jp", -"kamisu.ibaraki.jp", -"kasama.ibaraki.jp", -"kashima.ibaraki.jp", -"kasumigaura.ibaraki.jp", -"koga.ibaraki.jp", -"miho.ibaraki.jp", -"mito.ibaraki.jp", -"moriya.ibaraki.jp", -"naka.ibaraki.jp", -"namegata.ibaraki.jp", -"oarai.ibaraki.jp", -"ogawa.ibaraki.jp", -"omitama.ibaraki.jp", -"ryugasaki.ibaraki.jp", -"sakai.ibaraki.jp", -"sakuragawa.ibaraki.jp", -"shimodate.ibaraki.jp", -"shimotsuma.ibaraki.jp", -"shirosato.ibaraki.jp", -"sowa.ibaraki.jp", -"suifu.ibaraki.jp", -"takahagi.ibaraki.jp", -"tamatsukuri.ibaraki.jp", -"tokai.ibaraki.jp", -"tomobe.ibaraki.jp", -"tone.ibaraki.jp", -"toride.ibaraki.jp", -"tsuchiura.ibaraki.jp", -"tsukuba.ibaraki.jp", -"uchihara.ibaraki.jp", -"ushiku.ibaraki.jp", -"yachiyo.ibaraki.jp", -"yamagata.ibaraki.jp", -"yawara.ibaraki.jp", -"yuki.ibaraki.jp", -"anamizu.ishikawa.jp", -"hakui.ishikawa.jp", -"hakusan.ishikawa.jp", -"kaga.ishikawa.jp", -"kahoku.ishikawa.jp", -"kanazawa.ishikawa.jp", -"kawakita.ishikawa.jp", -"komatsu.ishikawa.jp", -"nakanoto.ishikawa.jp", -"nanao.ishikawa.jp", -"nomi.ishikawa.jp", -"nonoichi.ishikawa.jp", -"noto.ishikawa.jp", -"shika.ishikawa.jp", -"suzu.ishikawa.jp", -"tsubata.ishikawa.jp", -"tsurugi.ishikawa.jp", -"uchinada.ishikawa.jp", -"wajima.ishikawa.jp", -"fudai.iwate.jp", -"fujisawa.iwate.jp", -"hanamaki.iwate.jp", -"hiraizumi.iwate.jp", -"hirono.iwate.jp", -"ichinohe.iwate.jp", -"ichinoseki.iwate.jp", -"iwaizumi.iwate.jp", -"iwate.iwate.jp", -"joboji.iwate.jp", -"kamaishi.iwate.jp", -"kanegasaki.iwate.jp", -"karumai.iwate.jp", -"kawai.iwate.jp", -"kitakami.iwate.jp", -"kuji.iwate.jp", -"kunohe.iwate.jp", -"kuzumaki.iwate.jp", -"miyako.iwate.jp", -"mizusawa.iwate.jp", -"morioka.iwate.jp", -"ninohe.iwate.jp", -"noda.iwate.jp", -"ofunato.iwate.jp", -"oshu.iwate.jp", -"otsuchi.iwate.jp", -"rikuzentakata.iwate.jp", -"shiwa.iwate.jp", -"shizukuishi.iwate.jp", -"sumita.iwate.jp", -"tanohata.iwate.jp", -"tono.iwate.jp", -"yahaba.iwate.jp", -"yamada.iwate.jp", -"ayagawa.kagawa.jp", -"higashikagawa.kagawa.jp", -"kanonji.kagawa.jp", -"kotohira.kagawa.jp", -"manno.kagawa.jp", -"marugame.kagawa.jp", -"mitoyo.kagawa.jp", -"naoshima.kagawa.jp", -"sanuki.kagawa.jp", -"tadotsu.kagawa.jp", -"takamatsu.kagawa.jp", -"tonosho.kagawa.jp", -"uchinomi.kagawa.jp", -"utazu.kagawa.jp", -"zentsuji.kagawa.jp", -"akune.kagoshima.jp", -"amami.kagoshima.jp", -"hioki.kagoshima.jp", -"isa.kagoshima.jp", -"isen.kagoshima.jp", -"izumi.kagoshima.jp", -"kagoshima.kagoshima.jp", -"kanoya.kagoshima.jp", -"kawanabe.kagoshima.jp", -"kinko.kagoshima.jp", -"kouyama.kagoshima.jp", -"makurazaki.kagoshima.jp", -"matsumoto.kagoshima.jp", -"minamitane.kagoshima.jp", -"nakatane.kagoshima.jp", -"nishinoomote.kagoshima.jp", -"satsumasendai.kagoshima.jp", -"soo.kagoshima.jp", -"tarumizu.kagoshima.jp", -"yusui.kagoshima.jp", -"aikawa.kanagawa.jp", -"atsugi.kanagawa.jp", -"ayase.kanagawa.jp", -"chigasaki.kanagawa.jp", -"ebina.kanagawa.jp", -"fujisawa.kanagawa.jp", -"hadano.kanagawa.jp", -"hakone.kanagawa.jp", -"hiratsuka.kanagawa.jp", -"isehara.kanagawa.jp", -"kaisei.kanagawa.jp", -"kamakura.kanagawa.jp", -"kiyokawa.kanagawa.jp", -"matsuda.kanagawa.jp", -"minamiashigara.kanagawa.jp", -"miura.kanagawa.jp", -"nakai.kanagawa.jp", -"ninomiya.kanagawa.jp", -"odawara.kanagawa.jp", -"oi.kanagawa.jp", -"oiso.kanagawa.jp", -"sagamihara.kanagawa.jp", -"samukawa.kanagawa.jp", -"tsukui.kanagawa.jp", -"yamakita.kanagawa.jp", -"yamato.kanagawa.jp", -"yokosuka.kanagawa.jp", -"yugawara.kanagawa.jp", -"zama.kanagawa.jp", -"zushi.kanagawa.jp", -"aki.kochi.jp", -"geisei.kochi.jp", -"hidaka.kochi.jp", -"higashitsuno.kochi.jp", -"ino.kochi.jp", -"kagami.kochi.jp", -"kami.kochi.jp", -"kitagawa.kochi.jp", -"kochi.kochi.jp", -"mihara.kochi.jp", -"motoyama.kochi.jp", -"muroto.kochi.jp", -"nahari.kochi.jp", -"nakamura.kochi.jp", -"nankoku.kochi.jp", -"nishitosa.kochi.jp", -"niyodogawa.kochi.jp", -"ochi.kochi.jp", -"okawa.kochi.jp", -"otoyo.kochi.jp", -"otsuki.kochi.jp", -"sakawa.kochi.jp", -"sukumo.kochi.jp", -"susaki.kochi.jp", -"tosa.kochi.jp", -"tosashimizu.kochi.jp", -"toyo.kochi.jp", -"tsuno.kochi.jp", -"umaji.kochi.jp", -"yasuda.kochi.jp", -"yusuhara.kochi.jp", -"amakusa.kumamoto.jp", -"arao.kumamoto.jp", -"aso.kumamoto.jp", -"choyo.kumamoto.jp", -"gyokuto.kumamoto.jp", -"kamiamakusa.kumamoto.jp", -"kikuchi.kumamoto.jp", -"kumamoto.kumamoto.jp", -"mashiki.kumamoto.jp", -"mifune.kumamoto.jp", -"minamata.kumamoto.jp", -"minamioguni.kumamoto.jp", -"nagasu.kumamoto.jp", -"nishihara.kumamoto.jp", -"oguni.kumamoto.jp", -"ozu.kumamoto.jp", -"sumoto.kumamoto.jp", -"takamori.kumamoto.jp", -"uki.kumamoto.jp", -"uto.kumamoto.jp", -"yamaga.kumamoto.jp", -"yamato.kumamoto.jp", -"yatsushiro.kumamoto.jp", -"ayabe.kyoto.jp", -"fukuchiyama.kyoto.jp", -"higashiyama.kyoto.jp", -"ide.kyoto.jp", -"ine.kyoto.jp", -"joyo.kyoto.jp", -"kameoka.kyoto.jp", -"kamo.kyoto.jp", -"kita.kyoto.jp", -"kizu.kyoto.jp", -"kumiyama.kyoto.jp", -"kyotamba.kyoto.jp", -"kyotanabe.kyoto.jp", -"kyotango.kyoto.jp", -"maizuru.kyoto.jp", -"minami.kyoto.jp", -"minamiyamashiro.kyoto.jp", -"miyazu.kyoto.jp", -"muko.kyoto.jp", -"nagaokakyo.kyoto.jp", -"nakagyo.kyoto.jp", -"nantan.kyoto.jp", -"oyamazaki.kyoto.jp", -"sakyo.kyoto.jp", -"seika.kyoto.jp", -"tanabe.kyoto.jp", -"uji.kyoto.jp", -"ujitawara.kyoto.jp", -"wazuka.kyoto.jp", -"yamashina.kyoto.jp", -"yawata.kyoto.jp", -"asahi.mie.jp", -"inabe.mie.jp", -"ise.mie.jp", -"kameyama.mie.jp", -"kawagoe.mie.jp", -"kiho.mie.jp", -"kisosaki.mie.jp", -"kiwa.mie.jp", -"komono.mie.jp", -"kumano.mie.jp", -"kuwana.mie.jp", -"matsusaka.mie.jp", -"meiwa.mie.jp", -"mihama.mie.jp", -"minamiise.mie.jp", -"misugi.mie.jp", -"miyama.mie.jp", -"nabari.mie.jp", -"shima.mie.jp", -"suzuka.mie.jp", -"tado.mie.jp", -"taiki.mie.jp", -"taki.mie.jp", -"tamaki.mie.jp", -"toba.mie.jp", -"tsu.mie.jp", -"udono.mie.jp", -"ureshino.mie.jp", -"watarai.mie.jp", -"yokkaichi.mie.jp", -"furukawa.miyagi.jp", -"higashimatsushima.miyagi.jp", -"ishinomaki.miyagi.jp", -"iwanuma.miyagi.jp", -"kakuda.miyagi.jp", -"kami.miyagi.jp", -"kawasaki.miyagi.jp", -"marumori.miyagi.jp", -"matsushima.miyagi.jp", -"minamisanriku.miyagi.jp", -"misato.miyagi.jp", -"murata.miyagi.jp", -"natori.miyagi.jp", -"ogawara.miyagi.jp", -"ohira.miyagi.jp", -"onagawa.miyagi.jp", -"osaki.miyagi.jp", -"rifu.miyagi.jp", -"semine.miyagi.jp", -"shibata.miyagi.jp", -"shichikashuku.miyagi.jp", -"shikama.miyagi.jp", -"shiogama.miyagi.jp", -"shiroishi.miyagi.jp", -"tagajo.miyagi.jp", -"taiwa.miyagi.jp", -"tome.miyagi.jp", -"tomiya.miyagi.jp", -"wakuya.miyagi.jp", -"watari.miyagi.jp", -"yamamoto.miyagi.jp", -"zao.miyagi.jp", -"aya.miyazaki.jp", -"ebino.miyazaki.jp", -"gokase.miyazaki.jp", -"hyuga.miyazaki.jp", -"kadogawa.miyazaki.jp", -"kawaminami.miyazaki.jp", -"kijo.miyazaki.jp", -"kitagawa.miyazaki.jp", -"kitakata.miyazaki.jp", -"kitaura.miyazaki.jp", -"kobayashi.miyazaki.jp", -"kunitomi.miyazaki.jp", -"kushima.miyazaki.jp", -"mimata.miyazaki.jp", -"miyakonojo.miyazaki.jp", -"miyazaki.miyazaki.jp", -"morotsuka.miyazaki.jp", -"nichinan.miyazaki.jp", -"nishimera.miyazaki.jp", -"nobeoka.miyazaki.jp", -"saito.miyazaki.jp", -"shiiba.miyazaki.jp", -"shintomi.miyazaki.jp", -"takaharu.miyazaki.jp", -"takanabe.miyazaki.jp", -"takazaki.miyazaki.jp", -"tsuno.miyazaki.jp", -"achi.nagano.jp", -"agematsu.nagano.jp", -"anan.nagano.jp", -"aoki.nagano.jp", -"asahi.nagano.jp", -"azumino.nagano.jp", -"chikuhoku.nagano.jp", -"chikuma.nagano.jp", -"chino.nagano.jp", -"fujimi.nagano.jp", -"hakuba.nagano.jp", -"hara.nagano.jp", -"hiraya.nagano.jp", -"iida.nagano.jp", -"iijima.nagano.jp", -"iiyama.nagano.jp", -"iizuna.nagano.jp", -"ikeda.nagano.jp", -"ikusaka.nagano.jp", -"ina.nagano.jp", -"karuizawa.nagano.jp", -"kawakami.nagano.jp", -"kiso.nagano.jp", -"kisofukushima.nagano.jp", -"kitaaiki.nagano.jp", -"komagane.nagano.jp", -"komoro.nagano.jp", -"matsukawa.nagano.jp", -"matsumoto.nagano.jp", -"miasa.nagano.jp", -"minamiaiki.nagano.jp", -"minamimaki.nagano.jp", -"minamiminowa.nagano.jp", -"minowa.nagano.jp", -"miyada.nagano.jp", -"miyota.nagano.jp", -"mochizuki.nagano.jp", -"nagano.nagano.jp", -"nagawa.nagano.jp", -"nagiso.nagano.jp", -"nakagawa.nagano.jp", -"nakano.nagano.jp", -"nozawaonsen.nagano.jp", -"obuse.nagano.jp", -"ogawa.nagano.jp", -"okaya.nagano.jp", -"omachi.nagano.jp", -"omi.nagano.jp", -"ookuwa.nagano.jp", -"ooshika.nagano.jp", -"otaki.nagano.jp", -"otari.nagano.jp", -"sakae.nagano.jp", -"sakaki.nagano.jp", -"saku.nagano.jp", -"sakuho.nagano.jp", -"shimosuwa.nagano.jp", -"shinanomachi.nagano.jp", -"shiojiri.nagano.jp", -"suwa.nagano.jp", -"suzaka.nagano.jp", -"takagi.nagano.jp", -"takamori.nagano.jp", -"takayama.nagano.jp", -"tateshina.nagano.jp", -"tatsuno.nagano.jp", -"togakushi.nagano.jp", -"togura.nagano.jp", -"tomi.nagano.jp", -"ueda.nagano.jp", -"wada.nagano.jp", -"yamagata.nagano.jp", -"yamanouchi.nagano.jp", -"yasaka.nagano.jp", -"yasuoka.nagano.jp", -"chijiwa.nagasaki.jp", -"futsu.nagasaki.jp", -"goto.nagasaki.jp", -"hasami.nagasaki.jp", -"hirado.nagasaki.jp", -"iki.nagasaki.jp", -"isahaya.nagasaki.jp", -"kawatana.nagasaki.jp", -"kuchinotsu.nagasaki.jp", -"matsuura.nagasaki.jp", -"nagasaki.nagasaki.jp", -"obama.nagasaki.jp", -"omura.nagasaki.jp", -"oseto.nagasaki.jp", -"saikai.nagasaki.jp", -"sasebo.nagasaki.jp", -"seihi.nagasaki.jp", -"shimabara.nagasaki.jp", -"shinkamigoto.nagasaki.jp", -"togitsu.nagasaki.jp", -"tsushima.nagasaki.jp", -"unzen.nagasaki.jp", -"ando.nara.jp", -"gose.nara.jp", -"heguri.nara.jp", -"higashiyoshino.nara.jp", -"ikaruga.nara.jp", -"ikoma.nara.jp", -"kamikitayama.nara.jp", -"kanmaki.nara.jp", -"kashiba.nara.jp", -"kashihara.nara.jp", -"katsuragi.nara.jp", -"kawai.nara.jp", -"kawakami.nara.jp", -"kawanishi.nara.jp", -"koryo.nara.jp", -"kurotaki.nara.jp", -"mitsue.nara.jp", -"miyake.nara.jp", -"nara.nara.jp", -"nosegawa.nara.jp", -"oji.nara.jp", -"ouda.nara.jp", -"oyodo.nara.jp", -"sakurai.nara.jp", -"sango.nara.jp", -"shimoichi.nara.jp", -"shimokitayama.nara.jp", -"shinjo.nara.jp", -"soni.nara.jp", -"takatori.nara.jp", -"tawaramoto.nara.jp", -"tenkawa.nara.jp", -"tenri.nara.jp", -"uda.nara.jp", -"yamatokoriyama.nara.jp", -"yamatotakada.nara.jp", -"yamazoe.nara.jp", -"yoshino.nara.jp", -"aga.niigata.jp", -"agano.niigata.jp", -"gosen.niigata.jp", -"itoigawa.niigata.jp", -"izumozaki.niigata.jp", -"joetsu.niigata.jp", -"kamo.niigata.jp", -"kariwa.niigata.jp", -"kashiwazaki.niigata.jp", -"minamiuonuma.niigata.jp", -"mitsuke.niigata.jp", -"muika.niigata.jp", -"murakami.niigata.jp", -"myoko.niigata.jp", -"nagaoka.niigata.jp", -"niigata.niigata.jp", -"ojiya.niigata.jp", -"omi.niigata.jp", -"sado.niigata.jp", -"sanjo.niigata.jp", -"seiro.niigata.jp", -"seirou.niigata.jp", -"sekikawa.niigata.jp", -"shibata.niigata.jp", -"tagami.niigata.jp", -"tainai.niigata.jp", -"tochio.niigata.jp", -"tokamachi.niigata.jp", -"tsubame.niigata.jp", -"tsunan.niigata.jp", -"uonuma.niigata.jp", -"yahiko.niigata.jp", -"yoita.niigata.jp", -"yuzawa.niigata.jp", -"beppu.oita.jp", -"bungoono.oita.jp", -"bungotakada.oita.jp", -"hasama.oita.jp", -"hiji.oita.jp", -"himeshima.oita.jp", -"hita.oita.jp", -"kamitsue.oita.jp", -"kokonoe.oita.jp", -"kuju.oita.jp", -"kunisaki.oita.jp", -"kusu.oita.jp", -"oita.oita.jp", -"saiki.oita.jp", -"taketa.oita.jp", -"tsukumi.oita.jp", -"usa.oita.jp", -"usuki.oita.jp", -"yufu.oita.jp", -"akaiwa.okayama.jp", -"asakuchi.okayama.jp", -"bizen.okayama.jp", -"hayashima.okayama.jp", -"ibara.okayama.jp", -"kagamino.okayama.jp", -"kasaoka.okayama.jp", -"kibichuo.okayama.jp", -"kumenan.okayama.jp", -"kurashiki.okayama.jp", -"maniwa.okayama.jp", -"misaki.okayama.jp", -"nagi.okayama.jp", -"niimi.okayama.jp", -"nishiawakura.okayama.jp", -"okayama.okayama.jp", -"satosho.okayama.jp", -"setouchi.okayama.jp", -"shinjo.okayama.jp", -"shoo.okayama.jp", -"soja.okayama.jp", -"takahashi.okayama.jp", -"tamano.okayama.jp", -"tsuyama.okayama.jp", -"wake.okayama.jp", -"yakage.okayama.jp", -"aguni.okinawa.jp", -"ginowan.okinawa.jp", -"ginoza.okinawa.jp", -"gushikami.okinawa.jp", -"haebaru.okinawa.jp", -"higashi.okinawa.jp", -"hirara.okinawa.jp", -"iheya.okinawa.jp", -"ishigaki.okinawa.jp", -"ishikawa.okinawa.jp", -"itoman.okinawa.jp", -"izena.okinawa.jp", -"kadena.okinawa.jp", -"kin.okinawa.jp", -"kitadaito.okinawa.jp", -"kitanakagusuku.okinawa.jp", -"kumejima.okinawa.jp", -"kunigami.okinawa.jp", -"minamidaito.okinawa.jp", -"motobu.okinawa.jp", -"nago.okinawa.jp", -"naha.okinawa.jp", -"nakagusuku.okinawa.jp", -"nakijin.okinawa.jp", -"nanjo.okinawa.jp", -"nishihara.okinawa.jp", -"ogimi.okinawa.jp", -"okinawa.okinawa.jp", -"onna.okinawa.jp", -"shimoji.okinawa.jp", -"taketomi.okinawa.jp", -"tarama.okinawa.jp", -"tokashiki.okinawa.jp", -"tomigusuku.okinawa.jp", -"tonaki.okinawa.jp", -"urasoe.okinawa.jp", -"uruma.okinawa.jp", -"yaese.okinawa.jp", -"yomitan.okinawa.jp", -"yonabaru.okinawa.jp", -"yonaguni.okinawa.jp", -"zamami.okinawa.jp", -"abeno.osaka.jp", -"chihayaakasaka.osaka.jp", -"chuo.osaka.jp", -"daito.osaka.jp", -"fujiidera.osaka.jp", -"habikino.osaka.jp", -"hannan.osaka.jp", -"higashiosaka.osaka.jp", -"higashisumiyoshi.osaka.jp", -"higashiyodogawa.osaka.jp", -"hirakata.osaka.jp", -"ibaraki.osaka.jp", -"ikeda.osaka.jp", -"izumi.osaka.jp", -"izumiotsu.osaka.jp", -"izumisano.osaka.jp", -"kadoma.osaka.jp", -"kaizuka.osaka.jp", -"kanan.osaka.jp", -"kashiwara.osaka.jp", -"katano.osaka.jp", -"kawachinagano.osaka.jp", -"kishiwada.osaka.jp", -"kita.osaka.jp", -"kumatori.osaka.jp", -"matsubara.osaka.jp", -"minato.osaka.jp", -"minoh.osaka.jp", -"misaki.osaka.jp", -"moriguchi.osaka.jp", -"neyagawa.osaka.jp", -"nishi.osaka.jp", -"nose.osaka.jp", -"osakasayama.osaka.jp", -"sakai.osaka.jp", -"sayama.osaka.jp", -"sennan.osaka.jp", -"settsu.osaka.jp", -"shijonawate.osaka.jp", -"shimamoto.osaka.jp", -"suita.osaka.jp", -"tadaoka.osaka.jp", -"taishi.osaka.jp", -"tajiri.osaka.jp", -"takaishi.osaka.jp", -"takatsuki.osaka.jp", -"tondabayashi.osaka.jp", -"toyonaka.osaka.jp", -"toyono.osaka.jp", -"yao.osaka.jp", -"ariake.saga.jp", -"arita.saga.jp", -"fukudomi.saga.jp", -"genkai.saga.jp", -"hamatama.saga.jp", -"hizen.saga.jp", -"imari.saga.jp", -"kamimine.saga.jp", -"kanzaki.saga.jp", -"karatsu.saga.jp", -"kashima.saga.jp", -"kitagata.saga.jp", -"kitahata.saga.jp", -"kiyama.saga.jp", -"kouhoku.saga.jp", -"kyuragi.saga.jp", -"nishiarita.saga.jp", -"ogi.saga.jp", -"omachi.saga.jp", -"ouchi.saga.jp", -"saga.saga.jp", -"shiroishi.saga.jp", -"taku.saga.jp", -"tara.saga.jp", -"tosu.saga.jp", -"yoshinogari.saga.jp", -"arakawa.saitama.jp", -"asaka.saitama.jp", -"chichibu.saitama.jp", -"fujimi.saitama.jp", -"fujimino.saitama.jp", -"fukaya.saitama.jp", -"hanno.saitama.jp", -"hanyu.saitama.jp", -"hasuda.saitama.jp", -"hatogaya.saitama.jp", -"hatoyama.saitama.jp", -"hidaka.saitama.jp", -"higashichichibu.saitama.jp", -"higashimatsuyama.saitama.jp", -"honjo.saitama.jp", -"ina.saitama.jp", -"iruma.saitama.jp", -"iwatsuki.saitama.jp", -"kamiizumi.saitama.jp", -"kamikawa.saitama.jp", -"kamisato.saitama.jp", -"kasukabe.saitama.jp", -"kawagoe.saitama.jp", -"kawaguchi.saitama.jp", -"kawajima.saitama.jp", -"kazo.saitama.jp", -"kitamoto.saitama.jp", -"koshigaya.saitama.jp", -"kounosu.saitama.jp", -"kuki.saitama.jp", -"kumagaya.saitama.jp", -"matsubushi.saitama.jp", -"minano.saitama.jp", -"misato.saitama.jp", -"miyashiro.saitama.jp", -"miyoshi.saitama.jp", -"moroyama.saitama.jp", -"nagatoro.saitama.jp", -"namegawa.saitama.jp", -"niiza.saitama.jp", -"ogano.saitama.jp", -"ogawa.saitama.jp", -"ogose.saitama.jp", -"okegawa.saitama.jp", -"omiya.saitama.jp", -"otaki.saitama.jp", -"ranzan.saitama.jp", -"ryokami.saitama.jp", -"saitama.saitama.jp", -"sakado.saitama.jp", -"satte.saitama.jp", -"sayama.saitama.jp", -"shiki.saitama.jp", -"shiraoka.saitama.jp", -"soka.saitama.jp", -"sugito.saitama.jp", -"toda.saitama.jp", -"tokigawa.saitama.jp", -"tokorozawa.saitama.jp", -"tsurugashima.saitama.jp", -"urawa.saitama.jp", -"warabi.saitama.jp", -"yashio.saitama.jp", -"yokoze.saitama.jp", -"yono.saitama.jp", -"yorii.saitama.jp", -"yoshida.saitama.jp", -"yoshikawa.saitama.jp", -"yoshimi.saitama.jp", -"aisho.shiga.jp", -"gamo.shiga.jp", -"higashiomi.shiga.jp", -"hikone.shiga.jp", -"koka.shiga.jp", -"konan.shiga.jp", -"kosei.shiga.jp", -"koto.shiga.jp", -"kusatsu.shiga.jp", -"maibara.shiga.jp", -"moriyama.shiga.jp", -"nagahama.shiga.jp", -"nishiazai.shiga.jp", -"notogawa.shiga.jp", -"omihachiman.shiga.jp", -"otsu.shiga.jp", -"ritto.shiga.jp", -"ryuoh.shiga.jp", -"takashima.shiga.jp", -"takatsuki.shiga.jp", -"torahime.shiga.jp", -"toyosato.shiga.jp", -"yasu.shiga.jp", -"akagi.shimane.jp", -"ama.shimane.jp", -"gotsu.shimane.jp", -"hamada.shimane.jp", -"higashiizumo.shimane.jp", -"hikawa.shimane.jp", -"hikimi.shimane.jp", -"izumo.shimane.jp", -"kakinoki.shimane.jp", -"masuda.shimane.jp", -"matsue.shimane.jp", -"misato.shimane.jp", -"nishinoshima.shimane.jp", -"ohda.shimane.jp", -"okinoshima.shimane.jp", -"okuizumo.shimane.jp", -"shimane.shimane.jp", -"tamayu.shimane.jp", -"tsuwano.shimane.jp", -"unnan.shimane.jp", -"yakumo.shimane.jp", -"yasugi.shimane.jp", -"yatsuka.shimane.jp", -"arai.shizuoka.jp", -"atami.shizuoka.jp", -"fuji.shizuoka.jp", -"fujieda.shizuoka.jp", -"fujikawa.shizuoka.jp", -"fujinomiya.shizuoka.jp", -"fukuroi.shizuoka.jp", -"gotemba.shizuoka.jp", -"haibara.shizuoka.jp", -"hamamatsu.shizuoka.jp", -"higashiizu.shizuoka.jp", -"ito.shizuoka.jp", -"iwata.shizuoka.jp", -"izu.shizuoka.jp", -"izunokuni.shizuoka.jp", -"kakegawa.shizuoka.jp", -"kannami.shizuoka.jp", -"kawanehon.shizuoka.jp", -"kawazu.shizuoka.jp", -"kikugawa.shizuoka.jp", -"kosai.shizuoka.jp", -"makinohara.shizuoka.jp", -"matsuzaki.shizuoka.jp", -"minamiizu.shizuoka.jp", -"mishima.shizuoka.jp", -"morimachi.shizuoka.jp", -"nishiizu.shizuoka.jp", -"numazu.shizuoka.jp", -"omaezaki.shizuoka.jp", -"shimada.shizuoka.jp", -"shimizu.shizuoka.jp", -"shimoda.shizuoka.jp", -"shizuoka.shizuoka.jp", -"susono.shizuoka.jp", -"yaizu.shizuoka.jp", -"yoshida.shizuoka.jp", -"ashikaga.tochigi.jp", -"bato.tochigi.jp", -"haga.tochigi.jp", -"ichikai.tochigi.jp", -"iwafune.tochigi.jp", -"kaminokawa.tochigi.jp", -"kanuma.tochigi.jp", -"karasuyama.tochigi.jp", -"kuroiso.tochigi.jp", -"mashiko.tochigi.jp", -"mibu.tochigi.jp", -"moka.tochigi.jp", -"motegi.tochigi.jp", -"nasu.tochigi.jp", -"nasushiobara.tochigi.jp", -"nikko.tochigi.jp", -"nishikata.tochigi.jp", -"nogi.tochigi.jp", -"ohira.tochigi.jp", -"ohtawara.tochigi.jp", -"oyama.tochigi.jp", -"sakura.tochigi.jp", -"sano.tochigi.jp", -"shimotsuke.tochigi.jp", -"shioya.tochigi.jp", -"takanezawa.tochigi.jp", -"tochigi.tochigi.jp", -"tsuga.tochigi.jp", -"ujiie.tochigi.jp", -"utsunomiya.tochigi.jp", -"yaita.tochigi.jp", -"aizumi.tokushima.jp", -"anan.tokushima.jp", -"ichiba.tokushima.jp", -"itano.tokushima.jp", -"kainan.tokushima.jp", -"komatsushima.tokushima.jp", -"matsushige.tokushima.jp", -"mima.tokushima.jp", -"minami.tokushima.jp", -"miyoshi.tokushima.jp", -"mugi.tokushima.jp", -"nakagawa.tokushima.jp", -"naruto.tokushima.jp", -"sanagochi.tokushima.jp", -"shishikui.tokushima.jp", -"tokushima.tokushima.jp", -"wajiki.tokushima.jp", -"adachi.tokyo.jp", -"akiruno.tokyo.jp", -"akishima.tokyo.jp", -"aogashima.tokyo.jp", -"arakawa.tokyo.jp", -"bunkyo.tokyo.jp", -"chiyoda.tokyo.jp", -"chofu.tokyo.jp", -"chuo.tokyo.jp", -"edogawa.tokyo.jp", -"fuchu.tokyo.jp", -"fussa.tokyo.jp", -"hachijo.tokyo.jp", -"hachioji.tokyo.jp", -"hamura.tokyo.jp", -"higashikurume.tokyo.jp", -"higashimurayama.tokyo.jp", -"higashiyamato.tokyo.jp", -"hino.tokyo.jp", -"hinode.tokyo.jp", -"hinohara.tokyo.jp", -"inagi.tokyo.jp", -"itabashi.tokyo.jp", -"katsushika.tokyo.jp", -"kita.tokyo.jp", -"kiyose.tokyo.jp", -"kodaira.tokyo.jp", -"koganei.tokyo.jp", -"kokubunji.tokyo.jp", -"komae.tokyo.jp", -"koto.tokyo.jp", -"kouzushima.tokyo.jp", -"kunitachi.tokyo.jp", -"machida.tokyo.jp", -"meguro.tokyo.jp", -"minato.tokyo.jp", -"mitaka.tokyo.jp", -"mizuho.tokyo.jp", -"musashimurayama.tokyo.jp", -"musashino.tokyo.jp", -"nakano.tokyo.jp", -"nerima.tokyo.jp", -"ogasawara.tokyo.jp", -"okutama.tokyo.jp", -"ome.tokyo.jp", -"oshima.tokyo.jp", -"ota.tokyo.jp", -"setagaya.tokyo.jp", -"shibuya.tokyo.jp", -"shinagawa.tokyo.jp", -"shinjuku.tokyo.jp", -"suginami.tokyo.jp", -"sumida.tokyo.jp", -"tachikawa.tokyo.jp", -"taito.tokyo.jp", -"tama.tokyo.jp", -"toshima.tokyo.jp", -"chizu.tottori.jp", -"hino.tottori.jp", -"kawahara.tottori.jp", -"koge.tottori.jp", -"kotoura.tottori.jp", -"misasa.tottori.jp", -"nanbu.tottori.jp", -"nichinan.tottori.jp", -"sakaiminato.tottori.jp", -"tottori.tottori.jp", -"wakasa.tottori.jp", -"yazu.tottori.jp", -"yonago.tottori.jp", -"asahi.toyama.jp", -"fuchu.toyama.jp", -"fukumitsu.toyama.jp", -"funahashi.toyama.jp", -"himi.toyama.jp", -"imizu.toyama.jp", -"inami.toyama.jp", -"johana.toyama.jp", -"kamiichi.toyama.jp", -"kurobe.toyama.jp", -"nakaniikawa.toyama.jp", -"namerikawa.toyama.jp", -"nanto.toyama.jp", -"nyuzen.toyama.jp", -"oyabe.toyama.jp", -"taira.toyama.jp", -"takaoka.toyama.jp", -"tateyama.toyama.jp", -"toga.toyama.jp", -"tonami.toyama.jp", -"toyama.toyama.jp", -"unazuki.toyama.jp", -"uozu.toyama.jp", -"yamada.toyama.jp", -"arida.wakayama.jp", -"aridagawa.wakayama.jp", -"gobo.wakayama.jp", -"hashimoto.wakayama.jp", -"hidaka.wakayama.jp", -"hirogawa.wakayama.jp", -"inami.wakayama.jp", -"iwade.wakayama.jp", -"kainan.wakayama.jp", -"kamitonda.wakayama.jp", -"katsuragi.wakayama.jp", -"kimino.wakayama.jp", -"kinokawa.wakayama.jp", -"kitayama.wakayama.jp", -"koya.wakayama.jp", -"koza.wakayama.jp", -"kozagawa.wakayama.jp", -"kudoyama.wakayama.jp", -"kushimoto.wakayama.jp", -"mihama.wakayama.jp", -"misato.wakayama.jp", -"nachikatsuura.wakayama.jp", -"shingu.wakayama.jp", -"shirahama.wakayama.jp", -"taiji.wakayama.jp", -"tanabe.wakayama.jp", -"wakayama.wakayama.jp", -"yuasa.wakayama.jp", -"yura.wakayama.jp", -"asahi.yamagata.jp", -"funagata.yamagata.jp", -"higashine.yamagata.jp", -"iide.yamagata.jp", -"kahoku.yamagata.jp", -"kaminoyama.yamagata.jp", -"kaneyama.yamagata.jp", -"kawanishi.yamagata.jp", -"mamurogawa.yamagata.jp", -"mikawa.yamagata.jp", -"murayama.yamagata.jp", -"nagai.yamagata.jp", -"nakayama.yamagata.jp", -"nanyo.yamagata.jp", -"nishikawa.yamagata.jp", -"obanazawa.yamagata.jp", -"oe.yamagata.jp", -"oguni.yamagata.jp", -"ohkura.yamagata.jp", -"oishida.yamagata.jp", -"sagae.yamagata.jp", -"sakata.yamagata.jp", -"sakegawa.yamagata.jp", -"shinjo.yamagata.jp", -"shirataka.yamagata.jp", -"shonai.yamagata.jp", -"takahata.yamagata.jp", -"tendo.yamagata.jp", -"tozawa.yamagata.jp", -"tsuruoka.yamagata.jp", -"yamagata.yamagata.jp", -"yamanobe.yamagata.jp", -"yonezawa.yamagata.jp", -"yuza.yamagata.jp", -"abu.yamaguchi.jp", -"hagi.yamaguchi.jp", -"hikari.yamaguchi.jp", -"hofu.yamaguchi.jp", -"iwakuni.yamaguchi.jp", -"kudamatsu.yamaguchi.jp", -"mitou.yamaguchi.jp", -"nagato.yamaguchi.jp", -"oshima.yamaguchi.jp", -"shimonoseki.yamaguchi.jp", -"shunan.yamaguchi.jp", -"tabuse.yamaguchi.jp", -"tokuyama.yamaguchi.jp", -"toyota.yamaguchi.jp", -"ube.yamaguchi.jp", -"yuu.yamaguchi.jp", -"chuo.yamanashi.jp", -"doshi.yamanashi.jp", -"fuefuki.yamanashi.jp", -"fujikawa.yamanashi.jp", -"fujikawaguchiko.yamanashi.jp", -"fujiyoshida.yamanashi.jp", -"hayakawa.yamanashi.jp", -"hokuto.yamanashi.jp", -"ichikawamisato.yamanashi.jp", -"kai.yamanashi.jp", -"kofu.yamanashi.jp", -"koshu.yamanashi.jp", -"kosuge.yamanashi.jp", -"minami-alps.yamanashi.jp", -"minobu.yamanashi.jp", -"nakamichi.yamanashi.jp", -"nanbu.yamanashi.jp", -"narusawa.yamanashi.jp", -"nirasaki.yamanashi.jp", -"nishikatsura.yamanashi.jp", -"oshino.yamanashi.jp", -"otsuki.yamanashi.jp", -"showa.yamanashi.jp", -"tabayama.yamanashi.jp", -"tsuru.yamanashi.jp", -"uenohara.yamanashi.jp", -"yamanakako.yamanashi.jp", -"yamanashi.yamanashi.jp", -"ac.ke", -"co.ke", -"go.ke", -"info.ke", -"me.ke", -"mobi.ke", -"ne.ke", -"or.ke", -"sc.ke", -"com.kg", -"edu.kg", -"gov.kg", -"mil.kg", -"net.kg", -"org.kg", -"com.kh", -"edu.kh", -"gov.kh", -"net.kh", -"org.kh", -"biz.ki", -"com.ki", -"edu.ki", -"gov.ki", -"info.ki", -"net.ki", -"org.ki", -"ass.km", -"com.km", -"edu.km", -"gov.km", -"mil.km", -"nom.km", -"org.km", -"prd.km", -"tm.km", -"asso.km", -"coop.km", -"gouv.km", -"medecin.km", -"notaires.km", -"pharmaciens.km", -"presse.km", -"veterinaire.km", -"edu.kn", -"gov.kn", -"net.kn", -"org.kn", -"com.kp", -"edu.kp", -"gov.kp", -"org.kp", -"rep.kp", -"tra.kp", -"ac.kr", -"ai.kr", -"co.kr", -"es.kr", -"go.kr", -"hs.kr", -"io.kr", -"it.kr", -"kg.kr", -"me.kr", -"mil.kr", -"ms.kr", -"ne.kr", -"or.kr", -"pe.kr", -"re.kr", -"sc.kr", -"busan.kr", -"chungbuk.kr", -"chungnam.kr", -"daegu.kr", -"daejeon.kr", -"gangwon.kr", -"gwangju.kr", -"gyeongbuk.kr", -"gyeonggi.kr", -"gyeongnam.kr", -"incheon.kr", -"jeju.kr", -"jeonbuk.kr", -"jeonnam.kr", -"seoul.kr", -"ulsan.kr", -"com.kw", -"edu.kw", -"emb.kw", -"gov.kw", -"ind.kw", -"net.kw", -"org.kw", -"com.ky", -"edu.ky", -"net.ky", -"org.ky", -"com.kz", -"edu.kz", -"gov.kz", -"mil.kz", -"net.kz", -"org.kz", -"com.la", -"edu.la", -"gov.la", -"info.la", -"int.la", -"net.la", -"org.la", -"per.la", -"com.lb", -"edu.lb", -"gov.lb", -"net.lb", -"org.lb", -"co.lc", -"com.lc", -"edu.lc", -"gov.lc", -"net.lc", -"org.lc", -"ac.lk", -"assn.lk", -"com.lk", -"edu.lk", -"gov.lk", -"grp.lk", -"hotel.lk", -"int.lk", -"ltd.lk", -"net.lk", -"ngo.lk", -"org.lk", -"sch.lk", -"soc.lk", -"web.lk", -"com.lr", -"edu.lr", -"gov.lr", -"net.lr", -"org.lr", -"ac.ls", -"biz.ls", -"co.ls", -"edu.ls", -"gov.ls", -"info.ls", -"net.ls", -"org.ls", -"sc.ls", -"gov.lt", -"asn.lv", -"com.lv", -"conf.lv", -"edu.lv", -"gov.lv", -"id.lv", -"mil.lv", -"net.lv", -"org.lv", -"com.ly", -"edu.ly", -"gov.ly", -"id.ly", -"med.ly", -"net.ly", -"org.ly", -"plc.ly", -"sch.ly", -"ac.ma", -"co.ma", -"gov.ma", -"net.ma", -"org.ma", -"press.ma", -"asso.mc", -"tm.mc", -"ac.me", -"co.me", -"edu.me", -"gov.me", -"its.me", -"net.me", -"org.me", -"priv.me", -"co.mg", -"com.mg", -"edu.mg", -"gov.mg", -"mil.mg", -"nom.mg", -"org.mg", -"prd.mg", -"com.mk", -"edu.mk", -"gov.mk", -"inf.mk", -"name.mk", -"net.mk", -"org.mk", -"ac.ml", -"art.ml", -"asso.ml", -"com.ml", -"edu.ml", -"gouv.ml", -"gov.ml", -"info.ml", -"inst.ml", -"net.ml", -"org.ml", -"pr.ml", -"presse.ml", -"edu.mn", -"gov.mn", -"org.mn", -"com.mo", -"edu.mo", -"gov.mo", -"net.mo", -"org.mo", -"gov.mr", -"com.ms", -"edu.ms", -"gov.ms", -"net.ms", -"org.ms", -"com.mt", -"edu.mt", -"net.mt", -"org.mt", -"ac.mu", -"co.mu", -"com.mu", -"gov.mu", -"net.mu", -"or.mu", -"org.mu", -"aero.mv", -"biz.mv", -"com.mv", -"coop.mv", -"edu.mv", -"gov.mv", -"info.mv", -"int.mv", -"mil.mv", -"museum.mv", -"name.mv", -"net.mv", -"org.mv", -"pro.mv", -"ac.mw", -"biz.mw", -"co.mw", -"com.mw", -"coop.mw", -"edu.mw", -"gov.mw", -"int.mw", -"net.mw", -"org.mw", -"com.mx", -"edu.mx", -"gob.mx", -"net.mx", -"org.mx", -"biz.my", -"com.my", -"edu.my", -"gov.my", -"mil.my", -"name.my", -"net.my", -"org.my", -"ac.mz", -"adv.mz", -"co.mz", -"edu.mz", -"gov.mz", -"mil.mz", -"net.mz", -"org.mz", -"alt.na", -"co.na", -"com.na", -"gov.na", -"net.na", -"org.na", -"asso.nc", -"nom.nc", -"arts.nf", -"com.nf", -"firm.nf", -"info.nf", -"net.nf", -"other.nf", -"per.nf", -"rec.nf", -"store.nf", -"web.nf", -"com.ng", -"edu.ng", -"gov.ng", -"i.ng", -"mil.ng", -"mobi.ng", -"name.ng", -"net.ng", -"org.ng", -"sch.ng", -"ac.ni", -"biz.ni", -"co.ni", -"com.ni", -"edu.ni", -"gob.ni", -"in.ni", -"info.ni", -"int.ni", -"mil.ni", -"net.ni", -"nom.ni", -"org.ni", -"web.ni", -"fhs.no", -"folkebibl.no", -"fylkesbibl.no", -"gielda.no", -"herad.no", -"idrett.no", -"kommune.no", -"museum.no", -"priv.no", -"suohkan.no", -"tjielte.no", -"uenorge.no", -"vgs.no", -"dep.no", -"mil.no", -"stat.no", -"aa.no", -"ah.no", -"bu.no", -"fm.no", -"hl.no", -"hm.no", -"jan-mayen.no", -"mr.no", -"nl.no", -"nt.no", -"of.no", -"ol.no", -"oslo.no", -"rl.no", -"sf.no", -"st.no", -"svalbard.no", -"tm.no", -"tr.no", -"va.no", -"vf.no", -"gs.aa.no", -"gs.ah.no", -"gs.bu.no", -"gs.fm.no", -"gs.hl.no", -"gs.hm.no", -"gs.jan-mayen.no", -"gs.mr.no", -"gs.nl.no", -"gs.nt.no", -"gs.of.no", -"gs.ol.no", -"gs.oslo.no", -"gs.rl.no", -"gs.sf.no", -"gs.st.no", -"gs.svalbard.no", -"gs.tm.no", -"gs.tr.no", -"gs.va.no", -"gs.vf.no", -"akrehamn.no", -"algard.no", -"arna.no", -"bronnoysund.no", -"brumunddal.no", -"bryne.no", -"drobak.no", -"egersund.no", -"fetsund.no", -"floro.no", -"fredrikstad.no", -"hokksund.no", -"honefoss.no", -"jessheim.no", -"jorpeland.no", -"kirkenes.no", -"kopervik.no", -"krokstadelva.no", -"langevag.no", -"leirvik.no", -"mjondalen.no", -"mo-i-rana.no", -"mosjoen.no", -"nesoddtangen.no", -"orkanger.no", -"osoyro.no", -"raholt.no", -"sandnessjoen.no", -"skedsmokorset.no", -"slattum.no", -"spjelkavik.no", -"stathelle.no", -"stavern.no", -"stjordalshalsen.no", -"tananger.no", -"tranby.no", -"vossevangen.no", -"aarborte.no", -"aejrie.no", -"afjord.no", -"agdenes.no", -"nes.akershus.no", -"aknoluokta.no", -"al.no", -"alaheadju.no", -"alesund.no", -"alstahaug.no", -"alta.no", -"alvdal.no", -"amli.no", -"amot.no", -"andasuolo.no", -"andebu.no", -"andoy.no", -"ardal.no", -"aremark.no", -"arendal.no", -"aseral.no", -"asker.no", -"askim.no", -"askoy.no", -"askvoll.no", -"asnes.no", -"audnedal.no", -"aukra.no", -"aure.no", -"aurland.no", -"aurskog-holand.no", -"austevoll.no", -"austrheim.no", -"averoy.no", -"badaddja.no", -"bahcavuotna.no", -"bahccavuotna.no", -"baidar.no", -"bajddar.no", -"balat.no", -"balestrand.no", -"ballangen.no", -"balsfjord.no", -"bamble.no", -"bardu.no", -"barum.no", -"batsfjord.no", -"bearalvahki.no", -"beardu.no", -"beiarn.no", -"berg.no", -"bergen.no", -"berlevag.no", -"bievat.no", -"bindal.no", -"birkenes.no", -"bjerkreim.no", -"bjugn.no", -"bodo.no", -"bokn.no", -"bomlo.no", -"bremanger.no", -"bronnoy.no", -"budejju.no", -"nes.buskerud.no", -"bygland.no", -"bykle.no", -"cahcesuolo.no", -"davvenjarga.no", -"davvesiida.no", -"deatnu.no", -"dielddanuorri.no", -"divtasvuodna.no", -"divttasvuotna.no", -"donna.no", -"dovre.no", -"drammen.no", -"drangedal.no", -"dyroy.no", -"eid.no", -"eidfjord.no", -"eidsberg.no", -"eidskog.no", -"eidsvoll.no", -"eigersund.no", -"elverum.no", -"enebakk.no", -"engerdal.no", -"etne.no", -"etnedal.no", -"evenassi.no", -"evenes.no", -"evje-og-hornnes.no", -"farsund.no", -"fauske.no", -"fedje.no", -"fet.no", -"finnoy.no", -"fitjar.no", -"fjaler.no", -"fjell.no", -"fla.no", -"flakstad.no", -"flatanger.no", -"flekkefjord.no", -"flesberg.no", -"flora.no", -"folldal.no", -"forde.no", -"forsand.no", -"fosnes.no", -"frana.no", -"frogn.no", -"froland.no", -"frosta.no", -"froya.no", -"fuoisku.no", -"fuossko.no", -"fusa.no", -"fyresdal.no", -"gaivuotna.no", -"galsa.no", -"gamvik.no", -"gangaviika.no", -"gaular.no", -"gausdal.no", -"giehtavuoatna.no", -"gildeskal.no", -"giske.no", -"gjemnes.no", -"gjerdrum.no", -"gjerstad.no", -"gjesdal.no", -"gjovik.no", -"gloppen.no", -"gol.no", -"gran.no", -"grane.no", -"granvin.no", -"gratangen.no", -"grimstad.no", -"grong.no", -"grue.no", -"gulen.no", -"guovdageaidnu.no", -"ha.no", -"habmer.no", -"hadsel.no", -"hagebostad.no", -"halden.no", -"halsa.no", -"hamar.no", -"hamaroy.no", -"hammarfeasta.no", -"hammerfest.no", -"hapmir.no", -"haram.no", -"hareid.no", -"harstad.no", -"hasvik.no", -"hattfjelldal.no", -"haugesund.no", -"os.hedmark.no", -"valer.hedmark.no", -"hemne.no", -"hemnes.no", -"hemsedal.no", -"hitra.no", -"hjartdal.no", -"hjelmeland.no", -"hobol.no", -"hof.no", -"hol.no", -"hole.no", -"holmestrand.no", -"holtalen.no", -"os.hordaland.no", -"hornindal.no", -"horten.no", -"hoyanger.no", -"hoylandet.no", -"hurdal.no", -"hurum.no", -"hvaler.no", -"hyllestad.no", -"ibestad.no", -"inderoy.no", -"iveland.no", -"ivgu.no", -"jevnaker.no", -"jolster.no", -"jondal.no", -"kafjord.no", -"karasjohka.no", -"karasjok.no", -"karlsoy.no", -"karmoy.no", -"kautokeino.no", -"klabu.no", -"klepp.no", -"kongsberg.no", -"kongsvinger.no", -"kraanghke.no", -"kragero.no", -"kristiansand.no", -"kristiansund.no", -"krodsherad.no", -"kvafjord.no", -"kvalsund.no", -"kvam.no", -"kvanangen.no", -"kvinesdal.no", -"kvinnherad.no", -"kviteseid.no", -"kvitsoy.no", -"laakesvuemie.no", -"lahppi.no", -"lardal.no", -"larvik.no", -"lavagis.no", -"lavangen.no", -"leangaviika.no", -"lebesby.no", -"leikanger.no", -"leirfjord.no", -"leka.no", -"leksvik.no", -"lenvik.no", -"lerdal.no", -"lesja.no", -"levanger.no", -"lier.no", -"lierne.no", -"lillehammer.no", -"lillesand.no", -"lindas.no", -"lindesnes.no", -"loabat.no", -"lodingen.no", -"lom.no", -"loppa.no", -"lorenskog.no", -"loten.no", -"lund.no", -"lunner.no", -"luroy.no", -"luster.no", -"lyngdal.no", -"lyngen.no", -"malatvuopmi.no", -"malselv.no", -"malvik.no", -"mandal.no", -"marker.no", -"marnardal.no", -"masfjorden.no", -"masoy.no", -"matta-varjjat.no", -"meland.no", -"meldal.no", -"melhus.no", -"meloy.no", -"meraker.no", -"midsund.no", -"midtre-gauldal.no", -"moareke.no", -"modalen.no", -"modum.no", -"molde.no", -"heroy.more-og-romsdal.no", -"sande.more-og-romsdal.no", -"moskenes.no", -"moss.no", -"muosat.no", -"naamesjevuemie.no", -"namdalseid.no", -"namsos.no", -"namsskogan.no", -"nannestad.no", -"naroy.no", -"narviika.no", -"narvik.no", -"naustdal.no", -"navuotna.no", -"nedre-eiker.no", -"nesna.no", -"nesodden.no", -"nesseby.no", -"nesset.no", -"nissedal.no", -"nittedal.no", -"nord-aurdal.no", -"nord-fron.no", -"nord-odal.no", -"norddal.no", -"nordkapp.no", -"bo.nordland.no", -"heroy.nordland.no", -"nordre-land.no", -"nordreisa.no", -"nore-og-uvdal.no", -"notodden.no", -"notteroy.no", -"odda.no", -"oksnes.no", -"omasvuotna.no", -"oppdal.no", -"oppegard.no", -"orkdal.no", -"orland.no", -"orskog.no", -"orsta.no", -"osen.no", -"osteroy.no", -"valer.ostfold.no", -"ostre-toten.no", -"overhalla.no", -"ovre-eiker.no", -"oyer.no", -"oygarden.no", -"oystre-slidre.no", -"porsanger.no", -"porsangu.no", -"porsgrunn.no", -"rade.no", -"radoy.no", -"rahkkeravju.no", -"raisa.no", -"rakkestad.no", -"ralingen.no", -"rana.no", -"randaberg.no", -"rauma.no", -"re.no", -"rendalen.no", -"rennebu.no", -"rennesoy.no", -"rindal.no", -"ringebu.no", -"ringerike.no", -"ringsaker.no", -"risor.no", -"rissa.no", -"roan.no", -"rodoy.no", -"rollag.no", -"romsa.no", -"romskog.no", -"roros.no", -"rost.no", -"royken.no", -"royrvik.no", -"ruovat.no", -"rygge.no", -"salangen.no", -"salat.no", -"saltdal.no", -"samnanger.no", -"sandefjord.no", -"sandnes.no", -"sandoy.no", -"sarpsborg.no", -"sauda.no", -"sauherad.no", -"sel.no", -"selbu.no", -"selje.no", -"seljord.no", -"siellak.no", -"sigdal.no", -"siljan.no", -"sirdal.no", -"skanit.no", -"skanland.no", -"skaun.no", -"skedsmo.no", -"ski.no", -"skien.no", -"skierva.no", -"skiptvet.no", -"skjak.no", -"skjervoy.no", -"skodje.no", -"smola.no", -"snaase.no", -"snasa.no", -"snillfjord.no", -"snoasa.no", -"sogndal.no", -"sogne.no", -"sokndal.no", -"sola.no", -"solund.no", -"somna.no", -"sondre-land.no", -"songdalen.no", -"sor-aurdal.no", -"sor-fron.no", -"sor-odal.no", -"sor-varanger.no", -"sorfold.no", -"sorreisa.no", -"sortland.no", -"sorum.no", -"spydeberg.no", -"stange.no", -"stavanger.no", -"steigen.no", -"steinkjer.no", -"stjordal.no", -"stokke.no", -"stor-elvdal.no", -"stord.no", -"stordal.no", -"storfjord.no", -"strand.no", -"stranda.no", -"stryn.no", -"sula.no", -"suldal.no", -"sund.no", -"sunndal.no", -"surnadal.no", -"sveio.no", -"svelvik.no", -"sykkylven.no", -"tana.no", -"bo.telemark.no", -"time.no", -"tingvoll.no", -"tinn.no", -"tjeldsund.no", -"tjome.no", -"tokke.no", -"tolga.no", -"tonsberg.no", -"torsken.no", -"trana.no", -"tranoy.no", -"troandin.no", -"trogstad.no", -"tromsa.no", -"tromso.no", -"trondheim.no", -"trysil.no", -"tvedestrand.no", -"tydal.no", -"tynset.no", -"tysfjord.no", -"tysnes.no", -"tysvar.no", -"ullensaker.no", -"ullensvang.no", -"ulstein.no", -"ulvik.no", -"unjarga.no", -"utsira.no", -"vaapste.no", -"vadso.no", -"vaga.no", -"vagan.no", -"vagsoy.no", -"vaksdal.no", -"valle.no", -"vang.no", -"vanylven.no", -"vardo.no", -"varggat.no", -"varoy.no", -"vefsn.no", -"vega.no", -"vegarshei.no", -"vennesla.no", -"verdal.no", -"verran.no", -"vestby.no", -"sande.vestfold.no", -"vestnes.no", -"vestre-slidre.no", -"vestre-toten.no", -"vestvagoy.no", -"vevelstad.no", -"vik.no", -"vikna.no", -"vindafjord.no", -"voagat.no", -"volda.no", -"voss.no", -"biz.nr", -"com.nr", -"edu.nr", -"gov.nr", -"info.nr", -"net.nr", -"org.nr", -"ac.nz", -"co.nz", -"cri.nz", -"geek.nz", -"gen.nz", -"govt.nz", -"health.nz", -"iwi.nz", -"kiwi.nz", -"maori.nz", -"mil.nz", -"net.nz", -"org.nz", -"parliament.nz", -"school.nz", -"co.om", -"com.om", -"edu.om", -"gov.om", -"med.om", -"museum.om", -"net.om", -"org.om", -"pro.om", -"abo.pa", -"ac.pa", -"com.pa", -"edu.pa", -"gob.pa", -"ing.pa", -"med.pa", -"net.pa", -"nom.pa", -"org.pa", -"sld.pa", -"com.pe", -"edu.pe", -"gob.pe", -"mil.pe", -"net.pe", -"nom.pe", -"org.pe", -"com.pf", -"edu.pf", -"org.pf", -"com.ph", -"edu.ph", -"gov.ph", -"i.ph", -"mil.ph", -"net.ph", -"ngo.ph", -"org.ph", -"ac.pk", -"biz.pk", -"com.pk", -"edu.pk", -"fam.pk", -"gkp.pk", -"gob.pk", -"gog.pk", -"gok.pk", -"gop.pk", -"gos.pk", -"gov.pk", -"net.pk", -"org.pk", -"web.pk", -"com.pl", -"net.pl", -"org.pl", -"agro.pl", -"aid.pl", -"atm.pl", -"auto.pl", -"biz.pl", -"edu.pl", -"gmina.pl", -"gsm.pl", -"info.pl", -"mail.pl", -"media.pl", -"miasta.pl", -"mil.pl", -"nieruchomosci.pl", -"nom.pl", -"pc.pl", -"powiat.pl", -"priv.pl", -"realestate.pl", -"rel.pl", -"sex.pl", -"shop.pl", -"sklep.pl", -"sos.pl", -"szkola.pl", -"targi.pl", -"tm.pl", -"tourism.pl", -"travel.pl", -"turystyka.pl", -"gov.pl", -"ap.gov.pl", -"griw.gov.pl", -"ic.gov.pl", -"is.gov.pl", -"kmpsp.gov.pl", -"konsulat.gov.pl", -"kppsp.gov.pl", -"kwp.gov.pl", -"kwpsp.gov.pl", -"mup.gov.pl", -"mw.gov.pl", -"oia.gov.pl", -"oirm.gov.pl", -"oke.gov.pl", -"oow.gov.pl", -"oschr.gov.pl", -"oum.gov.pl", -"pa.gov.pl", -"pinb.gov.pl", -"piw.gov.pl", -"po.gov.pl", -"pr.gov.pl", -"psp.gov.pl", -"psse.gov.pl", -"pup.gov.pl", -"rzgw.gov.pl", -"sa.gov.pl", -"sdn.gov.pl", -"sko.gov.pl", -"so.gov.pl", -"sr.gov.pl", -"starostwo.gov.pl", -"ug.gov.pl", -"ugim.gov.pl", -"um.gov.pl", -"umig.gov.pl", -"upow.gov.pl", -"uppo.gov.pl", -"us.gov.pl", -"uw.gov.pl", -"uzs.gov.pl", -"wif.gov.pl", -"wiih.gov.pl", -"winb.gov.pl", -"wios.gov.pl", -"witd.gov.pl", -"wiw.gov.pl", -"wkz.gov.pl", -"wsa.gov.pl", -"wskr.gov.pl", -"wsse.gov.pl", -"wuoz.gov.pl", -"wzmiuw.gov.pl", -"zp.gov.pl", -"zpisdn.gov.pl", -"augustow.pl", -"babia-gora.pl", -"bedzin.pl", -"beskidy.pl", -"bialowieza.pl", -"bialystok.pl", -"bielawa.pl", -"bieszczady.pl", -"boleslawiec.pl", -"bydgoszcz.pl", -"bytom.pl", -"cieszyn.pl", -"czeladz.pl", -"czest.pl", -"dlugoleka.pl", -"elblag.pl", -"elk.pl", -"glogow.pl", -"gniezno.pl", -"gorlice.pl", -"grajewo.pl", -"ilawa.pl", -"jaworzno.pl", -"jelenia-gora.pl", -"jgora.pl", -"kalisz.pl", -"karpacz.pl", -"kartuzy.pl", -"kaszuby.pl", -"katowice.pl", -"kazimierz-dolny.pl", -"kepno.pl", -"ketrzyn.pl", -"klodzko.pl", -"kobierzyce.pl", -"kolobrzeg.pl", -"konin.pl", -"konskowola.pl", -"kutno.pl", -"lapy.pl", -"lebork.pl", -"legnica.pl", -"lezajsk.pl", -"limanowa.pl", -"lomza.pl", -"lowicz.pl", -"lubin.pl", -"lukow.pl", -"malbork.pl", -"malopolska.pl", -"mazowsze.pl", -"mazury.pl", -"mielec.pl", -"mielno.pl", -"mragowo.pl", -"naklo.pl", -"nowaruda.pl", -"nysa.pl", -"olawa.pl", -"olecko.pl", -"olkusz.pl", -"olsztyn.pl", -"opoczno.pl", -"opole.pl", -"ostroda.pl", -"ostroleka.pl", -"ostrowiec.pl", -"ostrowwlkp.pl", -"pila.pl", -"pisz.pl", -"podhale.pl", -"podlasie.pl", -"polkowice.pl", -"pomorskie.pl", -"pomorze.pl", -"prochowice.pl", -"pruszkow.pl", -"przeworsk.pl", -"pulawy.pl", -"radom.pl", -"rawa-maz.pl", -"rybnik.pl", -"rzeszow.pl", -"sanok.pl", -"sejny.pl", -"skoczow.pl", -"slask.pl", -"slupsk.pl", -"sosnowiec.pl", -"stalowa-wola.pl", -"starachowice.pl", -"stargard.pl", -"suwalki.pl", -"swidnica.pl", -"swiebodzin.pl", -"swinoujscie.pl", -"szczecin.pl", -"szczytno.pl", -"tarnobrzeg.pl", -"tgory.pl", -"turek.pl", -"tychy.pl", -"ustka.pl", -"walbrzych.pl", -"warmia.pl", -"warszawa.pl", -"waw.pl", -"wegrow.pl", -"wielun.pl", -"wlocl.pl", -"wloclawek.pl", -"wodzislaw.pl", -"wolomin.pl", -"wroclaw.pl", -"zachpomor.pl", -"zagan.pl", -"zarow.pl", -"zgora.pl", -"zgorzelec.pl", -"co.pn", -"edu.pn", -"gov.pn", -"net.pn", -"org.pn", -"biz.pr", -"com.pr", -"edu.pr", -"gov.pr", -"info.pr", -"isla.pr", -"name.pr", -"net.pr", -"org.pr", -"pro.pr", -"ac.pr", -"est.pr", -"prof.pr", -"aaa.pro", -"aca.pro", -"acct.pro", -"avocat.pro", -"bar.pro", -"cpa.pro", -"eng.pro", -"jur.pro", -"law.pro", -"med.pro", -"recht.pro", -"com.ps", -"edu.ps", -"gov.ps", -"net.ps", -"org.ps", -"plo.ps", -"sec.ps", -"com.pt", -"edu.pt", -"gov.pt", -"int.pt", -"net.pt", -"nome.pt", -"org.pt", -"publ.pt", -"gov.pw", -"com.py", -"coop.py", -"edu.py", -"gov.py", -"mil.py", -"net.py", -"org.py", -"com.qa", -"edu.qa", -"gov.qa", -"mil.qa", -"name.qa", -"net.qa", -"org.qa", -"sch.qa", -"asso.re", -"com.re", -"arts.ro", -"com.ro", -"firm.ro", -"info.ro", -"nom.ro", -"nt.ro", -"org.ro", -"rec.ro", -"store.ro", -"tm.ro", -"www.ro", -"ac.rs", -"co.rs", -"edu.rs", -"gov.rs", -"in.rs", -"org.rs", -"ac.rw", -"co.rw", -"coop.rw", -"gov.rw", -"mil.rw", -"net.rw", -"org.rw", -"com.sa", -"edu.sa", -"gov.sa", -"med.sa", -"net.sa", -"org.sa", -"pub.sa", -"sch.sa", -"com.sb", -"edu.sb", -"gov.sb", -"net.sb", -"org.sb", -"com.sc", -"edu.sc", -"gov.sc", -"net.sc", -"org.sc", -"com.sd", -"edu.sd", -"gov.sd", -"info.sd", -"med.sd", -"net.sd", -"org.sd", -"tv.sd", -"a.se", -"ac.se", -"b.se", -"bd.se", -"brand.se", -"c.se", -"d.se", -"e.se", -"f.se", -"fh.se", -"fhsk.se", -"fhv.se", -"g.se", -"h.se", -"i.se", -"k.se", -"komforb.se", -"kommunalforbund.se", -"komvux.se", -"l.se", -"lanbib.se", -"m.se", -"n.se", -"naturbruksgymn.se", -"o.se", -"org.se", -"p.se", -"parti.se", -"pp.se", -"press.se", -"r.se", -"s.se", -"t.se", -"tm.se", -"u.se", -"w.se", -"x.se", -"y.se", -"z.se", -"com.sg", -"edu.sg", -"gov.sg", -"net.sg", -"org.sg", -"com.sh", -"gov.sh", -"mil.sh", -"net.sh", -"org.sh", -"org.sk", -"com.sl", -"edu.sl", -"gov.sl", -"net.sl", -"org.sl", -"art.sn", -"com.sn", -"edu.sn", -"gouv.sn", -"org.sn", -"univ.sn", -"com.so", -"edu.so", -"gov.so", -"me.so", -"net.so", -"org.so", -"biz.ss", -"co.ss", -"com.ss", -"edu.ss", -"gov.ss", -"me.ss", -"net.ss", -"org.ss", -"sch.ss", -"co.st", -"com.st", -"consulado.st", -"edu.st", -"embaixada.st", -"mil.st", -"net.st", -"org.st", -"principe.st", -"saotome.st", -"store.st", -"com.sv", -"edu.sv", -"gob.sv", -"org.sv", -"red.sv", -"gov.sx", -"com.sy", -"edu.sy", -"gov.sy", -"mil.sy", -"net.sy", -"org.sy", -"ac.sz", -"co.sz", -"org.sz", -"ac.th", -"co.th", -"go.th", -"in.th", -"mi.th", -"net.th", -"or.th", -"biz.tj", -"co.tj", -"com.tj", -"edu.tj", -"go.tj", -"gov.tj", -"int.tj", -"mil.tj", -"name.tj", -"net.tj", -"nic.tj", -"org.tj", -"test.tj", -"web.tj", -"gov.tl", -"co.tm", -"com.tm", -"edu.tm", -"gov.tm", -"mil.tm", -"net.tm", -"nom.tm", -"org.tm", -"com.tn", -"ens.tn", -"fin.tn", -"gov.tn", -"ind.tn", -"info.tn", -"intl.tn", -"mincom.tn", -"nat.tn", -"net.tn", -"org.tn", -"perso.tn", -"tourism.tn", -"com.to", -"edu.to", -"gov.to", -"mil.to", -"net.to", -"org.to", -"av.tr", -"bbs.tr", -"bel.tr", -"biz.tr", -"com.tr", -"dr.tr", -"edu.tr", -"gen.tr", -"gov.tr", -"info.tr", -"k12.tr", -"kep.tr", -"mil.tr", -"name.tr", -"net.tr", -"org.tr", -"pol.tr", -"tel.tr", -"tsk.tr", -"tv.tr", -"web.tr", -"nc.tr", -"gov.nc.tr", -"biz.tt", -"co.tt", -"com.tt", -"edu.tt", -"gov.tt", -"info.tt", -"mil.tt", -"name.tt", -"net.tt", -"org.tt", -"pro.tt", -"club.tw", -"com.tw", -"ebiz.tw", -"edu.tw", -"game.tw", -"gov.tw", -"idv.tw", -"mil.tw", -"net.tw", -"org.tw", -"ac.tz", -"co.tz", -"go.tz", -"hotel.tz", -"info.tz", -"me.tz", -"mil.tz", -"mobi.tz", -"ne.tz", -"or.tz", -"sc.tz", -"tv.tz", -"com.ua", -"edu.ua", -"gov.ua", -"in.ua", -"net.ua", -"org.ua", -"cherkassy.ua", -"cherkasy.ua", -"chernigov.ua", -"chernihiv.ua", -"chernivtsi.ua", -"chernovtsy.ua", -"ck.ua", -"cn.ua", -"cr.ua", -"crimea.ua", -"cv.ua", -"dn.ua", -"dnepropetrovsk.ua", -"dnipropetrovsk.ua", -"donetsk.ua", -"dp.ua", -"if.ua", -"ivano-frankivsk.ua", -"kh.ua", -"kharkiv.ua", -"kharkov.ua", -"kherson.ua", -"khmelnitskiy.ua", -"khmelnytskyi.ua", -"kiev.ua", -"kirovograd.ua", -"km.ua", -"kr.ua", -"kropyvnytskyi.ua", -"krym.ua", -"ks.ua", -"kv.ua", -"kyiv.ua", -"lg.ua", -"lt.ua", -"lugansk.ua", -"luhansk.ua", -"lutsk.ua", -"lv.ua", -"lviv.ua", -"mk.ua", -"mykolaiv.ua", -"nikolaev.ua", -"od.ua", -"odesa.ua", -"odessa.ua", -"pl.ua", -"poltava.ua", -"rivne.ua", -"rovno.ua", -"rv.ua", -"sb.ua", -"sebastopol.ua", -"sevastopol.ua", -"sm.ua", -"sumy.ua", -"te.ua", -"ternopil.ua", -"uz.ua", -"uzhgorod.ua", -"uzhhorod.ua", -"vinnica.ua", -"vinnytsia.ua", -"vn.ua", -"volyn.ua", -"yalta.ua", -"zakarpattia.ua", -"zaporizhzhe.ua", -"zaporizhzhia.ua", -"zhitomir.ua", -"zhytomyr.ua", -"zp.ua", -"zt.ua", -"ac.ug", -"co.ug", -"com.ug", -"edu.ug", -"go.ug", -"gov.ug", -"mil.ug", -"ne.ug", -"or.ug", -"org.ug", -"sc.ug", -"us.ug", -"ac.uk", -"co.uk", -"gov.uk", -"ltd.uk", -"me.uk", -"net.uk", -"nhs.uk", -"org.uk", -"plc.uk", -"police.uk", -"dni.us", -"isa.us", -"nsn.us", -"ak.us", -"al.us", -"ar.us", -"as.us", -"az.us", -"ca.us", -"co.us", -"ct.us", -"dc.us", -"de.us", -"fl.us", -"ga.us", -"gu.us", -"hi.us", -"ia.us", -"id.us", -"il.us", -"in.us", -"ks.us", -"ky.us", -"la.us", -"ma.us", -"md.us", -"me.us", -"mi.us", -"mn.us", -"mo.us", -"ms.us", -"mt.us", -"nc.us", -"nd.us", -"ne.us", -"nh.us", -"nj.us", -"nm.us", -"nv.us", -"ny.us", -"oh.us", -"ok.us", -"or.us", -"pa.us", -"pr.us", -"ri.us", -"sc.us", -"sd.us", -"tn.us", -"tx.us", -"ut.us", -"va.us", -"vi.us", -"vt.us", -"wa.us", -"wi.us", -"wv.us", -"wy.us", -"k12.ak.us", -"k12.al.us", -"k12.ar.us", -"k12.as.us", -"k12.az.us", -"k12.ca.us", -"k12.co.us", -"k12.ct.us", -"k12.dc.us", -"k12.fl.us", -"k12.ga.us", -"k12.gu.us", -"k12.ia.us", -"k12.id.us", -"k12.il.us", -"k12.in.us", -"k12.ks.us", -"k12.ky.us", -"k12.la.us", -"k12.ma.us", -"k12.md.us", -"k12.me.us", -"k12.mi.us", -"k12.mn.us", -"k12.mo.us", -"k12.ms.us", -"k12.mt.us", -"k12.nc.us", -"k12.ne.us", -"k12.nh.us", -"k12.nj.us", -"k12.nm.us", -"k12.nv.us", -"k12.ny.us", -"k12.oh.us", -"k12.ok.us", -"k12.or.us", -"k12.pa.us", -"k12.pr.us", -"k12.sc.us", -"k12.tn.us", -"k12.tx.us", -"k12.ut.us", -"k12.va.us", -"k12.vi.us", -"k12.vt.us", -"k12.wa.us", -"k12.wi.us", -"cc.ak.us", -"lib.ak.us", -"cc.al.us", -"lib.al.us", -"cc.ar.us", -"lib.ar.us", -"cc.as.us", -"lib.as.us", -"cc.az.us", -"lib.az.us", -"cc.ca.us", -"lib.ca.us", -"cc.co.us", -"lib.co.us", -"cc.ct.us", -"lib.ct.us", -"cc.dc.us", -"lib.dc.us", -"cc.de.us", -"cc.fl.us", -"lib.fl.us", -"cc.ga.us", -"lib.ga.us", -"cc.gu.us", -"lib.gu.us", -"cc.hi.us", -"lib.hi.us", -"cc.ia.us", -"lib.ia.us", -"cc.id.us", -"lib.id.us", -"cc.il.us", -"lib.il.us", -"cc.in.us", -"lib.in.us", -"cc.ks.us", -"lib.ks.us", -"cc.ky.us", -"lib.ky.us", -"cc.la.us", -"lib.la.us", -"cc.ma.us", -"lib.ma.us", -"cc.md.us", -"lib.md.us", -"cc.me.us", -"lib.me.us", -"cc.mi.us", -"lib.mi.us", -"cc.mn.us", -"lib.mn.us", -"cc.mo.us", -"lib.mo.us", -"cc.ms.us", -"cc.mt.us", -"lib.mt.us", -"cc.nc.us", -"lib.nc.us", -"cc.ne.us", -"lib.ne.us", -"cc.nh.us", -"lib.nh.us", -"cc.nj.us", -"lib.nj.us", -"cc.nm.us", -"lib.nm.us", -"cc.nv.us", -"lib.nv.us", -"cc.ny.us", -"lib.ny.us", -"cc.oh.us", -"lib.oh.us", -"cc.ok.us", -"lib.ok.us", -"cc.or.us", -"lib.or.us", -"cc.pa.us", -"lib.pa.us", -"cc.pr.us", -"lib.pr.us", -"cc.ri.us", -"lib.ri.us", -"cc.sc.us", -"lib.sc.us", -"cc.sd.us", -"lib.sd.us", -"cc.tn.us", -"lib.tn.us", -"cc.tx.us", -"lib.tx.us", -"cc.ut.us", -"lib.ut.us", -"cc.va.us", -"lib.va.us", -"cc.vi.us", -"lib.vi.us", -"cc.vt.us", -"lib.vt.us", -"cc.wa.us", -"lib.wa.us", -"cc.wi.us", -"lib.wi.us", -"cc.wv.us", -"cc.wy.us", -"k12.wy.us", -"lib.wy.us", -"chtr.k12.ma.us", -"paroch.k12.ma.us", -"pvt.k12.ma.us", -"ann-arbor.mi.us", -"cog.mi.us", -"dst.mi.us", -"eaton.mi.us", -"gen.mi.us", -"mus.mi.us", -"tec.mi.us", -"washtenaw.mi.us", -"com.uy", -"edu.uy", -"gub.uy", -"mil.uy", -"net.uy", -"org.uy", -"co.uz", -"com.uz", -"net.uz", -"org.uz", -"com.vc", -"edu.vc", -"gov.vc", -"mil.vc", -"net.vc", -"org.vc", -"arts.ve", -"bib.ve", -"co.ve", -"com.ve", -"e12.ve", -"edu.ve", -"emprende.ve", -"firm.ve", -"gob.ve", -"gov.ve", -"ia.ve", -"info.ve", -"int.ve", -"mil.ve", -"net.ve", -"nom.ve", -"org.ve", -"rar.ve", -"rec.ve", -"store.ve", -"tec.ve", -"web.ve", -"edu.vg", -"co.vi", -"com.vi", -"k12.vi", -"net.vi", -"org.vi", -"ac.vn", -"ai.vn", -"biz.vn", -"com.vn", -"edu.vn", -"gov.vn", -"health.vn", -"id.vn", -"info.vn", -"int.vn", -"io.vn", -"name.vn", -"net.vn", -"org.vn", -"pro.vn", -"angiang.vn", -"bacgiang.vn", -"backan.vn", -"baclieu.vn", -"bacninh.vn", -"baria-vungtau.vn", -"bentre.vn", -"binhdinh.vn", -"binhduong.vn", -"binhphuoc.vn", -"binhthuan.vn", -"camau.vn", -"cantho.vn", -"caobang.vn", -"daklak.vn", -"daknong.vn", -"danang.vn", -"dienbien.vn", -"dongnai.vn", -"dongthap.vn", -"gialai.vn", -"hagiang.vn", -"haiduong.vn", -"haiphong.vn", -"hanam.vn", -"hanoi.vn", -"hatinh.vn", -"haugiang.vn", -"hoabinh.vn", -"hue.vn", -"hungyen.vn", -"khanhhoa.vn", -"kiengiang.vn", -"kontum.vn", -"laichau.vn", -"lamdong.vn", -"langson.vn", -"laocai.vn", -"longan.vn", -"namdinh.vn", -"nghean.vn", -"ninhbinh.vn", -"ninhthuan.vn", -"phutho.vn", -"phuyen.vn", -"quangbinh.vn", -"quangnam.vn", -"quangngai.vn", -"quangninh.vn", -"quangtri.vn", -"soctrang.vn", -"sonla.vn", -"tayninh.vn", -"thaibinh.vn", -"thainguyen.vn", -"thanhhoa.vn", -"thanhphohochiminh.vn", -"thuathienhue.vn", -"tiengiang.vn", -"travinh.vn", -"tuyenquang.vn", -"vinhlong.vn", -"vinhphuc.vn", -"yenbai.vn", -"com.vu", -"edu.vu", -"net.vu", -"org.vu", -"com.ws", -"edu.ws", -"gov.ws", -"net.ws", -"org.ws", -"com.ye", -"edu.ye", -"gov.ye", -"mil.ye", -"net.ye", -"org.ye", -"ac.za", -"agric.za", -"alt.za", -"co.za", -"edu.za", -"gov.za", -"grondar.za", -"law.za", -"mil.za", -"net.za", -"ngo.za", -"nic.za", -"nis.za", -"nom.za", -"org.za", -"school.za", -"tm.za", -"web.za", -"ac.zm", -"biz.zm", -"co.zm", -"com.zm", -"edu.zm", -"gov.zm", -"info.zm", -"mil.zm", -"net.zm", -"org.zm", -"sch.zm", -"ac.zw", -"co.zw", -"gov.zw", -"mil.zw", -"org.zw", -"co.krd", -"edu.krd", -"art.pl", -"gliwice.pl", -"krakow.pl", -"poznan.pl", -"wroc.pl", -"zakopane.pl", -"cc.ua", -"inf.ua", -"ltd.ua", -"611.to", -"a2hosted.com", -"cpserver.com", -"activetrail.biz", -"adaptable.app", -"myaddr.dev", -"myaddr.io", -"dyn.addr.tools", -"myaddr.tools", -"adobeaemcloud.com", -"aem.live", -"hlx.live", -"adobeaemcloud.net", -"aem.network", -"aem.page", -"hlx.page", -"aem.reviews", -"adobeio-static.net", -"adobeioruntime.net", -"africa.com", -"beep.pl", -"aiven.app", -"aivencloud.com", -"akadns.net", -"akamai.net", -"akamai-staging.net", -"akamaiedge.net", -"akamaiedge-staging.net", -"akamaihd.net", -"akamaihd-staging.net", -"akamaiorigin.net", -"akamaiorigin-staging.net", -"akamaized.net", -"akamaized-staging.net", -"edgekey.net", -"edgekey-staging.net", -"edgesuite.net", -"edgesuite-staging.net", -"barsy.ca", -"alibabacloudcs.com", -"ms.fun", -"ms.show", -"kasserver.com", -"altervista.org", -"alwaysdata.net", -"myamaze.net", -"execute-api.cn-north-1.amazonaws.com.cn", -"execute-api.cn-northwest-1.amazonaws.com.cn", -"execute-api.af-south-1.amazonaws.com", -"execute-api.ap-east-1.amazonaws.com", -"execute-api.ap-northeast-1.amazonaws.com", -"execute-api.ap-northeast-2.amazonaws.com", -"execute-api.ap-northeast-3.amazonaws.com", -"execute-api.ap-south-1.amazonaws.com", -"execute-api.ap-south-2.amazonaws.com", -"execute-api.ap-southeast-1.amazonaws.com", -"execute-api.ap-southeast-2.amazonaws.com", -"execute-api.ap-southeast-3.amazonaws.com", -"execute-api.ap-southeast-4.amazonaws.com", -"execute-api.ap-southeast-5.amazonaws.com", -"execute-api.ca-central-1.amazonaws.com", -"execute-api.ca-west-1.amazonaws.com", -"execute-api.eu-central-1.amazonaws.com", -"execute-api.eu-central-2.amazonaws.com", -"execute-api.eu-north-1.amazonaws.com", -"execute-api.eu-south-1.amazonaws.com", -"execute-api.eu-south-2.amazonaws.com", -"execute-api.eu-west-1.amazonaws.com", -"execute-api.eu-west-2.amazonaws.com", -"execute-api.eu-west-3.amazonaws.com", -"execute-api.il-central-1.amazonaws.com", -"execute-api.me-central-1.amazonaws.com", -"execute-api.me-south-1.amazonaws.com", -"execute-api.sa-east-1.amazonaws.com", -"execute-api.us-east-1.amazonaws.com", -"execute-api.us-east-2.amazonaws.com", -"execute-api.us-gov-east-1.amazonaws.com", -"execute-api.us-gov-west-1.amazonaws.com", -"execute-api.us-west-1.amazonaws.com", -"execute-api.us-west-2.amazonaws.com", -"cloudfront.net", -"auth.af-south-1.amazoncognito.com", -"auth.ap-east-1.amazoncognito.com", -"auth.ap-northeast-1.amazoncognito.com", -"auth.ap-northeast-2.amazoncognito.com", -"auth.ap-northeast-3.amazoncognito.com", -"auth.ap-south-1.amazoncognito.com", -"auth.ap-south-2.amazoncognito.com", -"auth.ap-southeast-1.amazoncognito.com", -"auth.ap-southeast-2.amazoncognito.com", -"auth.ap-southeast-3.amazoncognito.com", -"auth.ap-southeast-4.amazoncognito.com", -"auth.ap-southeast-5.amazoncognito.com", -"auth.ap-southeast-7.amazoncognito.com", -"auth.ca-central-1.amazoncognito.com", -"auth.ca-west-1.amazoncognito.com", -"auth.eu-central-1.amazoncognito.com", -"auth.eu-central-2.amazoncognito.com", -"auth.eu-north-1.amazoncognito.com", -"auth.eu-south-1.amazoncognito.com", -"auth.eu-south-2.amazoncognito.com", -"auth.eu-west-1.amazoncognito.com", -"auth.eu-west-2.amazoncognito.com", -"auth.eu-west-3.amazoncognito.com", -"auth.il-central-1.amazoncognito.com", -"auth.me-central-1.amazoncognito.com", -"auth.me-south-1.amazoncognito.com", -"auth.mx-central-1.amazoncognito.com", -"auth.sa-east-1.amazoncognito.com", -"auth.us-east-1.amazoncognito.com", -"auth-fips.us-east-1.amazoncognito.com", -"auth.us-east-2.amazoncognito.com", -"auth-fips.us-east-2.amazoncognito.com", -"auth-fips.us-gov-east-1.amazoncognito.com", -"auth-fips.us-gov-west-1.amazoncognito.com", -"auth.us-west-1.amazoncognito.com", -"auth-fips.us-west-1.amazoncognito.com", -"auth.us-west-2.amazoncognito.com", -"auth-fips.us-west-2.amazoncognito.com", -"auth.cognito-idp.eusc-de-east-1.on.amazonwebservices.eu", -"us-east-1.amazonaws.com", -"emrappui-prod.cn-north-1.amazonaws.com.cn", -"emrnotebooks-prod.cn-north-1.amazonaws.com.cn", -"emrstudio-prod.cn-north-1.amazonaws.com.cn", -"emrappui-prod.cn-northwest-1.amazonaws.com.cn", -"emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn", -"emrstudio-prod.cn-northwest-1.amazonaws.com.cn", -"emrappui-prod.af-south-1.amazonaws.com", -"emrnotebooks-prod.af-south-1.amazonaws.com", -"emrstudio-prod.af-south-1.amazonaws.com", -"emrappui-prod.ap-east-1.amazonaws.com", -"emrnotebooks-prod.ap-east-1.amazonaws.com", -"emrstudio-prod.ap-east-1.amazonaws.com", -"emrappui-prod.ap-northeast-1.amazonaws.com", -"emrnotebooks-prod.ap-northeast-1.amazonaws.com", -"emrstudio-prod.ap-northeast-1.amazonaws.com", -"emrappui-prod.ap-northeast-2.amazonaws.com", -"emrnotebooks-prod.ap-northeast-2.amazonaws.com", -"emrstudio-prod.ap-northeast-2.amazonaws.com", -"emrappui-prod.ap-northeast-3.amazonaws.com", -"emrnotebooks-prod.ap-northeast-3.amazonaws.com", -"emrstudio-prod.ap-northeast-3.amazonaws.com", -"emrappui-prod.ap-south-1.amazonaws.com", -"emrnotebooks-prod.ap-south-1.amazonaws.com", -"emrstudio-prod.ap-south-1.amazonaws.com", -"emrappui-prod.ap-south-2.amazonaws.com", -"emrnotebooks-prod.ap-south-2.amazonaws.com", -"emrstudio-prod.ap-south-2.amazonaws.com", -"emrappui-prod.ap-southeast-1.amazonaws.com", -"emrnotebooks-prod.ap-southeast-1.amazonaws.com", -"emrstudio-prod.ap-southeast-1.amazonaws.com", -"emrappui-prod.ap-southeast-2.amazonaws.com", -"emrnotebooks-prod.ap-southeast-2.amazonaws.com", -"emrstudio-prod.ap-southeast-2.amazonaws.com", -"emrappui-prod.ap-southeast-3.amazonaws.com", -"emrnotebooks-prod.ap-southeast-3.amazonaws.com", -"emrstudio-prod.ap-southeast-3.amazonaws.com", -"emrappui-prod.ap-southeast-4.amazonaws.com", -"emrnotebooks-prod.ap-southeast-4.amazonaws.com", -"emrstudio-prod.ap-southeast-4.amazonaws.com", -"emrappui-prod.ca-central-1.amazonaws.com", -"emrnotebooks-prod.ca-central-1.amazonaws.com", -"emrstudio-prod.ca-central-1.amazonaws.com", -"emrappui-prod.ca-west-1.amazonaws.com", -"emrnotebooks-prod.ca-west-1.amazonaws.com", -"emrstudio-prod.ca-west-1.amazonaws.com", -"emrappui-prod.eu-central-1.amazonaws.com", -"emrnotebooks-prod.eu-central-1.amazonaws.com", -"emrstudio-prod.eu-central-1.amazonaws.com", -"emrappui-prod.eu-central-2.amazonaws.com", -"emrnotebooks-prod.eu-central-2.amazonaws.com", -"emrstudio-prod.eu-central-2.amazonaws.com", -"emrappui-prod.eu-north-1.amazonaws.com", -"emrnotebooks-prod.eu-north-1.amazonaws.com", -"emrstudio-prod.eu-north-1.amazonaws.com", -"emrappui-prod.eu-south-1.amazonaws.com", -"emrnotebooks-prod.eu-south-1.amazonaws.com", -"emrstudio-prod.eu-south-1.amazonaws.com", -"emrappui-prod.eu-south-2.amazonaws.com", -"emrnotebooks-prod.eu-south-2.amazonaws.com", -"emrstudio-prod.eu-south-2.amazonaws.com", -"emrappui-prod.eu-west-1.amazonaws.com", -"emrnotebooks-prod.eu-west-1.amazonaws.com", -"emrstudio-prod.eu-west-1.amazonaws.com", -"emrappui-prod.eu-west-2.amazonaws.com", -"emrnotebooks-prod.eu-west-2.amazonaws.com", -"emrstudio-prod.eu-west-2.amazonaws.com", -"emrappui-prod.eu-west-3.amazonaws.com", -"emrnotebooks-prod.eu-west-3.amazonaws.com", -"emrstudio-prod.eu-west-3.amazonaws.com", -"emrappui-prod.il-central-1.amazonaws.com", -"emrnotebooks-prod.il-central-1.amazonaws.com", -"emrstudio-prod.il-central-1.amazonaws.com", -"emrappui-prod.me-central-1.amazonaws.com", -"emrnotebooks-prod.me-central-1.amazonaws.com", -"emrstudio-prod.me-central-1.amazonaws.com", -"emrappui-prod.me-south-1.amazonaws.com", -"emrnotebooks-prod.me-south-1.amazonaws.com", -"emrstudio-prod.me-south-1.amazonaws.com", -"emrappui-prod.sa-east-1.amazonaws.com", -"emrnotebooks-prod.sa-east-1.amazonaws.com", -"emrstudio-prod.sa-east-1.amazonaws.com", -"emrappui-prod.us-east-1.amazonaws.com", -"emrnotebooks-prod.us-east-1.amazonaws.com", -"emrstudio-prod.us-east-1.amazonaws.com", -"emrappui-prod.us-east-2.amazonaws.com", -"emrnotebooks-prod.us-east-2.amazonaws.com", -"emrstudio-prod.us-east-2.amazonaws.com", -"emrappui-prod.us-gov-east-1.amazonaws.com", -"emrnotebooks-prod.us-gov-east-1.amazonaws.com", -"emrstudio-prod.us-gov-east-1.amazonaws.com", -"emrappui-prod.us-gov-west-1.amazonaws.com", -"emrnotebooks-prod.us-gov-west-1.amazonaws.com", -"emrstudio-prod.us-gov-west-1.amazonaws.com", -"emrappui-prod.us-west-1.amazonaws.com", -"emrnotebooks-prod.us-west-1.amazonaws.com", -"emrstudio-prod.us-west-1.amazonaws.com", -"emrappui-prod.us-west-2.amazonaws.com", -"emrnotebooks-prod.us-west-2.amazonaws.com", -"emrstudio-prod.us-west-2.amazonaws.com", -"s3.dualstack.cn-north-1.amazonaws.com.cn", -"s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn", -"s3-website.dualstack.cn-north-1.amazonaws.com.cn", -"s3.cn-north-1.amazonaws.com.cn", -"s3-accesspoint.cn-north-1.amazonaws.com.cn", -"s3-deprecated.cn-north-1.amazonaws.com.cn", -"s3-object-lambda.cn-north-1.amazonaws.com.cn", -"s3-website.cn-north-1.amazonaws.com.cn", -"s3.dualstack.cn-northwest-1.amazonaws.com.cn", -"s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn", -"s3.cn-northwest-1.amazonaws.com.cn", -"s3-accesspoint.cn-northwest-1.amazonaws.com.cn", -"s3-object-lambda.cn-northwest-1.amazonaws.com.cn", -"s3-website.cn-northwest-1.amazonaws.com.cn", -"s3.dualstack.af-south-1.amazonaws.com", -"s3-accesspoint.dualstack.af-south-1.amazonaws.com", -"s3-website.dualstack.af-south-1.amazonaws.com", -"s3.af-south-1.amazonaws.com", -"s3-accesspoint.af-south-1.amazonaws.com", -"s3-object-lambda.af-south-1.amazonaws.com", -"s3-website.af-south-1.amazonaws.com", -"s3.dualstack.ap-east-1.amazonaws.com", -"s3-accesspoint.dualstack.ap-east-1.amazonaws.com", -"s3.ap-east-1.amazonaws.com", -"s3-accesspoint.ap-east-1.amazonaws.com", -"s3-object-lambda.ap-east-1.amazonaws.com", -"s3-website.ap-east-1.amazonaws.com", -"s3.dualstack.ap-northeast-1.amazonaws.com", -"s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com", -"s3-website.dualstack.ap-northeast-1.amazonaws.com", -"s3.ap-northeast-1.amazonaws.com", -"s3-accesspoint.ap-northeast-1.amazonaws.com", -"s3-object-lambda.ap-northeast-1.amazonaws.com", -"s3-website.ap-northeast-1.amazonaws.com", -"s3.dualstack.ap-northeast-2.amazonaws.com", -"s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com", -"s3-website.dualstack.ap-northeast-2.amazonaws.com", -"s3.ap-northeast-2.amazonaws.com", -"s3-accesspoint.ap-northeast-2.amazonaws.com", -"s3-object-lambda.ap-northeast-2.amazonaws.com", -"s3-website.ap-northeast-2.amazonaws.com", -"s3.dualstack.ap-northeast-3.amazonaws.com", -"s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com", -"s3-website.dualstack.ap-northeast-3.amazonaws.com", -"s3.ap-northeast-3.amazonaws.com", -"s3-accesspoint.ap-northeast-3.amazonaws.com", -"s3-object-lambda.ap-northeast-3.amazonaws.com", -"s3-website.ap-northeast-3.amazonaws.com", -"s3.dualstack.ap-south-1.amazonaws.com", -"s3-accesspoint.dualstack.ap-south-1.amazonaws.com", -"s3-website.dualstack.ap-south-1.amazonaws.com", -"s3.ap-south-1.amazonaws.com", -"s3-accesspoint.ap-south-1.amazonaws.com", -"s3-object-lambda.ap-south-1.amazonaws.com", -"s3-website.ap-south-1.amazonaws.com", -"s3.dualstack.ap-south-2.amazonaws.com", -"s3-accesspoint.dualstack.ap-south-2.amazonaws.com", -"s3-website.dualstack.ap-south-2.amazonaws.com", -"s3.ap-south-2.amazonaws.com", -"s3-accesspoint.ap-south-2.amazonaws.com", -"s3-object-lambda.ap-south-2.amazonaws.com", -"s3-website.ap-south-2.amazonaws.com", -"s3.dualstack.ap-southeast-1.amazonaws.com", -"s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com", -"s3-website.dualstack.ap-southeast-1.amazonaws.com", -"s3.ap-southeast-1.amazonaws.com", -"s3-accesspoint.ap-southeast-1.amazonaws.com", -"s3-object-lambda.ap-southeast-1.amazonaws.com", -"s3-website.ap-southeast-1.amazonaws.com", -"s3.dualstack.ap-southeast-2.amazonaws.com", -"s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com", -"s3-website.dualstack.ap-southeast-2.amazonaws.com", -"s3.ap-southeast-2.amazonaws.com", -"s3-accesspoint.ap-southeast-2.amazonaws.com", -"s3-object-lambda.ap-southeast-2.amazonaws.com", -"s3-website.ap-southeast-2.amazonaws.com", -"s3.dualstack.ap-southeast-3.amazonaws.com", -"s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com", -"s3-website.dualstack.ap-southeast-3.amazonaws.com", -"s3.ap-southeast-3.amazonaws.com", -"s3-accesspoint.ap-southeast-3.amazonaws.com", -"s3-object-lambda.ap-southeast-3.amazonaws.com", -"s3-website.ap-southeast-3.amazonaws.com", -"s3.dualstack.ap-southeast-4.amazonaws.com", -"s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com", -"s3-website.dualstack.ap-southeast-4.amazonaws.com", -"s3.ap-southeast-4.amazonaws.com", -"s3-accesspoint.ap-southeast-4.amazonaws.com", -"s3-object-lambda.ap-southeast-4.amazonaws.com", -"s3-website.ap-southeast-4.amazonaws.com", -"s3.dualstack.ap-southeast-5.amazonaws.com", -"s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com", -"s3-website.dualstack.ap-southeast-5.amazonaws.com", -"s3.ap-southeast-5.amazonaws.com", -"s3-accesspoint.ap-southeast-5.amazonaws.com", -"s3-deprecated.ap-southeast-5.amazonaws.com", -"s3-object-lambda.ap-southeast-5.amazonaws.com", -"s3-website.ap-southeast-5.amazonaws.com", -"s3.dualstack.ca-central-1.amazonaws.com", -"s3-accesspoint.dualstack.ca-central-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com", -"s3-fips.dualstack.ca-central-1.amazonaws.com", -"s3-website.dualstack.ca-central-1.amazonaws.com", -"s3.ca-central-1.amazonaws.com", -"s3-accesspoint.ca-central-1.amazonaws.com", -"s3-accesspoint-fips.ca-central-1.amazonaws.com", -"s3-fips.ca-central-1.amazonaws.com", -"s3-object-lambda.ca-central-1.amazonaws.com", -"s3-website.ca-central-1.amazonaws.com", -"s3.dualstack.ca-west-1.amazonaws.com", -"s3-accesspoint.dualstack.ca-west-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com", -"s3-fips.dualstack.ca-west-1.amazonaws.com", -"s3-website.dualstack.ca-west-1.amazonaws.com", -"s3.ca-west-1.amazonaws.com", -"s3-accesspoint.ca-west-1.amazonaws.com", -"s3-accesspoint-fips.ca-west-1.amazonaws.com", -"s3-fips.ca-west-1.amazonaws.com", -"s3-object-lambda.ca-west-1.amazonaws.com", -"s3-website.ca-west-1.amazonaws.com", -"s3.dualstack.eu-central-1.amazonaws.com", -"s3-accesspoint.dualstack.eu-central-1.amazonaws.com", -"s3-website.dualstack.eu-central-1.amazonaws.com", -"s3.eu-central-1.amazonaws.com", -"s3-accesspoint.eu-central-1.amazonaws.com", -"s3-object-lambda.eu-central-1.amazonaws.com", -"s3-website.eu-central-1.amazonaws.com", -"s3.dualstack.eu-central-2.amazonaws.com", -"s3-accesspoint.dualstack.eu-central-2.amazonaws.com", -"s3-website.dualstack.eu-central-2.amazonaws.com", -"s3.eu-central-2.amazonaws.com", -"s3-accesspoint.eu-central-2.amazonaws.com", -"s3-object-lambda.eu-central-2.amazonaws.com", -"s3-website.eu-central-2.amazonaws.com", -"s3.dualstack.eu-north-1.amazonaws.com", -"s3-accesspoint.dualstack.eu-north-1.amazonaws.com", -"s3.eu-north-1.amazonaws.com", -"s3-accesspoint.eu-north-1.amazonaws.com", -"s3-object-lambda.eu-north-1.amazonaws.com", -"s3-website.eu-north-1.amazonaws.com", -"s3.dualstack.eu-south-1.amazonaws.com", -"s3-accesspoint.dualstack.eu-south-1.amazonaws.com", -"s3-website.dualstack.eu-south-1.amazonaws.com", -"s3.eu-south-1.amazonaws.com", -"s3-accesspoint.eu-south-1.amazonaws.com", -"s3-object-lambda.eu-south-1.amazonaws.com", -"s3-website.eu-south-1.amazonaws.com", -"s3.dualstack.eu-south-2.amazonaws.com", -"s3-accesspoint.dualstack.eu-south-2.amazonaws.com", -"s3-website.dualstack.eu-south-2.amazonaws.com", -"s3.eu-south-2.amazonaws.com", -"s3-accesspoint.eu-south-2.amazonaws.com", -"s3-object-lambda.eu-south-2.amazonaws.com", -"s3-website.eu-south-2.amazonaws.com", -"s3.dualstack.eu-west-1.amazonaws.com", -"s3-accesspoint.dualstack.eu-west-1.amazonaws.com", -"s3-website.dualstack.eu-west-1.amazonaws.com", -"s3.eu-west-1.amazonaws.com", -"s3-accesspoint.eu-west-1.amazonaws.com", -"s3-deprecated.eu-west-1.amazonaws.com", -"s3-object-lambda.eu-west-1.amazonaws.com", -"s3-website.eu-west-1.amazonaws.com", -"s3.dualstack.eu-west-2.amazonaws.com", -"s3-accesspoint.dualstack.eu-west-2.amazonaws.com", -"s3.eu-west-2.amazonaws.com", -"s3-accesspoint.eu-west-2.amazonaws.com", -"s3-object-lambda.eu-west-2.amazonaws.com", -"s3-website.eu-west-2.amazonaws.com", -"s3.dualstack.eu-west-3.amazonaws.com", -"s3-accesspoint.dualstack.eu-west-3.amazonaws.com", -"s3-website.dualstack.eu-west-3.amazonaws.com", -"s3.eu-west-3.amazonaws.com", -"s3-accesspoint.eu-west-3.amazonaws.com", -"s3-object-lambda.eu-west-3.amazonaws.com", -"s3-website.eu-west-3.amazonaws.com", -"s3.dualstack.il-central-1.amazonaws.com", -"s3-accesspoint.dualstack.il-central-1.amazonaws.com", -"s3-website.dualstack.il-central-1.amazonaws.com", -"s3.il-central-1.amazonaws.com", -"s3-accesspoint.il-central-1.amazonaws.com", -"s3-object-lambda.il-central-1.amazonaws.com", -"s3-website.il-central-1.amazonaws.com", -"s3.dualstack.me-central-1.amazonaws.com", -"s3-accesspoint.dualstack.me-central-1.amazonaws.com", -"s3-website.dualstack.me-central-1.amazonaws.com", -"s3.me-central-1.amazonaws.com", -"s3-accesspoint.me-central-1.amazonaws.com", -"s3-object-lambda.me-central-1.amazonaws.com", -"s3-website.me-central-1.amazonaws.com", -"s3.dualstack.me-south-1.amazonaws.com", -"s3-accesspoint.dualstack.me-south-1.amazonaws.com", -"s3.me-south-1.amazonaws.com", -"s3-accesspoint.me-south-1.amazonaws.com", -"s3-object-lambda.me-south-1.amazonaws.com", -"s3-website.me-south-1.amazonaws.com", -"s3.amazonaws.com", -"s3-1.amazonaws.com", -"s3-ap-east-1.amazonaws.com", -"s3-ap-northeast-1.amazonaws.com", -"s3-ap-northeast-2.amazonaws.com", -"s3-ap-northeast-3.amazonaws.com", -"s3-ap-south-1.amazonaws.com", -"s3-ap-southeast-1.amazonaws.com", -"s3-ap-southeast-2.amazonaws.com", -"s3-ca-central-1.amazonaws.com", -"s3-eu-central-1.amazonaws.com", -"s3-eu-north-1.amazonaws.com", -"s3-eu-west-1.amazonaws.com", -"s3-eu-west-2.amazonaws.com", -"s3-eu-west-3.amazonaws.com", -"s3-external-1.amazonaws.com", -"s3-fips-us-gov-east-1.amazonaws.com", -"s3-fips-us-gov-west-1.amazonaws.com", -"mrap.accesspoint.s3-global.amazonaws.com", -"s3-me-south-1.amazonaws.com", -"s3-sa-east-1.amazonaws.com", -"s3-us-east-2.amazonaws.com", -"s3-us-gov-east-1.amazonaws.com", -"s3-us-gov-west-1.amazonaws.com", -"s3-us-west-1.amazonaws.com", -"s3-us-west-2.amazonaws.com", -"s3-website-ap-northeast-1.amazonaws.com", -"s3-website-ap-southeast-1.amazonaws.com", -"s3-website-ap-southeast-2.amazonaws.com", -"s3-website-eu-west-1.amazonaws.com", -"s3-website-sa-east-1.amazonaws.com", -"s3-website-us-east-1.amazonaws.com", -"s3-website-us-gov-west-1.amazonaws.com", -"s3-website-us-west-1.amazonaws.com", -"s3-website-us-west-2.amazonaws.com", -"s3.dualstack.sa-east-1.amazonaws.com", -"s3-accesspoint.dualstack.sa-east-1.amazonaws.com", -"s3-website.dualstack.sa-east-1.amazonaws.com", -"s3.sa-east-1.amazonaws.com", -"s3-accesspoint.sa-east-1.amazonaws.com", -"s3-object-lambda.sa-east-1.amazonaws.com", -"s3-website.sa-east-1.amazonaws.com", -"s3.dualstack.us-east-1.amazonaws.com", -"s3-accesspoint.dualstack.us-east-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com", -"s3-fips.dualstack.us-east-1.amazonaws.com", -"s3-website.dualstack.us-east-1.amazonaws.com", -"s3.us-east-1.amazonaws.com", -"s3-accesspoint.us-east-1.amazonaws.com", -"s3-accesspoint-fips.us-east-1.amazonaws.com", -"s3-deprecated.us-east-1.amazonaws.com", -"s3-fips.us-east-1.amazonaws.com", -"s3-object-lambda.us-east-1.amazonaws.com", -"s3-website.us-east-1.amazonaws.com", -"s3.dualstack.us-east-2.amazonaws.com", -"s3-accesspoint.dualstack.us-east-2.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com", -"s3-fips.dualstack.us-east-2.amazonaws.com", -"s3-website.dualstack.us-east-2.amazonaws.com", -"s3.us-east-2.amazonaws.com", -"s3-accesspoint.us-east-2.amazonaws.com", -"s3-accesspoint-fips.us-east-2.amazonaws.com", -"s3-deprecated.us-east-2.amazonaws.com", -"s3-fips.us-east-2.amazonaws.com", -"s3-object-lambda.us-east-2.amazonaws.com", -"s3-website.us-east-2.amazonaws.com", -"s3.dualstack.us-gov-east-1.amazonaws.com", -"s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com", -"s3-fips.dualstack.us-gov-east-1.amazonaws.com", -"s3-website.dualstack.us-gov-east-1.amazonaws.com", -"s3.us-gov-east-1.amazonaws.com", -"s3-accesspoint.us-gov-east-1.amazonaws.com", -"s3-accesspoint-fips.us-gov-east-1.amazonaws.com", -"s3-fips.us-gov-east-1.amazonaws.com", -"s3-object-lambda.us-gov-east-1.amazonaws.com", -"s3-website.us-gov-east-1.amazonaws.com", -"s3.dualstack.us-gov-west-1.amazonaws.com", -"s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com", -"s3-fips.dualstack.us-gov-west-1.amazonaws.com", -"s3-website.dualstack.us-gov-west-1.amazonaws.com", -"s3.us-gov-west-1.amazonaws.com", -"s3-accesspoint.us-gov-west-1.amazonaws.com", -"s3-accesspoint-fips.us-gov-west-1.amazonaws.com", -"s3-fips.us-gov-west-1.amazonaws.com", -"s3-object-lambda.us-gov-west-1.amazonaws.com", -"s3-website.us-gov-west-1.amazonaws.com", -"s3.dualstack.us-west-1.amazonaws.com", -"s3-accesspoint.dualstack.us-west-1.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com", -"s3-fips.dualstack.us-west-1.amazonaws.com", -"s3-website.dualstack.us-west-1.amazonaws.com", -"s3.us-west-1.amazonaws.com", -"s3-accesspoint.us-west-1.amazonaws.com", -"s3-accesspoint-fips.us-west-1.amazonaws.com", -"s3-fips.us-west-1.amazonaws.com", -"s3-object-lambda.us-west-1.amazonaws.com", -"s3-website.us-west-1.amazonaws.com", -"s3.dualstack.us-west-2.amazonaws.com", -"s3-accesspoint.dualstack.us-west-2.amazonaws.com", -"s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com", -"s3-fips.dualstack.us-west-2.amazonaws.com", -"s3-website.dualstack.us-west-2.amazonaws.com", -"s3.us-west-2.amazonaws.com", -"s3-accesspoint.us-west-2.amazonaws.com", -"s3-accesspoint-fips.us-west-2.amazonaws.com", -"s3-deprecated.us-west-2.amazonaws.com", -"s3-fips.us-west-2.amazonaws.com", -"s3-object-lambda.us-west-2.amazonaws.com", -"s3-website.us-west-2.amazonaws.com", -"labeling.ap-northeast-1.sagemaker.aws", -"labeling.ap-northeast-2.sagemaker.aws", -"labeling.ap-south-1.sagemaker.aws", -"labeling.ap-southeast-1.sagemaker.aws", -"labeling.ap-southeast-2.sagemaker.aws", -"labeling.ca-central-1.sagemaker.aws", -"labeling.eu-central-1.sagemaker.aws", -"labeling.eu-west-1.sagemaker.aws", -"labeling.eu-west-2.sagemaker.aws", -"labeling.us-east-1.sagemaker.aws", -"labeling.us-east-2.sagemaker.aws", -"labeling.us-west-2.sagemaker.aws", -"notebook.af-south-1.sagemaker.aws", -"notebook.ap-east-1.sagemaker.aws", -"notebook.ap-northeast-1.sagemaker.aws", -"notebook.ap-northeast-2.sagemaker.aws", -"notebook.ap-northeast-3.sagemaker.aws", -"notebook.ap-south-1.sagemaker.aws", -"notebook.ap-south-2.sagemaker.aws", -"notebook.ap-southeast-1.sagemaker.aws", -"notebook.ap-southeast-2.sagemaker.aws", -"notebook.ap-southeast-3.sagemaker.aws", -"notebook.ap-southeast-4.sagemaker.aws", -"notebook.ca-central-1.sagemaker.aws", -"notebook-fips.ca-central-1.sagemaker.aws", -"notebook.ca-west-1.sagemaker.aws", -"notebook-fips.ca-west-1.sagemaker.aws", -"notebook.eu-central-1.sagemaker.aws", -"notebook.eu-central-2.sagemaker.aws", -"notebook.eu-north-1.sagemaker.aws", -"notebook.eu-south-1.sagemaker.aws", -"notebook.eu-south-2.sagemaker.aws", -"notebook.eu-west-1.sagemaker.aws", -"notebook.eu-west-2.sagemaker.aws", -"notebook.eu-west-3.sagemaker.aws", -"notebook.il-central-1.sagemaker.aws", -"notebook.me-central-1.sagemaker.aws", -"notebook.me-south-1.sagemaker.aws", -"notebook.sa-east-1.sagemaker.aws", -"notebook.us-east-1.sagemaker.aws", -"notebook-fips.us-east-1.sagemaker.aws", -"notebook.us-east-2.sagemaker.aws", -"notebook-fips.us-east-2.sagemaker.aws", -"notebook.us-gov-east-1.sagemaker.aws", -"notebook-fips.us-gov-east-1.sagemaker.aws", -"notebook.us-gov-west-1.sagemaker.aws", -"notebook-fips.us-gov-west-1.sagemaker.aws", -"notebook.us-west-1.sagemaker.aws", -"notebook-fips.us-west-1.sagemaker.aws", -"notebook.us-west-2.sagemaker.aws", -"notebook-fips.us-west-2.sagemaker.aws", -"notebook.cn-north-1.sagemaker.com.cn", -"notebook.cn-northwest-1.sagemaker.com.cn", -"studio.af-south-1.sagemaker.aws", -"studio.ap-east-1.sagemaker.aws", -"studio.ap-northeast-1.sagemaker.aws", -"studio.ap-northeast-2.sagemaker.aws", -"studio.ap-northeast-3.sagemaker.aws", -"studio.ap-south-1.sagemaker.aws", -"studio.ap-southeast-1.sagemaker.aws", -"studio.ap-southeast-2.sagemaker.aws", -"studio.ap-southeast-3.sagemaker.aws", -"studio.ca-central-1.sagemaker.aws", -"studio.eu-central-1.sagemaker.aws", -"studio.eu-central-2.sagemaker.aws", -"studio.eu-north-1.sagemaker.aws", -"studio.eu-south-1.sagemaker.aws", -"studio.eu-south-2.sagemaker.aws", -"studio.eu-west-1.sagemaker.aws", -"studio.eu-west-2.sagemaker.aws", -"studio.eu-west-3.sagemaker.aws", -"studio.il-central-1.sagemaker.aws", -"studio.me-central-1.sagemaker.aws", -"studio.me-south-1.sagemaker.aws", -"studio.sa-east-1.sagemaker.aws", -"studio.us-east-1.sagemaker.aws", -"studio.us-east-2.sagemaker.aws", -"studio.us-gov-east-1.sagemaker.aws", -"studio-fips.us-gov-east-1.sagemaker.aws", -"studio.us-gov-west-1.sagemaker.aws", -"studio-fips.us-gov-west-1.sagemaker.aws", -"studio.us-west-1.sagemaker.aws", -"studio.us-west-2.sagemaker.aws", -"studio.cn-north-1.sagemaker.com.cn", -"studio.cn-northwest-1.sagemaker.com.cn", -"analytics-gateway.ap-northeast-1.amazonaws.com", -"analytics-gateway.ap-northeast-2.amazonaws.com", -"analytics-gateway.ap-south-1.amazonaws.com", -"analytics-gateway.ap-southeast-1.amazonaws.com", -"analytics-gateway.ap-southeast-2.amazonaws.com", -"analytics-gateway.eu-central-1.amazonaws.com", -"analytics-gateway.eu-west-1.amazonaws.com", -"analytics-gateway.us-east-1.amazonaws.com", -"analytics-gateway.us-east-2.amazonaws.com", -"analytics-gateway.us-west-2.amazonaws.com", -"amplifyapp.com", -"webview-assets.aws-cloud9.af-south-1.amazonaws.com", -"vfs.cloud9.af-south-1.amazonaws.com", -"webview-assets.cloud9.af-south-1.amazonaws.com", -"webview-assets.aws-cloud9.ap-east-1.amazonaws.com", -"vfs.cloud9.ap-east-1.amazonaws.com", -"webview-assets.cloud9.ap-east-1.amazonaws.com", -"webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com", -"vfs.cloud9.ap-northeast-1.amazonaws.com", -"webview-assets.cloud9.ap-northeast-1.amazonaws.com", -"webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com", -"vfs.cloud9.ap-northeast-2.amazonaws.com", -"webview-assets.cloud9.ap-northeast-2.amazonaws.com", -"webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com", -"vfs.cloud9.ap-northeast-3.amazonaws.com", -"webview-assets.cloud9.ap-northeast-3.amazonaws.com", -"webview-assets.aws-cloud9.ap-south-1.amazonaws.com", -"vfs.cloud9.ap-south-1.amazonaws.com", -"webview-assets.cloud9.ap-south-1.amazonaws.com", -"webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com", -"vfs.cloud9.ap-southeast-1.amazonaws.com", -"webview-assets.cloud9.ap-southeast-1.amazonaws.com", -"webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com", -"vfs.cloud9.ap-southeast-2.amazonaws.com", -"webview-assets.cloud9.ap-southeast-2.amazonaws.com", -"webview-assets.aws-cloud9.ca-central-1.amazonaws.com", -"vfs.cloud9.ca-central-1.amazonaws.com", -"webview-assets.cloud9.ca-central-1.amazonaws.com", -"webview-assets.aws-cloud9.eu-central-1.amazonaws.com", -"vfs.cloud9.eu-central-1.amazonaws.com", -"webview-assets.cloud9.eu-central-1.amazonaws.com", -"webview-assets.aws-cloud9.eu-north-1.amazonaws.com", -"vfs.cloud9.eu-north-1.amazonaws.com", -"webview-assets.cloud9.eu-north-1.amazonaws.com", -"webview-assets.aws-cloud9.eu-south-1.amazonaws.com", -"vfs.cloud9.eu-south-1.amazonaws.com", -"webview-assets.cloud9.eu-south-1.amazonaws.com", -"webview-assets.aws-cloud9.eu-west-1.amazonaws.com", -"vfs.cloud9.eu-west-1.amazonaws.com", -"webview-assets.cloud9.eu-west-1.amazonaws.com", -"webview-assets.aws-cloud9.eu-west-2.amazonaws.com", -"vfs.cloud9.eu-west-2.amazonaws.com", -"webview-assets.cloud9.eu-west-2.amazonaws.com", -"webview-assets.aws-cloud9.eu-west-3.amazonaws.com", -"vfs.cloud9.eu-west-3.amazonaws.com", -"webview-assets.cloud9.eu-west-3.amazonaws.com", -"webview-assets.aws-cloud9.il-central-1.amazonaws.com", -"vfs.cloud9.il-central-1.amazonaws.com", -"webview-assets.aws-cloud9.me-south-1.amazonaws.com", -"vfs.cloud9.me-south-1.amazonaws.com", -"webview-assets.cloud9.me-south-1.amazonaws.com", -"webview-assets.aws-cloud9.sa-east-1.amazonaws.com", -"vfs.cloud9.sa-east-1.amazonaws.com", -"webview-assets.cloud9.sa-east-1.amazonaws.com", -"webview-assets.aws-cloud9.us-east-1.amazonaws.com", -"vfs.cloud9.us-east-1.amazonaws.com", -"webview-assets.cloud9.us-east-1.amazonaws.com", -"webview-assets.aws-cloud9.us-east-2.amazonaws.com", -"vfs.cloud9.us-east-2.amazonaws.com", -"webview-assets.cloud9.us-east-2.amazonaws.com", -"webview-assets.aws-cloud9.us-west-1.amazonaws.com", -"vfs.cloud9.us-west-1.amazonaws.com", -"webview-assets.cloud9.us-west-1.amazonaws.com", -"webview-assets.aws-cloud9.us-west-2.amazonaws.com", -"vfs.cloud9.us-west-2.amazonaws.com", -"webview-assets.cloud9.us-west-2.amazonaws.com", -"awsapps.com", -"cn-north-1.eb.amazonaws.com.cn", -"cn-northwest-1.eb.amazonaws.com.cn", -"elasticbeanstalk.com", -"af-south-1.elasticbeanstalk.com", -"ap-east-1.elasticbeanstalk.com", -"ap-northeast-1.elasticbeanstalk.com", -"ap-northeast-2.elasticbeanstalk.com", -"ap-northeast-3.elasticbeanstalk.com", -"ap-south-1.elasticbeanstalk.com", -"ap-southeast-1.elasticbeanstalk.com", -"ap-southeast-2.elasticbeanstalk.com", -"ap-southeast-3.elasticbeanstalk.com", -"ap-southeast-5.elasticbeanstalk.com", -"ap-southeast-7.elasticbeanstalk.com", -"ca-central-1.elasticbeanstalk.com", -"eu-central-1.elasticbeanstalk.com", -"eu-north-1.elasticbeanstalk.com", -"eu-south-1.elasticbeanstalk.com", -"eu-south-2.elasticbeanstalk.com", -"eu-west-1.elasticbeanstalk.com", -"eu-west-2.elasticbeanstalk.com", -"eu-west-3.elasticbeanstalk.com", -"il-central-1.elasticbeanstalk.com", -"me-central-1.elasticbeanstalk.com", -"me-south-1.elasticbeanstalk.com", -"sa-east-1.elasticbeanstalk.com", -"us-east-1.elasticbeanstalk.com", -"us-east-2.elasticbeanstalk.com", -"us-gov-east-1.elasticbeanstalk.com", -"us-gov-west-1.elasticbeanstalk.com", -"us-west-1.elasticbeanstalk.com", -"us-west-2.elasticbeanstalk.com", -"awsglobalaccelerator.com", -"lambda-url.af-south-1.on.aws", -"lambda-url.ap-east-1.on.aws", -"lambda-url.ap-northeast-1.on.aws", -"lambda-url.ap-northeast-2.on.aws", -"lambda-url.ap-northeast-3.on.aws", -"lambda-url.ap-south-1.on.aws", -"lambda-url.ap-southeast-1.on.aws", -"lambda-url.ap-southeast-2.on.aws", -"lambda-url.ap-southeast-3.on.aws", -"lambda-url.ca-central-1.on.aws", -"lambda-url.eu-central-1.on.aws", -"lambda-url.eu-north-1.on.aws", -"lambda-url.eu-south-1.on.aws", -"lambda-url.eu-west-1.on.aws", -"lambda-url.eu-west-2.on.aws", -"lambda-url.eu-west-3.on.aws", -"lambda-url.me-south-1.on.aws", -"lambda-url.sa-east-1.on.aws", -"lambda-url.us-east-1.on.aws", -"lambda-url.us-east-2.on.aws", -"lambda-url.us-west-1.on.aws", -"lambda-url.us-west-2.on.aws", -"transfer-webapp.af-south-1.on.aws", -"transfer-webapp.ap-east-1.on.aws", -"transfer-webapp.ap-northeast-1.on.aws", -"transfer-webapp.ap-northeast-2.on.aws", -"transfer-webapp.ap-northeast-3.on.aws", -"transfer-webapp.ap-south-1.on.aws", -"transfer-webapp.ap-south-2.on.aws", -"transfer-webapp.ap-southeast-1.on.aws", -"transfer-webapp.ap-southeast-2.on.aws", -"transfer-webapp.ap-southeast-3.on.aws", -"transfer-webapp.ap-southeast-4.on.aws", -"transfer-webapp.ap-southeast-5.on.aws", -"transfer-webapp.ap-southeast-7.on.aws", -"transfer-webapp.ca-central-1.on.aws", -"transfer-webapp.ca-west-1.on.aws", -"transfer-webapp.eu-central-1.on.aws", -"transfer-webapp.eu-central-2.on.aws", -"transfer-webapp.eu-north-1.on.aws", -"transfer-webapp.eu-south-1.on.aws", -"transfer-webapp.eu-south-2.on.aws", -"transfer-webapp.eu-west-1.on.aws", -"transfer-webapp.eu-west-2.on.aws", -"transfer-webapp.eu-west-3.on.aws", -"transfer-webapp.il-central-1.on.aws", -"transfer-webapp.me-central-1.on.aws", -"transfer-webapp.me-south-1.on.aws", -"transfer-webapp.mx-central-1.on.aws", -"transfer-webapp.sa-east-1.on.aws", -"transfer-webapp.us-east-1.on.aws", -"transfer-webapp.us-east-2.on.aws", -"transfer-webapp.us-gov-east-1.on.aws", -"transfer-webapp-fips.us-gov-east-1.on.aws", -"transfer-webapp.us-gov-west-1.on.aws", -"transfer-webapp-fips.us-gov-west-1.on.aws", -"transfer-webapp.us-west-1.on.aws", -"transfer-webapp.us-west-2.on.aws", -"transfer-webapp.cn-north-1.on.amazonwebservices.com.cn", -"transfer-webapp.cn-northwest-1.on.amazonwebservices.com.cn", -"eero.online", -"eero-stage.online", -"opentunnel.xyz", -"antagonist.cloud", -"claude.app", -"apigee.io", -"panel.dev", -"siiites.com", -"int.apple", -"appspacehosted.com", -"appspaceusercontent.com", -"appudo.net", -"appwrite.global", -"appwrite.network", -"on-aptible.com", -"f5.si", -"arvanedge.ir", -"user.aseinet.ne.jp", -"gv.vc", -"d.gv.vc", -"user.party.eus", -"pimienta.org", -"poivron.org", -"potager.org", -"sweetpepper.org", -"myasustor.com", -"cdn.prod.atlassian-dev.net", -"myfritz.link", -"myfritz.net", -"ecommerce-shop.pl", -"b-data.io", -"balena-devices.com", -"base.ec", -"official.ec", -"buyshop.jp", -"fashionstore.jp", -"handcrafted.jp", -"kawaiishop.jp", -"supersale.jp", -"theshop.jp", -"shopselect.net", -"base.shop", -"beagleboard.io", -"bearblog.dev", -"pages.gay", -"bnr.la", -"bitbucket.io", -"blackbaudcdn.net", -"of.je", -"square.site", -"bluebite.io", -"boomla.net", -"boutir.com", -"boxfuse.io", -"square7.ch", -"bplaced.com", -"bplaced.de", -"square7.de", -"bplaced.net", -"square7.net", -"brave.app", -"brave.dev", -"brave.io", -"shop.brendly.ba", -"shop.brendly.hr", -"shop.brendly.rs", -"browsersafetymark.io", -"radio.am", -"radio.fm", -"cdn.bubble.io", -"bubbleapps.io", -"cafjs.com", -"canva-apps.cn", -"my.canvasite.cn", -"khsj.cn", -"canva-apps.com", -"canva-hosted-embed.com", -"canvacode.com", -"rice-labs.com", -"canva.link", -"canva.run", -"my.canva.site", -"drr.ac", -"uwu.ai", -"carrd.co", -"crd.co", -"ju.mp", -"api.gov.uk", -"cdn77-storage.com", -"rsc.contentproxy9.cz", -"r.cdn77.net", -"cdn77-ssl.net", -"c.cdn77.org", -"rsc.cdn77.org", -"ssl.origin.cdn77-secure.org", -"za.bz", -"br.com", -"cn.com", -"de.com", -"eu.com", -"jpn.com", -"mex.com", -"ru.com", -"sa.com", -"uk.com", -"us.com", -"za.com", -"com.de", -"gb.net", -"hu.net", -"jp.net", -"se.net", -"uk.net", -"ae.org", -"com.se", -"cx.ua", -"discourse.diy", -"discourse.group", -"discourse.team", -"clerk.app", -"clerkstage.app", -"cleverapps.cc", -"cleverapps.io", -"cleverapps.tech", -"clickrising.net", -"cloudns.asia", -"cloudns.be", -"cloud-ip.biz", -"cloudns.biz", -"cloud-ip.cc", -"cloudns.cc", -"cloudns.ch", -"cloudns.cl", -"cloudns.club", -"abrdns.com", -"dnsabr.com", -"ip-ddns.com", -"cloudns.cx", -"cloudns.eu", -"cloudns.in", -"cloudns.info", -"ddns-ip.net", -"dns-cloud.net", -"dns-dynamic.net", -"cloudns.nz", -"cloudns.org", -"ip-dynamic.org", -"cloudns.ph", -"cloudns.pro", -"cloudns.pw", -"cloudns.us", -"c66.me", -"cloud66.ws", -"jdevcloud.com", -"wpdevcloud.com", -"cloudaccess.host", -"freesite.host", -"cloudaccess.net", -"cloudbeesusercontent.io", -"cloudflare.app", -"cf-ipfs.com", -"cloudflare-ipfs.com", -"trycloudflare.com", -"pages.dev", -"r2.dev", -"workers.dev", -"cloudflare.net", -"cdn.cloudflare.net", -"cdn.cloudflareanycast.net", -"cdn.cloudflarecn.net", -"cdn.cloudflareglobal.net", -"cust.cloudscale.ch", -"objects.lpg.cloudscale.ch", -"objects.rma.cloudscale.ch", -"lpg.objectstorage.ch", -"rma.objectstorage.ch", -"wnext.app", -"cnpy.gdn", -"co.ca", -"co.com", -"sch.ac", -"dev.cv", -"store.cv", -"codeberg.page", -"csb.app", -"preview.csb.app", -"co.nl", -"co.no", -"webhosting.be", -"prvw.eu", -"hosting-cluster.nl", -"ctfcloud.net", -"convex.app", -"convex.cloud", -"eu-west-1.convex.cloud", -"us-east-1.convex.cloud", -"convex.site", -"eu-west-1.convex.site", -"us-east-1.convex.site", -"ac.ru", -"edu.ru", -"gov.ru", -"int.ru", -"mil.ru", -"corespeed.app", -"dyn.cosidns.de", -"dnsupdater.de", -"dynamisches-dns.de", -"internet-dns.de", -"l-o-g-i-n.de", -"dynamic-dns.info", -"feste-ip.net", -"knx-server.net", -"static-access.net", -"craft.me", -"realm.cz", -"cfolks.pl", -"cyon.link", -"cyon.site", -"biz.dk", -"co.dk", -"firm.dk", -"reg.dk", -"store.dk", -"dyndns.dappnode.io", -"builtwithdark.com", -"darklang.io", -"demo.datadetect.com", -"instance.datadetect.com", -"edgestack.me", -"dattolocal.com", -"dattorelay.com", -"dattoweb.com", -"mydatto.com", -"dattolocal.net", -"mydatto.net", -"ddnss.de", -"dyn.ddnss.de", -"dyndns.ddnss.de", -"dyn-ip24.de", -"dyndns1.de", -"home-webserver.de", -"dyn.home-webserver.de", -"myhome-server.de", -"ddnss.org", -"debian.net", -"definima.io", -"definima.net", -"deno.dev", -"deno-staging.dev", -"deno.net", -"sandbox.deno.net", -"deployagent.com", -"piebox.site", -"deployagent.space", -"dedyn.io", -"deuxfleurs.eu", -"deuxfleurs.page", -"d6.ply.gg", -"joinmc.link", -"playit.plus", -"with.playit.plus", -"icp0.io", -"icp1.io", -"caffeine.site", -"caffeine.xyz", -"mybox.company", -"intouch.email", -"mybox.me", -"mybox.page", -"dfirma.pl", -"dkonto.pl", -"you2.pl", -"ondigitalocean.app", -"qzz.io", -"us.kg", -"xx.kg", -"dpdns.org", -"discordsays.com", -"discordsez.com", -"jozi.biz", -"ccwu.cc", -"cc.cd", -"us.ci", -"de5.net", -"dnshome.at", -"resolve.bar", -"ddns.berlin", -"dnshome.cloud", -"ddnssec.de", -"dnshome.de", -"dyndnssec.de", -"heimdns.de", -"srvdns.de", -"dnshome.eu", -"dnshome.it", -"dyn.now", -"heimdns.online", -"ddns.wtf", -"online.th", -"shop.th", -"co.scot", -"me.scot", -"org.scot", -"drayddns.com", -"shoparena.pl", -"dreamhosters.com", -"durumis.com", -"duckdns.org", -"dy.fi", -"tunk.org", -"dyndns.biz", -"for-better.biz", -"for-more.biz", -"for-some.biz", -"for-the.biz", -"selfip.biz", -"webhop.biz", -"ftpaccess.cc", -"game-server.cc", -"myphotos.cc", -"scrapping.cc", -"blogdns.com", -"cechire.com", -"dnsalias.com", -"dnsdojo.com", -"doesntexist.com", -"dontexist.com", -"doomdns.com", -"dyn-o-saur.com", -"dynalias.com", -"dyndns-at-home.com", -"dyndns-at-work.com", -"dyndns-blog.com", -"dyndns-free.com", -"dyndns-home.com", -"dyndns-ip.com", -"dyndns-mail.com", -"dyndns-office.com", -"dyndns-pics.com", -"dyndns-remote.com", -"dyndns-server.com", -"dyndns-web.com", -"dyndns-wiki.com", -"dyndns-work.com", -"est-a-la-maison.com", -"est-a-la-masion.com", -"est-le-patron.com", -"est-mon-blogueur.com", -"from-ak.com", -"from-al.com", -"from-ar.com", -"from-ca.com", -"from-ct.com", -"from-dc.com", -"from-de.com", -"from-fl.com", -"from-ga.com", -"from-hi.com", -"from-ia.com", -"from-id.com", -"from-il.com", -"from-in.com", -"from-ks.com", -"from-ky.com", -"from-ma.com", -"from-md.com", -"from-mi.com", -"from-mn.com", -"from-mo.com", -"from-ms.com", -"from-mt.com", -"from-nc.com", -"from-nd.com", -"from-ne.com", -"from-nh.com", -"from-nj.com", -"from-nm.com", -"from-nv.com", -"from-oh.com", -"from-ok.com", -"from-or.com", -"from-pa.com", -"from-pr.com", -"from-ri.com", -"from-sc.com", -"from-sd.com", -"from-tn.com", -"from-tx.com", -"from-ut.com", -"from-va.com", -"from-vt.com", -"from-wa.com", -"from-wi.com", -"from-wv.com", -"from-wy.com", -"getmyip.com", -"gotdns.com", -"hobby-site.com", -"homelinux.com", -"homeunix.com", -"iamallama.com", -"is-a-anarchist.com", -"is-a-blogger.com", -"is-a-bookkeeper.com", -"is-a-bulls-fan.com", -"is-a-caterer.com", -"is-a-chef.com", -"is-a-conservative.com", -"is-a-cpa.com", -"is-a-cubicle-slave.com", -"is-a-democrat.com", -"is-a-designer.com", -"is-a-doctor.com", -"is-a-financialadvisor.com", -"is-a-geek.com", -"is-a-green.com", -"is-a-guru.com", -"is-a-hard-worker.com", -"is-a-hunter.com", -"is-a-landscaper.com", -"is-a-lawyer.com", -"is-a-liberal.com", -"is-a-libertarian.com", -"is-a-llama.com", -"is-a-musician.com", -"is-a-nascarfan.com", -"is-a-nurse.com", -"is-a-painter.com", -"is-a-personaltrainer.com", -"is-a-photographer.com", -"is-a-player.com", -"is-a-republican.com", -"is-a-rockstar.com", -"is-a-socialist.com", -"is-a-student.com", -"is-a-teacher.com", -"is-a-techie.com", -"is-a-therapist.com", -"is-an-accountant.com", -"is-an-actor.com", -"is-an-actress.com", -"is-an-anarchist.com", -"is-an-artist.com", -"is-an-engineer.com", -"is-an-entertainer.com", -"is-certified.com", -"is-gone.com", -"is-into-anime.com", -"is-into-cars.com", -"is-into-cartoons.com", -"is-into-games.com", -"is-leet.com", -"is-not-certified.com", -"is-slick.com", -"is-uberleet.com", -"is-with-theband.com", -"isa-geek.com", -"isa-hockeynut.com", -"issmarterthanyou.com", -"likes-pie.com", -"likescandy.com", -"neat-url.com", -"saves-the-whales.com", -"selfip.com", -"sells-for-less.com", -"sells-for-u.com", -"servebbs.com", -"simple-url.com", -"space-to-rent.com", -"teaches-yoga.com", -"writesthisblog.com", -"ath.cx", -"fuettertdasnetz.de", -"isteingeek.de", -"istmein.de", -"lebtimnetz.de", -"leitungsen.de", -"traeumtgerade.de", -"barrel-of-knowledge.info", -"barrell-of-knowledge.info", -"dyndns.info", -"for-our.info", -"groks-the.info", -"groks-this.info", -"here-for-more.info", -"knowsitall.info", -"selfip.info", -"webhop.info", -"forgot.her.name", -"forgot.his.name", -"at-band-camp.net", -"blogdns.net", -"broke-it.net", -"buyshouses.net", -"dnsalias.net", -"dnsdojo.net", -"does-it.net", -"dontexist.net", -"dynalias.net", -"dynathome.net", -"endofinternet.net", -"from-az.net", -"from-co.net", -"from-la.net", -"from-ny.net", -"gets-it.net", -"ham-radio-op.net", -"homeftp.net", -"homeip.net", -"homelinux.net", -"homeunix.net", -"in-the-band.net", -"is-a-chef.net", -"is-a-geek.net", -"isa-geek.net", -"kicks-ass.net", -"office-on-the.net", -"podzone.net", -"scrapper-site.net", -"selfip.net", -"sells-it.net", -"servebbs.net", -"serveftp.net", -"thruhere.net", -"webhop.net", -"merseine.nu", -"mine.nu", -"shacknet.nu", -"blogdns.org", -"blogsite.org", -"boldlygoingnowhere.org", -"dnsalias.org", -"dnsdojo.org", -"doesntexist.org", -"dontexist.org", -"doomdns.org", -"dvrdns.org", -"dynalias.org", -"dyndns.org", -"go.dyndns.org", -"home.dyndns.org", -"endofinternet.org", -"endoftheinternet.org", -"from-me.org", -"game-host.org", -"gotdns.org", -"hobby-site.org", -"homedns.org", -"homeftp.org", -"homelinux.org", -"homeunix.org", -"is-a-bruinsfan.org", -"is-a-candidate.org", -"is-a-celticsfan.org", -"is-a-chef.org", -"is-a-geek.org", -"is-a-knight.org", -"is-a-linux-user.org", -"is-a-patsfan.org", -"is-a-soxfan.org", -"is-found.org", -"is-lost.org", -"is-saved.org", -"is-very-bad.org", -"is-very-evil.org", -"is-very-good.org", -"is-very-nice.org", -"is-very-sweet.org", -"isa-geek.org", -"kicks-ass.org", -"misconfused.org", -"podzone.org", -"readmyblog.org", -"selfip.org", -"sellsyourhome.org", -"servebbs.org", -"serveftp.org", -"servegame.org", -"stuff-4-sale.org", -"webhop.org", -"better-than.tv", -"dyndns.tv", -"on-the-web.tv", -"worse-than.tv", -"is-by.us", -"land-4-sale.us", -"stuff-4-sale.us", -"dyndns.ws", -"mypets.ws", -"1cooldns.com", -"bumbleshrimp.com", -"ddnsfree.com", -"ddnsgeek.com", -"ddnsguru.com", -"dynuddns.com", -"dynuhosting.com", -"giize.com", -"gleeze.com", -"kozow.com", -"loseyourip.com", -"ooguy.com", -"pivohosting.com", -"theworkpc.com", -"wiredbladehosting.com", -"casacam.net", -"dynu.net", -"dynuddns.net", -"mysynology.net", -"opik.net", -"spryt.net", -"accesscam.org", -"camdvr.org", -"freeddns.org", -"mywire.org", -"roxa.org", -"webredirect.org", -"myddns.rocks", -"dynv6.net", -"e4.cz", -"easypanel.app", -"easypanel.host", -"twmail.cc", -"twmail.net", -"twmail.org", -"mymailer.com.tw", -"url.tw", -"at.emf.camp", -"rt.ht", -"elementor.cloud", -"elementor.cool", -"emergent.cloud", -"preview.emergentagent.com", -"emergent.host", -"mytuleap.com", -"tuleap-partners.com", -"encr.app", -"frontend.encr.app", -"encoreapi.com", -"lp.dev", -"api.lp.dev", -"objects.lp.dev", -"eu.encoway.cloud", -"eu.org", -"al.eu.org", -"asso.eu.org", -"at.eu.org", -"au.eu.org", -"be.eu.org", -"bg.eu.org", -"ca.eu.org", -"cd.eu.org", -"ch.eu.org", -"cn.eu.org", -"cy.eu.org", -"cz.eu.org", -"de.eu.org", -"dk.eu.org", -"edu.eu.org", -"ee.eu.org", -"es.eu.org", -"fi.eu.org", -"fr.eu.org", -"gr.eu.org", -"hr.eu.org", -"hu.eu.org", -"ie.eu.org", -"il.eu.org", -"in.eu.org", -"int.eu.org", -"is.eu.org", -"it.eu.org", -"jp.eu.org", -"kr.eu.org", -"lt.eu.org", -"lu.eu.org", -"lv.eu.org", -"me.eu.org", -"mk.eu.org", -"mt.eu.org", -"my.eu.org", -"net.eu.org", -"ng.eu.org", -"nl.eu.org", -"no.eu.org", -"nz.eu.org", -"pl.eu.org", -"pt.eu.org", -"ro.eu.org", -"ru.eu.org", -"se.eu.org", -"si.eu.org", -"sk.eu.org", -"tr.eu.org", -"uk.eu.org", -"us.eu.org", -"eurodir.ru", -"eu-1.evennode.com", -"eu-2.evennode.com", -"eu-3.evennode.com", -"eu-4.evennode.com", -"us-1.evennode.com", -"us-2.evennode.com", -"us-3.evennode.com", -"us-4.evennode.com", -"relay.evervault.app", -"relay.evervault.dev", -"exe.xyz", -"expo.app", -"on.expo.app", -"staging.expo.app", -"on.staging.expo.app", -"fspages.org", -"ru.net", -"adygeya.ru", -"bashkiria.ru", -"bir.ru", -"cbg.ru", -"com.ru", -"dagestan.ru", -"grozny.ru", -"kalmykia.ru", -"kustanai.ru", -"marine.ru", -"mordovia.ru", -"msk.ru", -"mytis.ru", -"nalchik.ru", -"nov.ru", -"pyatigorsk.ru", -"spb.ru", -"vladikavkaz.ru", -"vladimir.ru", -"abkhazia.su", -"adygeya.su", -"aktyubinsk.su", -"arkhangelsk.su", -"armenia.su", -"ashgabad.su", -"azerbaijan.su", -"balashov.su", -"bashkiria.su", -"bryansk.su", -"bukhara.su", -"chimkent.su", -"dagestan.su", -"east-kazakhstan.su", -"exnet.su", -"georgia.su", -"grozny.su", -"ivanovo.su", -"jambyl.su", -"kalmykia.su", -"kaluga.su", -"karacol.su", -"karaganda.su", -"karelia.su", -"khakassia.su", -"krasnodar.su", -"kurgan.su", -"kustanai.su", -"lenug.su", -"mangyshlak.su", -"mordovia.su", -"msk.su", -"murmansk.su", -"nalchik.su", -"navoi.su", -"north-kazakhstan.su", -"nov.su", -"obninsk.su", -"penza.su", -"pokrovsk.su", -"sochi.su", -"spb.su", -"tashkent.su", -"termez.su", -"togliatti.su", -"troitsk.su", -"tselinograd.su", -"tula.su", -"tuva.su", -"vladikavkaz.su", -"vladimir.su", -"vologda.su", -"channelsdvr.net", -"u.channelsdvr.net", -"edgecompute.app", -"fastly-edge.com", -"fastly-terrarium.com", -"freetls.fastly.net", -"map.fastly.net", -"a.prod.fastly.net", -"global.prod.fastly.net", -"a.ssl.fastly.net", -"b.ssl.fastly.net", -"global.ssl.fastly.net", -"fastlylb.net", -"map.fastlylb.net", -"fastvps-server.com", -"fastvps.host", -"myfast.host", -"fastvps.site", -"myfast.space", -"conn.uk", -"copro.uk", -"hosp.uk", -"fedorainfracloud.org", -"fedorapeople.org", -"cloud.fedoraproject.org", -"app.os.fedoraproject.org", -"app.os.stg.fedoraproject.org", -"mydobiss.com", -"fh-muenster.io", -"payload.dev", -"figma.site", -"figma-gov.site", -"preview.site", -"filegear.me", -"firebaseapp.com", -"fldrv.com", -"on-fleek.app", -"flutterflow.app", -"sprites.app", -"fly.dev", -"e2b.app", -"framer.ai", -"framer.app", -"framercanvas.com", -"framer.media", -"framer.photos", -"framer.website", -"framer.wiki", -"freebox-os.com", -"freeboxos.com", -"fbx-os.fr", -"fbxos.fr", -"freebox-os.fr", -"freeboxos.fr", -"freedesktop.org", -"freemyip.com", -"wien.funkfeuer.at", -"daemon.asia", -"dix.asia", -"mydns.bz", -"0am.jp", -"0g0.jp", -"0j0.jp", -"0t0.jp", -"mydns.jp", -"pgw.jp", -"wjg.jp", -"keyword-on.net", -"live-on.net", -"server-on.net", -"mydns.tw", -"mydns.vc", -"futurehosting.at", -"futuremailing.at", -"gadget.app", -"gadget.host", -"aliases121.com", -"campaign.gov.uk", -"service.gov.uk", -"independent-commission.uk", -"independent-inquest.uk", -"independent-inquiry.uk", -"independent-panel.uk", -"independent-review.uk", -"public-inquiry.uk", -"royal-commission.uk", -"gehirn.ne.jp", -"usercontent.jp", -"gentapps.com", -"gentlentapis.com", -"cdn-edges.net", -"gsj.bz", -"gitbook.io", -"github.app", -"githubusercontent.com", -"githubpreview.dev", -"github.io", -"gitlab.io", -"gitapp.si", -"gitpage.si", -"nog.community", -"co.ro", -"shop.ro", -"lolipop.io", -"angry.jp", -"babyblue.jp", -"babymilk.jp", -"backdrop.jp", -"bambina.jp", -"bitter.jp", -"blush.jp", -"boo.jp", -"boy.jp", -"boyfriend.jp", -"but.jp", -"candypop.jp", -"capoo.jp", -"catfood.jp", -"cheap.jp", -"chicappa.jp", -"chillout.jp", -"chips.jp", -"chowder.jp", -"chu.jp", -"ciao.jp", -"cocotte.jp", -"coolblog.jp", -"cranky.jp", -"cutegirl.jp", -"daa.jp", -"deca.jp", -"deci.jp", -"digick.jp", -"egoism.jp", -"fakefur.jp", -"fem.jp", -"flier.jp", -"floppy.jp", -"fool.jp", -"frenchkiss.jp", -"girlfriend.jp", -"girly.jp", -"gloomy.jp", -"gonna.jp", -"greater.jp", -"hacca.jp", -"heavy.jp", -"her.jp", -"hiho.jp", -"hippy.jp", -"holy.jp", -"hungry.jp", -"icurus.jp", -"itigo.jp", -"jellybean.jp", -"kikirara.jp", -"kill.jp", -"kilo.jp", -"kuron.jp", -"littlestar.jp", -"lolipopmc.jp", -"lolitapunk.jp", -"lomo.jp", -"lovepop.jp", -"lovesick.jp", -"main.jp", -"mods.jp", -"mond.jp", -"mongolian.jp", -"moo.jp", -"namaste.jp", -"nikita.jp", -"nobushi.jp", -"noor.jp", -"oops.jp", -"parallel.jp", -"parasite.jp", -"pecori.jp", -"peewee.jp", -"penne.jp", -"pepper.jp", -"perma.jp", -"pigboat.jp", -"pinoko.jp", -"punyu.jp", -"pupu.jp", -"pussycat.jp", -"pya.jp", -"raindrop.jp", -"readymade.jp", -"sadist.jp", -"schoolbus.jp", -"secret.jp", -"staba.jp", -"stripper.jp", -"sub.jp", -"sunnyday.jp", -"thick.jp", -"tonkotsu.jp", -"under.jp", -"upper.jp", -"velvet.jp", -"verse.jp", -"versus.jp", -"vivian.jp", -"watson.jp", -"weblike.jp", -"whitesnow.jp", -"zombie.jp", -"heteml.net", -"vibehost.space", -"graphic.design", -"goip.de", -"web.app", -"appspot.com", -"blogspot.com", -"codespot.com", -"googleapis.com", -"googlecode.com", -"pagespeedmobilizer.com", -"withgoogle.com", -"withyoutube.com", -"cloud.goog", -"translate.goog", -"cloudfunctions.net", -"goupile.fr", -"pymnt.uk", -"gov.nl", -"grafana-dev.net", -"grayjayleagues.com", -"grebedoc.dev", -"gv.uy", -"hackclub.app", -"hashbang.sh", -"hasura.app", -"hasura-app.io", -"hatenablog.com", -"hatenadiary.com", -"hateblo.jp", -"hatenablog.jp", -"hatenadiary.jp", -"hatenadiary.org", -"pages.it.hs-heilbronn.de", -"pages-research.it.hs-heilbronn.de", -"heiyu.space", -"helioho.st", -"heliohost.us", -"hepforge.org", -"onhercules.app", -"hercules-app.com", -"hercules-dev.com", -"herokuapp.com", -"heyflow.page", -"heyflow.site", -"ravendb.cloud", -"ravendb.community", -"development.run", -"ravendb.run", -"hidns.co", -"hidns.vip", -"homesklep.pl", -"seprox.hooc.me", -"hoplix.shop", -"orx.biz", -"biz.ng", -"co.biz.ng", -"dl.biz.ng", -"go.biz.ng", -"lg.biz.ng", -"on.biz.ng", -"col.ng", -"firm.ng", -"gen.ng", -"ltd.ng", -"ngo.ng", -"plc.ng", -"hstgr.cloud", -"hostyhosting.io", -"hf.space", -"static.hf.space", -"hypernode.io", -"iobb.net", -"co.cz", -"moonscale.net", -"gr.com", -"iki.fi", -"ibxos.it", -"iliadboxos.it", -"imagine.diy", -"imagine-proxy.work", -"smushcdn.com", -"wphostedmail.com", -"wpmucdn.com", -"tempurl.host", -"wpmudev.host", -"dyn-berlin.de", -"in-berlin.de", -"in-brb.de", -"in-butter.de", -"in-dsl.de", -"in-vpn.de", -"in-dsl.net", -"in-vpn.net", -"in-dsl.org", -"in-vpn.org", -"oninferno.net", -"info.cx", -"ac.leg.br", -"al.leg.br", -"am.leg.br", -"ap.leg.br", -"ba.leg.br", -"ce.leg.br", -"df.leg.br", -"es.leg.br", -"go.leg.br", -"ma.leg.br", -"mg.leg.br", -"ms.leg.br", -"mt.leg.br", -"pa.leg.br", -"pb.leg.br", -"pe.leg.br", -"pi.leg.br", -"pr.leg.br", -"rj.leg.br", -"rn.leg.br", -"ro.leg.br", -"rr.leg.br", -"rs.leg.br", -"sc.leg.br", -"se.leg.br", -"sp.leg.br", -"to.leg.br", -"pixolino.com", -"na4u.ru", -"botdash.app", -"botdash.dev", -"botdash.gg", -"botdash.net", -"botda.sh", -"botdash.xyz", -"apps-1and1.com", -"live-website.com", -"webspace-host.com", -"apps-1and1.net", -"websitebuilder.online", -"app-ionos.space", -"iopsys.se", -"ipifony.net", -"home64.de", -"ipv64.de", -"ipv64.net", -"ir.md", -"is-a-good.dev", -"iservschule.de", -"mein-iserv.de", -"schuldock.de", -"schulplattform.de", -"schulserver.de", -"test-iserv.de", -"iserv.dev", -"iserv.host", -"ispmanager.name", -"mel.cloudlets.com.au", -"cloud.interhostsolutions.be", -"alp1.ae.flow.ch", -"appengine.flow.ch", -"es-1.axarnet.cloud", -"diadem.cloud", -"vip.jelastic.cloud", -"jele.cloud", -"it1.eur.aruba.jenv-aruba.cloud", -"it1.jenv-aruba.cloud", -"keliweb.cloud", -"cs.keliweb.cloud", -"oxa.cloud", -"tn.oxa.cloud", -"uk.oxa.cloud", -"primetel.cloud", -"uk.primetel.cloud", -"ca.reclaim.cloud", -"uk.reclaim.cloud", -"us.reclaim.cloud", -"ch.trendhosting.cloud", -"de.trendhosting.cloud", -"jele.club", -"dopaas.com", -"paas.hosted-by-previder.com", -"rag-cloud.hosteur.com", -"rag-cloud-ch.hosteur.com", -"jcloud.ik-server.com", -"jcloud-ver-jpc.ik-server.com", -"demo.jelastic.com", -"paas.massivegrid.com", -"jed.wafaicloud.com", -"ryd.wafaicloud.com", -"j.scaleforce.com.cy", -"jelastic.dogado.eu", -"fi.cloudplatform.fi", -"demo.datacenter.fi", -"paas.datacenter.fi", -"jele.host", -"mircloud.host", -"paas.beebyte.io", -"sekd1.beebyteapp.io", -"jele.io", -"jc.neen.it", -"jcloud.kz", -"cloudjiffy.net", -"fra1-de.cloudjiffy.net", -"west1-us.cloudjiffy.net", -"jls-sto1.elastx.net", -"jls-sto2.elastx.net", -"jls-sto3.elastx.net", -"fr-1.paas.massivegrid.net", -"lon-1.paas.massivegrid.net", -"lon-2.paas.massivegrid.net", -"ny-1.paas.massivegrid.net", -"ny-2.paas.massivegrid.net", -"sg-1.paas.massivegrid.net", -"jelastic.saveincloud.net", -"nordeste-idc.saveincloud.net", -"j.scaleforce.net", -"sdscloud.pl", -"unicloud.pl", -"mircloud.ru", -"enscaled.sg", -"jele.site", -"jelastic.team", -"orangecloud.tn", -"j.layershift.co.uk", -"phx.enscaled.us", -"mircloud.us", -"myjino.ru", -"jote.cloud", -"jotelulu.cloud", -"eu1-plenit.com", -"la1-plenit.com", -"us1-plenit.com", -"webadorsite.com", -"jouwweb.site", -"js.org", -"elastic.k2.cloud", -"lb.ru-msk.k2.cloud", -"s3.ru-msk.k2.cloud", -"website.ru-msk.k2.cloud", -"lb.ru-spb.k2.cloud", -"s3.ru-spb.k2.cloud", -"website.ru-spb.k2.cloud", -"s3.k2.cloud", -"website.k2.cloud", -"kaas.gg", -"khplay.nl", -"kapsi.fi", -"kdns.fr", -"ezproxy.kuleuven.be", -"kuleuven.cloud", -"keenetic.io", -"keenetic.link", -"keenetic.name", -"keenetic.pro", -"ae.kg", -"keymachine.de", -"kiloapps.ai", -"kiloapps.io", -"kinghost.net", -"uni5.net", -"knightpoint.systems", -"koobin.events", -"webthings.io", -"krellian.net", -"oya.to", -"co.de", -"shiptoday.app", -"shiptoday.build", -"laravel.cloud", -"on-forge.com", -"on-vapor.com", -"git-repos.de", -"lcube-server.de", -"svn-repos.de", -"leadpages.co", -"lpages.co", -"lpusercontent.com", -"leapcell.app", -"leapcell.dev", -"leapcell.online", -"liara.run", -"iran.liara.run", -"libp2p.direct", -"runcontainers.dev", -"co.business", -"co.education", -"co.events", -"co.financial", -"co.network", -"co.place", -"co.technology", -"linkyard-cloud.ch", -"linkyard.cloud", -"members.linode.com", -"ip.linodeusercontent.com", -"we.bs", -"filegear-sg.me", -"ggff.net", -"localtonet.com", -"lodz.pl", -"pabianice.pl", -"plock.pl", -"sieradz.pl", -"skierniewice.pl", -"zgierz.pl", -"loginline.app", -"loginline.dev", -"loginline.io", -"loginline.services", -"loginline.site", -"lohmus.me", -"lovable.app", -"lovableproject.com", -"lovable.run", -"lovable.sh", -"krasnik.pl", -"leczna.pl", -"lubartow.pl", -"lublin.pl", -"poniatowa.pl", -"swidnik.pl", -"glug.org.uk", -"lug.org.uk", -"lugs.org.uk", -"barsy.bg", -"barsy.club", -"barsycenter.com", -"barsyonline.com", -"barsy.de", -"barsy.dev", -"barsy.eu", -"barsy.gr", -"barsy.in", -"barsy.info", -"barsy.io", -"barsy.me", -"barsy.menu", -"barsyonline.menu", -"barsy.mobi", -"barsy.net", -"barsy.online", -"barsy.org", -"barsy.pro", -"barsy.pub", -"barsy.ro", -"barsy.rs", -"barsy.shop", -"barsyonline.shop", -"barsy.site", -"barsy.store", -"barsy.support", -"barsy.uk", -"barsy.co.uk", -"barsyonline.co.uk", -"luyani.app", -"luyani.net", -"magicpatterns.app", -"magicpatternsapp.com", -"hb.cldmail.ru", -"matlab.cloud", -"modelscape.com", -"mwcloudnonprod.com", -"polyspace.com", -"mayfirst.info", -"mcdir.me", -"mcdir.ru", -"vps.mcdir.ru", -"mcpre.ru", -"mediatech.by", -"mediatech.dev", -"hra.health", -"medusajs.app", -"miniserver.com", -"memset.net", -"messerli.app", -"atmeta.com", -"apps.fbsbx.com", -"custom.metacentrum.cz", -"flt.cloud.muni.cz", -"usr.cloud.muni.cz", -"meteorapp.com", -"eu.meteorapp.com", -"co.pl", -"azure-api.net", -"azure-mobile.net", -"azureedge.net", -"azurefd.net", -"azurestaticapps.net", -"1.azurestaticapps.net", -"2.azurestaticapps.net", -"3.azurestaticapps.net", -"4.azurestaticapps.net", -"5.azurestaticapps.net", -"6.azurestaticapps.net", -"7.azurestaticapps.net", -"centralus.azurestaticapps.net", -"eastasia.azurestaticapps.net", -"eastus2.azurestaticapps.net", -"westeurope.azurestaticapps.net", -"westus2.azurestaticapps.net", -"azurewebsites.net", -"cloudapp.net", -"trafficmanager.net", -"blob.core.usgovcloudapi.net", -"file.core.usgovcloudapi.net", -"web.core.usgovcloudapi.net", -"servicebus.usgovcloudapi.net", -"usgovcloudapp.net", -"usgovtrafficmanager.net", -"blob.core.windows.net", -"file.core.windows.net", -"web.core.windows.net", -"servicebus.windows.net", -"azure-api.us", -"azurewebsites.us", -"routingthecloud.com", -"sn.mynetname.net", -"routingthecloud.net", -"routingthecloud.org", -"same-app.com", -"same-preview.com", -"csx.cc", -"miren.app", -"miren.systems", -"mydbserver.com", -"webspaceconfig.de", -"mittwald.info", -"mittwaldserver.info", -"typo3server.info", -"project.space", -"mkm.fan", -"mocha.app", -"mochausercontent.com", -"mocha-sandbox.dev", -"modx.dev", -"bmoattachments.org", -"net.ru", -"org.ru", -"pp.ru", -"my.be", -"hostedpi.com", -"caracal.mythic-beasts.com", -"customer.mythic-beasts.com", -"fentiger.mythic-beasts.com", -"lynx.mythic-beasts.com", -"ocelot.mythic-beasts.com", -"oncilla.mythic-beasts.com", -"onza.mythic-beasts.com", -"sphinx.mythic-beasts.com", -"vs.mythic-beasts.com", -"x.mythic-beasts.com", -"yali.mythic-beasts.com", -"cust.retrosnub.co.uk", -"ui.nabu.casa", -"needle.run", -"co.site", -"cloud.nospamproxy.com", -"o365.cloud.nospamproxy.com", -"netlib.re", -"netlify.app", -"4u.com", -"nfshost.com", -"ipfs.nftstorage.link", -"ngo.us", -"ngrok.app", -"ngrok-free.app", -"ngrok.dev", -"ngrok-free.dev", -"ngrok.io", -"ap.ngrok.io", -"au.ngrok.io", -"eu.ngrok.io", -"in.ngrok.io", -"jp.ngrok.io", -"sa.ngrok.io", -"us.ngrok.io", -"ngrok.pizza", -"ngrok.pro", -"torun.pl", -"nh-serv.co.uk", -"nimsite.uk", -"mmafan.biz", -"myftp.biz", -"no-ip.biz", -"no-ip.ca", -"fantasyleague.cc", -"gotdns.ch", -"3utilities.com", -"blogsyte.com", -"ciscofreak.com", -"damnserver.com", -"ddnsking.com", -"ditchyourip.com", -"dnsiskinky.com", -"dynns.com", -"geekgalaxy.com", -"health-carereform.com", -"homesecuritymac.com", -"homesecuritypc.com", -"myactivedirectory.com", -"mysecuritycamera.com", -"myvnc.com", -"net-freaks.com", -"onthewifi.com", -"point2this.com", -"quicksytes.com", -"securitytactics.com", -"servebeer.com", -"servecounterstrike.com", -"serveexchange.com", -"serveftp.com", -"servegame.com", -"servehalflife.com", -"servehttp.com", -"servehumour.com", -"serveirc.com", -"servemp3.com", -"servep2p.com", -"servepics.com", -"servequake.com", -"servesarcasm.com", -"stufftoread.com", -"unusualperson.com", -"workisboring.com", -"dvrcam.info", -"ilovecollege.info", -"no-ip.info", -"brasilia.me", -"ddns.me", -"dnsfor.me", -"hopto.me", -"loginto.me", -"noip.me", -"webhop.me", -"bounceme.net", -"ddns.net", -"eating-organic.net", -"mydissent.net", -"myeffect.net", -"mymediapc.net", -"mypsx.net", -"mysecuritycamera.net", -"nhlfan.net", -"no-ip.net", -"pgafan.net", -"privatizehealthinsurance.net", -"redirectme.net", -"serveblog.net", -"serveminecraft.net", -"sytes.net", -"cable-modem.org", -"collegefan.org", -"couchpotatofries.org", -"hopto.org", -"mlbfan.org", -"myftp.org", -"mysecuritycamera.org", -"nflfan.org", -"no-ip.org", -"read-books.org", -"ufcfan.org", -"zapto.org", -"no-ip.co.uk", -"golffan.us", -"noip.us", -"pointto.us", -"stage.nodeart.io", -"noop.app", -"aberdeen.wa.us", -"bainbridge-isl.wa.us", -"bellevue.wa.us", -"bremerton.wa.us", -"centralia.wa.us", -"chehalis.wa.us", -"forks.wa.us", -"gig-harbor.wa.us", -"hoquiam.wa.us", -"keyport.wa.us", -"kingston.wa.us", -"olympia.wa.us", -"port-angeles.wa.us", -"port-ludlow.wa.us", -"port-orchard.wa.us", -"port-townsend.wa.us", -"poulsbo.wa.us", -"redmond.wa.us", -"renton.wa.us", -"sea.wa.us", -"seattle.wa.us", -"sequim.wa.us", -"shelton.wa.us", -"silverdale.wa.us", -"yarrow-point.wa.us", -"noticeable.news", -"notion.site", -"dnsking.ch", -"mypi.co", -"myiphost.com", -"forumz.info", -"soundcast.me", -"tcp4.me", -"dnsup.net", -"hicam.net", -"now-dns.net", -"ownip.net", -"vpndns.net", -"dynserv.org", -"now-dns.org", -"x443.pw", -"ntdll.top", -"freeddns.us", -"nsupdate.info", -"nerdpol.ovh", -"prvcy.page", -"observablehq.cloud", -"static.observableusercontent.com", -"omg.lol", -"cloudycluster.net", -"omniwe.site", -"123webseite.at", -"123website.be", -"simplesite.com.br", -"123website.ch", -"simplesite.com", -"123webseite.de", -"123hjemmeside.dk", -"123miweb.es", -"123kotisivu.fi", -"123siteweb.fr", -"simplesite.gr", -"123homepage.it", -"123website.lu", -"123website.nl", -"123hjemmeside.no", -"service.one", -"website.one", -"simplesite.pl", -"123paginaweb.pt", -"123minsida.se", -"onid.ca", -"is-a-fullstack.dev", -"is-cool.dev", -"is-not-a.dev", -"localplayer.dev", -"is-local.org", -"opensocial.site", -"chatgpt.site", -"opencraft.hosting", -"16-b.it", -"32-b.it", -"64-b.it", -"orsites.com", -"operaunite.com", -"tech.orange", -"can.re", -"authgear-staging.com", -"authgearapps.com", -"outsystemscloud.com", -"ownprovider.com", -"own.pm", -"ox.rs", -"oy.lc", -"pgfog.com", -"gotpantheon.com", -"pantheonsite.io", -"xmit.dev", -"madethis.site", -"srv.us", -"gh.srv.us", -"gl.srv.us", -"mypep.link", -"pplx.app", -"perspecta.cloud", -"forgeblocks.com", -"id.forgerock.io", -"support.site", -"on-web.fr", -"upsunapp.com", -"ent.platform.sh", -"eu.platform.sh", -"us.platform.sh", -"playcode.site", -"pley.games", -"onporter.run", -"co.bn", -"postman-echo.com", -"pstmn.io", -"mock.pstmn.io", -"httpbin.org", -"prequalifyme.today", -"xen.prgmr.com", -"priv.at", -"c01.kr", -"eliv-api.kr", -"eliv-cdn.kr", -"eliv-dns.kr", -"mmv.kr", -"vki.kr", -"dev.project-study.com", -"platter-app.dev", -"e.id", -"chirurgiens-dentistes-en-france.fr", -"byen.site", -"nyc.mn", -"pubtls.org", -"puter.app", -"puter.site", -"puter.work", -"pythonanywhere.com", -"eu.pythonanywhere.com", -"qa2.com", -"qcx.io", -"myqnapcloud.cn", -"alpha-myqnapcloud.com", -"dev-myqnapcloud.com", -"mycloudnas.com", -"mynascloud.com", -"myqnapcloud.com", -"qoto.io", -"qualifioapp.com", -"ladesk.com", -"qbuser.com", -"vapor.cloud", -"vaporcloud.io", -"rackmaze.com", -"rackmaze.net", -"cloudsite.builders", -"myradweb.net", -"servername.us", -"web.in", -"in.net", -"myrdbx.io", -"site.rb-hosting.io", -"up.railway.app", -"ravpage.co.il", -"readthedocs-hosted.com", -"readthedocs.io", -"rhcloud.com", -"instances.spawn.cc", -"onrender.com", -"app.render.com", -"replit.app", -"id.replit.app", -"firewalledreplit.co", -"id.firewalledreplit.co", -"repl.co", -"id.repl.co", -"replit.dev", -"archer.replit.dev", -"bones.replit.dev", -"canary.replit.dev", -"global.replit.dev", -"hacker.replit.dev", -"id.replit.dev", -"janeway.replit.dev", -"kim.replit.dev", -"kira.replit.dev", -"kirk.replit.dev", -"odo.replit.dev", -"paris.replit.dev", -"picard.replit.dev", -"pike.replit.dev", -"prerelease.replit.dev", -"reed.replit.dev", -"riker.replit.dev", -"sisko.replit.dev", -"spock.replit.dev", -"staging.replit.dev", -"sulu.replit.dev", -"tarpit.replit.dev", -"teams.replit.dev", -"tucker.replit.dev", -"wesley.replit.dev", -"worf.replit.dev", -"repl.run", -"resindevice.io", -"devices.resinstaging.io", -"adimo.co.uk", -"itcouldbewor.se", -"aus.basketball", -"nz.basketball", -"subsc-pay.com", -"subsc-pay.net", -"git-pages.rit.edu", -"rocky.page", -"rub.de", -"ruhr-uni-bochum.de", -"io.noc.ruhr-uni-bochum.de", -"ras.ru", -"nyat.app", -"180r.com", -"dojin.com", -"sakuratan.com", -"sakuraweb.com", -"x0.com", -"2-d.jp", -"bona.jp", -"crap.jp", -"daynight.jp", -"eek.jp", -"flop.jp", -"halfmoon.jp", -"jeez.jp", -"matrix.jp", -"mimoza.jp", -"ivory.ne.jp", -"mail-box.ne.jp", -"mints.ne.jp", -"mokuren.ne.jp", -"opal.ne.jp", -"sakura.ne.jp", -"sumomo.ne.jp", -"topaz.ne.jp", -"netgamers.jp", -"nyanta.jp", -"o0o0.jp", -"rdy.jp", -"rgr.jp", -"rulez.jp", -"s3.isk01.sakurastorage.jp", -"s3.isk02.sakurastorage.jp", -"saloon.jp", -"sblo.jp", -"skr.jp", -"tank.jp", -"uh-oh.jp", -"undo.jp", -"rs.webaccel.jp", -"user.webaccel.jp", -"websozai.jp", -"xii.jp", -"squares.net", -"jpn.org", -"kirara.st", -"x0.to", -"from.tv", -"sakura.tv", -"sandcats.io", -"sav.case", -"logoip.com", -"logoip.de", -"fr-par-1.baremetal.scw.cloud", -"fr-par-2.baremetal.scw.cloud", -"nl-ams-1.baremetal.scw.cloud", -"cockpit.fr-par.scw.cloud", -"ddl.fr-par.scw.cloud", -"dtwh.fr-par.scw.cloud", -"fnc.fr-par.scw.cloud", -"functions.fnc.fr-par.scw.cloud", -"ifr.fr-par.scw.cloud", -"k8s.fr-par.scw.cloud", -"nodes.k8s.fr-par.scw.cloud", -"kafk.fr-par.scw.cloud", -"mgdb.fr-par.scw.cloud", -"rdb.fr-par.scw.cloud", -"s3.fr-par.scw.cloud", -"s3-website.fr-par.scw.cloud", -"scbl.fr-par.scw.cloud", -"whm.fr-par.scw.cloud", -"priv.instances.scw.cloud", -"pub.instances.scw.cloud", -"k8s.scw.cloud", -"cockpit.nl-ams.scw.cloud", -"ddl.nl-ams.scw.cloud", -"dtwh.nl-ams.scw.cloud", -"ifr.nl-ams.scw.cloud", -"k8s.nl-ams.scw.cloud", -"nodes.k8s.nl-ams.scw.cloud", -"kafk.nl-ams.scw.cloud", -"mgdb.nl-ams.scw.cloud", -"rdb.nl-ams.scw.cloud", -"s3.nl-ams.scw.cloud", -"s3-website.nl-ams.scw.cloud", -"scbl.nl-ams.scw.cloud", -"whm.nl-ams.scw.cloud", -"cockpit.pl-waw.scw.cloud", -"ddl.pl-waw.scw.cloud", -"dtwh.pl-waw.scw.cloud", -"ifr.pl-waw.scw.cloud", -"k8s.pl-waw.scw.cloud", -"nodes.k8s.pl-waw.scw.cloud", -"kafk.pl-waw.scw.cloud", -"mgdb.pl-waw.scw.cloud", -"rdb.pl-waw.scw.cloud", -"s3.pl-waw.scw.cloud", -"s3-website.pl-waw.scw.cloud", -"scbl.pl-waw.scw.cloud", -"scalebook.scw.cloud", -"smartlabeling.scw.cloud", -"dedibox.fr", -"schokokeks.net", -"gov.scot", -"service.gov.scot", -"mygov.scot", -"scrysec.com", -"client.scrypted.io", -"firewall-gateway.com", -"firewall-gateway.de", -"my-gateway.de", -"my-router.de", -"spdns.de", -"spdns.eu", -"firewall-gateway.net", -"my-firewall.org", -"myfirewall.org", -"spdns.org", -"seidat.net", -"sellfy.store", -"minisite.ms", -"senseering.net", -"servebolt.cloud", -"biz.ua", -"co.ua", -"pp.ua", -"as.sh.cn", -"vicp.fun", -"yicp.fun", -"zicp.fun", -"sheezy.games", -"myshopblocks.com", -"myshopify.com", -"shopitsite.com", -"shopware.shop", -"shopware.store", -"mo-siemens.io", -"1kapp.com", -"appchizi.com", -"applinzi.com", -"sinaapp.com", -"vipsinaapp.com", -"siteleaf.net", -"small-web.org", -"aeroport.fr", -"avocat.fr", -"chambagri.fr", -"chirurgiens-dentistes.fr", -"experts-comptables.fr", -"medecin.fr", -"notaires.fr", -"pharmacien.fr", -"port.fr", -"veterinaire.fr", -"vp4.me", -"streamlit.app", -"streamlitapp.com", -"try-snowplow.com", -"mafelo.net", -"sol.site", -"playstation-cloud.com", -"srht.site", -"apps.lair.io", -"4.at", -"my.at", -"my.de", -"nx.gw", -"spawnbase.app", -"customer.speedpartner.de", -"myspreadshop.at", -"myspreadshop.com.au", -"myspreadshop.be", -"myspreadshop.ca", -"myspreadshop.ch", -"myspreadshop.com", -"myspreadshop.de", -"myspreadshop.dk", -"myspreadshop.es", -"myspreadshop.fi", -"myspreadshop.fr", -"myspreadshop.ie", -"myspreadshop.it", -"myspreadshop.net", -"myspreadshop.nl", -"myspreadshop.no", -"myspreadshop.pl", -"myspreadshop.se", -"myspreadshop.co.uk", -"w-corp-staticblitz.com", -"w-credentialless-staticblitz.com", -"w-staticblitz.com", -"bolt.host", -"stackhero-network.com", -"runs.onstackit.cloud", -"stackit.gg", -"stackit.rocks", -"stackit.run", -"stackit.zone", -"sryze.cc", -"indevs.in", -"musician.io", -"novecore.site", -"statichost.page", -"feedback.ac", -"forms.ac", -"assessments.cx", -"calculators.cx", -"funnels.cx", -"paynow.cx", -"quizzes.cx", -"researched.cx", -"tests.cx", -"surveys.so", -"ipfs.storacha.link", -"ipfs.w3s.link", -"storebase.store", -"strapiapp.com", -"media.strapiapp.com", -"vps-host.net", -"atl.jelastic.vps-host.net", -"njs.jelastic.vps-host.net", -"ric.jelastic.vps-host.net", -"streak-link.com", -"streaklinks.com", -"streakusercontent.com", -"soc.srcf.net", -"user.srcf.net", -"utwente.io", -"temp-dns.com", -"supabase.co", -"realtime.supabase.co", -"storage.supabase.co", -"supabase.in", -"supabase.net", -"syncloud.it", -"dscloud.biz", -"direct.quickconnect.cn", -"dsmynas.com", -"familyds.com", -"diskstation.me", -"dscloud.me", -"i234.me", -"myds.me", -"synology.me", -"dscloud.mobi", -"dsmynas.net", -"familyds.net", -"dsmynas.org", -"familyds.org", -"direct.quickconnect.to", -"vpnplus.to", -"mytabit.com", -"mytabit.co.il", -"tabitorder.co.il", -"taifun-dns.de", -"erp.dev", -"web.erp.dev", -"ts.net", -"gda.pl", -"gdansk.pl", -"gdynia.pl", -"med.pl", -"sopot.pl", -"taveusercontent.com", -"p.tawk.email", -"p.tawkto.email", -"tche.br", -"site.tb-hosting.com", -"directwp.eu", -"ec.cc", -"eu.cc", -"gu.cc", -"uk.cc", -"us.cc", -"edugit.io", -"s3.teckids.org", -"telebit.app", -"telebit.io", -"teleport.sh", -"reservd.com", -"thingdustdata.com", -"cust.dev.thingdust.io", -"reservd.dev.thingdust.io", -"cust.disrec.thingdust.io", -"reservd.disrec.thingdust.io", -"cust.prod.thingdust.io", -"cust.testing.thingdust.io", -"reservd.testing.thingdust.io", -"tickets.io", -"t3.storage.dev", -"t3.storageapi.dev", -"arvo.network", -"azimuth.network", -"tlon.network", -"torproject.net", -"pages.torproject.net", -"townnews-staging.com", -"12hp.at", -"2ix.at", -"4lima.at", -"lima-city.at", -"12hp.ch", -"2ix.ch", -"4lima.ch", -"lima-city.ch", -"trafficplex.cloud", -"de.cool", -"12hp.de", -"2ix.de", -"4lima.de", -"lima-city.de", -"1337.pictures", -"clan.rip", -"lima-city.rocks", -"webspace.rocks", -"lima.zone", -"site.transip.me", -"tunnelmole.net", -"tuxfamily.org", -"typedream.app", -"pro.typeform.com", -"uber.space", -"hk.com", -"inc.hk", -"ltd.hk", -"hk.org", -"it.com", -"umso.co", -"unison-services.cloud", -"virtual-user.de", -"virtualuser.de", -"obj.ag", -"name.pm", -"sch.tf", -"biz.wf", -"sch.wf", -"org.yt", -"rs.ba", -"bielsko.pl", -"urown.cloud", -"dnsupdate.info", -"us.org", -"v.ua", -"val.run", -"web.val.run", -"vercel.app", -"v0.build", -"vercel.dev", -"vusercontent.net", -"vercel.run", -"now.sh", -"2038.io", -"v-info.info", -"vistablog.ir", -"deus-canvas.com", -"vivenushop.com", -"vivenushop.dev", -"voorloper.cloud", -"wafflecell.com", -"wal.app", -"wasmer.app", -"webflow.io", -"webflowtest.io", -"hotelwithflight.com", -"reserve-online.net", -"book.online", -"cprapid.com", -"pleskns.com", -"wp2.host", -"pdns.page", -"plesk.page", -"cpanel.site", -"wpsquared.site", -"remotewd.com", -"box.ca", -"pages.wiardweb.com", -"toolforge.org", -"wmcloud.org", -"beta.wmcloud.org", -"wmflabs.org", -"vps.hrsn.au", -"hrsn.dev", -"is-a.dev", -"localcert.net", -"windsurf.app", -"windsurf.build", -"drive-platform.com", -"drive-platform.io", -"panel.gg", -"daemon.panel.gg", -"base44.app", -"base44-sandbox.com", -"wixsite.com", -"wixstudio.com", -"editorx.io", -"wixstudio.io", -"wix.run", -"messwithdns.com", -"woltlab-demo.com", -"myforum.community", -"community-pro.de", -"diskussionsbereich.de", -"community-pro.net", -"meinforum.net", -"affinitylottery.org.uk", -"raffleentry.org.uk", -"weeklylottery.org.uk", -"wpenginepowered.com", -"js.wpenginepowered.com", -"grok.me", -"half.host", -"xnbay.com", -"u2.xnbay.com", -"u2-local.xnbay.com", -"cistron.nl", -"demon.nl", -"xs4all.space", -"xtooldevice.com", -"yandexcloud.net", -"storage.yandexcloud.net", -"website.yandexcloud.net", -"sourcecraft.site", -"official.academy", -"yolasite.com", -"ynh.fr", -"nohost.me", -"noho.st", -"za.net", -"za.org", -"zap.cloud", -"zeabur.app", -"prg1-zerops.zone", -"bss.design", -"basicserver.io", -"virtualserver.io", -"enterprisecloud.nu", -"zone.id", -"nett.to", -"zabc.net", -0}; +#include "pubsuffix.hh" +const std::string g_pubsuffix = +"com.ac\\n" +"edu.ac\\n" +"gov.ac\\n" +"mil.ac\\n" +"net.ac\\n" +"org.ac\\n" +"ac.ae\\n" +"co.ae\\n" +"gov.ae\\n" +"mil.ae\\n" +"net.ae\\n" +"org.ae\\n" +"sch.ae\\n" +"airline.aero\\n" +"airport.aero\\n" +"accident-investigation.aero\\n" +"accident-prevention.aero\\n" +"aerobatic.aero\\n" +"aeroclub.aero\\n" +"aerodrome.aero\\n" +"agents.aero\\n" +"air-surveillance.aero\\n" +"air-traffic-control.aero\\n" +"aircraft.aero\\n" +"airtraffic.aero\\n" +"ambulance.aero\\n" +"association.aero\\n" +"author.aero\\n" +"ballooning.aero\\n" +"broker.aero\\n" +"caa.aero\\n" +"cargo.aero\\n" +"catering.aero\\n" +"certification.aero\\n" +"championship.aero\\n" +"charter.aero\\n" +"civilaviation.aero\\n" +"club.aero\\n" +"conference.aero\\n" +"consultant.aero\\n" +"consulting.aero\\n" +"control.aero\\n" +"council.aero\\n" +"crew.aero\\n" +"design.aero\\n" +"dgca.aero\\n" +"educator.aero\\n" +"emergency.aero\\n" +"engine.aero\\n" +"engineer.aero\\n" +"entertainment.aero\\n" +"equipment.aero\\n" +"exchange.aero\\n" +"express.aero\\n" +"federation.aero\\n" +"flight.aero\\n" +"freight.aero\\n" +"fuel.aero\\n" +"gliding.aero\\n" +"government.aero\\n" +"groundhandling.aero\\n" +"group.aero\\n" +"hanggliding.aero\\n" +"homebuilt.aero\\n" +"insurance.aero\\n" +"journal.aero\\n" +"journalist.aero\\n" +"leasing.aero\\n" +"logistics.aero\\n" +"magazine.aero\\n" +"maintenance.aero\\n" +"marketplace.aero\\n" +"media.aero\\n" +"microlight.aero\\n" +"modelling.aero\\n" +"navigation.aero\\n" +"parachuting.aero\\n" +"paragliding.aero\\n" +"passenger-association.aero\\n" +"pilot.aero\\n" +"press.aero\\n" +"production.aero\\n" +"recreation.aero\\n" +"repbody.aero\\n" +"res.aero\\n" +"research.aero\\n" +"rotorcraft.aero\\n" +"safety.aero\\n" +"scientist.aero\\n" +"services.aero\\n" +"show.aero\\n" +"skydiving.aero\\n" +"software.aero\\n" +"student.aero\\n" +"taxi.aero\\n" +"trader.aero\\n" +"trading.aero\\n" +"trainer.aero\\n" +"union.aero\\n" +"workinggroup.aero\\n" +"works.aero\\n" +"com.af\\n" +"edu.af\\n" +"gov.af\\n" +"net.af\\n" +"org.af\\n" +"co.ag\\n" +"com.ag\\n" +"net.ag\\n" +"nom.ag\\n" +"org.ag\\n" +"com.ai\\n" +"net.ai\\n" +"off.ai\\n" +"org.ai\\n" +"com.al\\n" +"edu.al\\n" +"gov.al\\n" +"mil.al\\n" +"net.al\\n" +"org.al\\n" +"co.am\\n" +"com.am\\n" +"commune.am\\n" +"net.am\\n" +"org.am\\n" +"co.ao\\n" +"ed.ao\\n" +"edu.ao\\n" +"gov.ao\\n" +"gv.ao\\n" +"it.ao\\n" +"og.ao\\n" +"org.ao\\n" +"pb.ao\\n" +"bet.ar\\n" +"com.ar\\n" +"coop.ar\\n" +"edu.ar\\n" +"gob.ar\\n" +"gov.ar\\n" +"int.ar\\n" +"mil.ar\\n" +"musica.ar\\n" +"mutual.ar\\n" +"net.ar\\n" +"org.ar\\n" +"seg.ar\\n" +"senasa.ar\\n" +"tur.ar\\n" +"e164.arpa\\n" +"home.arpa\\n" +"in-addr.arpa\\n" +"ip6.arpa\\n" +"iris.arpa\\n" +"uri.arpa\\n" +"urn.arpa\\n" +"gov.as\\n" +"ac.at\\n" +"sth.ac.at\\n" +"co.at\\n" +"gv.at\\n" +"or.at\\n" +"asn.au\\n" +"com.au\\n" +"edu.au\\n" +"gov.au\\n" +"id.au\\n" +"net.au\\n" +"org.au\\n" +"conf.au\\n" +"oz.au\\n" +"act.au\\n" +"nsw.au\\n" +"nt.au\\n" +"qld.au\\n" +"sa.au\\n" +"tas.au\\n" +"vic.au\\n" +"wa.au\\n" +"act.edu.au\\n" +"catholic.edu.au\\n" +"nsw.edu.au\\n" +"nt.edu.au\\n" +"qld.edu.au\\n" +"sa.edu.au\\n" +"tas.edu.au\\n" +"vic.edu.au\\n" +"wa.edu.au\\n" +"qld.gov.au\\n" +"sa.gov.au\\n" +"tas.gov.au\\n" +"vic.gov.au\\n" +"wa.gov.au\\n" +"com.aw\\n" +"biz.az\\n" +"co.az\\n" +"com.az\\n" +"edu.az\\n" +"gov.az\\n" +"info.az\\n" +"int.az\\n" +"mil.az\\n" +"name.az\\n" +"net.az\\n" +"org.az\\n" +"pp.az\\n" +"pro.az\\n" +"com.ba\\n" +"edu.ba\\n" +"gov.ba\\n" +"mil.ba\\n" +"net.ba\\n" +"org.ba\\n" +"biz.bb\\n" +"co.bb\\n" +"com.bb\\n" +"edu.bb\\n" +"gov.bb\\n" +"info.bb\\n" +"net.bb\\n" +"org.bb\\n" +"store.bb\\n" +"tv.bb\\n" +"ac.bd\\n" +"ai.bd\\n" +"co.bd\\n" +"com.bd\\n" +"edu.bd\\n" +"gov.bd\\n" +"id.bd\\n" +"info.bd\\n" +"it.bd\\n" +"mil.bd\\n" +"net.bd\\n" +"org.bd\\n" +"sch.bd\\n" +"tv.bd\\n" +"ac.be\\n" +"gov.bf\\n" +"0.bg\\n" +"1.bg\\n" +"2.bg\\n" +"3.bg\\n" +"4.bg\\n" +"5.bg\\n" +"6.bg\\n" +"7.bg\\n" +"8.bg\\n" +"9.bg\\n" +"a.bg\\n" +"b.bg\\n" +"c.bg\\n" +"d.bg\\n" +"e.bg\\n" +"f.bg\\n" +"g.bg\\n" +"h.bg\\n" +"i.bg\\n" +"j.bg\\n" +"k.bg\\n" +"l.bg\\n" +"m.bg\\n" +"n.bg\\n" +"o.bg\\n" +"p.bg\\n" +"q.bg\\n" +"r.bg\\n" +"s.bg\\n" +"t.bg\\n" +"u.bg\\n" +"v.bg\\n" +"w.bg\\n" +"x.bg\\n" +"y.bg\\n" +"z.bg\\n" +"com.bh\\n" +"edu.bh\\n" +"gov.bh\\n" +"net.bh\\n" +"org.bh\\n" +"co.bi\\n" +"com.bi\\n" +"edu.bi\\n" +"or.bi\\n" +"org.bi\\n" +"africa.bj\\n" +"agro.bj\\n" +"architectes.bj\\n" +"assur.bj\\n" +"avocats.bj\\n" +"co.bj\\n" +"com.bj\\n" +"eco.bj\\n" +"econo.bj\\n" +"edu.bj\\n" +"info.bj\\n" +"loisirs.bj\\n" +"money.bj\\n" +"net.bj\\n" +"org.bj\\n" +"ote.bj\\n" +"restaurant.bj\\n" +"resto.bj\\n" +"tourism.bj\\n" +"univ.bj\\n" +"com.bm\\n" +"edu.bm\\n" +"gov.bm\\n" +"net.bm\\n" +"org.bm\\n" +"com.bn\\n" +"edu.bn\\n" +"gov.bn\\n" +"net.bn\\n" +"org.bn\\n" +"com.bo\\n" +"edu.bo\\n" +"gob.bo\\n" +"int.bo\\n" +"mil.bo\\n" +"net.bo\\n" +"org.bo\\n" +"tv.bo\\n" +"web.bo\\n" +"academia.bo\\n" +"agro.bo\\n" +"arte.bo\\n" +"blog.bo\\n" +"bolivia.bo\\n" +"ciencia.bo\\n" +"cooperativa.bo\\n" +"democracia.bo\\n" +"deporte.bo\\n" +"ecologia.bo\\n" +"economia.bo\\n" +"empresa.bo\\n" +"ia.bo\\n" +"indigena.bo\\n" +"industria.bo\\n" +"info.bo\\n" +"medicina.bo\\n" +"movimiento.bo\\n" +"musica.bo\\n" +"natural.bo\\n" +"nombre.bo\\n" +"noticias.bo\\n" +"patria.bo\\n" +"plurinacional.bo\\n" +"politica.bo\\n" +"profesional.bo\\n" +"pueblo.bo\\n" +"revista.bo\\n" +"salud.bo\\n" +"tecnologia.bo\\n" +"tksat.bo\\n" +"transporte.bo\\n" +"wiki.bo\\n" +"9guacu.br\\n" +"abc.br\\n" +"adm.br\\n" +"adv.br\\n" +"agr.br\\n" +"aju.br\\n" +"am.br\\n" +"anani.br\\n" +"aparecida.br\\n" +"api.br\\n" +"app.br\\n" +"arq.br\\n" +"art.br\\n" +"ato.br\\n" +"b.br\\n" +"barueri.br\\n" +"belem.br\\n" +"bet.br\\n" +"bhz.br\\n" +"bib.br\\n" +"bio.br\\n" +"blog.br\\n" +"bmd.br\\n" +"boavista.br\\n" +"bsb.br\\n" +"campinagrande.br\\n" +"campinas.br\\n" +"caxias.br\\n" +"cim.br\\n" +"cng.br\\n" +"cnt.br\\n" +"com.br\\n" +"contagem.br\\n" +"coop.br\\n" +"coz.br\\n" +"cri.br\\n" +"cuiaba.br\\n" +"curitiba.br\\n" +"def.br\\n" +"des.br\\n" +"det.br\\n" +"dev.br\\n" +"ecn.br\\n" +"eco.br\\n" +"edu.br\\n" +"emp.br\\n" +"enf.br\\n" +"eng.br\\n" +"esp.br\\n" +"etc.br\\n" +"eti.br\\n" +"far.br\\n" +"feira.br\\n" +"flog.br\\n" +"floripa.br\\n" +"fm.br\\n" +"fnd.br\\n" +"fortal.br\\n" +"fot.br\\n" +"foz.br\\n" +"fst.br\\n" +"g12.br\\n" +"geo.br\\n" +"ggf.br\\n" +"goiania.br\\n" +"gov.br\\n" +"ac.gov.br\\n" +"al.gov.br\\n" +"am.gov.br\\n" +"ap.gov.br\\n" +"ba.gov.br\\n" +"ce.gov.br\\n" +"df.gov.br\\n" +"es.gov.br\\n" +"go.gov.br\\n" +"ma.gov.br\\n" +"mg.gov.br\\n" +"ms.gov.br\\n" +"mt.gov.br\\n" +"pa.gov.br\\n" +"pb.gov.br\\n" +"pe.gov.br\\n" +"pi.gov.br\\n" +"pr.gov.br\\n" +"rj.gov.br\\n" +"rn.gov.br\\n" +"ro.gov.br\\n" +"rr.gov.br\\n" +"rs.gov.br\\n" +"sc.gov.br\\n" +"se.gov.br\\n" +"sp.gov.br\\n" +"to.gov.br\\n" +"gru.br\\n" +"ia.br\\n" +"imb.br\\n" +"ind.br\\n" +"inf.br\\n" +"jab.br\\n" +"jampa.br\\n" +"jdf.br\\n" +"joinville.br\\n" +"jor.br\\n" +"jus.br\\n" +"leg.br\\n" +"leilao.br\\n" +"lel.br\\n" +"log.br\\n" +"londrina.br\\n" +"macapa.br\\n" +"maceio.br\\n" +"manaus.br\\n" +"maringa.br\\n" +"mat.br\\n" +"med.br\\n" +"mil.br\\n" +"morena.br\\n" +"mp.br\\n" +"mus.br\\n" +"natal.br\\n" +"net.br\\n" +"niteroi.br\\n" +"not.br\\n" +"ntr.br\\n" +"odo.br\\n" +"ong.br\\n" +"org.br\\n" +"osasco.br\\n" +"palmas.br\\n" +"poa.br\\n" +"ppg.br\\n" +"pro.br\\n" +"psc.br\\n" +"psi.br\\n" +"pvh.br\\n" +"qsl.br\\n" +"radio.br\\n" +"rec.br\\n" +"recife.br\\n" +"rep.br\\n" +"ribeirao.br\\n" +"rio.br\\n" +"riobranco.br\\n" +"riopreto.br\\n" +"salvador.br\\n" +"sampa.br\\n" +"santamaria.br\\n" +"santoandre.br\\n" +"saobernardo.br\\n" +"saogonca.br\\n" +"seg.br\\n" +"sjc.br\\n" +"slg.br\\n" +"slz.br\\n" +"social.br\\n" +"sorocaba.br\\n" +"srv.br\\n" +"taxi.br\\n" +"tc.br\\n" +"tec.br\\n" +"teo.br\\n" +"the.br\\n" +"tmp.br\\n" +"trd.br\\n" +"tur.br\\n" +"tv.br\\n" +"udi.br\\n" +"vet.br\\n" +"vix.br\\n" +"vlog.br\\n" +"wiki.br\\n" +"xyz.br\\n" +"zlg.br\\n" +"com.bs\\n" +"edu.bs\\n" +"gov.bs\\n" +"net.bs\\n" +"org.bs\\n" +"com.bt\\n" +"edu.bt\\n" +"gov.bt\\n" +"net.bt\\n" +"org.bt\\n" +"ac.bw\\n" +"co.bw\\n" +"gov.bw\\n" +"net.bw\\n" +"org.bw\\n" +"gov.by\\n" +"mil.by\\n" +"com.by\\n" +"of.by\\n" +"co.bz\\n" +"com.bz\\n" +"edu.bz\\n" +"gov.bz\\n" +"net.bz\\n" +"org.bz\\n" +"ab.ca\\n" +"bc.ca\\n" +"mb.ca\\n" +"nb.ca\\n" +"nf.ca\\n" +"nl.ca\\n" +"ns.ca\\n" +"nt.ca\\n" +"nu.ca\\n" +"on.ca\\n" +"pe.ca\\n" +"qc.ca\\n" +"sk.ca\\n" +"yk.ca\\n" +"gc.ca\\n" +"gov.cd\\n" +"ac.ci\\n" +"asso.ci\\n" +"co.ci\\n" +"com.ci\\n" +"ed.ci\\n" +"edu.ci\\n" +"go.ci\\n" +"gouv.ci\\n" +"int.ci\\n" +"net.ci\\n" +"or.ci\\n" +"org.ci\\n" +"co.cl\\n" +"gob.cl\\n" +"gov.cl\\n" +"mil.cl\\n" +"co.cm\\n" +"com.cm\\n" +"gov.cm\\n" +"net.cm\\n" +"ac.cn\\n" +"com.cn\\n" +"edu.cn\\n" +"gov.cn\\n" +"mil.cn\\n" +"net.cn\\n" +"org.cn\\n" +"ah.cn\\n" +"bj.cn\\n" +"cq.cn\\n" +"fj.cn\\n" +"gd.cn\\n" +"gs.cn\\n" +"gx.cn\\n" +"gz.cn\\n" +"ha.cn\\n" +"hb.cn\\n" +"he.cn\\n" +"hi.cn\\n" +"hk.cn\\n" +"hl.cn\\n" +"hn.cn\\n" +"jl.cn\\n" +"js.cn\\n" +"jx.cn\\n" +"ln.cn\\n" +"mo.cn\\n" +"nm.cn\\n" +"nx.cn\\n" +"qh.cn\\n" +"sc.cn\\n" +"sd.cn\\n" +"sh.cn\\n" +"sn.cn\\n" +"sx.cn\\n" +"tj.cn\\n" +"tw.cn\\n" +"xj.cn\\n" +"xz.cn\\n" +"yn.cn\\n" +"zj.cn\\n" +"com.co\\n" +"edu.co\\n" +"gov.co\\n" +"mil.co\\n" +"net.co\\n" +"nom.co\\n" +"org.co\\n" +"ac.cr\\n" +"co.cr\\n" +"ed.cr\\n" +"fi.cr\\n" +"go.cr\\n" +"or.cr\\n" +"sa.cr\\n" +"com.cu\\n" +"edu.cu\\n" +"gob.cu\\n" +"inf.cu\\n" +"nat.cu\\n" +"net.cu\\n" +"org.cu\\n" +"com.cv\\n" +"edu.cv\\n" +"id.cv\\n" +"int.cv\\n" +"net.cv\\n" +"nome.cv\\n" +"org.cv\\n" +"publ.cv\\n" +"com.cw\\n" +"edu.cw\\n" +"net.cw\\n" +"org.cw\\n" +"gov.cx\\n" +"ac.cy\\n" +"biz.cy\\n" +"com.cy\\n" +"ekloges.cy\\n" +"gov.cy\\n" +"ltd.cy\\n" +"mil.cy\\n" +"net.cy\\n" +"org.cy\\n" +"press.cy\\n" +"pro.cy\\n" +"tm.cy\\n" +"gov.cz\\n" +"co.dm\\n" +"com.dm\\n" +"edu.dm\\n" +"gov.dm\\n" +"net.dm\\n" +"org.dm\\n" +"art.do\\n" +"com.do\\n" +"edu.do\\n" +"gob.do\\n" +"gov.do\\n" +"mil.do\\n" +"net.do\\n" +"org.do\\n" +"sld.do\\n" +"web.do\\n" +"art.dz\\n" +"asso.dz\\n" +"com.dz\\n" +"edu.dz\\n" +"gov.dz\\n" +"net.dz\\n" +"org.dz\\n" +"pol.dz\\n" +"soc.dz\\n" +"tm.dz\\n" +"abg.ec\\n" +"adm.ec\\n" +"agron.ec\\n" +"arqt.ec\\n" +"art.ec\\n" +"bar.ec\\n" +"chef.ec\\n" +"com.ec\\n" +"cont.ec\\n" +"cpa.ec\\n" +"cue.ec\\n" +"dent.ec\\n" +"dgn.ec\\n" +"disco.ec\\n" +"doc.ec\\n" +"edu.ec\\n" +"eng.ec\\n" +"esm.ec\\n" +"fin.ec\\n" +"fot.ec\\n" +"gal.ec\\n" +"gob.ec\\n" +"gov.ec\\n" +"gye.ec\\n" +"ibr.ec\\n" +"info.ec\\n" +"k12.ec\\n" +"lat.ec\\n" +"loj.ec\\n" +"med.ec\\n" +"mil.ec\\n" +"mktg.ec\\n" +"mon.ec\\n" +"net.ec\\n" +"ntr.ec\\n" +"odont.ec\\n" +"org.ec\\n" +"pro.ec\\n" +"prof.ec\\n" +"psic.ec\\n" +"psiq.ec\\n" +"pub.ec\\n" +"rio.ec\\n" +"rrpp.ec\\n" +"sal.ec\\n" +"tech.ec\\n" +"tul.ec\\n" +"tur.ec\\n" +"uio.ec\\n" +"vet.ec\\n" +"xxx.ec\\n" +"aip.ee\\n" +"com.ee\\n" +"edu.ee\\n" +"fie.ee\\n" +"gov.ee\\n" +"lib.ee\\n" +"med.ee\\n" +"org.ee\\n" +"pri.ee\\n" +"riik.ee\\n" +"ac.eg\\n" +"com.eg\\n" +"edu.eg\\n" +"eun.eg\\n" +"gov.eg\\n" +"info.eg\\n" +"me.eg\\n" +"mil.eg\\n" +"name.eg\\n" +"net.eg\\n" +"org.eg\\n" +"sci.eg\\n" +"sport.eg\\n" +"tv.eg\\n" +"com.es\\n" +"edu.es\\n" +"gob.es\\n" +"nom.es\\n" +"org.es\\n" +"biz.et\\n" +"com.et\\n" +"edu.et\\n" +"gov.et\\n" +"info.et\\n" +"name.et\\n" +"net.et\\n" +"org.et\\n" +"aland.fi\\n" +"ac.fj\\n" +"biz.fj\\n" +"com.fj\\n" +"edu.fj\\n" +"gov.fj\\n" +"id.fj\\n" +"info.fj\\n" +"mil.fj\\n" +"name.fj\\n" +"net.fj\\n" +"org.fj\\n" +"pro.fj\\n" +"com.fm\\n" +"edu.fm\\n" +"net.fm\\n" +"org.fm\\n" +"asso.fr\\n" +"com.fr\\n" +"gouv.fr\\n" +"nom.fr\\n" +"prd.fr\\n" +"tm.fr\\n" +"avoues.fr\\n" +"cci.fr\\n" +"greta.fr\\n" +"huissier-justice.fr\\n" +"edu.gd\\n" +"gov.gd\\n" +"com.ge\\n" +"cyb.ge\\n" +"edu.ge\\n" +"gov.ge\\n" +"llc.ge\\n" +"net.ge\\n" +"online.ge\\n" +"org.ge\\n" +"pvt.ge\\n" +"school.ge\\n" +"tnx.ge\\n" +"co.gg\\n" +"net.gg\\n" +"org.gg\\n" +"biz.gh\\n" +"com.gh\\n" +"edu.gh\\n" +"gov.gh\\n" +"mil.gh\\n" +"net.gh\\n" +"org.gh\\n" +"com.gi\\n" +"edu.gi\\n" +"gov.gi\\n" +"ltd.gi\\n" +"mod.gi\\n" +"org.gi\\n" +"co.gl\\n" +"com.gl\\n" +"edu.gl\\n" +"net.gl\\n" +"org.gl\\n" +"ac.gn\\n" +"com.gn\\n" +"edu.gn\\n" +"gov.gn\\n" +"net.gn\\n" +"org.gn\\n" +"asso.gp\\n" +"com.gp\\n" +"edu.gp\\n" +"mobi.gp\\n" +"net.gp\\n" +"org.gp\\n" +"com.gr\\n" +"edu.gr\\n" +"gov.gr\\n" +"net.gr\\n" +"org.gr\\n" +"com.gt\\n" +"edu.gt\\n" +"gob.gt\\n" +"ind.gt\\n" +"mil.gt\\n" +"net.gt\\n" +"org.gt\\n" +"com.gu\\n" +"edu.gu\\n" +"gov.gu\\n" +"guam.gu\\n" +"info.gu\\n" +"net.gu\\n" +"org.gu\\n" +"web.gu\\n" +"co.gy\\n" +"com.gy\\n" +"edu.gy\\n" +"gov.gy\\n" +"net.gy\\n" +"org.gy\\n" +"com.hk\\n" +"edu.hk\\n" +"gov.hk\\n" +"idv.hk\\n" +"net.hk\\n" +"org.hk\\n" +"com.hn\\n" +"edu.hn\\n" +"gob.hn\\n" +"mil.hn\\n" +"net.hn\\n" +"org.hn\\n" +"com.hr\\n" +"from.hr\\n" +"iz.hr\\n" +"name.hr\\n" +"adult.ht\\n" +"art.ht\\n" +"asso.ht\\n" +"com.ht\\n" +"coop.ht\\n" +"edu.ht\\n" +"firm.ht\\n" +"gouv.ht\\n" +"info.ht\\n" +"med.ht\\n" +"net.ht\\n" +"org.ht\\n" +"perso.ht\\n" +"pol.ht\\n" +"pro.ht\\n" +"rel.ht\\n" +"shop.ht\\n" +"2000.hu\\n" +"agrar.hu\\n" +"bolt.hu\\n" +"casino.hu\\n" +"city.hu\\n" +"co.hu\\n" +"erotica.hu\\n" +"erotika.hu\\n" +"film.hu\\n" +"forum.hu\\n" +"games.hu\\n" +"hotel.hu\\n" +"info.hu\\n" +"ingatlan.hu\\n" +"jogasz.hu\\n" +"konyvelo.hu\\n" +"lakas.hu\\n" +"media.hu\\n" +"news.hu\\n" +"org.hu\\n" +"priv.hu\\n" +"reklam.hu\\n" +"sex.hu\\n" +"shop.hu\\n" +"sport.hu\\n" +"suli.hu\\n" +"szex.hu\\n" +"tm.hu\\n" +"tozsde.hu\\n" +"utazas.hu\\n" +"video.hu\\n" +"ac.id\\n" +"ai.id\\n" +"biz.id\\n" +"co.id\\n" +"desa.id\\n" +"go.id\\n" +"kop.id\\n" +"mil.id\\n" +"my.id\\n" +"net.id\\n" +"or.id\\n" +"ponpes.id\\n" +"sch.id\\n" +"web.id\\n" +"gov.ie\\n" +"ac.il\\n" +"co.il\\n" +"gov.il\\n" +"idf.il\\n" +"k12.il\\n" +"muni.il\\n" +"net.il\\n" +"org.il\\n" +"ac.im\\n" +"co.im\\n" +"ltd.co.im\\n" +"plc.co.im\\n" +"com.im\\n" +"net.im\\n" +"org.im\\n" +"tt.im\\n" +"tv.im\\n" +"5g.in\\n" +"6g.in\\n" +"ac.in\\n" +"aero.in\\n" +"ai.in\\n" +"alumni.in\\n" +"am.in\\n" +"bank.in\\n" +"bihar.in\\n" +"biz.in\\n" +"business.in\\n" +"ca.in\\n" +"cn.in\\n" +"co.in\\n" +"com.in\\n" +"coop.in\\n" +"cs.in\\n" +"delhi.in\\n" +"dr.in\\n" +"edu.in\\n" +"er.in\\n" +"fin.in\\n" +"firm.in\\n" +"gen.in\\n" +"gov.in\\n" +"gujarat.in\\n" +"ind.in\\n" +"info.in\\n" +"int.in\\n" +"internet.in\\n" +"io.in\\n" +"me.in\\n" +"mil.in\\n" +"net.in\\n" +"nic.in\\n" +"org.in\\n" +"pg.in\\n" +"post.in\\n" +"pro.in\\n" +"res.in\\n" +"school.in\\n" +"travel.in\\n" +"tv.in\\n" +"ub.in\\n" +"uk.in\\n" +"up.in\\n" +"us.in\\n" +"eu.int\\n" +"co.io\\n" +"com.io\\n" +"edu.io\\n" +"gov.io\\n" +"mil.io\\n" +"net.io\\n" +"nom.io\\n" +"org.io\\n" +"com.iq\\n" +"edu.iq\\n" +"gov.iq\\n" +"mil.iq\\n" +"net.iq\\n" +"org.iq\\n" +"ac.ir\\n" +"co.ir\\n" +"gov.ir\\n" +"id.ir\\n" +"net.ir\\n" +"org.ir\\n" +"sch.ir\\n" +"edu.it\\n" +"gov.it\\n" +"abr.it\\n" +"abruzzo.it\\n" +"aosta-valley.it\\n" +"aostavalley.it\\n" +"bas.it\\n" +"basilicata.it\\n" +"cal.it\\n" +"calabria.it\\n" +"cam.it\\n" +"campania.it\\n" +"emilia-romagna.it\\n" +"emiliaromagna.it\\n" +"emr.it\\n" +"friuli-v-giulia.it\\n" +"friuli-ve-giulia.it\\n" +"friuli-vegiulia.it\\n" +"friuli-venezia-giulia.it\\n" +"friuli-veneziagiulia.it\\n" +"friuli-vgiulia.it\\n" +"friuliv-giulia.it\\n" +"friulive-giulia.it\\n" +"friulivegiulia.it\\n" +"friulivenezia-giulia.it\\n" +"friuliveneziagiulia.it\\n" +"friulivgiulia.it\\n" +"fvg.it\\n" +"laz.it\\n" +"lazio.it\\n" +"lig.it\\n" +"liguria.it\\n" +"lom.it\\n" +"lombardia.it\\n" +"lombardy.it\\n" +"lucania.it\\n" +"mar.it\\n" +"marche.it\\n" +"mol.it\\n" +"molise.it\\n" +"piedmont.it\\n" +"piemonte.it\\n" +"pmn.it\\n" +"pug.it\\n" +"puglia.it\\n" +"sar.it\\n" +"sardegna.it\\n" +"sardinia.it\\n" +"sic.it\\n" +"sicilia.it\\n" +"sicily.it\\n" +"taa.it\\n" +"tos.it\\n" +"toscana.it\\n" +"trentin-sud-tirol.it\\n" +"trentin-sudtirol.it\\n" +"trentin-sued-tirol.it\\n" +"trentin-suedtirol.it\\n" +"trentino-a-adige.it\\n" +"trentino-aadige.it\\n" +"trentino-alto-adige.it\\n" +"trentino-altoadige.it\\n" +"trentino-s-tirol.it\\n" +"trentino-stirol.it\\n" +"trentino-sud-tirol.it\\n" +"trentino-sudtirol.it\\n" +"trentino-sued-tirol.it\\n" +"trentino-suedtirol.it\\n" +"trentinoa-adige.it\\n" +"trentinoaadige.it\\n" +"trentinoalto-adige.it\\n" +"trentinoaltoadige.it\\n" +"trentinos-tirol.it\\n" +"trentinostirol.it\\n" +"trentinosud-tirol.it\\n" +"trentinosued-tirol.it\\n" +"trentinosuedtirol.it\\n" +"trentinsud-tirol.it\\n" +"trentinsudtirol.it\\n" +"trentinsued-tirol.it\\n" +"trentinsuedtirol.it\\n" +"tuscany.it\\n" +"umb.it\\n" +"umbria.it\\n" +"val-d-aosta.it\\n" +"val-daosta.it\\n" +"vald-aosta.it\\n" +"valle-aosta.it\\n" +"valle-d-aosta.it\\n" +"valle-daosta.it\\n" +"valleaosta.it\\n" +"valled-aosta.it\\n" +"valledaosta.it\\n" +"vallee-aoste.it\\n" +"vallee-d-aoste.it\\n" +"valleeaoste.it\\n" +"valleedaoste.it\\n" +"vao.it\\n" +"vda.it\\n" +"ven.it\\n" +"veneto.it\\n" +"ag.it\\n" +"agrigento.it\\n" +"al.it\\n" +"alessandria.it\\n" +"alto-adige.it\\n" +"altoadige.it\\n" +"an.it\\n" +"ancona.it\\n" +"andria-barletta-trani.it\\n" +"andria-trani-barletta.it\\n" +"andriabarlettatrani.it\\n" +"andriatranibarletta.it\\n" +"ao.it\\n" +"aosta.it\\n" +"aoste.it\\n" +"ap.it\\n" +"aq.it\\n" +"ar.it\\n" +"arezzo.it\\n" +"ascoli-piceno.it\\n" +"ascolipiceno.it\\n" +"asti.it\\n" +"at.it\\n" +"av.it\\n" +"avellino.it\\n" +"ba.it\\n" +"balsan.it\\n" +"balsan-sudtirol.it\\n" +"balsan-suedtirol.it\\n" +"bari.it\\n" +"barletta-trani-andria.it\\n" +"barlettatraniandria.it\\n" +"belluno.it\\n" +"benevento.it\\n" +"bergamo.it\\n" +"bg.it\\n" +"bi.it\\n" +"biella.it\\n" +"bl.it\\n" +"bn.it\\n" +"bo.it\\n" +"bologna.it\\n" +"bolzano.it\\n" +"bolzano-altoadige.it\\n" +"bozen.it\\n" +"bozen-sudtirol.it\\n" +"bozen-suedtirol.it\\n" +"br.it\\n" +"brescia.it\\n" +"brindisi.it\\n" +"bs.it\\n" +"bt.it\\n" +"bulsan.it\\n" +"bulsan-sudtirol.it\\n" +"bulsan-suedtirol.it\\n" +"bz.it\\n" +"ca.it\\n" +"cagliari.it\\n" +"caltanissetta.it\\n" +"campidano-medio.it\\n" +"campidanomedio.it\\n" +"campobasso.it\\n" +"carbonia-iglesias.it\\n" +"carboniaiglesias.it\\n" +"carrara-massa.it\\n" +"carraramassa.it\\n" +"caserta.it\\n" +"catania.it\\n" +"catanzaro.it\\n" +"cb.it\\n" +"ce.it\\n" +"cesena-forli.it\\n" +"cesenaforli.it\\n" +"ch.it\\n" +"chieti.it\\n" +"ci.it\\n" +"cl.it\\n" +"cn.it\\n" +"co.it\\n" +"como.it\\n" +"cosenza.it\\n" +"cr.it\\n" +"cremona.it\\n" +"crotone.it\\n" +"cs.it\\n" +"ct.it\\n" +"cuneo.it\\n" +"cz.it\\n" +"dell-ogliastra.it\\n" +"dellogliastra.it\\n" +"en.it\\n" +"enna.it\\n" +"fc.it\\n" +"fe.it\\n" +"fermo.it\\n" +"ferrara.it\\n" +"fg.it\\n" +"fi.it\\n" +"firenze.it\\n" +"florence.it\\n" +"fm.it\\n" +"foggia.it\\n" +"forli-cesena.it\\n" +"forlicesena.it\\n" +"fr.it\\n" +"frosinone.it\\n" +"ge.it\\n" +"genoa.it\\n" +"genova.it\\n" +"go.it\\n" +"gorizia.it\\n" +"gr.it\\n" +"grosseto.it\\n" +"iglesias-carbonia.it\\n" +"iglesiascarbonia.it\\n" +"im.it\\n" +"imperia.it\\n" +"is.it\\n" +"isernia.it\\n" +"kr.it\\n" +"la-spezia.it\\n" +"laquila.it\\n" +"laspezia.it\\n" +"latina.it\\n" +"lc.it\\n" +"le.it\\n" +"lecce.it\\n" +"lecco.it\\n" +"li.it\\n" +"livorno.it\\n" +"lo.it\\n" +"lodi.it\\n" +"lt.it\\n" +"lu.it\\n" +"lucca.it\\n" +"macerata.it\\n" +"mantova.it\\n" +"massa-carrara.it\\n" +"massacarrara.it\\n" +"matera.it\\n" +"mb.it\\n" +"mc.it\\n" +"me.it\\n" +"medio-campidano.it\\n" +"mediocampidano.it\\n" +"messina.it\\n" +"mi.it\\n" +"milan.it\\n" +"milano.it\\n" +"mn.it\\n" +"mo.it\\n" +"modena.it\\n" +"monza.it\\n" +"monza-brianza.it\\n" +"monza-e-della-brianza.it\\n" +"monzabrianza.it\\n" +"monzaebrianza.it\\n" +"monzaedellabrianza.it\\n" +"ms.it\\n" +"mt.it\\n" +"na.it\\n" +"naples.it\\n" +"napoli.it\\n" +"no.it\\n" +"novara.it\\n" +"nu.it\\n" +"nuoro.it\\n" +"og.it\\n" +"ogliastra.it\\n" +"olbia-tempio.it\\n" +"olbiatempio.it\\n" +"or.it\\n" +"oristano.it\\n" +"ot.it\\n" +"pa.it\\n" +"padova.it\\n" +"padua.it\\n" +"palermo.it\\n" +"parma.it\\n" +"pavia.it\\n" +"pc.it\\n" +"pd.it\\n" +"pe.it\\n" +"perugia.it\\n" +"pesaro-urbino.it\\n" +"pesarourbino.it\\n" +"pescara.it\\n" +"pg.it\\n" +"pi.it\\n" +"piacenza.it\\n" +"pisa.it\\n" +"pistoia.it\\n" +"pn.it\\n" +"po.it\\n" +"pordenone.it\\n" +"potenza.it\\n" +"pr.it\\n" +"prato.it\\n" +"pt.it\\n" +"pu.it\\n" +"pv.it\\n" +"pz.it\\n" +"ra.it\\n" +"ragusa.it\\n" +"ravenna.it\\n" +"rc.it\\n" +"re.it\\n" +"reggio-calabria.it\\n" +"reggio-emilia.it\\n" +"reggiocalabria.it\\n" +"reggioemilia.it\\n" +"rg.it\\n" +"ri.it\\n" +"rieti.it\\n" +"rimini.it\\n" +"rm.it\\n" +"rn.it\\n" +"ro.it\\n" +"roma.it\\n" +"rome.it\\n" +"rovigo.it\\n" +"sa.it\\n" +"salerno.it\\n" +"sassari.it\\n" +"savona.it\\n" +"si.it\\n" +"siena.it\\n" +"siracusa.it\\n" +"so.it\\n" +"sondrio.it\\n" +"sp.it\\n" +"sr.it\\n" +"ss.it\\n" +"su.it\\n" +"sud-sardegna.it\\n" +"sudsardegna.it\\n" +"suedtirol.it\\n" +"sv.it\\n" +"ta.it\\n" +"taranto.it\\n" +"te.it\\n" +"tempio-olbia.it\\n" +"tempioolbia.it\\n" +"teramo.it\\n" +"terni.it\\n" +"tn.it\\n" +"to.it\\n" +"torino.it\\n" +"tp.it\\n" +"tr.it\\n" +"trani-andria-barletta.it\\n" +"trani-barletta-andria.it\\n" +"traniandriabarletta.it\\n" +"tranibarlettaandria.it\\n" +"trapani.it\\n" +"trentino.it\\n" +"trento.it\\n" +"treviso.it\\n" +"trieste.it\\n" +"ts.it\\n" +"turin.it\\n" +"tv.it\\n" +"ud.it\\n" +"udine.it\\n" +"urbino-pesaro.it\\n" +"urbinopesaro.it\\n" +"va.it\\n" +"varese.it\\n" +"vb.it\\n" +"vc.it\\n" +"ve.it\\n" +"venezia.it\\n" +"venice.it\\n" +"verbania.it\\n" +"verbano-cusio-ossola.it\\n" +"vercelli.it\\n" +"verona.it\\n" +"vi.it\\n" +"vibo-valentia.it\\n" +"vibovalentia.it\\n" +"vicenza.it\\n" +"viterbo.it\\n" +"vr.it\\n" +"vs.it\\n" +"vt.it\\n" +"vv.it\\n" +"co.je\\n" +"net.je\\n" +"org.je\\n" +"agri.jo\\n" +"ai.jo\\n" +"com.jo\\n" +"edu.jo\\n" +"eng.jo\\n" +"fm.jo\\n" +"gov.jo\\n" +"mil.jo\\n" +"net.jo\\n" +"org.jo\\n" +"per.jo\\n" +"phd.jo\\n" +"sch.jo\\n" +"tv.jo\\n" +"ac.jp\\n" +"ad.jp\\n" +"co.jp\\n" +"ed.jp\\n" +"go.jp\\n" +"gr.jp\\n" +"lg.jp\\n" +"ne.jp\\n" +"or.jp\\n" +"aichi.jp\\n" +"akita.jp\\n" +"aomori.jp\\n" +"chiba.jp\\n" +"ehime.jp\\n" +"fukui.jp\\n" +"fukuoka.jp\\n" +"fukushima.jp\\n" +"gifu.jp\\n" +"gunma.jp\\n" +"hiroshima.jp\\n" +"hokkaido.jp\\n" +"hyogo.jp\\n" +"ibaraki.jp\\n" +"ishikawa.jp\\n" +"iwate.jp\\n" +"kagawa.jp\\n" +"kagoshima.jp\\n" +"kanagawa.jp\\n" +"kochi.jp\\n" +"kumamoto.jp\\n" +"kyoto.jp\\n" +"mie.jp\\n" +"miyagi.jp\\n" +"miyazaki.jp\\n" +"nagano.jp\\n" +"nagasaki.jp\\n" +"nara.jp\\n" +"niigata.jp\\n" +"oita.jp\\n" +"okayama.jp\\n" +"okinawa.jp\\n" +"osaka.jp\\n" +"saga.jp\\n" +"saitama.jp\\n" +"shiga.jp\\n" +"shimane.jp\\n" +"shizuoka.jp\\n" +"tochigi.jp\\n" +"tokushima.jp\\n" +"tokyo.jp\\n" +"tottori.jp\\n" +"toyama.jp\\n" +"wakayama.jp\\n" +"yamagata.jp\\n" +"yamaguchi.jp\\n" +"yamanashi.jp\\n" +"aisai.aichi.jp\\n" +"ama.aichi.jp\\n" +"anjo.aichi.jp\\n" +"asuke.aichi.jp\\n" +"chiryu.aichi.jp\\n" +"chita.aichi.jp\\n" +"fuso.aichi.jp\\n" +"gamagori.aichi.jp\\n" +"handa.aichi.jp\\n" +"hazu.aichi.jp\\n" +"hekinan.aichi.jp\\n" +"higashiura.aichi.jp\\n" +"ichinomiya.aichi.jp\\n" +"inazawa.aichi.jp\\n" +"inuyama.aichi.jp\\n" +"isshiki.aichi.jp\\n" +"iwakura.aichi.jp\\n" +"kanie.aichi.jp\\n" +"kariya.aichi.jp\\n" +"kasugai.aichi.jp\\n" +"kira.aichi.jp\\n" +"kiyosu.aichi.jp\\n" +"komaki.aichi.jp\\n" +"konan.aichi.jp\\n" +"kota.aichi.jp\\n" +"mihama.aichi.jp\\n" +"miyoshi.aichi.jp\\n" +"nishio.aichi.jp\\n" +"nisshin.aichi.jp\\n" +"obu.aichi.jp\\n" +"oguchi.aichi.jp\\n" +"oharu.aichi.jp\\n" +"okazaki.aichi.jp\\n" +"owariasahi.aichi.jp\\n" +"seto.aichi.jp\\n" +"shikatsu.aichi.jp\\n" +"shinshiro.aichi.jp\\n" +"shitara.aichi.jp\\n" +"tahara.aichi.jp\\n" +"takahama.aichi.jp\\n" +"tobishima.aichi.jp\\n" +"toei.aichi.jp\\n" +"togo.aichi.jp\\n" +"tokai.aichi.jp\\n" +"tokoname.aichi.jp\\n" +"toyoake.aichi.jp\\n" +"toyohashi.aichi.jp\\n" +"toyokawa.aichi.jp\\n" +"toyone.aichi.jp\\n" +"toyota.aichi.jp\\n" +"tsushima.aichi.jp\\n" +"yatomi.aichi.jp\\n" +"akita.akita.jp\\n" +"daisen.akita.jp\\n" +"fujisato.akita.jp\\n" +"gojome.akita.jp\\n" +"hachirogata.akita.jp\\n" +"happou.akita.jp\\n" +"higashinaruse.akita.jp\\n" +"honjo.akita.jp\\n" +"honjyo.akita.jp\\n" +"ikawa.akita.jp\\n" +"kamikoani.akita.jp\\n" +"kamioka.akita.jp\\n" +"katagami.akita.jp\\n" +"kazuno.akita.jp\\n" +"kitaakita.akita.jp\\n" +"kosaka.akita.jp\\n" +"kyowa.akita.jp\\n" +"misato.akita.jp\\n" +"mitane.akita.jp\\n" +"moriyoshi.akita.jp\\n" +"nikaho.akita.jp\\n" +"noshiro.akita.jp\\n" +"odate.akita.jp\\n" +"oga.akita.jp\\n" +"ogata.akita.jp\\n" +"semboku.akita.jp\\n" +"yokote.akita.jp\\n" +"yurihonjo.akita.jp\\n" +"aomori.aomori.jp\\n" +"gonohe.aomori.jp\\n" +"hachinohe.aomori.jp\\n" +"hashikami.aomori.jp\\n" +"hiranai.aomori.jp\\n" +"hirosaki.aomori.jp\\n" +"itayanagi.aomori.jp\\n" +"kuroishi.aomori.jp\\n" +"misawa.aomori.jp\\n" +"mutsu.aomori.jp\\n" +"nakadomari.aomori.jp\\n" +"noheji.aomori.jp\\n" +"oirase.aomori.jp\\n" +"owani.aomori.jp\\n" +"rokunohe.aomori.jp\\n" +"sannohe.aomori.jp\\n" +"shichinohe.aomori.jp\\n" +"shingo.aomori.jp\\n" +"takko.aomori.jp\\n" +"towada.aomori.jp\\n" +"tsugaru.aomori.jp\\n" +"tsuruta.aomori.jp\\n" +"abiko.chiba.jp\\n" +"asahi.chiba.jp\\n" +"chonan.chiba.jp\\n" +"chosei.chiba.jp\\n" +"choshi.chiba.jp\\n" +"chuo.chiba.jp\\n" +"funabashi.chiba.jp\\n" +"futtsu.chiba.jp\\n" +"hanamigawa.chiba.jp\\n" +"ichihara.chiba.jp\\n" +"ichikawa.chiba.jp\\n" +"ichinomiya.chiba.jp\\n" +"inzai.chiba.jp\\n" +"isumi.chiba.jp\\n" +"kamagaya.chiba.jp\\n" +"kamogawa.chiba.jp\\n" +"kashiwa.chiba.jp\\n" +"katori.chiba.jp\\n" +"katsuura.chiba.jp\\n" +"kimitsu.chiba.jp\\n" +"kisarazu.chiba.jp\\n" +"kozaki.chiba.jp\\n" +"kujukuri.chiba.jp\\n" +"kyonan.chiba.jp\\n" +"matsudo.chiba.jp\\n" +"midori.chiba.jp\\n" +"mihama.chiba.jp\\n" +"minamiboso.chiba.jp\\n" +"mobara.chiba.jp\\n" +"mutsuzawa.chiba.jp\\n" +"nagara.chiba.jp\\n" +"nagareyama.chiba.jp\\n" +"narashino.chiba.jp\\n" +"narita.chiba.jp\\n" +"noda.chiba.jp\\n" +"oamishirasato.chiba.jp\\n" +"omigawa.chiba.jp\\n" +"onjuku.chiba.jp\\n" +"otaki.chiba.jp\\n" +"sakae.chiba.jp\\n" +"sakura.chiba.jp\\n" +"shimofusa.chiba.jp\\n" +"shirako.chiba.jp\\n" +"shiroi.chiba.jp\\n" +"shisui.chiba.jp\\n" +"sodegaura.chiba.jp\\n" +"sosa.chiba.jp\\n" +"tako.chiba.jp\\n" +"tateyama.chiba.jp\\n" +"togane.chiba.jp\\n" +"tohnosho.chiba.jp\\n" +"tomisato.chiba.jp\\n" +"urayasu.chiba.jp\\n" +"yachimata.chiba.jp\\n" +"yachiyo.chiba.jp\\n" +"yokaichiba.chiba.jp\\n" +"yokoshibahikari.chiba.jp\\n" +"yotsukaido.chiba.jp\\n" +"ainan.ehime.jp\\n" +"honai.ehime.jp\\n" +"ikata.ehime.jp\\n" +"imabari.ehime.jp\\n" +"iyo.ehime.jp\\n" +"kamijima.ehime.jp\\n" +"kihoku.ehime.jp\\n" +"kumakogen.ehime.jp\\n" +"masaki.ehime.jp\\n" +"matsuno.ehime.jp\\n" +"matsuyama.ehime.jp\\n" +"namikata.ehime.jp\\n" +"niihama.ehime.jp\\n" +"ozu.ehime.jp\\n" +"saijo.ehime.jp\\n" +"seiyo.ehime.jp\\n" +"shikokuchuo.ehime.jp\\n" +"tobe.ehime.jp\\n" +"toon.ehime.jp\\n" +"uchiko.ehime.jp\\n" +"uwajima.ehime.jp\\n" +"yawatahama.ehime.jp\\n" +"echizen.fukui.jp\\n" +"eiheiji.fukui.jp\\n" +"fukui.fukui.jp\\n" +"ikeda.fukui.jp\\n" +"katsuyama.fukui.jp\\n" +"mihama.fukui.jp\\n" +"minamiechizen.fukui.jp\\n" +"obama.fukui.jp\\n" +"ohi.fukui.jp\\n" +"ono.fukui.jp\\n" +"sabae.fukui.jp\\n" +"sakai.fukui.jp\\n" +"takahama.fukui.jp\\n" +"tsuruga.fukui.jp\\n" +"wakasa.fukui.jp\\n" +"ashiya.fukuoka.jp\\n" +"buzen.fukuoka.jp\\n" +"chikugo.fukuoka.jp\\n" +"chikuho.fukuoka.jp\\n" +"chikujo.fukuoka.jp\\n" +"chikushino.fukuoka.jp\\n" +"chikuzen.fukuoka.jp\\n" +"chuo.fukuoka.jp\\n" +"dazaifu.fukuoka.jp\\n" +"fukuchi.fukuoka.jp\\n" +"hakata.fukuoka.jp\\n" +"higashi.fukuoka.jp\\n" +"hirokawa.fukuoka.jp\\n" +"hisayama.fukuoka.jp\\n" +"iizuka.fukuoka.jp\\n" +"inatsuki.fukuoka.jp\\n" +"kaho.fukuoka.jp\\n" +"kasuga.fukuoka.jp\\n" +"kasuya.fukuoka.jp\\n" +"kawara.fukuoka.jp\\n" +"keisen.fukuoka.jp\\n" +"koga.fukuoka.jp\\n" +"kurate.fukuoka.jp\\n" +"kurogi.fukuoka.jp\\n" +"kurume.fukuoka.jp\\n" +"minami.fukuoka.jp\\n" +"miyako.fukuoka.jp\\n" +"miyama.fukuoka.jp\\n" +"miyawaka.fukuoka.jp\\n" +"mizumaki.fukuoka.jp\\n" +"munakata.fukuoka.jp\\n" +"nakagawa.fukuoka.jp\\n" +"nakama.fukuoka.jp\\n" +"nishi.fukuoka.jp\\n" +"nogata.fukuoka.jp\\n" +"ogori.fukuoka.jp\\n" +"okagaki.fukuoka.jp\\n" +"okawa.fukuoka.jp\\n" +"oki.fukuoka.jp\\n" +"omuta.fukuoka.jp\\n" +"onga.fukuoka.jp\\n" +"onojo.fukuoka.jp\\n" +"oto.fukuoka.jp\\n" +"saigawa.fukuoka.jp\\n" +"sasaguri.fukuoka.jp\\n" +"shingu.fukuoka.jp\\n" +"shinyoshitomi.fukuoka.jp\\n" +"shonai.fukuoka.jp\\n" +"soeda.fukuoka.jp\\n" +"sue.fukuoka.jp\\n" +"tachiarai.fukuoka.jp\\n" +"tagawa.fukuoka.jp\\n" +"takata.fukuoka.jp\\n" +"toho.fukuoka.jp\\n" +"toyotsu.fukuoka.jp\\n" +"tsuiki.fukuoka.jp\\n" +"ukiha.fukuoka.jp\\n" +"umi.fukuoka.jp\\n" +"usui.fukuoka.jp\\n" +"yamada.fukuoka.jp\\n" +"yame.fukuoka.jp\\n" +"yanagawa.fukuoka.jp\\n" +"yukuhashi.fukuoka.jp\\n" +"aizubange.fukushima.jp\\n" +"aizumisato.fukushima.jp\\n" +"aizuwakamatsu.fukushima.jp\\n" +"asakawa.fukushima.jp\\n" +"bandai.fukushima.jp\\n" +"date.fukushima.jp\\n" +"fukushima.fukushima.jp\\n" +"furudono.fukushima.jp\\n" +"futaba.fukushima.jp\\n" +"hanawa.fukushima.jp\\n" +"higashi.fukushima.jp\\n" +"hirata.fukushima.jp\\n" +"hirono.fukushima.jp\\n" +"iitate.fukushima.jp\\n" +"inawashiro.fukushima.jp\\n" +"ishikawa.fukushima.jp\\n" +"iwaki.fukushima.jp\\n" +"izumizaki.fukushima.jp\\n" +"kagamiishi.fukushima.jp\\n" +"kaneyama.fukushima.jp\\n" +"kawamata.fukushima.jp\\n" +"kitakata.fukushima.jp\\n" +"kitashiobara.fukushima.jp\\n" +"koori.fukushima.jp\\n" +"koriyama.fukushima.jp\\n" +"kunimi.fukushima.jp\\n" +"miharu.fukushima.jp\\n" +"mishima.fukushima.jp\\n" +"namie.fukushima.jp\\n" +"nango.fukushima.jp\\n" +"nishiaizu.fukushima.jp\\n" +"nishigo.fukushima.jp\\n" +"okuma.fukushima.jp\\n" +"omotego.fukushima.jp\\n" +"ono.fukushima.jp\\n" +"otama.fukushima.jp\\n" +"samegawa.fukushima.jp\\n" +"shimogo.fukushima.jp\\n" +"shirakawa.fukushima.jp\\n" +"showa.fukushima.jp\\n" +"soma.fukushima.jp\\n" +"sukagawa.fukushima.jp\\n" +"taishin.fukushima.jp\\n" +"tamakawa.fukushima.jp\\n" +"tanagura.fukushima.jp\\n" +"tenei.fukushima.jp\\n" +"yabuki.fukushima.jp\\n" +"yamato.fukushima.jp\\n" +"yamatsuri.fukushima.jp\\n" +"yanaizu.fukushima.jp\\n" +"yugawa.fukushima.jp\\n" +"anpachi.gifu.jp\\n" +"ena.gifu.jp\\n" +"gifu.gifu.jp\\n" +"ginan.gifu.jp\\n" +"godo.gifu.jp\\n" +"gujo.gifu.jp\\n" +"hashima.gifu.jp\\n" +"hichiso.gifu.jp\\n" +"hida.gifu.jp\\n" +"higashishirakawa.gifu.jp\\n" +"ibigawa.gifu.jp\\n" +"ikeda.gifu.jp\\n" +"kakamigahara.gifu.jp\\n" +"kani.gifu.jp\\n" +"kasahara.gifu.jp\\n" +"kasamatsu.gifu.jp\\n" +"kawaue.gifu.jp\\n" +"kitagata.gifu.jp\\n" +"mino.gifu.jp\\n" +"minokamo.gifu.jp\\n" +"mitake.gifu.jp\\n" +"mizunami.gifu.jp\\n" +"motosu.gifu.jp\\n" +"nakatsugawa.gifu.jp\\n" +"ogaki.gifu.jp\\n" +"sakahogi.gifu.jp\\n" +"seki.gifu.jp\\n" +"sekigahara.gifu.jp\\n" +"shirakawa.gifu.jp\\n" +"tajimi.gifu.jp\\n" +"takayama.gifu.jp\\n" +"tarui.gifu.jp\\n" +"toki.gifu.jp\\n" +"tomika.gifu.jp\\n" +"wanouchi.gifu.jp\\n" +"yamagata.gifu.jp\\n" +"yaotsu.gifu.jp\\n" +"yoro.gifu.jp\\n" +"annaka.gunma.jp\\n" +"chiyoda.gunma.jp\\n" +"fujioka.gunma.jp\\n" +"higashiagatsuma.gunma.jp\\n" +"isesaki.gunma.jp\\n" +"itakura.gunma.jp\\n" +"kanna.gunma.jp\\n" +"kanra.gunma.jp\\n" +"katashina.gunma.jp\\n" +"kawaba.gunma.jp\\n" +"kiryu.gunma.jp\\n" +"kusatsu.gunma.jp\\n" +"maebashi.gunma.jp\\n" +"meiwa.gunma.jp\\n" +"midori.gunma.jp\\n" +"minakami.gunma.jp\\n" +"naganohara.gunma.jp\\n" +"nakanojo.gunma.jp\\n" +"nanmoku.gunma.jp\\n" +"numata.gunma.jp\\n" +"oizumi.gunma.jp\\n" +"ora.gunma.jp\\n" +"ota.gunma.jp\\n" +"shibukawa.gunma.jp\\n" +"shimonita.gunma.jp\\n" +"shinto.gunma.jp\\n" +"showa.gunma.jp\\n" +"takasaki.gunma.jp\\n" +"takayama.gunma.jp\\n" +"tamamura.gunma.jp\\n" +"tatebayashi.gunma.jp\\n" +"tomioka.gunma.jp\\n" +"tsukiyono.gunma.jp\\n" +"tsumagoi.gunma.jp\\n" +"ueno.gunma.jp\\n" +"yoshioka.gunma.jp\\n" +"asaminami.hiroshima.jp\\n" +"daiwa.hiroshima.jp\\n" +"etajima.hiroshima.jp\\n" +"fuchu.hiroshima.jp\\n" +"fukuyama.hiroshima.jp\\n" +"hatsukaichi.hiroshima.jp\\n" +"higashihiroshima.hiroshima.jp\\n" +"hongo.hiroshima.jp\\n" +"jinsekikogen.hiroshima.jp\\n" +"kaita.hiroshima.jp\\n" +"kui.hiroshima.jp\\n" +"kumano.hiroshima.jp\\n" +"kure.hiroshima.jp\\n" +"mihara.hiroshima.jp\\n" +"miyoshi.hiroshima.jp\\n" +"naka.hiroshima.jp\\n" +"onomichi.hiroshima.jp\\n" +"osakikamijima.hiroshima.jp\\n" +"otake.hiroshima.jp\\n" +"saka.hiroshima.jp\\n" +"sera.hiroshima.jp\\n" +"seranishi.hiroshima.jp\\n" +"shinichi.hiroshima.jp\\n" +"shobara.hiroshima.jp\\n" +"takehara.hiroshima.jp\\n" +"abashiri.hokkaido.jp\\n" +"abira.hokkaido.jp\\n" +"aibetsu.hokkaido.jp\\n" +"akabira.hokkaido.jp\\n" +"akkeshi.hokkaido.jp\\n" +"asahikawa.hokkaido.jp\\n" +"ashibetsu.hokkaido.jp\\n" +"ashoro.hokkaido.jp\\n" +"assabu.hokkaido.jp\\n" +"atsuma.hokkaido.jp\\n" +"bibai.hokkaido.jp\\n" +"biei.hokkaido.jp\\n" +"bifuka.hokkaido.jp\\n" +"bihoro.hokkaido.jp\\n" +"biratori.hokkaido.jp\\n" +"chippubetsu.hokkaido.jp\\n" +"chitose.hokkaido.jp\\n" +"date.hokkaido.jp\\n" +"ebetsu.hokkaido.jp\\n" +"embetsu.hokkaido.jp\\n" +"eniwa.hokkaido.jp\\n" +"erimo.hokkaido.jp\\n" +"esan.hokkaido.jp\\n" +"esashi.hokkaido.jp\\n" +"fukagawa.hokkaido.jp\\n" +"fukushima.hokkaido.jp\\n" +"furano.hokkaido.jp\\n" +"furubira.hokkaido.jp\\n" +"haboro.hokkaido.jp\\n" +"hakodate.hokkaido.jp\\n" +"hamatonbetsu.hokkaido.jp\\n" +"hidaka.hokkaido.jp\\n" +"higashikagura.hokkaido.jp\\n" +"higashikawa.hokkaido.jp\\n" +"hiroo.hokkaido.jp\\n" +"hokuryu.hokkaido.jp\\n" +"hokuto.hokkaido.jp\\n" +"honbetsu.hokkaido.jp\\n" +"horokanai.hokkaido.jp\\n" +"horonobe.hokkaido.jp\\n" +"ikeda.hokkaido.jp\\n" +"imakane.hokkaido.jp\\n" +"ishikari.hokkaido.jp\\n" +"iwamizawa.hokkaido.jp\\n" +"iwanai.hokkaido.jp\\n" +"kamifurano.hokkaido.jp\\n" +"kamikawa.hokkaido.jp\\n" +"kamishihoro.hokkaido.jp\\n" +"kamisunagawa.hokkaido.jp\\n" +"kamoenai.hokkaido.jp\\n" +"kayabe.hokkaido.jp\\n" +"kembuchi.hokkaido.jp\\n" +"kikonai.hokkaido.jp\\n" +"kimobetsu.hokkaido.jp\\n" +"kitahiroshima.hokkaido.jp\\n" +"kitami.hokkaido.jp\\n" +"kiyosato.hokkaido.jp\\n" +"koshimizu.hokkaido.jp\\n" +"kunneppu.hokkaido.jp\\n" +"kuriyama.hokkaido.jp\\n" +"kuromatsunai.hokkaido.jp\\n" +"kushiro.hokkaido.jp\\n" +"kutchan.hokkaido.jp\\n" +"kyowa.hokkaido.jp\\n" +"mashike.hokkaido.jp\\n" +"matsumae.hokkaido.jp\\n" +"mikasa.hokkaido.jp\\n" +"minamifurano.hokkaido.jp\\n" +"mombetsu.hokkaido.jp\\n" +"moseushi.hokkaido.jp\\n" +"mukawa.hokkaido.jp\\n" +"muroran.hokkaido.jp\\n" +"naie.hokkaido.jp\\n" +"nakagawa.hokkaido.jp\\n" +"nakasatsunai.hokkaido.jp\\n" +"nakatombetsu.hokkaido.jp\\n" +"nanae.hokkaido.jp\\n" +"nanporo.hokkaido.jp\\n" +"nayoro.hokkaido.jp\\n" +"nemuro.hokkaido.jp\\n" +"niikappu.hokkaido.jp\\n" +"niki.hokkaido.jp\\n" +"nishiokoppe.hokkaido.jp\\n" +"noboribetsu.hokkaido.jp\\n" +"numata.hokkaido.jp\\n" +"obihiro.hokkaido.jp\\n" +"obira.hokkaido.jp\\n" +"oketo.hokkaido.jp\\n" +"okoppe.hokkaido.jp\\n" +"otaru.hokkaido.jp\\n" +"otobe.hokkaido.jp\\n" +"otofuke.hokkaido.jp\\n" +"otoineppu.hokkaido.jp\\n" +"oumu.hokkaido.jp\\n" +"ozora.hokkaido.jp\\n" +"pippu.hokkaido.jp\\n" +"rankoshi.hokkaido.jp\\n" +"rebun.hokkaido.jp\\n" +"rikubetsu.hokkaido.jp\\n" +"rishiri.hokkaido.jp\\n" +"rishirifuji.hokkaido.jp\\n" +"saroma.hokkaido.jp\\n" +"sarufutsu.hokkaido.jp\\n" +"shakotan.hokkaido.jp\\n" +"shari.hokkaido.jp\\n" +"shibecha.hokkaido.jp\\n" +"shibetsu.hokkaido.jp\\n" +"shikabe.hokkaido.jp\\n" +"shikaoi.hokkaido.jp\\n" +"shimamaki.hokkaido.jp\\n" +"shimizu.hokkaido.jp\\n" +"shimokawa.hokkaido.jp\\n" +"shinshinotsu.hokkaido.jp\\n" +"shintoku.hokkaido.jp\\n" +"shiranuka.hokkaido.jp\\n" +"shiraoi.hokkaido.jp\\n" +"shiriuchi.hokkaido.jp\\n" +"sobetsu.hokkaido.jp\\n" +"sunagawa.hokkaido.jp\\n" +"taiki.hokkaido.jp\\n" +"takasu.hokkaido.jp\\n" +"takikawa.hokkaido.jp\\n" +"takinoue.hokkaido.jp\\n" +"teshikaga.hokkaido.jp\\n" +"tobetsu.hokkaido.jp\\n" +"tohma.hokkaido.jp\\n" +"tomakomai.hokkaido.jp\\n" +"tomari.hokkaido.jp\\n" +"toya.hokkaido.jp\\n" +"toyako.hokkaido.jp\\n" +"toyotomi.hokkaido.jp\\n" +"toyoura.hokkaido.jp\\n" +"tsubetsu.hokkaido.jp\\n" +"tsukigata.hokkaido.jp\\n" +"urakawa.hokkaido.jp\\n" +"urausu.hokkaido.jp\\n" +"uryu.hokkaido.jp\\n" +"utashinai.hokkaido.jp\\n" +"wakkanai.hokkaido.jp\\n" +"wassamu.hokkaido.jp\\n" +"yakumo.hokkaido.jp\\n" +"yoichi.hokkaido.jp\\n" +"aioi.hyogo.jp\\n" +"akashi.hyogo.jp\\n" +"ako.hyogo.jp\\n" +"amagasaki.hyogo.jp\\n" +"aogaki.hyogo.jp\\n" +"asago.hyogo.jp\\n" +"ashiya.hyogo.jp\\n" +"awaji.hyogo.jp\\n" +"fukusaki.hyogo.jp\\n" +"goshiki.hyogo.jp\\n" +"harima.hyogo.jp\\n" +"himeji.hyogo.jp\\n" +"ichikawa.hyogo.jp\\n" +"inagawa.hyogo.jp\\n" +"itami.hyogo.jp\\n" +"kakogawa.hyogo.jp\\n" +"kamigori.hyogo.jp\\n" +"kamikawa.hyogo.jp\\n" +"kasai.hyogo.jp\\n" +"kasuga.hyogo.jp\\n" +"kawanishi.hyogo.jp\\n" +"miki.hyogo.jp\\n" +"minamiawaji.hyogo.jp\\n" +"nishinomiya.hyogo.jp\\n" +"nishiwaki.hyogo.jp\\n" +"ono.hyogo.jp\\n" +"sanda.hyogo.jp\\n" +"sannan.hyogo.jp\\n" +"sasayama.hyogo.jp\\n" +"sayo.hyogo.jp\\n" +"shingu.hyogo.jp\\n" +"shinonsen.hyogo.jp\\n" +"shiso.hyogo.jp\\n" +"sumoto.hyogo.jp\\n" +"taishi.hyogo.jp\\n" +"taka.hyogo.jp\\n" +"takarazuka.hyogo.jp\\n" +"takasago.hyogo.jp\\n" +"takino.hyogo.jp\\n" +"tamba.hyogo.jp\\n" +"tatsuno.hyogo.jp\\n" +"toyooka.hyogo.jp\\n" +"yabu.hyogo.jp\\n" +"yashiro.hyogo.jp\\n" +"yoka.hyogo.jp\\n" +"yokawa.hyogo.jp\\n" +"ami.ibaraki.jp\\n" +"asahi.ibaraki.jp\\n" +"bando.ibaraki.jp\\n" +"chikusei.ibaraki.jp\\n" +"daigo.ibaraki.jp\\n" +"fujishiro.ibaraki.jp\\n" +"hitachi.ibaraki.jp\\n" +"hitachinaka.ibaraki.jp\\n" +"hitachiomiya.ibaraki.jp\\n" +"hitachiota.ibaraki.jp\\n" +"ibaraki.ibaraki.jp\\n" +"ina.ibaraki.jp\\n" +"inashiki.ibaraki.jp\\n" +"itako.ibaraki.jp\\n" +"iwama.ibaraki.jp\\n" +"joso.ibaraki.jp\\n" +"kamisu.ibaraki.jp\\n" +"kasama.ibaraki.jp\\n" +"kashima.ibaraki.jp\\n" +"kasumigaura.ibaraki.jp\\n" +"koga.ibaraki.jp\\n" +"miho.ibaraki.jp\\n" +"mito.ibaraki.jp\\n" +"moriya.ibaraki.jp\\n" +"naka.ibaraki.jp\\n" +"namegata.ibaraki.jp\\n" +"oarai.ibaraki.jp\\n" +"ogawa.ibaraki.jp\\n" +"omitama.ibaraki.jp\\n" +"ryugasaki.ibaraki.jp\\n" +"sakai.ibaraki.jp\\n" +"sakuragawa.ibaraki.jp\\n" +"shimodate.ibaraki.jp\\n" +"shimotsuma.ibaraki.jp\\n" +"shirosato.ibaraki.jp\\n" +"sowa.ibaraki.jp\\n" +"suifu.ibaraki.jp\\n" +"takahagi.ibaraki.jp\\n" +"tamatsukuri.ibaraki.jp\\n" +"tokai.ibaraki.jp\\n" +"tomobe.ibaraki.jp\\n" +"tone.ibaraki.jp\\n" +"toride.ibaraki.jp\\n" +"tsuchiura.ibaraki.jp\\n" +"tsukuba.ibaraki.jp\\n" +"uchihara.ibaraki.jp\\n" +"ushiku.ibaraki.jp\\n" +"yachiyo.ibaraki.jp\\n" +"yamagata.ibaraki.jp\\n" +"yawara.ibaraki.jp\\n" +"yuki.ibaraki.jp\\n" +"anamizu.ishikawa.jp\\n" +"hakui.ishikawa.jp\\n" +"hakusan.ishikawa.jp\\n" +"kaga.ishikawa.jp\\n" +"kahoku.ishikawa.jp\\n" +"kanazawa.ishikawa.jp\\n" +"kawakita.ishikawa.jp\\n" +"komatsu.ishikawa.jp\\n" +"nakanoto.ishikawa.jp\\n" +"nanao.ishikawa.jp\\n" +"nomi.ishikawa.jp\\n" +"nonoichi.ishikawa.jp\\n" +"noto.ishikawa.jp\\n" +"shika.ishikawa.jp\\n" +"suzu.ishikawa.jp\\n" +"tsubata.ishikawa.jp\\n" +"tsurugi.ishikawa.jp\\n" +"uchinada.ishikawa.jp\\n" +"wajima.ishikawa.jp\\n" +"fudai.iwate.jp\\n" +"fujisawa.iwate.jp\\n" +"hanamaki.iwate.jp\\n" +"hiraizumi.iwate.jp\\n" +"hirono.iwate.jp\\n" +"ichinohe.iwate.jp\\n" +"ichinoseki.iwate.jp\\n" +"iwaizumi.iwate.jp\\n" +"iwate.iwate.jp\\n" +"joboji.iwate.jp\\n" +"kamaishi.iwate.jp\\n" +"kanegasaki.iwate.jp\\n" +"karumai.iwate.jp\\n" +"kawai.iwate.jp\\n" +"kitakami.iwate.jp\\n" +"kuji.iwate.jp\\n" +"kunohe.iwate.jp\\n" +"kuzumaki.iwate.jp\\n" +"miyako.iwate.jp\\n" +"mizusawa.iwate.jp\\n" +"morioka.iwate.jp\\n" +"ninohe.iwate.jp\\n" +"noda.iwate.jp\\n" +"ofunato.iwate.jp\\n" +"oshu.iwate.jp\\n" +"otsuchi.iwate.jp\\n" +"rikuzentakata.iwate.jp\\n" +"shiwa.iwate.jp\\n" +"shizukuishi.iwate.jp\\n" +"sumita.iwate.jp\\n" +"tanohata.iwate.jp\\n" +"tono.iwate.jp\\n" +"yahaba.iwate.jp\\n" +"yamada.iwate.jp\\n" +"ayagawa.kagawa.jp\\n" +"higashikagawa.kagawa.jp\\n" +"kanonji.kagawa.jp\\n" +"kotohira.kagawa.jp\\n" +"manno.kagawa.jp\\n" +"marugame.kagawa.jp\\n" +"mitoyo.kagawa.jp\\n" +"naoshima.kagawa.jp\\n" +"sanuki.kagawa.jp\\n" +"tadotsu.kagawa.jp\\n" +"takamatsu.kagawa.jp\\n" +"tonosho.kagawa.jp\\n" +"uchinomi.kagawa.jp\\n" +"utazu.kagawa.jp\\n" +"zentsuji.kagawa.jp\\n" +"akune.kagoshima.jp\\n" +"amami.kagoshima.jp\\n" +"hioki.kagoshima.jp\\n" +"isa.kagoshima.jp\\n" +"isen.kagoshima.jp\\n" +"izumi.kagoshima.jp\\n" +"kagoshima.kagoshima.jp\\n" +"kanoya.kagoshima.jp\\n" +"kawanabe.kagoshima.jp\\n" +"kinko.kagoshima.jp\\n" +"kouyama.kagoshima.jp\\n" +"makurazaki.kagoshima.jp\\n" +"matsumoto.kagoshima.jp\\n" +"minamitane.kagoshima.jp\\n" +"nakatane.kagoshima.jp\\n" +"nishinoomote.kagoshima.jp\\n" +"satsumasendai.kagoshima.jp\\n" +"soo.kagoshima.jp\\n" +"tarumizu.kagoshima.jp\\n" +"yusui.kagoshima.jp\\n" +"aikawa.kanagawa.jp\\n" +"atsugi.kanagawa.jp\\n" +"ayase.kanagawa.jp\\n" +"chigasaki.kanagawa.jp\\n" +"ebina.kanagawa.jp\\n" +"fujisawa.kanagawa.jp\\n" +"hadano.kanagawa.jp\\n" +"hakone.kanagawa.jp\\n" +"hiratsuka.kanagawa.jp\\n" +"isehara.kanagawa.jp\\n" +"kaisei.kanagawa.jp\\n" +"kamakura.kanagawa.jp\\n" +"kiyokawa.kanagawa.jp\\n" +"matsuda.kanagawa.jp\\n" +"minamiashigara.kanagawa.jp\\n" +"miura.kanagawa.jp\\n" +"nakai.kanagawa.jp\\n" +"ninomiya.kanagawa.jp\\n" +"odawara.kanagawa.jp\\n" +"oi.kanagawa.jp\\n" +"oiso.kanagawa.jp\\n" +"sagamihara.kanagawa.jp\\n" +"samukawa.kanagawa.jp\\n" +"tsukui.kanagawa.jp\\n" +"yamakita.kanagawa.jp\\n" +"yamato.kanagawa.jp\\n" +"yokosuka.kanagawa.jp\\n" +"yugawara.kanagawa.jp\\n" +"zama.kanagawa.jp\\n" +"zushi.kanagawa.jp\\n" +"aki.kochi.jp\\n" +"geisei.kochi.jp\\n" +"hidaka.kochi.jp\\n" +"higashitsuno.kochi.jp\\n" +"ino.kochi.jp\\n" +"kagami.kochi.jp\\n" +"kami.kochi.jp\\n" +"kitagawa.kochi.jp\\n" +"kochi.kochi.jp\\n" +"mihara.kochi.jp\\n" +"motoyama.kochi.jp\\n" +"muroto.kochi.jp\\n" +"nahari.kochi.jp\\n" +"nakamura.kochi.jp\\n" +"nankoku.kochi.jp\\n" +"nishitosa.kochi.jp\\n" +"niyodogawa.kochi.jp\\n" +"ochi.kochi.jp\\n" +"okawa.kochi.jp\\n" +"otoyo.kochi.jp\\n" +"otsuki.kochi.jp\\n" +"sakawa.kochi.jp\\n" +"sukumo.kochi.jp\\n" +"susaki.kochi.jp\\n" +"tosa.kochi.jp\\n" +"tosashimizu.kochi.jp\\n" +"toyo.kochi.jp\\n" +"tsuno.kochi.jp\\n" +"umaji.kochi.jp\\n" +"yasuda.kochi.jp\\n" +"yusuhara.kochi.jp\\n" +"amakusa.kumamoto.jp\\n" +"arao.kumamoto.jp\\n" +"aso.kumamoto.jp\\n" +"choyo.kumamoto.jp\\n" +"gyokuto.kumamoto.jp\\n" +"kamiamakusa.kumamoto.jp\\n" +"kikuchi.kumamoto.jp\\n" +"kumamoto.kumamoto.jp\\n" +"mashiki.kumamoto.jp\\n" +"mifune.kumamoto.jp\\n" +"minamata.kumamoto.jp\\n" +"minamioguni.kumamoto.jp\\n" +"nagasu.kumamoto.jp\\n" +"nishihara.kumamoto.jp\\n" +"oguni.kumamoto.jp\\n" +"ozu.kumamoto.jp\\n" +"sumoto.kumamoto.jp\\n" +"takamori.kumamoto.jp\\n" +"uki.kumamoto.jp\\n" +"uto.kumamoto.jp\\n" +"yamaga.kumamoto.jp\\n" +"yamato.kumamoto.jp\\n" +"yatsushiro.kumamoto.jp\\n" +"ayabe.kyoto.jp\\n" +"fukuchiyama.kyoto.jp\\n" +"higashiyama.kyoto.jp\\n" +"ide.kyoto.jp\\n" +"ine.kyoto.jp\\n" +"joyo.kyoto.jp\\n" +"kameoka.kyoto.jp\\n" +"kamo.kyoto.jp\\n" +"kita.kyoto.jp\\n" +"kizu.kyoto.jp\\n" +"kumiyama.kyoto.jp\\n" +"kyotamba.kyoto.jp\\n" +"kyotanabe.kyoto.jp\\n" +"kyotango.kyoto.jp\\n" +"maizuru.kyoto.jp\\n" +"minami.kyoto.jp\\n" +"minamiyamashiro.kyoto.jp\\n" +"miyazu.kyoto.jp\\n" +"muko.kyoto.jp\\n" +"nagaokakyo.kyoto.jp\\n" +"nakagyo.kyoto.jp\\n" +"nantan.kyoto.jp\\n" +"oyamazaki.kyoto.jp\\n" +"sakyo.kyoto.jp\\n" +"seika.kyoto.jp\\n" +"tanabe.kyoto.jp\\n" +"uji.kyoto.jp\\n" +"ujitawara.kyoto.jp\\n" +"wazuka.kyoto.jp\\n" +"yamashina.kyoto.jp\\n" +"yawata.kyoto.jp\\n" +"asahi.mie.jp\\n" +"inabe.mie.jp\\n" +"ise.mie.jp\\n" +"kameyama.mie.jp\\n" +"kawagoe.mie.jp\\n" +"kiho.mie.jp\\n" +"kisosaki.mie.jp\\n" +"kiwa.mie.jp\\n" +"komono.mie.jp\\n" +"kumano.mie.jp\\n" +"kuwana.mie.jp\\n" +"matsusaka.mie.jp\\n" +"meiwa.mie.jp\\n" +"mihama.mie.jp\\n" +"minamiise.mie.jp\\n" +"misugi.mie.jp\\n" +"miyama.mie.jp\\n" +"nabari.mie.jp\\n" +"shima.mie.jp\\n" +"suzuka.mie.jp\\n" +"tado.mie.jp\\n" +"taiki.mie.jp\\n" +"taki.mie.jp\\n" +"tamaki.mie.jp\\n" +"toba.mie.jp\\n" +"tsu.mie.jp\\n" +"udono.mie.jp\\n" +"ureshino.mie.jp\\n" +"watarai.mie.jp\\n" +"yokkaichi.mie.jp\\n" +"furukawa.miyagi.jp\\n" +"higashimatsushima.miyagi.jp\\n" +"ishinomaki.miyagi.jp\\n" +"iwanuma.miyagi.jp\\n" +"kakuda.miyagi.jp\\n" +"kami.miyagi.jp\\n" +"kawasaki.miyagi.jp\\n" +"marumori.miyagi.jp\\n" +"matsushima.miyagi.jp\\n" +"minamisanriku.miyagi.jp\\n" +"misato.miyagi.jp\\n" +"murata.miyagi.jp\\n" +"natori.miyagi.jp\\n" +"ogawara.miyagi.jp\\n" +"ohira.miyagi.jp\\n" +"onagawa.miyagi.jp\\n" +"osaki.miyagi.jp\\n" +"rifu.miyagi.jp\\n" +"semine.miyagi.jp\\n" +"shibata.miyagi.jp\\n" +"shichikashuku.miyagi.jp\\n" +"shikama.miyagi.jp\\n" +"shiogama.miyagi.jp\\n" +"shiroishi.miyagi.jp\\n" +"tagajo.miyagi.jp\\n" +"taiwa.miyagi.jp\\n" +"tome.miyagi.jp\\n" +"tomiya.miyagi.jp\\n" +"wakuya.miyagi.jp\\n" +"watari.miyagi.jp\\n" +"yamamoto.miyagi.jp\\n" +"zao.miyagi.jp\\n" +"aya.miyazaki.jp\\n" +"ebino.miyazaki.jp\\n" +"gokase.miyazaki.jp\\n" +"hyuga.miyazaki.jp\\n" +"kadogawa.miyazaki.jp\\n" +"kawaminami.miyazaki.jp\\n" +"kijo.miyazaki.jp\\n" +"kitagawa.miyazaki.jp\\n" +"kitakata.miyazaki.jp\\n" +"kitaura.miyazaki.jp\\n" +"kobayashi.miyazaki.jp\\n" +"kunitomi.miyazaki.jp\\n" +"kushima.miyazaki.jp\\n" +"mimata.miyazaki.jp\\n" +"miyakonojo.miyazaki.jp\\n" +"miyazaki.miyazaki.jp\\n" +"morotsuka.miyazaki.jp\\n" +"nichinan.miyazaki.jp\\n" +"nishimera.miyazaki.jp\\n" +"nobeoka.miyazaki.jp\\n" +"saito.miyazaki.jp\\n" +"shiiba.miyazaki.jp\\n" +"shintomi.miyazaki.jp\\n" +"takaharu.miyazaki.jp\\n" +"takanabe.miyazaki.jp\\n" +"takazaki.miyazaki.jp\\n" +"tsuno.miyazaki.jp\\n" +"achi.nagano.jp\\n" +"agematsu.nagano.jp\\n" +"anan.nagano.jp\\n" +"aoki.nagano.jp\\n" +"asahi.nagano.jp\\n" +"azumino.nagano.jp\\n" +"chikuhoku.nagano.jp\\n" +"chikuma.nagano.jp\\n" +"chino.nagano.jp\\n" +"fujimi.nagano.jp\\n" +"hakuba.nagano.jp\\n" +"hara.nagano.jp\\n" +"hiraya.nagano.jp\\n" +"iida.nagano.jp\\n" +"iijima.nagano.jp\\n" +"iiyama.nagano.jp\\n" +"iizuna.nagano.jp\\n" +"ikeda.nagano.jp\\n" +"ikusaka.nagano.jp\\n" +"ina.nagano.jp\\n" +"karuizawa.nagano.jp\\n" +"kawakami.nagano.jp\\n" +"kiso.nagano.jp\\n" +"kisofukushima.nagano.jp\\n" +"kitaaiki.nagano.jp\\n" +"komagane.nagano.jp\\n" +"komoro.nagano.jp\\n" +"matsukawa.nagano.jp\\n" +"matsumoto.nagano.jp\\n" +"miasa.nagano.jp\\n" +"minamiaiki.nagano.jp\\n" +"minamimaki.nagano.jp\\n" +"minamiminowa.nagano.jp\\n" +"minowa.nagano.jp\\n" +"miyada.nagano.jp\\n" +"miyota.nagano.jp\\n" +"mochizuki.nagano.jp\\n" +"nagano.nagano.jp\\n" +"nagawa.nagano.jp\\n" +"nagiso.nagano.jp\\n" +"nakagawa.nagano.jp\\n" +"nakano.nagano.jp\\n" +"nozawaonsen.nagano.jp\\n" +"obuse.nagano.jp\\n" +"ogawa.nagano.jp\\n" +"okaya.nagano.jp\\n" +"omachi.nagano.jp\\n" +"omi.nagano.jp\\n" +"ookuwa.nagano.jp\\n" +"ooshika.nagano.jp\\n" +"otaki.nagano.jp\\n" +"otari.nagano.jp\\n" +"sakae.nagano.jp\\n" +"sakaki.nagano.jp\\n" +"saku.nagano.jp\\n" +"sakuho.nagano.jp\\n" +"shimosuwa.nagano.jp\\n" +"shinanomachi.nagano.jp\\n" +"shiojiri.nagano.jp\\n" +"suwa.nagano.jp\\n" +"suzaka.nagano.jp\\n" +"takagi.nagano.jp\\n" +"takamori.nagano.jp\\n" +"takayama.nagano.jp\\n" +"tateshina.nagano.jp\\n" +"tatsuno.nagano.jp\\n" +"togakushi.nagano.jp\\n" +"togura.nagano.jp\\n" +"tomi.nagano.jp\\n" +"ueda.nagano.jp\\n" +"wada.nagano.jp\\n" +"yamagata.nagano.jp\\n" +"yamanouchi.nagano.jp\\n" +"yasaka.nagano.jp\\n" +"yasuoka.nagano.jp\\n" +"chijiwa.nagasaki.jp\\n" +"futsu.nagasaki.jp\\n" +"goto.nagasaki.jp\\n" +"hasami.nagasaki.jp\\n" +"hirado.nagasaki.jp\\n" +"iki.nagasaki.jp\\n" +"isahaya.nagasaki.jp\\n" +"kawatana.nagasaki.jp\\n" +"kuchinotsu.nagasaki.jp\\n" +"matsuura.nagasaki.jp\\n" +"nagasaki.nagasaki.jp\\n" +"obama.nagasaki.jp\\n" +"omura.nagasaki.jp\\n" +"oseto.nagasaki.jp\\n" +"saikai.nagasaki.jp\\n" +"sasebo.nagasaki.jp\\n" +"seihi.nagasaki.jp\\n" +"shimabara.nagasaki.jp\\n" +"shinkamigoto.nagasaki.jp\\n" +"togitsu.nagasaki.jp\\n" +"tsushima.nagasaki.jp\\n" +"unzen.nagasaki.jp\\n" +"ando.nara.jp\\n" +"gose.nara.jp\\n" +"heguri.nara.jp\\n" +"higashiyoshino.nara.jp\\n" +"ikaruga.nara.jp\\n" +"ikoma.nara.jp\\n" +"kamikitayama.nara.jp\\n" +"kanmaki.nara.jp\\n" +"kashiba.nara.jp\\n" +"kashihara.nara.jp\\n" +"katsuragi.nara.jp\\n" +"kawai.nara.jp\\n" +"kawakami.nara.jp\\n" +"kawanishi.nara.jp\\n" +"koryo.nara.jp\\n" +"kurotaki.nara.jp\\n" +"mitsue.nara.jp\\n" +"miyake.nara.jp\\n" +"nara.nara.jp\\n" +"nosegawa.nara.jp\\n" +"oji.nara.jp\\n" +"ouda.nara.jp\\n" +"oyodo.nara.jp\\n" +"sakurai.nara.jp\\n" +"sango.nara.jp\\n" +"shimoichi.nara.jp\\n" +"shimokitayama.nara.jp\\n" +"shinjo.nara.jp\\n" +"soni.nara.jp\\n" +"takatori.nara.jp\\n" +"tawaramoto.nara.jp\\n" +"tenkawa.nara.jp\\n" +"tenri.nara.jp\\n" +"uda.nara.jp\\n" +"yamatokoriyama.nara.jp\\n" +"yamatotakada.nara.jp\\n" +"yamazoe.nara.jp\\n" +"yoshino.nara.jp\\n" +"aga.niigata.jp\\n" +"agano.niigata.jp\\n" +"gosen.niigata.jp\\n" +"itoigawa.niigata.jp\\n" +"izumozaki.niigata.jp\\n" +"joetsu.niigata.jp\\n" +"kamo.niigata.jp\\n" +"kariwa.niigata.jp\\n" +"kashiwazaki.niigata.jp\\n" +"minamiuonuma.niigata.jp\\n" +"mitsuke.niigata.jp\\n" +"muika.niigata.jp\\n" +"murakami.niigata.jp\\n" +"myoko.niigata.jp\\n" +"nagaoka.niigata.jp\\n" +"niigata.niigata.jp\\n" +"ojiya.niigata.jp\\n" +"omi.niigata.jp\\n" +"sado.niigata.jp\\n" +"sanjo.niigata.jp\\n" +"seiro.niigata.jp\\n" +"seirou.niigata.jp\\n" +"sekikawa.niigata.jp\\n" +"shibata.niigata.jp\\n" +"tagami.niigata.jp\\n" +"tainai.niigata.jp\\n" +"tochio.niigata.jp\\n" +"tokamachi.niigata.jp\\n" +"tsubame.niigata.jp\\n" +"tsunan.niigata.jp\\n" +"uonuma.niigata.jp\\n" +"yahiko.niigata.jp\\n" +"yoita.niigata.jp\\n" +"yuzawa.niigata.jp\\n" +"beppu.oita.jp\\n" +"bungoono.oita.jp\\n" +"bungotakada.oita.jp\\n" +"hasama.oita.jp\\n" +"hiji.oita.jp\\n" +"himeshima.oita.jp\\n" +"hita.oita.jp\\n" +"kamitsue.oita.jp\\n" +"kokonoe.oita.jp\\n" +"kuju.oita.jp\\n" +"kunisaki.oita.jp\\n" +"kusu.oita.jp\\n" +"oita.oita.jp\\n" +"saiki.oita.jp\\n" +"taketa.oita.jp\\n" +"tsukumi.oita.jp\\n" +"usa.oita.jp\\n" +"usuki.oita.jp\\n" +"yufu.oita.jp\\n" +"akaiwa.okayama.jp\\n" +"asakuchi.okayama.jp\\n" +"bizen.okayama.jp\\n" +"hayashima.okayama.jp\\n" +"ibara.okayama.jp\\n" +"kagamino.okayama.jp\\n" +"kasaoka.okayama.jp\\n" +"kibichuo.okayama.jp\\n" +"kumenan.okayama.jp\\n" +"kurashiki.okayama.jp\\n" +"maniwa.okayama.jp\\n" +"misaki.okayama.jp\\n" +"nagi.okayama.jp\\n" +"niimi.okayama.jp\\n" +"nishiawakura.okayama.jp\\n" +"okayama.okayama.jp\\n" +"satosho.okayama.jp\\n" +"setouchi.okayama.jp\\n" +"shinjo.okayama.jp\\n" +"shoo.okayama.jp\\n" +"soja.okayama.jp\\n" +"takahashi.okayama.jp\\n" +"tamano.okayama.jp\\n" +"tsuyama.okayama.jp\\n" +"wake.okayama.jp\\n" +"yakage.okayama.jp\\n" +"aguni.okinawa.jp\\n" +"ginowan.okinawa.jp\\n" +"ginoza.okinawa.jp\\n" +"gushikami.okinawa.jp\\n" +"haebaru.okinawa.jp\\n" +"higashi.okinawa.jp\\n" +"hirara.okinawa.jp\\n" +"iheya.okinawa.jp\\n" +"ishigaki.okinawa.jp\\n" +"ishikawa.okinawa.jp\\n" +"itoman.okinawa.jp\\n" +"izena.okinawa.jp\\n" +"kadena.okinawa.jp\\n" +"kin.okinawa.jp\\n" +"kitadaito.okinawa.jp\\n" +"kitanakagusuku.okinawa.jp\\n" +"kumejima.okinawa.jp\\n" +"kunigami.okinawa.jp\\n" +"minamidaito.okinawa.jp\\n" +"motobu.okinawa.jp\\n" +"nago.okinawa.jp\\n" +"naha.okinawa.jp\\n" +"nakagusuku.okinawa.jp\\n" +"nakijin.okinawa.jp\\n" +"nanjo.okinawa.jp\\n" +"nishihara.okinawa.jp\\n" +"ogimi.okinawa.jp\\n" +"okinawa.okinawa.jp\\n" +"onna.okinawa.jp\\n" +"shimoji.okinawa.jp\\n" +"taketomi.okinawa.jp\\n" +"tarama.okinawa.jp\\n" +"tokashiki.okinawa.jp\\n" +"tomigusuku.okinawa.jp\\n" +"tonaki.okinawa.jp\\n" +"urasoe.okinawa.jp\\n" +"uruma.okinawa.jp\\n" +"yaese.okinawa.jp\\n" +"yomitan.okinawa.jp\\n" +"yonabaru.okinawa.jp\\n" +"yonaguni.okinawa.jp\\n" +"zamami.okinawa.jp\\n" +"abeno.osaka.jp\\n" +"chihayaakasaka.osaka.jp\\n" +"chuo.osaka.jp\\n" +"daito.osaka.jp\\n" +"fujiidera.osaka.jp\\n" +"habikino.osaka.jp\\n" +"hannan.osaka.jp\\n" +"higashiosaka.osaka.jp\\n" +"higashisumiyoshi.osaka.jp\\n" +"higashiyodogawa.osaka.jp\\n" +"hirakata.osaka.jp\\n" +"ibaraki.osaka.jp\\n" +"ikeda.osaka.jp\\n" +"izumi.osaka.jp\\n" +"izumiotsu.osaka.jp\\n" +"izumisano.osaka.jp\\n" +"kadoma.osaka.jp\\n" +"kaizuka.osaka.jp\\n" +"kanan.osaka.jp\\n" +"kashiwara.osaka.jp\\n" +"katano.osaka.jp\\n" +"kawachinagano.osaka.jp\\n" +"kishiwada.osaka.jp\\n" +"kita.osaka.jp\\n" +"kumatori.osaka.jp\\n" +"matsubara.osaka.jp\\n" +"minato.osaka.jp\\n" +"minoh.osaka.jp\\n" +"misaki.osaka.jp\\n" +"moriguchi.osaka.jp\\n" +"neyagawa.osaka.jp\\n" +"nishi.osaka.jp\\n" +"nose.osaka.jp\\n" +"osakasayama.osaka.jp\\n" +"sakai.osaka.jp\\n" +"sayama.osaka.jp\\n" +"sennan.osaka.jp\\n" +"settsu.osaka.jp\\n" +"shijonawate.osaka.jp\\n" +"shimamoto.osaka.jp\\n" +"suita.osaka.jp\\n" +"tadaoka.osaka.jp\\n" +"taishi.osaka.jp\\n" +"tajiri.osaka.jp\\n" +"takaishi.osaka.jp\\n" +"takatsuki.osaka.jp\\n" +"tondabayashi.osaka.jp\\n" +"toyonaka.osaka.jp\\n" +"toyono.osaka.jp\\n" +"yao.osaka.jp\\n" +"ariake.saga.jp\\n" +"arita.saga.jp\\n" +"fukudomi.saga.jp\\n" +"genkai.saga.jp\\n" +"hamatama.saga.jp\\n" +"hizen.saga.jp\\n" +"imari.saga.jp\\n" +"kamimine.saga.jp\\n" +"kanzaki.saga.jp\\n" +"karatsu.saga.jp\\n" +"kashima.saga.jp\\n" +"kitagata.saga.jp\\n" +"kitahata.saga.jp\\n" +"kiyama.saga.jp\\n" +"kouhoku.saga.jp\\n" +"kyuragi.saga.jp\\n" +"nishiarita.saga.jp\\n" +"ogi.saga.jp\\n" +"omachi.saga.jp\\n" +"ouchi.saga.jp\\n" +"saga.saga.jp\\n" +"shiroishi.saga.jp\\n" +"taku.saga.jp\\n" +"tara.saga.jp\\n" +"tosu.saga.jp\\n" +"yoshinogari.saga.jp\\n" +"arakawa.saitama.jp\\n" +"asaka.saitama.jp\\n" +"chichibu.saitama.jp\\n" +"fujimi.saitama.jp\\n" +"fujimino.saitama.jp\\n" +"fukaya.saitama.jp\\n" +"hanno.saitama.jp\\n" +"hanyu.saitama.jp\\n" +"hasuda.saitama.jp\\n" +"hatogaya.saitama.jp\\n" +"hatoyama.saitama.jp\\n" +"hidaka.saitama.jp\\n" +"higashichichibu.saitama.jp\\n" +"higashimatsuyama.saitama.jp\\n" +"honjo.saitama.jp\\n" +"ina.saitama.jp\\n" +"iruma.saitama.jp\\n" +"iwatsuki.saitama.jp\\n" +"kamiizumi.saitama.jp\\n" +"kamikawa.saitama.jp\\n" +"kamisato.saitama.jp\\n" +"kasukabe.saitama.jp\\n" +"kawagoe.saitama.jp\\n" +"kawaguchi.saitama.jp\\n" +"kawajima.saitama.jp\\n" +"kazo.saitama.jp\\n" +"kitamoto.saitama.jp\\n" +"koshigaya.saitama.jp\\n" +"kounosu.saitama.jp\\n" +"kuki.saitama.jp\\n" +"kumagaya.saitama.jp\\n" +"matsubushi.saitama.jp\\n" +"minano.saitama.jp\\n" +"misato.saitama.jp\\n" +"miyashiro.saitama.jp\\n" +"miyoshi.saitama.jp\\n" +"moroyama.saitama.jp\\n" +"nagatoro.saitama.jp\\n" +"namegawa.saitama.jp\\n" +"niiza.saitama.jp\\n" +"ogano.saitama.jp\\n" +"ogawa.saitama.jp\\n" +"ogose.saitama.jp\\n" +"okegawa.saitama.jp\\n" +"omiya.saitama.jp\\n" +"otaki.saitama.jp\\n" +"ranzan.saitama.jp\\n" +"ryokami.saitama.jp\\n" +"saitama.saitama.jp\\n" +"sakado.saitama.jp\\n" +"satte.saitama.jp\\n" +"sayama.saitama.jp\\n" +"shiki.saitama.jp\\n" +"shiraoka.saitama.jp\\n" +"soka.saitama.jp\\n" +"sugito.saitama.jp\\n" +"toda.saitama.jp\\n" +"tokigawa.saitama.jp\\n" +"tokorozawa.saitama.jp\\n" +"tsurugashima.saitama.jp\\n" +"urawa.saitama.jp\\n" +"warabi.saitama.jp\\n" +"yashio.saitama.jp\\n" +"yokoze.saitama.jp\\n" +"yono.saitama.jp\\n" +"yorii.saitama.jp\\n" +"yoshida.saitama.jp\\n" +"yoshikawa.saitama.jp\\n" +"yoshimi.saitama.jp\\n" +"aisho.shiga.jp\\n" +"gamo.shiga.jp\\n" +"higashiomi.shiga.jp\\n" +"hikone.shiga.jp\\n" +"koka.shiga.jp\\n" +"konan.shiga.jp\\n" +"kosei.shiga.jp\\n" +"koto.shiga.jp\\n" +"kusatsu.shiga.jp\\n" +"maibara.shiga.jp\\n" +"moriyama.shiga.jp\\n" +"nagahama.shiga.jp\\n" +"nishiazai.shiga.jp\\n" +"notogawa.shiga.jp\\n" +"omihachiman.shiga.jp\\n" +"otsu.shiga.jp\\n" +"ritto.shiga.jp\\n" +"ryuoh.shiga.jp\\n" +"takashima.shiga.jp\\n" +"takatsuki.shiga.jp\\n" +"torahime.shiga.jp\\n" +"toyosato.shiga.jp\\n" +"yasu.shiga.jp\\n" +"akagi.shimane.jp\\n" +"ama.shimane.jp\\n" +"gotsu.shimane.jp\\n" +"hamada.shimane.jp\\n" +"higashiizumo.shimane.jp\\n" +"hikawa.shimane.jp\\n" +"hikimi.shimane.jp\\n" +"izumo.shimane.jp\\n" +"kakinoki.shimane.jp\\n" +"masuda.shimane.jp\\n" +"matsue.shimane.jp\\n" +"misato.shimane.jp\\n" +"nishinoshima.shimane.jp\\n" +"ohda.shimane.jp\\n" +"okinoshima.shimane.jp\\n" +"okuizumo.shimane.jp\\n" +"shimane.shimane.jp\\n" +"tamayu.shimane.jp\\n" +"tsuwano.shimane.jp\\n" +"unnan.shimane.jp\\n" +"yakumo.shimane.jp\\n" +"yasugi.shimane.jp\\n" +"yatsuka.shimane.jp\\n" +"arai.shizuoka.jp\\n" +"atami.shizuoka.jp\\n" +"fuji.shizuoka.jp\\n" +"fujieda.shizuoka.jp\\n" +"fujikawa.shizuoka.jp\\n" +"fujinomiya.shizuoka.jp\\n" +"fukuroi.shizuoka.jp\\n" +"gotemba.shizuoka.jp\\n" +"haibara.shizuoka.jp\\n" +"hamamatsu.shizuoka.jp\\n" +"higashiizu.shizuoka.jp\\n" +"ito.shizuoka.jp\\n" +"iwata.shizuoka.jp\\n" +"izu.shizuoka.jp\\n" +"izunokuni.shizuoka.jp\\n" +"kakegawa.shizuoka.jp\\n" +"kannami.shizuoka.jp\\n" +"kawanehon.shizuoka.jp\\n" +"kawazu.shizuoka.jp\\n" +"kikugawa.shizuoka.jp\\n" +"kosai.shizuoka.jp\\n" +"makinohara.shizuoka.jp\\n" +"matsuzaki.shizuoka.jp\\n" +"minamiizu.shizuoka.jp\\n" +"mishima.shizuoka.jp\\n" +"morimachi.shizuoka.jp\\n" +"nishiizu.shizuoka.jp\\n" +"numazu.shizuoka.jp\\n" +"omaezaki.shizuoka.jp\\n" +"shimada.shizuoka.jp\\n" +"shimizu.shizuoka.jp\\n" +"shimoda.shizuoka.jp\\n" +"shizuoka.shizuoka.jp\\n" +"susono.shizuoka.jp\\n" +"yaizu.shizuoka.jp\\n" +"yoshida.shizuoka.jp\\n" +"ashikaga.tochigi.jp\\n" +"bato.tochigi.jp\\n" +"haga.tochigi.jp\\n" +"ichikai.tochigi.jp\\n" +"iwafune.tochigi.jp\\n" +"kaminokawa.tochigi.jp\\n" +"kanuma.tochigi.jp\\n" +"karasuyama.tochigi.jp\\n" +"kuroiso.tochigi.jp\\n" +"mashiko.tochigi.jp\\n" +"mibu.tochigi.jp\\n" +"moka.tochigi.jp\\n" +"motegi.tochigi.jp\\n" +"nasu.tochigi.jp\\n" +"nasushiobara.tochigi.jp\\n" +"nikko.tochigi.jp\\n" +"nishikata.tochigi.jp\\n" +"nogi.tochigi.jp\\n" +"ohira.tochigi.jp\\n" +"ohtawara.tochigi.jp\\n" +"oyama.tochigi.jp\\n" +"sakura.tochigi.jp\\n" +"sano.tochigi.jp\\n" +"shimotsuke.tochigi.jp\\n" +"shioya.tochigi.jp\\n" +"takanezawa.tochigi.jp\\n" +"tochigi.tochigi.jp\\n" +"tsuga.tochigi.jp\\n" +"ujiie.tochigi.jp\\n" +"utsunomiya.tochigi.jp\\n" +"yaita.tochigi.jp\\n" +"aizumi.tokushima.jp\\n" +"anan.tokushima.jp\\n" +"ichiba.tokushima.jp\\n" +"itano.tokushima.jp\\n" +"kainan.tokushima.jp\\n" +"komatsushima.tokushima.jp\\n" +"matsushige.tokushima.jp\\n" +"mima.tokushima.jp\\n" +"minami.tokushima.jp\\n" +"miyoshi.tokushima.jp\\n" +"mugi.tokushima.jp\\n" +"nakagawa.tokushima.jp\\n" +"naruto.tokushima.jp\\n" +"sanagochi.tokushima.jp\\n" +"shishikui.tokushima.jp\\n" +"tokushima.tokushima.jp\\n" +"wajiki.tokushima.jp\\n" +"adachi.tokyo.jp\\n" +"akiruno.tokyo.jp\\n" +"akishima.tokyo.jp\\n" +"aogashima.tokyo.jp\\n" +"arakawa.tokyo.jp\\n" +"bunkyo.tokyo.jp\\n" +"chiyoda.tokyo.jp\\n" +"chofu.tokyo.jp\\n" +"chuo.tokyo.jp\\n" +"edogawa.tokyo.jp\\n" +"fuchu.tokyo.jp\\n" +"fussa.tokyo.jp\\n" +"hachijo.tokyo.jp\\n" +"hachioji.tokyo.jp\\n" +"hamura.tokyo.jp\\n" +"higashikurume.tokyo.jp\\n" +"higashimurayama.tokyo.jp\\n" +"higashiyamato.tokyo.jp\\n" +"hino.tokyo.jp\\n" +"hinode.tokyo.jp\\n" +"hinohara.tokyo.jp\\n" +"inagi.tokyo.jp\\n" +"itabashi.tokyo.jp\\n" +"katsushika.tokyo.jp\\n" +"kita.tokyo.jp\\n" +"kiyose.tokyo.jp\\n" +"kodaira.tokyo.jp\\n" +"koganei.tokyo.jp\\n" +"kokubunji.tokyo.jp\\n" +"komae.tokyo.jp\\n" +"koto.tokyo.jp\\n" +"kouzushima.tokyo.jp\\n" +"kunitachi.tokyo.jp\\n" +"machida.tokyo.jp\\n" +"meguro.tokyo.jp\\n" +"minato.tokyo.jp\\n" +"mitaka.tokyo.jp\\n" +"mizuho.tokyo.jp\\n" +"musashimurayama.tokyo.jp\\n" +"musashino.tokyo.jp\\n" +"nakano.tokyo.jp\\n" +"nerima.tokyo.jp\\n" +"ogasawara.tokyo.jp\\n" +"okutama.tokyo.jp\\n" +"ome.tokyo.jp\\n" +"oshima.tokyo.jp\\n" +"ota.tokyo.jp\\n" +"setagaya.tokyo.jp\\n" +"shibuya.tokyo.jp\\n" +"shinagawa.tokyo.jp\\n" +"shinjuku.tokyo.jp\\n" +"suginami.tokyo.jp\\n" +"sumida.tokyo.jp\\n" +"tachikawa.tokyo.jp\\n" +"taito.tokyo.jp\\n" +"tama.tokyo.jp\\n" +"toshima.tokyo.jp\\n" +"chizu.tottori.jp\\n" +"hino.tottori.jp\\n" +"kawahara.tottori.jp\\n" +"koge.tottori.jp\\n" +"kotoura.tottori.jp\\n" +"misasa.tottori.jp\\n" +"nanbu.tottori.jp\\n" +"nichinan.tottori.jp\\n" +"sakaiminato.tottori.jp\\n" +"tottori.tottori.jp\\n" +"wakasa.tottori.jp\\n" +"yazu.tottori.jp\\n" +"yonago.tottori.jp\\n" +"asahi.toyama.jp\\n" +"fuchu.toyama.jp\\n" +"fukumitsu.toyama.jp\\n" +"funahashi.toyama.jp\\n" +"himi.toyama.jp\\n" +"imizu.toyama.jp\\n" +"inami.toyama.jp\\n" +"johana.toyama.jp\\n" +"kamiichi.toyama.jp\\n" +"kurobe.toyama.jp\\n" +"nakaniikawa.toyama.jp\\n" +"namerikawa.toyama.jp\\n" +"nanto.toyama.jp\\n" +"nyuzen.toyama.jp\\n" +"oyabe.toyama.jp\\n" +"taira.toyama.jp\\n" +"takaoka.toyama.jp\\n" +"tateyama.toyama.jp\\n" +"toga.toyama.jp\\n" +"tonami.toyama.jp\\n" +"toyama.toyama.jp\\n" +"unazuki.toyama.jp\\n" +"uozu.toyama.jp\\n" +"yamada.toyama.jp\\n" +"arida.wakayama.jp\\n" +"aridagawa.wakayama.jp\\n" +"gobo.wakayama.jp\\n" +"hashimoto.wakayama.jp\\n" +"hidaka.wakayama.jp\\n" +"hirogawa.wakayama.jp\\n" +"inami.wakayama.jp\\n" +"iwade.wakayama.jp\\n" +"kainan.wakayama.jp\\n" +"kamitonda.wakayama.jp\\n" +"katsuragi.wakayama.jp\\n" +"kimino.wakayama.jp\\n" +"kinokawa.wakayama.jp\\n" +"kitayama.wakayama.jp\\n" +"koya.wakayama.jp\\n" +"koza.wakayama.jp\\n" +"kozagawa.wakayama.jp\\n" +"kudoyama.wakayama.jp\\n" +"kushimoto.wakayama.jp\\n" +"mihama.wakayama.jp\\n" +"misato.wakayama.jp\\n" +"nachikatsuura.wakayama.jp\\n" +"shingu.wakayama.jp\\n" +"shirahama.wakayama.jp\\n" +"taiji.wakayama.jp\\n" +"tanabe.wakayama.jp\\n" +"wakayama.wakayama.jp\\n" +"yuasa.wakayama.jp\\n" +"yura.wakayama.jp\\n" +"asahi.yamagata.jp\\n" +"funagata.yamagata.jp\\n" +"higashine.yamagata.jp\\n" +"iide.yamagata.jp\\n" +"kahoku.yamagata.jp\\n" +"kaminoyama.yamagata.jp\\n" +"kaneyama.yamagata.jp\\n" +"kawanishi.yamagata.jp\\n" +"mamurogawa.yamagata.jp\\n" +"mikawa.yamagata.jp\\n" +"murayama.yamagata.jp\\n" +"nagai.yamagata.jp\\n" +"nakayama.yamagata.jp\\n" +"nanyo.yamagata.jp\\n" +"nishikawa.yamagata.jp\\n" +"obanazawa.yamagata.jp\\n" +"oe.yamagata.jp\\n" +"oguni.yamagata.jp\\n" +"ohkura.yamagata.jp\\n" +"oishida.yamagata.jp\\n" +"sagae.yamagata.jp\\n" +"sakata.yamagata.jp\\n" +"sakegawa.yamagata.jp\\n" +"shinjo.yamagata.jp\\n" +"shirataka.yamagata.jp\\n" +"shonai.yamagata.jp\\n" +"takahata.yamagata.jp\\n" +"tendo.yamagata.jp\\n" +"tozawa.yamagata.jp\\n" +"tsuruoka.yamagata.jp\\n" +"yamagata.yamagata.jp\\n" +"yamanobe.yamagata.jp\\n" +"yonezawa.yamagata.jp\\n" +"yuza.yamagata.jp\\n" +"abu.yamaguchi.jp\\n" +"hagi.yamaguchi.jp\\n" +"hikari.yamaguchi.jp\\n" +"hofu.yamaguchi.jp\\n" +"iwakuni.yamaguchi.jp\\n" +"kudamatsu.yamaguchi.jp\\n" +"mitou.yamaguchi.jp\\n" +"nagato.yamaguchi.jp\\n" +"oshima.yamaguchi.jp\\n" +"shimonoseki.yamaguchi.jp\\n" +"shunan.yamaguchi.jp\\n" +"tabuse.yamaguchi.jp\\n" +"tokuyama.yamaguchi.jp\\n" +"toyota.yamaguchi.jp\\n" +"ube.yamaguchi.jp\\n" +"yuu.yamaguchi.jp\\n" +"chuo.yamanashi.jp\\n" +"doshi.yamanashi.jp\\n" +"fuefuki.yamanashi.jp\\n" +"fujikawa.yamanashi.jp\\n" +"fujikawaguchiko.yamanashi.jp\\n" +"fujiyoshida.yamanashi.jp\\n" +"hayakawa.yamanashi.jp\\n" +"hokuto.yamanashi.jp\\n" +"ichikawamisato.yamanashi.jp\\n" +"kai.yamanashi.jp\\n" +"kofu.yamanashi.jp\\n" +"koshu.yamanashi.jp\\n" +"kosuge.yamanashi.jp\\n" +"minami-alps.yamanashi.jp\\n" +"minobu.yamanashi.jp\\n" +"nakamichi.yamanashi.jp\\n" +"nanbu.yamanashi.jp\\n" +"narusawa.yamanashi.jp\\n" +"nirasaki.yamanashi.jp\\n" +"nishikatsura.yamanashi.jp\\n" +"oshino.yamanashi.jp\\n" +"otsuki.yamanashi.jp\\n" +"showa.yamanashi.jp\\n" +"tabayama.yamanashi.jp\\n" +"tsuru.yamanashi.jp\\n" +"uenohara.yamanashi.jp\\n" +"yamanakako.yamanashi.jp\\n" +"yamanashi.yamanashi.jp\\n" +"ac.ke\\n" +"co.ke\\n" +"go.ke\\n" +"info.ke\\n" +"me.ke\\n" +"mobi.ke\\n" +"ne.ke\\n" +"or.ke\\n" +"sc.ke\\n" +"com.kg\\n" +"edu.kg\\n" +"gov.kg\\n" +"mil.kg\\n" +"net.kg\\n" +"org.kg\\n" +"com.kh\\n" +"edu.kh\\n" +"gov.kh\\n" +"net.kh\\n" +"org.kh\\n" +"biz.ki\\n" +"com.ki\\n" +"edu.ki\\n" +"gov.ki\\n" +"info.ki\\n" +"net.ki\\n" +"org.ki\\n" +"ass.km\\n" +"com.km\\n" +"edu.km\\n" +"gov.km\\n" +"mil.km\\n" +"nom.km\\n" +"org.km\\n" +"prd.km\\n" +"tm.km\\n" +"asso.km\\n" +"coop.km\\n" +"gouv.km\\n" +"medecin.km\\n" +"notaires.km\\n" +"pharmaciens.km\\n" +"presse.km\\n" +"veterinaire.km\\n" +"edu.kn\\n" +"gov.kn\\n" +"net.kn\\n" +"org.kn\\n" +"com.kp\\n" +"edu.kp\\n" +"gov.kp\\n" +"org.kp\\n" +"rep.kp\\n" +"tra.kp\\n" +"ac.kr\\n" +"ai.kr\\n" +"co.kr\\n" +"es.kr\\n" +"go.kr\\n" +"hs.kr\\n" +"io.kr\\n" +"it.kr\\n" +"kg.kr\\n" +"me.kr\\n" +"mil.kr\\n" +"ms.kr\\n" +"ne.kr\\n" +"or.kr\\n" +"pe.kr\\n" +"re.kr\\n" +"sc.kr\\n" +"busan.kr\\n" +"chungbuk.kr\\n" +"chungnam.kr\\n" +"daegu.kr\\n" +"daejeon.kr\\n" +"gangwon.kr\\n" +"gwangju.kr\\n" +"gyeongbuk.kr\\n" +"gyeonggi.kr\\n" +"gyeongnam.kr\\n" +"incheon.kr\\n" +"jeju.kr\\n" +"jeonbuk.kr\\n" +"jeonnam.kr\\n" +"seoul.kr\\n" +"ulsan.kr\\n" +"com.kw\\n" +"edu.kw\\n" +"emb.kw\\n" +"gov.kw\\n" +"ind.kw\\n" +"net.kw\\n" +"org.kw\\n" +"com.ky\\n" +"edu.ky\\n" +"net.ky\\n" +"org.ky\\n" +"com.kz\\n" +"edu.kz\\n" +"gov.kz\\n" +"mil.kz\\n" +"net.kz\\n" +"org.kz\\n" +"com.la\\n" +"edu.la\\n" +"gov.la\\n" +"info.la\\n" +"int.la\\n" +"net.la\\n" +"org.la\\n" +"per.la\\n" +"com.lb\\n" +"edu.lb\\n" +"gov.lb\\n" +"net.lb\\n" +"org.lb\\n" +"co.lc\\n" +"com.lc\\n" +"edu.lc\\n" +"gov.lc\\n" +"net.lc\\n" +"org.lc\\n" +"ac.lk\\n" +"assn.lk\\n" +"com.lk\\n" +"edu.lk\\n" +"gov.lk\\n" +"grp.lk\\n" +"hotel.lk\\n" +"int.lk\\n" +"ltd.lk\\n" +"net.lk\\n" +"ngo.lk\\n" +"org.lk\\n" +"sch.lk\\n" +"soc.lk\\n" +"web.lk\\n" +"com.lr\\n" +"edu.lr\\n" +"gov.lr\\n" +"net.lr\\n" +"org.lr\\n" +"ac.ls\\n" +"biz.ls\\n" +"co.ls\\n" +"edu.ls\\n" +"gov.ls\\n" +"info.ls\\n" +"net.ls\\n" +"org.ls\\n" +"sc.ls\\n" +"gov.lt\\n" +"asn.lv\\n" +"com.lv\\n" +"conf.lv\\n" +"edu.lv\\n" +"gov.lv\\n" +"id.lv\\n" +"mil.lv\\n" +"net.lv\\n" +"org.lv\\n" +"com.ly\\n" +"edu.ly\\n" +"gov.ly\\n" +"id.ly\\n" +"med.ly\\n" +"net.ly\\n" +"org.ly\\n" +"plc.ly\\n" +"sch.ly\\n" +"ac.ma\\n" +"co.ma\\n" +"gov.ma\\n" +"net.ma\\n" +"org.ma\\n" +"press.ma\\n" +"asso.mc\\n" +"tm.mc\\n" +"ac.me\\n" +"co.me\\n" +"edu.me\\n" +"gov.me\\n" +"its.me\\n" +"net.me\\n" +"org.me\\n" +"priv.me\\n" +"co.mg\\n" +"com.mg\\n" +"edu.mg\\n" +"gov.mg\\n" +"mil.mg\\n" +"nom.mg\\n" +"org.mg\\n" +"prd.mg\\n" +"com.mk\\n" +"edu.mk\\n" +"gov.mk\\n" +"inf.mk\\n" +"name.mk\\n" +"net.mk\\n" +"org.mk\\n" +"ac.ml\\n" +"art.ml\\n" +"asso.ml\\n" +"com.ml\\n" +"edu.ml\\n" +"gouv.ml\\n" +"gov.ml\\n" +"info.ml\\n" +"inst.ml\\n" +"net.ml\\n" +"org.ml\\n" +"pr.ml\\n" +"presse.ml\\n" +"edu.mn\\n" +"gov.mn\\n" +"org.mn\\n" +"com.mo\\n" +"edu.mo\\n" +"gov.mo\\n" +"net.mo\\n" +"org.mo\\n" +"gov.mr\\n" +"com.ms\\n" +"edu.ms\\n" +"gov.ms\\n" +"net.ms\\n" +"org.ms\\n" +"com.mt\\n" +"edu.mt\\n" +"net.mt\\n" +"org.mt\\n" +"ac.mu\\n" +"co.mu\\n" +"com.mu\\n" +"gov.mu\\n" +"net.mu\\n" +"or.mu\\n" +"org.mu\\n" +"aero.mv\\n" +"biz.mv\\n" +"com.mv\\n" +"coop.mv\\n" +"edu.mv\\n" +"gov.mv\\n" +"info.mv\\n" +"int.mv\\n" +"mil.mv\\n" +"museum.mv\\n" +"name.mv\\n" +"net.mv\\n" +"org.mv\\n" +"pro.mv\\n" +"ac.mw\\n" +"biz.mw\\n" +"co.mw\\n" +"com.mw\\n" +"coop.mw\\n" +"edu.mw\\n" +"gov.mw\\n" +"int.mw\\n" +"net.mw\\n" +"org.mw\\n" +"com.mx\\n" +"edu.mx\\n" +"gob.mx\\n" +"net.mx\\n" +"org.mx\\n" +"biz.my\\n" +"com.my\\n" +"edu.my\\n" +"gov.my\\n" +"mil.my\\n" +"name.my\\n" +"net.my\\n" +"org.my\\n" +"ac.mz\\n" +"adv.mz\\n" +"co.mz\\n" +"edu.mz\\n" +"gov.mz\\n" +"mil.mz\\n" +"net.mz\\n" +"org.mz\\n" +"alt.na\\n" +"co.na\\n" +"com.na\\n" +"gov.na\\n" +"net.na\\n" +"org.na\\n" +"asso.nc\\n" +"nom.nc\\n" +"arts.nf\\n" +"com.nf\\n" +"firm.nf\\n" +"info.nf\\n" +"net.nf\\n" +"other.nf\\n" +"per.nf\\n" +"rec.nf\\n" +"store.nf\\n" +"web.nf\\n" +"com.ng\\n" +"edu.ng\\n" +"gov.ng\\n" +"i.ng\\n" +"mil.ng\\n" +"mobi.ng\\n" +"name.ng\\n" +"net.ng\\n" +"org.ng\\n" +"sch.ng\\n" +"ac.ni\\n" +"biz.ni\\n" +"co.ni\\n" +"com.ni\\n" +"edu.ni\\n" +"gob.ni\\n" +"in.ni\\n" +"info.ni\\n" +"int.ni\\n" +"mil.ni\\n" +"net.ni\\n" +"nom.ni\\n" +"org.ni\\n" +"web.ni\\n" +"fhs.no\\n" +"folkebibl.no\\n" +"fylkesbibl.no\\n" +"gielda.no\\n" +"herad.no\\n" +"idrett.no\\n" +"kommune.no\\n" +"museum.no\\n" +"priv.no\\n" +"suohkan.no\\n" +"tjielte.no\\n" +"uenorge.no\\n" +"vgs.no\\n" +"dep.no\\n" +"mil.no\\n" +"stat.no\\n" +"aa.no\\n" +"ah.no\\n" +"bu.no\\n" +"fm.no\\n" +"hl.no\\n" +"hm.no\\n" +"jan-mayen.no\\n" +"mr.no\\n" +"nl.no\\n" +"nt.no\\n" +"of.no\\n" +"ol.no\\n" +"oslo.no\\n" +"rl.no\\n" +"sf.no\\n" +"st.no\\n" +"svalbard.no\\n" +"tm.no\\n" +"tr.no\\n" +"va.no\\n" +"vf.no\\n" +"gs.aa.no\\n" +"gs.ah.no\\n" +"gs.bu.no\\n" +"gs.fm.no\\n" +"gs.hl.no\\n" +"gs.hm.no\\n" +"gs.jan-mayen.no\\n" +"gs.mr.no\\n" +"gs.nl.no\\n" +"gs.nt.no\\n" +"gs.of.no\\n" +"gs.ol.no\\n" +"gs.oslo.no\\n" +"gs.rl.no\\n" +"gs.sf.no\\n" +"gs.st.no\\n" +"gs.svalbard.no\\n" +"gs.tm.no\\n" +"gs.tr.no\\n" +"gs.va.no\\n" +"gs.vf.no\\n" +"akrehamn.no\\n" +"algard.no\\n" +"arna.no\\n" +"bronnoysund.no\\n" +"brumunddal.no\\n" +"bryne.no\\n" +"drobak.no\\n" +"egersund.no\\n" +"fetsund.no\\n" +"floro.no\\n" +"fredrikstad.no\\n" +"hokksund.no\\n" +"honefoss.no\\n" +"jessheim.no\\n" +"jorpeland.no\\n" +"kirkenes.no\\n" +"kopervik.no\\n" +"krokstadelva.no\\n" +"langevag.no\\n" +"leirvik.no\\n" +"mjondalen.no\\n" +"mo-i-rana.no\\n" +"mosjoen.no\\n" +"nesoddtangen.no\\n" +"orkanger.no\\n" +"osoyro.no\\n" +"raholt.no\\n" +"sandnessjoen.no\\n" +"skedsmokorset.no\\n" +"slattum.no\\n" +"spjelkavik.no\\n" +"stathelle.no\\n" +"stavern.no\\n" +"stjordalshalsen.no\\n" +"tananger.no\\n" +"tranby.no\\n" +"vossevangen.no\\n" +"aarborte.no\\n" +"aejrie.no\\n" +"afjord.no\\n" +"agdenes.no\\n" +"nes.akershus.no\\n" +"aknoluokta.no\\n" +"al.no\\n" +"alaheadju.no\\n" +"alesund.no\\n" +"alstahaug.no\\n" +"alta.no\\n" +"alvdal.no\\n" +"amli.no\\n" +"amot.no\\n" +"andasuolo.no\\n" +"andebu.no\\n" +"andoy.no\\n" +"ardal.no\\n" +"aremark.no\\n" +"arendal.no\\n" +"aseral.no\\n" +"asker.no\\n" +"askim.no\\n" +"askoy.no\\n" +"askvoll.no\\n" +"asnes.no\\n" +"audnedal.no\\n" +"aukra.no\\n" +"aure.no\\n" +"aurland.no\\n" +"aurskog-holand.no\\n" +"austevoll.no\\n" +"austrheim.no\\n" +"averoy.no\\n" +"badaddja.no\\n" +"bahcavuotna.no\\n" +"bahccavuotna.no\\n" +"baidar.no\\n" +"bajddar.no\\n" +"balat.no\\n" +"balestrand.no\\n" +"ballangen.no\\n" +"balsfjord.no\\n" +"bamble.no\\n" +"bardu.no\\n" +"barum.no\\n" +"batsfjord.no\\n" +"bearalvahki.no\\n" +"beardu.no\\n" +"beiarn.no\\n" +"berg.no\\n" +"bergen.no\\n" +"berlevag.no\\n" +"bievat.no\\n" +"bindal.no\\n" +"birkenes.no\\n" +"bjerkreim.no\\n" +"bjugn.no\\n" +"bodo.no\\n" +"bokn.no\\n" +"bomlo.no\\n" +"bremanger.no\\n" +"bronnoy.no\\n" +"budejju.no\\n" +"nes.buskerud.no\\n" +"bygland.no\\n" +"bykle.no\\n" +"cahcesuolo.no\\n" +"davvenjarga.no\\n" +"davvesiida.no\\n" +"deatnu.no\\n" +"dielddanuorri.no\\n" +"divtasvuodna.no\\n" +"divttasvuotna.no\\n" +"donna.no\\n" +"dovre.no\\n" +"drammen.no\\n" +"drangedal.no\\n" +"dyroy.no\\n" +"eid.no\\n" +"eidfjord.no\\n" +"eidsberg.no\\n" +"eidskog.no\\n" +"eidsvoll.no\\n" +"eigersund.no\\n" +"elverum.no\\n" +"enebakk.no\\n" +"engerdal.no\\n" +"etne.no\\n" +"etnedal.no\\n" +"evenassi.no\\n" +"evenes.no\\n" +"evje-og-hornnes.no\\n" +"farsund.no\\n" +"fauske.no\\n" +"fedje.no\\n" +"fet.no\\n" +"finnoy.no\\n" +"fitjar.no\\n" +"fjaler.no\\n" +"fjell.no\\n" +"fla.no\\n" +"flakstad.no\\n" +"flatanger.no\\n" +"flekkefjord.no\\n" +"flesberg.no\\n" +"flora.no\\n" +"folldal.no\\n" +"forde.no\\n" +"forsand.no\\n" +"fosnes.no\\n" +"frana.no\\n" +"frogn.no\\n" +"froland.no\\n" +"frosta.no\\n" +"froya.no\\n" +"fuoisku.no\\n" +"fuossko.no\\n" +"fusa.no\\n" +"fyresdal.no\\n" +"gaivuotna.no\\n" +"galsa.no\\n" +"gamvik.no\\n" +"gangaviika.no\\n" +"gaular.no\\n" +"gausdal.no\\n" +"giehtavuoatna.no\\n" +"gildeskal.no\\n" +"giske.no\\n" +"gjemnes.no\\n" +"gjerdrum.no\\n" +"gjerstad.no\\n" +"gjesdal.no\\n" +"gjovik.no\\n" +"gloppen.no\\n" +"gol.no\\n" +"gran.no\\n" +"grane.no\\n" +"granvin.no\\n" +"gratangen.no\\n" +"grimstad.no\\n" +"grong.no\\n" +"grue.no\\n" +"gulen.no\\n" +"guovdageaidnu.no\\n" +"ha.no\\n" +"habmer.no\\n" +"hadsel.no\\n" +"hagebostad.no\\n" +"halden.no\\n" +"halsa.no\\n" +"hamar.no\\n" +"hamaroy.no\\n" +"hammarfeasta.no\\n" +"hammerfest.no\\n" +"hapmir.no\\n" +"haram.no\\n" +"hareid.no\\n" +"harstad.no\\n" +"hasvik.no\\n" +"hattfjelldal.no\\n" +"haugesund.no\\n" +"os.hedmark.no\\n" +"valer.hedmark.no\\n" +"hemne.no\\n" +"hemnes.no\\n" +"hemsedal.no\\n" +"hitra.no\\n" +"hjartdal.no\\n" +"hjelmeland.no\\n" +"hobol.no\\n" +"hof.no\\n" +"hol.no\\n" +"hole.no\\n" +"holmestrand.no\\n" +"holtalen.no\\n" +"os.hordaland.no\\n" +"hornindal.no\\n" +"horten.no\\n" +"hoyanger.no\\n" +"hoylandet.no\\n" +"hurdal.no\\n" +"hurum.no\\n" +"hvaler.no\\n" +"hyllestad.no\\n" +"ibestad.no\\n" +"inderoy.no\\n" +"iveland.no\\n" +"ivgu.no\\n" +"jevnaker.no\\n" +"jolster.no\\n" +"jondal.no\\n" +"kafjord.no\\n" +"karasjohka.no\\n" +"karasjok.no\\n" +"karlsoy.no\\n" +"karmoy.no\\n" +"kautokeino.no\\n" +"klabu.no\\n" +"klepp.no\\n" +"kongsberg.no\\n" +"kongsvinger.no\\n" +"kraanghke.no\\n" +"kragero.no\\n" +"kristiansand.no\\n" +"kristiansund.no\\n" +"krodsherad.no\\n" +"kvafjord.no\\n" +"kvalsund.no\\n" +"kvam.no\\n" +"kvanangen.no\\n" +"kvinesdal.no\\n" +"kvinnherad.no\\n" +"kviteseid.no\\n" +"kvitsoy.no\\n" +"laakesvuemie.no\\n" +"lahppi.no\\n" +"lardal.no\\n" +"larvik.no\\n" +"lavagis.no\\n" +"lavangen.no\\n" +"leangaviika.no\\n" +"lebesby.no\\n" +"leikanger.no\\n" +"leirfjord.no\\n" +"leka.no\\n" +"leksvik.no\\n" +"lenvik.no\\n" +"lerdal.no\\n" +"lesja.no\\n" +"levanger.no\\n" +"lier.no\\n" +"lierne.no\\n" +"lillehammer.no\\n" +"lillesand.no\\n" +"lindas.no\\n" +"lindesnes.no\\n" +"loabat.no\\n" +"lodingen.no\\n" +"lom.no\\n" +"loppa.no\\n" +"lorenskog.no\\n" +"loten.no\\n" +"lund.no\\n" +"lunner.no\\n" +"luroy.no\\n" +"luster.no\\n" +"lyngdal.no\\n" +"lyngen.no\\n" +"malatvuopmi.no\\n" +"malselv.no\\n" +"malvik.no\\n" +"mandal.no\\n" +"marker.no\\n" +"marnardal.no\\n" +"masfjorden.no\\n" +"masoy.no\\n" +"matta-varjjat.no\\n" +"meland.no\\n" +"meldal.no\\n" +"melhus.no\\n" +"meloy.no\\n" +"meraker.no\\n" +"midsund.no\\n" +"midtre-gauldal.no\\n" +"moareke.no\\n" +"modalen.no\\n" +"modum.no\\n" +"molde.no\\n" +"heroy.more-og-romsdal.no\\n" +"sande.more-og-romsdal.no\\n" +"moskenes.no\\n" +"moss.no\\n" +"muosat.no\\n" +"naamesjevuemie.no\\n" +"namdalseid.no\\n" +"namsos.no\\n" +"namsskogan.no\\n" +"nannestad.no\\n" +"naroy.no\\n" +"narviika.no\\n" +"narvik.no\\n" +"naustdal.no\\n" +"navuotna.no\\n" +"nedre-eiker.no\\n" +"nesna.no\\n" +"nesodden.no\\n" +"nesseby.no\\n" +"nesset.no\\n" +"nissedal.no\\n" +"nittedal.no\\n" +"nord-aurdal.no\\n" +"nord-fron.no\\n" +"nord-odal.no\\n" +"norddal.no\\n" +"nordkapp.no\\n" +"bo.nordland.no\\n" +"heroy.nordland.no\\n" +"nordre-land.no\\n" +"nordreisa.no\\n" +"nore-og-uvdal.no\\n" +"notodden.no\\n" +"notteroy.no\\n" +"odda.no\\n" +"oksnes.no\\n" +"omasvuotna.no\\n" +"oppdal.no\\n" +"oppegard.no\\n" +"orkdal.no\\n" +"orland.no\\n" +"orskog.no\\n" +"orsta.no\\n" +"osen.no\\n" +"osteroy.no\\n" +"valer.ostfold.no\\n" +"ostre-toten.no\\n" +"overhalla.no\\n" +"ovre-eiker.no\\n" +"oyer.no\\n" +"oygarden.no\\n" +"oystre-slidre.no\\n" +"porsanger.no\\n" +"porsangu.no\\n" +"porsgrunn.no\\n" +"rade.no\\n" +"radoy.no\\n" +"rahkkeravju.no\\n" +"raisa.no\\n" +"rakkestad.no\\n" +"ralingen.no\\n" +"rana.no\\n" +"randaberg.no\\n" +"rauma.no\\n" +"re.no\\n" +"rendalen.no\\n" +"rennebu.no\\n" +"rennesoy.no\\n" +"rindal.no\\n" +"ringebu.no\\n" +"ringerike.no\\n" +"ringsaker.no\\n" +"risor.no\\n" +"rissa.no\\n" +"roan.no\\n" +"rodoy.no\\n" +"rollag.no\\n" +"romsa.no\\n" +"romskog.no\\n" +"roros.no\\n" +"rost.no\\n" +"royken.no\\n" +"royrvik.no\\n" +"ruovat.no\\n" +"rygge.no\\n" +"salangen.no\\n" +"salat.no\\n" +"saltdal.no\\n" +"samnanger.no\\n" +"sandefjord.no\\n" +"sandnes.no\\n" +"sandoy.no\\n" +"sarpsborg.no\\n" +"sauda.no\\n" +"sauherad.no\\n" +"sel.no\\n" +"selbu.no\\n" +"selje.no\\n" +"seljord.no\\n" +"siellak.no\\n" +"sigdal.no\\n" +"siljan.no\\n" +"sirdal.no\\n" +"skanit.no\\n" +"skanland.no\\n" +"skaun.no\\n" +"skedsmo.no\\n" +"ski.no\\n" +"skien.no\\n" +"skierva.no\\n" +"skiptvet.no\\n" +"skjak.no\\n" +"skjervoy.no\\n" +"skodje.no\\n" +"smola.no\\n" +"snaase.no\\n" +"snasa.no\\n" +"snillfjord.no\\n" +"snoasa.no\\n" +"sogndal.no\\n" +"sogne.no\\n" +"sokndal.no\\n" +"sola.no\\n" +"solund.no\\n" +"somna.no\\n" +"sondre-land.no\\n" +"songdalen.no\\n" +"sor-aurdal.no\\n" +"sor-fron.no\\n" +"sor-odal.no\\n" +"sor-varanger.no\\n" +"sorfold.no\\n" +"sorreisa.no\\n" +"sortland.no\\n" +"sorum.no\\n" +"spydeberg.no\\n" +"stange.no\\n" +"stavanger.no\\n" +"steigen.no\\n" +"steinkjer.no\\n" +"stjordal.no\\n" +"stokke.no\\n" +"stor-elvdal.no\\n" +"stord.no\\n" +"stordal.no\\n" +"storfjord.no\\n" +"strand.no\\n" +"stranda.no\\n" +"stryn.no\\n" +"sula.no\\n" +"suldal.no\\n" +"sund.no\\n" +"sunndal.no\\n" +"surnadal.no\\n" +"sveio.no\\n" +"svelvik.no\\n" +"sykkylven.no\\n" +"tana.no\\n" +"bo.telemark.no\\n" +"time.no\\n" +"tingvoll.no\\n" +"tinn.no\\n" +"tjeldsund.no\\n" +"tjome.no\\n" +"tokke.no\\n" +"tolga.no\\n" +"tonsberg.no\\n" +"torsken.no\\n" +"trana.no\\n" +"tranoy.no\\n" +"troandin.no\\n" +"trogstad.no\\n" +"tromsa.no\\n" +"tromso.no\\n" +"trondheim.no\\n" +"trysil.no\\n" +"tvedestrand.no\\n" +"tydal.no\\n" +"tynset.no\\n" +"tysfjord.no\\n" +"tysnes.no\\n" +"tysvar.no\\n" +"ullensaker.no\\n" +"ullensvang.no\\n" +"ulstein.no\\n" +"ulvik.no\\n" +"unjarga.no\\n" +"utsira.no\\n" +"vaapste.no\\n" +"vadso.no\\n" +"vaga.no\\n" +"vagan.no\\n" +"vagsoy.no\\n" +"vaksdal.no\\n" +"valle.no\\n" +"vang.no\\n" +"vanylven.no\\n" +"vardo.no\\n" +"varggat.no\\n" +"varoy.no\\n" +"vefsn.no\\n" +"vega.no\\n" +"vegarshei.no\\n" +"vennesla.no\\n" +"verdal.no\\n" +"verran.no\\n" +"vestby.no\\n" +"sande.vestfold.no\\n" +"vestnes.no\\n" +"vestre-slidre.no\\n" +"vestre-toten.no\\n" +"vestvagoy.no\\n" +"vevelstad.no\\n" +"vik.no\\n" +"vikna.no\\n" +"vindafjord.no\\n" +"voagat.no\\n" +"volda.no\\n" +"voss.no\\n" +"biz.nr\\n" +"com.nr\\n" +"edu.nr\\n" +"gov.nr\\n" +"info.nr\\n" +"net.nr\\n" +"org.nr\\n" +"ac.nz\\n" +"co.nz\\n" +"cri.nz\\n" +"geek.nz\\n" +"gen.nz\\n" +"govt.nz\\n" +"health.nz\\n" +"iwi.nz\\n" +"kiwi.nz\\n" +"maori.nz\\n" +"mil.nz\\n" +"net.nz\\n" +"org.nz\\n" +"parliament.nz\\n" +"school.nz\\n" +"co.om\\n" +"com.om\\n" +"edu.om\\n" +"gov.om\\n" +"med.om\\n" +"museum.om\\n" +"net.om\\n" +"org.om\\n" +"pro.om\\n" +"abo.pa\\n" +"ac.pa\\n" +"com.pa\\n" +"edu.pa\\n" +"gob.pa\\n" +"ing.pa\\n" +"med.pa\\n" +"net.pa\\n" +"nom.pa\\n" +"org.pa\\n" +"sld.pa\\n" +"com.pe\\n" +"edu.pe\\n" +"gob.pe\\n" +"mil.pe\\n" +"net.pe\\n" +"nom.pe\\n" +"org.pe\\n" +"com.pf\\n" +"edu.pf\\n" +"org.pf\\n" +"com.ph\\n" +"edu.ph\\n" +"gov.ph\\n" +"i.ph\\n" +"mil.ph\\n" +"net.ph\\n" +"ngo.ph\\n" +"org.ph\\n" +"ac.pk\\n" +"biz.pk\\n" +"com.pk\\n" +"edu.pk\\n" +"fam.pk\\n" +"gkp.pk\\n" +"gob.pk\\n" +"gog.pk\\n" +"gok.pk\\n" +"gop.pk\\n" +"gos.pk\\n" +"gov.pk\\n" +"net.pk\\n" +"org.pk\\n" +"web.pk\\n" +"com.pl\\n" +"net.pl\\n" +"org.pl\\n" +"agro.pl\\n" +"aid.pl\\n" +"atm.pl\\n" +"auto.pl\\n" +"biz.pl\\n" +"edu.pl\\n" +"gmina.pl\\n" +"gsm.pl\\n" +"info.pl\\n" +"mail.pl\\n" +"media.pl\\n" +"miasta.pl\\n" +"mil.pl\\n" +"nieruchomosci.pl\\n" +"nom.pl\\n" +"pc.pl\\n" +"powiat.pl\\n" +"priv.pl\\n" +"realestate.pl\\n" +"rel.pl\\n" +"sex.pl\\n" +"shop.pl\\n" +"sklep.pl\\n" +"sos.pl\\n" +"szkola.pl\\n" +"targi.pl\\n" +"tm.pl\\n" +"tourism.pl\\n" +"travel.pl\\n" +"turystyka.pl\\n" +"gov.pl\\n" +"ap.gov.pl\\n" +"griw.gov.pl\\n" +"ic.gov.pl\\n" +"is.gov.pl\\n" +"kmpsp.gov.pl\\n" +"konsulat.gov.pl\\n" +"kppsp.gov.pl\\n" +"kwp.gov.pl\\n" +"kwpsp.gov.pl\\n" +"mup.gov.pl\\n" +"mw.gov.pl\\n" +"oia.gov.pl\\n" +"oirm.gov.pl\\n" +"oke.gov.pl\\n" +"oow.gov.pl\\n" +"oschr.gov.pl\\n" +"oum.gov.pl\\n" +"pa.gov.pl\\n" +"pinb.gov.pl\\n" +"piw.gov.pl\\n" +"po.gov.pl\\n" +"pr.gov.pl\\n" +"psp.gov.pl\\n" +"psse.gov.pl\\n" +"pup.gov.pl\\n" +"rzgw.gov.pl\\n" +"sa.gov.pl\\n" +"sdn.gov.pl\\n" +"sko.gov.pl\\n" +"so.gov.pl\\n" +"sr.gov.pl\\n" +"starostwo.gov.pl\\n" +"ug.gov.pl\\n" +"ugim.gov.pl\\n" +"um.gov.pl\\n" +"umig.gov.pl\\n" +"upow.gov.pl\\n" +"uppo.gov.pl\\n" +"us.gov.pl\\n" +"uw.gov.pl\\n" +"uzs.gov.pl\\n" +"wif.gov.pl\\n" +"wiih.gov.pl\\n" +"winb.gov.pl\\n" +"wios.gov.pl\\n" +"witd.gov.pl\\n" +"wiw.gov.pl\\n" +"wkz.gov.pl\\n" +"wsa.gov.pl\\n" +"wskr.gov.pl\\n" +"wsse.gov.pl\\n" +"wuoz.gov.pl\\n" +"wzmiuw.gov.pl\\n" +"zp.gov.pl\\n" +"zpisdn.gov.pl\\n" +"augustow.pl\\n" +"babia-gora.pl\\n" +"bedzin.pl\\n" +"beskidy.pl\\n" +"bialowieza.pl\\n" +"bialystok.pl\\n" +"bielawa.pl\\n" +"bieszczady.pl\\n" +"boleslawiec.pl\\n" +"bydgoszcz.pl\\n" +"bytom.pl\\n" +"cieszyn.pl\\n" +"czeladz.pl\\n" +"czest.pl\\n" +"dlugoleka.pl\\n" +"elblag.pl\\n" +"elk.pl\\n" +"glogow.pl\\n" +"gniezno.pl\\n" +"gorlice.pl\\n" +"grajewo.pl\\n" +"ilawa.pl\\n" +"jaworzno.pl\\n" +"jelenia-gora.pl\\n" +"jgora.pl\\n" +"kalisz.pl\\n" +"karpacz.pl\\n" +"kartuzy.pl\\n" +"kaszuby.pl\\n" +"katowice.pl\\n" +"kazimierz-dolny.pl\\n" +"kepno.pl\\n" +"ketrzyn.pl\\n" +"klodzko.pl\\n" +"kobierzyce.pl\\n" +"kolobrzeg.pl\\n" +"konin.pl\\n" +"konskowola.pl\\n" +"kutno.pl\\n" +"lapy.pl\\n" +"lebork.pl\\n" +"legnica.pl\\n" +"lezajsk.pl\\n" +"limanowa.pl\\n" +"lomza.pl\\n" +"lowicz.pl\\n" +"lubin.pl\\n" +"lukow.pl\\n" +"malbork.pl\\n" +"malopolska.pl\\n" +"mazowsze.pl\\n" +"mazury.pl\\n" +"mielec.pl\\n" +"mielno.pl\\n" +"mragowo.pl\\n" +"naklo.pl\\n" +"nowaruda.pl\\n" +"nysa.pl\\n" +"olawa.pl\\n" +"olecko.pl\\n" +"olkusz.pl\\n" +"olsztyn.pl\\n" +"opoczno.pl\\n" +"opole.pl\\n" +"ostroda.pl\\n" +"ostroleka.pl\\n" +"ostrowiec.pl\\n" +"ostrowwlkp.pl\\n" +"pila.pl\\n" +"pisz.pl\\n" +"podhale.pl\\n" +"podlasie.pl\\n" +"polkowice.pl\\n" +"pomorskie.pl\\n" +"pomorze.pl\\n" +"prochowice.pl\\n" +"pruszkow.pl\\n" +"przeworsk.pl\\n" +"pulawy.pl\\n" +"radom.pl\\n" +"rawa-maz.pl\\n" +"rybnik.pl\\n" +"rzeszow.pl\\n" +"sanok.pl\\n" +"sejny.pl\\n" +"skoczow.pl\\n" +"slask.pl\\n" +"slupsk.pl\\n" +"sosnowiec.pl\\n" +"stalowa-wola.pl\\n" +"starachowice.pl\\n" +"stargard.pl\\n" +"suwalki.pl\\n" +"swidnica.pl\\n" +"swiebodzin.pl\\n" +"swinoujscie.pl\\n" +"szczecin.pl\\n" +"szczytno.pl\\n" +"tarnobrzeg.pl\\n" +"tgory.pl\\n" +"turek.pl\\n" +"tychy.pl\\n" +"ustka.pl\\n" +"walbrzych.pl\\n" +"warmia.pl\\n" +"warszawa.pl\\n" +"waw.pl\\n" +"wegrow.pl\\n" +"wielun.pl\\n" +"wlocl.pl\\n" +"wloclawek.pl\\n" +"wodzislaw.pl\\n" +"wolomin.pl\\n" +"wroclaw.pl\\n" +"zachpomor.pl\\n" +"zagan.pl\\n" +"zarow.pl\\n" +"zgora.pl\\n" +"zgorzelec.pl\\n" +"co.pn\\n" +"edu.pn\\n" +"gov.pn\\n" +"net.pn\\n" +"org.pn\\n" +"ac.pr\\n" +"biz.pr\\n" +"com.pr\\n" +"edu.pr\\n" +"est.pr\\n" +"gov.pr\\n" +"info.pr\\n" +"isla.pr\\n" +"name.pr\\n" +"net.pr\\n" +"org.pr\\n" +"pro.pr\\n" +"prof.pr\\n" +"aaa.pro\\n" +"aca.pro\\n" +"acct.pro\\n" +"avocat.pro\\n" +"bar.pro\\n" +"cpa.pro\\n" +"eng.pro\\n" +"jur.pro\\n" +"law.pro\\n" +"med.pro\\n" +"recht.pro\\n" +"com.ps\\n" +"edu.ps\\n" +"gov.ps\\n" +"net.ps\\n" +"org.ps\\n" +"plo.ps\\n" +"sec.ps\\n" +"com.pt\\n" +"edu.pt\\n" +"gov.pt\\n" +"int.pt\\n" +"net.pt\\n" +"nome.pt\\n" +"org.pt\\n" +"publ.pt\\n" +"gov.pw\\n" +"com.py\\n" +"coop.py\\n" +"edu.py\\n" +"gov.py\\n" +"mil.py\\n" +"net.py\\n" +"org.py\\n" +"com.qa\\n" +"edu.qa\\n" +"gov.qa\\n" +"mil.qa\\n" +"name.qa\\n" +"net.qa\\n" +"org.qa\\n" +"sch.qa\\n" +"asso.re\\n" +"com.re\\n" +"arts.ro\\n" +"com.ro\\n" +"firm.ro\\n" +"info.ro\\n" +"nom.ro\\n" +"nt.ro\\n" +"org.ro\\n" +"rec.ro\\n" +"store.ro\\n" +"tm.ro\\n" +"www.ro\\n" +"ac.rs\\n" +"co.rs\\n" +"edu.rs\\n" +"gov.rs\\n" +"in.rs\\n" +"org.rs\\n" +"ac.rw\\n" +"co.rw\\n" +"coop.rw\\n" +"gov.rw\\n" +"mil.rw\\n" +"net.rw\\n" +"org.rw\\n" +"com.sa\\n" +"edu.sa\\n" +"gov.sa\\n" +"med.sa\\n" +"net.sa\\n" +"org.sa\\n" +"pub.sa\\n" +"sch.sa\\n" +"com.sb\\n" +"edu.sb\\n" +"gov.sb\\n" +"net.sb\\n" +"org.sb\\n" +"com.sc\\n" +"edu.sc\\n" +"gov.sc\\n" +"net.sc\\n" +"org.sc\\n" +"com.sd\\n" +"edu.sd\\n" +"gov.sd\\n" +"info.sd\\n" +"med.sd\\n" +"net.sd\\n" +"org.sd\\n" +"tv.sd\\n" +"a.se\\n" +"ac.se\\n" +"b.se\\n" +"bd.se\\n" +"brand.se\\n" +"c.se\\n" +"d.se\\n" +"e.se\\n" +"f.se\\n" +"fh.se\\n" +"fhsk.se\\n" +"fhv.se\\n" +"g.se\\n" +"h.se\\n" +"i.se\\n" +"k.se\\n" +"komforb.se\\n" +"kommunalforbund.se\\n" +"komvux.se\\n" +"l.se\\n" +"lanbib.se\\n" +"m.se\\n" +"n.se\\n" +"naturbruksgymn.se\\n" +"o.se\\n" +"org.se\\n" +"p.se\\n" +"parti.se\\n" +"pp.se\\n" +"press.se\\n" +"r.se\\n" +"s.se\\n" +"t.se\\n" +"tm.se\\n" +"u.se\\n" +"w.se\\n" +"x.se\\n" +"y.se\\n" +"z.se\\n" +"com.sg\\n" +"edu.sg\\n" +"gov.sg\\n" +"net.sg\\n" +"org.sg\\n" +"com.sh\\n" +"gov.sh\\n" +"mil.sh\\n" +"net.sh\\n" +"org.sh\\n" +"org.sk\\n" +"com.sl\\n" +"edu.sl\\n" +"gov.sl\\n" +"net.sl\\n" +"org.sl\\n" +"art.sn\\n" +"com.sn\\n" +"edu.sn\\n" +"gouv.sn\\n" +"org.sn\\n" +"univ.sn\\n" +"com.so\\n" +"edu.so\\n" +"gov.so\\n" +"me.so\\n" +"net.so\\n" +"org.so\\n" +"biz.ss\\n" +"co.ss\\n" +"com.ss\\n" +"edu.ss\\n" +"gov.ss\\n" +"me.ss\\n" +"net.ss\\n" +"org.ss\\n" +"sch.ss\\n" +"co.st\\n" +"com.st\\n" +"consulado.st\\n" +"edu.st\\n" +"embaixada.st\\n" +"mil.st\\n" +"net.st\\n" +"org.st\\n" +"principe.st\\n" +"saotome.st\\n" +"store.st\\n" +"com.sv\\n" +"edu.sv\\n" +"gob.sv\\n" +"org.sv\\n" +"red.sv\\n" +"gov.sx\\n" +"com.sy\\n" +"edu.sy\\n" +"gov.sy\\n" +"mil.sy\\n" +"net.sy\\n" +"org.sy\\n" +"ac.sz\\n" +"co.sz\\n" +"org.sz\\n" +"ac.th\\n" +"co.th\\n" +"go.th\\n" +"in.th\\n" +"mi.th\\n" +"net.th\\n" +"or.th\\n" +"biz.tj\\n" +"co.tj\\n" +"com.tj\\n" +"edu.tj\\n" +"go.tj\\n" +"gov.tj\\n" +"int.tj\\n" +"mil.tj\\n" +"name.tj\\n" +"net.tj\\n" +"nic.tj\\n" +"org.tj\\n" +"test.tj\\n" +"web.tj\\n" +"gov.tl\\n" +"co.tm\\n" +"com.tm\\n" +"edu.tm\\n" +"gov.tm\\n" +"mil.tm\\n" +"net.tm\\n" +"nom.tm\\n" +"org.tm\\n" +"com.tn\\n" +"ens.tn\\n" +"fin.tn\\n" +"gov.tn\\n" +"ind.tn\\n" +"info.tn\\n" +"intl.tn\\n" +"mincom.tn\\n" +"nat.tn\\n" +"net.tn\\n" +"org.tn\\n" +"perso.tn\\n" +"tourism.tn\\n" +"com.to\\n" +"edu.to\\n" +"gov.to\\n" +"mil.to\\n" +"net.to\\n" +"org.to\\n" +"av.tr\\n" +"bbs.tr\\n" +"bel.tr\\n" +"biz.tr\\n" +"com.tr\\n" +"dr.tr\\n" +"edu.tr\\n" +"gen.tr\\n" +"gov.tr\\n" +"info.tr\\n" +"k12.tr\\n" +"kep.tr\\n" +"mil.tr\\n" +"name.tr\\n" +"net.tr\\n" +"org.tr\\n" +"pol.tr\\n" +"tel.tr\\n" +"tsk.tr\\n" +"tv.tr\\n" +"web.tr\\n" +"nc.tr\\n" +"gov.nc.tr\\n" +"biz.tt\\n" +"co.tt\\n" +"com.tt\\n" +"edu.tt\\n" +"gov.tt\\n" +"info.tt\\n" +"mil.tt\\n" +"name.tt\\n" +"net.tt\\n" +"org.tt\\n" +"pro.tt\\n" +"club.tw\\n" +"com.tw\\n" +"ebiz.tw\\n" +"edu.tw\\n" +"game.tw\\n" +"gov.tw\\n" +"idv.tw\\n" +"mil.tw\\n" +"net.tw\\n" +"org.tw\\n" +"ac.tz\\n" +"co.tz\\n" +"go.tz\\n" +"hotel.tz\\n" +"info.tz\\n" +"me.tz\\n" +"mil.tz\\n" +"mobi.tz\\n" +"ne.tz\\n" +"or.tz\\n" +"sc.tz\\n" +"tv.tz\\n" +"com.ua\\n" +"edu.ua\\n" +"gov.ua\\n" +"in.ua\\n" +"net.ua\\n" +"org.ua\\n" +"cherkassy.ua\\n" +"cherkasy.ua\\n" +"chernigov.ua\\n" +"chernihiv.ua\\n" +"chernivtsi.ua\\n" +"chernovtsy.ua\\n" +"ck.ua\\n" +"cn.ua\\n" +"cr.ua\\n" +"crimea.ua\\n" +"cv.ua\\n" +"dn.ua\\n" +"dnepropetrovsk.ua\\n" +"dnipropetrovsk.ua\\n" +"donetsk.ua\\n" +"dp.ua\\n" +"if.ua\\n" +"ivano-frankivsk.ua\\n" +"kh.ua\\n" +"kharkiv.ua\\n" +"kharkov.ua\\n" +"kherson.ua\\n" +"khmelnitskiy.ua\\n" +"khmelnytskyi.ua\\n" +"kiev.ua\\n" +"kirovograd.ua\\n" +"km.ua\\n" +"kr.ua\\n" +"kropyvnytskyi.ua\\n" +"krym.ua\\n" +"ks.ua\\n" +"kv.ua\\n" +"kyiv.ua\\n" +"lg.ua\\n" +"lt.ua\\n" +"lugansk.ua\\n" +"luhansk.ua\\n" +"lutsk.ua\\n" +"lv.ua\\n" +"lviv.ua\\n" +"mk.ua\\n" +"mykolaiv.ua\\n" +"nikolaev.ua\\n" +"od.ua\\n" +"odesa.ua\\n" +"odessa.ua\\n" +"pl.ua\\n" +"poltava.ua\\n" +"rivne.ua\\n" +"rovno.ua\\n" +"rv.ua\\n" +"sb.ua\\n" +"sebastopol.ua\\n" +"sevastopol.ua\\n" +"sm.ua\\n" +"sumy.ua\\n" +"te.ua\\n" +"ternopil.ua\\n" +"uz.ua\\n" +"uzhgorod.ua\\n" +"uzhhorod.ua\\n" +"vinnica.ua\\n" +"vinnytsia.ua\\n" +"vn.ua\\n" +"volyn.ua\\n" +"yalta.ua\\n" +"zakarpattia.ua\\n" +"zaporizhzhe.ua\\n" +"zaporizhzhia.ua\\n" +"zhitomir.ua\\n" +"zhytomyr.ua\\n" +"zp.ua\\n" +"zt.ua\\n" +"ac.ug\\n" +"co.ug\\n" +"com.ug\\n" +"edu.ug\\n" +"go.ug\\n" +"gov.ug\\n" +"mil.ug\\n" +"ne.ug\\n" +"or.ug\\n" +"org.ug\\n" +"sc.ug\\n" +"us.ug\\n" +"ac.uk\\n" +"co.uk\\n" +"gov.uk\\n" +"ltd.uk\\n" +"me.uk\\n" +"net.uk\\n" +"nhs.uk\\n" +"org.uk\\n" +"plc.uk\\n" +"police.uk\\n" +"dni.us\\n" +"isa.us\\n" +"nsn.us\\n" +"ak.us\\n" +"al.us\\n" +"ar.us\\n" +"as.us\\n" +"az.us\\n" +"ca.us\\n" +"co.us\\n" +"ct.us\\n" +"dc.us\\n" +"de.us\\n" +"fl.us\\n" +"ga.us\\n" +"gu.us\\n" +"hi.us\\n" +"ia.us\\n" +"id.us\\n" +"il.us\\n" +"in.us\\n" +"ks.us\\n" +"ky.us\\n" +"la.us\\n" +"ma.us\\n" +"md.us\\n" +"me.us\\n" +"mi.us\\n" +"mn.us\\n" +"mo.us\\n" +"ms.us\\n" +"mt.us\\n" +"nc.us\\n" +"nd.us\\n" +"ne.us\\n" +"nh.us\\n" +"nj.us\\n" +"nm.us\\n" +"nv.us\\n" +"ny.us\\n" +"oh.us\\n" +"ok.us\\n" +"or.us\\n" +"pa.us\\n" +"pr.us\\n" +"ri.us\\n" +"sc.us\\n" +"sd.us\\n" +"tn.us\\n" +"tx.us\\n" +"ut.us\\n" +"va.us\\n" +"vi.us\\n" +"vt.us\\n" +"wa.us\\n" +"wi.us\\n" +"wv.us\\n" +"wy.us\\n" +"k12.ak.us\\n" +"k12.al.us\\n" +"k12.ar.us\\n" +"k12.as.us\\n" +"k12.az.us\\n" +"k12.ca.us\\n" +"k12.co.us\\n" +"k12.ct.us\\n" +"k12.dc.us\\n" +"k12.fl.us\\n" +"k12.ga.us\\n" +"k12.gu.us\\n" +"k12.ia.us\\n" +"k12.id.us\\n" +"k12.il.us\\n" +"k12.in.us\\n" +"k12.ks.us\\n" +"k12.ky.us\\n" +"k12.la.us\\n" +"k12.ma.us\\n" +"k12.md.us\\n" +"k12.me.us\\n" +"k12.mi.us\\n" +"k12.mn.us\\n" +"k12.mo.us\\n" +"k12.ms.us\\n" +"k12.mt.us\\n" +"k12.nc.us\\n" +"k12.ne.us\\n" +"k12.nh.us\\n" +"k12.nj.us\\n" +"k12.nm.us\\n" +"k12.nv.us\\n" +"k12.ny.us\\n" +"k12.oh.us\\n" +"k12.ok.us\\n" +"k12.or.us\\n" +"k12.pa.us\\n" +"k12.pr.us\\n" +"k12.sc.us\\n" +"k12.tn.us\\n" +"k12.tx.us\\n" +"k12.ut.us\\n" +"k12.va.us\\n" +"k12.vi.us\\n" +"k12.vt.us\\n" +"k12.wa.us\\n" +"k12.wi.us\\n" +"cc.ak.us\\n" +"lib.ak.us\\n" +"cc.al.us\\n" +"lib.al.us\\n" +"cc.ar.us\\n" +"lib.ar.us\\n" +"cc.as.us\\n" +"lib.as.us\\n" +"cc.az.us\\n" +"lib.az.us\\n" +"cc.ca.us\\n" +"lib.ca.us\\n" +"cc.co.us\\n" +"lib.co.us\\n" +"cc.ct.us\\n" +"lib.ct.us\\n" +"cc.dc.us\\n" +"lib.dc.us\\n" +"cc.de.us\\n" +"cc.fl.us\\n" +"lib.fl.us\\n" +"cc.ga.us\\n" +"lib.ga.us\\n" +"cc.gu.us\\n" +"lib.gu.us\\n" +"cc.hi.us\\n" +"lib.hi.us\\n" +"cc.ia.us\\n" +"lib.ia.us\\n" +"cc.id.us\\n" +"lib.id.us\\n" +"cc.il.us\\n" +"lib.il.us\\n" +"cc.in.us\\n" +"lib.in.us\\n" +"cc.ks.us\\n" +"lib.ks.us\\n" +"cc.ky.us\\n" +"lib.ky.us\\n" +"cc.la.us\\n" +"lib.la.us\\n" +"cc.ma.us\\n" +"lib.ma.us\\n" +"cc.md.us\\n" +"lib.md.us\\n" +"cc.me.us\\n" +"lib.me.us\\n" +"cc.mi.us\\n" +"lib.mi.us\\n" +"cc.mn.us\\n" +"lib.mn.us\\n" +"cc.mo.us\\n" +"lib.mo.us\\n" +"cc.ms.us\\n" +"cc.mt.us\\n" +"lib.mt.us\\n" +"cc.nc.us\\n" +"lib.nc.us\\n" +"cc.ne.us\\n" +"lib.ne.us\\n" +"cc.nh.us\\n" +"lib.nh.us\\n" +"cc.nj.us\\n" +"lib.nj.us\\n" +"cc.nm.us\\n" +"lib.nm.us\\n" +"cc.nv.us\\n" +"lib.nv.us\\n" +"cc.ny.us\\n" +"lib.ny.us\\n" +"cc.oh.us\\n" +"lib.oh.us\\n" +"cc.ok.us\\n" +"lib.ok.us\\n" +"cc.or.us\\n" +"lib.or.us\\n" +"cc.pa.us\\n" +"lib.pa.us\\n" +"cc.pr.us\\n" +"lib.pr.us\\n" +"cc.ri.us\\n" +"lib.ri.us\\n" +"cc.sc.us\\n" +"lib.sc.us\\n" +"cc.sd.us\\n" +"lib.sd.us\\n" +"cc.tn.us\\n" +"lib.tn.us\\n" +"cc.tx.us\\n" +"lib.tx.us\\n" +"cc.ut.us\\n" +"lib.ut.us\\n" +"cc.va.us\\n" +"lib.va.us\\n" +"cc.vi.us\\n" +"lib.vi.us\\n" +"cc.vt.us\\n" +"lib.vt.us\\n" +"cc.wa.us\\n" +"lib.wa.us\\n" +"cc.wi.us\\n" +"lib.wi.us\\n" +"cc.wv.us\\n" +"cc.wy.us\\n" +"k12.wy.us\\n" +"lib.wy.us\\n" +"chtr.k12.ma.us\\n" +"paroch.k12.ma.us\\n" +"pvt.k12.ma.us\\n" +"ann-arbor.mi.us\\n" +"cog.mi.us\\n" +"dst.mi.us\\n" +"eaton.mi.us\\n" +"gen.mi.us\\n" +"mus.mi.us\\n" +"tec.mi.us\\n" +"washtenaw.mi.us\\n" +"com.uy\\n" +"edu.uy\\n" +"gub.uy\\n" +"mil.uy\\n" +"net.uy\\n" +"org.uy\\n" +"co.uz\\n" +"com.uz\\n" +"net.uz\\n" +"org.uz\\n" +"com.vc\\n" +"edu.vc\\n" +"gov.vc\\n" +"mil.vc\\n" +"net.vc\\n" +"org.vc\\n" +"arts.ve\\n" +"bib.ve\\n" +"co.ve\\n" +"com.ve\\n" +"e12.ve\\n" +"edu.ve\\n" +"emprende.ve\\n" +"firm.ve\\n" +"gob.ve\\n" +"gov.ve\\n" +"ia.ve\\n" +"info.ve\\n" +"int.ve\\n" +"mil.ve\\n" +"net.ve\\n" +"nom.ve\\n" +"org.ve\\n" +"rar.ve\\n" +"rec.ve\\n" +"store.ve\\n" +"tec.ve\\n" +"web.ve\\n" +"edu.vg\\n" +"co.vi\\n" +"com.vi\\n" +"k12.vi\\n" +"net.vi\\n" +"org.vi\\n" +"ac.vn\\n" +"ai.vn\\n" +"biz.vn\\n" +"com.vn\\n" +"edu.vn\\n" +"gov.vn\\n" +"health.vn\\n" +"id.vn\\n" +"info.vn\\n" +"int.vn\\n" +"io.vn\\n" +"name.vn\\n" +"net.vn\\n" +"org.vn\\n" +"pro.vn\\n" +"angiang.vn\\n" +"bacgiang.vn\\n" +"backan.vn\\n" +"baclieu.vn\\n" +"bacninh.vn\\n" +"baria-vungtau.vn\\n" +"bentre.vn\\n" +"binhdinh.vn\\n" +"binhduong.vn\\n" +"binhphuoc.vn\\n" +"binhthuan.vn\\n" +"camau.vn\\n" +"cantho.vn\\n" +"caobang.vn\\n" +"daklak.vn\\n" +"daknong.vn\\n" +"danang.vn\\n" +"dienbien.vn\\n" +"dongnai.vn\\n" +"dongthap.vn\\n" +"gialai.vn\\n" +"hagiang.vn\\n" +"haiduong.vn\\n" +"haiphong.vn\\n" +"hanam.vn\\n" +"hanoi.vn\\n" +"hatinh.vn\\n" +"haugiang.vn\\n" +"hoabinh.vn\\n" +"hue.vn\\n" +"hungyen.vn\\n" +"khanhhoa.vn\\n" +"kiengiang.vn\\n" +"kontum.vn\\n" +"laichau.vn\\n" +"lamdong.vn\\n" +"langson.vn\\n" +"laocai.vn\\n" +"longan.vn\\n" +"namdinh.vn\\n" +"nghean.vn\\n" +"ninhbinh.vn\\n" +"ninhthuan.vn\\n" +"phutho.vn\\n" +"phuyen.vn\\n" +"quangbinh.vn\\n" +"quangnam.vn\\n" +"quangngai.vn\\n" +"quangninh.vn\\n" +"quangtri.vn\\n" +"soctrang.vn\\n" +"sonla.vn\\n" +"tayninh.vn\\n" +"thaibinh.vn\\n" +"thainguyen.vn\\n" +"thanhhoa.vn\\n" +"thanhphohochiminh.vn\\n" +"thuathienhue.vn\\n" +"tiengiang.vn\\n" +"travinh.vn\\n" +"tuyenquang.vn\\n" +"vinhlong.vn\\n" +"vinhphuc.vn\\n" +"yenbai.vn\\n" +"com.vu\\n" +"edu.vu\\n" +"net.vu\\n" +"org.vu\\n" +"com.ws\\n" +"edu.ws\\n" +"gov.ws\\n" +"net.ws\\n" +"org.ws\\n" +"com.ye\\n" +"edu.ye\\n" +"gov.ye\\n" +"mil.ye\\n" +"net.ye\\n" +"org.ye\\n" +"ac.za\\n" +"agric.za\\n" +"alt.za\\n" +"co.za\\n" +"edu.za\\n" +"gov.za\\n" +"grondar.za\\n" +"law.za\\n" +"mil.za\\n" +"net.za\\n" +"ngo.za\\n" +"nic.za\\n" +"nis.za\\n" +"nom.za\\n" +"org.za\\n" +"school.za\\n" +"tm.za\\n" +"web.za\\n" +"ac.zm\\n" +"biz.zm\\n" +"co.zm\\n" +"com.zm\\n" +"edu.zm\\n" +"gov.zm\\n" +"info.zm\\n" +"mil.zm\\n" +"net.zm\\n" +"org.zm\\n" +"sch.zm\\n" +"ac.zw\\n" +"co.zw\\n" +"gov.zw\\n" +"mil.zw\\n" +"org.zw\\n" +"co.krd\\n" +"edu.krd\\n" +"art.pl\\n" +"gliwice.pl\\n" +"krakow.pl\\n" +"poznan.pl\\n" +"wroc.pl\\n" +"zakopane.pl\\n" +"cc.ua\\n" +"inf.ua\\n" +"ltd.ua\\n" +"611.to\\n" +"a2hosted.com\\n" +"cpserver.com\\n" +"activetrail.biz\\n" +"myaddr.dev\\n" +"myaddr.io\\n" +"dyn.addr.tools\\n" +"myaddr.tools\\n" +"adobeaemcloud.com\\n" +"aem.live\\n" +"hlx.live\\n" +"adobeaemcloud.net\\n" +"aem.network\\n" +"aem.page\\n" +"hlx.page\\n" +"aem.reviews\\n" +"adobeio-static.net\\n" +"adobeioruntime.net\\n" +"africa.com\\n" +"beep.pl\\n" +"aiven.app\\n" +"akadns.net\\n" +"akamai.net\\n" +"akamai-staging.net\\n" +"akamaiedge.net\\n" +"akamaiedge-staging.net\\n" +"akamaihd.net\\n" +"akamaihd-staging.net\\n" +"akamaiorigin.net\\n" +"akamaiorigin-staging.net\\n" +"akamaized.net\\n" +"akamaized-staging.net\\n" +"edgekey.net\\n" +"edgekey-staging.net\\n" +"edgesuite.net\\n" +"edgesuite-staging.net\\n" +"barsy.ca\\n" +"alibabacloudcs.com\\n" +"ms.fun\\n" +"ms.show\\n" +"kasserver.com\\n" +"altervista.org\\n" +"alwaysdata.net\\n" +"myamaze.net\\n" +"execute-api.cn-north-1.amazonaws.com.cn\\n" +"execute-api.cn-northwest-1.amazonaws.com.cn\\n" +"execute-api.af-south-1.amazonaws.com\\n" +"execute-api.ap-east-1.amazonaws.com\\n" +"execute-api.ap-northeast-1.amazonaws.com\\n" +"execute-api.ap-northeast-2.amazonaws.com\\n" +"execute-api.ap-northeast-3.amazonaws.com\\n" +"execute-api.ap-south-1.amazonaws.com\\n" +"execute-api.ap-south-2.amazonaws.com\\n" +"execute-api.ap-southeast-1.amazonaws.com\\n" +"execute-api.ap-southeast-2.amazonaws.com\\n" +"execute-api.ap-southeast-3.amazonaws.com\\n" +"execute-api.ap-southeast-4.amazonaws.com\\n" +"execute-api.ap-southeast-5.amazonaws.com\\n" +"execute-api.ca-central-1.amazonaws.com\\n" +"execute-api.ca-west-1.amazonaws.com\\n" +"execute-api.eu-central-1.amazonaws.com\\n" +"execute-api.eu-central-2.amazonaws.com\\n" +"execute-api.eu-north-1.amazonaws.com\\n" +"execute-api.eu-south-1.amazonaws.com\\n" +"execute-api.eu-south-2.amazonaws.com\\n" +"execute-api.eu-west-1.amazonaws.com\\n" +"execute-api.eu-west-2.amazonaws.com\\n" +"execute-api.eu-west-3.amazonaws.com\\n" +"execute-api.il-central-1.amazonaws.com\\n" +"execute-api.me-central-1.amazonaws.com\\n" +"execute-api.me-south-1.amazonaws.com\\n" +"execute-api.sa-east-1.amazonaws.com\\n" +"execute-api.us-east-1.amazonaws.com\\n" +"execute-api.us-east-2.amazonaws.com\\n" +"execute-api.us-gov-east-1.amazonaws.com\\n" +"execute-api.us-gov-west-1.amazonaws.com\\n" +"execute-api.us-west-1.amazonaws.com\\n" +"execute-api.us-west-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-northeast-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-northeast-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-south-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-south-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-southeast-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-southeast-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-southeast-5.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ap-southeast-7.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.ca-central-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-central-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-north-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-south-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-south-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-west-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-west-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.eu-west-3.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.sa-east-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.us-east-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.us-east-2.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.us-gov-west-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.us-west-1.amazonaws.com\\n" +"consent-portal.bedrock-agentcore.us-west-2.amazonaws.com\\n" +"cloudfront.net\\n" +"auth.af-south-1.amazoncognito.com\\n" +"auth.ap-east-1.amazoncognito.com\\n" +"auth.ap-east-2.amazoncognito.com\\n" +"auth.ap-northeast-1.amazoncognito.com\\n" +"auth.ap-northeast-2.amazoncognito.com\\n" +"auth.ap-northeast-3.amazoncognito.com\\n" +"auth.ap-south-1.amazoncognito.com\\n" +"auth.ap-south-2.amazoncognito.com\\n" +"auth.ap-southeast-1.amazoncognito.com\\n" +"auth.ap-southeast-2.amazoncognito.com\\n" +"auth.ap-southeast-3.amazoncognito.com\\n" +"auth.ap-southeast-4.amazoncognito.com\\n" +"auth.ap-southeast-5.amazoncognito.com\\n" +"auth.ap-southeast-6.amazoncognito.com\\n" +"auth.ap-southeast-7.amazoncognito.com\\n" +"auth.ca-central-1.amazoncognito.com\\n" +"auth.ca-west-1.amazoncognito.com\\n" +"auth.eu-central-1.amazoncognito.com\\n" +"auth.eu-central-2.amazoncognito.com\\n" +"auth.eu-north-1.amazoncognito.com\\n" +"auth.eu-south-1.amazoncognito.com\\n" +"auth.eu-south-2.amazoncognito.com\\n" +"auth.eu-west-1.amazoncognito.com\\n" +"auth.eu-west-2.amazoncognito.com\\n" +"auth.eu-west-3.amazoncognito.com\\n" +"auth.il-central-1.amazoncognito.com\\n" +"auth.me-central-1.amazoncognito.com\\n" +"auth.me-south-1.amazoncognito.com\\n" +"auth.mx-central-1.amazoncognito.com\\n" +"auth.sa-east-1.amazoncognito.com\\n" +"auth.us-east-1.amazoncognito.com\\n" +"auth-fips.us-east-1.amazoncognito.com\\n" +"auth.us-east-2.amazoncognito.com\\n" +"auth-fips.us-east-2.amazoncognito.com\\n" +"auth-fips.us-gov-east-1.amazoncognito.com\\n" +"auth-fips.us-gov-west-1.amazoncognito.com\\n" +"auth.us-west-1.amazoncognito.com\\n" +"auth-fips.us-west-1.amazoncognito.com\\n" +"auth.us-west-2.amazoncognito.com\\n" +"auth-fips.us-west-2.amazoncognito.com\\n" +"auth.cognito-idp.eusc-de-east-1.on.amazonwebservices.eu\\n" +"us-east-1.amazonaws.com\\n" +"emrappui-prod.cn-north-1.amazonaws.com.cn\\n" +"emrnotebooks-prod.cn-north-1.amazonaws.com.cn\\n" +"emrstudio-prod.cn-north-1.amazonaws.com.cn\\n" +"emrappui-prod.cn-northwest-1.amazonaws.com.cn\\n" +"emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn\\n" +"emrstudio-prod.cn-northwest-1.amazonaws.com.cn\\n" +"emrappui-prod.af-south-1.amazonaws.com\\n" +"emrnotebooks-prod.af-south-1.amazonaws.com\\n" +"emrstudio-prod.af-south-1.amazonaws.com\\n" +"emrappui-prod.ap-east-1.amazonaws.com\\n" +"emrnotebooks-prod.ap-east-1.amazonaws.com\\n" +"emrstudio-prod.ap-east-1.amazonaws.com\\n" +"emrappui-prod.ap-northeast-1.amazonaws.com\\n" +"emrnotebooks-prod.ap-northeast-1.amazonaws.com\\n" +"emrstudio-prod.ap-northeast-1.amazonaws.com\\n" +"emrappui-prod.ap-northeast-2.amazonaws.com\\n" +"emrnotebooks-prod.ap-northeast-2.amazonaws.com\\n" +"emrstudio-prod.ap-northeast-2.amazonaws.com\\n" +"emrappui-prod.ap-northeast-3.amazonaws.com\\n" +"emrnotebooks-prod.ap-northeast-3.amazonaws.com\\n" +"emrstudio-prod.ap-northeast-3.amazonaws.com\\n" +"emrappui-prod.ap-south-1.amazonaws.com\\n" +"emrnotebooks-prod.ap-south-1.amazonaws.com\\n" +"emrstudio-prod.ap-south-1.amazonaws.com\\n" +"emrappui-prod.ap-south-2.amazonaws.com\\n" +"emrnotebooks-prod.ap-south-2.amazonaws.com\\n" +"emrstudio-prod.ap-south-2.amazonaws.com\\n" +"emrappui-prod.ap-southeast-1.amazonaws.com\\n" +"emrnotebooks-prod.ap-southeast-1.amazonaws.com\\n" +"emrstudio-prod.ap-southeast-1.amazonaws.com\\n" +"emrappui-prod.ap-southeast-2.amazonaws.com\\n" +"emrnotebooks-prod.ap-southeast-2.amazonaws.com\\n" +"emrstudio-prod.ap-southeast-2.amazonaws.com\\n" +"emrappui-prod.ap-southeast-3.amazonaws.com\\n" +"emrnotebooks-prod.ap-southeast-3.amazonaws.com\\n" +"emrstudio-prod.ap-southeast-3.amazonaws.com\\n" +"emrappui-prod.ap-southeast-4.amazonaws.com\\n" +"emrnotebooks-prod.ap-southeast-4.amazonaws.com\\n" +"emrstudio-prod.ap-southeast-4.amazonaws.com\\n" +"emrappui-prod.ca-central-1.amazonaws.com\\n" +"emrnotebooks-prod.ca-central-1.amazonaws.com\\n" +"emrstudio-prod.ca-central-1.amazonaws.com\\n" +"emrappui-prod.ca-west-1.amazonaws.com\\n" +"emrnotebooks-prod.ca-west-1.amazonaws.com\\n" +"emrstudio-prod.ca-west-1.amazonaws.com\\n" +"emrappui-prod.eu-central-1.amazonaws.com\\n" +"emrnotebooks-prod.eu-central-1.amazonaws.com\\n" +"emrstudio-prod.eu-central-1.amazonaws.com\\n" +"emrappui-prod.eu-central-2.amazonaws.com\\n" +"emrnotebooks-prod.eu-central-2.amazonaws.com\\n" +"emrstudio-prod.eu-central-2.amazonaws.com\\n" +"emrappui-prod.eu-north-1.amazonaws.com\\n" +"emrnotebooks-prod.eu-north-1.amazonaws.com\\n" +"emrstudio-prod.eu-north-1.amazonaws.com\\n" +"emrappui-prod.eu-south-1.amazonaws.com\\n" +"emrnotebooks-prod.eu-south-1.amazonaws.com\\n" +"emrstudio-prod.eu-south-1.amazonaws.com\\n" +"emrappui-prod.eu-south-2.amazonaws.com\\n" +"emrnotebooks-prod.eu-south-2.amazonaws.com\\n" +"emrstudio-prod.eu-south-2.amazonaws.com\\n" +"emrappui-prod.eu-west-1.amazonaws.com\\n" +"emrnotebooks-prod.eu-west-1.amazonaws.com\\n" +"emrstudio-prod.eu-west-1.amazonaws.com\\n" +"emrappui-prod.eu-west-2.amazonaws.com\\n" +"emrnotebooks-prod.eu-west-2.amazonaws.com\\n" +"emrstudio-prod.eu-west-2.amazonaws.com\\n" +"emrappui-prod.eu-west-3.amazonaws.com\\n" +"emrnotebooks-prod.eu-west-3.amazonaws.com\\n" +"emrstudio-prod.eu-west-3.amazonaws.com\\n" +"emrappui-prod.il-central-1.amazonaws.com\\n" +"emrnotebooks-prod.il-central-1.amazonaws.com\\n" +"emrstudio-prod.il-central-1.amazonaws.com\\n" +"emrappui-prod.me-central-1.amazonaws.com\\n" +"emrnotebooks-prod.me-central-1.amazonaws.com\\n" +"emrstudio-prod.me-central-1.amazonaws.com\\n" +"emrappui-prod.me-south-1.amazonaws.com\\n" +"emrnotebooks-prod.me-south-1.amazonaws.com\\n" +"emrstudio-prod.me-south-1.amazonaws.com\\n" +"emrappui-prod.sa-east-1.amazonaws.com\\n" +"emrnotebooks-prod.sa-east-1.amazonaws.com\\n" +"emrstudio-prod.sa-east-1.amazonaws.com\\n" +"emrappui-prod.us-east-1.amazonaws.com\\n" +"emrnotebooks-prod.us-east-1.amazonaws.com\\n" +"emrstudio-prod.us-east-1.amazonaws.com\\n" +"emrappui-prod.us-east-2.amazonaws.com\\n" +"emrnotebooks-prod.us-east-2.amazonaws.com\\n" +"emrstudio-prod.us-east-2.amazonaws.com\\n" +"emrappui-prod.us-gov-east-1.amazonaws.com\\n" +"emrnotebooks-prod.us-gov-east-1.amazonaws.com\\n" +"emrstudio-prod.us-gov-east-1.amazonaws.com\\n" +"emrappui-prod.us-gov-west-1.amazonaws.com\\n" +"emrnotebooks-prod.us-gov-west-1.amazonaws.com\\n" +"emrstudio-prod.us-gov-west-1.amazonaws.com\\n" +"emrappui-prod.us-west-1.amazonaws.com\\n" +"emrnotebooks-prod.us-west-1.amazonaws.com\\n" +"emrstudio-prod.us-west-1.amazonaws.com\\n" +"emrappui-prod.us-west-2.amazonaws.com\\n" +"emrnotebooks-prod.us-west-2.amazonaws.com\\n" +"emrstudio-prod.us-west-2.amazonaws.com\\n" +"amazonlightsail.com\\n" +"s3.dualstack.cn-north-1.amazonaws.com.cn\\n" +"s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn\\n" +"s3-website.dualstack.cn-north-1.amazonaws.com.cn\\n" +"s3.cn-north-1.amazonaws.com.cn\\n" +"s3-accesspoint.cn-north-1.amazonaws.com.cn\\n" +"s3-deprecated.cn-north-1.amazonaws.com.cn\\n" +"s3-object-lambda.cn-north-1.amazonaws.com.cn\\n" +"s3-website.cn-north-1.amazonaws.com.cn\\n" +"s3.dualstack.cn-northwest-1.amazonaws.com.cn\\n" +"s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn\\n" +"s3.cn-northwest-1.amazonaws.com.cn\\n" +"s3-accesspoint.cn-northwest-1.amazonaws.com.cn\\n" +"s3-object-lambda.cn-northwest-1.amazonaws.com.cn\\n" +"s3-website.cn-northwest-1.amazonaws.com.cn\\n" +"s3.dualstack.af-south-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.af-south-1.amazonaws.com\\n" +"s3-website.dualstack.af-south-1.amazonaws.com\\n" +"s3.af-south-1.amazonaws.com\\n" +"s3-accesspoint.af-south-1.amazonaws.com\\n" +"s3-object-lambda.af-south-1.amazonaws.com\\n" +"s3-website.af-south-1.amazonaws.com\\n" +"s3.dualstack.ap-east-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-east-1.amazonaws.com\\n" +"s3.ap-east-1.amazonaws.com\\n" +"s3-accesspoint.ap-east-1.amazonaws.com\\n" +"s3-object-lambda.ap-east-1.amazonaws.com\\n" +"s3-website.ap-east-1.amazonaws.com\\n" +"s3.dualstack.ap-northeast-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com\\n" +"s3-website.dualstack.ap-northeast-1.amazonaws.com\\n" +"s3.ap-northeast-1.amazonaws.com\\n" +"s3-accesspoint.ap-northeast-1.amazonaws.com\\n" +"s3-object-lambda.ap-northeast-1.amazonaws.com\\n" +"s3-website.ap-northeast-1.amazonaws.com\\n" +"s3.dualstack.ap-northeast-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com\\n" +"s3-website.dualstack.ap-northeast-2.amazonaws.com\\n" +"s3.ap-northeast-2.amazonaws.com\\n" +"s3-accesspoint.ap-northeast-2.amazonaws.com\\n" +"s3-object-lambda.ap-northeast-2.amazonaws.com\\n" +"s3-website.ap-northeast-2.amazonaws.com\\n" +"s3.dualstack.ap-northeast-3.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com\\n" +"s3-website.dualstack.ap-northeast-3.amazonaws.com\\n" +"s3.ap-northeast-3.amazonaws.com\\n" +"s3-accesspoint.ap-northeast-3.amazonaws.com\\n" +"s3-object-lambda.ap-northeast-3.amazonaws.com\\n" +"s3-website.ap-northeast-3.amazonaws.com\\n" +"s3.dualstack.ap-south-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-south-1.amazonaws.com\\n" +"s3-website.dualstack.ap-south-1.amazonaws.com\\n" +"s3.ap-south-1.amazonaws.com\\n" +"s3-accesspoint.ap-south-1.amazonaws.com\\n" +"s3-object-lambda.ap-south-1.amazonaws.com\\n" +"s3-website.ap-south-1.amazonaws.com\\n" +"s3.dualstack.ap-south-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-south-2.amazonaws.com\\n" +"s3-website.dualstack.ap-south-2.amazonaws.com\\n" +"s3.ap-south-2.amazonaws.com\\n" +"s3-accesspoint.ap-south-2.amazonaws.com\\n" +"s3-object-lambda.ap-south-2.amazonaws.com\\n" +"s3-website.ap-south-2.amazonaws.com\\n" +"s3.dualstack.ap-southeast-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com\\n" +"s3-website.dualstack.ap-southeast-1.amazonaws.com\\n" +"s3.ap-southeast-1.amazonaws.com\\n" +"s3-accesspoint.ap-southeast-1.amazonaws.com\\n" +"s3-object-lambda.ap-southeast-1.amazonaws.com\\n" +"s3-website.ap-southeast-1.amazonaws.com\\n" +"s3.dualstack.ap-southeast-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com\\n" +"s3-website.dualstack.ap-southeast-2.amazonaws.com\\n" +"s3.ap-southeast-2.amazonaws.com\\n" +"s3-accesspoint.ap-southeast-2.amazonaws.com\\n" +"s3-object-lambda.ap-southeast-2.amazonaws.com\\n" +"s3-website.ap-southeast-2.amazonaws.com\\n" +"s3.dualstack.ap-southeast-3.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com\\n" +"s3-website.dualstack.ap-southeast-3.amazonaws.com\\n" +"s3.ap-southeast-3.amazonaws.com\\n" +"s3-accesspoint.ap-southeast-3.amazonaws.com\\n" +"s3-object-lambda.ap-southeast-3.amazonaws.com\\n" +"s3-website.ap-southeast-3.amazonaws.com\\n" +"s3.dualstack.ap-southeast-4.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com\\n" +"s3-website.dualstack.ap-southeast-4.amazonaws.com\\n" +"s3.ap-southeast-4.amazonaws.com\\n" +"s3-accesspoint.ap-southeast-4.amazonaws.com\\n" +"s3-object-lambda.ap-southeast-4.amazonaws.com\\n" +"s3-website.ap-southeast-4.amazonaws.com\\n" +"s3.dualstack.ap-southeast-5.amazonaws.com\\n" +"s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com\\n" +"s3-website.dualstack.ap-southeast-5.amazonaws.com\\n" +"s3.ap-southeast-5.amazonaws.com\\n" +"s3-accesspoint.ap-southeast-5.amazonaws.com\\n" +"s3-deprecated.ap-southeast-5.amazonaws.com\\n" +"s3-object-lambda.ap-southeast-5.amazonaws.com\\n" +"s3-website.ap-southeast-5.amazonaws.com\\n" +"s3.dualstack.ca-central-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ca-central-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com\\n" +"s3-fips.dualstack.ca-central-1.amazonaws.com\\n" +"s3-website.dualstack.ca-central-1.amazonaws.com\\n" +"s3.ca-central-1.amazonaws.com\\n" +"s3-accesspoint.ca-central-1.amazonaws.com\\n" +"s3-accesspoint-fips.ca-central-1.amazonaws.com\\n" +"s3-fips.ca-central-1.amazonaws.com\\n" +"s3-object-lambda.ca-central-1.amazonaws.com\\n" +"s3-website.ca-central-1.amazonaws.com\\n" +"s3.dualstack.ca-west-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.ca-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com\\n" +"s3-fips.dualstack.ca-west-1.amazonaws.com\\n" +"s3-website.dualstack.ca-west-1.amazonaws.com\\n" +"s3.ca-west-1.amazonaws.com\\n" +"s3-accesspoint.ca-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.ca-west-1.amazonaws.com\\n" +"s3-fips.ca-west-1.amazonaws.com\\n" +"s3-object-lambda.ca-west-1.amazonaws.com\\n" +"s3-website.ca-west-1.amazonaws.com\\n" +"s3.dualstack.eu-central-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-central-1.amazonaws.com\\n" +"s3-website.dualstack.eu-central-1.amazonaws.com\\n" +"s3.eu-central-1.amazonaws.com\\n" +"s3-accesspoint.eu-central-1.amazonaws.com\\n" +"s3-object-lambda.eu-central-1.amazonaws.com\\n" +"s3-website.eu-central-1.amazonaws.com\\n" +"s3.dualstack.eu-central-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-central-2.amazonaws.com\\n" +"s3-website.dualstack.eu-central-2.amazonaws.com\\n" +"s3.eu-central-2.amazonaws.com\\n" +"s3-accesspoint.eu-central-2.amazonaws.com\\n" +"s3-object-lambda.eu-central-2.amazonaws.com\\n" +"s3-website.eu-central-2.amazonaws.com\\n" +"s3.dualstack.eu-north-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-north-1.amazonaws.com\\n" +"s3.eu-north-1.amazonaws.com\\n" +"s3-accesspoint.eu-north-1.amazonaws.com\\n" +"s3-object-lambda.eu-north-1.amazonaws.com\\n" +"s3-website.eu-north-1.amazonaws.com\\n" +"s3.dualstack.eu-south-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-south-1.amazonaws.com\\n" +"s3-website.dualstack.eu-south-1.amazonaws.com\\n" +"s3.eu-south-1.amazonaws.com\\n" +"s3-accesspoint.eu-south-1.amazonaws.com\\n" +"s3-object-lambda.eu-south-1.amazonaws.com\\n" +"s3-website.eu-south-1.amazonaws.com\\n" +"s3.dualstack.eu-south-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-south-2.amazonaws.com\\n" +"s3-website.dualstack.eu-south-2.amazonaws.com\\n" +"s3.eu-south-2.amazonaws.com\\n" +"s3-accesspoint.eu-south-2.amazonaws.com\\n" +"s3-object-lambda.eu-south-2.amazonaws.com\\n" +"s3-website.eu-south-2.amazonaws.com\\n" +"s3.dualstack.eu-west-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-west-1.amazonaws.com\\n" +"s3-website.dualstack.eu-west-1.amazonaws.com\\n" +"s3.eu-west-1.amazonaws.com\\n" +"s3-accesspoint.eu-west-1.amazonaws.com\\n" +"s3-deprecated.eu-west-1.amazonaws.com\\n" +"s3-object-lambda.eu-west-1.amazonaws.com\\n" +"s3-website.eu-west-1.amazonaws.com\\n" +"s3.dualstack.eu-west-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-west-2.amazonaws.com\\n" +"s3.eu-west-2.amazonaws.com\\n" +"s3-accesspoint.eu-west-2.amazonaws.com\\n" +"s3-object-lambda.eu-west-2.amazonaws.com\\n" +"s3-website.eu-west-2.amazonaws.com\\n" +"s3.dualstack.eu-west-3.amazonaws.com\\n" +"s3-accesspoint.dualstack.eu-west-3.amazonaws.com\\n" +"s3-website.dualstack.eu-west-3.amazonaws.com\\n" +"s3.eu-west-3.amazonaws.com\\n" +"s3-accesspoint.eu-west-3.amazonaws.com\\n" +"s3-object-lambda.eu-west-3.amazonaws.com\\n" +"s3-website.eu-west-3.amazonaws.com\\n" +"s3.dualstack.il-central-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.il-central-1.amazonaws.com\\n" +"s3-website.dualstack.il-central-1.amazonaws.com\\n" +"s3.il-central-1.amazonaws.com\\n" +"s3-accesspoint.il-central-1.amazonaws.com\\n" +"s3-object-lambda.il-central-1.amazonaws.com\\n" +"s3-website.il-central-1.amazonaws.com\\n" +"s3.dualstack.me-central-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.me-central-1.amazonaws.com\\n" +"s3-website.dualstack.me-central-1.amazonaws.com\\n" +"s3.me-central-1.amazonaws.com\\n" +"s3-accesspoint.me-central-1.amazonaws.com\\n" +"s3-object-lambda.me-central-1.amazonaws.com\\n" +"s3-website.me-central-1.amazonaws.com\\n" +"s3.dualstack.me-south-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.me-south-1.amazonaws.com\\n" +"s3.me-south-1.amazonaws.com\\n" +"s3-accesspoint.me-south-1.amazonaws.com\\n" +"s3-object-lambda.me-south-1.amazonaws.com\\n" +"s3-website.me-south-1.amazonaws.com\\n" +"s3.amazonaws.com\\n" +"s3-1.amazonaws.com\\n" +"s3-ap-east-1.amazonaws.com\\n" +"s3-ap-northeast-1.amazonaws.com\\n" +"s3-ap-northeast-2.amazonaws.com\\n" +"s3-ap-northeast-3.amazonaws.com\\n" +"s3-ap-south-1.amazonaws.com\\n" +"s3-ap-southeast-1.amazonaws.com\\n" +"s3-ap-southeast-2.amazonaws.com\\n" +"s3-ca-central-1.amazonaws.com\\n" +"s3-eu-central-1.amazonaws.com\\n" +"s3-eu-north-1.amazonaws.com\\n" +"s3-eu-west-1.amazonaws.com\\n" +"s3-eu-west-2.amazonaws.com\\n" +"s3-eu-west-3.amazonaws.com\\n" +"s3-external-1.amazonaws.com\\n" +"s3-fips-us-gov-east-1.amazonaws.com\\n" +"s3-fips-us-gov-west-1.amazonaws.com\\n" +"mrap.accesspoint.s3-global.amazonaws.com\\n" +"s3-me-south-1.amazonaws.com\\n" +"s3-sa-east-1.amazonaws.com\\n" +"s3-us-east-2.amazonaws.com\\n" +"s3-us-gov-east-1.amazonaws.com\\n" +"s3-us-gov-west-1.amazonaws.com\\n" +"s3-us-west-1.amazonaws.com\\n" +"s3-us-west-2.amazonaws.com\\n" +"s3-website-ap-northeast-1.amazonaws.com\\n" +"s3-website-ap-southeast-1.amazonaws.com\\n" +"s3-website-ap-southeast-2.amazonaws.com\\n" +"s3-website-eu-west-1.amazonaws.com\\n" +"s3-website-sa-east-1.amazonaws.com\\n" +"s3-website-us-east-1.amazonaws.com\\n" +"s3-website-us-gov-west-1.amazonaws.com\\n" +"s3-website-us-west-1.amazonaws.com\\n" +"s3-website-us-west-2.amazonaws.com\\n" +"s3.dualstack.sa-east-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.sa-east-1.amazonaws.com\\n" +"s3-website.dualstack.sa-east-1.amazonaws.com\\n" +"s3.sa-east-1.amazonaws.com\\n" +"s3-accesspoint.sa-east-1.amazonaws.com\\n" +"s3-object-lambda.sa-east-1.amazonaws.com\\n" +"s3-website.sa-east-1.amazonaws.com\\n" +"s3.dualstack.us-east-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-east-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com\\n" +"s3-fips.dualstack.us-east-1.amazonaws.com\\n" +"s3-website.dualstack.us-east-1.amazonaws.com\\n" +"s3.us-east-1.amazonaws.com\\n" +"s3-accesspoint.us-east-1.amazonaws.com\\n" +"s3-accesspoint-fips.us-east-1.amazonaws.com\\n" +"s3-deprecated.us-east-1.amazonaws.com\\n" +"s3-fips.us-east-1.amazonaws.com\\n" +"s3-object-lambda.us-east-1.amazonaws.com\\n" +"s3-website.us-east-1.amazonaws.com\\n" +"s3.dualstack.us-east-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-east-2.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com\\n" +"s3-fips.dualstack.us-east-2.amazonaws.com\\n" +"s3-website.dualstack.us-east-2.amazonaws.com\\n" +"s3.us-east-2.amazonaws.com\\n" +"s3-accesspoint.us-east-2.amazonaws.com\\n" +"s3-accesspoint-fips.us-east-2.amazonaws.com\\n" +"s3-deprecated.us-east-2.amazonaws.com\\n" +"s3-fips.us-east-2.amazonaws.com\\n" +"s3-object-lambda.us-east-2.amazonaws.com\\n" +"s3-website.us-east-2.amazonaws.com\\n" +"s3.dualstack.us-gov-east-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com\\n" +"s3-fips.dualstack.us-gov-east-1.amazonaws.com\\n" +"s3-website.dualstack.us-gov-east-1.amazonaws.com\\n" +"s3.us-gov-east-1.amazonaws.com\\n" +"s3-accesspoint.us-gov-east-1.amazonaws.com\\n" +"s3-accesspoint-fips.us-gov-east-1.amazonaws.com\\n" +"s3-fips.us-gov-east-1.amazonaws.com\\n" +"s3-object-lambda.us-gov-east-1.amazonaws.com\\n" +"s3-website.us-gov-east-1.amazonaws.com\\n" +"s3.dualstack.us-gov-west-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com\\n" +"s3-fips.dualstack.us-gov-west-1.amazonaws.com\\n" +"s3-website.dualstack.us-gov-west-1.amazonaws.com\\n" +"s3.us-gov-west-1.amazonaws.com\\n" +"s3-accesspoint.us-gov-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.us-gov-west-1.amazonaws.com\\n" +"s3-fips.us-gov-west-1.amazonaws.com\\n" +"s3-object-lambda.us-gov-west-1.amazonaws.com\\n" +"s3-website.us-gov-west-1.amazonaws.com\\n" +"s3.dualstack.us-west-1.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com\\n" +"s3-fips.dualstack.us-west-1.amazonaws.com\\n" +"s3-website.dualstack.us-west-1.amazonaws.com\\n" +"s3.us-west-1.amazonaws.com\\n" +"s3-accesspoint.us-west-1.amazonaws.com\\n" +"s3-accesspoint-fips.us-west-1.amazonaws.com\\n" +"s3-fips.us-west-1.amazonaws.com\\n" +"s3-object-lambda.us-west-1.amazonaws.com\\n" +"s3-website.us-west-1.amazonaws.com\\n" +"s3.dualstack.us-west-2.amazonaws.com\\n" +"s3-accesspoint.dualstack.us-west-2.amazonaws.com\\n" +"s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com\\n" +"s3-fips.dualstack.us-west-2.amazonaws.com\\n" +"s3-website.dualstack.us-west-2.amazonaws.com\\n" +"s3.us-west-2.amazonaws.com\\n" +"s3-accesspoint.us-west-2.amazonaws.com\\n" +"s3-accesspoint-fips.us-west-2.amazonaws.com\\n" +"s3-deprecated.us-west-2.amazonaws.com\\n" +"s3-fips.us-west-2.amazonaws.com\\n" +"s3-object-lambda.us-west-2.amazonaws.com\\n" +"s3-website.us-west-2.amazonaws.com\\n" +"labeling.ap-northeast-1.sagemaker.aws\\n" +"labeling.ap-northeast-2.sagemaker.aws\\n" +"labeling.ap-south-1.sagemaker.aws\\n" +"labeling.ap-southeast-1.sagemaker.aws\\n" +"labeling.ap-southeast-2.sagemaker.aws\\n" +"labeling.ca-central-1.sagemaker.aws\\n" +"labeling.eu-central-1.sagemaker.aws\\n" +"labeling.eu-west-1.sagemaker.aws\\n" +"labeling.eu-west-2.sagemaker.aws\\n" +"labeling.us-east-1.sagemaker.aws\\n" +"labeling.us-east-2.sagemaker.aws\\n" +"labeling.us-west-2.sagemaker.aws\\n" +"notebook.af-south-1.sagemaker.aws\\n" +"notebook.ap-east-1.sagemaker.aws\\n" +"notebook.ap-northeast-1.sagemaker.aws\\n" +"notebook.ap-northeast-2.sagemaker.aws\\n" +"notebook.ap-northeast-3.sagemaker.aws\\n" +"notebook.ap-south-1.sagemaker.aws\\n" +"notebook.ap-south-2.sagemaker.aws\\n" +"notebook.ap-southeast-1.sagemaker.aws\\n" +"notebook.ap-southeast-2.sagemaker.aws\\n" +"notebook.ap-southeast-3.sagemaker.aws\\n" +"notebook.ap-southeast-4.sagemaker.aws\\n" +"notebook.ca-central-1.sagemaker.aws\\n" +"notebook-fips.ca-central-1.sagemaker.aws\\n" +"notebook.ca-west-1.sagemaker.aws\\n" +"notebook-fips.ca-west-1.sagemaker.aws\\n" +"notebook.eu-central-1.sagemaker.aws\\n" +"notebook.eu-central-2.sagemaker.aws\\n" +"notebook.eu-north-1.sagemaker.aws\\n" +"notebook.eu-south-1.sagemaker.aws\\n" +"notebook.eu-south-2.sagemaker.aws\\n" +"notebook.eu-west-1.sagemaker.aws\\n" +"notebook.eu-west-2.sagemaker.aws\\n" +"notebook.eu-west-3.sagemaker.aws\\n" +"notebook.il-central-1.sagemaker.aws\\n" +"notebook.me-central-1.sagemaker.aws\\n" +"notebook.me-south-1.sagemaker.aws\\n" +"notebook.sa-east-1.sagemaker.aws\\n" +"notebook.us-east-1.sagemaker.aws\\n" +"notebook-fips.us-east-1.sagemaker.aws\\n" +"notebook.us-east-2.sagemaker.aws\\n" +"notebook-fips.us-east-2.sagemaker.aws\\n" +"notebook.us-gov-east-1.sagemaker.aws\\n" +"notebook-fips.us-gov-east-1.sagemaker.aws\\n" +"notebook.us-gov-west-1.sagemaker.aws\\n" +"notebook-fips.us-gov-west-1.sagemaker.aws\\n" +"notebook.us-west-1.sagemaker.aws\\n" +"notebook-fips.us-west-1.sagemaker.aws\\n" +"notebook.us-west-2.sagemaker.aws\\n" +"notebook-fips.us-west-2.sagemaker.aws\\n" +"notebook.cn-north-1.sagemaker.com.cn\\n" +"notebook.cn-northwest-1.sagemaker.com.cn\\n" +"studio.af-south-1.sagemaker.aws\\n" +"studio.ap-east-1.sagemaker.aws\\n" +"studio.ap-northeast-1.sagemaker.aws\\n" +"studio.ap-northeast-2.sagemaker.aws\\n" +"studio.ap-northeast-3.sagemaker.aws\\n" +"studio.ap-south-1.sagemaker.aws\\n" +"studio.ap-southeast-1.sagemaker.aws\\n" +"studio.ap-southeast-2.sagemaker.aws\\n" +"studio.ap-southeast-3.sagemaker.aws\\n" +"studio.ca-central-1.sagemaker.aws\\n" +"studio.eu-central-1.sagemaker.aws\\n" +"studio.eu-central-2.sagemaker.aws\\n" +"studio.eu-north-1.sagemaker.aws\\n" +"studio.eu-south-1.sagemaker.aws\\n" +"studio.eu-south-2.sagemaker.aws\\n" +"studio.eu-west-1.sagemaker.aws\\n" +"studio.eu-west-2.sagemaker.aws\\n" +"studio.eu-west-3.sagemaker.aws\\n" +"studio.il-central-1.sagemaker.aws\\n" +"studio.me-central-1.sagemaker.aws\\n" +"studio.me-south-1.sagemaker.aws\\n" +"studio.sa-east-1.sagemaker.aws\\n" +"studio.us-east-1.sagemaker.aws\\n" +"studio.us-east-2.sagemaker.aws\\n" +"studio.us-gov-east-1.sagemaker.aws\\n" +"studio-fips.us-gov-east-1.sagemaker.aws\\n" +"studio.us-gov-west-1.sagemaker.aws\\n" +"studio-fips.us-gov-west-1.sagemaker.aws\\n" +"studio.us-west-1.sagemaker.aws\\n" +"studio.us-west-2.sagemaker.aws\\n" +"studio.cn-north-1.sagemaker.com.cn\\n" +"studio.cn-northwest-1.sagemaker.com.cn\\n" +"analytics-gateway.ap-northeast-1.amazonaws.com\\n" +"analytics-gateway.ap-northeast-2.amazonaws.com\\n" +"analytics-gateway.ap-south-1.amazonaws.com\\n" +"analytics-gateway.ap-southeast-1.amazonaws.com\\n" +"analytics-gateway.ap-southeast-2.amazonaws.com\\n" +"analytics-gateway.eu-central-1.amazonaws.com\\n" +"analytics-gateway.eu-west-1.amazonaws.com\\n" +"analytics-gateway.us-east-1.amazonaws.com\\n" +"analytics-gateway.us-east-2.amazonaws.com\\n" +"analytics-gateway.us-west-2.amazonaws.com\\n" +"amplifyapp.com\\n" +"webview-assets.aws-cloud9.af-south-1.amazonaws.com\\n" +"vfs.cloud9.af-south-1.amazonaws.com\\n" +"webview-assets.cloud9.af-south-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-east-1.amazonaws.com\\n" +"vfs.cloud9.ap-east-1.amazonaws.com\\n" +"webview-assets.cloud9.ap-east-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com\\n" +"vfs.cloud9.ap-northeast-1.amazonaws.com\\n" +"webview-assets.cloud9.ap-northeast-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com\\n" +"vfs.cloud9.ap-northeast-2.amazonaws.com\\n" +"webview-assets.cloud9.ap-northeast-2.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com\\n" +"vfs.cloud9.ap-northeast-3.amazonaws.com\\n" +"webview-assets.cloud9.ap-northeast-3.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-south-1.amazonaws.com\\n" +"vfs.cloud9.ap-south-1.amazonaws.com\\n" +"webview-assets.cloud9.ap-south-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com\\n" +"vfs.cloud9.ap-southeast-1.amazonaws.com\\n" +"webview-assets.cloud9.ap-southeast-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com\\n" +"vfs.cloud9.ap-southeast-2.amazonaws.com\\n" +"webview-assets.cloud9.ap-southeast-2.amazonaws.com\\n" +"webview-assets.aws-cloud9.ca-central-1.amazonaws.com\\n" +"vfs.cloud9.ca-central-1.amazonaws.com\\n" +"webview-assets.cloud9.ca-central-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-central-1.amazonaws.com\\n" +"vfs.cloud9.eu-central-1.amazonaws.com\\n" +"webview-assets.cloud9.eu-central-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-north-1.amazonaws.com\\n" +"vfs.cloud9.eu-north-1.amazonaws.com\\n" +"webview-assets.cloud9.eu-north-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-south-1.amazonaws.com\\n" +"vfs.cloud9.eu-south-1.amazonaws.com\\n" +"webview-assets.cloud9.eu-south-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-west-1.amazonaws.com\\n" +"vfs.cloud9.eu-west-1.amazonaws.com\\n" +"webview-assets.cloud9.eu-west-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-west-2.amazonaws.com\\n" +"vfs.cloud9.eu-west-2.amazonaws.com\\n" +"webview-assets.cloud9.eu-west-2.amazonaws.com\\n" +"webview-assets.aws-cloud9.eu-west-3.amazonaws.com\\n" +"vfs.cloud9.eu-west-3.amazonaws.com\\n" +"webview-assets.cloud9.eu-west-3.amazonaws.com\\n" +"webview-assets.aws-cloud9.il-central-1.amazonaws.com\\n" +"vfs.cloud9.il-central-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.me-south-1.amazonaws.com\\n" +"vfs.cloud9.me-south-1.amazonaws.com\\n" +"webview-assets.cloud9.me-south-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.sa-east-1.amazonaws.com\\n" +"vfs.cloud9.sa-east-1.amazonaws.com\\n" +"webview-assets.cloud9.sa-east-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.us-east-1.amazonaws.com\\n" +"vfs.cloud9.us-east-1.amazonaws.com\\n" +"webview-assets.cloud9.us-east-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.us-east-2.amazonaws.com\\n" +"vfs.cloud9.us-east-2.amazonaws.com\\n" +"webview-assets.cloud9.us-east-2.amazonaws.com\\n" +"webview-assets.aws-cloud9.us-west-1.amazonaws.com\\n" +"vfs.cloud9.us-west-1.amazonaws.com\\n" +"webview-assets.cloud9.us-west-1.amazonaws.com\\n" +"webview-assets.aws-cloud9.us-west-2.amazonaws.com\\n" +"vfs.cloud9.us-west-2.amazonaws.com\\n" +"webview-assets.cloud9.us-west-2.amazonaws.com\\n" +"awsapps.com\\n" +"cn-north-1.eb.amazonaws.com.cn\\n" +"cn-northwest-1.eb.amazonaws.com.cn\\n" +"elasticbeanstalk.com\\n" +"af-south-1.elasticbeanstalk.com\\n" +"ap-east-1.elasticbeanstalk.com\\n" +"ap-northeast-1.elasticbeanstalk.com\\n" +"ap-northeast-2.elasticbeanstalk.com\\n" +"ap-northeast-3.elasticbeanstalk.com\\n" +"ap-south-1.elasticbeanstalk.com\\n" +"ap-south-2.elasticbeanstalk.com\\n" +"ap-southeast-1.elasticbeanstalk.com\\n" +"ap-southeast-2.elasticbeanstalk.com\\n" +"ap-southeast-3.elasticbeanstalk.com\\n" +"ap-southeast-4.elasticbeanstalk.com\\n" +"ap-southeast-5.elasticbeanstalk.com\\n" +"ap-southeast-6.elasticbeanstalk.com\\n" +"ap-southeast-7.elasticbeanstalk.com\\n" +"ca-central-1.elasticbeanstalk.com\\n" +"ca-west-1.elasticbeanstalk.com\\n" +"eu-central-1.elasticbeanstalk.com\\n" +"eu-central-2.elasticbeanstalk.com\\n" +"eu-north-1.elasticbeanstalk.com\\n" +"eu-south-1.elasticbeanstalk.com\\n" +"eu-south-2.elasticbeanstalk.com\\n" +"eu-west-1.elasticbeanstalk.com\\n" +"eu-west-2.elasticbeanstalk.com\\n" +"eu-west-3.elasticbeanstalk.com\\n" +"il-central-1.elasticbeanstalk.com\\n" +"me-central-1.elasticbeanstalk.com\\n" +"me-south-1.elasticbeanstalk.com\\n" +"sa-east-1.elasticbeanstalk.com\\n" +"us-east-1.elasticbeanstalk.com\\n" +"us-east-2.elasticbeanstalk.com\\n" +"us-gov-east-1.elasticbeanstalk.com\\n" +"us-gov-west-1.elasticbeanstalk.com\\n" +"us-west-1.elasticbeanstalk.com\\n" +"us-west-2.elasticbeanstalk.com\\n" +"awsglobalaccelerator.com\\n" +"lambda-url.af-south-1.on.aws\\n" +"lambda-url.ap-east-1.on.aws\\n" +"lambda-url.ap-northeast-1.on.aws\\n" +"lambda-url.ap-northeast-2.on.aws\\n" +"lambda-url.ap-northeast-3.on.aws\\n" +"lambda-url.ap-south-1.on.aws\\n" +"lambda-url.ap-southeast-1.on.aws\\n" +"lambda-url.ap-southeast-2.on.aws\\n" +"lambda-url.ap-southeast-3.on.aws\\n" +"lambda-url.ca-central-1.on.aws\\n" +"lambda-url.eu-central-1.on.aws\\n" +"lambda-url.eu-north-1.on.aws\\n" +"lambda-url.eu-south-1.on.aws\\n" +"lambda-url.eu-west-1.on.aws\\n" +"lambda-url.eu-west-2.on.aws\\n" +"lambda-url.eu-west-3.on.aws\\n" +"lambda-url.me-south-1.on.aws\\n" +"lambda-url.sa-east-1.on.aws\\n" +"lambda-url.us-east-1.on.aws\\n" +"lambda-url.us-east-2.on.aws\\n" +"lambda-url.us-west-1.on.aws\\n" +"lambda-url.us-west-2.on.aws\\n" +"transfer-webapp.af-south-1.on.aws\\n" +"transfer-webapp.ap-east-1.on.aws\\n" +"transfer-webapp.ap-east-2.on.aws\\n" +"transfer-webapp.ap-northeast-1.on.aws\\n" +"transfer-webapp.ap-northeast-2.on.aws\\n" +"transfer-webapp.ap-northeast-3.on.aws\\n" +"transfer-webapp.ap-south-1.on.aws\\n" +"transfer-webapp.ap-south-2.on.aws\\n" +"transfer-webapp.ap-southeast-1.on.aws\\n" +"transfer-webapp.ap-southeast-2.on.aws\\n" +"transfer-webapp.ap-southeast-3.on.aws\\n" +"transfer-webapp.ap-southeast-4.on.aws\\n" +"transfer-webapp.ap-southeast-5.on.aws\\n" +"transfer-webapp.ap-southeast-6.on.aws\\n" +"transfer-webapp.ap-southeast-7.on.aws\\n" +"transfer-webapp.ca-central-1.on.aws\\n" +"transfer-webapp.ca-west-1.on.aws\\n" +"transfer-webapp.eu-central-1.on.aws\\n" +"transfer-webapp.eu-central-2.on.aws\\n" +"transfer-webapp.eu-north-1.on.aws\\n" +"transfer-webapp.eu-south-1.on.aws\\n" +"transfer-webapp.eu-south-2.on.aws\\n" +"transfer-webapp.eu-west-1.on.aws\\n" +"transfer-webapp.eu-west-2.on.aws\\n" +"transfer-webapp.eu-west-3.on.aws\\n" +"transfer-webapp.il-central-1.on.aws\\n" +"transfer-webapp.me-central-1.on.aws\\n" +"transfer-webapp.me-south-1.on.aws\\n" +"transfer-webapp.mx-central-1.on.aws\\n" +"transfer-webapp.sa-east-1.on.aws\\n" +"transfer-webapp.us-east-1.on.aws\\n" +"transfer-webapp.us-east-2.on.aws\\n" +"transfer-webapp.us-gov-east-1.on.aws\\n" +"transfer-webapp-fips.us-gov-east-1.on.aws\\n" +"transfer-webapp.us-gov-west-1.on.aws\\n" +"transfer-webapp-fips.us-gov-west-1.on.aws\\n" +"transfer-webapp.us-west-1.on.aws\\n" +"transfer-webapp.us-west-2.on.aws\\n" +"transfer-webapp.cn-north-1.on.amazonwebservices.com.cn\\n" +"transfer-webapp.cn-northwest-1.on.amazonwebservices.com.cn\\n" +"transfer-webapp.eusc-de-east-1.on.amazonwebservices.eu\\n" +"eero.online\\n" +"eero-stage.online\\n" +"opentunnel.xyz\\n" +"antagonist.cloud\\n" +"claude.app\\n" +"claudeusercontent.com\\n" +"frame.claudeusercontent.com\\n" +"apigee.io\\n" +"panel.dev\\n" +"siiites.com\\n" +"int.apple\\n" +"appspacehosted.com\\n" +"appspaceusercontent.com\\n" +"appudo.net\\n" +"appwrite.global\\n" +"appwrite.network\\n" +"on-aptible.com\\n" +"f5.si\\n" +"arvanedge.ir\\n" +"user.aseinet.ne.jp\\n" +"gv.vc\\n" +"d.gv.vc\\n" +"user.party.eus\\n" +"pimienta.org\\n" +"poivron.org\\n" +"potager.org\\n" +"sweetpepper.org\\n" +"myasustor.com\\n" +"cdn.prod.atlassian-dev.net\\n" +"myfritz.link\\n" +"myfritz.net\\n" +"ecommerce-shop.pl\\n" +"b-data.io\\n" +"balena-devices.com\\n" +"base.ec\\n" +"official.ec\\n" +"buyshop.jp\\n" +"fashionstore.jp\\n" +"handcrafted.jp\\n" +"kawaiishop.jp\\n" +"supersale.jp\\n" +"theshop.jp\\n" +"shopselect.net\\n" +"base.shop\\n" +"beagleboard.io\\n" +"bearblog.dev\\n" +"pages.gay\\n" +"bnr.la\\n" +"bitbucket.io\\n" +"blackbaudcdn.net\\n" +"of.je\\n" +"square.site\\n" +"bluebite.io\\n" +"boomla.net\\n" +"boutir.com\\n" +"boxfuse.io\\n" +"square7.ch\\n" +"bplaced.com\\n" +"bplaced.de\\n" +"square7.de\\n" +"bplaced.net\\n" +"square7.net\\n" +"brave.app\\n" +"brave.dev\\n" +"brave.io\\n" +"shop.brendly.ba\\n" +"shop.brendly.hr\\n" +"shop.brendly.rs\\n" +"browsersafetymark.io\\n" +"radio.am\\n" +"radio.fm\\n" +"cdn.bubble.io\\n" +"bubbleapps.io\\n" +"cafjs.com\\n" +"canva-apps.cn\\n" +"canva-code.cn\\n" +"my.canvasite.cn\\n" +"khsj.cn\\n" +"canva-apps.com\\n" +"canva-hosted-embed.com\\n" +"canvacode.com\\n" +"rice-labs.com\\n" +"canva.link\\n" +"canva.run\\n" +"my.canva.site\\n" +"drr.ac\\n" +"uwu.ai\\n" +"carrd.co\\n" +"crd.co\\n" +"ju.mp\\n" +"api.gov.uk\\n" +"cdn77-storage.com\\n" +"rsc.contentproxy9.cz\\n" +"r.cdn77.net\\n" +"cdn77-ssl.net\\n" +"c.cdn77.org\\n" +"rsc.cdn77.org\\n" +"ssl.origin.cdn77-secure.org\\n" +"za.bz\\n" +"br.com\\n" +"cn.com\\n" +"de.com\\n" +"eu.com\\n" +"jpn.com\\n" +"mex.com\\n" +"ru.com\\n" +"sa.com\\n" +"uk.com\\n" +"us.com\\n" +"za.com\\n" +"com.de\\n" +"gb.net\\n" +"hu.net\\n" +"jp.net\\n" +"se.net\\n" +"uk.net\\n" +"ae.org\\n" +"com.se\\n" +"cx.ua\\n" +"discourse.diy\\n" +"discourse.group\\n" +"discourse.team\\n" +"clerk.app\\n" +"clerkstage.app\\n" +"cleverapps.cc\\n" +"cleverapps.io\\n" +"cleverapps.tech\\n" +"clickrising.net\\n" +"cloudns.asia\\n" +"cloudns.be\\n" +"cloud-ip.biz\\n" +"cloudns.biz\\n" +"cloud-ip.cc\\n" +"cloudns.cc\\n" +"cloudns.ch\\n" +"cloudns.cl\\n" +"cloudns.club\\n" +"abrdns.com\\n" +"dnsabr.com\\n" +"ip-ddns.com\\n" +"cloudns.cx\\n" +"cloudns.eu\\n" +"cloudns.in\\n" +"cloudns.info\\n" +"ddns-ip.net\\n" +"dns-cloud.net\\n" +"dns-dynamic.net\\n" +"cloudns.nz\\n" +"cloudns.org\\n" +"ip-dynamic.org\\n" +"cloudns.ph\\n" +"cloudns.pro\\n" +"cloudns.pw\\n" +"cloudns.us\\n" +"c66.me\\n" +"cloud66.ws\\n" +"jdevcloud.com\\n" +"wpdevcloud.com\\n" +"cloudaccess.host\\n" +"freesite.host\\n" +"cloudaccess.net\\n" +"cloudbeesusercontent.io\\n" +"cloudflare.app\\n" +"cf-ipfs.com\\n" +"cloudflare-ipfs.com\\n" +"trycloudflare.com\\n" +"pages.dev\\n" +"r2.dev\\n" +"workers.dev\\n" +"cloudflare.net\\n" +"cdn.cloudflare.net\\n" +"cdn.cloudflareanycast.net\\n" +"cdn.cloudflarecn.net\\n" +"cdn.cloudflareglobal.net\\n" +"cust.cloudscale.ch\\n" +"objects.lpg.cloudscale.ch\\n" +"objects.rma.cloudscale.ch\\n" +"lpg.objectstorage.ch\\n" +"rma.objectstorage.ch\\n" +"wnext.app\\n" +"cnpy.gdn\\n" +"co.ca\\n" +"co.com\\n" +"sch.ac\\n" +"dev.cv\\n" +"store.cv\\n" +"codeberg.page\\n" +"codepen.app\\n" +"codepen.dev\\n" +"csb.app\\n" +"preview.csb.app\\n" +"co.nl\\n" +"co.no\\n" +"webhosting.be\\n" +"site.webhosting.be\\n" +"prvw.eu\\n" +"hosting-cluster.nl\\n" +"site.hosting-cluster.nl\\n" +"ctfcloud.net\\n" +"convex.app\\n" +"convex.cloud\\n" +"eu-west-1.convex.cloud\\n" +"us-east-1.convex.cloud\\n" +"convex.site\\n" +"eu-west-1.convex.site\\n" +"us-east-1.convex.site\\n" +"ac.ru\\n" +"edu.ru\\n" +"gov.ru\\n" +"int.ru\\n" +"mil.ru\\n" +"corespeed.app\\n" +"dyn.cosidns.de\\n" +"dnsupdater.de\\n" +"dynamisches-dns.de\\n" +"internet-dns.de\\n" +"l-o-g-i-n.de\\n" +"dynamic-dns.info\\n" +"feste-ip.net\\n" +"knx-server.net\\n" +"static-access.net\\n" +"craft.me\\n" +"realm.cz\\n" +"cfolks.pl\\n" +"cyon.link\\n" +"cyon.site\\n" +"biz.dk\\n" +"co.dk\\n" +"firm.dk\\n" +"reg.dk\\n" +"store.dk\\n" +"dyndns.dappnode.io\\n" +"builtwithdark.com\\n" +"darklang.io\\n" +"aws.databricksapps.com\\n" +"gcp.databricksapps.com\\n" +"aws-gov.databricksapps.us\\n" +"demo.datadetect.com\\n" +"instance.datadetect.com\\n" +"edgestack.me\\n" +"dattolocal.com\\n" +"dattorelay.com\\n" +"dattoweb.com\\n" +"mydatto.com\\n" +"dattolocal.net\\n" +"mydatto.net\\n" +"ddnss.de\\n" +"dyn.ddnss.de\\n" +"dyndns.ddnss.de\\n" +"dyn-ip24.de\\n" +"dyndns1.de\\n" +"home-webserver.de\\n" +"dyn.home-webserver.de\\n" +"myhome-server.de\\n" +"ddnss.org\\n" +"debian.net\\n" +"definima.io\\n" +"definima.net\\n" +"deno.dev\\n" +"deno-staging.dev\\n" +"deno.net\\n" +"sandbox.deno.net\\n" +"deployagent.com\\n" +"piebox.site\\n" +"deployagent.space\\n" +"dedyn.io\\n" +"deuxfleurs.eu\\n" +"deuxfleurs.page\\n" +"d6.ply.gg\\n" +"joinmc.link\\n" +"playit.plus\\n" +"with.playit.plus\\n" +"icp0.io\\n" +"icp1.io\\n" +"opencloud.me\\n" +"caffeine.site\\n" +"caffeine.xyz\\n" +"mybox.company\\n" +"intouch.email\\n" +"mybox.me\\n" +"mybox.page\\n" +"dfirma.pl\\n" +"dkonto.pl\\n" +"you2.pl\\n" +"ondigitalocean.app\\n" +"qzz.io\\n" +"us.kg\\n" +"xx.kg\\n" +"dpdns.org\\n" +"discordsays.com\\n" +"discordsez.com\\n" +"jozi.biz\\n" +"ccwu.cc\\n" +"cc.cd\\n" +"us.ci\\n" +"de5.net\\n" +"dnshome.at\\n" +"resolve.bar\\n" +"ddns.berlin\\n" +"dnshome.cloud\\n" +"ddnssec.de\\n" +"dnshome.de\\n" +"dyndnssec.de\\n" +"heimdns.de\\n" +"srvdns.de\\n" +"dnshome.eu\\n" +"dnshome.it\\n" +"dyn.now\\n" +"heimdns.online\\n" +"ddns.wtf\\n" +"online.th\\n" +"shop.th\\n" +"co.scot\\n" +"me.scot\\n" +"org.scot\\n" +"drayddns.com\\n" +"shoparena.pl\\n" +"dreamhosters.com\\n" +"durumis.com\\n" +"duckdns.org\\n" +"dy.fi\\n" +"tunk.org\\n" +"dyndns.biz\\n" +"for-better.biz\\n" +"for-more.biz\\n" +"for-some.biz\\n" +"for-the.biz\\n" +"selfip.biz\\n" +"webhop.biz\\n" +"ftpaccess.cc\\n" +"game-server.cc\\n" +"myphotos.cc\\n" +"scrapping.cc\\n" +"blogdns.com\\n" +"cechire.com\\n" +"dnsalias.com\\n" +"dnsdojo.com\\n" +"doesntexist.com\\n" +"dontexist.com\\n" +"doomdns.com\\n" +"dyn-o-saur.com\\n" +"dynalias.com\\n" +"dyndns-at-home.com\\n" +"dyndns-at-work.com\\n" +"dyndns-blog.com\\n" +"dyndns-free.com\\n" +"dyndns-home.com\\n" +"dyndns-ip.com\\n" +"dyndns-mail.com\\n" +"dyndns-office.com\\n" +"dyndns-pics.com\\n" +"dyndns-remote.com\\n" +"dyndns-server.com\\n" +"dyndns-web.com\\n" +"dyndns-wiki.com\\n" +"dyndns-work.com\\n" +"est-a-la-maison.com\\n" +"est-a-la-masion.com\\n" +"est-le-patron.com\\n" +"est-mon-blogueur.com\\n" +"from-ak.com\\n" +"from-al.com\\n" +"from-ar.com\\n" +"from-ca.com\\n" +"from-ct.com\\n" +"from-dc.com\\n" +"from-de.com\\n" +"from-fl.com\\n" +"from-ga.com\\n" +"from-hi.com\\n" +"from-ia.com\\n" +"from-id.com\\n" +"from-il.com\\n" +"from-in.com\\n" +"from-ks.com\\n" +"from-ky.com\\n" +"from-ma.com\\n" +"from-md.com\\n" +"from-mi.com\\n" +"from-mn.com\\n" +"from-mo.com\\n" +"from-ms.com\\n" +"from-mt.com\\n" +"from-nc.com\\n" +"from-nd.com\\n" +"from-ne.com\\n" +"from-nh.com\\n" +"from-nj.com\\n" +"from-nm.com\\n" +"from-nv.com\\n" +"from-oh.com\\n" +"from-ok.com\\n" +"from-or.com\\n" +"from-pa.com\\n" +"from-pr.com\\n" +"from-ri.com\\n" +"from-sc.com\\n" +"from-sd.com\\n" +"from-tn.com\\n" +"from-tx.com\\n" +"from-ut.com\\n" +"from-va.com\\n" +"from-vt.com\\n" +"from-wa.com\\n" +"from-wi.com\\n" +"from-wv.com\\n" +"from-wy.com\\n" +"getmyip.com\\n" +"gotdns.com\\n" +"hobby-site.com\\n" +"homelinux.com\\n" +"homeunix.com\\n" +"iamallama.com\\n" +"is-a-anarchist.com\\n" +"is-a-blogger.com\\n" +"is-a-bookkeeper.com\\n" +"is-a-bulls-fan.com\\n" +"is-a-caterer.com\\n" +"is-a-chef.com\\n" +"is-a-conservative.com\\n" +"is-a-cpa.com\\n" +"is-a-cubicle-slave.com\\n" +"is-a-democrat.com\\n" +"is-a-designer.com\\n" +"is-a-doctor.com\\n" +"is-a-financialadvisor.com\\n" +"is-a-geek.com\\n" +"is-a-green.com\\n" +"is-a-guru.com\\n" +"is-a-hard-worker.com\\n" +"is-a-hunter.com\\n" +"is-a-landscaper.com\\n" +"is-a-lawyer.com\\n" +"is-a-liberal.com\\n" +"is-a-libertarian.com\\n" +"is-a-llama.com\\n" +"is-a-musician.com\\n" +"is-a-nascarfan.com\\n" +"is-a-nurse.com\\n" +"is-a-painter.com\\n" +"is-a-personaltrainer.com\\n" +"is-a-photographer.com\\n" +"is-a-player.com\\n" +"is-a-republican.com\\n" +"is-a-rockstar.com\\n" +"is-a-socialist.com\\n" +"is-a-student.com\\n" +"is-a-teacher.com\\n" +"is-a-techie.com\\n" +"is-a-therapist.com\\n" +"is-an-accountant.com\\n" +"is-an-actor.com\\n" +"is-an-actress.com\\n" +"is-an-anarchist.com\\n" +"is-an-artist.com\\n" +"is-an-engineer.com\\n" +"is-an-entertainer.com\\n" +"is-certified.com\\n" +"is-gone.com\\n" +"is-into-anime.com\\n" +"is-into-cars.com\\n" +"is-into-cartoons.com\\n" +"is-into-games.com\\n" +"is-leet.com\\n" +"is-not-certified.com\\n" +"is-slick.com\\n" +"is-uberleet.com\\n" +"is-with-theband.com\\n" +"isa-geek.com\\n" +"isa-hockeynut.com\\n" +"issmarterthanyou.com\\n" +"likes-pie.com\\n" +"likescandy.com\\n" +"neat-url.com\\n" +"saves-the-whales.com\\n" +"selfip.com\\n" +"sells-for-less.com\\n" +"sells-for-u.com\\n" +"servebbs.com\\n" +"simple-url.com\\n" +"space-to-rent.com\\n" +"teaches-yoga.com\\n" +"writesthisblog.com\\n" +"ath.cx\\n" +"fuettertdasnetz.de\\n" +"isteingeek.de\\n" +"istmein.de\\n" +"lebtimnetz.de\\n" +"leitungsen.de\\n" +"traeumtgerade.de\\n" +"barrel-of-knowledge.info\\n" +"barrell-of-knowledge.info\\n" +"dyndns.info\\n" +"for-our.info\\n" +"groks-the.info\\n" +"groks-this.info\\n" +"here-for-more.info\\n" +"knowsitall.info\\n" +"selfip.info\\n" +"webhop.info\\n" +"forgot.her.name\\n" +"forgot.his.name\\n" +"at-band-camp.net\\n" +"blogdns.net\\n" +"broke-it.net\\n" +"buyshouses.net\\n" +"dnsalias.net\\n" +"dnsdojo.net\\n" +"does-it.net\\n" +"dontexist.net\\n" +"dynalias.net\\n" +"dynathome.net\\n" +"endofinternet.net\\n" +"from-az.net\\n" +"from-co.net\\n" +"from-la.net\\n" +"from-ny.net\\n" +"gets-it.net\\n" +"ham-radio-op.net\\n" +"homeftp.net\\n" +"homeip.net\\n" +"homelinux.net\\n" +"homeunix.net\\n" +"in-the-band.net\\n" +"is-a-chef.net\\n" +"is-a-geek.net\\n" +"isa-geek.net\\n" +"kicks-ass.net\\n" +"office-on-the.net\\n" +"podzone.net\\n" +"scrapper-site.net\\n" +"selfip.net\\n" +"sells-it.net\\n" +"servebbs.net\\n" +"serveftp.net\\n" +"thruhere.net\\n" +"webhop.net\\n" +"merseine.nu\\n" +"mine.nu\\n" +"shacknet.nu\\n" +"blogdns.org\\n" +"blogsite.org\\n" +"boldlygoingnowhere.org\\n" +"dnsalias.org\\n" +"dnsdojo.org\\n" +"doesntexist.org\\n" +"dontexist.org\\n" +"doomdns.org\\n" +"dvrdns.org\\n" +"dynalias.org\\n" +"dyndns.org\\n" +"go.dyndns.org\\n" +"home.dyndns.org\\n" +"endofinternet.org\\n" +"endoftheinternet.org\\n" +"from-me.org\\n" +"game-host.org\\n" +"gotdns.org\\n" +"hobby-site.org\\n" +"homedns.org\\n" +"homeftp.org\\n" +"homelinux.org\\n" +"homeunix.org\\n" +"is-a-bruinsfan.org\\n" +"is-a-candidate.org\\n" +"is-a-celticsfan.org\\n" +"is-a-chef.org\\n" +"is-a-geek.org\\n" +"is-a-knight.org\\n" +"is-a-linux-user.org\\n" +"is-a-patsfan.org\\n" +"is-a-soxfan.org\\n" +"is-found.org\\n" +"is-lost.org\\n" +"is-saved.org\\n" +"is-very-bad.org\\n" +"is-very-evil.org\\n" +"is-very-good.org\\n" +"is-very-nice.org\\n" +"is-very-sweet.org\\n" +"isa-geek.org\\n" +"kicks-ass.org\\n" +"misconfused.org\\n" +"podzone.org\\n" +"readmyblog.org\\n" +"selfip.org\\n" +"sellsyourhome.org\\n" +"servebbs.org\\n" +"serveftp.org\\n" +"servegame.org\\n" +"stuff-4-sale.org\\n" +"webhop.org\\n" +"better-than.tv\\n" +"dyndns.tv\\n" +"on-the-web.tv\\n" +"worse-than.tv\\n" +"is-by.us\\n" +"land-4-sale.us\\n" +"stuff-4-sale.us\\n" +"dyndns.ws\\n" +"mypets.ws\\n" +"1cooldns.com\\n" +"bumbleshrimp.com\\n" +"ddnsfree.com\\n" +"ddnsgeek.com\\n" +"ddnsguru.com\\n" +"dynuddns.com\\n" +"dynuhosting.com\\n" +"giize.com\\n" +"gleeze.com\\n" +"kozow.com\\n" +"loseyourip.com\\n" +"ooguy.com\\n" +"pivohosting.com\\n" +"theworkpc.com\\n" +"wiredbladehosting.com\\n" +"casacam.net\\n" +"dynu.net\\n" +"dynuddns.net\\n" +"mysynology.net\\n" +"opik.net\\n" +"spryt.net\\n" +"accesscam.org\\n" +"camdvr.org\\n" +"freeddns.org\\n" +"mywire.org\\n" +"roxa.org\\n" +"webredirect.org\\n" +"myddns.rocks\\n" +"dynv6.net\\n" +"e4.cz\\n" +"easypanel.app\\n" +"easypanel.host\\n" +"twmail.cc\\n" +"twmail.net\\n" +"twmail.org\\n" +"mymailer.com.tw\\n" +"url.tw\\n" +"at.emf.camp\\n" +"rt.ht\\n" +"elementor.cloud\\n" +"elementor.cool\\n" +"emergent.cloud\\n" +"preview.emergentagent.com\\n" +"emergent.host\\n" +"mytuleap.com\\n" +"tuleap-partners.com\\n" +"encr.app\\n" +"frontend.encr.app\\n" +"encoreapi.com\\n" +"lp.dev\\n" +"api.lp.dev\\n" +"objects.lp.dev\\n" +"eu.encoway.cloud\\n" +"eu.org\\n" +"al.eu.org\\n" +"asso.eu.org\\n" +"at.eu.org\\n" +"au.eu.org\\n" +"be.eu.org\\n" +"bg.eu.org\\n" +"ca.eu.org\\n" +"cd.eu.org\\n" +"ch.eu.org\\n" +"cn.eu.org\\n" +"cy.eu.org\\n" +"cz.eu.org\\n" +"de.eu.org\\n" +"dk.eu.org\\n" +"edu.eu.org\\n" +"ee.eu.org\\n" +"es.eu.org\\n" +"fi.eu.org\\n" +"fr.eu.org\\n" +"gr.eu.org\\n" +"hr.eu.org\\n" +"hu.eu.org\\n" +"ie.eu.org\\n" +"il.eu.org\\n" +"in.eu.org\\n" +"int.eu.org\\n" +"is.eu.org\\n" +"it.eu.org\\n" +"jp.eu.org\\n" +"kr.eu.org\\n" +"lt.eu.org\\n" +"lu.eu.org\\n" +"lv.eu.org\\n" +"me.eu.org\\n" +"mk.eu.org\\n" +"mt.eu.org\\n" +"my.eu.org\\n" +"net.eu.org\\n" +"ng.eu.org\\n" +"nl.eu.org\\n" +"no.eu.org\\n" +"nz.eu.org\\n" +"pl.eu.org\\n" +"pt.eu.org\\n" +"ro.eu.org\\n" +"ru.eu.org\\n" +"se.eu.org\\n" +"si.eu.org\\n" +"sk.eu.org\\n" +"tr.eu.org\\n" +"uk.eu.org\\n" +"us.eu.org\\n" +"eurodir.ru\\n" +"eu-1.evennode.com\\n" +"eu-2.evennode.com\\n" +"eu-3.evennode.com\\n" +"eu-4.evennode.com\\n" +"us-1.evennode.com\\n" +"us-2.evennode.com\\n" +"us-3.evennode.com\\n" +"us-4.evennode.com\\n" +"relay.evervault.app\\n" +"relay.evervault.dev\\n" +"exe.xyz\\n" +"expo.app\\n" +"on.expo.app\\n" +"staging.expo.app\\n" +"on.staging.expo.app\\n" +"fspages.org\\n" +"ru.net\\n" +"adygeya.ru\\n" +"bashkiria.ru\\n" +"bir.ru\\n" +"cbg.ru\\n" +"com.ru\\n" +"dagestan.ru\\n" +"grozny.ru\\n" +"kalmykia.ru\\n" +"kustanai.ru\\n" +"marine.ru\\n" +"mordovia.ru\\n" +"msk.ru\\n" +"mytis.ru\\n" +"nalchik.ru\\n" +"nov.ru\\n" +"pyatigorsk.ru\\n" +"spb.ru\\n" +"vladikavkaz.ru\\n" +"vladimir.ru\\n" +"abkhazia.su\\n" +"adygeya.su\\n" +"aktyubinsk.su\\n" +"arkhangelsk.su\\n" +"armenia.su\\n" +"ashgabad.su\\n" +"azerbaijan.su\\n" +"balashov.su\\n" +"bashkiria.su\\n" +"bryansk.su\\n" +"bukhara.su\\n" +"chimkent.su\\n" +"dagestan.su\\n" +"east-kazakhstan.su\\n" +"exnet.su\\n" +"georgia.su\\n" +"grozny.su\\n" +"ivanovo.su\\n" +"jambyl.su\\n" +"kalmykia.su\\n" +"kaluga.su\\n" +"karacol.su\\n" +"karaganda.su\\n" +"karelia.su\\n" +"khakassia.su\\n" +"krasnodar.su\\n" +"kurgan.su\\n" +"kustanai.su\\n" +"lenug.su\\n" +"mangyshlak.su\\n" +"mordovia.su\\n" +"msk.su\\n" +"murmansk.su\\n" +"nalchik.su\\n" +"navoi.su\\n" +"north-kazakhstan.su\\n" +"nov.su\\n" +"obninsk.su\\n" +"penza.su\\n" +"pokrovsk.su\\n" +"sochi.su\\n" +"spb.su\\n" +"tashkent.su\\n" +"termez.su\\n" +"togliatti.su\\n" +"troitsk.su\\n" +"tselinograd.su\\n" +"tula.su\\n" +"tuva.su\\n" +"vladikavkaz.su\\n" +"vladimir.su\\n" +"vologda.su\\n" +"channelsdvr.net\\n" +"u.channelsdvr.net\\n" +"edgecompute.app\\n" +"fastly-edge.com\\n" +"fastly-terrarium.com\\n" +"freetls.fastly.net\\n" +"map.fastly.net\\n" +"a.prod.fastly.net\\n" +"global.prod.fastly.net\\n" +"a.ssl.fastly.net\\n" +"b.ssl.fastly.net\\n" +"global.ssl.fastly.net\\n" +"fastlylb.net\\n" +"map.fastlylb.net\\n" +"fastvps-server.com\\n" +"fastvps.host\\n" +"myfast.host\\n" +"fastvps.site\\n" +"myfast.space\\n" +"conn.uk\\n" +"copro.uk\\n" +"hosp.uk\\n" +"fedorainfracloud.org\\n" +"fedorapeople.org\\n" +"cloud.fedoraproject.org\\n" +"app.os.fedoraproject.org\\n" +"app.os.stg.fedoraproject.org\\n" +"mydobiss.com\\n" +"fh-muenster.io\\n" +"payload.dev\\n" +"figma.site\\n" +"figma-gov.site\\n" +"preview.site\\n" +"filegear.me\\n" +"hosted-by-files.com\\n" +"firebaseapp.com\\n" +"fldrv.com\\n" +"on-fleek.app\\n" +"flutterflow.app\\n" +"sprites.app\\n" +"fly.dev\\n" +"e2b.app\\n" +"framer.ai\\n" +"framer.app\\n" +"framercanvas.com\\n" +"framer.media\\n" +"framer.photos\\n" +"framer.website\\n" +"framer.wiki\\n" +"freebox-os.com\\n" +"freeboxos.com\\n" +"fbx-os.fr\\n" +"fbxos.fr\\n" +"freebox-os.fr\\n" +"freeboxos.fr\\n" +"freedesktop.org\\n" +"freemyip.com\\n" +"wien.funkfeuer.at\\n" +"daemon.asia\\n" +"dix.asia\\n" +"mydns.bz\\n" +"0am.jp\\n" +"0g0.jp\\n" +"0j0.jp\\n" +"0t0.jp\\n" +"mydns.jp\\n" +"pgw.jp\\n" +"wjg.jp\\n" +"keyword-on.net\\n" +"live-on.net\\n" +"server-on.net\\n" +"mydns.tw\\n" +"mydns.vc\\n" +"futurehosting.at\\n" +"futuremailing.at\\n" +"gadget.app\\n" +"gadget.host\\n" +"campaign.gov.uk\\n" +"service.gov.uk\\n" +"independent-commission.uk\\n" +"independent-inquest.uk\\n" +"independent-inquiry.uk\\n" +"independent-panel.uk\\n" +"independent-review.uk\\n" +"public-inquiry.uk\\n" +"royal-commission.uk\\n" +"gehirn.ne.jp\\n" +"usercontent.jp\\n" +"gentapps.com\\n" +"gentlentapis.com\\n" +"cdn-edges.net\\n" +"gsj.bz\\n" +"gitbook.io\\n" +"github.app\\n" +"githubusercontent.com\\n" +"githubpreview.dev\\n" +"github.io\\n" +"gitlab.io\\n" +"gitpage.si\\n" +"glideos.app\\n" +"nog.community\\n" +"co.ro\\n" +"shop.ro\\n" +"lolipop.io\\n" +"angry.jp\\n" +"babyblue.jp\\n" +"babymilk.jp\\n" +"backdrop.jp\\n" +"bambina.jp\\n" +"bitter.jp\\n" +"blush.jp\\n" +"boo.jp\\n" +"boy.jp\\n" +"boyfriend.jp\\n" +"but.jp\\n" +"candypop.jp\\n" +"capoo.jp\\n" +"catfood.jp\\n" +"cheap.jp\\n" +"chicappa.jp\\n" +"chillout.jp\\n" +"chips.jp\\n" +"chowder.jp\\n" +"chu.jp\\n" +"ciao.jp\\n" +"cocotte.jp\\n" +"coolblog.jp\\n" +"cranky.jp\\n" +"cutegirl.jp\\n" +"daa.jp\\n" +"deca.jp\\n" +"deci.jp\\n" +"digick.jp\\n" +"egoism.jp\\n" +"fakefur.jp\\n" +"fem.jp\\n" +"flier.jp\\n" +"floppy.jp\\n" +"fool.jp\\n" +"frenchkiss.jp\\n" +"girlfriend.jp\\n" +"girly.jp\\n" +"gloomy.jp\\n" +"gonna.jp\\n" +"greater.jp\\n" +"hacca.jp\\n" +"heavy.jp\\n" +"her.jp\\n" +"hiho.jp\\n" +"hippy.jp\\n" +"holy.jp\\n" +"hungry.jp\\n" +"icurus.jp\\n" +"itigo.jp\\n" +"jellybean.jp\\n" +"kikirara.jp\\n" +"kill.jp\\n" +"kilo.jp\\n" +"kuron.jp\\n" +"littlestar.jp\\n" +"lolipopmc.jp\\n" +"lolitapunk.jp\\n" +"lomo.jp\\n" +"lovepop.jp\\n" +"lovesick.jp\\n" +"main.jp\\n" +"mods.jp\\n" +"mond.jp\\n" +"mongolian.jp\\n" +"moo.jp\\n" +"namaste.jp\\n" +"nikita.jp\\n" +"nobushi.jp\\n" +"noor.jp\\n" +"oops.jp\\n" +"parallel.jp\\n" +"parasite.jp\\n" +"pecori.jp\\n" +"peewee.jp\\n" +"penne.jp\\n" +"pepper.jp\\n" +"perma.jp\\n" +"pigboat.jp\\n" +"pinoko.jp\\n" +"punyu.jp\\n" +"pupu.jp\\n" +"pussycat.jp\\n" +"pya.jp\\n" +"raindrop.jp\\n" +"readymade.jp\\n" +"sadist.jp\\n" +"schoolbus.jp\\n" +"secret.jp\\n" +"staba.jp\\n" +"stripper.jp\\n" +"sub.jp\\n" +"sunnyday.jp\\n" +"thick.jp\\n" +"tonkotsu.jp\\n" +"under.jp\\n" +"upper.jp\\n" +"velvet.jp\\n" +"verse.jp\\n" +"versus.jp\\n" +"vivian.jp\\n" +"watson.jp\\n" +"weblike.jp\\n" +"whitesnow.jp\\n" +"zombie.jp\\n" +"heteml.net\\n" +"vibehost.space\\n" +"graphic.design\\n" +"goip.de\\n" +"web.app\\n" +"appspot.com\\n" +"blogspot.com\\n" +"codespot.com\\n" +"googleapis.com\\n" +"googlecode.com\\n" +"pagespeedmobilizer.com\\n" +"withgoogle.com\\n" +"withyoutube.com\\n" +"cloud.goog\\n" +"translate.goog\\n" +"cloudfunctions.net\\n" +"cloud.run\\n" +"ai.studio\\n" +"goupile.fr\\n" +"pymnt.uk\\n" +"gov.nl\\n" +"grafana-dev.net\\n" +"grayjayleagues.com\\n" +"grebedoc.dev\\n" +"gv.uy\\n" +"hackclub.app\\n" +"hashbang.sh\\n" +"hasura.app\\n" +"hasura-app.io\\n" +"hatenablog.com\\n" +"hatenadiary.com\\n" +"hateblo.jp\\n" +"hatenablog.jp\\n" +"hatenadiary.jp\\n" +"hatenadiary.org\\n" +"pages.it.hs-heilbronn.de\\n" +"pages-research.it.hs-heilbronn.de\\n" +"heiyu.space\\n" +"helioho.st\\n" +"heliohost.us\\n" +"hepforge.org\\n" +"onhercules.app\\n" +"hercules-app.com\\n" +"hercules-dev.com\\n" +"here.now\\n" +"herokuapp.com\\n" +"heyflow.page\\n" +"heyflow.site\\n" +"ravendb.cloud\\n" +"ravendb.community\\n" +"development.run\\n" +"ravendb.run\\n" +"hidns.co\\n" +"hidns.vip\\n" +"homesklep.pl\\n" +"seprox.hooc.me\\n" +"hoplix.shop\\n" +"orx.biz\\n" +"biz.ng\\n" +"co.biz.ng\\n" +"dl.biz.ng\\n" +"go.biz.ng\\n" +"lg.biz.ng\\n" +"on.biz.ng\\n" +"col.ng\\n" +"firm.ng\\n" +"gen.ng\\n" +"ltd.ng\\n" +"ngo.ng\\n" +"plc.ng\\n" +"hstgr.cloud\\n" +"hostyhosting.io\\n" +"hf.space\\n" +"static.hf.space\\n" +"hypernode.io\\n" +"iobb.net\\n" +"co.cz\\n" +"moonscale.net\\n" +"gr.com\\n" +"iki.fi\\n" +"ibxos.it\\n" +"iliadboxos.it\\n" +"imagine.diy\\n" +"imagine-proxy.work\\n" +"smushcdn.com\\n" +"wphostedmail.com\\n" +"wpmucdn.com\\n" +"tempurl.host\\n" +"wpmudev.host\\n" +"dyn-berlin.de\\n" +"in-berlin.de\\n" +"in-brb.de\\n" +"in-butter.de\\n" +"in-dsl.de\\n" +"in-vpn.de\\n" +"in-dsl.net\\n" +"in-vpn.net\\n" +"in-dsl.org\\n" +"in-vpn.org\\n" +"oninferno.net\\n" +"info.cx\\n" +"ac.leg.br\\n" +"al.leg.br\\n" +"am.leg.br\\n" +"ap.leg.br\\n" +"ba.leg.br\\n" +"ce.leg.br\\n" +"df.leg.br\\n" +"es.leg.br\\n" +"go.leg.br\\n" +"ma.leg.br\\n" +"mg.leg.br\\n" +"ms.leg.br\\n" +"mt.leg.br\\n" +"pa.leg.br\\n" +"pb.leg.br\\n" +"pe.leg.br\\n" +"pi.leg.br\\n" +"pr.leg.br\\n" +"rj.leg.br\\n" +"rn.leg.br\\n" +"ro.leg.br\\n" +"rr.leg.br\\n" +"rs.leg.br\\n" +"sc.leg.br\\n" +"se.leg.br\\n" +"sp.leg.br\\n" +"to.leg.br\\n" +"pixolino.com\\n" +"na4u.ru\\n" +"botdash.app\\n" +"botdash.dev\\n" +"botdash.gg\\n" +"botdash.net\\n" +"botda.sh\\n" +"botdash.xyz\\n" +"online-server.cloud\\n" +"apps-1and1.com\\n" +"live-website.com\\n" +"webspace-host.com\\n" +"apps-1and1.net\\n" +"websitebuilder.online\\n" +"app-ionos.space\\n" +"iopsys.se\\n" +"ipifony.net\\n" +"home64.de\\n" +"ipv64.de\\n" +"ipv64.net\\n" +"iqhs.pl\\n" +"ir.md\\n" +"is-a-good.dev\\n" +"iservschule.de\\n" +"mein-iserv.de\\n" +"schuldock.de\\n" +"schulplattform.de\\n" +"schulserver.de\\n" +"test-iserv.de\\n" +"iserv.dev\\n" +"iserv.host\\n" +"ispmanager.name\\n" +"mel.cloudlets.com.au\\n" +"cloud.interhostsolutions.be\\n" +"alp1.ae.flow.ch\\n" +"appengine.flow.ch\\n" +"es-1.axarnet.cloud\\n" +"diadem.cloud\\n" +"vip.jelastic.cloud\\n" +"jele.cloud\\n" +"it1.eur.aruba.jenv-aruba.cloud\\n" +"it1.jenv-aruba.cloud\\n" +"keliweb.cloud\\n" +"cs.keliweb.cloud\\n" +"oxa.cloud\\n" +"tn.oxa.cloud\\n" +"uk.oxa.cloud\\n" +"primetel.cloud\\n" +"uk.primetel.cloud\\n" +"ca.reclaim.cloud\\n" +"uk.reclaim.cloud\\n" +"us.reclaim.cloud\\n" +"ch.trendhosting.cloud\\n" +"de.trendhosting.cloud\\n" +"jele.club\\n" +"dopaas.com\\n" +"paas.hosted-by-previder.com\\n" +"rag-cloud.hosteur.com\\n" +"rag-cloud-ch.hosteur.com\\n" +"jcloud.ik-server.com\\n" +"jcloud-ver-jpc.ik-server.com\\n" +"demo.jelastic.com\\n" +"paas.massivegrid.com\\n" +"jed.wafaicloud.com\\n" +"ryd.wafaicloud.com\\n" +"j.scaleforce.com.cy\\n" +"jelastic.dogado.eu\\n" +"fi.cloudplatform.fi\\n" +"jele.host\\n" +"mircloud.host\\n" +"paas.beebyte.io\\n" +"sekd1.beebyteapp.io\\n" +"jele.io\\n" +"jc.neen.it\\n" +"jcloud.kz\\n" +"cloudjiffy.net\\n" +"fra1-de.cloudjiffy.net\\n" +"west1-us.cloudjiffy.net\\n" +"jls-sto1.elastx.net\\n" +"jls-sto2.elastx.net\\n" +"jls-sto3.elastx.net\\n" +"fr-1.paas.massivegrid.net\\n" +"lon-1.paas.massivegrid.net\\n" +"lon-2.paas.massivegrid.net\\n" +"ny-1.paas.massivegrid.net\\n" +"ny-2.paas.massivegrid.net\\n" +"sg-1.paas.massivegrid.net\\n" +"jelastic.saveincloud.net\\n" +"nordeste-idc.saveincloud.net\\n" +"j.scaleforce.net\\n" +"sdscloud.pl\\n" +"unicloud.pl\\n" +"mircloud.ru\\n" +"enscaled.sg\\n" +"jele.site\\n" +"jelastic.team\\n" +"orangecloud.tn\\n" +"j.layershift.co.uk\\n" +"phx.enscaled.us\\n" +"mircloud.us\\n" +"myjino.ru\\n" +"jote.cloud\\n" +"jotelulu.cloud\\n" +"eu1-plenit.com\\n" +"la1-plenit.com\\n" +"us1-plenit.com\\n" +"webadorsite.com\\n" +"jouwweb.site\\n" +"js.org\\n" +"elastic.k2.cloud\\n" +"lb.ru-msk.k2.cloud\\n" +"s3.ru-msk.k2.cloud\\n" +"website.ru-msk.k2.cloud\\n" +"lb.ru-spb.k2.cloud\\n" +"s3.ru-spb.k2.cloud\\n" +"website.ru-spb.k2.cloud\\n" +"s3.k2.cloud\\n" +"website.k2.cloud\\n" +"kaas.gg\\n" +"khplay.nl\\n" +"kapsi.fi\\n" +"kdns.fr\\n" +"ezproxy.kuleuven.be\\n" +"kuleuven.cloud\\n" +"keenetic.io\\n" +"keenetic.link\\n" +"keenetic.name\\n" +"keenetic.pro\\n" +"ae.kg\\n" +"keymachine.de\\n" +"kiloapps.ai\\n" +"kiloapps.io\\n" +"kinghost.net\\n" +"uni5.net\\n" +"koobin.events\\n" +"webthings.io\\n" +"krellian.net\\n" +"co.de\\n" +"shiptoday.app\\n" +"shiptoday.build\\n" +"laravel.cloud\\n" +"on-forge.com\\n" +"on-vapor.com\\n" +"git-repos.de\\n" +"lcube-server.de\\n" +"svn-repos.de\\n" +"leadpages.co\\n" +"lpages.co\\n" +"lpusercontent.com\\n" +"leapcell.app\\n" +"leapcell.dev\\n" +"leapcell.online\\n" +"liara.run\\n" +"iran.liara.run\\n" +"libp2p.direct\\n" +"runcontainers.dev\\n" +"co.business\\n" +"co.education\\n" +"co.events\\n" +"co.financial\\n" +"co.network\\n" +"co.place\\n" +"co.technology\\n" +"linkyard-cloud.ch\\n" +"linkyard.cloud\\n" +"members.linode.com\\n" +"ip.linodeusercontent.com\\n" +"we.bs\\n" +"filegear-sg.me\\n" +"ggff.net\\n" +"localtonet.com\\n" +"lodz.pl\\n" +"pabianice.pl\\n" +"plock.pl\\n" +"sieradz.pl\\n" +"skierniewice.pl\\n" +"zgierz.pl\\n" +"loginline.app\\n" +"loginline.dev\\n" +"loginline.io\\n" +"loginline.services\\n" +"loginline.site\\n" +"lohmus.me\\n" +"lovable.app\\n" +"lovableproject.com\\n" +"lovable.run\\n" +"lovable.sh\\n" +"krasnik.pl\\n" +"leczna.pl\\n" +"lubartow.pl\\n" +"lublin.pl\\n" +"poniatowa.pl\\n" +"swidnik.pl\\n" +"glug.org.uk\\n" +"lug.org.uk\\n" +"lugs.org.uk\\n" +"barsy.bg\\n" +"barsy.club\\n" +"barsycenter.com\\n" +"barsyonline.com\\n" +"barsy.de\\n" +"barsy.dev\\n" +"barsy.eu\\n" +"barsy.gr\\n" +"barsy.in\\n" +"barsy.info\\n" +"barsy.io\\n" +"barsy.me\\n" +"barsy.menu\\n" +"barsyonline.menu\\n" +"barsy.mobi\\n" +"barsy.net\\n" +"barsy.online\\n" +"barsy.org\\n" +"barsy.pro\\n" +"barsy.pub\\n" +"barsy.ro\\n" +"barsy.rs\\n" +"barsy.shop\\n" +"barsyonline.shop\\n" +"barsy.site\\n" +"barsy.store\\n" +"barsy.support\\n" +"barsy.uk\\n" +"barsy.co.uk\\n" +"barsyonline.co.uk\\n" +"luyani.app\\n" +"luyani.net\\n" +"magicpatterns.app\\n" +"magicpatternsapp.com\\n" +"hb.cldmail.ru\\n" +"matlab.cloud\\n" +"modelscape.com\\n" +"mwcloudnonprod.com\\n" +"polyspace.com\\n" +"mayfirst.info\\n" +"mcdir.me\\n" +"mcdir.ru\\n" +"vps.mcdir.ru\\n" +"mcpre.ru\\n" +"mediatech.by\\n" +"mediatech.dev\\n" +"hra.health\\n" +"medusajs.app\\n" +"miniserver.com\\n" +"memset.net\\n" +"messerli.app\\n" +"atmeta.com\\n" +"apps.fbsbx.com\\n" +"custom.metacentrum.cz\\n" +"flt.cloud.muni.cz\\n" +"usr.cloud.muni.cz\\n" +"meteorapp.com\\n" +"eu.meteorapp.com\\n" +"co.pl\\n" +"azure-api.net\\n" +"azure-mobile.net\\n" +"azureedge.net\\n" +"azurefd.net\\n" +"azurestaticapps.net\\n" +"1.azurestaticapps.net\\n" +"2.azurestaticapps.net\\n" +"3.azurestaticapps.net\\n" +"4.azurestaticapps.net\\n" +"5.azurestaticapps.net\\n" +"6.azurestaticapps.net\\n" +"7.azurestaticapps.net\\n" +"centralus.azurestaticapps.net\\n" +"eastasia.azurestaticapps.net\\n" +"eastus2.azurestaticapps.net\\n" +"westeurope.azurestaticapps.net\\n" +"westus2.azurestaticapps.net\\n" +"azurewebsites.net\\n" +"australiacentral-01.azurewebsites.net\\n" +"australiacentral2-01.azurewebsites.net\\n" +"australiaeast-01.azurewebsites.net\\n" +"australiasoutheast-01.azurewebsites.net\\n" +"austriaeast-01.azurewebsites.net\\n" +"belgiumcentral-01.azurewebsites.net\\n" +"brazilsouth-01.azurewebsites.net\\n" +"brazilsoutheast-01.azurewebsites.net\\n" +"canadacentral-01.azurewebsites.net\\n" +"canadaeast-01.azurewebsites.net\\n" +"centralindia-01.azurewebsites.net\\n" +"centralus-01.azurewebsites.net\\n" +"centraluseuap-01.azurewebsites.net\\n" +"chilecentral-01.azurewebsites.net\\n" +"denmarkeast-01.azurewebsites.net\\n" +"eastasia-01.azurewebsites.net\\n" +"eastasiastage-01.azurewebsites.net\\n" +"eastus-01.azurewebsites.net\\n" +"eastus2-01.azurewebsites.net\\n" +"eastus2euap-01.azurewebsites.net\\n" +"eastus3-01.azurewebsites.net\\n" +"francecentral-01.azurewebsites.net\\n" +"francesouth-01.azurewebsites.net\\n" +"germanynorth-01.azurewebsites.net\\n" +"germanywestcentral-01.azurewebsites.net\\n" +"indiasouthcentral-01.azurewebsites.net\\n" +"indonesiacentral-01.azurewebsites.net\\n" +"israelcentral-01.azurewebsites.net\\n" +"israelnorthwest-01.azurewebsites.net\\n" +"italynorth-01.azurewebsites.net\\n" +"japaneast-01.azurewebsites.net\\n" +"japanwest-01.azurewebsites.net\\n" +"jioindiacentral-01.azurewebsites.net\\n" +"jioindiawest-01.azurewebsites.net\\n" +"koreacentral-01.azurewebsites.net\\n" +"koreasouth-01.azurewebsites.net\\n" +"malaysiawest-01.azurewebsites.net\\n" +"mexicocentral-01.azurewebsites.net\\n" +"newzealandnorth-01.azurewebsites.net\\n" +"northcentralus-01.azurewebsites.net\\n" +"northcentralusstage-01.azurewebsites.net\\n" +"northeastus5-01.azurewebsites.net\\n" +"northeurope-01.azurewebsites.net\\n" +"norwayeast-01.azurewebsites.net\\n" +"norwaywest-01.azurewebsites.net\\n" +"polandcentral-01.azurewebsites.net\\n" +"qatarcentral-01.azurewebsites.net\\n" +"southafricanorth-01.azurewebsites.net\\n" +"southafricawest-01.azurewebsites.net\\n" +"southcentralus-01.azurewebsites.net\\n" +"southcentralus2-01.azurewebsites.net\\n" +"southeastasia-01.azurewebsites.net\\n" +"southeastus5-01.azurewebsites.net\\n" +"southindia-01.azurewebsites.net\\n" +"spaincentral-01.azurewebsites.net\\n" +"swedencentral-01.azurewebsites.net\\n" +"swedensouth-01.azurewebsites.net\\n" +"switzerlandnorth-01.azurewebsites.net\\n" +"switzerlandwest-01.azurewebsites.net\\n" +"taiwannorth-01.azurewebsites.net\\n" +"taiwannorthwest-01.azurewebsites.net\\n" +"uaecentral-01.azurewebsites.net\\n" +"uaenorth-01.azurewebsites.net\\n" +"uksouth-01.azurewebsites.net\\n" +"ukwest-01.azurewebsites.net\\n" +"westcentralus-01.azurewebsites.net\\n" +"westeurope-01.azurewebsites.net\\n" +"westindia-01.azurewebsites.net\\n" +"westus-01.azurewebsites.net\\n" +"westus2-01.azurewebsites.net\\n" +"westus3-01.azurewebsites.net\\n" +"cloudapp.net\\n" +"trafficmanager.net\\n" +"blob.core.usgovcloudapi.net\\n" +"file.core.usgovcloudapi.net\\n" +"web.core.usgovcloudapi.net\\n" +"servicebus.usgovcloudapi.net\\n" +"usgovcloudapp.net\\n" +"usgovtrafficmanager.net\\n" +"blob.core.windows.net\\n" +"file.core.windows.net\\n" +"web.core.windows.net\\n" +"servicebus.windows.net\\n" +"azure-api.us\\n" +"azurewebsites.us\\n" +"routingthecloud.com\\n" +"sn.mynetname.net\\n" +"routingthecloud.net\\n" +"routingthecloud.org\\n" +"same-app.com\\n" +"same-preview.com\\n" +"csx.cc\\n" +"miren.app\\n" +"miren.systems\\n" +"mydbserver.com\\n" +"webspaceconfig.de\\n" +"mittwald.info\\n" +"mittwaldserver.info\\n" +"typo3server.info\\n" +"project.space\\n" +"mkm.fan\\n" +"mocha.app\\n" +"mochausercontent.com\\n" +"mocha-sandbox.dev\\n" +"modx.dev\\n" +"bmoattachments.org\\n" +"net.ru\\n" +"org.ru\\n" +"pp.ru\\n" +"my.be\\n" +"hostedpi.com\\n" +"caracal.mythic-beasts.com\\n" +"customer.mythic-beasts.com\\n" +"fentiger.mythic-beasts.com\\n" +"lynx.mythic-beasts.com\\n" +"ocelot.mythic-beasts.com\\n" +"oncilla.mythic-beasts.com\\n" +"onza.mythic-beasts.com\\n" +"sphinx.mythic-beasts.com\\n" +"vs.mythic-beasts.com\\n" +"x.mythic-beasts.com\\n" +"yali.mythic-beasts.com\\n" +"cust.retrosnub.co.uk\\n" +"ui.nabu.casa\\n" +"kr.object.fin-ncloudstorage.com\\n" +"s3-website.kr.object.fin-ncloudstorage.com\\n" +"kr.object.private.fin-ncloudstorage.com\\n" +"kr.gov-ncloudstorage.com\\n" +"kr-private.gov-ncloudstorage.com\\n" +"kr.object.gov-ncloudstorage.com\\n" +"s3-website.kr.object.gov-ncloudstorage.com\\n" +"krs.object.gov-ncloudstorage.com\\n" +"s3-website.krs.object.gov-ncloudstorage.com\\n" +"kr.object.private.gov-ncloudstorage.com\\n" +"krs.object.private.gov-ncloudstorage.com\\n" +"kr.objectstorage.ncloud.com\\n" +"sg.objectstorage.ncloud.com\\n" +"kr.ncloudstorage.com\\n" +"kr-naver.ncloudstorage.com\\n" +"kr-naver-dev.ncloudstorage.com\\n" +"kr-private.ncloudstorage.com\\n" +"de.object.ncloudstorage.com\\n" +"s3-website.de.object.ncloudstorage.com\\n" +"kr.object.ncloudstorage.com\\n" +"s3-website.kr.object.ncloudstorage.com\\n" +"sg.object.ncloudstorage.com\\n" +"s3-website.sg.object.ncloudstorage.com\\n" +"us.object.ncloudstorage.com\\n" +"s3-website.us.object.ncloudstorage.com\\n" +"kr.object.private.ncloudstorage.com\\n" +"sg.object.private.ncloudstorage.com\\n" +"kr.website.ncloudstorage.com\\n" +"kr-naver.website.ncloudstorage.com\\n" +"kr-naver-dev.website.ncloudstorage.com\\n" +"jp.object.ncpstorage.com\\n" +"jp.jp4.object.ncpstorage.com\\n" +"jp.jp5.object.ncpstorage.com\\n" +"kr.object.ncpstorage.com\\n" +"s3-website-jp.object.ncpstorage.com\\n" +"jp.object.private.ncpstorage.com\\n" +"jp.jp4.object.private.ncpstorage.com\\n" +"jp.jp5.object.private.ncpstorage.com\\n" +"kr.object.private.ncpstorage.com\\n" +"needle.run\\n" +"co.site\\n" +"cloud.nospamproxy.com\\n" +"o365.cloud.nospamproxy.com\\n" +"netlib.re\\n" +"netlify.app\\n" +"4u.com\\n" +"nfshost.com\\n" +"ipfs.nftstorage.link\\n" +"ngo.us\\n" +"ngrok.app\\n" +"ngrok-free.app\\n" +"ngrok.dev\\n" +"ngrok-free.dev\\n" +"ngrok.io\\n" +"ap.ngrok.io\\n" +"au.ngrok.io\\n" +"eu.ngrok.io\\n" +"in.ngrok.io\\n" +"jp.ngrok.io\\n" +"sa.ngrok.io\\n" +"us.ngrok.io\\n" +"ngrok.pizza\\n" +"ngrok.pro\\n" +"torun.pl\\n" +"nh-serv.co.uk\\n" +"nimsite.uk\\n" +"mmafan.biz\\n" +"myftp.biz\\n" +"no-ip.biz\\n" +"no-ip.ca\\n" +"fantasyleague.cc\\n" +"gotdns.ch\\n" +"3utilities.com\\n" +"blogsyte.com\\n" +"ciscofreak.com\\n" +"damnserver.com\\n" +"ddnsking.com\\n" +"ditchyourip.com\\n" +"dnsiskinky.com\\n" +"dynns.com\\n" +"geekgalaxy.com\\n" +"health-carereform.com\\n" +"homesecuritymac.com\\n" +"homesecuritypc.com\\n" +"myactivedirectory.com\\n" +"mysecuritycamera.com\\n" +"myvnc.com\\n" +"net-freaks.com\\n" +"onthewifi.com\\n" +"point2this.com\\n" +"quicksytes.com\\n" +"securitytactics.com\\n" +"servebeer.com\\n" +"servecounterstrike.com\\n" +"serveexchange.com\\n" +"serveftp.com\\n" +"servegame.com\\n" +"servehalflife.com\\n" +"servehttp.com\\n" +"servehumour.com\\n" +"serveirc.com\\n" +"servemp3.com\\n" +"servep2p.com\\n" +"servepics.com\\n" +"servequake.com\\n" +"servesarcasm.com\\n" +"stufftoread.com\\n" +"unusualperson.com\\n" +"workisboring.com\\n" +"dvrcam.info\\n" +"ilovecollege.info\\n" +"no-ip.info\\n" +"brasilia.me\\n" +"ddns.me\\n" +"dnsfor.me\\n" +"hopto.me\\n" +"loginto.me\\n" +"noip.me\\n" +"webhop.me\\n" +"bounceme.net\\n" +"ddns.net\\n" +"eating-organic.net\\n" +"mydissent.net\\n" +"myeffect.net\\n" +"mymediapc.net\\n" +"mypsx.net\\n" +"mysecuritycamera.net\\n" +"nhlfan.net\\n" +"no-ip.net\\n" +"pgafan.net\\n" +"privatizehealthinsurance.net\\n" +"redirectme.net\\n" +"serveblog.net\\n" +"serveminecraft.net\\n" +"sytes.net\\n" +"cable-modem.org\\n" +"collegefan.org\\n" +"couchpotatofries.org\\n" +"hopto.org\\n" +"mlbfan.org\\n" +"myftp.org\\n" +"mysecuritycamera.org\\n" +"nflfan.org\\n" +"no-ip.org\\n" +"read-books.org\\n" +"ufcfan.org\\n" +"zapto.org\\n" +"no-ip.co.uk\\n" +"golffan.us\\n" +"noip.us\\n" +"pointto.us\\n" +"stage.nodeart.io\\n" +"noop.app\\n" +"aberdeen.wa.us\\n" +"bainbridge-isl.wa.us\\n" +"bellevue.wa.us\\n" +"bremerton.wa.us\\n" +"centralia.wa.us\\n" +"chehalis.wa.us\\n" +"forks.wa.us\\n" +"gig-harbor.wa.us\\n" +"hoquiam.wa.us\\n" +"keyport.wa.us\\n" +"kingston.wa.us\\n" +"olympia.wa.us\\n" +"port-angeles.wa.us\\n" +"port-ludlow.wa.us\\n" +"port-orchard.wa.us\\n" +"port-townsend.wa.us\\n" +"poulsbo.wa.us\\n" +"redmond.wa.us\\n" +"renton.wa.us\\n" +"sea.wa.us\\n" +"seattle.wa.us\\n" +"sequim.wa.us\\n" +"shelton.wa.us\\n" +"silverdale.wa.us\\n" +"yarrow-point.wa.us\\n" +"noticeable.news\\n" +"notion.site\\n" +"dnsking.ch\\n" +"mypi.co\\n" +"myiphost.com\\n" +"forumz.info\\n" +"soundcast.me\\n" +"tcp4.me\\n" +"dnsup.net\\n" +"hicam.net\\n" +"now-dns.net\\n" +"ownip.net\\n" +"vpndns.net\\n" +"dynserv.org\\n" +"now-dns.org\\n" +"x443.pw\\n" +"ntdll.top\\n" +"freeddns.us\\n" +"nsupdate.info\\n" +"nerdpol.ovh\\n" +"prvcy.page\\n" +"observablehq.cloud\\n" +"static.observableusercontent.com\\n" +"omg.lol\\n" +"cloudycluster.net\\n" +"omniwe.site\\n" +"123webseite.at\\n" +"123website.be\\n" +"simplesite.com.br\\n" +"123website.ch\\n" +"simplesite.com\\n" +"123webseite.de\\n" +"123hjemmeside.dk\\n" +"123miweb.es\\n" +"123kotisivu.fi\\n" +"123siteweb.fr\\n" +"simplesite.gr\\n" +"123homepage.it\\n" +"123website.lu\\n" +"123website.nl\\n" +"123hjemmeside.no\\n" +"service.one\\n" +"website.one\\n" +"simplesite.pl\\n" +"123paginaweb.pt\\n" +"123minsida.se\\n" +"onid.ca\\n" +"is-a-fullstack.dev\\n" +"is-cool.dev\\n" +"is-not-a.dev\\n" +"localplayer.dev\\n" +"is-local.org\\n" +"opensocial.site\\n" +"chatgpt.site\\n" +"opencraft.hosting\\n" +"16-b.it\\n" +"32-b.it\\n" +"64-b.it\\n" +"orsites.com\\n" +"operaunite.com\\n" +"tech.orange\\n" +"can.re\\n" +"authgear-staging.com\\n" +"authgearapps.com\\n" +"outsystemscloud.com\\n" +"ownprovider.com\\n" +"own.pm\\n" +"ox.rs\\n" +"oy.lc\\n" +"pgfog.com\\n" +"gotpantheon.com\\n" +"pantheonsite.io\\n" +"xmit.dev\\n" +"madethis.site\\n" +"srv.us\\n" +"gh.srv.us\\n" +"gl.srv.us\\n" +"mypep.link\\n" +"pplx.app\\n" +"forgeblocks.com\\n" +"id.forgerock.io\\n" +"support.site\\n" +"on-web.fr\\n" +"upsunapp.com\\n" +"ent.platform.sh\\n" +"eu.platform.sh\\n" +"us.platform.sh\\n" +"playcode.site\\n" +"pley.games\\n" +"onporter.run\\n" +"co.bn\\n" +"postman-echo.com\\n" +"pstmn.io\\n" +"mock.pstmn.io\\n" +"httpbin.org\\n" +"prequalifyme.today\\n" +"xen.prgmr.com\\n" +"priv.at\\n" +"c01.kr\\n" +"eliv-api.kr\\n" +"eliv-cdn.kr\\n" +"eliv-dns.kr\\n" +"mmv.kr\\n" +"vki.kr\\n" +"dev.project-study.com\\n" +"platter-app.dev\\n" +"e.id\\n" +"chirurgiens-dentistes-en-france.fr\\n" +"byen.site\\n" +"nyc.mn\\n" +"pubtls.org\\n" +"puter.app\\n" +"puter.site\\n" +"puter.work\\n" +"pythonanywhere.com\\n" +"eu.pythonanywhere.com\\n" +"qa2.com\\n" +"qcx.io\\n" +"myqnapcloud.cn\\n" +"mycloudnas.com\\n" +"mynascloud.com\\n" +"myqnapcloud.com\\n" +"qoto.io\\n" +"qualifioapp.com\\n" +"ladesk.com\\n" +"qbuser.com\\n" +"vapor.cloud\\n" +"vaporcloud.io\\n" +"rackmaze.com\\n" +"rackmaze.net\\n" +"cloudsite.builders\\n" +"myradweb.net\\n" +"servername.us\\n" +"web.in\\n" +"in.net\\n" +"myrdbx.io\\n" +"site.rb-hosting.io\\n" +"up.railway.app\\n" +"ravpage.co.il\\n" +"readthedocs-hosted.com\\n" +"readthedocs.io\\n" +"rhcloud.com\\n" +"instances.spawn.cc\\n" +"onrender.com\\n" +"app.render.com\\n" +"replit.app\\n" +"id.replit.app\\n" +"firewalledreplit.co\\n" +"id.firewalledreplit.co\\n" +"repl.co\\n" +"id.repl.co\\n" +"repl.run\\n" +"resindevice.io\\n" +"devices.resinstaging.io\\n" +"retool.app\\n" +"adimo.co.uk\\n" +"itcouldbewor.se\\n" +"aus.basketball\\n" +"nz.basketball\\n" +"subsc-pay.com\\n" +"subsc-pay.net\\n" +"git-pages.rit.edu\\n" +"rocketpreview.app\\n" +"rocky.page\\n" +"rub.de\\n" +"ruhr-uni-bochum.de\\n" +"io.noc.ruhr-uni-bochum.de\\n" +"ras.ru\\n" +"nyat.app\\n" +"180r.com\\n" +"dojin.com\\n" +"sakuratan.com\\n" +"sakuraweb.com\\n" +"x0.com\\n" +"2-d.jp\\n" +"bona.jp\\n" +"crap.jp\\n" +"daynight.jp\\n" +"eek.jp\\n" +"flop.jp\\n" +"halfmoon.jp\\n" +"jeez.jp\\n" +"matrix.jp\\n" +"mimoza.jp\\n" +"ivory.ne.jp\\n" +"mail-box.ne.jp\\n" +"mints.ne.jp\\n" +"mokuren.ne.jp\\n" +"opal.ne.jp\\n" +"sakura.ne.jp\\n" +"sumomo.ne.jp\\n" +"topaz.ne.jp\\n" +"netgamers.jp\\n" +"nyanta.jp\\n" +"o0o0.jp\\n" +"rdy.jp\\n" +"rgr.jp\\n" +"rulez.jp\\n" +"s3.isk01.sakurastorage.jp\\n" +"s3.isk02.sakurastorage.jp\\n" +"saloon.jp\\n" +"sblo.jp\\n" +"skr.jp\\n" +"tank.jp\\n" +"uh-oh.jp\\n" +"undo.jp\\n" +"rs.webaccel.jp\\n" +"user.webaccel.jp\\n" +"websozai.jp\\n" +"xii.jp\\n" +"squares.net\\n" +"jpn.org\\n" +"kirara.st\\n" +"x0.to\\n" +"from.tv\\n" +"sakura.tv\\n" +"sandcats.io\\n" +"sav.case\\n" +"logoip.com\\n" +"logoip.de\\n" +"fr-par-1.baremetal.scw.cloud\\n" +"fr-par-2.baremetal.scw.cloud\\n" +"nl-ams-1.baremetal.scw.cloud\\n" +"cockpit.fr-par.scw.cloud\\n" +"ddl.fr-par.scw.cloud\\n" +"dtwh.fr-par.scw.cloud\\n" +"fnc.fr-par.scw.cloud\\n" +"functions.fnc.fr-par.scw.cloud\\n" +"ifr.fr-par.scw.cloud\\n" +"k8s.fr-par.scw.cloud\\n" +"nodes.k8s.fr-par.scw.cloud\\n" +"kafk.fr-par.scw.cloud\\n" +"mgdb.fr-par.scw.cloud\\n" +"rdb.fr-par.scw.cloud\\n" +"s3.fr-par.scw.cloud\\n" +"s3-website.fr-par.scw.cloud\\n" +"scbl.fr-par.scw.cloud\\n" +"whm.fr-par.scw.cloud\\n" +"priv.instances.scw.cloud\\n" +"pub.instances.scw.cloud\\n" +"k8s.scw.cloud\\n" +"cockpit.nl-ams.scw.cloud\\n" +"ddl.nl-ams.scw.cloud\\n" +"dtwh.nl-ams.scw.cloud\\n" +"ifr.nl-ams.scw.cloud\\n" +"k8s.nl-ams.scw.cloud\\n" +"nodes.k8s.nl-ams.scw.cloud\\n" +"kafk.nl-ams.scw.cloud\\n" +"mgdb.nl-ams.scw.cloud\\n" +"rdb.nl-ams.scw.cloud\\n" +"s3.nl-ams.scw.cloud\\n" +"s3-website.nl-ams.scw.cloud\\n" +"scbl.nl-ams.scw.cloud\\n" +"whm.nl-ams.scw.cloud\\n" +"cockpit.pl-waw.scw.cloud\\n" +"ddl.pl-waw.scw.cloud\\n" +"dtwh.pl-waw.scw.cloud\\n" +"ifr.pl-waw.scw.cloud\\n" +"k8s.pl-waw.scw.cloud\\n" +"nodes.k8s.pl-waw.scw.cloud\\n" +"kafk.pl-waw.scw.cloud\\n" +"mgdb.pl-waw.scw.cloud\\n" +"rdb.pl-waw.scw.cloud\\n" +"s3.pl-waw.scw.cloud\\n" +"s3-website.pl-waw.scw.cloud\\n" +"scbl.pl-waw.scw.cloud\\n" +"scalebook.scw.cloud\\n" +"smartlabeling.scw.cloud\\n" +"dedibox.fr\\n" +"scw.site\\n" +"ams.scw.site\\n" +"waw.scw.site\\n" +"schokokeks.net\\n" +"gov.scot\\n" +"service.gov.scot\\n" +"mygov.scot\\n" +"scrysec.com\\n" +"client.scrypted.io\\n" +"firewall-gateway.com\\n" +"firewall-gateway.de\\n" +"my-gateway.de\\n" +"my-router.de\\n" +"spdns.de\\n" +"spdns.eu\\n" +"firewall-gateway.net\\n" +"my-firewall.org\\n" +"myfirewall.org\\n" +"spdns.org\\n" +"seidat.net\\n" +"sellfy.store\\n" +"minisite.ms\\n" +"senseering.net\\n" +"servebolt.cloud\\n" +"biz.ua\\n" +"co.ua\\n" +"pp.ua\\n" +"as.sh.cn\\n" +"vicp.fun\\n" +"yicp.fun\\n" +"zicp.fun\\n" +"sheezy.games\\n" +"myshopblocks.com\\n" +"myshopify.com\\n" +"shopitsite.com\\n" +"shopware.shop\\n" +"shopware.store\\n" +"mo-siemens.io\\n" +"1kapp.com\\n" +"appchizi.com\\n" +"applinzi.com\\n" +"sinaapp.com\\n" +"vipsinaapp.com\\n" +"siteleaf.net\\n" +"small-web.org\\n" +"aeroport.fr\\n" +"avocat.fr\\n" +"chambagri.fr\\n" +"chirurgiens-dentistes.fr\\n" +"experts-comptables.fr\\n" +"medecin.fr\\n" +"notaires.fr\\n" +"pharmacien.fr\\n" +"port.fr\\n" +"veterinaire.fr\\n" +"vp4.me\\n" +"streamlit.app\\n" +"streamlitapp.com\\n" +"try-snowplow.com\\n" +"mafelo.net\\n" +"sol.site\\n" +"playstation-cloud.com\\n" +"srht.site\\n" +"apps.lair.io\\n" +"4.at\\n" +"my.at\\n" +"my.de\\n" +"nx.gw\\n" +"spawnbase.app\\n" +"customer.speedpartner.de\\n" +"myspreadshop.at\\n" +"myspreadshop.com.au\\n" +"myspreadshop.be\\n" +"myspreadshop.ca\\n" +"myspreadshop.ch\\n" +"myspreadshop.com\\n" +"myspreadshop.de\\n" +"myspreadshop.dk\\n" +"myspreadshop.es\\n" +"myspreadshop.fi\\n" +"myspreadshop.fr\\n" +"myspreadshop.ie\\n" +"myspreadshop.it\\n" +"myspreadshop.net\\n" +"myspreadshop.nl\\n" +"myspreadshop.no\\n" +"myspreadshop.pl\\n" +"myspreadshop.se\\n" +"myspreadshop.co.uk\\n" +"w-corp-staticblitz.com\\n" +"w-credentialless-staticblitz.com\\n" +"w-staticblitz.com\\n" +"bolt.host\\n" +"stackhero-network.com\\n" +"runs.onstackit.cloud\\n" +"stackit.gg\\n" +"stackit.rocks\\n" +"stackit.run\\n" +"stackit.zone\\n" +"sryze.cc\\n" +"indevs.in\\n" +"musician.io\\n" +"novecore.site\\n" +"statichost.page\\n" +"feedback.ac\\n" +"forms.ac\\n" +"assessments.cx\\n" +"calculators.cx\\n" +"funnels.cx\\n" +"paynow.cx\\n" +"quizzes.cx\\n" +"researched.cx\\n" +"tests.cx\\n" +"surveys.so\\n" +"ipfs.storacha.link\\n" +"ipfs.w3s.link\\n" +"storebase.store\\n" +"strapiapp.com\\n" +"media.strapiapp.com\\n" +"vps-host.net\\n" +"atl.jelastic.vps-host.net\\n" +"njs.jelastic.vps-host.net\\n" +"ric.jelastic.vps-host.net\\n" +"streak-link.com\\n" +"streaklinks.com\\n" +"streakusercontent.com\\n" +"soc.srcf.net\\n" +"user.srcf.net\\n" +"utwente.io\\n" +"temp-dns.com\\n" +"supabase.co\\n" +"realtime.supabase.co\\n" +"storage.supabase.co\\n" +"supabase.in\\n" +"supabase.net\\n" +"surge.sh\\n" +"syncloud.it\\n" +"dscloud.biz\\n" +"direct.quickconnect.cn\\n" +"dsmynas.com\\n" +"familyds.com\\n" +"diskstation.me\\n" +"dscloud.me\\n" +"i234.me\\n" +"myds.me\\n" +"synology.me\\n" +"dscloud.mobi\\n" +"dsmynas.net\\n" +"familyds.net\\n" +"dsmynas.org\\n" +"familyds.org\\n" +"direct.quickconnect.to\\n" +"vpnplus.to\\n" +"mytabit.com\\n" +"mytabit.co.il\\n" +"tabitorder.co.il\\n" +"taifun-dns.de\\n" +"erp.dev\\n" +"web.erp.dev\\n" +"ts.net\\n" +"gda.pl\\n" +"gdansk.pl\\n" +"gdynia.pl\\n" +"med.pl\\n" +"sopot.pl\\n" +"taveusercontent.com\\n" +"p.tawk.email\\n" +"p.tawkto.email\\n" +"tche.br\\n" +"site.tb-hosting.com\\n" +"directwp.eu\\n" +"ec.cc\\n" +"eu.cc\\n" +"gu.cc\\n" +"uk.cc\\n" +"us.cc\\n" +"edugit.io\\n" +"s3.teckids.org\\n" +"telebit.app\\n" +"telebit.io\\n" +"teleport.sh\\n" +"reservd.com\\n" +"thingdustdata.com\\n" +"cust.dev.thingdust.io\\n" +"reservd.dev.thingdust.io\\n" +"cust.disrec.thingdust.io\\n" +"reservd.disrec.thingdust.io\\n" +"cust.prod.thingdust.io\\n" +"cust.testing.thingdust.io\\n" +"reservd.testing.thingdust.io\\n" +"tickets.io\\n" +"t3.storage.dev\\n" +"t3.storageapi.dev\\n" +"arvo.network\\n" +"azimuth.network\\n" +"tlon.network\\n" +"torproject.net\\n" +"pages.torproject.net\\n" +"townnews-staging.com\\n" +"12hp.at\\n" +"2ix.at\\n" +"4lima.at\\n" +"lima-city.at\\n" +"12hp.ch\\n" +"2ix.ch\\n" +"4lima.ch\\n" +"lima-city.ch\\n" +"trafficplex.cloud\\n" +"de.cool\\n" +"12hp.de\\n" +"2ix.de\\n" +"4lima.de\\n" +"lima-city.de\\n" +"1337.pictures\\n" +"clan.rip\\n" +"lima-city.rocks\\n" +"webspace.rocks\\n" +"lima.zone\\n" +"site.transip.me\\n" +"tunnelmole.net\\n" +"tuxfamily.org\\n" +"typedream.app\\n" +"pro.typeform.com\\n" +"uber.space\\n" +"hk.com\\n" +"inc.hk\\n" +"ltd.hk\\n" +"hk.org\\n" +"it.com\\n" +"umso.co\\n" +"unison-services.cloud\\n" +"virtual-user.de\\n" +"virtualuser.de\\n" +"obj.ag\\n" +"name.pm\\n" +"sch.tf\\n" +"biz.wf\\n" +"sch.wf\\n" +"org.yt\\n" +"rs.ba\\n" +"bielsko.pl\\n" +"urown.cloud\\n" +"dnsupdate.info\\n" +"us.org\\n" +"v.ua\\n" +"val.run\\n" +"web.val.run\\n" +"vercel.app\\n" +"v0.build\\n" +"vercel.dev\\n" +"vusercontent.net\\n" +"tmp.now\\n" +"vercel.run\\n" +"now.sh\\n" +"2038.io\\n" +"v-info.info\\n" +"vistablog.ir\\n" +"deus-canvas.com\\n" +"vivenushop.com\\n" +"vivenushop.dev\\n" +"voorloper.cloud\\n" +"wafflecell.com\\n" +"wal.app\\n" +"wasmer.app\\n" +"webflow.io\\n" +"webflowtest.io\\n" +"hotelwithflight.com\\n" +"reserve-online.net\\n" +"book.online\\n" +"cprapid.com\\n" +"pleskns.com\\n" +"wp2.host\\n" +"pdns.page\\n" +"plesk.page\\n" +"cpanel.site\\n" +"wpsquared.site\\n" +"remotewd.com\\n" +"box.ca\\n" +"pages.wiardweb.com\\n" +"toolforge.org\\n" +"wmcloud.org\\n" +"beta.wmcloud.org\\n" +"wmflabs.org\\n" +"hrsn.dev\\n" +"is-a.dev\\n" +"vps.hrsn.net\\n" +"localcert.net\\n" +"windsurf.app\\n" +"windsurf.build\\n" +"drive-platform.com\\n" +"drive-platform.io\\n" +"panel.gg\\n" +"daemon.panel.gg\\n" +"base44.app\\n" +"base44-sandbox.com\\n" +"wixsite.com\\n" +"wixstudio.com\\n" +"editorx.io\\n" +"wixstudio.io\\n" +"wix.run\\n" +"messwithdns.com\\n" +"woltlab-demo.com\\n" +"myforum.community\\n" +"community-pro.de\\n" +"diskussionsbereich.de\\n" +"community-pro.net\\n" +"meinforum.net\\n" +"affinitylottery.org.uk\\n" +"raffleentry.org.uk\\n" +"weeklylottery.org.uk\\n" +"wpenginepowered.com\\n" +"js.wpenginepowered.com\\n" +"grok.me\\n" +"half.host\\n" +"cistron.nl\\n" +"demon.nl\\n" +"xs4all.space\\n" +"xtooldevice.com\\n" +"yandexcloud.net\\n" +"storage.yandexcloud.net\\n" +"website.yandexcloud.net\\n" +"sourcecraft.site\\n" +"official.academy\\n" +"yolasite.com\\n" +"ynh.fr\\n" +"nohost.me\\n" +"noho.st\\n" +"za.net\\n" +"za.org\\n" +"zap.cloud\\n" +"zeabur.app\\n" +"prg1-zerops.zone\\n" +"bss.design\\n" +"basicserver.io\\n" +"virtualserver.io\\n" +"enterprisecloud.nu\\n" +"zone.id\\n" +"nett.to\\n" +"zabc.net\\n" +; diff -Nru pdns-recursor-5.2.13/pubsuffix.hh pdns-recursor-5.4.9/pubsuffix.hh --- pdns-recursor-5.2.13/pubsuffix.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/pubsuffix.hh 2026-10-26 08:26:51.000000000 +0000 @@ -25,6 +25,7 @@ #include extern std::vector> g_pubs; +extern const std::string g_pubsuffix; /* initialize the g_pubs variable with the public suffix list, using the file passed in parameter if any, or the built-in diff -Nru pdns-recursor-5.2.13/pubsuffixloader.cc pdns-recursor-5.4.9/pubsuffixloader.cc --- pdns-recursor-5.2.13/pubsuffixloader.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/pubsuffixloader.cc 2026-10-26 08:26:51.000000000 +0000 @@ -24,72 +24,75 @@ #include #include "dnsname.hh" -#include "logger.hh" #include "logging.hh" #include "misc.hh" #include "pubsuffix.hh" -extern const char* g_pubsuffix[]; std::vector> g_pubs; +static bool initPublicSuffixList(const std::string& file, std::istream& stream, std::vector>& pbList) +{ + + try { + Regex reg("^[.0-9a-z-]*$"); + + std::string line; + while (std::getline(stream, line)) { + if (line.empty() || (line.rfind("//", 0) == 0)) { + /* skip empty and commented lines */ + continue; + } + try { + line = toLower(line); + if (!reg.match(line)) { + continue; + } + DNSName name(line); + if (name.countLabels() < 2) { + continue; + } + pbList.emplace_back(name.labelReverse().getRawLabels()); + } + catch (...) { + /* not a DNS name, ignoring */ + continue; + } + } + + if (file != "internal") { + g_slog->withName("runtime")->info(Logr::Info, "Loaded the Public Suffix List", "file", Logging::Loggable(file)); + } + return true; + } + catch (const std::exception& e) { + g_slog->withName("runtime")->error(Logr::Error, e.what(), "Error while loading the Public Suffix List", "file", Logging::Loggable(file)); + } + return false; +} + void initPublicSuffixList(const std::string& file) { + bool loaded = false; std::vector> pbList; - bool loaded = false; if (!file.empty()) { try { - Regex reg("^[.0-9a-z-]*$"); std::ifstream suffixFile(file); if (!suffixFile.is_open()) { throw std::runtime_error("Error opening the public suffix list file"); } - - std::string line; - while (std::getline(suffixFile, line)) { - if (line.empty() || (line.rfind("//", 0) == 0)) { - /* skip empty and commented lines */ - continue; - } - try { - line = toLower(line); - if (!reg.match(line)) { - continue; - } - DNSName name(toLower(line)); - if (name.countLabels() < 2) { - continue; - } - pbList.push_back(name.labelReverse().getRawLabels()); - } - catch (...) { - /* not a DNS name, ignoring */ - } - } - - SLOG(g_log << Logger::Info << "Loaded the Public Suffix List from '" << file << "'" << endl, - g_slog->withName("runtime")->info(Logr::Info, "Loaded the Public Suffix List", "file", Logging::Loggable(file))); - loaded = true; + loaded = initPublicSuffixList(file, suffixFile, pbList); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Error while loading the Public Suffix List from '" << file << "', falling back to the built-in list: " << e.what() << endl, - g_slog->withName("runtime")->error(Logr::Error, e.what(), "Error while loading the Public Suffix List", "file", Logging::Loggable(file))); + g_slog->withName("runtime")->error(Logr::Error, e.what(), "Error while loading the Public Suffix List", "file", Logging::Loggable(file)); } } if (!loaded) { pbList.clear(); - - for (const char** p = g_pubsuffix; *p; ++p) { - string low = toLower(*p); - - vector parts; - stringtok(parts, low, "."); - reverse(parts.begin(), parts.end()); - pbList.push_back(parts); - } + std::istringstream stream(g_pubsuffix); + initPublicSuffixList("internal", stream, pbList); } - - sort(pbList.begin(), pbList.end()); + std::sort(pbList.begin(), pbList.end()); g_pubs = std::move(pbList); } diff -Nru pdns-recursor-5.2.13/qtype.cc pdns-recursor-5.4.9/qtype.cc --- pdns-recursor-5.2.13/qtype.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/qtype.cc 2026-10-26 09:46:36.000000000 +0000 @@ -76,6 +76,8 @@ {"ZONEMD", 63}, {"SVCB", 64}, {"HTTPS", 65}, + {"HHIT", 67}, + {"BRID", 68}, {"SPF", 99}, {"NID", 104}, {"L32", 105}, @@ -92,6 +94,7 @@ {"ANY", 255}, {"URI", 256}, {"CAA", 257}, + {"RESINFO", 261}, {"DLV", 32769}, {"ADDR", 65400}, #if !defined(RECURSOR) @@ -166,7 +169,23 @@ return *this; } -const std::string QClass::toString() const +static const std::map s_classMap = { + {"IN", QClass::IN}, + {"CHAOS", QClass::CHAOS}, + {"NONE", QClass::NONE}, + {"ANY", QClass::ANY}, +}; + +QClass::QClass(const std::string& code) +{ + auto mapIt = s_classMap.find(code); + if (mapIt == s_classMap.end()) { + throw std::runtime_error("Invalid QClass '" + code + "'"); + } + qclass = mapIt->second; +} + +std::string QClass::toString() const { switch (qclass) { case IN: @@ -181,3 +200,7 @@ return "CLASS" + std::to_string(qclass); } } + +const std::set QType::exclusiveEntryTypes = { + QType::CNAME +}; diff -Nru pdns-recursor-5.2.13/qtype.hh pdns-recursor-5.4.9/qtype.hh --- pdns-recursor-5.2.13/qtype.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/qtype.hh 2026-10-26 09:46:36.000000000 +0000 @@ -20,6 +20,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once + +#include + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -60,7 +63,7 @@ /** * \brief Return whether we know the name of this type. * - * This does not presume that we have an implemented a content representation for this type, + * This does not presume that we have implemented a content representation for this type, * for that please see DNSRecordContent::isRegisteredType(). */ bool isSupportedType() const; @@ -120,6 +123,8 @@ ZONEMD = 63, SVCB = 64, HTTPS = 65, + HHIT = 67, + BRID = 68, SPF = 99, NID = 104, L32 = 105, @@ -136,6 +141,7 @@ ANY = 255, URI = 256, CAA = 257, + RESINFO = 261, DLV = 32769, ADDR = 65400, #if !defined(RECURSOR) @@ -151,6 +157,9 @@ const static map names; const static map numbers; + // QTypes that MUST NOT be used with any other QType on the same name. + const static std::set exclusiveEntryTypes; + private: uint16_t code; @@ -178,6 +187,7 @@ struct QClass { constexpr QClass(uint16_t code = 0) : qclass(code) {} + explicit QClass(const std::string& code); constexpr operator uint16_t() const { return qclass; @@ -186,7 +196,7 @@ { return qclass; } - const std::string toString() const; + std::string toString() const; static const QClass IN; static const QClass CHAOS; diff -Nru pdns-recursor-5.2.13/ratelimitedlog.hh pdns-recursor-5.4.9/ratelimitedlog.hh --- pdns-recursor-5.2.13/ratelimitedlog.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ratelimitedlog.hh 2026-10-26 08:26:51.000000000 +0000 @@ -22,7 +22,6 @@ #pragma once #include "lock.hh" -#include "logger.hh" #include "logging.hh" namespace pdns @@ -38,10 +37,9 @@ { uint32_t count{}; if (doLog(count)) { - SLOG(g_log << Logger::Error << msg << " created an exception" << endl, - slog->info(Logr::Error, msg + " created an exception", - "ratelimitingSkipped", Logging::Loggable(count), - "exception", Logging::Loggable("other"), args...)); + slog->info(Logr::Error, msg + " created an exception", + "ratelimitingSkipped", Logging::Loggable(count), + "exception", Logging::Loggable("other"), args...); }; } @@ -50,10 +48,9 @@ { uint32_t count{}; if (doLog(count)) { - SLOG(g_log << Logger::Error << msg << " created an exception: " << stdException.what() << endl, - slog->error(Logr::Error, stdException.what(), msg + " created an exception", - "ratelimitingSkipped", Logging::Loggable(count), - "exception", Logging::Loggable("std::exception"), args...)); + slog->error(Logr::Error, stdException.what(), msg + " created an exception", + "ratelimitingSkipped", Logging::Loggable(count), + "exception", Logging::Loggable("std::exception"), args...); } } @@ -62,10 +59,9 @@ { uint32_t count{}; if (doLog(count)) { - SLOG(g_log << Logger::Error << msg << " created an PDNSException: " << pdnsException.reason << endl, - slog->error(Logr::Error, pdnsException.reason, msg + " created an exception", - "ratelimitingSkipped", Logging::Loggable(count), - "exception", Logging::Loggable("PDNSException"), args...)); + slog->error(Logr::Error, pdnsException.reason, msg + " created an exception", + "ratelimitingSkipped", Logging::Loggable(count), + "exception", Logging::Loggable("PDNSException"), args...); } } diff -Nru pdns-recursor-5.2.13/rcpgenerator.cc pdns-recursor-5.4.9/rcpgenerator.cc --- pdns-recursor-5.2.13/rcpgenerator.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rcpgenerator.cc 2026-10-26 09:46:36.000000000 +0000 @@ -36,7 +36,8 @@ #include "base64.hh" #include "namespaces.hh" -RecordTextReader::RecordTextReader(string str, DNSName zone) : d_string(std::move(str)), d_zone(std::move(zone)), d_pos(0) +RecordTextReader::RecordTextReader(string str, ZoneName zone) : + d_string(std::move(str)), d_zone(std::move(zone)) { /* remove whitespace */ if(!d_string.empty() && ( dns_isspace(*d_string.begin()) || dns_isspace(*d_string.rbegin()) )) @@ -46,9 +47,11 @@ void RecordTextReader::xfr48BitInt(uint64_t &val) { + auto oldpos = d_pos; xfr64BitInt(val); - if (val > 281474976710655LL) - throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve + if (val >= (1ULL << 48)) { + throw RecordTextException("Numerical value " + d_string.substr(oldpos, d_pos - oldpos) + " at position " + std::to_string(oldpos) + " is too large for a 48-bit integer"); + } } void RecordTextReader::xfrNodeOrLocatorID(NodeOrLocatorID& val) { @@ -121,6 +124,13 @@ throw RecordTextException("unable to parse '"+std::to_string(itmp)+"' into a valid time at position "+std::to_string(d_pos)+" in '"+d_string+"'"); } + // Note tm_mon is still in 1..12 range at this point + if (tm.tm_sec < 0 || tm.tm_sec > 60 || tm.tm_min < 0 || tm.tm_min > 59 || + tm.tm_hour < 0 || tm.tm_hour > 23 || tm.tm_mday < 0 || tm.tm_mday > 31 || + tm.tm_mon < 1 || tm.tm_mon > 12) { + throw RecordTextException("invalid time specification '"+std::to_string(itmp)+"' at position "+std::to_string(d_pos)+" in '"+d_string+"'"); + } + tm.tm_year-=1900; tm.tm_mon-=1; // coverity[store_truncates_time_t] @@ -233,24 +243,28 @@ void RecordTextReader::xfr16BitInt(uint16_t &val) { - uint32_t tmp; + auto oldpos = d_pos; + uint32_t tmp{0}; xfr32BitInt(tmp); val=tmp; - if(val!=tmp) - throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve + if(val!=tmp) { + throw RecordTextException("Numerical value " + d_string.substr(oldpos, d_pos - oldpos) + " at position " + std::to_string(oldpos) + " is too large for a 16-bit integer"); + } } void RecordTextReader::xfr8BitInt(uint8_t &val) { - uint32_t tmp; + auto oldpos = d_pos; + uint32_t tmp{0}; xfr32BitInt(tmp); val=tmp; - if(val!=tmp) - throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve + if(val!=tmp) { + throw RecordTextException("Numerical value " + d_string.substr(oldpos, d_pos - oldpos) + " at position " + std::to_string(oldpos) + " is too large for a 8-bit integer"); + } } // this code should leave all the escapes around -void RecordTextReader::xfrName(DNSName& val, bool, bool) +void RecordTextReader::xfrName(DNSName& val, [[maybe_unused]] bool compress) { skipSpaces(); DNSName sval; @@ -270,10 +284,10 @@ } if (sval.empty()) { - sval = d_zone; + sval = DNSName(d_zone); } else if (!d_zone.empty()) { - sval += d_zone; + sval += DNSName(d_zone); } val = std::move(sval); } @@ -293,12 +307,15 @@ return false; } -void RecordTextReader::xfrBlobNoSpaces(string& val, int len) { +void RecordTextReader::xfrBlobNoSpaces(string& val, int len) +{ skipSpaces(); - int pos=(int)d_pos; + auto pos = d_pos; const char* strptr=d_string.c_str(); - while(d_pos < d_end && isbase64(strptr[d_pos], false)) + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + while(d_pos < d_end && isbase64(strptr[d_pos], false)) { d_pos++; + } string tmp; tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); @@ -313,10 +330,12 @@ void RecordTextReader::xfrBlob(string& val, int) { skipSpaces(); - int pos=(int)d_pos; + auto pos = d_pos; const char* strptr=d_string.c_str(); - while(d_pos < d_end && isbase64(strptr[d_pos], true)) + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + while(d_pos < d_end && isbase64(strptr[d_pos], true)) { d_pos++; + } string tmp; tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); @@ -343,7 +362,7 @@ return; // Find the SvcParamKey - size_t pos = d_pos; + auto pos = d_pos; while (d_pos != d_end) { if (d_string.at(d_pos) == '=' || d_string.at(d_pos) == ' ') { break; @@ -361,10 +380,7 @@ throw RecordTextException(e.what()); } - if (key != SvcParam::no_default_alpn) { - if (d_pos == d_end || d_string.at(d_pos) != '=') { - throw RecordTextException("expected '=' after " + k); - } + if (d_pos != d_end && d_string.at(d_pos) == '=') { d_pos++; // Now on the first character after '=' if (d_pos == d_end || d_string.at(d_pos) == ' ') { throw RecordTextException("expected value after " + k + "="); @@ -373,7 +389,8 @@ switch (key) { case SvcParam::no_default_alpn: - if (d_pos != d_end && d_string.at(d_pos) == '=') { + case SvcParam::ohttp: + if (d_pos != d_end && d_string.at(d_pos) != ' ') { throw RecordTextException(k + " key can not have values"); } val.insert(SvcParam(key)); @@ -405,10 +422,13 @@ hints.push_back(ComboAddress(v)); } } + if (!doAuto && hints.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } try { auto p = SvcParam(key, std::move(hints)); p.setAutoHint(doAuto); - val.insert(p); + val.insert(std::move(p)); } catch (const std::invalid_argument& e) { throw RecordTextException(e.what()); @@ -424,6 +444,9 @@ while (spos < v.length()) { len = v.at(spos); spos += 1; + if (len == 0) { + throw RecordTextException("ALPN values cannot be empty strings"); + } if (len > v.length() - spos) { throw RecordTextException("Length of ALPN value goes over total length of alpn SVC Param"); } @@ -433,6 +456,14 @@ } else { xfrSVCBValueList(value); } + if (value.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } + for (const auto &alpn_value : value) { + if (alpn_value.empty()) { + throw RecordTextException("ALPN values cannot be empty strings"); + } + } val.insert(SvcParam(key, std::move(value))); break; } @@ -440,6 +471,9 @@ if (generic) { string v; xfrRFC1035CharString(v); + if (v.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } if (v.length() % 2 != 0) { throw RecordTextException("Wrong number of bytes in SVC Param " + k); } @@ -454,6 +488,9 @@ } vector parts; xfrSVCBValueList(parts); + if (parts.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } set values(parts.begin(), parts.end()); val.insert(SvcParam(key, std::move(values))); break; @@ -471,6 +508,9 @@ } else { string portstring; xfrRFC1035CharString(portstring); + if (portstring.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } try { pdns::checked_stoi_into(port, portstring); } catch (const std::exception &e) { @@ -497,12 +537,54 @@ d_pos++; } } + if (value.empty()) { + throw RecordTextException("value is required for SVC Param " + k); + } + val.insert(SvcParam(key, value)); + break; + } + case SvcParam::tls_supported_groups: { + string string_value; + xfrRFC1035CharString(string_value); + if (string_value.empty()) { + throw RecordTextException("Value is required for SVC Param " + k); + } + + vector parts; + stringtok(parts, string_value, ","); + + vector values; + values.reserve(parts.size()); + for (const auto& part : parts) { + uint16_t int_part{0}; + try { + pdns::checked_stoi_into(int_part, part); + } catch (const std::invalid_argument&) { + throw RecordTextException("Value in invalid format for SVC Param " + k); + } + values.emplace_back(int_part); + } + + val.insert(SvcParam(key, std::move(values))); + break; + } + case SvcParam::dohpath: { + string value; + xfrRFC1035CharString(value); + if (value.empty()) { + throw RecordTextException("Value is required for SVC Param " + k); + } val.insert(SvcParam(key, value)); break; } default: { string value; xfrRFC1035CharString(value); + if (!generic && value.empty()) { + // for generic format, we do not know. + // Known keys which forbid having a value need to implement a switch case, above. + throw RecordTextException("value is required for SVC Param " + k); + } val.insert(SvcParam(key, value)); break; } @@ -523,48 +605,52 @@ } -static void HEXDecode(const char* begin, const char* end, string& out) +static void HEXDecode(std::string_view chunk, string& out) { - if(end - begin == 1 && *begin=='-') { - out.clear(); + out.clear(); + if (chunk.length() == 1 && chunk[0] == '-') { return; } - out.clear(); - out.reserve((end-begin)/2); - uint8_t mode=0, val=0; - for(; begin != end; ++begin) { - if(!isalnum(*begin)) + out.reserve(chunk.length() / 2); + bool lowdigit{false}; + uint8_t val{0}; + for (auto chr : chunk) { + if(isalnum(chr) == 0) { continue; - if(mode==0) { - val = 16*hextodec(*begin); - mode=1; + } + if (!lowdigit) { + val = 16*hextodec(chr); + lowdigit = true; } else { - val += hextodec(*begin); + val += hextodec(chr); out.append(1, (char) val); - mode = 0; + lowdigit = false; val = 0; } } - if(mode) - throw RecordTextException("Hexadecimal blob with odd number of characters"); + if (lowdigit) { + throw RecordTextException("Hexadecimal blob '" + std::string(chunk) + "' contains an odd number of hex digits"); + } } void RecordTextReader::xfrHexBlob(string& val, bool keepReading) { skipSpaces(); - int pos=(int)d_pos; - while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) + auto pos = d_pos; + while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) { d_pos++; + } - HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); + HEXDecode(std::string_view(d_string).substr(pos, d_pos - pos), val); } void RecordTextReader::xfrBase32HexBlob(string& val) { skipSpaces(); - int pos=(int)d_pos; - while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + auto pos = d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) { d_pos++; + } val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos)); } @@ -584,37 +670,66 @@ val.clear(); val.reserve(d_end - d_pos); - while(d_pos != d_end) { - if(!val.empty()) + while (d_pos != d_end) { + if (!val.empty()) { val.append(1, ' '); + } skipSpaces(); - if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes - string::size_type pos = d_pos; - while(pos != d_end && isalnum(d_string[pos])) - pos++; - if(pos == d_end) { - val.append(1, '"'); - val.append(d_string.c_str() + d_pos, d_end - d_pos); - val.append(1, '"'); - d_pos = d_end; - break; - } - throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos)+" of '"+d_string+"'"); - } + char delimiter{'"'}; + bool quoted = d_string[d_pos] == '"'; + // If the word is quoted, process up to the next quote; otherwise, + // process up to the next whitespace (but output it in quotes). val.append(1, '"'); - while(++d_pos < d_end && d_string[d_pos]!='"') { - if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { - val.append(1, d_string[d_pos++]); + if (quoted) { + ++d_pos; + } + else { + // RFC1035: ``a contiguous set of characters without interior spaces'' + delimiter = ' '; + } + while (d_pos != d_end && d_string[d_pos] != delimiter) { + if (d_string[d_pos] == '\\' && d_pos + 1 != d_end) { + val.append(1, d_string[d_pos++]); // copy escape slash + char chr = d_string[d_pos]; + if (chr >= '0' && chr <= '9') { + bool valid{false}; + // Must be a three-digit character escape sequence + if (d_end - d_pos >= 3) { + char chr2 = d_string[d_pos + 1]; + char chr3 = d_string[d_pos + 2]; + if (chr2 >= '0' && chr2 <= '9' && chr3 >= '0' && chr3 <= '9') { + valid = 100 * (chr - '0') + 10 * (chr2 - '0') + chr3 - '0' < 256; + } + } + if (!valid) { + throw RecordTextException("Data field in DNS contains an invalid escape at position "+std::to_string(d_pos)+" of '"+d_string+"'"); + } + } + // Not advancing d_pos, we'll append the next 1 or 3 characters as + // part of the regular case. + } + if (!quoted && d_string[d_pos] == '"') { + // Bind allows a non-quoted text to be immediately followed by a + // quoted text, without any whitespace in between, so handle this + // as a delimiter. + break; } val.append(1, d_string[d_pos]); + ++d_pos; } val.append(1,'"'); - if(d_pos == d_end) - throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); - d_pos++; - if(!multi) + if (quoted) { + // If we reached the end in a quoted section, the closing quote is missing. + if (d_pos == d_end) { + throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); + } + // Skip closing quote + ++d_pos; + } + if (!multi) { break; + } } } @@ -636,9 +751,10 @@ void RecordTextReader::xfrType(uint16_t& val) { skipSpaces(); - int pos=(int)d_pos; - while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + auto pos = d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) { d_pos++; + } string tmp; tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); @@ -792,7 +908,7 @@ } // should not mess with the escapes -void RecordTextWriter::xfrName(const DNSName& val, bool /* unused */, bool /* noDot */) +void RecordTextWriter::xfrName(const DNSName& val, bool /* unused */) { if(!d_string.empty()) d_string.append(1,' '); @@ -837,27 +953,6 @@ } } -// FIXME copied from dnsparser.cc, see #6010 and #3503 if you want a proper solution -static string txtEscape(const string &name) -{ - string ret; - char ebuf[5]; - - for(char i : name) { - if((unsigned char) i >= 127 || (unsigned char) i < 32) { - snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)i); - ret += ebuf; - } - else if(i=='"' || i=='\\'){ - ret += '\\'; - ret += i; - } - else - ret += i; - } - return ret; -} - void RecordTextWriter::xfrSVCBValueList(const vector &val) { bool shouldQuote{false}; vector escaped; @@ -880,7 +975,7 @@ } unescaped += ch; } - escaped.push_back(unescaped); + escaped.push_back(std::move(unescaped)); } if (shouldQuote) { d_string.append(1, '"'); @@ -897,7 +992,7 @@ d_string.append(1, ' '); d_string.append(SvcParam::keyToString(param.getKey())); - if (param.getKey() != SvcParam::no_default_alpn) { + if (param.getKey() != SvcParam::no_default_alpn && param.getKey() != SvcParam::ohttp) { d_string.append(1, '='); } @@ -942,6 +1037,24 @@ d_string = str + '"' + d_string + '"'; break; } + case SvcParam::ohttp: + // no value + break; + case SvcParam::tls_supported_groups: { + auto str = d_string; + d_string.clear(); + bool first = true; + for (auto const &group: param.getTLSSupportedGroups()) { + if (!first) { + str += ','; + } + str += std::to_string(group); + first = false; + } + d_string = std::move(str); + break; + } + case SvcParam::dohpath: default: auto str = d_string; d_string.clear(); @@ -957,7 +1070,12 @@ if(!d_string.empty()) d_string.append(1,' '); - d_string.append(val); + if (val.empty()) { + d_string.append(2, '"'); + } + else { + d_string.append(val); + } } void RecordTextWriter::xfrUnquotedText(const string& val, bool /* lenField */) diff -Nru pdns-recursor-5.2.13/rcpgenerator.hh pdns-recursor-5.4.9/rcpgenerator.hh --- pdns-recursor-5.2.13/rcpgenerator.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rcpgenerator.hh 2026-10-26 09:46:36.000000000 +0000 @@ -40,7 +40,7 @@ class RecordTextReader { public: - RecordTextReader(string str, DNSName zone=DNSName("")); + RecordTextReader(string str, ZoneName zone=ZoneName("")); void xfrNodeOrLocatorID(NodeOrLocatorID& val); void xfr64BitInt(uint64_t& val); void xfr48BitInt(uint64_t& val); @@ -55,7 +55,7 @@ void xfrCAPort(ComboAddress &val); void xfrTime(uint32_t& val); - void xfrName(DNSName& val, bool compress=false, bool noDot=false); + void xfrName(DNSName& val, bool compress=false); void xfrText(string& val, bool multi=false, bool lenField=true); void xfrUnquotedText(string& val, bool lenField=true); void xfrHexBlob(string& val, bool keepReading=false); @@ -76,8 +76,8 @@ bool eof(); private: string d_string; - DNSName d_zone; - string::size_type d_pos; + ZoneName d_zone; + string::size_type d_pos{0}; string::size_type d_end; void skipSpaces(); }; @@ -99,7 +99,7 @@ void xfrBase32HexBlob(const string& val); void xfrType(const uint16_t& val); - void xfrName(const DNSName& val, bool compress=false, bool noDot=false); + void xfrName(const DNSName& val, bool compress=false); void xfrText(const string& val, bool multi=false, bool lenField=true); void xfrUnquotedText(const string& val, bool lenField=true); void xfrBlobNoSpaces(const string& val, int len=-1); diff -Nru pdns-recursor-5.2.13/rec-carbon.cc pdns-recursor-5.4.9/rec-carbon.cc --- pdns-recursor-5.2.13/rec-carbon.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-carbon.cc 2026-10-26 08:26:51.000000000 +0000 @@ -45,10 +45,8 @@ Socket s(remote.sin4.sin_family, SOCK_STREAM); s.setNonBlocking(); std::shared_ptr tlsCtx{nullptr}; - const struct timeval timeout - { - g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000 - }; + const struct timeval timeout{ + g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000}; auto handler = std::make_shared("", false, s.releaseHandle(), timeout, tlsCtx); handler->tryConnect(SyncRes::s_tcp_fast_open_connect, remote); // we do the connect so the first attempt happens while we gather stats @@ -67,27 +65,22 @@ auto ret = asendtcp(msg, handler); // this will actually do the right thing waiting on the connect if (ret == LWResult::Result::Timeout) { - SLOG(g_log << Logger::Warning << "Timeout connecting/writing carbon data to " << remote.toStringWithPort() << endl, - log->info(Logr::Warning, "Timeout connecting/writing carbon data", "address", Logging::Loggable(remote))); + log->info(Logr::Warning, "Timeout connecting/writing carbon data", "address", Logging::Loggable(remote)); } else if (ret != LWResult::Result::Success) { int err = errno; - SLOG(g_log << Logger::Warning << "Error writing carbon data to " << remote.toStringWithPort() << ": " << stringerror(err) << endl, - log->error(Logr::Warning, err, "Error writing carbon data", "address", Logging::Loggable(remote))); + log->error(Logr::Warning, err, "Error writing carbon data", "address", Logging::Loggable(remote)); } handler->close(); } } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error in carbon thread: " << e.reason << endl, - log->error(Logr::Error, e.reason, "Error in carbon thread", "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Error, e.reason, "Error in carbon thread", "exception", Logging::Loggable("PDNSException")); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error in carbon thread: " << e.what() << endl, - log->error(Logr::Error, e.what(), "Error in carbon thread", "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Error, e.what(), "Error in carbon thread", "exception", Logging::Loggable("std::exception")); } catch (...) { - SLOG(g_log << Logger::Error << "Unknown error in carbon thread" << endl, - log->info(Logr::Error, "Error in carbon thread")); + log->info(Logr::Error, "Error in carbon thread"); } } diff -Nru pdns-recursor-5.2.13/rec-cookiestore.cc pdns-recursor-5.4.9/rec-cookiestore.cc --- pdns-recursor-5.2.13/rec-cookiestore.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-cookiestore.cc 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * 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 "misc.hh" +#include "rec-cookiestore.hh" + +void CookieStore::prune(time_t cutoff) +{ + auto& ind = get(); + ind.erase(ind.begin(), ind.upper_bound(cutoff)); +} + +uint64_t CookieStore::dump(int fileDesc) const +{ + int newfd = dup(fileDesc); + if (newfd == -1) { + return 0; + } + auto filePtr = pdns::UniqueFilePtr(fdopen(newfd, "w")); + if (!filePtr) { + close(newfd); + return 0; + } + uint64_t theCount = 0; + + fprintf(filePtr.get(), "; cookie dump follows\n; server\tlocal\tcookie\tsupport\tts\n"); + for (const auto& entry : *this) { + theCount++; + timebuf_t tmp; + fprintf(filePtr.get(), "%s\t%s\t%s\t%s\t%s\n", + entry.d_address.toStringWithPortExcept(53).c_str(), + entry.d_localaddress.isUnspecified() ? "-" : entry.d_localaddress.toString().c_str(), + entry.d_support == CookieEntry::Support::Unsupported ? "-" : entry.d_cookie.toDisplayString().c_str(), + CookieEntry::toString(entry.d_support).c_str(), + entry.d_lastused == std::numeric_limits::max() ? "Forever" : timestamp(entry.d_lastused, tmp)); + } + return theCount; +} diff -Nru pdns-recursor-5.2.13/rec-cookiestore.hh pdns-recursor-5.4.9/rec-cookiestore.hh --- pdns-recursor-5.2.13/rec-cookiestore.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-cookiestore.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * 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 + +/* + CookieStore is used to keep track of client cookies used for contacting authoritative servers. + According to RFC 7873 and RFC 9018, it has the following design. + + - Cookies are stored with an auth IP:port address as primary index and are generated randomly. + + - If an auth does not support cookies, it is marked as such and no cookies will be sent to it + for a period of time. When a cookie is sent again, it must be a newly generated one. + + - A cookie is stored together with the local IP (as rec can have many). If an auth is to be + contacted again, it should use the same bound IP. + + - Although it is perfectly fine for a client cookie to live for a long time, this design will + flush entries older that a certain period of time, to avoid an ever growing CookieStore. +*/ + +#include +#include +#include +#include +#include +#include + +#include "iputils.hh" +#include "ednscookies.hh" + +using namespace ::boost::multi_index; + +struct CookieEntry +{ + enum class Support : uint8_t + { + Unsupported, + Supported, + Probing + }; + + static std::string toString(Support support) + { + static const std::array names = { + "Unsupported", + "Supported", + "Probing"}; + const auto index = static_cast(support); + if (index >= names.size()) { + return "?"; + } + return names.at(index); + } + + Support getSupport() const + { + return d_support; + } + + void setSupport(Support support, time_t now) const // modifying mutable field + { + d_lastused = now; + d_support = support; + } + + bool supported() const + { + return d_support == Support::Supported; + } + + ComboAddress d_address; + mutable ComboAddress d_localaddress; // The address we were bound to, see RFC 9018 + mutable EDNSCookiesOpt d_cookie; // Contains both client and server cookie + mutable time_t d_lastused{}; + mutable Support d_support{Support::Unsupported}; +}; + +class CookieStore : public multi_index_container, member>, + ordered_non_unique, member>>> +{ +public: + void prune(time_t cutoff); + [[nodiscard]] uint64_t dump(int fileDesc) const; +}; diff -Nru pdns-recursor-5.2.13/rec-eventtrace.cc pdns-recursor-5.4.9/rec-eventtrace.cc --- pdns-recursor-5.2.13/rec-eventtrace.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-eventtrace.cc 2026-10-26 08:26:51.000000000 +0000 @@ -21,10 +21,7 @@ */ #include "rec-eventtrace.hh" -#define NameEntry(M) \ - { \ - M, #M \ - } +#define NameEntry(M) {M, #M} const std::unordered_map RecEventTrace::s_eventNames = { NameEntry(CustomEvent), @@ -41,4 +38,112 @@ NameEntry(LuaPostResolve), NameEntry(LuaNoData), NameEntry(LuaNXDomain), - NameEntry(LuaPostResolveFFI)}; + NameEntry(LuaPostResolveFFI), + NameEntry(AuthRequest), + NameEntry(PacketParse), + NameEntry(ProcessUDP), + NameEntry(ProcessTCP), +}; + +using namespace pdns::trace; + +static void addValue(const RecEventTrace::Entry& event, Span& work, bool start) +{ + if (std::holds_alternative(event.d_value)) { + return; + } + string key = start ? event.d_valueName : "result"; + if (std::holds_alternative(event.d_value)) { + work.attributes.emplace_back(KeyValue{std::move(key), {std::get(event.d_value)}}); + } + else if (std::holds_alternative(event.d_value)) { + work.attributes.emplace_back(KeyValue{std::move(key), {std::get(event.d_value)}}); + } + else if (std::holds_alternative(event.d_value)) { + work.attributes.emplace_back(KeyValue{std::move(key), {std::get(event.d_value)}}); + } + else { + work.attributes.emplace_back(KeyValue{std::move(key), {RecEventTrace::toString(event.d_value)}}); + } + for (const auto& [ekey, value] : event.d_extraValues) { + if (std::holds_alternative(value)) { + work.attributes.emplace_back(KeyValue{ekey, {std::get(value)}}); + } + else if (std::holds_alternative(value)) { + work.attributes.emplace_back(KeyValue{ekey, {std::get(value)}}); + } + else if (std::holds_alternative(value)) { + work.attributes.emplace_back(KeyValue{ekey, {std::get(value)}}); + } + else { + work.attributes.emplace_back(KeyValue{ekey, {RecEventTrace::toString(value)}}); + } + } +} + +// The event trace uses start-stop records which need to be mapped to OpenTelemetry Spans, which is a +// list of spans. Spans can refer to other spans as their parent. +std::vector RecEventTrace::convertToOT(const InitialSpanInfo& span) const +{ + timespec realtime{}; + clock_gettime(CLOCK_REALTIME, &realtime); + timespec monotime{}; + clock_gettime(CLOCK_MONOTONIC, &monotime); + auto diff = (1000000000ULL * realtime.tv_sec) + realtime.tv_nsec - ((1000000000ULL * monotime.tv_sec) + monotime.tv_nsec); + diff += d_base; + + std::vector ret; + ret.reserve((d_events.size() / 2) + 1); + + // The parent of all Spans + ret.emplace_back(Span{ + .trace_id = span.trace_id, + .span_id = span.span_id, + .trace_state = "", + .parent_span_id = span.parent_span_id, + .name = "RecRequest", + .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER, + .start_time_unix_nano = span.start_time_unix_nano, + .end_time_unix_nano = timestamp(), + }); + + std::vector spanIDs; // mapping of span index in ret vector to SpanID + std::map ids; // mapping from event record index to index in ret vector (Spans) + + size_t index = 0; + for (const auto& event : d_events) { + if (event.d_start) { + // It's an open event + Span work{}; + work.trace_id = span.trace_id; + work.name = RecEventTrace::toString(event.d_event); + work.start_time_unix_nano = static_cast(event.d_ts + diff); + work.end_time_unix_nano = static_cast(event.d_ts + diff); // will be updated when we process the close event + if (event.d_parent == 0 || event.d_parent >= spanIDs.size()) { + // Use the given parent + work.parent_span_id = span.span_id; + } + else { + // The parent is coming from the events we already processed + work.parent_span_id = spanIDs.at(event.d_parent); + } + // Assign a span id. + work.span_id.makeRandom(); + addValue(event, work, true); + spanIDs.emplace_back(work.span_id); + ret.emplace_back(work); + ids[index] = ret.size() - 1; + } + else { + // It's a close event + if (const auto match = ids.find(event.d_matching); match != ids.end()) { + auto& work = ret.at(match->second); + addValue(event, work, false); + work.end_time_unix_nano = static_cast(event.d_ts + diff); + spanIDs.emplace_back(work.span_id); + } + } + ++index; + } + return ret; +} diff -Nru pdns-recursor-5.2.13/rec-eventtrace.hh pdns-recursor-5.4.9/rec-eventtrace.hh --- pdns-recursor-5.2.13/rec-eventtrace.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-eventtrace.hh 2026-10-26 08:26:51.000000000 +0000 @@ -21,14 +21,13 @@ */ #pragma once -#include "namespaces.hh" #include "misc.hh" #include "noinitvector.hh" #include -#include #include #include +#include "protozero-trace.hh" class RecEventTrace { @@ -55,6 +54,11 @@ LuaNoData = 108, LuaNXDomain = 109, LuaPostResolveFFI = 110, + + AuthRequest = 120, + PacketParse = 121, + ProcessUDP = 122, + ProcessTCP = 123, }; static const std::unordered_map s_eventNames; @@ -67,7 +71,8 @@ RecEventTrace(const RecEventTrace& old) : d_events(old.d_events), d_base(old.d_base), - d_status(old.d_status) + d_status(old.d_status), + d_OTTrace(old.d_OTTrace) { // An RecEventTrace object can be copied, but the original will be marked invalid. // This is do detect (very likely) unintended modifications to the original after @@ -75,10 +80,11 @@ old.d_status = Invalid; } - RecEventTrace(RecEventTrace&& old) : + RecEventTrace(RecEventTrace&& old) noexcept : d_events(std::move(old.d_events)), d_base(old.d_base), - d_status(old.d_status) + d_status(old.d_status), + d_OTTrace(old.d_OTTrace) { // An RecEventTrace object can be moved, but the original will be marked invalid. // This is do detect (very likely) unintended modifications to the original after @@ -87,72 +93,79 @@ } RecEventTrace& operator=(const RecEventTrace& old) = delete; - RecEventTrace& operator=(RecEventTrace&& old) + RecEventTrace& operator=(RecEventTrace&& old) noexcept { d_events = std::move(old.d_events); d_base = old.d_base; d_status = old.d_status; + d_OTTrace = old.d_OTTrace; old.d_status = Invalid; return *this; } + ~RecEventTrace() = default; + // We distinguish between strings and byte arrays. Does not matter in C++, but in Go, Java etc it does - typedef std::variant Value_t; + using Value_t = std::variant; - static std::string toString(const EventType v) + static std::string toString(const EventType eventType) { - return s_eventNames.at(v); + return s_eventNames.at(eventType); } - static std::string toString(const Value_t& v) + static std::string toString(const Value_t& value) { - if (std::holds_alternative(v)) { + if (std::holds_alternative(value)) { return ""; } - else if (std::holds_alternative(v)) { - return std::to_string(std::get(v)); + if (std::holds_alternative(value)) { + return std::to_string(std::get(value)); } - else if (std::holds_alternative(v)) { - return std::to_string(std::get(v)); + if (std::holds_alternative(value)) { + return std::to_string(std::get(value)); } - else if (std::holds_alternative(v)) { - return std::get(v); + if (std::holds_alternative(value)) { + return std::get(value); } - else if (std::holds_alternative(v)) { - const PacketBuffer& p = std::get(v); - return makeHexDump(std::string(reinterpret_cast(p.data()), p.size())); + if (std::holds_alternative(value)) { + const auto& packet = std::get(value); + return makeHexDump(std::string(reinterpret_cast(packet.data()), packet.size())); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) } return "?"; } struct Entry { - Entry(Value_t&& v, EventType e, bool start, int64_t ts) : - d_value(std::move(v)), d_ts(ts), d_event(e), d_start(start) + Entry(Value_t&& value, EventType eventType, bool start, int64_t timestamp, size_t parent, size_t match) : + d_value(std::move(value)), d_ts(timestamp), d_parent(parent), d_matching(match), d_event(eventType), d_start(start) { } - Entry(Value_t&& v, const std::string& custom, bool start, int64_t ts) : - d_value(std::move(v)), d_custom(custom), d_ts(ts), d_event(CustomEvent), d_start(start) + Entry(Value_t&& value, std::string custom, bool start, int64_t timestamp, size_t parent, size_t match) : + d_value(std::move(value)), d_custom(std::move(custom)), d_ts(timestamp), d_parent(parent), d_matching(match), d_event(CustomEvent), d_start(start) { } Value_t d_value; + std::vector> d_extraValues; std::string d_custom; + std::string d_valueName{"arg"}; int64_t d_ts; + size_t d_parent; + size_t d_matching; EventType d_event; bool d_start; - std::string toString() const + [[nodiscard]] std::string toString() const { - std::string v = RecEventTrace::toString(d_value); - if (!v.empty()) { - v = "," + v; + std::string value = RecEventTrace::toString(d_value); + if (!value.empty()) { + value = "," + value; } std::string name = RecEventTrace::toString(d_event); if (d_event == EventType::CustomEvent) { name += ":" + d_custom; } - return name + "(" + std::to_string(d_ts) + v + (d_start ? ")" : ",done)"); + return name + "(" + std::to_string(d_ts) + value + (d_start ? ")" : ",done)"); } }; @@ -168,55 +181,75 @@ } template - void add(E e, Value_t&& v, bool start, int64_t stamp = 0) + size_t add(E event, Value_t&& value, bool start, size_t match, int64_t stamp = 0) { assert(d_status != Invalid); if (d_status == Disabled) { - return; + return 0; } + if (stamp == 0) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - stamp = ts.tv_nsec + ts.tv_sec * 1000000000; + struct timespec theTime{}; + clock_gettime(CLOCK_MONOTONIC, &theTime); + stamp = theTime.tv_nsec + theTime.tv_sec * 1000000000; } if (stamp < d_base) { // If we get a ts before d_base, we adjust d_base and the existing events - // This is possble if we add a kernel provided packet timestamp in the future + // This is possible if we add a kernel provided packet timestamp in the future // (Though it seems those timestamps do not use CLOCK_MONOTONIC...) const int64_t adj = d_base - stamp; - for (auto& i : d_events) { - i.d_ts += adj; + for (auto& iter : d_events) { + iter.d_ts += adj; } // and move to the new base d_base = stamp; } stamp -= d_base; - d_events.emplace_back(std::move(v), e, start, stamp); + d_events.emplace_back(std::move(value), event, start, stamp, d_parent, match); + return d_events.size() - 1; } template - void add(E e) + size_t add(E eventType) { - add(e, Value_t(std::nullopt), true); + return add(eventType, Value_t(std::nullopt), true, 0, 0); } // We store uint32 in an int64_t template - void add(E e, uint32_t v, bool start) + size_t add(E eventType, uint32_t value, bool start, size_t match) { - add(e, static_cast(v), start); + return add(eventType, static_cast(value), start, match, 0); } // We store int32 in an int64_t template - void add(E e, int32_t v, bool start) + size_t add(E eventType, int32_t value, bool start, size_t match) { - add(e, static_cast(v), start); + return add(eventType, static_cast(value), start, match, 0); } template - void add(E e, T v, bool start) + size_t add(E eventType, T value, bool start, size_t match) + { + return add(eventType, Value_t(value), start, match, 0); + } + + void setValueName(size_t index, const std::string& name) + { + assert(d_status != Invalid); + if (d_status == Disabled) { + return; + } + d_events.at(index).d_valueName = name; + } + + void addExtraValues(size_t index, std::vector>&& values) { - add(e, Value_t(v), start); + assert(d_status != Invalid); + if (d_status == Disabled) { + return; + } + d_events.at(index).d_extraValues = std::move(values); } void clear() @@ -227,9 +260,10 @@ void reset() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - d_base = ts.tv_nsec + ts.tv_sec * 1000000000; + struct timespec theTime{}; + clock_gettime(CLOCK_MONOTONIC, &theTime); + d_base = theTime.tv_nsec + theTime.tv_sec * 1000000000; + d_OTTrace = false; d_status = Disabled; } @@ -241,14 +275,14 @@ } std::string ret = "eventTrace ["; bool first = true; - for (const auto& e : d_events) { + for (const auto& event : d_events) { if (first) { first = false; } else { ret += "; "; } - ret += e.toString(); + ret += event.toString(); } ret += ']'; return ret; @@ -259,9 +293,75 @@ return d_events; } + std::vector convertToOT(const pdns::trace::InitialSpanInfo& span) const; + + size_t setParent(size_t parent) + { + size_t old = d_parent; + d_parent = parent; + return old; + } + + bool getThisOTTraceEnabled() const + { + return d_OTTrace; + } + + void setThisOTTraceEnabled() + { + d_OTTrace = true; + } + + // The EventScope class is used to close (add an end event) automatically upon the scope object + // going out of scope. It is also possible to manually close it, specifying a value to be registered + // at the close event. In that case the dt call will become a no-op. + class EventScope + { + public: + EventScope(size_t oldParent, RecEventTrace& eventTrace) : + d_eventTrace(eventTrace), + d_oldParent(oldParent) + { + if (d_eventTrace.enabled() && !d_eventTrace.d_events.empty()) { + d_event = d_eventTrace.d_events.back().d_event; + d_match = d_eventTrace.d_events.size() - 1; + } + } + + // Only int64_t for now needed, might become a template in the future. + void close(int64_t val) + { + if (!d_eventTrace.enabled() || d_closed) { + return; + } + d_eventTrace.setParent(d_oldParent); + d_eventTrace.add(d_event, val, false, d_match); + d_closed = true; + } + + ~EventScope() + { + // If the dt is called after an explicit close(), value does not matter. + // Otherwise, it signals an implicit close, e.g. an exception was thrown + close(-1); + } + EventScope(const EventScope&) = delete; + EventScope(EventScope&&) = delete; + EventScope& operator=(const EventScope&) = delete; + EventScope& operator=(EventScope&&) = delete; + + private: + RecEventTrace& d_eventTrace; + size_t d_oldParent; + size_t d_match{0}; + EventType d_event{EventType::CustomEvent}; + bool d_closed{false}; + }; + private: std::vector d_events; - int64_t d_base; + int64_t d_base{0}; + size_t d_parent{0}; enum Status : uint8_t { Disabled, @@ -269,4 +369,5 @@ Enabled }; mutable Status d_status{Disabled}; + bool d_OTTrace{false}; }; diff -Nru pdns-recursor-5.2.13/rec-lua-conf.cc pdns-recursor-5.4.9/rec-lua-conf.cc --- pdns-recursor-5.2.13/rec-lua-conf.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-lua-conf.cc 2026-10-26 08:26:51.000000000 +0000 @@ -1,20 +1,38 @@ +/* + * 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 + #include "config.h" #include "ext/luawrapper/include/LuaContext.hpp" +#include "rec-lua-conf.hh" -#include -#include #include "namespaces.hh" -#include "logger.hh" #include "lua-base4.hh" -#include "rec-lua-conf.hh" #include "sortlist.hh" #include "filterpo.hh" #include "syncres.hh" #include "rpzloader.hh" #include "base64.hh" -#include "remote_logger.hh" -#include "validate.hh" -#include "validate-recursor.hh" #include "root-dnssec.hh" #include "rec-system-resolve.hh" @@ -89,16 +107,7 @@ return !(configA == configB); } -template -typename C::value_type::second_type constGet(const C& c, const std::string& name) -{ - auto iter = c.find(name); - if (iter == c.end()) - return 0; - return iter->second; -} - -typedef std::unordered_map>>> rpzOptions_t; +using rpzOptions_t = std::unordered_map>>>; static void parseRPZParameters(const rpzOptions_t& have, RPZTrackerParams& params) { @@ -164,9 +173,9 @@ } } -typedef std::unordered_map>>> protobufOptions_t; +using protobufOptions_t = std::unordered_map>>>; -static void parseProtobufOptions(const boost::optional& vars, ProtobufExportConfig& config) +static void parseProtobufOptions(const std::optional& vars, ProtobufExportConfig& config) { if (!vars) { return; @@ -228,9 +237,9 @@ } #ifdef HAVE_FSTRM -typedef std::unordered_map>>> frameStreamOptions_t; +using frameStreamOptions_t = std::unordered_map>>>; -static void parseFrameStreamOptions(const boost::optional& vars, FrameStreamExportConfig& config) +static void parseFrameStreamOptions(const std::optional& vars, FrameStreamExportConfig& config) { if (!vars) { return; @@ -271,7 +280,7 @@ } #endif /* HAVE_FSTRM */ -static void rpzPrimary(LuaConfigItems& lci, const boost::variant>>& primaries_, const string& zoneName, const boost::optional& options) +static void rpzPrimary(LuaConfigItems& lci, const boost::variant>>& primaries_, const string& zoneName, const std::optional& options) { RPZTrackerParams params; params.zoneXFRParams.name = zoneName; @@ -289,7 +298,7 @@ try { if (options) { - auto& have = *options; + const auto& have = *options; parseRPZParameters(have, params); if (have.count("tsigname") != 0) { @@ -302,8 +311,7 @@ if (have.count("refresh") != 0) { params.zoneXFRParams.refreshFromConf = boost::get(have.at("refresh")); if (params.zoneXFRParams.refreshFromConf == 0) { - SLOG(g_log << Logger::Warning << "rpzPrimary refresh value of 0 ignored" << endl, - lci.d_slog->info(Logr::Warning, "rpzPrimary refresh value of 0 ignored")); + lci.d_slog->info(Logr::Warning, "rpzPrimary refresh value of 0 ignored"); } } @@ -340,12 +348,10 @@ lci.rpzs.emplace_back(params); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Problem configuring 'rpzPrimary': " << e.what() << endl, - lci.d_slog->error(Logr::Error, e.what(), "Exception configuring 'rpzPrimary'", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, e.what(), "Exception configuring 'rpzPrimary'", "exception", Logging::Loggable("std::exception")); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Problem configuring 'rpzPrimary': " << e.reason << endl, - lci.d_slog->error(Logr::Error, e.reason, "Exception configuring 'rpzPrimary'", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, e.reason, "Exception configuring 'rpzPrimary'", Logging::Loggable("PDNSException")); } } @@ -361,13 +367,13 @@ void postPrepareContext() override { // clang-format off - d_pd.push_back({"AdditionalMode", in_t{ + d_pd.emplace_back("AdditionalMode", in_t{ {"Ignore", static_cast(AdditionalMode::Ignore)}, {"CacheOnly", static_cast(AdditionalMode::CacheOnly)}, {"CacheOnlyRequireAuth", static_cast(AdditionalMode::CacheOnlyRequireAuth)}, {"ResolveImmediately", static_cast(AdditionalMode::ResolveImmediately)}, {"ResolveDeferred", static_cast(AdditionalMode::ResolveDeferred)} - }}); + }); } void postLoad() override { @@ -387,11 +393,13 @@ RecLuaConfigContext Lua; - if (fname.empty()) + if (fname.empty()) { return; + } ifstream ifs(fname); - if (!ifs) + if (!ifs) { throw PDNSException("Cannot open file '" + fname + "': " + stringerror()); + } auto luaconfsLocal = g_luaconfs.getLocal(); lci.generation = luaconfsLocal->generation + 1; @@ -412,7 +420,8 @@ {"Custom", DNSFilterEngine::PolicyKind::Custom}}; Lua->writeVariable("Policy", pmap); - Lua->writeFunction("rpzFile", [&lci](const string& filename, boost::optional options) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("rpzFile", [&lci](const string& filename, std::optional options) { RPZTrackerParams params; params.zoneXFRParams.name = filename; params.polName = "rpzFile"; @@ -422,25 +431,22 @@ lci.rpzs.emplace_back(params); }); - Lua->writeFunction("rpzMaster", [&lci](const boost::variant>>& primaries_, const string& zoneName, const boost::optional& options) { - SLOG(g_log << Logger::Warning << "'rpzMaster' is deprecated and will be removed in a future release, use 'rpzPrimary' instead" << endl, - lci.d_slog->info(Logr::Warning, "'rpzMaster' is deprecated and will be removed in a future release, use 'rpzPrimary' instead")); - rpzPrimary(lci, primaries_, zoneName, options); - }); - Lua->writeFunction("rpzPrimary", [&lci](const boost::variant>>& primaries_, const string& zoneName, const boost::optional& options) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("rpzPrimary", [&lci](const boost::variant>>& primaries_, const string& zoneName, std::optional options) { rpzPrimary(lci, primaries_, zoneName, options); }); - typedef std::unordered_map> zoneToCacheOptions_t; + using zoneToCacheOptions_t = std::unordered_map>; - Lua->writeFunction("zoneToCache", [&lci](const string& zoneName, const string& method, const boost::variant>>& srcs, boost::optional options) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("zoneToCache", [&lci](const string& zoneName, const string& method, const boost::variant>>& srcs, std::optional options) { try { RecZoneToCache::Config conf; DNSName validZoneName(zoneName); conf.d_zone = zoneName; const set methods = {"axfr", "url", "file"}; if (methods.count(method) == 0) { - throw std::runtime_error("unknwon method '" + method + "'"); + throw std::runtime_error("unknown method '" + method + "'"); } conf.d_method = method; if (srcs.type() == typeid(std::string)) { @@ -468,7 +474,7 @@ } if (have.count("maxReceivedMBytes")) { conf.d_maxReceivedBytes = static_cast(boost::get(have.at("maxReceivedMBytes"))); - conf.d_maxReceivedBytes *= 1024 * 1024; + conf.d_maxReceivedBytes *= static_cast(1024 * 1024); } if (have.count("localAddress")) { conf.d_local = ComboAddress(boost::get(have.at("localAddress"))); @@ -486,114 +492,97 @@ }; if (have.count("zonemd")) { string zonemdValidation = boost::get(have.at("zonemd")); - auto it = nameToVal.find(zonemdValidation); - if (it == nameToVal.end()) { + auto iter = nameToVal.find(zonemdValidation); + if (iter == nameToVal.end()) { throw std::runtime_error(zonemdValidation + " is not a valid value for `zonemd`"); } - else { - conf.d_zonemd = it->second; - } + conf.d_zonemd = iter->second; } if (have.count("dnssec")) { string dnssec = boost::get(have.at("dnssec")); - auto it = nameToVal.find(dnssec); - if (it == nameToVal.end()) { + auto iter = nameToVal.find(dnssec); + if (iter == nameToVal.end()) { throw std::runtime_error(dnssec + " is not a valid value for `dnssec`"); } - else { - conf.d_dnssec = it->second; - } + conf.d_dnssec = iter->second; } } lci.ztcConfigs[validZoneName] = std::move(conf); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Problem configuring zoneToCache for zone '" << zoneName << "': " << e.what() << endl, - lci.d_slog->error(Logr::Error, e.what(), "Problem configuring zoneToCache", "zone", Logging::Loggable(zoneName), - "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, e.what(), "Problem configuring zoneToCache", "zone", Logging::Loggable(zoneName), + "exception", Logging::Loggable("std::exception")); } }); - typedef vector>>>> argvec_t; + using argvec_t = vector>>>>; Lua->writeFunction("addSortList", [&lci](const std::string& formask_, const boost::variant& masks, - boost::optional order_) { + std::optional order_) { try { Netmask formask(formask_); int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask) + 1; - if (auto str = boost::get(&masks)) + if (const auto *str = boost::get(&masks)) { lci.sortlist.addEntry(formask, Netmask(*str), order); + } else { - auto vec = boost::get(&masks); - for (const auto& e : *vec) { - if (auto s = boost::get(&e.second)) { - lci.sortlist.addEntry(formask, Netmask(*s), order); + const auto *vec = boost::get(&masks); + for (const auto& vecentry : *vec) { + if (const auto *value = boost::get(&vecentry.second)) { + lci.sortlist.addEntry(formask, Netmask(*value), order); } else { - const auto& v = boost::get>>(e.second); - for (const auto& entry : v) + const auto& entries = boost::get>>(vecentry.second); + for (const auto& entry : entries) { lci.sortlist.addEntry(formask, Netmask(entry.second), order); + } } ++order; } } } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error in addSortList: " << e.what() << endl, - lci.d_slog->error(Logr::Error, e.what(), "Error in addSortList", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, e.what(), "Error in addSortList", "exception", Logging::Loggable("std::exception")); } }); Lua->writeFunction("addTA", [&lci](const std::string& who, const std::string& what) { DNSName zone(who); - auto ds = std::dynamic_pointer_cast(DSRecordContent::make(what)); - lci.dsAnchors[zone].insert(*ds); - }); - - Lua->writeFunction("clearTA", [&lci](boost::optional who) { - if (who) - lci.dsAnchors.erase(DNSName(*who)); - else - lci.dsAnchors.clear(); - }); - - /* Remove in 4.3 */ - Lua->writeFunction("addDS", [&lci](const std::string& who, const std::string& what) { - SLOG(g_log << Logger::Warning << "addDS is deprecated and will be removed in the future, switch to addTA" << endl, - lci.d_slog->info(Logr::Warning, "addDS is deprecated and will be removed in the future, switch to addTA")); - DNSName zone(who); - auto ds = std::dynamic_pointer_cast(DSRecordContent::make(what)); - lci.dsAnchors[zone].insert(*ds); + auto dsRecordContent = std::dynamic_pointer_cast(DSRecordContent::make(what)); + lci.dsAnchors[zone].insert(*dsRecordContent); }); - /* Remove in 4.3 */ - Lua->writeFunction("clearDS", [&lci](boost::optional who) { - SLOG(g_log << Logger::Warning << "clearDS is deprecated and will be removed in the future, switch to clearTA" << endl, - lci.d_slog->info(Logr::Warning, "clearDS is deprecated and will be removed in the future, switch to clearTA")); - if (who) + Lua->writeFunction("clearTA", [&lci](std::optional who) { + if (who) { lci.dsAnchors.erase(DNSName(*who)); - else + } + else { lci.dsAnchors.clear(); + } }); - Lua->writeFunction("addNTA", [&lci](const std::string& who, const boost::optional why) { - if (why) + Lua->writeFunction("addNTA", [&lci](const std::string& who, std::optional why) { + if (why) { lci.negAnchors[DNSName(who)] = static_cast(*why); - else + } + else { lci.negAnchors[DNSName(who)] = ""; + } }); - Lua->writeFunction("clearNTA", [&lci](boost::optional who) { - if (who) + Lua->writeFunction("clearNTA", [&lci](std::optional who) { + if (who) { lci.negAnchors.erase(DNSName(*who)); - else + } + else { lci.negAnchors.clear(); + } }); - Lua->writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fnamearg, const boost::optional interval) { + Lua->writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fnamearg, std::optional interval) { uint32_t realInterval = 24; if (interval) { realInterval = static_cast(*interval); @@ -607,7 +596,8 @@ lci.protobufMaskV6 = maskV6; }); - Lua->writeFunction("protobufServer", [&lci](boost::variant> servers, boost::optional vars) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("protobufServer", [&lci](boost::variant> servers, std::optional vars) { if (!lci.protobufExportConfig.enabled) { lci.protobufExportConfig.enabled = true; @@ -628,21 +618,19 @@ parseProtobufOptions(vars, lci.protobufExportConfig); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error while adding protobuf logger: " << e.what() << endl, - lci.d_slog->error(Logr::Error, e.what(), "Exception while adding protobuf logger", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, e.what(), "Exception while adding protobuf logger", "exception", Logging::Loggable("std::exception")); } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Error while adding protobuf logger: " << e.reason << endl, - lci.d_slog->error(Logr::Error, e.reason, "Exception while adding protobuf logger", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, e.reason, "Exception while adding protobuf logger", "exception", Logging::Loggable("PDNSException")); } } else { - SLOG(g_log << Logger::Error << "Only one protobufServer() directive can be configured, we already have " << lci.protobufExportConfig.servers.at(0).toString() << endl, - lci.d_slog->info(Logr::Error, "Only one protobufServer() directive can be configured", "existing", Logging::Loggable(lci.protobufExportConfig.servers.at(0).toString()))); + lci.d_slog->info(Logr::Error, "Only one protobufServer() directive can be configured", "existing", Logging::Loggable(lci.protobufExportConfig.servers.at(0).toString())); } }); - Lua->writeFunction("outgoingProtobufServer", [&lci](boost::variant> servers, boost::optional vars) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("outgoingProtobufServer", [&lci](boost::variant> servers, std::optional vars) { if (!lci.outgoingProtobufExportConfig.enabled) { lci.outgoingProtobufExportConfig.enabled = true; @@ -663,22 +651,20 @@ parseProtobufOptions(vars, lci.outgoingProtobufExportConfig); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error while starting outgoing protobuf logger: " << e.what() << endl, - lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("std::exception")); } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Error while starting outgoing protobuf logger: " << e.reason << endl, - lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, "Exception while starting outgoing protobuf logger", "exception", Logging::Loggable("PDNSException")); } } else { - SLOG(g_log << Logger::Error << "Only one outgoingProtobufServer() directive can be configured, we already have " << lci.outgoingProtobufExportConfig.servers.at(0).toString() << endl, - lci.d_slog->info(Logr::Error, "Only one outgoingProtobufServer() directive can be configured", "existing", Logging::Loggable(lci.outgoingProtobufExportConfig.servers.at(0).toString()))); + lci.d_slog->info(Logr::Error, "Only one outgoingProtobufServer() directive can be configured", "existing", Logging::Loggable(lci.outgoingProtobufExportConfig.servers.at(0).toString())); } }); #ifdef HAVE_FSTRM - Lua->writeFunction("dnstapFrameStreamServer", [&lci](boost::variant> servers, boost::optional vars) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("dnstapFrameStreamServer", [&lci](boost::variant> servers, std::optional vars) { if (!lci.frameStreamExportConfig.enabled) { lci.frameStreamExportConfig.enabled = true; @@ -701,20 +687,18 @@ parseFrameStreamOptions(vars, lci.frameStreamExportConfig); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error reading config for dnstap framestream logger: " << e.what() << endl, - lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("std::exception")); } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Error reading config for dnstap framestream logger: " << e.reason << endl, - lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, "Exception reading config for dnstap framestream logger", "exception", Logging::Loggable("PDNSException")); } } else { - SLOG(g_log << Logger::Error << "Only one dnstapFrameStreamServer() directive can be configured, we already have " << lci.frameStreamExportConfig.servers.at(0) << endl, - lci.d_slog->info(Logr::Error, "Only one dnstapFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.frameStreamExportConfig.servers.at(0)))); + lci.d_slog->info(Logr::Error, "Only one dnstapFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.frameStreamExportConfig.servers.at(0))); } }); - Lua->writeFunction("dnstapNODFrameStreamServer", [&lci](boost::variant> servers, boost::optional vars) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("dnstapNODFrameStreamServer", [&lci](boost::variant> servers, std::optional vars) { if (!lci.nodFrameStreamExportConfig.enabled) { lci.nodFrameStreamExportConfig.enabled = true; @@ -736,22 +720,20 @@ parseFrameStreamOptions(vars, lci.nodFrameStreamExportConfig); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error reading config for dnstap NOD framestream logger: " << e.what() << endl, - lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("std::exception")); } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Error reading config for dnstap NOD framestream logger: " << e.reason << endl, - lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, "Exception reading config for dnstap NOD framestream logger", "exception", Logging::Loggable("PDNSException")); } } else { - SLOG(g_log << Logger::Error << "Only one dnstapNODFrameStreamServer() directive can be configured, we already have " << lci.nodFrameStreamExportConfig.servers.at(0) << endl, - lci.d_slog->info(Logr::Error, "Only one dnstapNODFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.nodFrameStreamExportConfig.servers.at(0)))); + lci.d_slog->info(Logr::Error, "Only one dnstapNODFrameStreamServer() directive can be configured", "existing", Logging::Loggable(lci.nodFrameStreamExportConfig.servers.at(0))); } }); #endif /* HAVE_FSTRM */ - Lua->writeFunction("addAllowedAdditionalQType", [&lci](int qtype, std::unordered_map targetqtypes, boost::optional> options) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("addAllowedAdditionalQType", [&lci](int qtype, const std::unordered_map& targetqtypes, std::optional> options) { switch (qtype) { case QType::MX: case QType::SRV: @@ -760,78 +742,71 @@ case QType::NAPTR: break; default: - SLOG(g_log << Logger::Error << "addAllowedAdditionalQType does not support " << QType(qtype).toString() << endl, - lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType does not support this qtype", "qtype", Logging::Loggable(QType(qtype).toString()))); + lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType does not support this qtype", "qtype", Logging::Loggable(QType(qtype).toString())); return; } std::set targets; - for (const auto& t : targetqtypes) { - targets.emplace(QType(t.second)); + for (const auto& target : targetqtypes) { + targets.emplace(target.second); } AdditionalMode mode = AdditionalMode::CacheOnlyRequireAuth; // Always cheap and should be safe if (options) { - if (const auto it = options->find("mode"); it != options->end()) { - mode = static_cast(it->second); + if (const auto iter = options->find("mode"); iter != options->end()) { + mode = static_cast(iter->second); if (mode > AdditionalMode::ResolveDeferred) { - SLOG(g_log << Logger::Error << "addAllowedAdditionalQType: unknown mode " << it->second << endl, - lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType: unknown mode", "mode", Logging::Loggable( it->second))); + lci.d_slog->info(Logr::Error, "addAllowedAdditionalQType: unknown mode", "mode", Logging::Loggable( iter->second)); } } } lci.allowAdditionalQTypes.insert_or_assign(qtype, pair(targets, mode)); }); - Lua->writeFunction("addProxyMapping", [&proxyMapping,&lci](const string& netmaskArg, const string& addressArg, boost::optional>> smnStrings) { + // NOLINTNEXTLINE(performance-unnecessary-value-param) Lua wrapper does not handle optional & + Lua->writeFunction("addProxyMapping", [&proxyMapping,&lci](const string& netmaskArg, const string& addressArg, std::optional>> smnStrings) { try { Netmask netmask(netmaskArg); ComboAddress address(addressArg); - boost::optional smn; + std::optional smn; if (smnStrings) { - smn = boost::make_optional(SuffixMatchNode{}); - for (const auto& el : *smnStrings) { - smn->add(el.second); + smn = std::make_optional(SuffixMatchNode{}); + for (const auto& subnet : *smnStrings) { + smn->add(subnet.second); } } - proxyMapping.insert_or_assign(netmask, {address, smn}); + proxyMapping.insert_or_assign(netmask, {std::move(address), std::move(smn)}); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Error processing addProxyMapping: " << e.what() << endl, - lci.d_slog->error(Logr::Error, e.what(), "Exception processing addProxyMapping", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, e.what(), "Exception processing addProxyMapping", "exception", Logging::Loggable("std::exception")); } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Error processing addProxyMapping: " << e.reason << endl, - lci.d_slog->error(Logr::Error, e.reason, "Exception processing addProxyMapping", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, e.reason, "Exception processing addProxyMapping", "exception", Logging::Loggable("PDNSException")); } }); try { Lua->executeCode(ifs); - newLuaConfig = lci; + newLuaConfig = std::move(lci); } catch (const LuaContext::ExecutionErrorException& e) { - SLOG(g_log << Logger::Error << "Unable to load Lua script from '" + fname + "': ", - lci.d_slog->error(Logr::Error, e.what(), "Unable to load Lua script", "file", Logging::Loggable(fname))); + lci.d_slog->error(Logr::Error, e.what(), "Unable to load Lua script", "file", Logging::Loggable(fname)); try { std::rethrow_if_nested(e); } catch (const std::exception& exp) { // exp is the exception that was thrown from inside the lambda - SLOG(g_log << exp.what() << std::endl, - lci.d_slog->error(Logr::Error, exp.what(), "Exception loading Lua", "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, exp.what(), "Exception loading Lua", "exception", Logging::Loggable("std::exception")); } catch (const PDNSException& exp) { // exp is the exception that was thrown from inside the lambda - SLOG(g_log << exp.reason << std::endl, - lci.d_slog->error(Logr::Error, exp.reason, "Exception loading Lua", "exception", Logging::Loggable("PDNSException"))); + lci.d_slog->error(Logr::Error, exp.reason, "Exception loading Lua", "exception", Logging::Loggable("PDNSException")); } throw; } catch (std::exception& err) { - SLOG(g_log << Logger::Error << "Unable to load Lua script from '" + fname + "': " << err.what() << endl, - lci.d_slog->error(Logr::Error, err.what(), "Unable to load Lua script", "file", Logging::Loggable(fname), "exception", Logging::Loggable("std::exception"))); + lci.d_slog->error(Logr::Error, err.what(), "Unable to load Lua script", "file", Logging::Loggable(fname), "exception", Logging::Loggable("std::exception")); throw; } } diff -Nru pdns-recursor-5.2.13/rec-lua-conf.hh pdns-recursor-5.4.9/rec-lua-conf.hh --- pdns-recursor-5.2.13/rec-lua-conf.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-lua-conf.hh 2026-10-26 08:26:51.000000000 +0000 @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once + #include #include @@ -28,8 +29,6 @@ #include "filterpo.hh" #include "validate.hh" #include "rec-zonetocache.hh" -#include "logging.hh" -#include "fstrm_logger.hh" #include "rpzloader.hh" struct ProtobufExportConfig @@ -93,12 +92,23 @@ struct ProxyByTableValue { ComboAddress address; - boost::optional suffixMatchNode; + std::optional suffixMatchNode; mutable ProxyMappingCounts stats{}; }; using ProxyMapping = NetmaskTree; +struct OpenTelemetryTraceCondition +{ + std::optional d_qnames; + std::optional> d_qtypes; + std::optional d_qid; + bool d_edns_option_required{false}; + bool d_traceid_only{false}; +}; + +using OpenTelemetryTraceConditions = NetmaskTree; + using rpzOptions_t = std::unordered_map>>>; class LuaConfigItems diff -Nru pdns-recursor-5.2.13/rec-main.cc pdns-recursor-5.4.9/rec-main.cc --- pdns-recursor-5.2.13/rec-main.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-main.cc 2026-10-26 08:26:51.000000000 +0000 @@ -38,12 +38,13 @@ #include "rec-taskqueue.hh" #include "secpoll-recursor.hh" #include "logging.hh" -#include "dnsseckeeper.hh" -#include "settings/cxxsettings.hh" +#include "dnssec.hh" +#include "rec-rust-lib/cxxsettings.hh" #include "json.hh" #include "rec-system-resolve.hh" #include "root-dnssec.hh" #include "ratelimitedlog.hh" +#include "rec-rust-lib/rust/web.rs.h" #ifdef NOD_ENABLED #include "nod.hh" @@ -68,17 +69,7 @@ thread_local FrameStreamServersInfo t_nodFrameStreamServersInfo; #endif /* HAVE_FSTRM */ -/* 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 -#if __has_feature(address_sanitizer) -#define __SANITIZE_ADDRESS__ 1 -#endif -#endif +#include "sanitizer.hh" string g_programname = "pdns_recursor"; string g_pidfname; @@ -105,16 +96,16 @@ std::atomic statsWanted; uint32_t g_disthashseed; bool g_useIncomingECS; -NetmaskGroup g_proxyProtocolACL; -std::set g_proxyProtocolExceptions; -boost::optional g_dns64Prefix{boost::none}; +static shared_ptr g_initialProxyProtocolACL; +static shared_ptr> g_initialProxyProtocolExceptions; +std::optional g_dns64Prefix{std::nullopt}; DNSName g_dns64PrefixReverse; unsigned int g_maxChainLength; -std::shared_ptr g_initialDomainMap; // new threads needs this to be setup -std::shared_ptr g_initialAllowFrom; // new thread needs to be setup with this -std::shared_ptr g_initialAllowNotifyFrom; // new threads need this to be setup -std::shared_ptr g_initialAllowNotifyFor; // new threads need this to be setup -bool g_logRPZChanges{false}; +LockGuarded> g_initialDomainMap; // new threads needs this to be setup +LockGuarded> g_initialAllowFrom; // new thread needs to be setup with this +LockGuarded> g_initialAllowNotifyFrom; // new threads need this to be setup +LockGuarded> g_initialAllowNotifyFor; // new threads need this to be setup +LockGuarded> g_initialOpenTelemetryConditions; // new threads need this to be setup static time_t s_statisticsInterval; static std::atomic s_counter; int g_argc; @@ -130,8 +121,7 @@ static deferredAdd_t s_deferredUDPadds; static deferredAdd_t s_deferredTCPadds; -/* first we have the handler thread, t_id == 0 (some other - helper threads like SNMP might have t_id == 0 as well) +/* first we have the handler thread, t_id == 0 (threads not created as a RecursorThread have t_id = NOT_INITED) then the distributor threads if any and finally the workers */ std::vector RecThreadInfo::s_threadInfos; @@ -139,11 +129,13 @@ std::unique_ptr g_proxyMapping; // new threads needs this to be setup thread_local std::unique_ptr t_proxyMapping; +thread_local std::unique_ptr t_OTConditions; + bool RecThreadInfo::s_weDistributeQueries; // if true, 1 or more threads listen on the incoming query sockets and distribute them to workers unsigned int RecThreadInfo::s_numDistributorThreads; unsigned int RecThreadInfo::s_numUDPWorkerThreads; unsigned int RecThreadInfo::s_numTCPWorkerThreads; -thread_local unsigned int RecThreadInfo::t_id; +thread_local unsigned int RecThreadInfo::t_id{RecThreadInfo::TID_NOT_INITED}; pdns::RateLimitedLog g_rateLimitedLogger; @@ -156,8 +148,7 @@ const std::string value = ::arg()["cpu-map"]; if (!value.empty() && !isSettingThreadCPUAffinitySupported()) { - SLOG(g_log << Logger::Warning << "CPU mapping requested but not supported, skipping" << endl, - log->info(Logr::Warning, "CPU mapping requested but not supported, skipping")); + log->info(Logr::Warning, "CPU mapping requested but not supported, skipping"); return result; } @@ -187,8 +178,7 @@ } } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error parsing cpu-map entry '" << part << "': " << e.what() << endl, - log->error(Logr::Error, e.what(), "Error parsing cpu-map entry", "entry", Logging::Loggable(part))); + log->error(Logr::Error, e.what(), "Error parsing cpu-map entry", "entry", Logging::Loggable(part)); } } @@ -203,28 +193,10 @@ } int ret = mapThreadToCPUList(tid, cpuMapping->second); if (ret == 0) { - if (!g_slogStructured) { - g_log << Logger::Info << "CPU affinity for thread " << n << " has been set to CPU map:"; - for (const auto cpu : cpuMapping->second) { - g_log << Logger::Info << " " << cpu; - } - g_log << Logger::Info << endl; - } - else { - log->info(Logr::Info, "CPU affinity has been set", "thread", Logging::Loggable(n), "cpumap", Logging::IterLoggable(cpuMapping->second.begin(), cpuMapping->second.end())); - } + log->info(Logr::Info, "CPU affinity has been set", "thread", Logging::Loggable(n), "cpumap", Logging::IterLoggable(cpuMapping->second.begin(), cpuMapping->second.end())); } else { - if (!g_slogStructured) { - g_log << Logger::Warning << "Error setting CPU affinity for thread " << n << " to CPU map:"; - for (const auto cpu : cpuMapping->second) { - g_log << Logger::Info << " " << cpu; - } - g_log << Logger::Info << ' ' << stringerror(ret) << endl; - } - else { - log->error(Logr::Warning, ret, "Error setting CPU affinity", "thread", Logging::Loggable(n), "cpumap", Logging::IterLoggable(cpuMapping->second.begin(), cpuMapping->second.end())); - } + log->error(Logr::Warning, ret, "Error setting CPU affinity", "thread", Logging::Loggable(n), "cpumap", Logging::IterLoggable(cpuMapping->second.begin(), cpuMapping->second.end())); } } @@ -248,8 +220,7 @@ const auto cpusMap = parseCPUMap(log); if (RecThreadInfo::numDistributors() + RecThreadInfo::numUDPWorkers() == 1) { - SLOG(g_log << Logger::Warning << "Operating with single UDP distributor/worker thread" << endl, - log->info(Logr::Notice, "Operating with single UDP distributor/worker thread")); + log->info(Logr::Notice, "Operating with single UDP distributor/worker thread"); /* This thread handles the web server, carbon, statistics and the control channel */ unsigned int currentThreadId = 0; @@ -272,6 +243,10 @@ taskInfo.start(currentThreadId, "task", cpusMap, log); } + if (::arg().mustDo("webserver")) { + serveRustWeb(); + } + currentThreadId = 1; auto& info = RecThreadInfo::info(currentThreadId); info.setListener(); @@ -279,10 +254,9 @@ RecThreadInfo::setThreadId(currentThreadId); recursorThread(); - for (unsigned int thread = 0; thread < RecThreadInfo::numRecursorThreads(); thread++) { - if (thread == 1) { - continue; - } + // Skip handler thread (it might be still handling the quit-nicely) and 1, which is actually the main thread in this case; + // handler thread (0) will be handled in main(). + for (unsigned int thread = 2; thread < RecThreadInfo::numRecursorThreads(); thread++) { auto& tInfo = RecThreadInfo::info(thread); tInfo.thread.join(); if (tInfo.exitCode != 0) { @@ -316,23 +290,20 @@ // And now start the actual threads currentThreadId = 1; if (RecThreadInfo::weDistributeQueries()) { - SLOG(g_log << Logger::Warning << "Launching " << RecThreadInfo::numDistributors() << " distributor threads" << endl, - log->info(Logr::Notice, "Launching distributor threads", "count", Logging::Loggable(RecThreadInfo::numDistributors()))); + log->info(Logr::Notice, "Launching distributor threads", "count", Logging::Loggable(RecThreadInfo::numDistributors())); for (unsigned int thread = 0; thread < RecThreadInfo::numDistributors(); thread++, currentThreadId++) { auto& info = RecThreadInfo::info(currentThreadId); info.start(currentThreadId, "distr", cpusMap, log); } } - SLOG(g_log << Logger::Warning << "Launching " << RecThreadInfo::numUDPWorkers() << " worker threads" << endl, - log->info(Logr::Notice, "Launching worker threads", "count", Logging::Loggable(RecThreadInfo::numUDPWorkers()))); + log->info(Logr::Notice, "Launching worker threads", "count", Logging::Loggable(RecThreadInfo::numUDPWorkers())); for (unsigned int thread = 0; thread < RecThreadInfo::numUDPWorkers(); thread++, currentThreadId++) { auto& info = RecThreadInfo::info(currentThreadId); info.start(currentThreadId, "worker", cpusMap, log); } - SLOG(g_log << Logger::Warning << "Launching " << RecThreadInfo::numTCPWorkers() << " tcpworker threads" << endl, - log->info(Logr::Notice, "Launching tcpworker threads", "count", Logging::Loggable(RecThreadInfo::numTCPWorkers()))); + log->info(Logr::Notice, "Launching tcpworker threads", "count", Logging::Loggable(RecThreadInfo::numTCPWorkers())); for (unsigned int thread = 0; thread < RecThreadInfo::numTCPWorkers(); thread++, currentThreadId++) { auto& info = RecThreadInfo::info(currentThreadId); @@ -350,7 +321,14 @@ info.setHandler(); info.start(currentThreadId, "web+stat", cpusMap, log); + if (::arg().mustDo("webserver")) { + serveRustWeb(); + } for (auto& tInfo : RecThreadInfo::infos()) { + // who handles the handler? the caller! + if (tInfo.isHandler()) { + continue; + } tInfo.thread.join(); if (tInfo.exitCode != 0) { ret = tInfo.exitCode; @@ -364,8 +342,7 @@ { auto pipeBufferSize = ::arg().asNum("distribution-pipe-buffer-size"); if (pipeBufferSize > 0) { - SLOG(g_log << Logger::Info << "Resizing the buffer of the distribution pipe to " << pipeBufferSize << endl, - log->info(Logr::Info, "Resizing the buffer of the distribution pipe", "size", Logging::Loggable(pipeBufferSize))); + log->info(Logr::Info, "Resizing the buffer of the distribution pipe", "size", Logging::Loggable(pipeBufferSize)); } /* thread 0 is the handler / SNMP, worker threads start at 1 */ @@ -402,12 +379,10 @@ if (pipeBufferSize > 0) { if (!setPipeBufferSize(threadInfo.pipes.writeQueriesToThread, pipeBufferSize)) { int err = errno; - SLOG(g_log << Logger::Warning << "Error resizing the buffer of the distribution pipe for thread " << thread << " to " << pipeBufferSize << ": " << stringerror(err) << endl, - log->error(Logr::Warning, err, "Error resizing the buffer of the distribution pipe for thread", "thread", Logging::Loggable(thread), "size", Logging::Loggable(pipeBufferSize))); + log->error(Logr::Warning, err, "Error resizing the buffer of the distribution pipe for thread", "thread", Logging::Loggable(thread), "size", Logging::Loggable(pipeBufferSize)); auto existingSize = getPipeBufferSize(threadInfo.pipes.writeQueriesToThread); if (existingSize > 0) { - SLOG(g_log << Logger::Warning << "The current size of the distribution pipe's buffer for thread " << thread << " is " << existingSize << endl, - log->info(Logr::Warning, "The current size of the distribution pipe's buffer for thread", "thread", Logging::Loggable(thread), "size", Logging::Loggable(existingSize))); + log->info(Logr::Warning, "The current size of the distribution pipe's buffer for thread", "thread", Logging::Loggable(thread), "size", Logging::Loggable(existingSize)); } } } @@ -433,16 +408,13 @@ return ret; } catch (FDMultiplexerException& fe) { - SLOG(g_log << Logger::Warning << "Non-fatal error initializing possible multiplexer (" << fe.what() << "), falling back" << endl, - log->error(Logr::Warning, fe.what(), "Non-fatal error initializing possible multiplexer, falling back")); + log->error(Logr::Warning, fe.what(), "Non-fatal error initializing possible multiplexer, falling back"); } catch (...) { - SLOG(g_log << Logger::Warning << "Non-fatal error initializing possible multiplexer" << endl, - log->info(Logr::Warning, "Non-fatal error initializing possible multiplexer")); + log->info(Logr::Warning, "Non-fatal error initializing possible multiplexer"); } } - SLOG(g_log << Logger::Error << "No working multiplexer found!" << endl, - log->info(Logr::Error, "No working multiplexer found!")); + log->info(Logr::Error, "No working multiplexer found!"); _exit(1); } @@ -458,12 +430,10 @@ result->emplace_back(std::move(logger)); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error while starting protobuf logger to '" << server << ": " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while starting protobuf logger", "exception", Logging::Loggable("std::exception"), "server", Logging::Loggable(server))); + log->error(Logr::Error, e.what(), "Exception while starting protobuf logger", "exception", Logging::Loggable("std::exception"), "server", Logging::Loggable(server)); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error while starting protobuf logger to '" << server << ": " << e.reason << endl, - log->error(Logr::Error, e.reason, "Exception while starting protobuf logger", "exception", Logging::Loggable("PDNSException"), "server", Logging::Loggable(server))); + log->error(Logr::Error, e.reason, "Exception while starting protobuf logger", "exception", Logging::Loggable("PDNSException"), "server", Logging::Loggable(server)); } } @@ -524,7 +494,7 @@ return true; } -void protobufLogQuery(LocalStateHolder& luaconfsLocal, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const ComboAddress& mappedSource, const Netmask& ednssubnet, bool tcp, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::unordered_set& policyTags, const std::string& requestorId, const std::string& deviceId, const std::string& deviceName, const std::map& meta, const boost::optional& ednsVersion, const dnsheader& header) +void protobufLogQuery(LocalStateHolder& luaconfsLocal, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const ComboAddress& mappedSource, const Netmask& ednssubnet, bool tcp, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::unordered_set& policyTags, const std::string& requestorId, const std::string& deviceId, const std::string& deviceName, const std::map& meta, const std::optional& ednsVersion, const dnsheader& header, const pdns::trace::TraceID& traceID) { auto log = g_slog->withName("pblq"); @@ -552,7 +522,7 @@ msg.setRequestorId(requestorId); msg.setDeviceId(deviceId); msg.setDeviceName(deviceName); - msg.setWorkerId(RecThreadInfo::id()); + msg.setWorkerId(RecThreadInfo::thread_local_id()); // For queries, packetCacheHit and outgoingQueries are not relevant if (!policyTags.empty()) { @@ -565,6 +535,9 @@ if (ednsVersion) { msg.setEDNSVersion(*ednsVersion); } + if (traceID != pdns::trace::s_emptyTraceID) { + msg.setOpenTelemetryTraceID(traceID); + } std::string strMsg(msg.finishAndMoveBuf()); for (auto& server : *t_protobufServers.servers) { @@ -584,7 +557,8 @@ } } -void protobufLogResponse(const struct dnsheader* header, LocalStateHolder& luaconfsLocal, +void protobufLogResponse(const DNSName& qname, QType qtype, + const struct dnsheader* header, LocalStateHolder& luaconfsLocal, const RecursorPacketCache::OptPBData& pbData, const struct timeval& tval, bool tcp, const ComboAddress& source, const ComboAddress& destination, const ComboAddress& mappedSource, @@ -592,6 +566,7 @@ const boost::uuids::uuid& uniqueId, const string& requestorId, const string& deviceId, const string& deviceName, const std::map& meta, const RecEventTrace& eventTrace, + pdns::trace::InitialSpanInfo& otTrace, const std::unordered_set& policyTags) { pdns::ProtoZero::RecMessage pbMessage(pbData ? pbData->d_message : "", pbData ? pbData->d_response : "", 64, 10); // The extra bytes we are going to add @@ -631,12 +606,12 @@ pbMessage.setId(header->id); pbMessage.setTime(); - pbMessage.setEDNSSubnet(ednssubnet.source, ednssubnet.source.isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); + pbMessage.setEDNSSubnet(ednssubnet.getSource(), ednssubnet.getSource().isIPv4() ? luaconfsLocal->protobufMaskV4 : luaconfsLocal->protobufMaskV6); pbMessage.setRequestorId(requestorId); pbMessage.setDeviceId(deviceId); pbMessage.setDeviceName(deviceName); pbMessage.setToPort(destination.getPort()); - pbMessage.setWorkerId(RecThreadInfo::id()); + pbMessage.setWorkerId(RecThreadInfo::thread_local_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 @@ -649,9 +624,21 @@ pbMessage.setNewlyObservedDomain(false); } #endif - if (eventTrace.enabled() && (SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_pb) != 0) { + if (eventTrace.enabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_pb)) { pbMessage.addEvents(eventTrace); } + + if (eventTrace.enabled() && eventTrace.getThisOTTraceEnabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + otTrace.setIDsIfNotSet(); + auto trace = pdns::trace::TracesData::boilerPlate("rec", eventTrace.convertToOT(otTrace), + {{"query.qname", {qname.toLogString()}}, + {"query.qtype", {qtype.toString()}}}, + SyncRes::s_serverID); + pbMessage.setOpenTelemetryData(trace.encode()); + } + if (otTrace.trace_id != pdns::trace::s_emptyTraceID) { + pbMessage.setOpenTelemetryTraceID(otTrace.trace_id); + } pbMessage.addPolicyTags(policyTags); protobufLogResponse(pbMessage); @@ -687,12 +674,10 @@ result->emplace_back(std::move(fsl)); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error while starting dnstap framestream logger to '" << server << ": " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while starting dnstap framestream logger", "exception", Logging::Loggable("std::exception"), "server", Logging::Loggable(server))); + log->error(Logr::Error, e.what(), "Exception while starting dnstap framestream logger", "exception", Logging::Loggable("std::exception"), "server", Logging::Loggable(server)); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error while starting dnstap framestream logger to '" << server << ": " << e.reason << endl, - log->error(Logr::Error, e.reason, "Exception while starting dnstap framestream logger", "exception", Logging::Loggable("PDNSException"), "server", Logging::Loggable(server))); + log->error(Logr::Error, e.reason, "Exception while starting dnstap framestream logger", "exception", Logging::Loggable("PDNSException"), "server", Logging::Loggable(server)); } } @@ -784,8 +769,7 @@ } else { int err = errno; - SLOG(g_log << Logger::Error << "Writing pid for " << Utility::getpid() << " to " << g_pidfname << " failed: " << stringerror(err) << endl, - log->error(Logr::Error, err, "Writing pid failed", "pid", Logging::Loggable(Utility::getpid()), "file", Logging::Loggable(g_pidfname))); + log->error(Logr::Error, err, "Writing pid failed", "pid", Logging::Loggable(Utility::getpid()), "file", Logging::Loggable(g_pidfname)); } } @@ -808,8 +792,7 @@ return; } dir = ::arg()["chroot"] + dir; - SLOG(g_log << Logger::Error << "Problem with socket directory " << dir << ": " << msg << "; see https://docs.powerdns.com/recursor/upgrade.html#x-to-4-3-0" << endl, - log->error(Logr::Error, msg, "Problem with socket directory, see https://docs.powerdns.com/recursor/upgrade.html#x-to-4-3-0", "dir", Logging::Loggable(dir))); + log->error(Logr::Error, msg, "Problem with socket directory, see https://docs.powerdns.com/recursor/upgrade.html#x-to-4-3-0", "dir", Logging::Loggable(dir)); _exit(1); } @@ -823,13 +806,11 @@ g_nodDBp->setCacheDir(::arg()["new-domain-history-dir"]); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "new-domain-history-dir (" << ::arg()["new-domain-history-dir"] << ") is not readable or does not exist" << endl, - log->error(Logr::Error, e.reason, "new-domain-history-dir is not readable or does not exists", "dir", Logging::Loggable(::arg()["new-domain-history-dir"]))); + log->error(Logr::Error, e.reason, "new-domain-history-dir is not readable or does not exist", "dir", Logging::Loggable(::arg()["new-domain-history-dir"])); _exit(1); } if (!g_nodDBp->init()) { - SLOG(g_log << Logger::Error << "Could not initialize domain tracking" << endl, - log->info(Logr::Error, "Could not initialize domain tracking")); + log->info(Logr::Error, "Could not initialize domain tracking"); _exit(1); } if (::arg().asNum("new-domain-db-snapshot-interval") > 0) { @@ -847,13 +828,11 @@ g_udrDBp->setCacheDir(::arg()["unique-response-history-dir"]); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "unique-response-history-dir (" << ::arg()["unique-response-history-dir"] << ") is not readable or does not exist" << endl, - log->info(Logr::Error, "unique-response-history-dir is not readable or does not exist", "dir", Logging::Loggable(::arg()["unique-response-history-dir"]))); + log->info(Logr::Error, "unique-response-history-dir is not readable or does not exist", "dir", Logging::Loggable(::arg()["unique-response-history-dir"])); _exit(1); } if (!g_udrDBp->init()) { - SLOG(g_log << Logger::Error << "Could not initialize unique response tracking" << endl, - log->info(Logr::Error, "Could not initialize unique response tracking")); + log->info(Logr::Error, "Could not initialize unique response tracking"); _exit(1); } if (::arg().asNum("new-domain-db-snapshot-interval") > 0) { @@ -890,8 +869,7 @@ 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"))); + g_slog->withName("config")->error(Logr::Warning, e.what(), "Ignoring line of ignorelist due to an error", "exception", Logging::Loggable("std::exception")); } } } @@ -902,7 +880,6 @@ g_nodEnabled = ::arg().mustDo("new-domain-tracking"); g_nodLookupDomain = DNSName(::arg()["new-domain-lookup"]); g_nodLog = ::arg().mustDo("new-domain-log"); - 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); @@ -925,8 +902,7 @@ if (auto pid = fork(); pid != 0) { if (pid < 0) { int err = errno; - SLOG(g_log << Logger::Critical << "Fork failed: " << stringerror(err) << endl, - log->error(Logr::Critical, err, "Fork failed")); + log->error(Logr::Critical, err, "Fork failed"); exit(1); // NOLINT(concurrency-mt-unsafe) } exit(0); // NOLINT(concurrency-mt-unsafe) @@ -937,8 +913,7 @@ int devNull = open("/dev/null", O_RDWR); /* open stdin */ if (devNull < 0) { int err = errno; - SLOG(g_log << Logger::Critical << "Unable to open /dev/null: " << stringerror(err) << endl, - log->error(Logr::Critical, err, "Unable to open /dev/null")); + log->error(Logr::Critical, err, "Unable to open /dev/null"); } else { dup2(devNull, 0); /* stdin */ @@ -950,7 +925,7 @@ static void termIntHandler([[maybe_unused]] int arg) { - doExit(); + _exit(1); } static void usr1Handler([[maybe_unused]] int arg) @@ -972,8 +947,7 @@ if (readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line)) { int lim = std::stoi(line); if (lim < 16384) { - SLOG(g_log << Logger::Error << "If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to " << lim << " which is < 16384" << endl, - log->info(Logr::Error, "If using IPv6, please raise sysctl net.ipv6.route.max_size to a size >= 16384", "current", Logging::Loggable(lim))); + log->info(Logr::Error, "If using IPv6, please raise sysctl net.ipv6.route.max_size to a size >= 16384", "current", Logging::Loggable(lim)); } } #endif @@ -991,10 +965,9 @@ auto mapsNeeded = 4ULL * g_maxMThreads * workers; if (lim < mapsNeeded) { g_maxMThreads = static_cast(lim / (4ULL * workers)); - SLOG(g_log << Logger::Error << "sysctl vm.max_map_count= <" << mapsNeeded << ", this may cause 'bad_alloc' exceptions; adjusting max-mthreads to " << g_maxMThreads << endl, - log->info(Logr::Error, "sysctl vm.max_map_count < mapsNeeded, this may cause 'bad_alloc' exceptions, adjusting max-mthreads", - "vm.max_map_count", Logging::Loggable(lim), "mapsNeeded", Logging::Loggable(mapsNeeded), - "max-mthreads", Logging::Loggable(g_maxMThreads))); + log->info(Logr::Error, "sysctl vm.max_map_count < mapsNeeded, this may cause 'bad_alloc' exceptions, adjusting max-mthreads", + "vm.max_map_count", Logging::Loggable(lim), "mapsNeeded", Logging::Loggable(mapsNeeded), + "max-mthreads", Logging::Loggable(g_maxMThreads)); } } #endif @@ -1075,22 +1048,22 @@ Logger::Urgency urgency = entry.d_priority != 0 ? Logger::Urgency(entry.d_priority) : Logger::Info; if (urgency > s_logUrgency) { // We do not log anything if the Urgency of the message is lower than the requested loglevel. - // Not that lower Urgency means higher number. + // Note that lower Urgency means higher number. return; } - // We need to keep the string in mem until sd_journal_sendv has ben called + // We need to keep the string in mem until sd_journal_sendv has been called vector strings; auto appendKeyAndVal = [&strings](const string& key, const string& value) { strings.emplace_back(key + "=" + value); }; appendKeyAndVal("MESSAGE", entry.message); if (entry.error) { - appendKeyAndVal("ERROR", entry.error.get()); + appendKeyAndVal("ERROR", entry.error.value()); } appendKeyAndVal("LEVEL", std::to_string(entry.level)); appendKeyAndVal("PRIORITY", std::to_string(entry.d_priority)); if (entry.name) { - appendKeyAndVal("SUBSYSTEM", entry.name.get()); + appendKeyAndVal("SUBSYSTEM", entry.name.value()); } std::array timebuf{}; appendKeyAndVal("TIMESTAMP", Logging::toTimestampStringMilli(entry.d_timestamp, timebuf)); @@ -1106,7 +1079,7 @@ } // Thread id filled in by backend, since the SL code does not know about RecursorThreads // We use the Recursor thread, other threads get id 0. May need to revisit. - appendKeyAndVal("TID", std::to_string(RecThreadInfo::id())); + appendKeyAndVal("TID", std::to_string(RecThreadInfo::thread_local_id())); vector iov; iov.reserve(strings.size()); @@ -1124,7 +1097,7 @@ Logger::Urgency urg = entry.d_priority != 0 ? Logger::Urgency(entry.d_priority) : Logger::Info; if (urg > s_logUrgency) { // We do not log anything if the Urgency of the message is lower than the requested loglevel. - // Not that lower Urgency means higher number. + // Note that lower Urgency means higher number. return; } @@ -1134,16 +1107,16 @@ {"level", std::to_string(entry.level)}, // Thread id filled in by backend, since the SL code does not know about RecursorThreads // We use the Recursor thread, other threads get id 0. May need to revisit. - {"tid", std::to_string(RecThreadInfo::id())}, + {"tid", std::to_string(RecThreadInfo::thread_local_id())}, {"ts", Logging::toTimestampStringMilli(entry.d_timestamp, timebuf)}, }; if (entry.error) { - json.emplace("error", entry.error.get()); + json.emplace("error", entry.error.value()); } if (entry.name) { - json.emplace("subsystem", entry.name.get()); + json.emplace("subsystem", entry.name.value()); } if (entry.d_priority != 0) { @@ -1175,11 +1148,11 @@ buf.str(""); buf << "msg=" << std::quoted(entry.message); if (entry.error) { - buf << " error=" << std::quoted(entry.error.get()); + buf << " error=" << std::quoted(entry.error.value()); } if (entry.name) { - buf << " subsystem=" << std::quoted(entry.name.get()); + buf << " subsystem=" << std::quoted(entry.name.value()); } buf << " level=" << std::quoted(std::to_string(entry.level)); if (entry.d_priority != 0) { @@ -1187,7 +1160,7 @@ } // Thread id filled in by backend, since the SL code does not know about RecursorThreads // We use the Recursor thread, other threads get id 0. May need to revisit. - buf << " tid=" << std::quoted(std::to_string(RecThreadInfo::id())); + buf << " tid=" << std::quoted(std::to_string(RecThreadInfo::thread_local_id())); std::array timebuf{}; buf << " ts=" << std::quoted(Logging::toTimestampStringMilli(entry.d_timestamp, timebuf)); for (auto const& value : entry.values) { @@ -1331,9 +1304,8 @@ result->addMask(line); } } - SLOG(g_log << Logger::Info << "Done parsing " << result->size() << " " << aclSetting << " ranges from file '" << file << "' - overriding '" << aclSetting << "' setting" << endl, - log->info(Logr::Info, "Done parsing ranges from file, will override setting", "setting", Logging::Loggable(aclSetting), - "number", Logging::Loggable(result->size()), "file", Logging::Loggable(file))); + log->info(Logr::Info, "Done parsing ranges from file, will override setting", "setting", Logging::Loggable(aclSetting), + "number", Logging::Loggable(result->size()), "file", Logging::Loggable(file)); } else if (!::arg()[aclSetting].empty()) { vector ips; @@ -1342,19 +1314,7 @@ for (const auto& address : ips) { result->addMask(address); } - if (!g_slogStructured) { - g_log << Logger::Info << aclSetting << ": "; - for (auto i = ips.begin(); i != ips.end(); ++i) { - if (i != ips.begin()) { - g_log << Logger::Info << ", "; - } - g_log << Logger::Info << *i; - } - g_log << Logger::Info << endl; - } - else { - log->info(Logr::Info, "Setting access control", "acl", Logging::Loggable(aclSetting), "addresses", Logging::IterLoggable(ips.begin(), ips.end())); - } + log->info(Logr::Info, "Setting access control", "acl", Logging::Loggable(aclSetting), "addresses", Logging::IterLoggable(ips.begin(), ips.end())); } return result; @@ -1378,11 +1338,25 @@ return nullptr; } +static void* pleaseSupplantProxyProtocolSettings(std::shared_ptr acl, std::shared_ptr> except) +{ + t_proxyProtocolACL = std::move(acl); + t_proxyProtocolExceptions = std::move(except); + return nullptr; +} + void parseACLs() { auto log = g_slog->withName("config"); static bool l_initialized; + const std::array aclNames = { + "allow-from-file", + "allow-from", + "allow-notify-from-file", + "allow-notify-from", + "proxy-protocol-from", + "proxy-protocol-exceptions"}; if (l_initialized) { // only reload configuration file on second call @@ -1424,6 +1398,8 @@ throw runtime_error("Unable to re-parse configuration file '" + configName + "'"); } ::arg().preParseFile(configName, "allow-notify-from"); + ::arg().preParseFile(configName, "proxy-protocol-from"); + ::arg().preParseFile(configName, "proxy-protocol-exceptions"); ::arg().preParseFile(configName, "include-dir"); ::arg().preParse(g_argc, g_argv, "include-dir"); @@ -1433,59 +1409,75 @@ ::arg().gatherIncludes(::arg()["include-dir"], ".conf", extraConfigs); for (const std::string& fileName : extraConfigs) { - if (!::arg().preParseFile(fileName, "allow-from-file", ::arg()["allow-from-file"])) { - throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'"); - } - if (!::arg().preParseFile(fileName, "allow-from", ::arg()["allow-from"])) { - throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'"); - } - - if (!::arg().preParseFile(fileName, "allow-notify-from-file", ::arg()["allow-notify-from-file"])) { - throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'"); - } - if (!::arg().preParseFile(fileName, "allow-notify-from", ::arg()["allow-notify-from"])) { - throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'"); + for (const auto& aclName : aclNames) { + if (!::arg().preParseFile(fileName, aclName, ::arg()[aclName])) { + throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'"); + } } } } } // Process command line args potentially overriding settings read from file - ::arg().preParse(g_argc, g_argv, "allow-from-file"); - ::arg().preParse(g_argc, g_argv, "allow-from"); - - ::arg().preParse(g_argc, g_argv, "allow-notify-from-file"); - ::arg().preParse(g_argc, g_argv, "allow-notify-from"); + for (const auto& aclName : aclNames) { + ::arg().preParse(g_argc, g_argv, aclName); + } auto allowFrom = parseACL("allow-from-file", "allow-from", log); if (allowFrom->empty()) { if (::arg()["local-address"] != "127.0.0.1" && ::arg().asNum("local-port") == 53) { - SLOG(g_log << Logger::Warning << "WARNING: Allowing queries from all IP addresses - this can be a security risk!" << endl, - log->info(Logr::Warning, "WARNING: Allowing queries from all IP addresses - this can be a security risk!")); + log->info(Logr::Warning, "WARNING: Allowing queries from all IP addresses - this can be a security risk!"); } allowFrom = nullptr; } - g_initialAllowFrom = allowFrom; + *g_initialAllowFrom.lock() = allowFrom; // coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads broadcastFunction([=] { return pleaseSupplantAllowFrom(allowFrom); }); auto allowNotifyFrom = parseACL("allow-notify-from-file", "allow-notify-from", log); - g_initialAllowNotifyFrom = allowNotifyFrom; + *g_initialAllowNotifyFrom.lock() = allowNotifyFrom; // coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads broadcastFunction([=] { return pleaseSupplantAllowNotifyFrom(allowNotifyFrom); }); + std::shared_ptr proxyProtocolACL; + std::shared_ptr> proxyProtocolExceptions; + if (!::arg()["proxy-protocol-from"].empty()) { + proxyProtocolACL = std::make_shared(); + proxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]); + + std::vector vec; + stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", "); + if (!vec.empty()) { + proxyProtocolExceptions = std::make_shared>(); + for (const auto& sockAddrStr : vec) { + ComboAddress sockAddr(sockAddrStr, 53); + proxyProtocolExceptions->emplace(sockAddr); + } + } + } + g_initialProxyProtocolACL = proxyProtocolACL; + g_initialProxyProtocolExceptions = proxyProtocolExceptions; + + // coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads + broadcastFunction([=] { return pleaseSupplantProxyProtocolSettings(proxyProtocolACL, proxyProtocolExceptions); }); + l_initialized = true; } +static std::mutex pipeBroadCastMutex{}; + void broadcastFunction(const pipefunc_t& func) { - /* This function might be called by the worker with t_id 0 during startup + // we do not want the handler and web code to use pipes simultaneously + std::scoped_lock lock(pipeBroadCastMutex); + + /* This function might be called by the worker with t_id not inited during startup for the initialization of ACLs and domain maps. After that it should only be called by the handler. */ - if (RecThreadInfo::infos().empty() && RecThreadInfo::id() == 0) { + if (RecThreadInfo::infos().empty() && !RecThreadInfo::is_thread_inited()) { /* the handler and distributors will call themselves below, but during startup we get called while g_threadInfos has not been populated yet to update the ACL or domain maps, so we need to @@ -1496,7 +1488,7 @@ unsigned int thread = 0; for (const auto& threadInfo : RecThreadInfo::infos()) { - if (thread++ == RecThreadInfo::id()) { + if (thread++ == RecThreadInfo::thread_local_id()) { func(); // don't write to ourselves! continue; } @@ -1504,7 +1496,13 @@ ThreadMSG* tmsg = new ThreadMSG(); // NOLINT: manual ownership handling tmsg->func = func; tmsg->wantAnswer = true; + + __tsan_release(tmsg); + if (write(threadInfo.getPipes().writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // NOLINT: sizeof correct + + __tsan_acquire(tmsg); + delete tmsg; // NOLINT: manual ownership handling unixDie("write to thread pipe returned wrong size or error"); @@ -1515,6 +1513,8 @@ unixDie("read from thread pipe returned wrong size or error"); } + __tsan_acquire(resp); + if (resp != nullptr) { delete resp; // NOLINT: manual ownership handling resp = nullptr; @@ -1558,24 +1558,25 @@ return lhs; } -// This function should only be called by the handler to gather -// metrics, wipe the cache, reload the Lua script (not the Lua config) -// or change the current trace regex, and by the SNMP thread to gather -// metrics. -// Note that this currently skips the handler, but includes the taskThread(s). +// This function should only be called by the handler and web thread to gather metrics, wipe the +// cache, reload the Lua script (not the Lua config) or change the current trace regex, and by the +// SNMP thread to gather metrics. Note that this currently skips the handler, but includes the +// taskThread(s). template T broadcastAccFunction(const std::function& func) { - if (!RecThreadInfo::self().isHandler()) { - SLOG(g_log << Logger::Error << "broadcastAccFunction has been called by a worker (" << RecThreadInfo::id() << ")" << endl, - g_slog->withName("runtime")->info(Logr::Critical, "broadcastAccFunction has been called by a worker")); // tid will be added + if (RecThreadInfo::thread_local_id() != 0) { + g_slog->withName("runtime")->info(Logr::Critical, "broadcastAccFunction has been called by a worker"); // tid will be added _exit(1); } + // we do not want the handler and web code to use pipes simultaneously + std::scoped_lock lock(pipeBroadCastMutex); + unsigned int thread = 0; T ret = T(); for (const auto& threadInfo : RecThreadInfo::infos()) { - if (thread++ == RecThreadInfo::id()) { + if (thread++ == RecThreadInfo::thread_local_id()) { continue; } @@ -1584,7 +1585,12 @@ tmsg->func = [func] { return voider(func); }; tmsg->wantAnswer = true; + __tsan_release(tmsg); + if (write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // NOLINT:: sizeof correct + + __tsan_acquire(tmsg); + delete tmsg; // NOLINT: manual ownership handling unixDie("write to thread pipe returned wrong size or error"); } @@ -1593,6 +1599,8 @@ if (read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) // NOLINT: sizeof correct unixDie("read from thread pipe returned wrong size or error"); + __tsan_acquire(resp); + if (resp) { ret += *resp; delete resp; // NOLINT: manual ownership handling @@ -1619,34 +1627,28 @@ pdns::parseQueryLocalAddress(::arg()["query-local-address"]); } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Assigning local query addresses: " << e.what(), - log->error(Logr::Error, e.what(), "Unable to assign local query address")); + log->error(Logr::Error, e.what(), "Unable to assign local query address"); return 99; } if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) { SyncRes::s_doIPv4 = true; - SLOG(g_log << Logger::Warning << "Enabling IPv4 transport for outgoing queries" << endl, - log->info(Logr::Notice, "Enabling IPv4 transport for outgoing queries")); + log->info(Logr::Notice, "Enabling IPv4 transport for outgoing queries"); } else { - SLOG(g_log << Logger::Warning << "NOT using IPv4 for outgoing queries - add an IPv4 address (like '0.0.0.0') to query-local-address to enable" << endl, - log->info(Logr::Warning, "NOT using IPv4 for outgoing queries - add an IPv4 address (like '0.0.0.0') to query-local-address to enable")); + log->info(Logr::Warning, "NOT using IPv4 for outgoing queries - add an IPv4 address (like '0.0.0.0') to query-local-address to enable"); } if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) { SyncRes::s_doIPv6 = true; - SLOG(g_log << Logger::Warning << "Enabling IPv6 transport for outgoing queries" << endl, - log->info(Logr::Notice, "Enabling IPv6 transport for outgoing queries")); + log->info(Logr::Notice, "Enabling IPv6 transport for outgoing queries"); } else { - SLOG(g_log << Logger::Warning << "NOT using IPv6 for outgoing queries - add an IPv6 address (like '::') to query-local-address to enable" << endl, - log->info(Logr::Warning, "NOT using IPv6 for outgoing queries - add an IPv6 address (like '::') to query-local-address to enable")); + log->info(Logr::Warning, "NOT using IPv6 for outgoing queries - add an IPv6 address (like '::') to query-local-address to enable"); } if (!SyncRes::s_doIPv6 && !SyncRes::s_doIPv4) { - SLOG(g_log << Logger::Error << "No outgoing addresses configured! Can not continue" << endl, - log->info(Logr::Error, "No outgoing addresses configured! Can not continue")); + log->info(Logr::Error, "No outgoing addresses configured! Can not continue"); return 99; } return 0; @@ -1670,16 +1672,17 @@ g_dnssecmode = DNSSECMode::ValidateForLog; } else { - SLOG(g_log << Logger::Error << "Unknown DNSSEC mode " << ::arg()["dnssec"] << endl, - log->info(Logr::Error, "Unknown DNSSEC mode", "dnssec", Logging::Loggable(::arg()["dnssec"]))); + log->info(Logr::Error, "Unknown DNSSEC mode", "dnssec", Logging::Loggable(::arg()["dnssec"])); return 1; } - g_signatureInceptionSkew = ::arg().asNum("signature-inception-skew"); - if (g_signatureInceptionSkew < 0) { - SLOG(g_log << Logger::Error << "A negative value for 'signature-inception-skew' is not allowed" << endl, - log->info(Logr::Error, "A negative value for 'signature-inception-skew' is not allowed")); - return 1; + { + auto value = ::arg().asNum("signature-inception-skew"); + if (value < 0) { + log->info(Logr::Error, "A negative value for 'signature-inception-skew' is not allowed"); + return 1; + } + g_signatureInceptionSkew = value; } g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus"); @@ -1699,7 +1702,7 @@ } } else { - for (auto algo : {DNSSECKeeper::RSASHA1, DNSSECKeeper::RSASHA1NSEC3SHA1}) { + for (auto algo : {DNSSEC::RSASHA1, DNSSEC::RSASHA1NSEC3SHA1}) { if (!DNSCryptoKeyEngine::verifyOne(algo)) { DNSCryptoKeyEngine::switchOffAlgorithm(algo); nums.push_back(std::to_string(algo)); @@ -1707,19 +1710,7 @@ } } if (!nums.empty()) { - if (!g_slogStructured) { - g_log << Logger::Warning << (automatic ? "Automatically" : "Manually") << " disabled DNSSEC algorithms: "; - for (auto i = nums.begin(); i != nums.end(); ++i) { - if (i != nums.begin()) { - g_log << Logger::Warning << ", "; - } - g_log << Logger::Warning << *i; - } - g_log << Logger::Warning << endl; - } - else { - log->info(Logr::Notice, "Disabled DNSSEC algorithms", "automatically", Logging::Loggable(automatic), "algorithms", Logging::IterLoggable(nums.begin(), nums.end())); - } + log->info(Logr::Notice, "Disabled DNSSEC algorithms", "automatically", Logging::Loggable(automatic), "algorithms", Logging::IterLoggable(nums.begin(), nums.end())); } return 0; @@ -1736,19 +1727,7 @@ for (const auto& anIP : ips) { SyncRes::addDontQuery(anIP); } - if (!g_slogStructured) { - g_log << Logger::Warning << "Will not send queries to: "; - for (auto i = ips.begin(); i != ips.end(); ++i) { - if (i != ips.begin()) { - g_log << Logger::Warning << ", "; - } - g_log << Logger::Warning << *i; - } - g_log << Logger::Warning << endl; - } - else { - log->info(Logr::Notice, "Will not send queries to", "addresses", Logging::IterLoggable(ips.begin(), ips.end())); - } + log->info(Logr::Notice, "Will not send queries to", "addresses", Logging::IterLoggable(ips.begin(), ips.end())); } } @@ -1795,8 +1774,7 @@ { uint64_t sse = ::arg().asNum("serve-stale-extensions"); if (sse > std::numeric_limits::max()) { - SLOG(g_log << Logger::Error << "Illegal serve-stale-extensions value: " << sse << "; range = 0..65536" << endl, - log->info(Logr::Error, "Illegal serve-stale-extensions value; range = 0..65536", "value", Logging::Loggable(sse))); + log->info(Logr::Error, "Illegal serve-stale-extensions value; range = 0..65536", "value", Logging::Loggable(sse)); return 1; } MemRecursorCache::s_maxServedStaleExtensions = sse; @@ -1831,8 +1809,7 @@ SyncRes::s_hardenNXD = SyncRes::HardenNXD::No; } else if (value != "dnssec") { - SLOG(g_log << Logger::Error << "Unknown nothing-below-nxdomain mode: " << value << endl, - log->info(Logr::Error, "Unknown nothing-below-nxdomain mode", "mode", Logging::Loggable(value))); + log->info(Logr::Error, "Unknown nothing-below-nxdomain mode", "mode", Logging::Loggable(value)); return 1; } @@ -1862,10 +1839,10 @@ SyncRes::setECSScopeZeroAddress(netmask); } - SyncRes::parseEDNSSubnetAllowlist(::arg()["edns-subnet-whitelist"]); SyncRes::parseEDNSSubnetAllowlist(::arg()["edns-subnet-allow-list"]); SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]); g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet"); + SyncRes::s_outAnyToTcp = ::arg().mustDo("out-any-to-tcp"); return 0; } @@ -1875,15 +1852,14 @@ g_balancingFactor = ::arg().asDouble("distribution-load-factor"); if (g_balancingFactor != 0.0 && g_balancingFactor < 1.0) { g_balancingFactor = 0.0; - SLOG(g_log << Logger::Warning << "Asked to run with a distribution-load-factor below 1.0, disabling it instead" << endl, - log->info(Logr::Warning, "Asked to run with a distribution-load-factor below 1.0, disabling it instead")); + log->info(Logr::Warning, "Asked to run with a distribution-load-factor below 1.0, disabling it instead"); } #ifdef SO_REUSEPORT g_reusePort = ::arg().mustDo("reuseport"); #endif - RecThreadInfo::infos().resize(RecThreadInfo::numRecursorThreads()); + RecThreadInfo::resize(RecThreadInfo::numRecursorThreads()); if (g_reusePort) { unsigned int threadNum = 1; @@ -1938,8 +1914,7 @@ } if (::arg().mustDo("daemon")) { - SLOG(g_log << Logger::Warning << "Calling daemonize, going to background" << endl, - log->info(Logr::Warning, "Calling daemonize, going to background")); + log->info(Logr::Warning, "Calling daemonize, going to background"); g_log.toConsole(Logger::Critical); daemonize(log); } @@ -1961,10 +1936,6 @@ signal(SIGTERM, termIntHandler); signal(SIGINT, termIntHandler); } -#if defined(__SANITIZE_THREAD__) || (defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)) - // If san is wanted, we dump the info ourselves - signal(SIGTERM, termIntHandler); -#endif signal(SIGUSR1, usr1Handler); signal(SIGUSR2, usr2Handler); @@ -1976,28 +1947,26 @@ { int port = ::arg().asNum("udp-source-port-min"); if (port < 1024 || port > 65535) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-min is not a valid port number" << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-min is not a valid port number")); + log->info(Logr::Error, "Unable to launch, udp-source-port-min is not a valid port number"); return 99; // this isn't going to fix itself either } g_minUdpSourcePort = port; port = ::arg().asNum("udp-source-port-max"); if (port < 1024 || port > 65535 || port < g_minUdpSourcePort) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min" << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min")); + log->info(Logr::Error, "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min"); return 99; // this isn't going to fix itself either } g_maxUdpSourcePort = port; + g_avoidUdpSourcePorts.resize(std::numeric_limits::max() + 1); std::vector parts{}; stringtok(parts, ::arg()["udp-source-port-avoid"], ", "); for (const auto& part : parts) { port = std::stoi(part); if (port < 1024 || port > 65535) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-avoid contains an invalid port number: " << part << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-avoid contains an invalid port number", "port", Logging::Loggable(part))); + log->info(Logr::Error, "Unable to launch, udp-source-port-avoid contains an invalid port number", "port", Logging::Loggable(part)); return 99; // this isn't going to fix itself either } - g_avoidUdpSourcePorts.insert(port); + g_avoidUdpSourcePorts[port] = true; } return 0; } @@ -2007,15 +1976,11 @@ if (::arg().mustDo("snmp-agent")) { #ifdef HAVE_NET_SNMP string setting = ::arg()["snmp-daemon-socket"]; - if (setting.empty()) { - setting = ::arg()["snmp-master-socket"]; - } g_snmpAgent = std::make_shared("recursor", setting); g_snmpAgent->run(); #else const std::string msg = "snmp-agent set but SNMP support not compiled in"; - SLOG(g_log << Logger::Error << msg << endl, - log->info(Logr::Error, msg)); + log->info(Logr::Error, msg); #endif // HAVE_NET_SNMP } } @@ -2027,19 +1992,16 @@ char* ns; ns = getenv("NOTIFY_SOCKET"); if (ns != nullptr) { - SLOG(g_log << Logger::Error << "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'" << endl, - log->info(Logr::Error, "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'")); + log->info(Logr::Error, "Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"); return 1; } #endif if (chroot(::arg()["chroot"].c_str()) < 0 || chdir("/") < 0) { int err = errno; - SLOG(g_log << Logger::Error << "Unable to chroot to '" + ::arg()["chroot"] + "': " << stringerror(err) << ", exiting" << endl, - log->error(Logr::Error, err, "Unable to chroot", "chroot", Logging::Loggable(::arg()["chroot"]))); + log->error(Logr::Error, err, "Unable to chroot", "chroot", Logging::Loggable(::arg()["chroot"])); return 1; } - SLOG(g_log << Logger::Info << "Chrooted to '" << ::arg()["chroot"] << "'" << endl, - log->info(Logr::Info, "Chrooted", "chroot", Logging::Loggable(::arg()["chroot"]))); + log->info(Logr::Info, "Chrooted", "chroot", Logging::Loggable(::arg()["chroot"])); } checkSocketDir(log); @@ -2061,8 +2023,7 @@ dropCapabilities(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << e.what() << endl, - log->error(Logr::Warning, e.what(), "Could not drop capabilities")); + log->error(Logr::Warning, e.what(), "Could not drop capabilities"); } return 0; } @@ -2099,8 +2060,7 @@ stringtok(parts, ::arg()["dot-to-auth-names"], " ,"); #ifndef HAVE_DNS_OVER_TLS if (!parts.empty()) { - SLOG(g_log << Logger::Error << "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored." << endl, - log->info(Logr::Error, "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored")); + log->info(Logr::Error, "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored"); } #endif for (const auto& part : parts) { @@ -2126,8 +2086,7 @@ try { auto dns64Prefix = Netmask(::arg()["dns64-prefix"]); if (dns64Prefix.getBits() != 96) { - SLOG(g_log << Logger::Error << "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes: " << ::arg()["dns64-prefix"] << endl, - log->info(Logr::Error, "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes", "prefix", Logging::Loggable(::arg()["dns64-prefix"]))); + log->info(Logr::Error, "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes", "prefix", Logging::Loggable(::arg()["dns64-prefix"])); return 1; } g_dns64Prefix = dns64Prefix.getNetwork(); @@ -2138,8 +2097,7 @@ } } catch (const NetmaskException& ne) { - SLOG(g_log << Logger::Error << "Invalid prefix '" << ::arg()["dns64-prefix"] << "' for 'dns64-prefix': " << ne.reason << endl, - log->info(Logr::Error, "Invalid prefix", "dns64-prefix", Logging::Loggable(::arg()["dns64-prefix"]))); + log->info(Logr::Error, "Invalid prefix", "dns64-prefix", Logging::Loggable(::arg()["dns64-prefix"])); return 1; } } @@ -2159,8 +2117,7 @@ g_log.setFacility(val); } else { - SLOG(g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl, - log->info(Logr::Error, "Unknown logging facility", "facility", Logging::Loggable(::arg().asNum("logging-facility")))); + log->info(Logr::Error, "Unknown logging facility", "facility", Logging::Loggable(::arg().asNum("logging-facility"))); } } @@ -2179,8 +2136,7 @@ auto luaResult = luaconfig(false); if (luaResult.d_ret != 0) { - SLOG(g_log << Logger::Error << "Cannot load Lua or equivalent YAML configuration: " << luaResult.d_str << endl, - log->error(Logr::Error, luaResult.d_str, "Cannot load Lua or equivalent YAML configuration")); + log->error(Logr::Error, luaResult.d_str, "Cannot load Lua or equivalent YAML configuration"); return 1; } @@ -2191,8 +2147,7 @@ RecThreadInfo::setWeDistributeQueries(::arg().mustDo("pdns-distributes-queries")); if (RecThreadInfo::weDistributeQueries()) { - SLOG(g_log << Logger::Warning << "PowerDNS Recursor itself will distribute queries over threads" << endl, - log->info(Logr::Notice, "PowerDNS Recursor itself will distribute queries over threads")); + log->info(Logr::Notice, "PowerDNS Recursor itself will distribute queries over threads"); } g_outgoingEDNSBufsize = ::arg().asNum("edns-outgoing-bufsize"); @@ -2211,13 +2166,18 @@ return ret; } - g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]); - { + if (!::arg()["proxy-protocol-from"].empty()) { + g_initialProxyProtocolACL = std::make_shared(); + g_initialProxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]); + std::vector vec; stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", "); - for (const auto& sockAddrStr : vec) { - ComboAddress sockAddr(sockAddrStr, 53); - g_proxyProtocolExceptions.emplace(sockAddr); + if (!vec.empty()) { + g_initialProxyProtocolExceptions = std::make_shared>(); + for (const auto& sockAddrStr : vec) { + ComboAddress sockAddr(sockAddrStr, 53); + g_initialProxyProtocolExceptions->emplace(sockAddr); + } } } g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size"); @@ -2228,7 +2188,10 @@ } g_networkTimeoutMsec = ::arg().asNum("network-timeout"); - std::tie(g_initialDomainMap, g_initialAllowNotifyFor) = parseZoneConfiguration(g_yamlSettings); + { // Reduce scope of locks (otherwise Coverity induces from this line the global vars below should be + // protected by a mutex) + std::tie(*g_initialDomainMap.lock(), *g_initialAllowNotifyFor.lock()) = parseZoneConfiguration(g_yamlSettings); + } g_latencyStatSize = ::arg().asNum("latency-statistic-size"); @@ -2249,25 +2212,25 @@ g_paddingMode = PaddingMode::PaddedQueries; } else { - SLOG(g_log << Logger::Error << "Unknown edns-padding-mode: " << ::arg()["edns-padding-mode"] << endl, - log->info(Logr::Error, "Unknown edns-padding-mode", "edns-padding-mode", Logging::Loggable(::arg()["edns-padding-mode"]))); + log->info(Logr::Error, "Unknown edns-padding-mode", "edns-padding-mode", Logging::Loggable(::arg()["edns-padding-mode"])); return 1; } g_paddingTag = ::arg().asNum("edns-padding-tag"); g_paddingOutgoing = ::arg().mustDo("edns-padding-out"); g_ECSHardening = ::arg().mustDo("edns-subnet-harden"); + // Ignong errors return value, as YAML parsing already checked the format of the entries. + enableOutgoingCookies(::arg().mustDo("outgoing-cookies"), ::arg()["outgoing-cookies-unsupported"]); + RecThreadInfo::setNumDistributorThreads(::arg().asNum("distributor-threads")); RecThreadInfo::setNumUDPWorkerThreads(::arg().asNum("threads")); if (RecThreadInfo::numUDPWorkers() < 1) { - SLOG(g_log << Logger::Warning << "Asked to run with 0 threads, raising to 1 instead" << endl, - log->info(Logr::Warning, "Asked to run with 0 threads, raising to 1 instead")); + log->info(Logr::Warning, "Asked to run with 0 threads, raising to 1 instead"); RecThreadInfo::setNumUDPWorkerThreads(1); } RecThreadInfo::setNumTCPWorkerThreads(::arg().asNum("tcp-threads")); if (RecThreadInfo::numTCPWorkers() < 1) { - SLOG(g_log << Logger::Warning << "Asked to run with 0 TCP threads, raising to 1 instead" << endl, - log->info(Logr::Warning, "Asked to run with 0 TCP threads, raising to 1 instead")); + log->info(Logr::Warning, "Asked to run with 0 TCP threads, raising to 1 instead"); RecThreadInfo::setNumTCPWorkerThreads(1); } @@ -2275,8 +2238,7 @@ int64_t maxInFlight = ::arg().asNum("max-concurrent-requests-per-tcp-connection"); if (maxInFlight < 1 || maxInFlight > USHRT_MAX || maxInFlight >= g_maxMThreads) { - SLOG(g_log << Logger::Warning << "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)" << endl, - log->info(Logr::Warning, "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)")); + log->info(Logr::Warning, "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)"); TCPConnection::s_maxInFlight = 10; } else { @@ -2300,15 +2262,13 @@ g_aggressiveNSECCache = make_unique(::arg().asNum("aggressive-nsec-cache-size")); } else { - SLOG(g_log << Logger::Warning << "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring" << endl, - log->info(Logr::Warning, "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring")); + log->info(Logr::Warning, "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring"); } } AggressiveNSECCache::s_nsec3DenialProofMaxCost = ::arg().asNum("aggressive-cache-max-nsec3-hash-cost"); AggressiveNSECCache::s_maxNSEC3CommonPrefix = static_cast(std::round(std::log2(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")))); - SLOG(g_log << Logger::Debug << "NSEC3 aggressive cache tuning: aggressive-cache-min-nsec3-hit-ratio: " << ::arg().asNum("aggressive-cache-min-nsec3-hit-ratio") << " max common prefix bits: " << std::to_string(AggressiveNSECCache::s_maxNSEC3CommonPrefix) << endl, - log->info(Logr::Debug, "NSEC3 aggressive cache tuning", "aggressive-cache-min-nsec3-hit-ratio", Logging::Loggable(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")), "maxCommonPrefixBits", Logging::Loggable(AggressiveNSECCache::s_maxNSEC3CommonPrefix))); + log->info(Logr::Debug, "NSEC3 aggressive cache tuning", "aggressive-cache-min-nsec3-hit-ratio", Logging::Loggable(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")), "maxCommonPrefixBits", Logging::Loggable(AggressiveNSECCache::s_maxNSEC3CommonPrefix)); initSuffixMatchNodes(log); initCarbon(); @@ -2330,13 +2290,16 @@ g_useKernelTimestamp = ::arg().mustDo("protobuf-use-kernel-timestamp"); g_maxChainLength = ::arg().asNum("max-chain-length"); + PacketReader::s_MaxPointersPerByte = ::arg().asNum("max-pointers-per-packet-byte"); + DNSName::s_maxPointersToPointers = ::arg().asNum("max-pointers-to-pointers"); + DNSName::s_maxPointersPerName = ::arg().asNum("max-pointers-per-name"); + checkOrFixFDS(listeningSockets, log); checkOrFixLinuxMapCountLimits(log); #ifdef HAVE_LIBSODIUM if (sodium_init() == -1) { - SLOG(g_log << Logger::Error << "Unable to initialize sodium crypto library" << endl, - log->info(Logr::Error, "Unable to initialize sodium crypto library")); + log->info(Logr::Error, "Unable to initialize sodium crypto library"); return 99; } #endif @@ -2367,11 +2330,6 @@ RecThreadInfo::makeThreadPipes(log); - disableStats(StatComponent::API, ::arg()["stats-api-blacklist"]); - disableStats(StatComponent::Carbon, ::arg()["stats-carbon-blacklist"]); - disableStats(StatComponent::RecControl, ::arg()["stats-rec-control-blacklist"]); - disableStats(StatComponent::SNMP, ::arg()["stats-snmp-blacklist"]); - disableStats(StatComponent::API, ::arg()["stats-api-disabled-list"]); disableStats(StatComponent::Carbon, ::arg()["stats-carbon-disabled-list"]); disableStats(StatComponent::RecControl, ::arg()["stats-rec-control-disabled-list"]); @@ -2405,6 +2363,8 @@ unixDie("read from thread pipe returned wrong size or error"); } + __tsan_acquire(tmsg); + void* resp = nullptr; try { resp = tmsg->func(); @@ -2414,7 +2374,7 @@ } catch (const MOADNSException& moadnsexception) { if (g_logCommonErrors) { - g_slog->withName("runtime")->error(moadnsexception.what(), "PIPE function created an exception", "excepion", Logging::Loggable("MOADNSException")); + g_slog->withName("runtime")->error(moadnsexception.what(), "PIPE function created an exception", "exception", Logging::Loggable("MOADNSException")); } } catch (const std::exception& stdException) { @@ -2424,6 +2384,9 @@ g_rateLimitedLogger.log(g_slog->withName("runtime"), "PIPE function"); } if (tmsg->wantAnswer) { + + __tsan_release(resp); + if (write(RecThreadInfo::self().getPipes().writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) { delete tmsg; // NOLINT: manual ownership handling unixDie("write to thread pipe returned wrong size or error"); @@ -2442,22 +2405,24 @@ throw PDNSException("accept failed"); } string msg = g_rcc.recv(clientfd).d_str; - SLOG(g_log << Logger::Info << "Received rec_control command '" << msg << "' via controlsocket" << endl, - log->info(Logr::Info, "Received rec_control command via control socket", "command", Logging::Loggable(msg))); + log->info(Logr::Info, "Received rec_control command via control socket", "command", Logging::Loggable(msg)); RecursorControlParser::func_t* command = nullptr; auto answer = RecursorControlParser::getAnswer(clientfd, msg, &command); - g_rcc.send(clientfd, answer); + if (command != doExitNicely) { + g_rcc.send(clientfd, answer); + } command(); + if (command == doExitNicely) { + g_rcc.send(clientfd, answer); + } } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error dealing with control socket request: " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while dealing with control socket request", "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Error, e.what(), "Exception while dealing with control socket request", "exception", Logging::Loggable("std::exception")); } catch (const PDNSException& ae) { - SLOG(g_log << Logger::Error << "Error dealing with control socket request: " << ae.reason << endl, - log->error(Logr::Error, ae.reason, "Exception while dealing with control socket request", "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Error, ae.reason, "Exception while dealing with control socket request", "exception", Logging::Loggable("PDNSException")); } } @@ -2502,19 +2467,15 @@ } private: - struct timeval last_run - { - 0, 0 - }; + struct timeval last_run{ + 0, 0}; struct timeval period; string name; }; static void houseKeepingWork(Logr::log_t log) { - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now); t_Counters.updateSnap(now, g_regressionTestMode); @@ -2616,6 +2577,11 @@ SyncRes::pruneSaveParentsNSSets(now.tv_sec); }); + static PeriodicTask pruneCookiesTask{"pruneCookiesTask", 30}; + pruneCookiesTask.runIfDue(now, [now]() { + pruneCookies(now.tv_sec - 3000); + }); + // By default, refresh at 80% of max-cache-ttl with a minimum period of 10s const unsigned int minRootRefreshInterval = 10; static PeriodicTask rootUpdateTask{"rootUpdateTask", std::max(SyncRes::s_maxcachettl * 8 / 10, minRootRefreshInterval)}; @@ -2625,7 +2591,7 @@ res = SyncRes::getRootNS(now, nullptr, 0, log); } if (res == 0) { - // Success, go back to the defaut period + // Success, go back to the default period rootUpdateTask.setPeriod(std::max(SyncRes::s_maxcachettl * 8 / 10, minRootRefreshInterval)); } else { @@ -2643,24 +2609,19 @@ doSecPoll(&t_last_secpoll, log); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Exception while performing security poll: " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while performing security poll")); + log->error(Logr::Error, e.what(), "Exception while performing security poll"); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Exception while performing security poll: " << e.reason << endl, - log->error(Logr::Error, e.reason, "Exception while performing security poll")); + log->error(Logr::Error, e.reason, "Exception while performing security poll"); } catch (const ImmediateServFailException& e) { - SLOG(g_log << Logger::Error << "Exception while performing security poll: " << e.reason << endl, - log->error(Logr::Error, e.reason, "Exception while performing security poll")); + log->error(Logr::Error, e.reason, "Exception while performing security poll"); } catch (const PolicyHitException& e) { - SLOG(g_log << Logger::Error << "Policy hit while performing security poll" << endl, - log->info(Logr::Error, "Policy hit while performing security poll")); + log->info(Logr::Error, "Policy hit while performing security poll"); } catch (...) { - SLOG(g_log << Logger::Error << "Exception while performing security poll" << endl, - log->info(Logr::Error, "Exception while performing security poll")); + log->info(Logr::Error, "Exception while performing security poll"); } }); @@ -2674,8 +2635,7 @@ trustAnchorTask.setPeriod(taInterval); trustAnchorTask.runIfDue(now, [&luaconfsLocal, &log]() { if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) { - SLOG(g_log << Logger::Debug << "Refreshing Trust Anchors from file" << endl, - log->info(Logr::Debug, "Refreshing Trust Anchors from file")); + log->info(Logr::Debug, "Refreshing Trust Anchors from file"); try { map dsAnchors; if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors, log)) { @@ -2685,8 +2645,7 @@ } } catch (const PDNSException& pe) { - SLOG(g_log << Logger::Error << "Unable to update Trust Anchors: " << pe.reason << endl, - log->error(Logr::Error, pe.reason, "Unable to update Trust Anchors")); + log->error(Logr::Error, pe.reason, "Unable to update Trust Anchors"); } } }); @@ -2709,14 +2668,12 @@ } catch (const PDNSException& ae) { t_running = false; - SLOG(g_log << Logger::Error << "Fatal error in housekeeping thread: " << ae.reason << endl, - log->error(Logr::Error, ae.reason, "Fatal error in housekeeping thread")); + log->error(Logr::Error, ae.reason, "Fatal error in housekeeping thread"); throw; } catch (...) { t_running = false; - SLOG(g_log << Logger::Error << "Uncaught exception in housekeeping thread" << endl, - log->info(Logr::Error, "Uncaught exception in housekeeping thread")); + log->info(Logr::Error, "Uncaught exception in housekeeping thread"); throw; } } @@ -2728,15 +2685,11 @@ if (threadInfo.isWorker()) { // either UDP of TCP worker // Only on threads processing queries if (g_now.tv_sec - last_lua_maintenance >= luaMaintenanceInterval) { - struct timeval start - { - }; + struct timeval start{}; Utility::gettimeofday(&start); t_pdl->maintenance(); last_lua_maintenance = g_now.tv_sec; - struct timeval stop - { - }; + struct timeval stop{}; Utility::gettimeofday(&stop); t_Counters.at(rec::Counter::maintenanceUsec) += uSec(stop - start); ++t_Counters.at(rec::Counter::maintenanceCalls); @@ -2781,8 +2734,7 @@ for (const auto& exp : expired) { auto conn = boost::any_cast>(exp.second); if (g_logCommonErrors) { - SLOG(g_log << Logger::Warning << "Timeout from remote TCP client " << conn->d_remote.toStringWithPort() << endl, - g_slogtcpin->info(Logr::Warning, "Timeout from remote TCP client", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Warning, "Timeout from remote TCP client", "remote", Logging::Loggable(conn->d_remote)); } t_fdm->removeReadFD(exp.first); } @@ -2829,28 +2781,33 @@ auto& threadInfo = RecThreadInfo::self(); { SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so.. - SyncRes::setDomainMap(g_initialDomainMap); - t_allowFrom = g_initialAllowFrom; - t_allowNotifyFrom = g_initialAllowNotifyFrom; - t_allowNotifyFor = g_initialAllowNotifyFor; + SyncRes::setDomainMap(*g_initialDomainMap.lock()); + t_allowFrom = *g_initialAllowFrom.lock(); + t_allowNotifyFrom = *g_initialAllowNotifyFrom.lock(); + t_allowNotifyFor = *g_initialAllowNotifyFor.lock(); + t_proxyProtocolACL = g_initialProxyProtocolACL; + t_proxyProtocolExceptions = g_initialProxyProtocolExceptions; t_udpclientsocks = std::make_unique(); - t_tcpClientCounts = std::make_unique(); if (g_proxyMapping) { t_proxyMapping = make_unique(*g_proxyMapping); } else { t_proxyMapping = nullptr; } - + auto lock = g_initialOpenTelemetryConditions.lock(); + if (*lock) { + t_OTConditions = make_unique(**lock); + } + else { + t_OTConditions = nullptr; + } if (threadInfo.isHandler()) { if (!primeHints()) { threadInfo.setExitCode(EXIT_FAILURE); RecursorControlChannel::stop = true; - SLOG(g_log << Logger::Critical << "Priming cache failed, stopping" << endl, - log->info(Logr::Critical, "Priming cache failed, stopping")); + log->info(Logr::Critical, "Priming cache failed, stopping"); } - SLOG(g_log << Logger::Debug << "Done priming cache with root hints" << endl, - log->info(Logr::Debug, "Done priming cache with root hints")); + log->info(Logr::Debug, "Done priming cache with root hints"); } } @@ -2860,13 +2817,11 @@ if (!::arg()["lua-dns-script"].empty()) { t_pdl = std::make_shared(); t_pdl->loadFile(::arg()["lua-dns-script"]); - SLOG(g_log << Logger::Warning << "Loaded 'lua' script from '" << ::arg()["lua-dns-script"] << "'" << endl, - log->info(Logr::Warning, "Loading Lua script from file", "name", Logging::Loggable(::arg()["lua-dns-script"]))); + log->info(Logr::Warning, "Loading Lua script from file", "name", Logging::Loggable(::arg()["lua-dns-script"])); } } catch (std::exception& e) { - SLOG(g_log << Logger::Error << "Failed to load 'lua' script from '" << ::arg()["lua-dns-script"] << "': " << e.what() << endl, - log->error(Logr::Error, e.what(), "Failed to load Lua script from file", "name", Logging::Loggable(::arg()["lua-dns-script"]))); + log->error(Logr::Error, e.what(), "Failed to load Lua script from file", "name", Logging::Loggable(::arg()["lua-dns-script"])); _exit(99); } } @@ -2914,26 +2869,10 @@ } t_fdm = unique_ptr(getMultiplexer(log)); - - std::unique_ptr rws; - t_fdm->addReadFD(threadInfo.getPipes().readToThread, handlePipeRequest); if (threadInfo.isHandler()) { - if (::arg().mustDo("webserver")) { - SLOG(g_log << Logger::Warning << "Enabling web server" << endl, - log->info(Logr::Info, "Enabling web server")); - try { - rws = make_unique(t_fdm.get()); - } - catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Unable to start the internal web server: " << e.reason << endl, - log->error(Logr::Critical, e.reason, "Exception while starting internal web server")); - _exit(99); - } - } - SLOG(g_log << Logger::Info << "Enabled '" << t_fdm->getName() << "' multiplexer" << endl, - log->info(Logr::Info, "Enabled multiplexer", "name", Logging::Loggable(t_fdm->getName()))); + log->info(Logr::Info, "Enabled multiplexer", "name", Logging::Loggable(t_fdm->getName())); } else { t_fdm->addReadFD(threadInfo.getPipes().readQueriesToThread, handlePipeRequest); @@ -2955,7 +2894,7 @@ } if (threadInfo.isHandler()) { - t_fdm->addReadFD(g_rcc.d_fd, handleRCC); // control channel + t_fdm->addReadFD(g_rcc.getDescriptor(), handleRCC); // control channel } #ifdef HAVE_SYSTEMD @@ -2970,16 +2909,13 @@ recLoop(); } catch (const PDNSException& ae) { - SLOG(g_log << Logger::Error << "Exception: " << ae.reason << endl, - log->error(Logr::Error, ae.reason, "Exception in RecursorThread", "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Error, ae.reason, "Exception in RecursorThread", "exception", Logging::Loggable("PDNSException")); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "STL Exception: " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception in RecursorThread", "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Error, e.what(), "Exception in RecursorThread", "exception", Logging::Loggable("std::exception")); } catch (...) { - SLOG(g_log << Logger::Error << "any other exception in main: " << endl, - log->info(Logr::Error, "Exception in RecursorThread")); + log->info(Logr::Error, "Exception in RecursorThread"); } } @@ -2993,7 +2929,8 @@ ::arg().parse(argc, argv); ProxyMapping proxyMapping; LuaConfigItems lci; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping); + OpenTelemetryTraceConditions conditions; + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping, conditions); auto yaml = settings.to_yaml_string(); cout << yaml << endl; } @@ -3014,26 +2951,24 @@ if (config == "check") { try { if (!::arg().file(configname)) { - SLOG(g_log << Logger::Warning << "Unable to open configuration file '" << configname << "'" << endl, - startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname))); + startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname)); return {1, true}; } ::arg().parse(argc, argv); return {0, true}; } catch (const ArgException& argException) { - SLOG(g_log << Logger::Warning << "Unable to parse configuration file '" << configname << "': " << argException.reason << endl, - startupLog->error("Cannot parse configuration", "Unable to parse configuration file", "config_file", Logging::Loggable(configname), "reason", Logging::Loggable(argException.reason))); + startupLog->error("Cannot parse configuration", "Unable to parse configuration file", "config_file", Logging::Loggable(configname), "reason", Logging::Loggable(argException.reason)); return {1, true}; } } else if (config == "default" || config.empty()) { - cout << ::arg().configstring(false, true); + auto yaml = pdns::settings::rec::defaultsToYaml(); + cout << yaml << endl; } else if (config == "diff") { if (!::arg().laxFile(configname)) { - SLOG(g_log << Logger::Warning << "Unable to open configuration file '" << configname << "'" << endl, - startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname))); + startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname)); return {1, true}; } ::arg().laxParse(argc, argv); @@ -3041,8 +2976,7 @@ } else { if (!::arg().laxFile(configname)) { - SLOG(g_log << Logger::Warning << "Unable to open configuration file '" << configname << "'" << endl, - startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname))); + startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname)); return {1, true}; } ::arg().laxParse(argc, argv); @@ -3083,8 +3017,7 @@ if (::arg()["server-id"] == RUNTIME) { // i.e. not set explicitly auto myHostname = getHostname(); if (!myHostname.has_value()) { - SLOG(g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty" << endl, - log->info(Logr::Warning, "Unable to get the hostname, NSID and id.server values will be empty")); + log->info(Logr::Warning, "Unable to get the hostname, NSID and id.server values will be empty"); } ::arg().set("server-id") = myHostname.has_value() ? *myHostname : ""; } @@ -3107,21 +3040,18 @@ if (::arg().asNum("threads") == 1) { if (::arg().mustDo("pdns-distributes-queries")) { - SLOG(g_log << Logger::Warning << "Only one thread, no need to distribute queries ourselves" << endl, - log->info(Logr::Warning, "Only one thread, no need to distribute queries ourselves")); + log->info(Logr::Warning, "Only one thread, no need to distribute queries ourselves"); ::arg().set("pdns-distributes-queries") = "no"; } } if (::arg().mustDo("pdns-distributes-queries") && ::arg().asNum("distributor-threads") == 0) { - SLOG(g_log << Logger::Warning << "Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1" << endl, - log->info(Logr::Warning, "Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1")); + log->info(Logr::Warning, "Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1"); ::arg().set("distributor-threads") = "1"; } if (!::arg().mustDo("pdns-distributes-queries") && ::arg().asNum("distributor-threads") > 0) { - SLOG(g_log << Logger::Warning << "Not distributing queries, setting distributor threads to 0" << endl, - log->info(Logr::Warning, "Not distributing queries, setting distributor threads to 0")); + log->info(Logr::Warning, "Not distributing queries, setting distributor threads to 0"); ::arg().set("distributor-threads") = "0"; } } @@ -3151,6 +3081,8 @@ } } +DoneRunning g_doneRunning; + int main(int argc, char** argv) { g_argc = argc; @@ -3261,21 +3193,22 @@ } 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)); + startupLog->info(Logr::Warning, "Trying to read YAML from .yml or .conf failed, falling 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) { return ret; } if (!::arg().file(configname)) { - SLOG(g_log << Logger::Warning << "Unable to open configuration file '" << configname << "'" << endl, - startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname))); + startupLog->error("No such file", "Unable to open configuration file", "config_file", Logging::Loggable(configname)); } else { if (!::arg().mustDo("enable-old-settings")) { - startupLog->info(Logr::Error, "Old-style settings syntax not enabled by default anymore. Use YAML or enable with --enable-old-settings on the command line", "configname", Logging::Loggable(configname)); + startupLog->info(Logr::Error, "Old-style settings syntax not supported by default anymore", "configname", Logging::Loggable(configname)); + startupLog->info(Logr::Error, "Convert to YAML settings. If not feasible use --enable-old-settings on the command line. This option will be removed in a future release."); return EXIT_FAILURE; } + startupLog->info(Logr::Warning, "Convert to YAML settings. The --enable-old-settings option on the command line will be removed in a future release."); } } @@ -3295,8 +3228,7 @@ g_log.toConsole(s_logUrgency); if (!::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty()) { - SLOG(g_log << Logger::Error << "Using chroot and enabling the API is not possible" << endl, - startupLog->info(Logr::Error, "Cannot use chroot and enable the API at the same time")); + startupLog->info(Logr::Error, "Cannot use chroot and enable the API at the same time"); return EXIT_FAILURE; } @@ -3324,20 +3256,23 @@ } ret = serviceMain(startupLog); + { + std::scoped_lock lock(g_doneRunning.mutex); + g_doneRunning.done = true; + g_doneRunning.condVar.notify_one(); + } + RecThreadInfo::joinThread0(); } catch (const PDNSException& ae) { - SLOG(g_log << Logger::Error << "Exception: " << ae.reason << endl, - g_slog->withName("config")->error(Logr::Critical, ae.reason, "Fatal error", "exception", Logging::Loggable("PDNSException"))); + g_slog->withName("config")->error(Logr::Critical, ae.reason, "Fatal error", "exception", Logging::Loggable("PDNSException")); ret = EXIT_FAILURE; } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "STL Exception: " << e.what() << endl, - g_slog->withName("config")->error(Logr::Critical, e.what(), "Fatal error", "exception", Logging::Loggable("std::exception"))); + g_slog->withName("config")->error(Logr::Critical, e.what(), "Fatal error", "exception", Logging::Loggable("std::exception")); ret = EXIT_FAILURE; } catch (...) { - SLOG(g_log << Logger::Error << "any other exception in main: " << endl, - g_slog->withName("config")->info(Logr::Critical, "Fatal error")); + g_slog->withName("config")->info(Logr::Critical, "Fatal error"); ret = EXIT_FAILURE; } @@ -3351,8 +3286,7 @@ try { if (fname.empty()) { t_pdl.reset(); - SLOG(g_log << Logger::Info << RecThreadInfo::id() << " Unloaded current lua script" << endl, - log->info(Logr::Info, "Unloaded current lua script")); + log->info(Logr::Info, "Unloaded current lua script"); return new RecursorControlChannel::Answer{0, string("unloaded\n")}; } @@ -3361,20 +3295,17 @@ t_pdl->loadFile(fname); } catch (std::runtime_error& ex) { - string msg = std::to_string(RecThreadInfo::id()) + " Retaining current script, could not read '" + fname + "': " + ex.what(); - SLOG(g_log << Logger::Error << msg << endl, - log->error(Logr::Error, ex.what(), "Retaining current script, could not read new script")); + string msg = std::to_string(RecThreadInfo::thread_local_id()) + " Retaining current script, could not read '" + fname + "': " + ex.what(); + log->error(Logr::Error, ex.what(), "Retaining current script, could not read new script"); return new RecursorControlChannel::Answer{1, msg + "\n"}; } } catch (std::exception& e) { - SLOG(g_log << Logger::Error << RecThreadInfo::id() << " Retaining current script, error from '" << fname << "': " << e.what() << endl, - log->error(Logr::Error, e.what(), "Retaining current script, error in new script")); + log->error(Logr::Error, e.what(), "Retaining current script, error in new script"); return new RecursorControlChannel::Answer{1, string("retaining current script, error from '" + fname + "': " + e.what() + "\n")}; } - SLOG(g_log << Logger::Warning << RecThreadInfo::id() << " (Re)loaded lua script from '" << fname << "'" << endl, - log->info(Logr::Warning, "(Re)loaded lua script")); + log->info(Logr::Warning, "(Re)loaded lua script"); return new RecursorControlChannel::Answer{0, string("(re)loaded '" + fname + "'\n")}; } @@ -3414,25 +3345,30 @@ return broadcastAccFunction([=] { return pleaseUseNewTraceRegex(begin != end ? *begin : "", fileno); }); } -struct WipeCacheResult wipeCaches(const DNSName& canon, bool subtree, uint16_t qtype) +WipeCacheResult wipeCaches(const DNSName& canon, bool subtree, uint16_t qtype) { - struct WipeCacheResult res; + WipeCacheResult res; try { res.record_count = static_cast(g_recCache->doWipeCache(canon, subtree, qtype)); - // scanbuild complains here about an allocated function object that is being leaked. Needs investigation - if (g_packetCache) { - res.packet_count = static_cast(g_packetCache->doWipePacketCache(canon, qtype, subtree)); - } res.negative_record_count = static_cast(g_negCache->wipe(canon, subtree)); if (g_aggressiveNSECCache) { g_aggressiveNSECCache->removeZoneInfo(canon, subtree); } + /* we need to do the packet cache last otherwise we could re-cache something that was just cleared: + - remove entry from the packet cache + - query comes in for the removed entry + - existing entry found in positive, negative or aggressive NSEC cache + - resulting packet inserted into the packet cache + - entry removed from the positive, negative or aggressive NSEC3 cache + */ + if (g_packetCache) { + res.packet_count = static_cast(g_packetCache->doWipePacketCache(canon, qtype, subtree)); + } } catch (const std::exception& e) { auto log = g_slog->withName("runtime"); - SLOG(g_log << Logger::Warning << ", failed: " << e.what() << endl, - log->error(Logr::Warning, e.what(), "Wipecache failed")); + log->error(Logr::Warning, e.what(), "Wipecache failed"); } return res; @@ -3451,13 +3387,11 @@ theThread.detach(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Problem starting RPZIXFRTracker thread: " << e.what() << endl, - g_slog->withName("rpz")->error(Logr::Error, e.what(), "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("std::exception"))); + g_slog->withName("rpz")->error(Logr::Error, e.what(), "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("std::exception")); exit(1); // NOLINT(concurrency-mt-unsafe) } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Problem starting RPZIXFRTracker thread: " << e.reason << endl, - g_slog->withName("rpz")->error(Logr::Error, e.reason, "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("PDNSException"))); + g_slog->withName("rpz")->error(Logr::Error, e.reason, "Exception starting RPZIXFRTracker thread", "exception", Logging::Loggable("PDNSException")); exit(1); // NOLINT(concurrency-mt-unsafe) } } @@ -3472,13 +3406,11 @@ theThread.detach(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Problem starting ZoneIXFRTracker thread: " << e.what() << endl, - g_slog->withName("zone")->error(Logr::Error, e.what(), "Exception starting ZoneXFRTracker thread", "exception", Logging::Loggable("std::exception"))); + g_slog->withName("zone")->error(Logr::Error, e.what(), "Exception starting ZoneXFRTracker thread", "exception", Logging::Loggable("std::exception")); exit(1); // NOLINT(concurrency-mt-unsafe) } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Problem starting ZoneIXFRTracker thread: " << e.reason << endl, - g_slog->withName("zone")->error(Logr::Error, e.reason, "Exception starting ZoneXFRTracker thread", "exception", Logging::Loggable("PDNSException"))); + g_slog->withName("zone")->error(Logr::Error, e.reason, "Exception starting ZoneXFRTracker thread", "exception", Logging::Loggable("PDNSException")); exit(1); // NOLINT(concurrency-mt-unsafe) } } @@ -3498,15 +3430,12 @@ 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")); + log->info(Logr::Info, "Loading RPZ from file"); loadRPZFromFile(params.zoneXFRParams.name, zone, params.defpol, params.defpolOverrideLocal, params.maxTTL); - SLOG(g_log << Logger::Warning << "Done loading RPZ from file '" << params.name << "'" << endl, - log->info(Logr::Info, "Done loading RPZ from file")); + log->info(Logr::Info, "Done loading RPZ from file"); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Unable to load RPZ zone from '" << params.name << "': " << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while loading RPZ zone from file")); + log->error(Logr::Error, e.what(), "Exception while loading RPZ zone from file"); zone->clear(); return false; } @@ -3518,8 +3447,7 @@ auto log = lci.d_slog->withValues("seedfile", Logging::Loggable(params.seedFileName), "zone", Logging::Loggable(params.zoneXFRParams.name)); if (!params.seedFileName.empty()) { - SLOG(g_log << Logger::Info << "Pre-loading RPZ zone " << params.name << " from seed file '" << params.seedFileName << "'" << endl, - log->info(Logr::Info, "Pre-loading RPZ zone from seed file")); + log->info(Logr::Info, "Pre-loading RPZ zone from seed file"); try { params.zoneXFRParams.soaRecordContent = loadRPZFromFile(params.seedFileName, zone, params.defpol, params.defpolOverrideLocal, params.maxTTL); @@ -3532,13 +3460,11 @@ } } catch (const PDNSException& e) { - SLOG(g_log << Logger::Warning << "Unable to pre-load RPZ zone " << params.name << " from seed file '" << params.seedFileName << "': " << e.reason << endl, - log->error(Logr::Warning, e.reason, "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Warning, e.reason, "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("PDNSException")); zone->clear(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Unable to pre-load RPZ zone " << params.name << " from seed file '" << params.seedFileName << "': " << e.what() << endl, - log->error(Logr::Warning, e.what(), "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Warning, e.what(), "Exception while pre-loading RPZ zone", "exception", Logging::Loggable("std::exception")); zone->clear(); } } diff -Nru pdns-recursor-5.2.13/rec-main.hh pdns-recursor-5.4.9/rec-main.hh --- pdns-recursor-5.2.13/rec-main.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-main.hh 2026-10-26 08:26:51.000000000 +0000 @@ -39,13 +39,12 @@ #include "threadname.hh" #include "recpacketcache.hh" #include "ratelimitedlog.hh" +#include "protozero-trace.hh" #ifdef NOD_ENABLED #include "nod.hh" #endif /* NOD_ENABLED */ -#include - extern std::shared_ptr g_slogtcpin; extern std::shared_ptr g_slogudpin; @@ -95,7 +94,7 @@ d_socket = sock; } - // get a string repesentation of the client address, including proxy info if applicable + // get a string representation of the client address, including proxy info if applicable string getRemote() const { if (d_source == d_remote) { @@ -108,20 +107,19 @@ MOADNSParser d_mdp; struct timeval d_now; - ComboAddress d_remote; // the address the query is coming from + ComboAddress d_remote; // the address from which the query is coming ComboAddress d_source; // the address we assume the query is coming from, might be set by proxy protocol ComboAddress d_local; // the address we received the query on ComboAddress d_destination; // the address we assume the query is sent to, might be set by proxy protocol ComboAddress d_mappedSource; // the source address after being mapped by table based proxy mapping RecEventTrace d_eventTrace; + pdns::trace::InitialSpanInfo d_otTrace; boost::uuids::uuid d_uuid; string d_requestorId; string d_deviceId; string d_deviceName; - struct timeval d_kernelTimestamp - { - 0, 0 - }; + struct timeval d_kernelTimestamp{ + 0, 0}; std::string d_query; std::unordered_set d_policyTags; std::unordered_set d_gettagPolicyTags; @@ -134,9 +132,9 @@ EDNSSubnetOpts d_ednssubnet; shared_ptr d_tcpConnection; - boost::optional d_extendedErrorCode{boost::none}; + std::optional d_extendedErrorCode{std::nullopt}; string d_extendedErrorExtra; - boost::optional d_rcode{boost::none}; + std::optional d_rcode{std::nullopt}; int d_socket{-1}; unsigned int d_tag{0}; uint32_t d_qhash{0}; @@ -155,6 +153,13 @@ extern uint16_t g_minUdpSourcePort; extern uint16_t g_maxUdpSourcePort; extern bool g_regressionTestMode; +struct DoneRunning +{ + std::mutex mutex; + std::condition_variable condVar; + std::atomic done{false}; +}; +extern DoneRunning g_doneRunning; // you can ask this class for a UDP socket to send a query from // this socket is not yours, don't even think about deleting it @@ -169,14 +174,14 @@ { } - LWResult::Result getSocket(const ComboAddress& toaddr, int* fileDesc); + LWResult::Result getSocket(const ComboAddress& toaddr, const std::optional& localAddress, int* fileDesc); // return a socket to the pool, or simply erase it void returnSocket(int fileDesc); private: // returns -1 for errors which might go away, throws for ones that won't - static int makeClientSocket(int family); + static int makeClientSocket(int family, const std::optional& localAddress); }; enum class PaddingMode @@ -193,6 +198,7 @@ extern bool g_yamlSettings; extern string g_yamlSettingsSuffix; +extern LockGuarded g_yamlStruct; extern bool g_logCommonErrors; extern size_t g_proxyProtocolMaximumSize; extern std::atomic g_quiet; @@ -218,20 +224,21 @@ extern thread_local std::shared_ptr t_allowNotifyFrom; extern thread_local std::shared_ptr t_allowNotifyFor; extern thread_local std::unique_ptr t_udpclientsocks; +extern thread_local std::shared_ptr t_proxyProtocolACL; +extern thread_local std::shared_ptr> t_proxyProtocolExceptions; extern bool g_useIncomingECS; -extern boost::optional g_dns64Prefix; +extern std::optional g_dns64Prefix; extern DNSName g_dns64PrefixReverse; extern uint64_t g_latencyStatSize; -extern NetmaskGroup g_proxyProtocolACL; -extern std::set g_proxyProtocolExceptions; extern std::atomic g_statsWanted; extern uint32_t g_disthashseed; extern int g_argc; extern char** g_argv; -extern std::shared_ptr g_initialDomainMap; // new threads needs this to be setup -extern std::shared_ptr g_initialAllowFrom; // new thread needs to be setup with this -extern std::shared_ptr g_initialAllowNotifyFrom; // new threads need this to be setup -extern std::shared_ptr g_initialAllowNotifyFor; // new threads need this to be setup +extern LockGuarded> g_initialDomainMap; // new threads needs this to be setup +extern LockGuarded> g_initialAllowFrom; // new thread needs to be setup with this +extern LockGuarded> g_initialAllowNotifyFrom; // new threads need this to be setup +extern LockGuarded> g_initialAllowNotifyFor; // new threads need this to be setup +extern LockGuarded> g_initialOpenTelemetryConditions; // new threads need this to be set extern thread_local std::shared_ptr t_traceRegex; extern thread_local FDWrapper t_tracefd; extern string g_programname; @@ -240,6 +247,7 @@ extern thread_local std::unique_ptr t_proxyMapping; using ProxyMappingStats_t = std::unordered_map; +extern thread_local std::unique_ptr t_OTConditions; extern pdns::RateLimitedLog g_rateLimitedLogger; #ifdef NOD_ENABLED @@ -277,14 +285,11 @@ extern thread_local FrameStreamServersInfo t_nodFrameStreamServersInfo; #endif /* HAVE_FSTRM */ -extern boost::container::flat_set g_avoidUdpSourcePorts; +extern std::vector g_avoidUdpSourcePorts; /* without reuseport, all listeners share the same sockets */ typedef vector>> deferredAdd_t; -typedef map tcpClientCounts_t; -extern thread_local std::unique_ptr t_tcpClientCounts; - inline MT_t* getMT() { return g_multiTasker ? g_multiTasker.get() : nullptr; @@ -326,8 +331,7 @@ // For communicating with our threads effectively readonly after // startup. -// First we have the handler thread, t_id == 0 (some other helper -// threads like SNMP might have t_id == 0 as well) then the +// First we have the handler thread, t_id == 0 then the // distributor threads if any and finally the workers struct RecThreadInfo { @@ -344,12 +348,16 @@ public: static RecThreadInfo& self() { - return s_threadInfos.at(t_id); + auto& info = s_threadInfos.at(t_id); + assert(info.d_myid == t_id); // internal consistency check + return info; } static RecThreadInfo& info(unsigned int index) { - return s_threadInfos.at(index); + auto& info = s_threadInfos.at(index); + assert(info.d_myid == index); + return info; } static vector& infos() @@ -359,17 +367,11 @@ [[nodiscard]] bool isDistributor() const { - if (t_id == 0) { - return false; - } return s_weDistributeQueries && listener; } [[nodiscard]] bool isHandler() const { - if (t_id == 0) { - return true; - } return handler; } @@ -421,11 +423,24 @@ taskThread = true; } - static unsigned int id() + static unsigned int thread_local_id() { + if (t_id == TID_NOT_INITED) { + return 0; // backward compatibility + } return t_id; } + static bool is_thread_inited() + { + return t_id != TID_NOT_INITED; + } + + [[nodiscard]] unsigned int id() const + { + return d_myid; + } + static void setThreadId(unsigned int arg) { t_id = arg; @@ -539,6 +554,22 @@ mt = theMT; } + static void joinThread0() + { + if (!s_threadInfos.empty()) { + info(0).thread.join(); + } + } + + static void resize(size_t size) + { + s_threadInfos.resize(size); + for (unsigned int i = 0; i < size; i++) { + s_threadInfos.at(i).d_myid = i; + } + } + static constexpr unsigned int TID_NOT_INITED = std::numeric_limits::max(); + private: // FD corresponding to TCP sockets this thread is listening on. // These FDs are also in deferredAdds when we have one socket per @@ -558,6 +589,7 @@ std::string name; std::thread thread; int exitCode{0}; + unsigned int d_myid{TID_NOT_INITED}; // should always be equal to the thread_local tid; // handle the web server, carbon, statistics and the control channel bool handler{false}; @@ -592,26 +624,29 @@ bool checkFrameStreamExport(LocalStateHolder& luaconfsLocal, const FrameStreamExportConfig& config, FrameStreamServersInfo& serverInfos); #endif void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uint16_t* qtype, uint16_t* qclass, - bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options, boost::optional& ednsVersion); -void protobufLogQuery(LocalStateHolder& luaconfsLocal, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const ComboAddress& mappedSource, const Netmask& ednssubnet, bool tcp, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::unordered_set& policyTags, const std::string& requestorId, const std::string& deviceId, const std::string& deviceName, const std::map& meta, const boost::optional& ednsVersion, const dnsheader& header); + bool& foundECS, EDNSSubnetOpts* ednssubnet, EDNSOptionViewMap* options, std::optional& ednsVersion); +void protobufLogQuery(LocalStateHolder& luaconfsLocal, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const ComboAddress& mappedSource, const Netmask& ednssubnet, bool tcp, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::unordered_set& policyTags, const std::string& requestorId, const std::string& deviceId, const std::string& deviceName, const std::map& meta, const std::optional& ednsVersion, const dnsheader& header, const pdns::trace::TraceID& traceID); bool isAllowNotifyForZone(DNSName qname); bool checkForCacheHit(bool qnameParsed, unsigned int tag, const string& data, DNSName& qname, uint16_t& qtype, uint16_t& qclass, const struct timeval& now, string& response, uint32_t& qhash, - RecursorPacketCache::OptPBData& pbData, bool tcp, const ComboAddress& source, const ComboAddress& mappedSource); + RecursorPacketCache::OptPBData& pbData, bool tcp, const ComboAddress& source, const ComboAddress& mappedSource, bool ecsFound, const EDNSSubnetOpts& edns); void protobufLogResponse(pdns::ProtoZero::RecMessage& message); -void protobufLogResponse(const struct dnsheader* header, LocalStateHolder& luaconfsLocal, +void protobufLogResponse(const DNSName& qname, QType qtype, const struct dnsheader* header, LocalStateHolder& luaconfsLocal, const RecursorPacketCache::OptPBData& pbData, const struct timeval& tv, bool tcp, const ComboAddress& source, const ComboAddress& destination, const ComboAddress& mappedSource, const EDNSSubnetOpts& ednssubnet, const boost::uuids::uuid& uniqueId, const string& requestorId, const string& deviceId, const string& deviceName, const std::map& meta, const RecEventTrace& eventTrace, + pdns::trace::InitialSpanInfo& otTrace, const std::unordered_set& policyTags); void requestWipeCaches(const DNSName& canon); void startDoResolve(void*); bool expectProxyProtocol(const ComboAddress& from, const ComboAddress& listenAddress); +bool matchOTConditions(const std::unique_ptr& conditions, const ComboAddress& source); +bool matchOTConditions(RecEventTrace& eventTrace, const std::unique_ptr& conditions, const ComboAddress& source, const DNSName& qname, QType qtype, uint16_t qid, bool edns_option_present); void finishTCPReply(std::unique_ptr&, bool hadError, bool updateInFlight); void checkFastOpenSysctl(bool active, Logr::log_t); void checkTFOconnect(Logr::log_t); diff -Nru pdns-recursor-5.2.13/rec-metrics-gen.h pdns-recursor-5.4.9/rec-metrics-gen.h --- pdns-recursor-5.2.13/rec-metrics-gen.h 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/rec-metrics-gen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,282 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py -addGetStat("questions", [] { return g_Counters.sum(rec::Counter::qcounter); }); -addGetStat("ipv6-questions", [] { return g_Counters.sum(rec::Counter::ipv6qcounter); }); -addGetStat("tcp-questions", [] { return g_Counters.sum(rec::Counter::tcpqcounter); }); -addGetStat("cache-hits", []() { return g_recCache->getCacheHits(); }); -addGetStat("cache-misses", []() { return g_recCache->getCacheMisses(); }); -addGetStat("cache-entries", doGetCacheSize); -addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); }); -addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load(); }); -addGetStat("cache-bytes", doGetCacheBytes); -addGetStat("packetcache-hits", [] { return g_packetCache ? g_packetCache->getHits() : 0; }); -addGetStat("packetcache-misses", [] { return g_packetCache ? g_packetCache->getMisses() : 0; }); -addGetStat("packetcache-entries", [] { return g_packetCache ? g_packetCache->size() : 0; }); -addGetStat("packetcache-bytes", [] { return g_packetCache ? g_packetCache->bytes() : 0; }); -addGetStat("malloc-bytes", doGetMallocated); -addGetStat("servfail-answers", [] { return g_Counters.sum(rec::Counter::servFails); }); -addGetStat("nxdomain-answers", [] { return g_Counters.sum(rec::Counter::nxDomains); }); -addGetStat("noerror-answers", [] { return g_Counters.sum(rec::Counter::noErrors); }); -addGetStat("unauthorized-udp", [] { return g_Counters.sum(rec::Counter::unauthorizedUDP); }); -addGetStat("unauthorized-tcp", [] { return g_Counters.sum(rec::Counter::unauthorizedTCP); }); -addGetStat("tcp-client-overflow", [] { return g_Counters.sum(rec::Counter::tcpClientOverflow); }); -addGetStat("client-parse-errors", [] { return g_Counters.sum(rec::Counter::clientParseError); }); -addGetStat("server-parse-errors", [] { return g_Counters.sum(rec::Counter::serverParseError); }); -addGetStat("too-old-drops", [] { return g_Counters.sum(rec::Counter::tooOldDrops); }); -addGetStat("answers0-1", []() { return g_Counters.sum(rec::Histogram::answers).getCount(0); }); -addGetStat("answers1-10", []() { return g_Counters.sum(rec::Histogram::answers).getCount(1); }); -addGetStat("answers10-100", []() { return g_Counters.sum(rec::Histogram::answers).getCount(2); }); -addGetStat("answers100-1000", []() { return g_Counters.sum(rec::Histogram::answers).getCount(3); }); -addGetStat("answers-slow", []() { return g_Counters.sum(rec::Histogram::answers).getCount(4); }); -addGetStat("x-ourtime0-1", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(0); }); -addGetStat("x-ourtime1-2", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(1); }); -addGetStat("x-ourtime2-4", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(2); }); -addGetStat("x-ourtime4-8", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(3); }); -addGetStat("x-ourtime8-16", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(4); }); -addGetStat("x-ourtime16-32", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(5); }); -addGetStat("x-ourtime-slow", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(6); }); -addGetStat("auth4-answers0-1", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(0); }); -addGetStat("auth4-answers1-10", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(1); }); -addGetStat("auth4-answers10-100", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(2); }); -addGetStat("auth4-answers100-1000", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(3); }); -addGetStat("auth4-answers-slow", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(4); }); -addGetStat("auth6-answers0-1", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(0); }); -addGetStat("auth6-answers1-10", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(1); }); -addGetStat("auth6-answers10-100", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(2); }); -addGetStat("auth6-answers100-1000", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(3); }); -addGetStat("auth6-answers-slow", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(4); }); -addGetStat("qa-latency", []() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyUsec)); }); -addGetStat("x-our-latency", []() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyOursUsec)); }); -addGetStat("unexpected-packets", [] { return g_Counters.sum(rec::Counter::unexpectedCount); }); -addGetStat("case-mismatches", [] { return g_Counters.sum(rec::Counter::caseMismatchCount); }); -addGetStat("spoof-prevents", [] { return g_Counters.sum(rec::Counter::spoofCount); }); -addGetStat("nsset-invalidations", [] { return g_Counters.sum(rec::Counter::nsSetInvalidations); }); -addGetStat("resource-limits", [] { return g_Counters.sum(rec::Counter::resourceLimits); }); -addGetStat("over-capacity-drops", [] { return g_Counters.sum(rec::Counter::overCapacityDrops); }); -addGetStat("policy-drops", [] { return g_Counters.sum(rec::Counter::policyDrops); }); -addGetStat("no-packet-error", [] { return g_Counters.sum(rec::Counter::noPacketError); }); -addGetStat("ignored-packets", [] { return g_Counters.sum(rec::Counter::ignoredCount); }); -addGetStat("max-mthread-stack", [] { return g_Counters.max(rec::Counter::maxMThreadStackUsage); }); -addGetStat("negcache-entries", getNegCacheSize); -addGetStat("throttle-entries", SyncRes::getThrottledServersSize); -addGetStat("nsspeeds-entries", SyncRes::getNSSpeedsSize); -addGetStat("failed-host-entries", SyncRes::getFailedServersSize); -addGetStat("concurrent-queries", getConcurrentQueries); -addGetStat("security-status", &g_security_status); -addGetStat("outgoing-timeouts", [] { return g_Counters.sum(rec::Counter::outgoingtimeouts); }); -addGetStat("outgoing4-timeouts", [] { return g_Counters.sum(rec::Counter::outgoing4timeouts); }); -addGetStat("outgoing6-timeouts", [] { return g_Counters.sum(rec::Counter::outgoing6timeouts); }); -addGetStat("auth-zone-queries", [] { return g_Counters.sum(rec::Counter::authzonequeries); }); -addGetStat("tcp-outqueries", [] { return g_Counters.sum(rec::Counter::tcpoutqueries); }); -addGetStat("all-outqueries", [] { return g_Counters.sum(rec::Counter::outqueries); }); -addGetStat("ipv6-outqueries", [] { return g_Counters.sum(rec::Counter::ipv6queries); }); -addGetStat("throttled-outqueries", [] { return g_Counters.sum(rec::Counter::throttledqueries); }); -addGetStat("dont-outqueries", [] { return g_Counters.sum(rec::Counter::dontqueries); }); -addGetStat("throttled-out", [] { return g_Counters.sum(rec::Counter::throttledqueries); }); -addGetStat("unreachables", [] { return g_Counters.sum(rec::Counter::unreachables); }); -addGetStat("ecs-queries", &SyncRes::s_ecsqueries); -addGetStat("ecs-responses", &SyncRes::s_ecsresponses); -addGetStat("chain-resends", [] { return g_Counters.sum(rec::Counter::chainResends); }); -addGetStat("tcp-clients", [] { return TCPConnection::getCurrentConnections(); }); -#ifdef __linux -addGetStat("udp-recvbuf-errors", [] { return udpErrorStats("udp-recvbuf-errors"); }); -#endif -#ifdef __linux -addGetStat("udp-sndbuf-errors", [] { return udpErrorStats("udp-sndbuf-errors"); }); -#endif -#ifdef __linux -addGetStat("udp-noport-errors", [] { return udpErrorStats("udp-noport-errors"); }); -#endif -#ifdef __linux -addGetStat("udp-in-errors", [] { return udpErrorStats("udp-in-errors"); }); -#endif -addGetStat("edns-ping-matches", [] { return g_Counters.sum(rec::Counter::ednsPingMatches); }); -addGetStat("edns-ping-mismatches", [] { return g_Counters.sum(rec::Counter::ednsPingMismatches); }); -addGetStat("dnssec-queries", [] { return g_Counters.sum(rec::Counter::dnssecQueries); }); -addGetStat("noping-outqueries", [] { return g_Counters.sum(rec::Counter::noPingOutQueries); }); -addGetStat("noedns-outqueries", [] { return g_Counters.sum(rec::Counter::noEdnsOutQueries); }); -addGetStat("uptime", [] { return time(nullptr) - s_startupTime; }); -addGetStat("real-memory-usage", [] { return getRealMemoryUsage(string()); }); -addGetStat("fd-usage", [] { return getOpenFileDescriptors(string()); }); -addGetStat("user-msec", getUserTimeMsec); -addGetStat("sys-msec", getSysTimeMsec); -addGetStat("dnssec-validations", [] { return g_Counters.sum(rec::Counter::dnssecValidations); }); -addGetStat("dnssec-result-insecure", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Insecure); }); -addGetStat("dnssec-result-secure", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Secure); }); -addGetStat("dnssec-result-bogus", []() { - std::set const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol}; - auto counts = g_Counters.sum(rec::DNSSECHistogram::dnssec); - uint64_t total = 0; - for (const auto& state : bogusStates) { - total += counts.at(state); - } - return total; - }); -addGetStat("dnssec-result-indeterminate", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Indeterminate); }); -addGetStat("dnssec-result-nta", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::NTA); }); -addGetStat("policy-result-noaction", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NoAction); }); -addGetStat("policy-result-drop", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Drop); }); -addGetStat("policy-result-nxdomain", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NXDOMAIN); }); -addGetStat("policy-result-nodata", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NODATA); }); -addGetStat("policy-result-truncate", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Truncate); }); -addGetStat("policy-result-custom", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Custom); }); -addGetStat("query-pipe-full-drops", [] { return g_Counters.sum(rec::Counter::queryPipeFullDrops); }); -addGetStat("truncated-drops", [] { return g_Counters.sum(rec::Counter::truncatedDrops); }); -addGetStat("empty-queries", [] { return g_Counters.sum(rec::Counter::emptyQueriesCount); }); -addGetStat("dnssec-authentic-data-queries", [] { return g_Counters.sum(rec::Counter::dnssecAuthenticDataQueries); }); -addGetStat("dnssec-check-disabled-queries", [] { return g_Counters.sum(rec::Counter::dnssecCheckDisabledQueries); }); -addGetStat("variable-responses", [] { return g_Counters.sum(rec::Counter::variableResponses); }); -addGetStat("special-memory-usage", [] { return getSpecialMemoryUsage(string()); }); -addGetStat("rebalanced-queries", [] { return g_Counters.sum(rec::Counter::rebalancedQueries); }); -addGetStat("qname-min-fallback-success", [] { return g_Counters.sum(rec::Counter::qnameminfallbacksuccess); }); -addGetStat("proxy-protocol-invalid", [] { return g_Counters.sum(rec::Counter::proxyProtocolInvalidCount); }); -addGetStat("record-cache-contended", []() { return g_recCache->stats().first; }); -addGetStat("record-cache-acquired", []() { return g_recCache->stats().second; }); -addGetStat("nod-lookups-dropped-oversize", [] { return g_Counters.sum(rec::Counter::nodLookupsDroppedOversize); }); -addGetStat("taskqueue-pushed", []() { return getTaskPushes(); }); -addGetStat("taskqueue-expired", []() { return getTaskExpired(); }); -addGetStat("taskqueue-size", []() { return getTaskSize(); }); -addGetStat("aggressive-nsec-cache-entries", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getEntriesCount() : 0; }); -addGetStat("aggressive-nsec-cache-nsec-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECHits() : 0; }); -addGetStat("aggressive-nsec-cache-nsec3-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3Hits() : 0; }); -addGetStat("aggressive-nsec-cache-nsec-wc-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECWildcardHits() : 0; }); -addGetStat("aggressive-nsec-cache-nsec3-wc-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3WildcardHits() : 0; }); -addGetStat("dot-outqueries", [] { return g_Counters.sum(rec::Counter::dotoutqueries); }); -addGetStat("dns64-prefix-answers", [] { return g_Counters.sum(rec::Counter::dns64prefixanswers); }); -addGetStat("almost-expired-pushed", []() { return getAlmostExpiredTasksPushed(); }); -addGetStat("almost-expired-run", []() { return getAlmostExpiredTasksRun(); }); -addGetStat("almost-expired-exceptions", []() { return getAlmostExpiredTaskExceptions(); }); -#ifdef __linux -addGetStat("udp-in-csum-errors", [] { return udpErrorStats("udp-in-csum-errors"); }); -#endif -#ifdef __linux -addGetStat("udp6-recvbuf-errors", [] { return udp6ErrorStats("udp6-recvbuf-errors"); }); -#endif -#ifdef __linux -addGetStat("udp6-sndbuf-errors", [] { return udp6ErrorStats("udp6-sndbuf-errors"); }); -#endif -#ifdef __linux -addGetStat("udp6-noport-errors", [] { return udp6ErrorStats("udp6-noport-errors"); }); -#endif -#ifdef __linux -addGetStat("udp6-in-errors", [] { return udp6ErrorStats("udp6-in-errors"); }); -#endif -#ifdef __linux -addGetStat("udp6-in-csum-errors", [] { return udp6ErrorStats("udp6-in-csum-errors"); }); -#endif -#ifdef __linux -addGetStat("cpu-iowait", [] { return getCPUIOWait(string()); }); -#endif -#ifdef __linux -addGetStat("cpu-steal", [] { return getCPUSteal(string()); }); -#endif -addGetStat("cpu-msec-thread-n", []() { return toCPUStatsMap("cpu-msec"); }); -#ifdef MALLOC_TRACE -addGetStat("memory-allocs", [] { return g_mtracer->getAllocs(string()); }); -#endif -#ifdef MALLOC_TRACE -addGetStat("memory-alloc-flux", [] { return g_mtracer->getAllocFlux(string()); }); -#endif -#ifdef MALLOC_TRACE -addGetStat("memory-allocated", [] { return g_mtracer->getTotAllocated(string()); }); -#endif -addGetStat("dnssec-result-bogus-no-valid-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidDNSKEY); }); -addGetStat("dnssec-result-bogus-invalid-denial", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDenial); }); -addGetStat("dnssec-result-bogus-unable-to-get-dss", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDSs); }); -addGetStat("dnssec-result-bogus-unable-to-get-dnskeys", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDNSKEYs); }); -addGetStat("dnssec-result-bogus-self-signed-ds", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSelfSignedDS); }); -addGetStat("dnssec-result-bogus-no-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoRRSIG); }); -addGetStat("dnssec-result-bogus-no-valid-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidRRSIG); }); -addGetStat("dnssec-result-bogus-missing-negative-indication", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusMissingNegativeIndication); }); -addGetStat("dnssec-result-bogus-signature-not-yet-valid", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureNotYetValid); }); -addGetStat("dnssec-result-bogus-signature-expired", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureExpired); }); -addGetStat("dnssec-result-bogus-unsupported-dnskey-algo", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }); -addGetStat("dnssec-result-bogus-unsupported-ds-digest-type", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDSDigestType); }); -addGetStat("dnssec-result-bogus-no-zone-key-bit-set", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoZoneKeyBitSet); }); -addGetStat("dnssec-result-bogus-revoked-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusRevokedDNSKEY); }); -addGetStat("dnssec-result-bogus-invalid-dnskey-protocol", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDNSKEYProtocol); }); -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus", []() { - std::set const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol}; - auto counts = g_Counters.sum(rec::DNSSECHistogram::xdnssec); - uint64_t total = 0; - for (const auto& state : bogusStates) { - total += counts.at(state); - } - return total; - }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-no-valid-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-invalid-denial", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-unable-to-get-dss", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-unable-to-get-dnskeys", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-self-signed-ds", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-no-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-no-valid-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-missing-negative-indication", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-signature-not-yet-valid", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-signature-expired", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-unsupported-dnskey-algo", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-unsupported-ds-digest-type", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-no-zone-key-bit-set", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-revoked-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-bogus-invalid-dnskey-protocol", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-indeterminate", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-nta", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-insecure", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); }); -} -if (::arg()["x-dnssec-names"].length() > 0) { -addGetStat("x-dnssec-result-secure", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); }); -} -addGetStat("idle-tcpout-connections", getCurrentIdleTCPConnections); -addGetStat("source-disallowed-notify", [] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); }); -addGetStat("zone-disallowed-notify", [] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); }); -addGetStat("non-resolving-nameserver-entries", SyncRes::getNonResolvingNSSize); -addGetStat("maintenance-usec", [] { return g_Counters.sum(rec::Counter::maintenanceUsec); }); -addGetStat("maintenance-calls", [] { return g_Counters.sum(rec::Counter::maintenanceCalls); }); -addGetStat("packetcache-contended", []() { return g_packetCache ? g_packetCache->stats().first : 0; }); -addGetStat("packetcache-acquired", []() { return g_packetCache ? g_packetCache->stats().second : 0; }); -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); }); -addGetStat("tcp-overflow", [] { return g_Counters.sum(rec::Counter::tcpOverflow); }); -addGetStat("remote-logger-count", []() { - return toRemoteLoggerStatsMap("remote-logger-count"); - }); -addGetStat("ecs-missing", [] { return g_Counters.sum(rec::Counter::ecsMissingCount); }); diff -Nru pdns-recursor-5.2.13/rec-nsspeeds.cc pdns-recursor-5.4.9/rec-nsspeeds.cc --- pdns-recursor-5.2.13/rec-nsspeeds.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-nsspeeds.cc 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,229 @@ +/* + * 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 +#include +#include "protozero-helpers.hh" + +#include "logging.hh" +#include "version.hh" + +#include "rec-nsspeeds.hh" + +enum class PBNSSpeedDump : protozero::pbf_tag_type +{ + required_string_version = 1, + required_string_identity = 2, + required_uint64_protocolVersion = 3, + required_int64_time = 4, + required_string_type = 5, + repeated_message_nsspeedEntry = 6, +}; + +enum class PBNSSpeedEntry : protozero::pbf_tag_type +{ + required_bytes_name = 1, + required_int64_lastgets = 2, + required_int64_lastgetus = 3, + repeated_message_map = 4, +}; + +enum class PBNSSpeedMap : protozero::pbf_tag_type +{ + required_bytes_address = 1, + required_float_val = 2, + required_int32_last = 3, +}; + +template +void nsspeeds_t::getPBEntry(T& message, U& entry) +{ + if (!entry.d_name.empty()) { + message.add_bytes(PBNSSpeedEntry::required_bytes_name, entry.d_name.toString()); + } + message.add_int64(PBNSSpeedEntry::required_int64_lastgets, entry.d_lastget.tv_sec); + message.add_int64(PBNSSpeedEntry::required_int64_lastgetus, entry.d_lastget.tv_usec); + for (const auto& [address, collection] : entry.d_collection) { + protozero::pbf_builder map(message, PBNSSpeedEntry::repeated_message_map); + encodeComboAddress(map, PBNSSpeedMap::required_bytes_address, address); + map.add_float(PBNSSpeedMap::required_float_val, collection.d_val); + map.add_int32(PBNSSpeedMap::required_int32_last, collection.d_last); + } +} + +size_t nsspeeds_t::getPB(const string& serverID, size_t maxSize, std::string& ret) const +{ + auto log = g_slog->withName("syncres")->withValues("maxSize", Logging::Loggable(maxSize)); + log->info(Logr::Info, "Producing nsspeed dump"); + + // A observed average record size is 60; + size_t estimate = maxSize == 0 ? size() * 60 : maxSize + 4096; // We may overshoot (will be rolled back) + + protozero::pbf_builder full(ret); + full.add_string(PBNSSpeedDump::required_string_version, getPDNSVersion()); + full.add_string(PBNSSpeedDump::required_string_identity, serverID); + full.add_uint64(PBNSSpeedDump::required_uint64_protocolVersion, 1); + full.add_int64(PBNSSpeedDump::required_int64_time, time(nullptr)); + full.add_string(PBNSSpeedDump::required_string_type, "PBNSSpeedDump"); + + size_t theCount = 0; + ret.reserve(estimate); + + for (const auto& entry : *this) { + protozero::pbf_builder message(full, PBNSSpeedDump::repeated_message_nsspeedEntry); + getPBEntry(message, entry); + if (maxSize > 0 && ret.size() > maxSize) { + message.rollback(); + log->info(Logr::Info, "Produced nsspeed dump (max size reached)", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(theCount)); + return theCount; + } + ++theCount; + } + log->info(Logr::Info, "Produced nsspeed dump", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(theCount)); + return theCount; +} + +template +bool nsspeeds_t::putPBEntry(time_t cutoff, T& message) +{ + DecayingEwmaCollection entry{{}}; + while (message.next()) { + switch (message.tag()) { + case PBNSSpeedEntry::required_bytes_name: + entry.d_name = DNSName(message.get_bytes()); + break; + case PBNSSpeedEntry::required_int64_lastgets: + entry.d_lastget.tv_sec = message.get_int64(); + break; + case PBNSSpeedEntry::required_int64_lastgetus: + entry.d_lastget.tv_usec = message.get_int64(); + break; + case PBNSSpeedEntry::repeated_message_map: { + protozero::pbf_message map = message.get_message(); + ComboAddress address; + float val{}; + int last{}; + while (map.next()) { + switch (map.tag()) { + case PBNSSpeedMap::required_bytes_address: + decodeComboAddress(map, address); + break; + case PBNSSpeedMap::required_float_val: + val = map.get_float(); + break; + case PBNSSpeedMap::required_int32_last: + last = map.get_int32(); + break; + default: + map.skip(); + break; + } + } + entry.insert(address, val, last); + break; + } + default: + message.skip(); + break; + } + } + if (!entry.stale(cutoff)) { + return insert(std::move(entry)).second; + } + return false; +} + +size_t nsspeeds_t::putPB(time_t cutoff, const std::string& pbuf) +{ + auto log = g_slog->withName("syncres")->withValues("size", Logging::Loggable(pbuf.size())); + log->info(Logr::Debug, "Processing nsspeed dump"); + + protozero::pbf_message full(pbuf); + size_t theCount = 0; + size_t inserted = 0; + try { + bool protocolVersionSeen = false; + bool typeSeen = false; + while (full.next()) { + switch (full.tag()) { + case PBNSSpeedDump::required_string_version: { + auto version = full.get_string(); + log = log->withValues("version", Logging::Loggable(version)); + break; + } + case PBNSSpeedDump::required_string_identity: { + auto identity = full.get_string(); + log = log->withValues("identity", Logging::Loggable(identity)); + break; + } + case PBNSSpeedDump::required_uint64_protocolVersion: { + auto protocolVersion = full.get_uint64(); + log = log->withValues("protocolVersion", Logging::Loggable(protocolVersion)); + if (protocolVersion != 1) { + throw std::runtime_error("Protocol version mismatch"); + } + protocolVersionSeen = true; + break; + } + case PBNSSpeedDump::required_int64_time: { + auto time = full.get_int64(); + log = log->withValues("time", Logging::Loggable(time)); + break; + } + case PBNSSpeedDump::required_string_type: { + auto type = full.get_string(); + if (type != "PBNSSpeedDump") { + throw std::runtime_error("Data type mismatch"); + } + typeSeen = true; + break; + } + case PBNSSpeedDump::repeated_message_nsspeedEntry: { + if (!protocolVersionSeen || !typeSeen) { + throw std::runtime_error("Required field missing"); + } + protozero::pbf_message message = full.get_message(); + if (putPBEntry(cutoff, message)) { + ++inserted; + } + ++theCount; + break; + } + default: + full.skip(); + break; + } + } + log->info(Logr::Info, "Processed nsspeed dump", "processed", Logging::Loggable(theCount), "inserted", Logging::Loggable(inserted)); + return inserted; + } + catch (const std::runtime_error& e) { + log->error(Logr::Error, e.what(), "Runtime exception processing cache dump"); + } + catch (const std::exception& e) { + log->error(Logr::Error, e.what(), "Exception processing cache dump"); + } + catch (...) { + log->error(Logr::Error, "Other exception processing cache dump"); + } + return 0; +} diff -Nru pdns-recursor-5.2.13/rec-nsspeeds.hh pdns-recursor-5.4.9/rec-nsspeeds.hh --- pdns-recursor-5.2.13/rec-nsspeeds.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-nsspeeds.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,172 @@ +/* + * 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 +#include +#include +#include +#include + +#include "iputils.hh" + +using namespace ::boost::multi_index; + +/** Class that implements a decaying EWMA. + This class keeps an exponentially weighted moving average which, additionally, decays over time. + The decaying is only done on get. +*/ + +//! This represents a number of decaying Ewmas, used to store performance per nameserver-name. +/** Modelled to work mostly like the underlying DecayingEwma */ +class DecayingEwmaCollection +{ +private: + struct DecayingEwma + { + public: + void submit(int arg, const struct timeval& last, const struct timeval& now) + { + d_last = arg; + auto val = static_cast(arg); + if (d_val == 0) { + d_val = val; + } + else { + auto diff = makeFloat(last - now); + auto factor = expf(diff) / 2.0F; // might be '0.5', or 0.0001 + d_val = (1.0F - factor) * val + factor * d_val; + } + } + + float get(float factor) + { + return d_val *= factor; + } + + [[nodiscard]] float peek() const + { + return d_val; + } + + [[nodiscard]] int last() const + { + return d_last; + } + + float d_val{0}; + int d_last{0}; + }; + +public: + DecayingEwmaCollection(DNSName name, const struct timeval val = {0, 0}) : + d_name(std::move(name)), d_lastget(val) + { + } + + void submit(const ComboAddress& remote, int usecs, const struct timeval& now) const + { + d_collection[remote].submit(usecs, d_lastget, now); + } + + float getFactor(const struct timeval& now) const + { + float diff = makeFloat(d_lastget - now); + return expf(diff / 60.0F); // is 1.0 or less + } + + bool stale(time_t limit) const + { + return limit > d_lastget.tv_sec; + } + + void purge(const std::map& keep) const + { + for (auto iter = d_collection.begin(); iter != d_collection.end();) { + if (keep.find(iter->first) != keep.end()) { + ++iter; + } + else { + iter = d_collection.erase(iter); + } + } + } + + void insert(const ComboAddress& address, float val, int last) + { + d_collection.insert(std::make_pair(address, DecayingEwma{val, last})); + } + + // d_collection is the modifyable part of the record, we index on DNSName and timeval, and DNSName never changes + mutable std::map d_collection; + DNSName d_name; + struct timeval d_lastget; +}; + +class nsspeeds_t : public multi_index_container, member>, + ordered_non_unique, member>>> +{ +public: + const auto& find_or_enter(const DNSName& name, const struct timeval& now) + { + const auto iter = insert(DecayingEwmaCollection{name, now}).first; + return *iter; + } + + const auto& find_or_enter(const DNSName& name) + { + const auto iter = insert(DecayingEwmaCollection{name}).first; + return *iter; + } + + float fastest(const DNSName& name, const struct timeval& now) + { + auto& ind = get(); + auto iter = insert(DecayingEwmaCollection{name, now}).first; + if (iter->d_collection.empty()) { + return 0; + } + // This could happen if find(DNSName) entered an entry; it's used only by test code + if (iter->d_lastget.tv_sec == 0 && iter->d_lastget.tv_usec == 0) { + ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; }); + } + + float ret = std::numeric_limits::max(); + const float factor = iter->getFactor(now); + for (auto& entry : iter->d_collection) { + ret = std::min(ret, entry.second.get(factor)); + } + ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; }); + return ret; + } + + size_t getPB(const string& serverID, size_t maxSize, std::string& ret) const; + size_t putPB(time_t cutoff, const std::string& pbuf); + +private: + template + static void getPBEntry(T& message, U& entry); + template + bool putPBEntry(time_t cutoff, T& message); +}; diff -Nru pdns-recursor-5.2.13/rec-oids-gen.h pdns-recursor-5.4.9/rec-oids-gen.h --- pdns-recursor-5.2.13/rec-oids-gen.h 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/rec-oids-gen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py -static const oid10 questionsOID = {RECURSOR_STATS_OID, 1}; -static const oid10 ipv6QuestionsOID = {RECURSOR_STATS_OID, 2}; -static const oid10 tcpQuestionsOID = {RECURSOR_STATS_OID, 3}; -static const oid10 cacheHitsOID = {RECURSOR_STATS_OID, 4}; -static const oid10 cacheMissesOID = {RECURSOR_STATS_OID, 5}; -static const oid10 cacheEntriesOID = {RECURSOR_STATS_OID, 6}; -static const oid10 cacheBytesOID = {RECURSOR_STATS_OID, 7}; -static const oid10 packetcacheHitsOID = {RECURSOR_STATS_OID, 8}; -static const oid10 packetcacheMissesOID = {RECURSOR_STATS_OID, 9}; -static const oid10 packetcacheEntriesOID = {RECURSOR_STATS_OID, 10}; -static const oid10 packetcacheBytesOID = {RECURSOR_STATS_OID, 11}; -static const oid10 mallocBytesOID = {RECURSOR_STATS_OID, 12}; -static const oid10 servfailAnswersOID = {RECURSOR_STATS_OID, 13}; -static const oid10 nxdomainAnswersOID = {RECURSOR_STATS_OID, 14}; -static const oid10 noerrorAnswersOID = {RECURSOR_STATS_OID, 15}; -static const oid10 unauthorizedUdpOID = {RECURSOR_STATS_OID, 16}; -static const oid10 unauthorizedTcpOID = {RECURSOR_STATS_OID, 17}; -static const oid10 tcpClientOverflowOID = {RECURSOR_STATS_OID, 18}; -static const oid10 clientParseErrorsOID = {RECURSOR_STATS_OID, 19}; -static const oid10 serverParseErrorsOID = {RECURSOR_STATS_OID, 20}; -static const oid10 tooOldDropsOID = {RECURSOR_STATS_OID, 21}; -static const oid10 answers01OID = {RECURSOR_STATS_OID, 22}; -static const oid10 answers110OID = {RECURSOR_STATS_OID, 23}; -static const oid10 answers10100OID = {RECURSOR_STATS_OID, 24}; -static const oid10 answers1001000OID = {RECURSOR_STATS_OID, 25}; -static const oid10 answersSlowOID = {RECURSOR_STATS_OID, 26}; -static const oid10 auth4Answers01OID = {RECURSOR_STATS_OID, 27}; -static const oid10 auth4Answers110OID = {RECURSOR_STATS_OID, 28}; -static const oid10 auth4Answers10100OID = {RECURSOR_STATS_OID, 29}; -static const oid10 auth4Answers1001000OID = {RECURSOR_STATS_OID, 30}; -static const oid10 auth4AnswersSlowOID = {RECURSOR_STATS_OID, 31}; -static const oid10 auth6Answers01OID = {RECURSOR_STATS_OID, 32}; -static const oid10 auth6Answers110OID = {RECURSOR_STATS_OID, 33}; -static const oid10 auth6Answers10100OID = {RECURSOR_STATS_OID, 34}; -static const oid10 auth6Answers1001000OID = {RECURSOR_STATS_OID, 35}; -static const oid10 auth6AnswersSlowOID = {RECURSOR_STATS_OID, 36}; -static const oid10 qaLatencyOID = {RECURSOR_STATS_OID, 37}; -static const oid10 unexpectedPacketsOID = {RECURSOR_STATS_OID, 38}; -static const oid10 caseMismatchesOID = {RECURSOR_STATS_OID, 39}; -static const oid10 spoofPreventsOID = {RECURSOR_STATS_OID, 40}; -static const oid10 nssetInvalidationsOID = {RECURSOR_STATS_OID, 41}; -static const oid10 resourceLimitsOID = {RECURSOR_STATS_OID, 42}; -static const oid10 overCapacityDropsOID = {RECURSOR_STATS_OID, 43}; -static const oid10 policyDropsOID = {RECURSOR_STATS_OID, 44}; -static const oid10 noPacketErrorOID = {RECURSOR_STATS_OID, 45}; -static const oid10 dlgOnlyDropsOID = {RECURSOR_STATS_OID, 46}; -static const oid10 ignoredPacketsOID = {RECURSOR_STATS_OID, 47}; -static const oid10 maxMthreadStackOID = {RECURSOR_STATS_OID, 48}; -static const oid10 negcacheEntriesOID = {RECURSOR_STATS_OID, 49}; -static const oid10 throttleEntriesOID = {RECURSOR_STATS_OID, 50}; -static const oid10 nsspeedsEntriesOID = {RECURSOR_STATS_OID, 51}; -static const oid10 failedHostEntriesOID = {RECURSOR_STATS_OID, 52}; -static const oid10 concurrentQueriesOID = {RECURSOR_STATS_OID, 53}; -static const oid10 securityStatusOID = {RECURSOR_STATS_OID, 54}; -static const oid10 outgoingTimeoutsOID = {RECURSOR_STATS_OID, 55}; -static const oid10 outgoing4TimeoutsOID = {RECURSOR_STATS_OID, 56}; -static const oid10 outgoing6TimeoutsOID = {RECURSOR_STATS_OID, 57}; -static const oid10 tcpOutqueriesOID = {RECURSOR_STATS_OID, 58}; -static const oid10 allOutqueriesOID = {RECURSOR_STATS_OID, 59}; -static const oid10 ipv6OutqueriesOID = {RECURSOR_STATS_OID, 60}; -static const oid10 throttledOutqueriesOID = {RECURSOR_STATS_OID, 61}; -static const oid10 dontOutqueriesOID = {RECURSOR_STATS_OID, 62}; -static const oid10 unreachablesOID = {RECURSOR_STATS_OID, 63}; -static const oid10 chainResendsOID = {RECURSOR_STATS_OID, 64}; -static const oid10 tcpClientsOID = {RECURSOR_STATS_OID, 65}; -#ifdef __linux -static const oid10 udpRecvbufErrorsOID = {RECURSOR_STATS_OID, 66}; -#endif -#ifdef __linux -static const oid10 udpSndbufErrorsOID = {RECURSOR_STATS_OID, 67}; -#endif -#ifdef __linux -static const oid10 udpNoportErrorsOID = {RECURSOR_STATS_OID, 68}; -#endif -#ifdef __linux -static const oid10 udpInErrorsOID = {RECURSOR_STATS_OID, 69}; -#endif -static const oid10 ednsPingMatchesOID = {RECURSOR_STATS_OID, 70}; -static const oid10 ednsPingMismatchesOID = {RECURSOR_STATS_OID, 71}; -static const oid10 dnssecQueriesOID = {RECURSOR_STATS_OID, 72}; -static const oid10 nopingOutqueriesOID = {RECURSOR_STATS_OID, 73}; -static const oid10 noednsOutqueriesOID = {RECURSOR_STATS_OID, 74}; -static const oid10 uptimeOID = {RECURSOR_STATS_OID, 75}; -static const oid10 realMemoryUsageOID = {RECURSOR_STATS_OID, 76}; -static const oid10 fdUsageOID = {RECURSOR_STATS_OID, 77}; -static const oid10 userMsecOID = {RECURSOR_STATS_OID, 78}; -static const oid10 sysMsecOID = {RECURSOR_STATS_OID, 79}; -static const oid10 dnssecValidationsOID = {RECURSOR_STATS_OID, 80}; -static const oid10 dnssecResultInsecureOID = {RECURSOR_STATS_OID, 81}; -static const oid10 dnssecResultSecureOID = {RECURSOR_STATS_OID, 82}; -static const oid10 dnssecResultBogusOID = {RECURSOR_STATS_OID, 83}; -static const oid10 dnssecResultIndeterminateOID = {RECURSOR_STATS_OID, 84}; -static const oid10 dnssecResultNtaOID = {RECURSOR_STATS_OID, 85}; -static const oid10 policyResultNoactionOID = {RECURSOR_STATS_OID, 86}; -static const oid10 policyResultDropOID = {RECURSOR_STATS_OID, 87}; -static const oid10 policyResultNxdomainOID = {RECURSOR_STATS_OID, 88}; -static const oid10 policyResultNodataOID = {RECURSOR_STATS_OID, 89}; -static const oid10 policyResultTruncateOID = {RECURSOR_STATS_OID, 90}; -static const oid10 policyResultCustomOID = {RECURSOR_STATS_OID, 91}; -static const oid10 queryPipeFullDropsOID = {RECURSOR_STATS_OID, 92}; -static const oid10 truncatedDropsOID = {RECURSOR_STATS_OID, 93}; -static const oid10 emptyQueriesOID = {RECURSOR_STATS_OID, 94}; -static const oid10 dnssecAuthenticDataQueriesOID = {RECURSOR_STATS_OID, 95}; -static const oid10 dnssecCheckDisabledQueriesOID = {RECURSOR_STATS_OID, 96}; -static const oid10 variableResponsesOID = {RECURSOR_STATS_OID, 97}; -static const oid10 specialMemoryUsageOID = {RECURSOR_STATS_OID, 98}; -static const oid10 rebalancedQueriesOID = {RECURSOR_STATS_OID, 99}; -static const oid10 qnameMinFallbackSuccessOID = {RECURSOR_STATS_OID, 100}; -static const oid10 proxyProtocolInvalidOID = {RECURSOR_STATS_OID, 101}; -static const oid10 recordCacheContendedOID = {RECURSOR_STATS_OID, 102}; -static const oid10 recordCacheAcquiredOID = {RECURSOR_STATS_OID, 103}; -static const oid10 nodLookupsDroppedOversizeOID = {RECURSOR_STATS_OID, 104}; -static const oid10 taskqueuePushedOID = {RECURSOR_STATS_OID, 105}; -static const oid10 taskqueueExpiredOID = {RECURSOR_STATS_OID, 106}; -static const oid10 taskqueueSizeOID = {RECURSOR_STATS_OID, 107}; -static const oid10 aggressiveNSECCacheEntriesOID = {RECURSOR_STATS_OID, 108}; -static const oid10 aggressiveNSECCacheNSECHitsOID = {RECURSOR_STATS_OID, 109}; -static const oid10 aggressiveNSECCacheNSEC3HitsOID = {RECURSOR_STATS_OID, 110}; -static const oid10 aggressiveNSECCacheNSECWcHitsOID = {RECURSOR_STATS_OID, 111}; -static const oid10 aggressiveNSECCacheNSEC3WcHitsOID = {RECURSOR_STATS_OID, 112}; -static const oid10 dotOutqueriesOID = {RECURSOR_STATS_OID, 113}; -static const oid10 dns64PrefixAnswersOID = {RECURSOR_STATS_OID, 114}; -static const oid10 almostExpiredPushedOID = {RECURSOR_STATS_OID, 115}; -static const oid10 almostExpiredRunOID = {RECURSOR_STATS_OID, 116}; -static const oid10 almostExpiredExceptionsOID = {RECURSOR_STATS_OID, 117}; -#ifdef __linux -static const oid10 udpInCsumErrorsOID = {RECURSOR_STATS_OID, 118}; -#endif -#ifdef __linux -static const oid10 udp6RecvbufErrorsOID = {RECURSOR_STATS_OID, 119}; -#endif -#ifdef __linux -static const oid10 udp6SndbufErrorsOID = {RECURSOR_STATS_OID, 120}; -#endif -#ifdef __linux -static const oid10 udp6NoportErrorsOID = {RECURSOR_STATS_OID, 121}; -#endif -#ifdef __linux -static const oid10 udp6InErrorsOID = {RECURSOR_STATS_OID, 122}; -#endif -#ifdef __linux -static const oid10 udp6InCsumErrorsOID = {RECURSOR_STATS_OID, 123}; -#endif -static const oid10 sourceDisallowedNotifyOID = {RECURSOR_STATS_OID, 124}; -static const oid10 zoneDisallowedNotifyOID = {RECURSOR_STATS_OID, 125}; -static const oid10 nonResolvingNameserverEntriesOID = {RECURSOR_STATS_OID, 126}; -static const oid10 maintenanceUsecOID = {RECURSOR_STATS_OID, 127}; -static const oid10 maintenanceCallsOID = {RECURSOR_STATS_OID, 128}; -static const oid10 authNoerrorAnswersOID = {RECURSOR_STATS_OID, 129}; -static const oid10 authFormerrAnswersOID = {RECURSOR_STATS_OID, 130}; -static const oid10 authServfailAnswersOID = {RECURSOR_STATS_OID, 131}; -static const oid10 authNxdomainAnswersOID = {RECURSOR_STATS_OID, 132}; -static const oid10 authNotimpAnswersOID = {RECURSOR_STATS_OID, 133}; -static const oid10 authRefusedAnswersOID = {RECURSOR_STATS_OID, 134}; -static const oid10 authYxdomainAnswersOID = {RECURSOR_STATS_OID, 135}; -static const oid10 authYxrrsetAnswersOID = {RECURSOR_STATS_OID, 136}; -static const oid10 authNxrrsetAnswersOID = {RECURSOR_STATS_OID, 137}; -static const oid10 authNotauthAnswersOID = {RECURSOR_STATS_OID, 138}; -static const oid10 authRcode10AnswersOID = {RECURSOR_STATS_OID, 139}; -static const oid10 authRcode11AnswersOID = {RECURSOR_STATS_OID, 140}; -static const oid10 authRcode12AnswersOID = {RECURSOR_STATS_OID, 141}; -static const oid10 authRcode13AnswersOID = {RECURSOR_STATS_OID, 142}; -static const oid10 authRcode14AnswersOID = {RECURSOR_STATS_OID, 143}; -static const oid10 authRcode15AnswersOID = {RECURSOR_STATS_OID, 144}; -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 const oid10 ecsMissingOID = {RECURSOR_STATS_OID, 153}; diff -Nru pdns-recursor-5.2.13/rec-prometheus-gen.h pdns-recursor-5.4.9/rec-prometheus-gen.h --- pdns-recursor-5.2.13/rec-prometheus-gen.h 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/rec-prometheus-gen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,200 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py -{"questions", MetricDefinition(PrometheusMetricType::counter, "Number of questions")}, -{"ipv6-questions", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 questions")}, -{"tcp-questions", MetricDefinition(PrometheusMetricType::counter, "Number of TCP questions")}, -{"cache-hits", MetricDefinition(PrometheusMetricType::counter, "Number of cache hits")}, -{"cache-misses", MetricDefinition(PrometheusMetricType::counter, "Number of cache misses")}, -{"cache-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of record cache entries")}, -{"max-cache-entries", MetricDefinition(PrometheusMetricType::gauge, "Currently configured maximum number of cache entries")}, -{"max-packetcache-entries", MetricDefinition(PrometheusMetricType::gauge, "Currently configured maximum number of packet cache entries")}, -{"cache-bytes", MetricDefinition(PrometheusMetricType::gauge, "Size of the cache in bytes")}, -{"packetcache-hits", MetricDefinition(PrometheusMetricType::counter, "Number of packetcache hits")}, -{"packetcache-misses", MetricDefinition(PrometheusMetricType::counter, "Number of packetcache misses")}, -{"packetcache-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of packetcache entries")}, -{"packetcache-bytes", MetricDefinition(PrometheusMetricType::gauge, "Size of the packetcache in bytes")}, -{"malloc-bytes", MetricDefinition(PrometheusMetricType::gauge, "Number of bytes allocated by malloc")}, -{"servfail-answers", MetricDefinition(PrometheusMetricType::counter, "Number of servfail answers")}, -{"nxdomain-answers", MetricDefinition(PrometheusMetricType::counter, "Number of nxdomain answers")}, -{"noerror-answers", MetricDefinition(PrometheusMetricType::counter, "Number of noerror answers")}, -{"unauthorized-udp", MetricDefinition(PrometheusMetricType::counter, "Number of unauthorized UDP queries")}, -{"unauthorized-tcp", MetricDefinition(PrometheusMetricType::counter, "Number of unauthorized TCP queries")}, -{"tcp-client-overflow", MetricDefinition(PrometheusMetricType::counter, "Number of TCP client connections refused because of too many connections")}, -{"client-parse-errors", MetricDefinition(PrometheusMetricType::counter, "Number of client parse errors")}, -{"server-parse-errors", MetricDefinition(PrometheusMetricType::counter, "Number of server parse errors")}, -{"too-old-drops", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because of a timeout")}, -{"answers0-1", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in less than 1 ms")}, -{"answers1-10", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 1-10 ms")}, -{"answers10-100", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 10-100 ms")}, -{"answers100-1000", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in 100-1000 ms")}, -{"answers-slow", MetricDefinition(PrometheusMetricType::counter, "Number of queries answered in more than 1000 ms")}, -{"x-ourtime0-1", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 0 and 1 milliseconds was spent within the Recursor")}, -{"x-ourtime1-2", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 1 and 2 milliseconds was spent within the Recursor")}, -{"x-ourtime2-4", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 16 and 32 milliseconds was spent within the Recursor")}, -{"x-ourtime4-8", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 4 and 8 milliseconds was spent within the Recursor")}, -{"x-ourtime8-16", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 8 and 16 milliseconds was spent within the Recursor")}, -{"x-ourtime16-32", MetricDefinition(PrometheusMetricType::counter, "Counts responses where between 16 and 32 milliseconds was spent within the Recursor")}, -{"x-ourtime-slow", MetricDefinition(PrometheusMetricType::counter, "Counts responses where more than 32 milliseconds was spent within the Recursor")}, -{"auth4-answers0-1", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 queries answered in less than 1 ms")}, -{"auth4-answers1-10", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 queries answered in 1-10 ms")}, -{"auth4-answers10-100", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 queries answered in 10-100 ms")}, -{"auth4-answers100-1000", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 queries answered in 100-1000 ms")}, -{"auth4-answers-slow", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 queries answered in more than 1000 ms")}, -{"auth6-answers0-1", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 queries answered in less than 1 ms")}, -{"auth6-answers1-10", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 queries answered in 1-10 ms")}, -{"auth6-answers10-100", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 queries answered in 10-100 ms")}, -{"auth6-answers100-1000", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 queries answered in 100-1000 ms")}, -{"auth6-answers-slow", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 queries answered in more than 1000 ms")}, -{"qa-latency", MetricDefinition(PrometheusMetricType::gauge, "Shows the current latency average, in microseconds, exponentially weighted over past 'latency-statistic-size' packets")}, -{"x-our-latency", MetricDefinition(PrometheusMetricType::gauge, "Shows the averaged time spent within PowerDNS, in microseconds, exponentially weighted over past 'latency-statistic-size' packets")}, -{"unexpected-packets", MetricDefinition(PrometheusMetricType::counter, "Number of unexpected packets")}, -{"case-mismatches", MetricDefinition(PrometheusMetricType::counter, "Number of case mismatches")}, -{"spoof-prevents", MetricDefinition(PrometheusMetricType::counter, "Number of spoof prevents")}, -{"nsset-invalidations", MetricDefinition(PrometheusMetricType::counter, "Number of nsset invalidations")}, -{"resource-limits", MetricDefinition(PrometheusMetricType::counter, "Number of resolution aborted because of a local resource limit")}, -{"over-capacity-drops", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because the threads limit was reached")}, -{"policy-drops", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because of a policy")}, -{"no-packet-error", MetricDefinition(PrometheusMetricType::counter, "Number of calls to recvmsg() that returned no packet even though the socket was ready")}, -{"dlg-only-drops", MetricDefinition(PrometheusMetricType::counter, "Obsolete")}, -{"ignored-packets", MetricDefinition(PrometheusMetricType::counter, "Number of ignored packets")}, -{"max-mthread-stack", MetricDefinition(PrometheusMetricType::counter, "Maximum amount of the mthread stack ever used")}, -{"negcache-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of negcache entries")}, -{"throttle-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of throttle entries")}, -{"nsspeeds-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of nsspeeds entries")}, -{"failed-host-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of entries in the failed NS cache")}, -{"concurrent-queries", MetricDefinition(PrometheusMetricType::gauge, "Number of concurrent queries")}, -{"security-status", MetricDefinition(PrometheusMetricType::gauge, "Current security status")}, -{"outgoing-timeouts", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing timeouts")}, -{"outgoing4-timeouts", MetricDefinition(PrometheusMetricType::counter, "Number of IPv4 outgoing timeouts")}, -{"outgoing6-timeouts", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 outgoing timeouts")}, -{"auth-zone-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries to locally hosted authoritative zones ('setting-auth-zones')")}, -{"tcp-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing TCP queries sent")}, -{"all-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing queries")}, -{"ipv6-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of IPv6 outgoing queries sent")}, -{"throttled-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of throttled outgoing queries")}, -{"dont-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing queries not sent because of a 'dont-query' setting")}, -{"throttled-out", MetricDefinition(PrometheusMetricType::counter, "Number of throttled outgoing queries")}, -{"unreachables", MetricDefinition(PrometheusMetricType::counter, "Number of errors due to an unreachable server")}, -{"ecs-queries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing queries adorned with an EDNS Client Subnet option")}, -{"ecs-responses", MetricDefinition(PrometheusMetricType::counter, "Number of responses received from authoritative servers with an EDNS Client Subnet option we used")}, -{"chain-resends", MetricDefinition(PrometheusMetricType::counter, "Number of chain resends")}, -{"tcp-clients", MetricDefinition(PrometheusMetricType::gauge, "Number of TCP clients")}, -{"udp-recvbuf-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP recvbuf errors (Linux only)")}, -{"udp-sndbuf-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP sndbuf errors (Linux only)")}, -{"udp-noport-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP noport errors (Linux only)")}, -{"udp-in-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP in errors (Linux only)")}, -{"edns-ping-matches", MetricDefinition(PrometheusMetricType::counter, "Number of EDNS Ping matches")}, -{"edns-ping-mismatches", MetricDefinition(PrometheusMetricType::counter, "Number of EDNS Ping mismatches")}, -{"dnssec-queries", MetricDefinition(PrometheusMetricType::counter, "Number of DNSSEC queries")}, -{"noping-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing queries without ping")}, -{"noedns-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing queries without EDNS")}, -{"uptime", MetricDefinition(PrometheusMetricType::counter, "Process uptime in seconds")}, -{"real-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Memory usage")}, -{"fd-usage", MetricDefinition(PrometheusMetricType::gauge, "File descriptors usage")}, -{"user-msec", MetricDefinition(PrometheusMetricType::counter, "CPU usage (user) in ms")}, -{"sys-msec", MetricDefinition(PrometheusMetricType::counter, "CPU usage (system) in ms")}, -{"dnssec-validations", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration")}, -{"dnssec-result-insecure", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC insecure state")}, -{"dnssec-result-secure", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC secure state")}, -{"dnssec-result-bogus", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC bogus state")}, -{"dnssec-result-indeterminate", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC indeterminate state")}, -{"dnssec-result-nta", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, excluding packet-cache hits, that were in the DNSSEC NTA state")}, -{"policy-result-noaction", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated no-action results")}, -{"policy-result-drop", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated drops")}, -{"policy-result-nxdomain", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated NXdomain results")}, -{"policy-result-nodata", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated nodata results")}, -{"policy-result-truncate", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated truncate results")}, -{"policy-result-custom", MetricDefinition(PrometheusMetricType::counter, "Number of policy-mandated custom results")}, -{"query-pipe-full-drops", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because the query distribution pipe was full")}, -{"truncated-drops", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because they were larger than 512 bytes")}, -{"empty-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped because they had a QD count of 0")}, -{"dnssec-authentic-data-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries received with the AD bit set")}, -{"dnssec-check-disabled-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries received with the CD bit set")}, -{"variable-responses", MetricDefinition(PrometheusMetricType::counter, "Number of variable responses")}, -{"special-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Memory usage (more precise but expensive to retrieve)")}, -{"rebalanced-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries re-distributed because the first selected worker thread was above the target load")}, -{"qname-min-fallback-success", MetricDefinition(PrometheusMetricType::counter, "Number of successful queries due to fallback mechanism within 'qname-minimization' setting")}, -{"proxy-protocol-invalid", MetricDefinition(PrometheusMetricType::counter, "Number of invalid proxy protocol headers received")}, -{"record-cache-contended", MetricDefinition(PrometheusMetricType::counter, "Number of contended record cache lock acquisitions")}, -{"record-cache-acquired", MetricDefinition(PrometheusMetricType::counter, "Number of record cache lock acquisitions")}, -{"nod-lookups-dropped-oversize", MetricDefinition(PrometheusMetricType::counter, "Number of NOD lookups dropped because they would exceed the maximum name length")}, -{"taskqueue-pushed", MetricDefinition(PrometheusMetricType::counter, "Number of tasks pushed to the taskqueues")}, -{"taskqueue-expired", MetricDefinition(PrometheusMetricType::counter, "Number of tasks expired before they could be run")}, -{"taskqueue-size", MetricDefinition(PrometheusMetricType::gauge, "Number of tasks currently in the taskqueues")}, -{"aggressive-nsec-cache-entries", MetricDefinition(PrometheusMetricType::counter, "Number of entries in the aggressive NSEC cache")}, -{"aggressive-nsec-cache-nsec-hits", MetricDefinition(PrometheusMetricType::counter, "Number of NSEC-related hits from the aggressive NSEC cache")}, -{"aggressive-nsec-cache-nsec3-hits", MetricDefinition(PrometheusMetricType::counter, "Number of NSEC3-related hits from the aggressive NSEC cache")}, -{"aggressive-nsec-cache-nsec-wc-hits", MetricDefinition(PrometheusMetricType::counter, "Number of answers synthesized from the NSEC aggressive cache")}, -{"aggressive-nsec-cache-nsec3-wc-hits", MetricDefinition(PrometheusMetricType::counter, "Number of answers synthesized from the NSEC3 aggressive cache")}, -{"dot-outqueries", MetricDefinition(PrometheusMetricType::counter, "Number of outgoing DoT queries")}, -{"dns64-prefix-answers", MetricDefinition(PrometheusMetricType::counter, "Number of answers generated by dns64-prefix matching")}, -{"almost-expired-pushed", MetricDefinition(PrometheusMetricType::counter, "Number of almost-expired tasks pushed")}, -{"almost-expired-run", MetricDefinition(PrometheusMetricType::counter, "Number of almost-expired tasks run to completion")}, -{"almost-expired-exceptions", MetricDefinition(PrometheusMetricType::counter, "Number of almost-expired tasks that caused an exception")}, -{"udp-in-csum-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP in checksum errors (Linux only)")}, -{"udp6-recvbuf-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP6 recvbuf errors (Linux only)")}, -{"udp6-sndbuf-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP6 sndbuf errors (Linux only)")}, -{"udp6-noport-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP6 noport errors (Linux only)")}, -{"udp6-in-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP6 in errors (Linux only)")}, -{"udp6-in-csum-errors", MetricDefinition(PrometheusMetricType::counter, "Number of UDP6 in checksum errors (Linux only)")}, -{"cpu-iowait", MetricDefinition(PrometheusMetricType::counter, "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ.")}, -{"cpu-steal", MetricDefinition(PrometheusMetricType::counter, "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ")}, -{"cpu-msec-thread-0", MetricDefinition(PrometheusMetricType::multicounter, "Number of milliseconds spent in thread n")}, -{"memory-allocs", MetricDefinition(PrometheusMetricType::counter, "Only relevant for development and if malloc tracing is enabled")}, -{"memory-alloc-flux", MetricDefinition(PrometheusMetricType::counter, "Only relevant for development and if malloc tracing is enabled")}, -{"memory-allocated", MetricDefinition(PrometheusMetricType::counter, "Only relevant for development and if malloc tracing is enabled")}, -{"dnssec-result-bogus-no-valid-dnskey", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found")}, -{"dnssec-result-bogus-invalid-denial", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found")}, -{"dnssec-result-bogus-unable-to-get-dss", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved")}, -{"dnssec-result-bogus-unable-to-get-dnskeys", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved")}, -{"dnssec-result-bogus-self-signed-ds", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself")}, -{"dnssec-result-bogus-no-rrsig", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer")}, -{"dnssec-result-bogus-no-valid-rrsig", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer")}, -{"dnssec-result-bogus-missing-negative-indication", MetricDefinition(PrometheusMetricType::counter, "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-not-yet-valid", MetricDefinition(PrometheusMetricType::counter, "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")}, -{"dnssec-result-bogus-signature-expired", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past")}, -{"dnssec-result-bogus-unsupported-dnskey-algo", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms")}, -{"dnssec-result-bogus-unsupported-ds-digest-type", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types")}, -{"dnssec-result-bogus-no-zone-key-bit-set", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found")}, -{"dnssec-result-bogus-revoked-dnskey", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked")}, -{"dnssec-result-bogus-invalid-dnskey-protocol", MetricDefinition(PrometheusMetricType::counter, "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols")}, -{"x-dnssec-result-bogus", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-no-valid-dnskey", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-invalid-denial", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-unable-to-get-dss", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-unable-to-get-dnskeys", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-self-signed-ds", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-no-rrsig", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-no-valid-rrsig", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-missing-negative-indication", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-signature-not-yet-valid", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-signature-expired", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-unsupported-dnskey-algo", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-unsupported-ds-digest-type", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-no-zone-key-bit-set", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-revoked-dnskey", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-bogus-invalid-dnskey-protocol", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-indeterminate", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-nta", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-insecure", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"x-dnssec-result-secure", MetricDefinition(PrometheusMetricType::counter, "Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.")}, -{"idle-tcpout-connections", MetricDefinition(PrometheusMetricType::gauge, "Number of connections in the TCP idle outgoing connections pool")}, -{"source-disallowed-notify", MetricDefinition(PrometheusMetricType::counter, "Number of NOTIFY operations not allowed by allow-notify-from")}, -{"zone-disallowed-notify", MetricDefinition(PrometheusMetricType::counter, "Number of NOTIFY operations not allowed by allow-notify-for")}, -{"non-resolving-nameserver-entries", MetricDefinition(PrometheusMetricType::gauge, "Number of entries in the non-resolving NS name cache")}, -{"maintenance-usec", MetricDefinition(PrometheusMetricType::counter, "Time spent doing internal maintenance, including Lua maintenance")}, -{"maintenance-calls", MetricDefinition(PrometheusMetricType::counter, "Number of times internal maintenance has been called, including Lua maintenance")}, -{"auth-formerr-answers", MetricDefinition(PrometheusMetricType::multicounter, "Counts the rcodes returned by authoritative servers.")}, -{"packetcache-contended", MetricDefinition(PrometheusMetricType::counter, "Number of contended packet cache lock acquisitions")}, -{"packetcache-acquired", MetricDefinition(PrometheusMetricType::counter, "Number of packet cache lock acquisitions")}, -{"nod-events", MetricDefinition(PrometheusMetricType::counter, "Count of NOD events")}, -{"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")}, -{"tcp-overflow", MetricDefinition(PrometheusMetricType::counter, "Incoming TCP limits reached")}, -{"remote-logger-count-o-0", MetricDefinition(PrometheusMetricType::multicounter, "Number of remote logging events")}, -{"cumul-clientanswers-count", MetricDefinition(PrometheusMetricType::histogram, "Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.")}, -{"cumul-authanswers-count4", MetricDefinition(PrometheusMetricType::histogram, "Cumulative counts of answer times to clients in buckets less than x microseconds.")}, -{"policy-hits", MetricDefinition(PrometheusMetricType::multicounter, "Number of policy decisions based on Lua")}, -{"proxy-mapping-total-n-0", MetricDefinition(PrometheusMetricType::multicounter, "Proxy mappings done")}, -{"ecs-missing", MetricDefinition(PrometheusMetricType::counter, "Number of answers where ECS info was missing")}, diff -Nru pdns-recursor-5.2.13/rec-protozero.hh pdns-recursor-5.4.9/rec-protozero.hh --- pdns-recursor-5.2.13/rec-protozero.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-protozero.hh 2026-10-26 08:26:51.000000000 +0000 @@ -70,7 +70,7 @@ void reserve(std::string::size_type sz1, std::string::size_type sz2) { - // We expect to grow the buffers, in the end the d_message will contains the (grown) d_response + // We expect to grow the buffers, in the end the d_message will contain the (grown) d_response // This is extra space in addition to what's already there // Different from what string.reserve() does std::string::size_type extra = sz1 + d_rspbuf.length() + sz2; diff -Nru pdns-recursor-5.2.13/rec-responsestats.cc pdns-recursor-5.4.9/rec-responsestats.cc --- pdns-recursor-5.2.13/rec-responsestats.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-responsestats.cc 2026-10-26 08:26:51.000000000 +0000 @@ -1,14 +1,27 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +/* + * 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 "rec-responsestats.hh" -#include - -#include "namespaces.hh" -#include "logger.hh" - #include "dnsparser.hh" static auto sizeBounds() @@ -21,8 +34,8 @@ bounds.push_back(80); bounds.push_back(100); bounds.push_back(150); - for (uint64_t n = 200; n < 65000; n += 200) { - bounds.push_back(n); + for (uint64_t count = 200; count < 65000; count += 200) { + bounds.push_back(count); } return bounds; } @@ -30,12 +43,6 @@ RecResponseStats::RecResponseStats() : d_sizecounters("SizeCounters", sizeBounds()) { - for (auto& entry : d_qtypecounters) { - entry = 0; - } - for (auto& entry : d_rcodecounters) { - entry = 0; - } } RecResponseStats& RecResponseStats::operator+=(const RecResponseStats& rhs) @@ -50,9 +57,9 @@ return *this; } -map RecResponseStats::getQTypeResponseCounts() const +std::map RecResponseStats::getQTypeResponseCounts() const { - map ret; + std::map ret; for (size_t i = 0; i < d_qtypecounters.size(); ++i) { auto count = d_qtypecounters.at(i); if (count != 0) { @@ -62,9 +69,9 @@ return ret; } -map RecResponseStats::getSizeResponseCounts() const +std::map RecResponseStats::getSizeResponseCounts() const { - map ret; + std::map ret; for (const auto& sizecounter : d_sizecounters.getRawData()) { if (sizecounter.d_count > 0) { ret[sizecounter.d_boundary] = sizecounter.d_count; @@ -73,9 +80,9 @@ return ret; } -map RecResponseStats::getRCodeResponseCounts() const +std::map RecResponseStats::getRCodeResponseCounts() const { - map ret; + std::map ret; for (size_t i = 0; i < d_rcodecounters.size(); ++i) { auto count = d_rcodecounters.at(i); if (count != 0) { @@ -85,10 +92,10 @@ return ret; } -string RecResponseStats::getQTypeReport() const +std::string RecResponseStats::getQTypeReport() const { auto qtypenums = getQTypeResponseCounts(); - ostringstream ostr; + std::ostringstream ostr; for (const auto& val : qtypenums) { ostr << DNSRecordContent::NumberToType(val.first) << '\t' << std::to_string(val.second) << endl; } diff -Nru pdns-recursor-5.2.13/rec-responsestats.hh pdns-recursor-5.4.9/rec-responsestats.hh --- pdns-recursor-5.2.13/rec-responsestats.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-responsestats.hh 2026-10-26 08:26:51.000000000 +0000 @@ -22,9 +22,10 @@ #pragma once #include +#include +#include #include "histogram.hh" -#include "dnspacket.hh" class RecResponseStats { @@ -63,10 +64,10 @@ } d_sizecounters(respsize); } - map getQTypeResponseCounts() const; - map getSizeResponseCounts() const; - map getRCodeResponseCounts() const; - string getQTypeReport() const; + std::map getQTypeResponseCounts() const; + std::map getSizeResponseCounts() const; + std::map getRCodeResponseCounts() const; + std::string getQTypeReport() const; private: std::array d_qtypecounters{}; diff -Nru pdns-recursor-5.2.13/rec-rust-lib/Makefile.am pdns-recursor-5.4.9/rec-rust-lib/Makefile.am --- pdns-recursor-5.2.13/rec-rust-lib/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/Makefile.am 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,33 @@ +# It's a bit dirty that this Makefile also generates a file inside rust/src (lib.rs). + +EXTRA_DIST = \ + cxxsettings-generated.cc \ + cxxsettings-private.hh \ + cxxsettings.hh \ + docs-new-preamble-in.rst \ + docs-old-preamble-in.rst \ + generate.py \ + rust-bridge-in.rs \ + rust-preamble-in.rs \ + table.py \ + rust/src/bridge.hh \ + rust/src/lib.rs + +all: cxxsettings-generated.cc rust/src/lib.rs + +BUILT_SOURCES=cxxsettings-generated.cc rust/src/lib.rs + +# We need to clean in the Rust dir, as in some cases the Serde/CXX derive/generate code does not get +# re-run by cargo after rust/src/lib.rs changed because of a generate.py run. In that case we end up +# with a rust/src/lib.rs.h that does not contain e.g. field name or field type changes. This +# cleanup is now done from generate.py itself. +# +# Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make +cxxsettings-generated%cc rust/src/lib%rs: table.py generate.py rust-preamble-in.rs rust-bridge-in.rs docs-old-preamble-in.rst docs-new-preamble-in.rst + @if test "$(PYTHON)" = ":"; then echo "Settings table table.py has changed, python is needed to regenerate the related settings files but python was not found. Please install python and re-run configure"; exit 1; fi + @if ! $(PYTHON) --version | grep -q "Python 3"; then echo $(PYTHON) should be at least version 3. Please install python 3 and re-run configure; exit 1; fi + (cd ${srcdir} && $(PYTHON) generate.py) + +clean-local: + rm -f cxxsettings-generated.cc rust/src/lib.rs + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/Makefile.in pdns-recursor-5.4.9/rec-rust-lib/Makefile.in --- pdns-recursor-5.2.13/rec-rust-lib/Makefile.in 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/Makefile.in 2026-10-26 09:47:08.881895300 +0000 @@ -0,0 +1,615 @@ +# Makefile.in generated by automake 1.17 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2024 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# It's a bit dirty that this Makefile also generates a file inside rust/src (lib.rs). +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = rec-rust-lib +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_check_sign.m4 \ + $(top_srcdir)/m4/ax_compare_version.m4 \ + $(top_srcdir)/m4/ax_compile_check_sizeof.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \ + $(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \ + $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/pdns_check_cargo.m4 \ + $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_dnstap.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_eddsa.m4 \ + $(top_srcdir)/m4/pdns_check_libcurl.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_python_venv.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_secure_memset.m4 \ + $(top_srcdir)/m4/pdns_check_time_t.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_coverage.m4 \ + $(top_srcdir)/m4/pdns_enable_lto.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_nod.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_tls.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_init_auto_vars.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_libcap.m4 \ + $(top_srcdir)/m4/pdns_with_libsodium.m4 \ + $(top_srcdir)/m4/pdns_with_libssl.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_service_user.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in README.md +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@ +BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@ +BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FSTRM_CFLAGS = @FSTRM_CFLAGS@ +FSTRM_LIBS = @FSTRM_LIBS@ +GREP = @GREP@ +HAVE_CXX17 = @HAVE_CXX17@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCAP_CFLAGS = @LIBCAP_CFLAGS@ +LIBCAP_LIBS = @LIBCAP_LIBS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBDL = @LIBDL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ +LIBSSL_LIBS = @LIBSSL_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMCTL = @SYSTEMCTL@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ +am__tar = @am__tar@ +am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nodcachedir = @nodcachedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +service_group = @service_group@ +service_user = @service_user@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + cxxsettings-generated.cc \ + cxxsettings-private.hh \ + cxxsettings.hh \ + docs-new-preamble-in.rst \ + docs-old-preamble-in.rst \ + generate.py \ + rust-bridge-in.rs \ + rust-preamble-in.rs \ + table.py \ + rust/src/bridge.hh \ + rust/src/lib.rs + +BUILT_SOURCES = cxxsettings-generated.cc rust/src/lib.rs +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign rec-rust-lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign rec-rust-lib/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -$(am__rm_f) $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: all check install install-am install-exec install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +all: cxxsettings-generated.cc rust/src/lib.rs + +# We need to clean in the Rust dir, as in some cases the Serde/CXX derive/generate code does not get +# re-run by cargo after rust/src/lib.rs changed because of a generate.py run. In that case we end up +# with a rust/src/lib.rs.h that does not contain e.g. field name or field type changes. This +# cleanup is now done from generate.py itself. +# +# Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make +cxxsettings-generated%cc rust/src/lib%rs: table.py generate.py rust-preamble-in.rs rust-bridge-in.rs docs-old-preamble-in.rst docs-new-preamble-in.rst + @if test "$(PYTHON)" = ":"; then echo "Settings table table.py has changed, python is needed to regenerate the related settings files but python was not found. Please install python and re-run configure"; exit 1; fi + @if ! $(PYTHON) --version | grep -q "Python 3"; then echo $(PYTHON) should be at least version 3. Please install python 3 and re-run configure; exit 1; fi + (cd ${srcdir} && $(PYTHON) generate.py) + +clean-local: + rm -f cxxsettings-generated.cc rust/src/lib.rs + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/rec-rust-lib/README.md pdns-recursor-5.4.9/rec-rust-lib/README.md --- pdns-recursor-5.2.13/rec-rust-lib/README.md 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/README.md 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,227 @@ +SETTINGS CODE +============= +This directory contains the code to generate both old-style as new style (YAML) settings code. + +Inside this directory, there is a `rust` subdirectory that contains the Rust code and build files. +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 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.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: + +* `rust`: This namespace contains the classes defined by CXX. +Note that it is sometimes needed to explicitly name it `::rust`, as the `pdns` namespace also has a subnamespace called `rust`. +* `pdns::rust::settings::rec`: The classes and functions generated by CXX, callable from C++. +* `pdns::settings::rec`: The classes and functions of the settings code implemented in C++. This is mainly the code handling the conversion of old-style definitions to new-style (and vice versa). + +Internally, the old-style settings are still used by the recursor code. +Rewriting the existing code to start using the new style settings directly would have made the PR introducing the new-style settings even bigger. +Therefore, we chose to keep the code *using* settings the same. +If a new-style settings YAML file is encountered, it will be parsed, validated and the resulting new-style settings will be used to set the old-style settings to the values found in the YAML file. +In the future, when old-style settings do not need to be supported any longer, the recursor itself can start to use the new style settings directly. + +A `rec_control show-yaml [file]` command has been added to show the conversion of old-style settings to the new-style YAML. + +This directory +-------------- +* `cxxsettings-generated.cc`: generated code that implements the C++ part of the settings code. +* `cxxsettings-private.hh`: private interface used by C++ settings code internally. +* `cxxsettings.hh`: public interface of C++ code to be used by pdns_recursor and rec_control. +* `cxxsupport.cc`: hand written C++ code. +* `docs-new-preamble-in.rst`: non-generated part of new settings docs. +* `docs-old-preamble-in.rst`: non-generated part of old settings docs. +* `generate.py`: the Python script to produce C++, Rust and .rst files based on `table.py`. +* `rust`: the directory containing rust code. +* `rust-bridge-in.rs`: file included in the generated Rust code, placed inside the CXX bridge module. +* `rust-preamble-in.rs`: file included in the generated Rust code as a preamble. +* `table.py`: the definitions of all settings. + +`rust` subdirectory +------------------- +* `Cargo.toml`: The definition of the Rust `settings` crate, including its dependencies. +* `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 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. + +The YAML settings are stored in a struct called (on the C++ side) `pdns::rust::settings::rec::Recursorsettings`. +This struct has a substruct for each section defined. +Each section has multiple typed variables. +Below we will tour some parts of the (generated) code. +An example settings file in YAML format: + +```yaml +dnssec: + log_bogus: true +incoming: + listen: + - 0.0.0.0:5301 + - '[::]:5301' +logging: + common_errors: true + disable_syslog: true + loglevel: 6 +recursor: + daemon: false + extended_resolution_errors: true + socket_dir: /tmp/rec + threads: 4 +webservice: + address: 127.0.0.1 + allow_from: + - 0.0.0.0/0 + api_key: secret + port: 8083 + webserver: true +``` + +The generated code +------------------ +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`: + +```python + { + 'name' : 'log_bogus', + 'section' : 'dnssec', + 'oldname' : 'dnssec-log-bogus', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Log DNSSEC bogus validations', + 'doc' : ''' +Log every DNSSEC validation failure. +**Note**: This is not logged per-query but every time records are validated as Bogus. + ''', + }, +``` + +The old-style documentation generated for this can be found in `../docs/settings.rst`: + +``` +.. _setting-dnssec-log-bogus: + +``dnssec-log-bogus`` +~~~~~~~~~~~~~~~~~~~~ + +- Boolean +- Default: no + +- YAML setting: :ref:`setting-yaml-dnssec.log_bogus` + +Log every DNSSEC validation failure. +**Note**: This is not logged per-query but every time records are validated as Bogus. +``` + +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: + +``dnssec.log_bogus`` +^^^^^^^^^^^^^^^^^^^^ + +- Boolean +- Default: ``false`` + +- Old style setting: :ref:`setting-dnssec-log-bogus` + +Log every DNSSEC validation failure. +**Note**: This is not logged per-query but every time records are validated as Bogus. +``` + +The C++ code generated from this entry can be found in `cxxsettings-generated.cc`. +The code to define the old-style settings, which is called by the recursor very early after startup and is a replacement for the hand-written code that defines all settings in the old recursor code. +Using generated code and generated docs makes sure the docs and the actual implementation are consistent. +Something which was not true for the old code in all cases. + +```cpp +void pdns::settings::rec::defineOldStyleSettings() + ... + ::arg().setSwitch("dnssec-log-bogus", "Log DNSSEC bogus validations") = "no"; + ... +``` + +There is also code generated to assign the current value of old-style `log_bogus` value to the right field in a `Recursorsettings` struct. +This code is used to convert the currently active settings to a YAML file (`pdns_recursor --config=diff`): +```cpp +void pdns::settings::rec::oldStyleSettingsToBridgeStruct(Recursorsettings& settings) + ... + settings.dnssec.log_bogus = arg().mustDo("dnssec-log-bogus"); + ... +``` + +Plus code to set the old-style setting, given a new-style struct: + +```cpp +void pdns::settings::rec::bridgeStructToOldStyleSettings(const Recursorsettings& settings) + ... + ::arg().set("dnssec-log-bogus") = to_arg(settings.dnssec.log_bogus); + ... +``` + +Lastly, there is code to support converting an old-style settings to a new-style struct found in `pdns::settings::rec::oldKVToBridgeStruct()`. +This code is used to convert old style settings files to YAML (used by `rec_control show-yaml`) and to generate a yaml file with all the defaults values (used by `pdns_recursor --config=default`). +The functions implementing that are `pdns::settings::rec::oldStyleSettingsFileToYaml` and `std::string pdns::settings::rec::defaultsToYaml()`, found in `cxxsupport.cc`. + +The Rust code generated by `generate.py` can be found in `rust/src/lib.rs`. +It contains these snippets that define the `log_bogus` field in the section struct `Dnssec` and the `dnssec` field in the `Recursorsettings` struct: + +```rust +pub struct Dnssec { + ... + #[serde(default, skip_serializing_if = "crate::is_default")] + log_bogus: bool, + ... +} +pub struct Recursorsettings { + ... + #[serde(default, skip_serializing_if = "crate::is_default")] + dnssec: Dnssec, + ... +} +``` +The `rust/src/lib.rs` file also contains the generated code to handle Serde defaults. +More details on this can be found in `generate.py`. + +The C++ version of the `Recursorsettings` struct and its substructs can be found in the CXX generated `rust/lib.rs.h` file: + +```cpp +struct Recursorsettings final { + ... + ::pdns::rust::settings::rec::Dnssec dnssec; + ... + }; + ... +struct Dnssec final { + ... + bool log_bogus; + ... +}; +``` + +The Rust functions callable from C++ are listed in `rust-bridge-in.rs` which gets included into `rust/src/lib.rs` by `generate.py` +An example is the function + +```rust + fn parse_yaml_string(str: &String) -> Result; +``` + +Which parses YAML and produces a struct with all the settings. +Settings that are not mentioned in the YAML string will have their default value. + +`rust/lib.rs.h` contains the corresponding C++ prototype, defined in the `pdns::rust::settings::rec` namespace: + +```cpp +::pdns::rust::settings::rec::Recursorsettings parse_yaml_string(::rust::String const &str); +``` + +The C++ function `pdns::settings::rec::readYamlSettings()` defined in `cxxsupport.cc` and called in `../rec-main.cc` calls the Rust function `pdns::rust::settings::rec::parse_yaml_string()` to do the actual YAML parsing. \ No newline at end of file diff -Nru pdns-recursor-5.2.13/rec-rust-lib/cxxsettings-private.hh pdns-recursor-5.4.9/rec-rust-lib/cxxsettings-private.hh --- pdns-recursor-5.2.13/rec-rust-lib/cxxsettings-private.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/cxxsettings-private.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,97 @@ +/* + * 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 +#include +#include +#include + +#include "rust/lib.rs.h" +#include "misc.hh" + +using pdns::rust::settings::rec::AuthZone; +using pdns::rust::settings::rec::ForwardZone; +using pdns::rust::settings::rec::Recursorsettings; + +namespace pdns::settings::rec +{ +::rust::Vec<::rust::String> getStrings(const std::string& name); +::rust::Vec getForwardZones(const std::string& name); +::rust::Vec getAuthZones(const std::string& name); + +inline std::string to_arg(bool arg) +{ + return arg ? "yes" : "no"; +} + +inline std::string to_arg(uint64_t arg) +{ + return std::to_string(arg); +} + +inline std::string to_arg(double arg) +{ + return std::to_string(arg); +} + +inline std::string to_arg(const ::rust::String& str) +{ + return std::string(str); +} + +std::string to_arg(const AuthZone& authzone); +std::string to_arg(const ForwardZone& forwardzone); + +template +std::string to_arg(const ::rust::Vec& vec) +{ + std::ostringstream str; + for (auto iter = vec.begin(); iter != vec.end(); ++iter) { + if (iter != vec.begin()) { + str << ','; + } + str << to_arg(*iter); + } + return str.str(); +} + +inline void to_yaml(bool& field, const std::string& val) +{ + field = val != "no" && val != "off"; +} + +inline void to_yaml(::rust::String& field, const std::string& val) +{ + field = val; +} + +inline void to_yaml(::rust::Vec<::rust::String>& field, const std::string& val) +{ + stringtok(field, val, ", ;"); +} + +void to_yaml(uint64_t& field, const std::string& val); +void to_yaml(double& field, const std::string& val); +void to_yaml(::rust::Vec& field, const std::string& val); +void to_yaml(::rust::Vec& field, const std::string& val, bool recurse = false); +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/cxxsettings.hh pdns-recursor-5.4.9/rec-rust-lib/cxxsettings.hh --- pdns-recursor-5.2.13/rec-rust-lib/cxxsettings.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/cxxsettings.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,59 @@ +/* + * 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 +#include "rust/cxx.h" +#include "rust/lib.rs.h" +#include "sholder.hh" +#include "logging.hh" +#include "rec-lua-conf.hh" + +namespace pdns::settings::rec +{ +enum YamlSettingsStatus : uint8_t +{ + OK, + CannotOpen, + PresentButFailed, +}; + +void defineOldStyleSettings(); +void oldStyleSettingsToBridgeStruct(pdns::rust::settings::rec::Recursorsettings& settings); +void oldStyleForwardsFileToBridgeStruct(const std::string& filename, ::rust::Vec& vec); +void oldStyleAllowFileToBridgeStruct(const std::string& filename, ::rust::Vec<::rust::String>& vec); +bool oldKVToBridgeStruct(string& key, const string& value, ::rust::String& section, ::rust::String& fieldname, ::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue); +std::string oldStyleSettingsFileToYaml(const string& fname, bool mainFile); +std::string defaultsToYaml(bool postProcess = true); +YamlSettingsStatus readYamlSettings(const std::string& configname, const std::string& includeDirOnCommandLine, rust::settings::rec::Recursorsettings& settings, std::string& msg, Logr::log_t log); +void processAPIDir(const string& includeDirOnCommandLine, pdns::rust::settings::rec::Recursorsettings& settings, Logr::log_t log); +void bridgeStructToOldStyleSettings(const pdns::rust::settings::rec::Recursorsettings& settings); +void readYamlForwardZonesFile(const std::string& filename, ::rust::Vec& vec, Logr::log_t log); +void readYamlAllowFromFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log); +void readYamlAllowNotifyForFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log); +void setArgsForZoneRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings); +void setArgsForACLRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings); +void fromLuaConfigToBridgeStruct(LuaConfigItems& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings); +void fromBridgeStructToLuaConfig(const pdns::rust::settings::rec::Recursorsettings& settings, LuaConfigItems& luaConfig, ProxyMapping& proxyMapping, OpenTelemetryTraceConditions& conditions); +bool luaItemSet(const pdns::rust::settings::rec::Recursorsettings& settings); +YamlSettingsStatus tryReadYAML(const string& yamlconfigname, bool setGlobals, bool& yamlSettings, bool& luaSettingsInYAML, rust::settings::rec::Recursorsettings& settings, Logr::log_t startupLog, Logr::Priority level = Logr::Debug); +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/cxxsupport.cc pdns-recursor-5.4.9/rec-rust-lib/cxxsupport.cc --- pdns-recursor-5.2.13/rec-rust-lib/cxxsupport.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/cxxsupport.cc 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,1549 @@ +/* + * 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 +#include +#include +#include +#include + +#include "namespaces.hh" +#include "arguments.hh" +#include "misc.hh" +#include "cxxsettings.hh" +#include "cxxsettings-private.hh" +#include "logger.hh" +#include "logging.hh" +#include "rec-lua-conf.hh" +#include "root-dnssec.hh" +#include "dnsrecords.hh" +#include "base64.hh" +#include "validate-recursor.hh" +#include "threadname.hh" +#include "iputils.hh" +#include "bridge.hh" +#include "rec-rust-lib/rust/web.rs.h" +#include "rec-rust-lib/rust/misc.rs.h" +#include "uuid-utils.hh" + +::rust::Vec<::rust::String> pdns::settings::rec::getStrings(const std::string& name) +{ + ::rust::Vec<::rust::String> vec; + to_yaml(vec, arg()[name]); + return vec; +} + +::rust::Vec pdns::settings::rec::getForwardZones(const string& name) +{ + ::rust::Vec vec; + const auto recurse = name == "forward-zones-recurse"; + to_yaml(vec, arg()[name], recurse); + return vec; +} + +::rust::Vec pdns::settings::rec::getAuthZones(const string& name) +{ + ::rust::Vec vec; + to_yaml(vec, arg()[name]); + return vec; +} + +void pdns::settings::rec::oldStyleForwardsFileToBridgeStruct(const std::string& file, ::rust::Vec& vec) +{ + auto filePtr = pdns::UniqueFilePtr(fopen(file.c_str(), "r")); + if (!filePtr) { + throw PDNSException("Error opening forward-zones-file '" + file + "': " + stringerror()); + } + + string line; + int linenum = 0; + while (linenum++, stringfgets(filePtr.get(), line)) { + boost::trim(line); + if (line.length() == 0 || line.at(0) == '#') { // Comment line, skip to the next line + continue; + } + auto [domain, instructions] = splitField(line, '='); + instructions = splitField(instructions, '#').first; // Remove EOL comments + boost::trim(domain); + boost::trim(instructions); + if (domain.empty() || instructions.empty()) { + throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + file); + } + bool allowNotify = false; + bool recurse = false; + for (; !domain.empty(); domain.erase(0, 1)) { + switch (domain[0]) { + case '+': + recurse = true; + continue; + case '^': + allowNotify = true; + continue; + } + break; + } + if (domain.empty()) { + throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + file); + } + ::rust::Vec<::rust::String> addresses; + stringtok(addresses, instructions, ",; "); + ForwardZone forwardzone{domain, std::move(addresses), recurse, allowNotify}; + vec.push_back(std::move(forwardzone)); + } +} + +void pdns::settings::rec::oldStyleAllowFileToBridgeStruct(const std::string& file, ::rust::Vec<::rust::String>& vec) +{ + string line; + ifstream ifs(file); + if (!ifs) { + int err = errno; + throw runtime_error("Could not open '" + file + "': " + stringerror(err)); + } + + while (getline(ifs, line)) { + auto pos = line.find('#'); + if (pos != string::npos) { + line.resize(pos); + } + boost::trim(line); + if (line.empty()) { + continue; + } + vec.emplace_back(line); + } +} + +static void mergeYamlSubFile(const std::string& configname, Recursorsettings& settings, bool allowabsent, Logr::log_t log) +{ + auto file = ifstream(configname); + if (!file.is_open()) { + if (allowabsent) { + return; + } + throw runtime_error("Cannot open " + configname); + } + log->info(Logr::Notice, "Processing YAML settings", "path", Logging::Loggable(configname)); + auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + pdns::rust::settings::rec::merge(settings, data); +} + +static void possiblyConvertACLFile(const string& includeDir, const string& apiDir, const std::string& filename, Logr::log_t log) +{ + auto path = includeDir; + path.append("/").append(filename).append(".conf"); + auto file = ifstream(path); + if (!file.is_open()) { + // Not an error, file just is not there + return; + } + rust::vec result; + std::string line; + while (getline(file, line)) { + auto pos = line.find('#'); + if (pos != string::npos) { + line.resize(pos); + } + boost::trim(line); + if (line.empty()) { + continue; + } + auto plusis = line.find("+="); + if (plusis != string::npos) { + auto val = line.substr(plusis + 2); + boost::trim(val); + vector acls; + stringtok(acls, val, " ,\t"); + for (const auto& acl : acls) { + result.emplace_back(acl); + } + } + } + + rust::string key = "allow_from"; + rust::string filekey = "allow_from_file"; + if (filename == "allow-notify-from") { + key = "allow_notify_from"; + filekey = "allow_notify_from_file"; + } + const auto yaml = pdns::rust::settings::rec::allow_from_to_yaml_string_incoming(key, filekey, result); + + string yamlfilename = apiDir; + yamlfilename.append("/").append(filename).append(".yml"); + string tmpfilename = yamlfilename + ".tmp"; + ofstream ofconf(tmpfilename); + if (!ofconf) { + int err = errno; + log->error(Logr::Error, err, "Cannot open for file for writing YAML", "to", Logging::Loggable(tmpfilename)); + throw runtime_error("YAML Conversion"); + } + ofconf << "# Generated by pdns-recursor REST API, DO NOT EDIT" << endl; + ofconf << yaml << endl; + ofconf.close(); + if (ofconf.bad()) { + log->error(Logr::Error, "Error writing YAML", "to", Logging::Loggable(tmpfilename)); + unlink(tmpfilename.c_str()); + throw runtime_error("YAML Conversion"); + } + if (rename(path.c_str(), (path + ".converted").c_str()) != 0) { + int err = errno; + log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path), "to", Logging::Loggable(path + ".converted")); + unlink(tmpfilename.c_str()); + throw runtime_error("YAML Conversion"); + } + + if (rename(tmpfilename.c_str(), yamlfilename.c_str()) != 0) { + int err = errno; + log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(tmpfilename), "to", Logging::Loggable(yamlfilename)); + if (rename((path + ".converted").c_str(), path.c_str()) != 0) { + err = errno; + log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path + ".converted"), "to", Logging::Loggable(path)); + } + throw runtime_error("YAML Conversion"); + } + log->info(Logr::Notice, "Converted to YAML", "file", Logging::Loggable(path), "to", Logging::Loggable(yamlfilename)); +} + +static void fileCopy(const string& src, const string& dst, Logr::log_t log) +{ + ifstream ifconf(src); + if (!ifconf) { + log->info(Logr::Error, "Cannot open for file for reading", "file", Logging::Loggable(src)); + throw runtime_error("YAML Conversion"); + } + ofstream ofconf(dst); + if (!ofconf) { + log->info(Logr::Error, "Cannot open for file for writing YAML", "to", Logging::Loggable(dst)); + throw runtime_error("YAML Conversion"); + } + for (;;) { + auto character = ifconf.get(); + if (ifconf.eof()) { + break; + } + if (ifconf.bad()) { + int err = errno; + log->error(Logr::Error, err, "Error reading", "to", Logging::Loggable(src)); + throw runtime_error("YAML Conversion"); + } + ofconf.put(static_cast(character)); + if (ofconf.bad()) { + int err = errno; + log->error(Logr::Error, err, "Error writing YAML", "to", Logging::Loggable(dst)); + throw runtime_error("YAML Conversion"); + } + } + ifconf.close(); + ofconf.close(); + if (ofconf.bad()) { + log->error(Logr::Error, "Error writing YAML", "to", Logging::Loggable(dst)); + throw runtime_error("YAML Conversion"); + } +} + +static void possiblyConvertForwardsAndAuths(const std::string& includeDir, const std::string& apiDir, Logr::log_t log) +{ + std::vector forwAndAuthFiles{}; + ::arg().gatherIncludes(includeDir, "..conf", forwAndAuthFiles); + pdns::rust::settings::rec::Recursorsettings settings{}; + for (const auto& file : forwAndAuthFiles) { + auto yaml = pdns::settings::rec::oldStyleSettingsFileToYaml(file, false); + pdns::rust::settings::rec::merge(settings, yaml); + } + const string yamlAPiZonesFile = apiDir + "/apizones"; + + for (auto& zone : settings.recursor.auth_zones) { + const std::string origName(zone.file); + std::string newName(zone.file); + newName.replace(0, includeDir.length(), apiDir); + log->info(Logr::Notice, "Copying auth zone file", "file", Logging::Loggable(origName), "to", Logging::Loggable(newName)); + fileCopy(origName, newName, log); + zone.file = ::rust::String(newName); + api_add_auth_zone(yamlAPiZonesFile, zone); + } + api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones); + api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones_recurse); + for (const auto& file : forwAndAuthFiles) { + if (rename(file.c_str(), (file + ".converted").c_str()) != 0) { + int err = errno; + log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(file), "to", Logging::Loggable(file + ".converted")); + } + } +} + +void pdns::settings::rec::processAPIDir(const string& includeDirOnCommandLine, pdns::rust::settings::rec::Recursorsettings& settings, Logr::log_t log) +{ + auto apiDir = std::string(settings.webservice.api_dir); + if (apiDir.empty()) { + return; + } + auto includeDir = std::string(settings.recursor.include_dir); + if (!includeDirOnCommandLine.empty()) { + includeDir = includeDirOnCommandLine; + } + if (includeDir == apiDir) { + throw runtime_error("Active YAML settings do not allow include_dir to be equal to api_dir"); + } + const std::array aclFiles = { + "allow-from", + "allow-notify-from"}; + for (const auto& file : aclFiles) { + possiblyConvertACLFile(includeDir, apiDir, file, log); + auto path = apiDir; + path.append("/").append(file).append(".yml"); + mergeYamlSubFile(path, settings, true, log); + } + possiblyConvertForwardsAndAuths(includeDir, apiDir, log); +} + +template +static void addToAllowNotifyFor(Recursorsettings& settings, const rust::Vec& vec) +{ + for (const auto& item : vec) { + if (item.notify_allowed) { + settings.incoming.allow_notify_for.emplace_back(item.zone); + } + } +} + +pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::readYamlSettings(const std::string& configname, const std::string& includeDirOnCommandLine, Recursorsettings& settings, std::string& msg, Logr::log_t log) +{ + auto file = ifstream(configname); + if (!file.is_open()) { + msg = stringerror(errno); + return YamlSettingsStatus::CannotOpen; + } + log->info(Logr::Notice, "Processing main YAML settings", "path", Logging::Loggable(configname)); + try { + auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + auto yamlstruct = pdns::rust::settings::rec::parse_yaml_string(data); + std::vector yamlFiles; + ::arg().gatherIncludes(!includeDirOnCommandLine.empty() ? includeDirOnCommandLine : string(yamlstruct.recursor.include_dir), + ".yml", yamlFiles); + for (const auto& yamlfile : yamlFiles) { + mergeYamlSubFile(yamlfile, yamlstruct, false, log); + } + // Add the zones with notify_allowed to allow_notify_for. For a forward_zones_file that will be + // taken care of elsewhere. One drawback: the zones will be shown in allow_notify_for if you + // run --config, while they aren't actually there in any config file. + addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forward_zones); + addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forward_zones_recurse); + addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forwarding_catalog_zones); + yamlstruct.validate(); + settings = std::move(yamlstruct); + return YamlSettingsStatus::OK; + } + catch (const ::rust::Error& ex) { + msg = ex.what(); + return YamlSettingsStatus::PresentButFailed; + } + catch (const std::exception& ex) { + msg = ex.what(); + return YamlSettingsStatus::PresentButFailed; + } + catch (...) { + msg = "Unexpected exception processing YAML"; + return YamlSettingsStatus::PresentButFailed; + } +} + +void pdns::settings::rec::readYamlAllowFromFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log) +{ + log->info(Logr::Notice, "Processing allow YAML settings", "path", Logging::Loggable(filename)); + auto file = ifstream(filename); + if (!file.is_open()) { + throw runtime_error(stringerror(errno)); + } + auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_allow_from(data); + pdns::rust::settings::rec::validate_allow_from(filename, yamlvec); + vec = std::move(yamlvec); +} + +void pdns::settings::rec::readYamlForwardZonesFile(const std::string& filename, ::rust::Vec& vec, Logr::log_t log) +{ + log->info(Logr::Notice, "Processing forwarding YAML settings", "path", Logging::Loggable(filename)); + auto file = ifstream(filename); + if (!file.is_open()) { + throw runtime_error(stringerror(errno)); + } + auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_forward_zones(data); + pdns::rust::settings::rec::validate_forward_zones("forward_zones", yamlvec); + vec = std::move(yamlvec); +} + +void pdns::settings::rec::readYamlAllowNotifyForFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log) +{ + log->info(Logr::Notice, "Processing allow-notify-for YAML settings", "path", Logging::Loggable(filename)); + auto file = ifstream(filename); + if (!file.is_open()) { + throw runtime_error(stringerror(errno)); + } + auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); + auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_allow_notify_for(data); + pdns::rust::settings::rec::validate_allow_notify_for("allow-notify-for", yamlvec); + vec = std::move(yamlvec); +} + +std::string pdns::settings::rec::to_arg(const AuthZone& authzone) +{ + std::ostringstream str; + str << to_arg(authzone.zone) << '=' << to_arg(authzone.file); + return str.str(); +} + +std::string pdns::settings::rec::to_arg(const ForwardZone& forwardzone) +{ + std::ostringstream str; + str << to_arg(forwardzone.zone) << '='; + const auto& vec = forwardzone.forwarders; + for (auto iter = vec.begin(); iter != vec.end(); ++iter) { + if (iter != vec.begin()) { + str << ';'; + } + str << to_arg(*iter); + } + return str.str(); +} + +void pdns::settings::rec::setArgsForZoneRelatedSettings(Recursorsettings& settings) +{ + ::arg().set("forward-zones") = to_arg(settings.recursor.forward_zones); + ::arg().set("forward-zones-file") = to_arg(settings.recursor.forward_zones_file); + ::arg().set("forward-zones-recurse") = to_arg(settings.recursor.forward_zones_recurse); + ::arg().set("auth-zones") = to_arg(settings.recursor.auth_zones); + ::arg().set("allow-notify-for") = to_arg(settings.incoming.allow_notify_for); + ::arg().set("allow-notify-for-file") = to_arg(settings.incoming.allow_notify_for_file); + ::arg().set("export-etc-hosts") = to_arg(settings.recursor.export_etc_hosts); + ::arg().set("serve-rfc1918") = to_arg(settings.recursor.serve_rfc1918); +} + +void pdns::settings::rec::setArgsForACLRelatedSettings(Recursorsettings& settings) +{ + ::arg().set("allow-from") = to_arg(settings.incoming.allow_from); + ::arg().set("allow-from-file") = to_arg(settings.incoming.allow_from_file); + ::arg().set("allow-notify-from") = to_arg(settings.incoming.allow_notify_from); + ::arg().set("allow-notify-from-file") = to_arg(settings.incoming.allow_notify_from_file); + ::arg().set("proxy-protocol-from") = to_arg(settings.incoming.proxy_protocol_from); + ::arg().set("proxy-protocol-exceptions") = to_arg(settings.incoming.proxy_protocol_exceptions); +} + +void pdns::settings::rec::to_yaml(uint64_t& field, const std::string& val) +{ + if (val.empty()) { + field = 0; + return; + } + + checked_stoi_into(field, val, nullptr, 0); +} + +void pdns::settings::rec::to_yaml(double& field, const std::string& val) +{ + if (val.empty()) { + field = 0.0; + return; + } + + const auto* cptr_orig = val.c_str(); + char* cptr_ret = nullptr; + auto retval = strtod(cptr_orig, &cptr_ret); + + field = retval; +} + +void pdns::settings::rec::to_yaml(::rust::Vec& field, const std::string& val) +{ + vector zones; + stringtok(zones, val, " ,\t\n\r"); + for (const auto& zone : zones) { + auto headers = splitField(zone, '='); + boost::trim(headers.first); + boost::trim(headers.second); + AuthZone authzone{headers.first, headers.second}; + field.push_back(std::move(authzone)); + } +} + +void pdns::settings::rec::to_yaml(::rust::Vec& field, const std::string& val, bool recurse) +{ + vector zones; + stringtok(zones, val, " ,\t\n\r"); + for (const auto& zone : zones) { + auto headers = splitField(zone, '='); + boost::trim(headers.first); + boost::trim(headers.second); + ::rust::Vec<::rust::String> addresses; + stringtok(addresses, headers.second, " ;"); + ForwardZone forwardzone{headers.first, std::move(addresses), recurse, false}; + field.push_back(std::move(forwardzone)); + } +} + +using FieldMap = std::map, pdns::rust::settings::rec::OldStyle>; + +static bool simpleRustType(const ::rust::String& rname) +{ + return rname == "bool" || rname == "u64" || rname == "f64" || rname == "String"; +} + +static void processLine(const std::string& arg, FieldMap& map, bool mainFile) +{ + string var; + string val; + string::size_type pos = 0; + bool incremental = false; + + if (arg.find("--") == 0 && (pos = arg.find("+=")) != string::npos) // this is a --port+=25 case + { + var = arg.substr(2, pos - 2); + val = arg.substr(pos + 2); + incremental = true; + } + else if (arg.find("--") == 0 && (pos = arg.find('=')) != string::npos) // this is a --port=25 case + { + var = arg.substr(2, pos - 2); + val = arg.substr(pos + 1); + } + else if (arg.find("--") == 0 && (arg.find('=') == string::npos)) // this is a --daemon case + { + var = arg.substr(2); + val = ""; + } + else if (arg[0] == '-' && arg.length() > 1) { + var = arg.substr(1); + val = ""; + } + boost::trim(var); + if (var.empty()) { + return; + } + pos = val.find_first_not_of(" \t"); // strip leading whitespace + if (pos != 0 && pos != string::npos) { + val = val.substr(pos); + } + + ::rust::String section; + ::rust::String fieldname; + ::rust::String type_name; + pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}; + if (pdns::settings::rec::oldKVToBridgeStruct(var, val, section, fieldname, type_name, rustvalue)) { + auto overriding = !mainFile && !incremental && !simpleRustType(type_name); + auto [existing, inserted] = map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, var, std::move(type_name), rustvalue, overriding}}); + if (!inserted) { + // Simple values overwrite always + existing->second.value.bool_val = rustvalue.bool_val; + existing->second.value.u64_val = rustvalue.u64_val; + existing->second.value.f64_val = rustvalue.f64_val; + existing->second.value.string_val = rustvalue.string_val; + // List values only if = was used + if (!incremental) { + existing->second.value.vec_string_val.clear(); + existing->second.value.vec_forwardzone_val.clear(); + existing->second.value.vec_authzone_val.clear(); + } + for (const auto& add : rustvalue.vec_string_val) { + existing->second.value.vec_string_val.emplace_back(add); + } + for (const auto& add : rustvalue.vec_forwardzone_val) { + existing->second.value.vec_forwardzone_val.emplace_back(add); + } + for (const auto& add : rustvalue.vec_authzone_val) { + existing->second.value.vec_authzone_val.emplace_back(add); + } + } + } +} + +std::string pdns::settings::rec::oldStyleSettingsFileToYaml(const string& fname, bool mainFile) +{ + string line; + string pline; + + std::ifstream configFileStream(fname); + if (!configFileStream) { + int err = errno; + throw runtime_error("Cannot read " + fname + ": " + stringerror(err)); + } + + // Read the old-style config file and produce a map with the data, taking into account the + // difference between = and += + FieldMap map; + while (getline(configFileStream, pline)) { + boost::trim_right(pline); + + if (!pline.empty() && pline[pline.size() - 1] == '\\') { + line += pline.substr(0, pline.length() - 1); + continue; + } + + line += pline; + + // strip everything after a # + string::size_type pos = line.find('#'); + if (pos != string::npos) { + // make sure it's either first char or has whitespace before + // fixes issue #354 + if (pos == 0 || (std::isspace(line[pos - 1]) != 0)) { + line = line.substr(0, pos); + } + } + + // strip trailing spaces + boost::trim_right(line); + + // strip leading spaces + pos = line.find_first_not_of(" \t\r\n"); + if (pos != string::npos) { + line = line.substr(pos); + } + + processLine("--" + line, map, mainFile); + line = ""; + } + + // Convert the map to a vector, as CXX does not have any dictionary like support. + ::rust::Vec vec; + vec.reserve(map.size()); + for (const auto& entry : map) { + vec.emplace_back(entry.second); + } + return std::string(pdns::rust::settings::rec::map_to_yaml_string(vec)); +} + +std::string pdns::settings::rec::defaultsToYaml(bool postProcess) +{ + // In this function we make use of the fact that we know a little about the formatting of YAML by + // serde_yaml. ATM there's no way around that, as serde_yaml itself does not have any support for + // comments (other than stripping them while parsing). So produced YAML cannot have any comments. + + // First we construct a map of (section, name) to info about the field (oldname, type, value etc) + FieldMap map; + for (const auto& var : arg().list()) { + if (const auto newname = ArgvMap::isDeprecated(var); !newname.empty()) { + continue; + } + ::rust::String section; + ::rust::String fieldname; + ::rust::String type_name; + pdns::rust::settings::rec::Value rustvalue{}; + string name = var; + string val = arg().getDefault(var); + if (pdns::settings::rec::oldKVToBridgeStruct(name, val, section, fieldname, type_name, rustvalue)) { + map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, name, std::move(type_name), std::move(rustvalue), false}}); + } + } + + // Should be generated + auto def = [&](const string& section, const string& name, const string& type) { + pdns::rust::settings::rec::Value rustvalue{}; + // Dirty hack: trustanchorfile_interval is the only u64 value, set the right default for it. + // 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, std::move(rustvalue), false}}); + }; + def("dnssec", "trustanchors", "Vec"); + def("dnssec", "negative_trustanchors", "Vec"); + def("dnssec", "trustanchorfile", "String"); + def("dnssec", "trustanchorfile_interval", "u64"); + def("logging", "protobuf_servers", "Vec"); + def("logging", "outgoing_protobuf_servers", "Vec"); + def("logging", "dnstap_framestream_servers", "Vec"); + def("logging", "dnstap_nod_framestream_servers", "Vec"); + def("recursor", "rpzs", "Vec"); + def("recursor", "sortlists", "Vec"); + def("recordcache", "zonetocaches", "Vec"); + def("recursor", "allowed_additional_qtypes", "Vec"); + def("incoming", "proxymappings", "Vec"); + def("recursor", "forwarding_catalog_zones", "Vec"); + def("webservice", "listen", "Vec"); + def("recursor", "tls_configurations", "Vec"); + // End of should be generated XXX + + // Convert the map to a vector, as CXX does not have any dictionary like support. + ::rust::Vec vec; + vec.reserve(map.size()); + for (const auto& entry : map) { + vec.emplace_back(entry.second); + } + auto defs = std::string(pdns::rust::settings::rec::map_to_yaml_string(vec)); + + if (!postProcess) { + return defs; + } + // We now have a YAML string, with all sections and all default values. Do a litle bit of parsing + // to insert the help text lines. + std::vector lines; + stringtok(lines, defs, "\n"); + std::string res; + + // These two RE's know about the formatting generated by serde_yaml + std::regex sectionRE("^(\\w+):"); + std::regex fieldRE("^ (\\w+):"); + std::string section; + std::string field; + + for (const auto& line : lines) { + bool withHelp = false; + bool sectionChange = false; + std::smatch matches; + std::regex_search(line, matches, sectionRE); + if (!matches.empty()) { + section = matches[1]; + sectionChange = true; + } + std::regex_search(line, matches, fieldRE); + if (!matches.empty()) { + field = matches[1]; + withHelp = true; + } + if (withHelp) { + std::string oldname; + if (auto iter = map.find(make_pair(section, field)); iter != map.end()) { + oldname = std::string(iter->second.old_name); + } + res += "##### "; + auto help = arg().getHelp(oldname); + if (help.empty()) { + replace(oldname.begin(), oldname.end(), '_', '-'); + help = arg().getHelp(oldname); + } + res += help; + res += '\n'; + } + if (sectionChange) { + res += "\n######### SECTION "; + res += section; + res += " #########\n"; + res += line; + } + else { + res += "# "; + res += line; + } + res += '\n'; + } + return res; +} + +namespace +{ +void fromLuaToRust(const LuaConfigItems& luaConfig, pdns::rust::settings::rec::Dnssec& dnssec) +{ + dnssec.trustanchorfile = luaConfig.trustAnchorFileInfo.fname; + dnssec.trustanchorfile_interval = luaConfig.trustAnchorFileInfo.interval; + dnssec.trustanchors.clear(); + for (const auto& anchors : luaConfig.dsAnchors) { + ::rust::Vec<::rust::String> dsRecords; + for (const auto& dsRecord : anchors.second) { + const auto dsString = dsRecord.getZoneRepresentation(); + if (anchors.first != g_rootdnsname || std::find(rootDSs.begin(), rootDSs.end(), dsString) == rootDSs.end()) { + dsRecords.emplace_back(dsRecord.getZoneRepresentation()); + } + } + if (!dsRecords.empty()) { + pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), std::move(dsRecords)}; + dnssec.trustanchors.emplace_back(trustAnchor); + } + } + for (const auto& anchors : luaConfig.negAnchors) { + pdns::rust::settings::rec::NegativeTrustAnchor negtrustAnchor{anchors.first.toString(), anchors.second}; + dnssec.negative_trustanchors.emplace_back(negtrustAnchor); + } +} + +void fromLuaToRust(const ProtobufExportConfig& pbConfig, pdns::rust::settings::rec::ProtobufServer& pbServer) +{ + for (const auto& server : pbConfig.servers) { + pbServer.servers.emplace_back(server.toStringWithPort()); + } + pbServer.timeout = pbConfig.timeout; + pbServer.maxQueuedEntries = pbConfig.maxQueuedEntries; + pbServer.reconnectWaitTime = pbConfig.reconnectWaitTime; + pbServer.taggedOnly = pbConfig.taggedOnly; + pbServer.asyncConnect = pbConfig.asyncConnect; + pbServer.logQueries = pbConfig.logQueries; + pbServer.logResponses = pbConfig.logResponses; + for (const auto num : pbConfig.exportTypes) { + pbServer.exportTypes.emplace_back(QType(num).toString()); + } + pbServer.logMappedFrom = pbConfig.logMappedFrom; +} + +void fromLuaToRust(const FrameStreamExportConfig& fsc, pdns::rust::settings::rec::DNSTapFrameStreamServer& dnstap) +{ + for (const auto& server : fsc.servers) { + dnstap.servers.emplace_back(server); + } + dnstap.logQueries = fsc.logQueries; + dnstap.logResponses = fsc.logResponses; + dnstap.bufferHint = fsc.bufferHint; + dnstap.flushTimeout = fsc.flushTimeout; + dnstap.inputQueueSize = fsc.inputQueueSize; + dnstap.outputQueueSize = fsc.outputQueueSize; + dnstap.queueNotifyThreshold = fsc.queueNotifyThreshold; + dnstap.reopenInterval = fsc.reopenInterval; +} + +void fromLuaToRust(const FrameStreamExportConfig& fsc, pdns::rust::settings::rec::DNSTapNODFrameStreamServer& dnstap) +{ + for (const auto& server : fsc.servers) { + dnstap.servers.emplace_back(server); + } + dnstap.logNODs = fsc.logNODs; + dnstap.logUDRs = fsc.logUDRs; + dnstap.bufferHint = fsc.bufferHint; + dnstap.flushTimeout = fsc.flushTimeout; + dnstap.inputQueueSize = fsc.inputQueueSize; + dnstap.outputQueueSize = fsc.outputQueueSize; + dnstap.queueNotifyThreshold = fsc.queueNotifyThreshold; + dnstap.reopenInterval = fsc.reopenInterval; +} + +void assign(pdns::rust::settings::rec::TSIGTriplet& var, const TSIGTriplet& tsig) +{ + var.name = tsig.name.empty() ? "" : tsig.name.toStringNoDot(); + var.algo = tsig.algo.empty() ? "" : tsig.algo.toStringNoDot(); + var.secret = Base64Encode(tsig.secret); +} + +void assign(TSIGTriplet& var, const pdns::rust::settings::rec::TSIGTriplet& tsig) +{ + if (!tsig.name.empty()) { + var.name = DNSName(std::string(tsig.name)); + } + if (!tsig.algo.empty()) { + var.algo = DNSName(std::string(tsig.algo)); + } + B64Decode(std::string(tsig.secret), var.secret); +} + +std::string cvt(DNSFilterEngine::PolicyKind kind) +{ + switch (kind) { + case DNSFilterEngine::PolicyKind::NoAction: + return "NoAction"; + case DNSFilterEngine::PolicyKind::Drop: + return "Drop"; + case DNSFilterEngine::PolicyKind::NXDOMAIN: + return "NXDOMAIN"; + case DNSFilterEngine::PolicyKind::NODATA: + return "NODATA"; + case DNSFilterEngine::PolicyKind::Truncate: + return "Truncate"; + case DNSFilterEngine::PolicyKind::Custom: + return "Custom"; + } + return "UnknownPolicyKind"; +} + +void fromLuaToRust(const vector& rpzs, pdns::rust::settings::rec::Recursor& rec) +{ + for (const auto& rpz : rpzs) { + pdns::rust::settings::rec::RPZ rustrpz{ + .name = "", + .addresses = {}, + .defcontent = "", + .defpol = "", + .defpolOverrideLocalData = true, + .defttl = std::numeric_limits::max(), + .extendedErrorCode = std::numeric_limits::max(), + .extendedErrorExtra = "", + .includeSOA = false, + .ignoreDuplicates = false, + .maxTTL = std::numeric_limits::max(), + .policyName = "", + .tags = {}, + .overridesGettag = true, + .zoneSizeHint = 0, + .tsig = {}, + .refresh = 0, + .maxReceivedMBytes = 0, + .localAddress = "", + .axfrTimeout = 20, + .dumpFile = "", + .seedFile = "", + }; + + for (const auto& address : rpz.zoneXFRParams.primaries) { + rustrpz.addresses.emplace_back(address); + } + rustrpz.name = rpz.zoneXFRParams.name; + rustrpz.defcontent = rpz.defcontent; + if (rpz.defpol) { + rustrpz.defpol = cvt(rpz.defpol->d_kind); + rustrpz.defttl = rpz.defpol->d_ttl; + } + rustrpz.defpolOverrideLocalData = rpz.defpolOverrideLocal; + rustrpz.extendedErrorCode = rpz.extendedErrorCode; + rustrpz.extendedErrorExtra = rpz.extendedErrorExtra; + rustrpz.includeSOA = rpz.includeSOA; + rustrpz.ignoreDuplicates = rpz.ignoreDuplicates; + rustrpz.maxTTL = rpz.maxTTL; + rustrpz.policyName = rpz.polName; + for (const auto& tag : rpz.tags) { + rustrpz.tags.emplace_back(tag); + } + rustrpz.overridesGettag = rpz.defpolOverrideLocal; + rustrpz.zoneSizeHint = rpz.zoneXFRParams.zoneSizeHint; + assign(rustrpz.tsig, rpz.zoneXFRParams.tsigtriplet); + rustrpz.refresh = rpz.zoneXFRParams.refreshFromConf; + rustrpz.maxReceivedMBytes = rpz.zoneXFRParams.maxReceivedMBytes; + if (rpz.zoneXFRParams.localAddress != ComboAddress()) { + rustrpz.localAddress = rpz.zoneXFRParams.localAddress.toString(); + } + rustrpz.axfrTimeout = rpz.zoneXFRParams.xfrTimeout; + rustrpz.dumpFile = rpz.dumpZoneFileName; + rustrpz.seedFile = rpz.seedFileName; + + rec.rpzs.emplace_back(rustrpz); + } +} + +string cvt(pdns::ZoneMD::Config cfg) +{ + switch (cfg) { + case pdns::ZoneMD::Config::Ignore: + return "ignore"; + case pdns::ZoneMD::Config::Validate: + return "validate"; + case pdns::ZoneMD::Config::Require: + return "require"; + } + return "UnknownZoneMDConfig"; +} + +void fromLuaToRust(const map& ztcConfigs, pdns::rust::settings::rec::Recordcache& recordcache) +{ + for (const auto& [_, iter] : ztcConfigs) { + pdns::rust::settings::rec::ZoneToCache ztc; + ztc.zone = iter.d_zone; + ztc.method = iter.d_method; + for (const auto& src : iter.d_sources) { + ztc.sources.emplace_back(src); + } + ztc.timeout = iter.d_timeout; + if (!iter.d_tt.name.empty()) { + ztc.tsig.name = iter.d_tt.name.toString(); + ztc.tsig.algo = iter.d_tt.algo.toString(); + ztc.tsig.secret = Base64Encode(iter.d_tt.secret); + } + ztc.refreshPeriod = iter.d_refreshPeriod; + ztc.retryOnErrorPeriod = iter.d_retryOnError; + ztc.maxReceivedMBytes = iter.d_maxReceivedBytes; + if (iter.d_local != ComboAddress()) { + ztc.localAddress = iter.d_local.toString(); + } + ztc.zonemd = cvt(iter.d_zonemd); + ztc.dnssec = cvt(iter.d_dnssec); + recordcache.zonetocaches.emplace_back(ztc); + } +} + +std::string cvt(AdditionalMode mode) +{ + switch (mode) { + case AdditionalMode::Ignore: + return "Ignore"; + case AdditionalMode::CacheOnly: + return "CacheOnly"; + case AdditionalMode::CacheOnlyRequireAuth: + return "CacheOnlyRequireAuth"; + case AdditionalMode::ResolveImmediately: + return "ResolveImmediately"; + case AdditionalMode::ResolveDeferred: + return "ResolveDeferred"; + } + return "UnknownAdditionalMode"; +} + +AdditionalMode cvtAdditional(const std::string& mode) +{ + static const std::map map = { + {"Ignore", AdditionalMode::Ignore}, + {"CacheOnly", AdditionalMode::CacheOnly}, + {"CacheOnlyRequireAuth", AdditionalMode::CacheOnlyRequireAuth}, + {"ResolveImmediately", AdditionalMode::ResolveImmediately}, + {"ResolveDeferred", AdditionalMode::ResolveDeferred}}; + if (auto iter = map.find(mode); iter != map.end()) { + return iter->second; + } + throw runtime_error("AdditionalMode '" + mode + "' unknown"); +} + +pdns::ZoneMD::Config cvtZoneMDConfig(const std::string& mode) +{ + static const std::map map = { + {"ignore", pdns::ZoneMD::Config::Ignore}, + {"validate", pdns::ZoneMD::Config::Validate}, + {"require", pdns::ZoneMD::Config::Require}, + }; + if (auto iter = map.find(mode); iter != map.end()) { + return iter->second; + } + throw runtime_error("ZoneMD config '" + mode + "' unknown"); +} + +void fromLuaToRust(const std::map, AdditionalMode>>& allowAdditionalQTypes, pdns::rust::settings::rec::Recursor& rec) +{ + for (const auto& [qtype, data] : allowAdditionalQTypes) { + const auto& [qtypeset, mode] = data; + pdns::rust::settings::rec::AllowedAdditionalQType add; + add.qtype = qtype.toString(); + for (const auto& extra : qtypeset) { + add.targets.emplace_back(extra.toString()); + } + add.mode = cvt(mode); + rec.allowed_additional_qtypes.emplace_back(add); + } +} + +void fromLuaToRust(const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Incoming& incoming) +{ + for (const auto& mapping : proxyMapping) { + pdns::rust::settings::rec::ProxyMapping pmap; + pmap.subnet = mapping.first.toString(); + pmap.address = mapping.second.address.toString(); + if (mapping.second.suffixMatchNode) { + for (const auto& domain : mapping.second.suffixMatchNode->d_tree.getNodes()) { + pmap.domains.emplace_back(domain.toString()); + } + } + incoming.proxymappings.emplace_back(pmap); + } +} + +void fromLuaToRust(const SortList& arg, pdns::rust::settings::rec::Recursor& rec) +{ + const auto& sortlist = arg.getTree(); + for (const auto& iter : sortlist) { + pdns::rust::settings::rec::SortList rsl; + rsl.key = iter.first.toString(); + const auto& sub = iter.second; + // Some extra work to present them ordered in the YAML + std::set indexes; + std::multimap ordered; + for (auto& order : sub.d_orders) { + indexes.emplace(order.second); + ordered.emplace(order.second, order.first); + } + for (const auto& index : indexes) { + const auto& range = ordered.equal_range(index); + for (auto subnet = range.first; subnet != range.second; ++subnet) { + pdns::rust::settings::rec::SubnetOrder snorder; + snorder.order = index; + snorder.subnet = subnet->second.toString(); + rsl.subnets.emplace_back(snorder); + } + } + rec.sortlists.emplace_back(rsl); + } +} +} // namespace + +void pdns::settings::rec::fromLuaConfigToBridgeStruct(LuaConfigItems& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings) +{ + + fromLuaToRust(luaConfig, settings.dnssec); + settings.logging.protobuf_mask_v4 = luaConfig.protobufMaskV4; + settings.logging.protobuf_mask_v6 = luaConfig.protobufMaskV6; + if (luaConfig.protobufExportConfig.enabled) { + pdns::rust::settings::rec::ProtobufServer pbServer; + fromLuaToRust(luaConfig.protobufExportConfig, pbServer); + settings.logging.protobuf_servers.emplace_back(pbServer); + } + if (luaConfig.outgoingProtobufExportConfig.enabled) { + pdns::rust::settings::rec::ProtobufServer pbServer; + fromLuaToRust(luaConfig.outgoingProtobufExportConfig, pbServer); + settings.logging.outgoing_protobuf_servers.emplace_back(pbServer); + } + if (luaConfig.frameStreamExportConfig.enabled) { + pdns::rust::settings::rec::DNSTapFrameStreamServer dnstap; + fromLuaToRust(luaConfig.frameStreamExportConfig, dnstap); + settings.logging.dnstap_framestream_servers.emplace_back(dnstap); + } + if (luaConfig.nodFrameStreamExportConfig.enabled) { + pdns::rust::settings::rec::DNSTapNODFrameStreamServer dnstap; + fromLuaToRust(luaConfig.nodFrameStreamExportConfig, dnstap); + settings.logging.dnstap_nod_framestream_servers.emplace_back(dnstap); + } + fromLuaToRust(luaConfig.rpzs, settings.recursor); + fromLuaToRust(luaConfig.sortlist, settings.recursor); + fromLuaToRust(luaConfig.ztcConfigs, settings.recordcache); + fromLuaToRust(luaConfig.allowAdditionalQTypes, settings.recursor); + fromLuaToRust(proxyMapping, settings.incoming); +} + +namespace +{ +void fromRustToLuaConfig(const pdns::rust::settings::rec::Dnssec& dnssec, LuaConfigItems& luaConfig) +{ + // This function fills a luaConfig equivalent to the given YAML config, assuming luaConfig has + // its default content. The docs say: "If the sequence contains an entry for the root zone, the + // default root zone trust anchor is not included." By default, a newly created luaConfig has the + // TAs for the root in it. If the YAML config has an entry for these, clear them from + // luaConfig. Otherwise the default TA's would remain even if the YAML config is trying to set + // them. This code actually clears all of the TAs in luaConfig mentioned in the YAML config, but + // as the luaConfig only contains the root TAs, this is equivalent (but not *very* efficient). + for (const auto& trustAnchor : dnssec.trustanchors) { + auto name = DNSName(std::string(trustAnchor.name)); + luaConfig.dsAnchors.erase(name); + } + for (const auto& trustAnchor : dnssec.trustanchors) { + auto name = DNSName(std::string(trustAnchor.name)); + for (const auto& dsRecord : trustAnchor.dsrecords) { + auto dsRecContent = std::dynamic_pointer_cast(DSRecordContent::make(std::string(dsRecord))); + luaConfig.dsAnchors[name].emplace(*dsRecContent); + } + } + for (const auto& nta : dnssec.negative_trustanchors) { + luaConfig.negAnchors[DNSName(std::string(nta.name))] = std::string(nta.reason); + } + luaConfig.trustAnchorFileInfo.fname = std::string(dnssec.trustanchorfile); + luaConfig.trustAnchorFileInfo.interval = dnssec.trustanchorfile_interval; +} + +void fromRustToLuaConfig(const pdns::rust::settings::rec::ProtobufServer& pbServer, ProtobufExportConfig& exp) +{ + exp.enabled = true; + exp.exportTypes.clear(); + for (const auto& type : pbServer.exportTypes) { + exp.exportTypes.emplace(QType::chartocode(std::string(type).c_str())); + } + for (const auto& server : pbServer.servers) { + exp.servers.emplace_back(std::string(server)); + } + exp.maxQueuedEntries = pbServer.maxQueuedEntries; + exp.timeout = pbServer.timeout; + exp.reconnectWaitTime = pbServer.reconnectWaitTime; + exp.asyncConnect = pbServer.asyncConnect; + exp.logQueries = pbServer.logQueries; + exp.logResponses = pbServer.logResponses; + exp.taggedOnly = pbServer.taggedOnly; + exp.logMappedFrom = pbServer.logMappedFrom; +} + +void fromRustToLuaConfig(const pdns::rust::settings::rec::DNSTapFrameStreamServer& dnstap, FrameStreamExportConfig& exp) +{ + exp.enabled = true; + for (const auto& server : dnstap.servers) { + exp.servers.emplace_back(std::string(server)); + } + exp.logQueries = dnstap.logQueries; + exp.logResponses = dnstap.logResponses; + exp.bufferHint = dnstap.bufferHint; + exp.flushTimeout = dnstap.flushTimeout; + exp.inputQueueSize = dnstap.inputQueueSize; + exp.outputQueueSize = dnstap.outputQueueSize; + exp.queueNotifyThreshold = dnstap.queueNotifyThreshold; + exp.reopenInterval = dnstap.reopenInterval; +} + +void fromRustToLuaConfig(const pdns::rust::settings::rec::DNSTapNODFrameStreamServer& dnstap, FrameStreamExportConfig& exp) +{ + exp.enabled = true; + for (const auto& server : dnstap.servers) { + exp.servers.emplace_back(std::string(server)); + } + exp.logNODs = dnstap.logNODs; + exp.logUDRs = dnstap.logUDRs; + exp.bufferHint = dnstap.bufferHint; + exp.flushTimeout = dnstap.flushTimeout; + exp.inputQueueSize = dnstap.inputQueueSize; + exp.outputQueueSize = dnstap.outputQueueSize; + exp.queueNotifyThreshold = dnstap.queueNotifyThreshold; + exp.reopenInterval = dnstap.reopenInterval; +} + +DNSFilterEngine::PolicyKind cvtKind(const std::string& kind) +{ + static const std::map map = { + {"Custom", DNSFilterEngine::PolicyKind::Custom}, + {"Drop", DNSFilterEngine::PolicyKind::Drop}, + {"NoAction", DNSFilterEngine::PolicyKind::NoAction}, + {"NODATA", DNSFilterEngine::PolicyKind::NODATA}, + {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN}, + {"Truncate", DNSFilterEngine::PolicyKind::Truncate}}; + if (auto iter = map.find(kind); iter != map.end()) { + return iter->second; + } + throw runtime_error("PolicyKind '" + kind + "' unknown"); +} + +void fromRustToLuaConfig(const rust::Vec& rpzs, LuaConfigItems& luaConfig) +{ + for (const auto& rpz : rpzs) { + RPZTrackerParams params; + for (const auto& address : rpz.addresses) { + params.zoneXFRParams.primaries.emplace_back(address); + } + params.zoneXFRParams.name = std::string(rpz.name); + params.polName = std::string(rpz.policyName); + + if (!rpz.defpol.empty()) { + params.defpol = DNSFilterEngine::Policy(); + params.defcontent = std::string(rpz.defcontent); + params.defpol->d_kind = cvtKind(std::string(rpz.defpol)); + params.defpol->setName(params.polName); + if (params.defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) { + if (!params.defpol->d_custom) { + params.defpol->d_custom = make_unique(); + } + params.defpol->d_custom->push_back(DNSRecordContent::make(QType::CNAME, QClass::IN, + std::string(params.defcontent))); + + if (rpz.defttl != std::numeric_limits::max()) { + params.defpol->d_ttl = static_cast(rpz.defttl); + } + else { + params.defpol->d_ttl = -1; // get it from the zone + } + } + } + params.defpolOverrideLocal = rpz.defpolOverrideLocalData; + params.extendedErrorCode = rpz.extendedErrorCode; + params.extendedErrorExtra = std::string(rpz.extendedErrorExtra); + params.includeSOA = rpz.includeSOA; + params.ignoreDuplicates = rpz.ignoreDuplicates; + params.maxTTL = rpz.maxTTL; + + for (const auto& tag : rpz.tags) { + params.tags.emplace(std::string(tag)); + } + params.defpolOverrideLocal = rpz.overridesGettag; + params.zoneXFRParams.zoneSizeHint = rpz.zoneSizeHint; + assign(params.zoneXFRParams.tsigtriplet, rpz.tsig); + params.zoneXFRParams.refreshFromConf = rpz.refresh; + params.zoneXFRParams.maxReceivedMBytes = rpz.maxReceivedMBytes; + if (!rpz.localAddress.empty()) { + params.zoneXFRParams.localAddress = ComboAddress(std::string(rpz.localAddress)); + } + params.zoneXFRParams.xfrTimeout = rpz.axfrTimeout; + params.dumpZoneFileName = std::string(rpz.dumpFile); + params.seedFileName = std::string(rpz.seedFile); + luaConfig.rpzs.emplace_back(params); + } +} + +void fromRustToLuaConfig(const rust::Vec& ztcs, map& lua) +{ + for (const auto& ztc : ztcs) { + DNSName zone = DNSName(std::string(ztc.zone)); + RecZoneToCache::Config lztc; + for (const auto& source : ztc.sources) { + lztc.d_sources.emplace_back(std::string(source)); + } + lztc.d_zone = std::string(ztc.zone); + lztc.d_method = std::string(ztc.method); + if (!ztc.localAddress.empty()) { + lztc.d_local = ComboAddress(std::string(ztc.localAddress)); + } + if (!ztc.tsig.name.empty()) { + lztc.d_tt.name = DNSName(std::string(ztc.tsig.name)); + lztc.d_tt.algo = DNSName(std::string(ztc.tsig.algo)); + B64Decode(std::string(ztc.tsig.secret), lztc.d_tt.secret); + } + lztc.d_maxReceivedBytes = ztc.maxReceivedMBytes; + lztc.d_retryOnError = static_cast(ztc.retryOnErrorPeriod); + lztc.d_refreshPeriod = static_cast(ztc.refreshPeriod); + lztc.d_timeout = ztc.timeout; + lztc.d_zonemd = cvtZoneMDConfig(std::string(ztc.zonemd)); + lztc.d_dnssec = cvtZoneMDConfig(std::string(ztc.dnssec)); + lua.emplace(zone, lztc); + } +} + +void fromRustToLuaConfig(const rust::Vec& sortlists, SortList& lua) +{ + for (const auto& sortlist : sortlists) { + for (const auto& entry : sortlist.subnets) { + lua.addEntry(Netmask(std::string(sortlist.key)), Netmask(std::string(entry.subnet)), static_cast(entry.order)); + } + } +} + +void fromRustToLuaConfig(const rust::Vec& alloweds, std::map, AdditionalMode>>& lua) +{ + for (const auto& allowed : alloweds) { + QType qtype(QType::chartocode(std::string(allowed.qtype).c_str())); + std::set set; + for (const auto& target : allowed.targets) { + set.emplace(QType::chartocode(std::string(target).c_str())); + } + AdditionalMode mode = AdditionalMode::CacheOnlyRequireAuth; + mode = cvtAdditional(std::string(allowed.mode)); + lua.emplace(qtype, std::pair{set, mode}); + } +} + +void fromRustToLuaConfig(const rust::Vec& pmaps, ProxyMapping& proxyMapping) +{ + for (const auto& pmap : pmaps) { + Netmask subnet = Netmask(std::string(pmap.subnet)); + ComboAddress address(std::string(pmap.address)); + std::optional smn; + if (!pmap.domains.empty()) { + smn = std::make_optional(SuffixMatchNode{}); + for (const auto& dom : pmap.domains) { + smn->add(DNSName(std::string(dom))); + } + } + proxyMapping.insert_or_assign(subnet, {std::move(address), std::move(smn)}); + } +} + +void fromRustToLuaConfig(const rust::Vec& catzones, std::vector& lua) +{ + for (const auto& catz : catzones) { + FWCatalogZone fwcatz; + for (const auto& def : catz.groups) { + fwcatz.d_defaults.emplace(def.name, def); + } + fwcatz.d_catz = std::make_shared(); + + for (const auto& address : catz.xfr.addresses) { + fwcatz.d_params.primaries.emplace_back(address); + } + fwcatz.d_params.name = std::string(catz.zone); + fwcatz.d_params.zoneSizeHint = catz.xfr.zoneSizeHint; + assign(fwcatz.d_params.tsigtriplet, catz.xfr.tsig); + fwcatz.d_params.refreshFromConf = catz.xfr.refresh; + fwcatz.d_params.maxReceivedMBytes = catz.xfr.maxReceivedMBytes; + if (!catz.xfr.localAddress.empty()) { + fwcatz.d_params.localAddress = ComboAddress(std::string(catz.xfr.localAddress)); + } + fwcatz.d_params.xfrTimeout = catz.xfr.axfrTimeout; + lua.emplace_back(std::move(fwcatz)); + } +} + +void fromRustToOTTraceConditions(const rust::Vec& settings, OpenTelemetryTraceConditions& conditions) +{ + for (const auto& setting : settings) { + OpenTelemetryTraceCondition condition; + if (!setting.qnames.empty()) { + condition.d_qnames = SuffixMatchNode(); + } + for (const auto& qname : setting.qnames) { + condition.d_qnames->add(DNSName(std::string(qname))); + } + if (!setting.qtypes.empty()) { + condition.d_qtypes = std::unordered_set(); + } + for (const auto& qtype : setting.qtypes) { + condition.d_qtypes->insert(QType::chartocode(std::string(qtype).data())); + } + if (setting.qid != std::numeric_limits::max()) { + condition.d_qid = setting.qid; + } + condition.d_edns_option_required = setting.edns_option_required; + condition.d_traceid_only = setting.traceid_only; + for (const auto& acl : setting.acls) { + conditions.insert(std::string(acl)).second = condition; + } + } +} +} + +void pdns::settings::rec::fromBridgeStructToLuaConfig(const pdns::rust::settings::rec::Recursorsettings& settings, LuaConfigItems& luaConfig, ProxyMapping& proxyMapping, OpenTelemetryTraceConditions& conditions) +{ + fromRustToLuaConfig(settings.dnssec, luaConfig); + luaConfig.protobufMaskV4 = settings.logging.protobuf_mask_v4; + luaConfig.protobufMaskV6 = settings.logging.protobuf_mask_v6; + if (!settings.logging.protobuf_servers.empty()) { + fromRustToLuaConfig(settings.logging.protobuf_servers.at(0), luaConfig.protobufExportConfig); + } + if (!settings.logging.outgoing_protobuf_servers.empty()) { + fromRustToLuaConfig(settings.logging.outgoing_protobuf_servers.at(0), luaConfig.outgoingProtobufExportConfig); + } + if (!settings.logging.dnstap_framestream_servers.empty()) { + fromRustToLuaConfig(settings.logging.dnstap_framestream_servers.at(0), luaConfig.frameStreamExportConfig); + } + if (!settings.logging.dnstap_nod_framestream_servers.empty()) { + fromRustToLuaConfig(settings.logging.dnstap_nod_framestream_servers.at(0), luaConfig.nodFrameStreamExportConfig); + } + fromRustToLuaConfig(settings.recursor.rpzs, luaConfig); + fromRustToLuaConfig(settings.recursor.sortlists, luaConfig.sortlist); + fromRustToLuaConfig(settings.recordcache.zonetocaches, luaConfig.ztcConfigs); + fromRustToLuaConfig(settings.recursor.allowed_additional_qtypes, luaConfig.allowAdditionalQTypes); + fromRustToLuaConfig(settings.recursor.forwarding_catalog_zones, luaConfig.catalogzones); + fromRustToLuaConfig(settings.incoming.proxymappings, proxyMapping); + fromRustToOTTraceConditions(settings.logging.opentelemetry_trace_conditions, conditions); +} + +// Return true if an item that's (also) a Lua config item is set +bool pdns::settings::rec::luaItemSet(const pdns::rust::settings::rec::Recursorsettings& settings) +{ + bool alldefault = true; + for (const auto& trustanchor : settings.dnssec.trustanchors) { + if (trustanchor.name == ".") { + if (trustanchor.dsrecords.size() != rootDSs.size()) { + alldefault = false; + break; + } + for (const auto& dsRecord : trustanchor.dsrecords) { + if (std::find(rootDSs.begin(), rootDSs.end(), std::string(dsRecord)) == rootDSs.end()) { + alldefault = false; + break; + } + } + } + else { + alldefault = false; + break; + } + } + alldefault = alldefault && settings.dnssec.negative_trustanchors.empty(); + alldefault = alldefault && settings.dnssec.trustanchorfile.empty(); + alldefault = alldefault && settings.dnssec.trustanchorfile_interval == 24; + alldefault = alldefault && settings.logging.protobuf_mask_v4 == 32; + alldefault = alldefault && settings.logging.protobuf_mask_v6 == 128; + alldefault = alldefault && settings.logging.protobuf_servers.empty(); + alldefault = alldefault && settings.logging.outgoing_protobuf_servers.empty(); + alldefault = alldefault && settings.logging.dnstap_framestream_servers.empty(); + alldefault = alldefault && settings.logging.dnstap_nod_framestream_servers.empty(); + alldefault = alldefault && settings.recursor.sortlists.empty(); + alldefault = alldefault && settings.recursor.rpzs.empty(); + alldefault = alldefault && settings.recursor.forwarding_catalog_zones.empty(); + alldefault = alldefault && settings.recordcache.zonetocaches.empty(); + alldefault = alldefault && settings.recursor.allowed_additional_qtypes.empty(); + alldefault = alldefault && settings.incoming.proxymappings.empty(); + return !alldefault; +} + +pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::tryReadYAML(const string& yamlconfigname, bool setGlobals, bool& yamlSettings, bool& luaSettingsInYAML, rust::settings::rec::Recursorsettings& settings, Logr::log_t startupLog, Logr::Priority level) +{ + string msg; + // TODO: handle include-dir on command line + auto yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, ::arg()["include-dir"], settings, msg, startupLog); + + switch (yamlstatus) { + case pdns::settings::rec::YamlSettingsStatus::CannotOpen: + startupLog->error(level, msg, "No YAML config found", "configname", Logging::Loggable(yamlconfigname)); + break; + + case pdns::settings::rec::YamlSettingsStatus::PresentButFailed: + startupLog->error(Logr::Error, msg, "YAML config found, but error occurred processing it", "configname", Logging::Loggable(yamlconfigname)); + break; + + case pdns::settings::rec::YamlSettingsStatus::OK: + yamlSettings = true; + startupLog->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname)); + pdns::settings::rec::processAPIDir(arg()["include-dir"], settings, startupLog); + luaSettingsInYAML = pdns::settings::rec::luaItemSet(settings); + if (luaSettingsInYAML && !settings.recursor.lua_config_file.empty()) { + const std::string err = "YAML settings include values originally in Lua but also sets `recursor.lua_config_file`. This is unsupported"; + startupLog->info(Logr::Error, err, "configname", Logging::Loggable(yamlconfigname)); + yamlstatus = pdns::settings::rec::PresentButFailed; + } + else if (!settings.recursor.forwarding_catalog_zones.empty() && settings.webservice.api_dir.empty()) { + startupLog->info(Logr::Error, "Catalog zones defined, but webservice.api_dir is not set", "configname", Logging::Loggable(yamlconfigname)); + yamlstatus = pdns::settings::rec::PresentButFailed; + } + else if (setGlobals) { + pdns::settings::rec::bridgeStructToOldStyleSettings(settings); + } + break; + } + return yamlstatus; +} + +namespace pdns::rust::misc +{ + +template +Wrapper::Wrapper(const M& arg) : + d_ptr(std::make_unique(arg)) +{ +} + +template +Wrapper::~Wrapper() = default; + +template +[[nodiscard]] const M& Wrapper::get() const +{ + return *d_ptr; +} + +template class Wrapper<::NetmaskGroup>; +template class Wrapper<::ComboAddress>; + +uint16_t qTypeStringToCode(::rust::Str str) +{ + std::string tmp(str.data(), str.length()); + return QType::chartocode(tmp.c_str()); +} + +bool isValidHostname(::rust::Str str) +{ + try { + auto name = DNSName(string(str)); + return name.isHostname(); + } + catch (...) { + return false; + } +} + +std::unique_ptr comboaddress(::rust::Str str) +{ + return std::make_unique(::ComboAddress(std::string(str))); +} + +bool matches(const std::unique_ptr& nmg, const std::unique_ptr& address) +{ + return nmg->get().match(address->get()); +} + +void log(const std::shared_ptr& logger, pdns::rust::misc::Priority log_level, ::rust::Str msg, const ::rust::Vec& values) +{ + auto log = logger; + for (const auto& [key, value] : values) { + log = log->withValues(std::string(key), Logging::Loggable(std::string(value))); + } + log->info(static_cast(log_level), std::string(msg)); +} + +void error(const std::shared_ptr& logger, pdns::rust::misc::Priority log_level, ::rust::Str error, ::rust::Str msg, const ::rust::Vec& values) +{ + auto log = logger; + for (const auto& [key, value] : values) { + log = log->withValues(std::string(key), Logging::Loggable(std::string(value))); + } + log->error(static_cast(log_level), std::string(error), std::string(msg)); +} + +std::shared_ptr withValue(const std::shared_ptr& logger, ::rust::Str key, ::rust::Str val) +{ + auto ret = logger->withValues(std::string(key), Logging::Loggable(std::string(val))); + return ret; +} + +::rust::String getUUID() +{ + auto uuid = getUniqueID(); + return to_string(uuid); +} +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/docs-new-preamble-in.rst pdns-recursor-5.4.9/rec-rust-lib/docs-new-preamble-in.rst --- pdns-recursor-5.2.13/rec-rust-lib/docs-new-preamble-in.rst 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/docs-new-preamble-in.rst 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,683 @@ +PowerDNS Recursor New Style (YAML) Settings +=========================================== + +Each setting can appear on the command line, prefixed by ``--`` and using the old style name, or in configuration files. +Settings on the command line are processed after the file-based settings are processed. + +.. note:: + Starting with version 5.0.0, :program:`Recursor` supports a new YAML syntax for configuration files + as described here. + 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`` file. + + 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 an 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 YAML configuration file and reading of old-style ``recursor.conf`` files will have to be enabled specifically by providing a command line option ``--enable-old-settings``. + + In a future release support for the "old-style" ``recursor.conf`` settings file will be dropped. + +.. note:: + Starting with version 5.1.0, the settings originally specified in a Lua config file can also be put in YAML form. + The conversion printed by ``rec_control show-yaml`` will print these settings if a Lua config file is specified in the config file being converted. + You have to choose however: either set Lua settings the old way in the Lua config file, or convert all to YAML. + If you are using YAML settings of items originally specified in the Lua config file do not set :ref:`setting-yaml-recursor.lua_config_file` anymore. The :program:`Recursor` will check that you do not mix both configuration methods. + + When using YAML style for settings originally found in the Lua config file ``rec_control reload-lua-config`` will reload parts of the YAML settings. Refer to the specific setting to learn if it is subject to reloading. Starting with version 5.2.0, the command ``rec_control reload-yaml`` can be used (which is an alias for ``rec_control reload-lua-config``). + +YAML settings file +------------------ +Please refer to e.g. ``_ +for a description of YAML syntax. + +A :program:`Recursor` configuration file has several sections. For example, ``incoming`` for +settings related to receiving queries and ``dnssec`` for settings related to DNSSEC processing. + +An example :program:`Recursor` YAML configuration file looks like: + +.. code-block:: yaml + + dnssec: + log_bogus: true + incoming: + listen: + - 0.0.0.0:5301 + - '[::]:5301' + recursor: + extended_resolution_errors: true + forward_zones: + - zone: example.com + forwarders: + - 127.0.0.1:5301 + outgoing: + source_address: + - 0.0.0.0 + - '::' + logging: + loglevel: 6 + +Take care when listing IPv6 addresses, as characters used for these are special to YAML. +If in doubt, quote any string containing ``:``, ``!``, ``[`` or ``]`` and use (online) tools to check your YAML syntax. +Specify an empty sequence using ``[]``. + +The main setting file is called ``recursor.yml`` and will be processed first. +This settings file might refer to other files via the `recursor.include_dir`_ setting. +The next section will describe how settings specified in multiple files are merged. + +Merging multiple setting files +------------------------------ +If `recursor.include_dir`_ is set, all ``.yml`` files in it will be processed in alphabetical order, modifying the settings processed so far. + +For simple values like a boolean or number setting, a value in the processed file will overwrite an existing setting. + +For values of type sequence, the new value will *replace* the existing value if the existing value is equal to the ``default`` or if the new value is marked with the ``!override`` tag. +Otherwise, the existing value will be *extended* with the new value by appending the new sequence to the existing. + +For example, with the above example ``recursor.yml`` and an include directory containing a file ``extra.yml``: + +.. code-block:: yaml + + dnssec: + log_bogus: false + recursor: + forward_zones: + - zone: example.net + forwarders: + - '::1' + outgoing: + source_address: !override + - 0.0.0.0 + dont_query: [] + +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`` 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:: + The merging process does not process values deeper than the second level. + For example if the main ``recursor.yml`` specified a forward zone + + .. code-block:: yaml + + recursor: + forward_zones: + - zone: example.net + forwarders: + - '::1' + + and another settings file contains + + .. code-block:: yaml + + recursor: + forward_zones: + - zone: example.net + forwarders: + - '::2' + + The result will *not* be 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 a string containing either an IP address or and IP address:port combination +For example: + +.. code-block:: yaml + + some_key: 127.0.0.1 + another_key: '[::1]:8080' + +Subnet +^^^^^^ +A subnet is a single IP address or an IP address followed by a slash and a prefix length. +If no prefix length is specified, ``/32`` or ``/128`` is assumed, indicating a single IP address. +Subnets can also be prefixed with a ``!``, specifying negation. +This can be used to deny addresses from a previously allowed range. + +For example, ``allow-from`` takes a sequence of subnets: + +.. code-block:: yaml + + incoming: + allow_from: + - '2001:DB8::/32' + - 128.66.0.0/16 + - '!128.66.1.2' + +In this case the address ``128.66.1.2`` is excluded from the addresses allowed access. + +Forward Zone +^^^^^^^^^^^^ +A forward zone is defined as: + +.. code-block:: yaml + + zone: string + forwarders: + - Socket Address + - ... + recurse: Boolean, default false (only relevant in a forwarding file) + notify_allowed: Boolean, default false + +An example of a ``forward_zones_file`` contents, which consists of a sequence of `Forward Zone`_ entries: + +.. code-block:: yaml + + - zone: example1.com + forwarders: + - 127.0.0.1 + - 127.0.0.1:5353 + - '[::1]:53' + - zone: example2.com + forwarders: + - '::1' + recurse: true + notify_allowed: true + +.. note:: + + The ``recurse`` field is relevant only in a ``Forward Zone`` clause in a forwarding file. + It has a fixed value in the context of :ref:`setting-yaml-recursor.forward_zones` and :ref:`setting-yaml-recursor.forward_zones_recurse`. + +Starting with version 5.1.0, names can be used if +:ref:`setting-yaml-recursor.system_resolver_ttl` is set. +The names will be resolved using the system resolver and an automatic refresh of the forwarding zones will happen if a name starts resolving to a new address. +The refresh is done by performing the equivalent of ``rec_control reload-zones``. + + +Auth Zone +^^^^^^^^^ +An auth zone is defined as: + +.. code-block:: yaml + + zone: string + file: string + +An example of a ``auth_zones`` entry, consisting of a sequence of `Auth Zone`_: + +.. code-block:: yaml + + recursor: + auth_zones: + - zone: example.com + file: zones/example.com.zone + - zone: example.net + file: zones/example.net.zone + + +Description of YAML syntax corresponding to Lua config items +------------------------------------------------------------ + +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 +^^^^^^^^^^^ +As of version 5.1.0, a trust anchor is defined as + +.. code-block:: yaml + + name: string + dsrecords: sequence of DS record strings in presentation format + +An example of a ``trustanchors`` entry, which is a sequence of `TrustAnchor`_: + +.. code-block:: yaml + + dnssec: + trustanchors: + - name: example.com + dsrecords: + - 10000 8 2 a06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d + +NegativeTrustAnchor +^^^^^^^^^^^^^^^^^^^ +As of version 5.1.0, a negative trust anchor is defined as + +.. code-block:: yaml + + name: string + reason: string + +An example of a ``negative_trustanchors`` entry, which is a sequence of `NegativeTrustAnchor`_: + +.. code-block:: yaml + + dnssec: + negative_trustanchors: + - name: example.com + reason: an example + +ProtobufServer +^^^^^^^^^^^^^^ +As of version 5.1.0, a protobuf server is defined as + +.. code-block:: yaml + + servers: [] Sequence of strings representing SocketAddress + timeout: 2 + maxQueuedEntries: 100 + reconnectWaitTime: 1 + taggedOnly: false + asyncConnect: false + logQueries: true + logResponses: true + exportTypes: [A, AAAA, CNAME] Sequence of QType names + logMappedFrom: false + +.. versionchanged:: 5.3.0 The aliases ``max_queued_entries``, ``reconnect_wait_time``, ``tagged_only``, ``async_connect``, ``log_queries``, ``log_responses``, ``export_types``, ``log_mapped_from`` have been introduced. + +An example of a ``protobuf_servers`` entry, which is a sequence of `ProtobufServer`_: + +.. code-block:: yaml + + logging: + protobuf_servers: + - servers: [127.0.0.1:4578] + exportTypes: [A, AAAA] + - servers: ['[2001:DB8::1]':7891] + logQueries: false + logResponses: true + exportTypes: [A] + +DNSTapFrameStreamServers +^^^^^^^^^^^^^^^^^^^^^^^^ +As of version 5.1.0, a dnstap framestream server is defined as + +.. code-block:: yaml + + servers: [] Sequence of strings representing SocketAddress or a socket path + logQueries: true + logResponses: true + bufferHint: 0 + flushTimeout: 0 + inputQueueSize: 0 + outputQueueSize: 0 + queueNotifyThreshold: 0 + reopenInterval: 0 + +.. versionchanged:: 5.3.0 The aliases ``log_queries``, ``log_responses``, ``buffer_hint``, ``flush_timeout``, ``input_queue_size``, ``output_queue_size``, ``queue_notify_threshold``, ``reopen_interval`` have been introduced. + +An example of a ``dnstap_framestream_servers`` entry, which is a sequence of `DNSTapFrameStreamServers`_: + +.. code-block:: yaml + + logging: + dnstap_framestream_servers: + - servers: [127.0.0.1:2024] + logQueries: false + logResponses: true + +DNSTapNODFrameStreamServers +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 socket path + logNODs: true + logUDRs: false + bufferHint: 0 + flushTimeout: 0 + inputQueueSize: 0 + outputQueueSize: 0 + queueNotifyThreshold: 0 + reopenInterval: 0 + +.. versionchanged:: 5.3.0 The aliases ``log_nods``, ``log_udrs``, ``buffer_hint``, ``flush_timeout``, ``input_queue_size``, ``output_queue_size``, ``queue_notify_threshold``, ``reopen_interval`` have been introduced. + +An example of a ``dnstap_nod_framestream_servers`` entry, which is a sequence of `DNSTapNODFrameStreamServers`_: + +.. code-block:: yaml + + logging: + 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 + +.. code-block:: yaml + + - key: Subnet + subnets: + - subnet: Subnet + order: number + +An example of a ``sortlists`` entry, which is a sequence of `SortList`_: + +.. code-block:: yaml + + recursor: + 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 + +.. code-block:: yaml + + name: name or pathname + addresses: [] Sequence of SocketAddress + defcontent: string + defpol: Custom, Drop, NXDOMAIN, NODATA Truncate or NoAction + defpolOverrideLocalData: true + defttl: number + extendedErrorCode: number + extendedErrorExtra: string + includeSOA: false + ignoreDuplicates: false + maxTTL: number + policyName: string + tags: Sequence of string + overridesGettag: true + zoneSizeHint: number + tsig: + name: string + algo: string + secret: base64string + refresh: number + maxReceivedMBytes: number + localAddress: IP address + axfrTimeout: number + dumpFile: string + seedFile: string + +.. versionchanged:: 5.3.0 The aliases ``defpol_override_local_data``, ``extended_error_code``, ``extended_error_extra``, ``include_soa``, ``ignore_duplicates``, ``policy_name``, ``overriddes_gettag``, ``zone_size_hint``, ``max_received_bytes``, ``local_address``, ``axfr_timeout``, ``dump_file``, ``seed_file`` have been introduced. + +If ``addresses`` is empty, the ``name`` field specifies the path name of the RPZ; otherwise, the ``name`` field defines the name of the RPZ. +Starting with version 5.2.0, names instead of IP addresses can be used for ``addresses`` if +:ref:`setting-yaml-recursor.system_resolver_ttl` is set. + +An example of an ``rpzs`` entry, which is a sequence of `RPZ`_: + +.. code-block:: yaml + + recursor: + rpzs: + - name: 'path/to/a/file' + - name: 'remote.rpz' + addresses: ['192.168.178.99'] + policyName: mypolicy + +ZoneToCache +^^^^^^^^^^^ +As of version 5.1.0, a ZoneToCache entry is defined as + +.. code-block:: yaml + + zone: zonename + method: One of axfr, url, file + sources: [] Sequence of string, representing IP address, URL or path + timeout: 20 + tsig: + name: name of key + algo: algorithm + secret: Base64 encoded secret + refreshPeriod: 86400 + retryOnErrorPeriod: 60 + maxReceivedMBytes: 0 Zero mean no restriction + localAddress: local IP address to bind to. + zonemd: One of ignore, validate, require + dnssec: One of ignore, validate, require + +.. versionchanged:: 5.3.0 The aliases ``refresh_period``, ``retry_on_error``, ``max_received_mbytes``, ``local_address`` has been introduced. + +An example of an ``zonetocaches`` entry, which is a sequence of `ZoneToCache`_: + +.. code-block:: yaml + + recordcache: + zonetocaches: + - 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 additional qtype entry is defined as: + +.. code-block:: yaml + + qtype: string representing a QType + targets: [] Sequence of string representing QType + mode: One of Ignore, CacheOnly, CacheOnlyRequireAuth, ResolveImmediately, ResolveDeferred, default CacheOnlyRequireAuth + +An example of an ``allowed_additional_qtypes`` entry, which is a sequence of `AllowedAdditionalQType`_: + +.. code-block:: yaml + + recursor: + allowed_additional_qtypes: + - qtype: MX + targets: [A, AAAA] + - qtype: NAPTR + targets: [A, AAAA, SRV] + mode: ResolveDeferred + +ProxyMapping +^^^^^^^^^^^^ +As of version 5.1.0, a proxy mapping entry is defined as: + +.. code-block:: yaml + + subnet: Subnet + address: IPAddress + domains: [] Sequence of string + +An example of an ``proxymappings`` entry, which is a sequence of `ProxyMapping`_: + +.. code-block:: yaml + + incoming: + proxymappings: + - 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 + +ForwardingCatalogZone +^^^^^^^^^^^^^^^^^^^^^ +As of version 5.2.0, a forwarding catalog zone entry is defined as: + +.. code-block:: yaml + + zone: Name of catalog zone + notify_allowed: bool, default false + xfr: + addresses: [] Sequence of SocketAddress + zoneSizeHint: number, default not set + tsig: + name: string + algo: string + secret: base64string + refresh: number, default not set + maxReceivedMBytes: number, default not set + localAddress: IP address, default not set + axfrTimeout: number, default 20 + groups: + - name: optional group name + forwarders: [] Sequence of SocketAddress + recurse: bool, default false + notify_allowed: bool, default false + +.. versionchanged:: 5.3.0 The aliases ``zone_size_hint``, ``max_received_bytes``, ``local_address``, ``axfr_timeout`` have been introduced. + +While this setting has no equivalent old-style Lua configuration, it cannot appear together with :ref:`setting-lua-config-file` being set. +If you want to use catalog zones to define forwards, you need to convert existing Lua configuration to YAML format. + +Names instead of IP addresses can be used for ``addresses`` if :ref:`setting-yaml-recursor.system_resolver_ttl` is set. +An example of a :ref:`setting-yaml-recursor.forwarding_catalog_zones` entry, which is a sequence of `ForwardingCatalogZone`_: + +.. code-block:: yaml + + recursor: + forwarding_catalog_zones: + - zone: 'forward.example' + xfr: + addresses: [128.66.1.2] + groups: + - forwarders: [192.168.178.1] # default forwarder + - name: mygroup + forwarders: [192.168.179.2] # forwarder for catalog zone members in mygroup + recurse: true + notify_allowed: true + - zone: 'forward2.example' + xfr: + addresses: [128.66.1.3] + groups: + - forwarders: [192.168.178.3] # only default forwarder for 2nd catalog zone + +:program:`Recursor` will transfer the catalog zone from the authoritative server using IXFR (falling back to AXFR if needed) and add forwarding clauses for all members of the catalog zone. +The forwarding parameters will be taken from the default group entry (the one without a name) defined in the YAML settings. +For catalog zone members in a group, the forwarding parameters will be taken from the group entry with the corresponding name. + +The forwarding definitions will be written into a file ``$api_dir/catzone.$zonename``. :ref:`setting-yaml-webservice.api_dir` must be defined, the directory must exist and be writable by the :program:`Recursor` process. + +.. _incoming-ws-config: + +IncomingWSConfig +^^^^^^^^^^^^^^^^ +As of version 5.3.0, an incoming web server configuration is defined as + +.. code-block:: yaml + + addresses: [] Sequence of SocketAddress + tls: + certificates: file containing full certificate chain in PEM format + key: file containing private key in PEM format + + +A :ref:`setting-yaml-webservice.listen` section contains a sequence of `IncomingWSConfig`_, for example: + +.. code-block:: yaml + + webservice: + listen: + - addresses: [127.0.0.1:8083, '[::]:8083'] + tls: + certificate: fullchain.pem + key: keyfile.key + - addresses: [127.0.0.1:8084, '[::]:8084'] + +If no ``tls`` section is present, plaintext ``http`` connections are accepted on the listed addresses. + +If a ``tls`` section is present, clients are required to use ``https`` to contact any of the address-port combinations listen in addresses. At the moment it is not possible to list additional properties of the TLS listener and encrypted key files cannot be used. + +OutgoingTLSConfiguration +^^^^^^^^^^^^^^^^^^^^^^^^ + +As of version 5.4.0, an outgoing TLS (DoT) configuration is defined as + +.. code-block:: yaml + + name: A name, default not set. + provider: Either 'openssl' (default) or 'gnutls'. + suffixes: A sequence of domain names, default empty. + subnets: A sequence of Subnet strings (no negation supported), default empty. + validate_certificate: Set to true to enforce certificate validation, default false. + ca_store: CA store file containing certificates in PEM format, default is to use the system CA store. + verbose_logging: Whether to log more details on DoT connections, default false. + subject_name: The subject name passed in the SNI value of the TLS handshake, and against which to validate the certificate presented if applicable. Default is to use the nameserver name if available. If set this value supersedes any ``subject_address`` one. + subject_address: The subject IP address passed in the SNI value of the TLS handshake, and against which to validate the certificate presented by the backend. Default is to use the remote IP address if no nameserver name is available. + ciphers: The TLS ciphers to use. The exact format depends on the provider used. When the OpenSSL provider is used, ciphers for TLS 1.3 must be specified via ciphers_tls_13. + ciphers_tls_13: The ciphers to use for TLS 1.3, when the OpenSSL provider is used. When the GnuTLS provider is used, ciphers applies regardless of the TLS protocol and this setting is not used. + +A :ref:`setting-yaml-outgoing.tls_configurations` section contains a sequence of `OutgoingTLSConfiguration`_, for example: + +.. code-block:: yaml + + outgoing: + tls_configurations: + - name: 'DoT with verify' + suffixes: [powerdns.com] + validate_certificate: true + - name: 'Forward to quad1 or quad9' + subnets: [1.1.1.0/24,9.9.9.9] + validate_certificate: true + verbose_logging: true + - name: 'Forward to google' + subnets: [8.8.8.8] + subject_name: dns.google + validate_certificate: true + +The first entry matches on a name server name in ``powerdns.com``, and switches on validation. +The second entry matches on a subnet or IP addresses, and enables (IP based) certificate validation and verbose logging. +The third entry matches on IP, and switches on validation with the SNI name ``dns.google``. + +When looking for an outgoing TLS configuration matching is done against the ``subnets`` lists with the remote IP as key. +This is typically a forwarding target. +If no match is found on IP, a suffix match against the names in the ``suffixes`` lists is done using the nameserver name as key. +If again no match is found, the default configuration is used, this mean using the ``openssl`` provider, no certificate validation and no verbose logging. + +OpenTelemetryTraceCondition +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As of version 5.4.0, an OpenTelemetry Trace condition is defined as + +.. code-block:: yaml + + acls: sequence of string representing subnets, required + qnames: sequence of string representing DNS names + qtypes: a sequence of string representing Query Type names + qid: an integer specifying a Query ID + edns_option_required: bool, default false + traceid_only: bool, default false + +A :ref:`setting-yaml-logging.opentelemetry_trace_conditions` section contains a sequence of `OpenTelemetryTraceCondition`_, for example: + +.. code-block:: yaml + + logging: + opentelemetry_trace_conditions: + - acls: [127.0.0.1] + - acls: [192.168.178.0/24] + qnames: [a.very.specific.suffix] + qtypes: ['A', 'AAAA'] + qid: 1234 + edns_option_required: true + traceid_only: false + +See :ref:`opentelemetry_tracing` for an explanation how to use OpenTelemetry Trace Conditions. + +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 + ... + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/docs-old-preamble-in.rst pdns-recursor-5.4.9/rec-rust-lib/docs-old-preamble-in.rst --- pdns-recursor-5.2.13/rec-rust-lib/docs-old-preamble-in.rst 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/docs-old-preamble-in.rst 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,41 @@ +PowerDNS Recursor Settings +========================== +Each setting can appear on the command line, prefixed by ``--``, or in the configuration file. +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`. + Starting with version 5.2.0, parsing of old-style settings must be explicitly enabled using a command line argument ``--enable-old-settings``. + In a future release support for the old-style settings described here will be dropped. + See :doc:`yamlsettings` for details. + +.. note:: + Settings marked as ``Boolean`` can either be set to an empty value, which means **on**, or to ``no`` or ``off`` which means **off**. + Anything else means **on**. + + For example: + + - ``serve-rfc1918`` on its own means: do serve those zones. + - ``serve-rfc1918 = off`` or ``serve-rfc1918 = no`` means: do not serve those zones. + - Anything else means: do serve those zones. + +You can use ``+=`` syntax to set some variables incrementally, but this +requires you to have at least one non-incremental setting for the +variable to act as base setting. This is mostly useful for +:ref:`setting-include-dir` directive. An example:: + + forward-zones = foo.example.com=192.168.100.1; + forward-zones += bar.example.com=[1234::abcde]:5353; + +When a list of **Netmasks** is mentioned, a list of subnets can be specified. +A subnet that is not followed by ``/`` will be interpreted as a ``/32`` or ``/128`` subnet (a single address), depending on address family. +For most settings, it is possible to exclude ranges by prefixing an item with the negation character ``!``. +For example:: + + allow-from = 2001:DB8::/32, 128.66.0.0/16, !128.66.1.2 + +In this case the address ``128.66.1.2`` is excluded from the addresses allowed access. + +The Settings +------------ diff -Nru pdns-recursor-5.2.13/rec-rust-lib/generate.py pdns-recursor-5.4.9/rec-rust-lib/generate.py --- pdns-recursor-5.2.13/rec-rust-lib/generate.py 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/generate.py 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,870 @@ +"""The Python script that takes table.py and generates C++, Rust ahd .rst code.""" +# +# For C++ it generates cxxsettings-generated.cc containing support for old style +# settings plus conversion from old style to new style. +# +# 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 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. +# +# Two documentation files are generated: ../docs/settings.rst and +# ../docs/yamlsettings.rst. Each of these files have a preamble as +# well, describing the syntax and giving some examples. +# +# An example table.py entry: +# +# { +# 'name' : "allow_from", +# 'section' : "incoming", +# 'oldname' : "allow-from", +# 'type' : LType.ListSubnets, +# 'default' : "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", +# 'help' : "If set, only allow these comma separated netmasks to recurse", +# 'doc' : """ +# """ +# } +# +# The fields are: +# +# name: short name within section, also yaml key, must be unique within section and not a C++ or +# Rust keyword +# section: yaml section +# oldname: name in old style settings, must be unique globally +# type : logical type (leave the space before the : as pylint is buggy parsing lines with type +# immediately followed by colon)x +# default: default value, use 'true' and 'false' for Booleans +# help: short help text +# doc: the docs text will be put here +# doc-rst: optional .rst annotations +# doc-new: optional docs text specific to YAML format, e.g. not talking about comma separated +# lists and giving YAML examples. (optional) +# skip-yaml: optional if this key is present, the field will be skipped in the new style settings. +# Use for deprecated settings, the generated code will use deprecated map from arg() +# to handle old names when converting .conf to .yml +# skip-old: optional if this key is present, the field will be skipped in the old style settings. +# versionadded: string or list of strings +# runtime: optional, mentions how the settings can be updated runtime (or via API) if applicable +# +# The above struct will generate in cxxsettings-generated.cc: +# +# ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse") = \ +# "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, ..."; +# +# For Rust, it will generate a field `allow_from' within struct Incoming. +# As CXX places restrictions on the Serde code (which means we cannot +# use Serde extensions) we have to handle the default value and "skip if +# default" functions ourselves. +# +# There are three cases: +# +# 1. Default is the same as the Rust default for the type +# In that case, the field becomes: +# +# #[serde(default, skip_serializing_if = "crate::is_default")] +# nameoffield: bool +# +# 2. Type is primitive and default value is different from the Rust default, e.g.: +# +# #[serde(default = "crate::U64::<2000>::value", +# skip_serializing_if = "crate::U64::<2000>::is_equal")] +# nameoffield: u64 +# +# U64 is implemented in rust/src/helpers.rs +# +# 3. Type is not primitive and has default value different from Rust default, e.g.: +# +# [serde(default = "crate::default_value_incoming_allow_from", +# skip_serializing_if = "crate::default_value_equal_incoming_allow_from")] +# allow_from: Vec +# +# The two functions default_value_incoming_allow_from() and +# default_value_equal_incoming_allow_from() are also generated. +# +from enum import Enum +from enum import auto +import os +import re +import sys +from pathlib import Path + +class LType(Enum): + """The type we handle in table.py""" + Bool = auto() + Command = auto() + Double = auto() + ListAllowedAdditionalQTypes = auto() + ListAuthZones = auto() + ListDNSTapFrameStreamServers = auto() + ListDNSTapNODFrameStreamServers = auto() + ListForwardZones = auto() + ListForwardingCatalogZones = auto() + ListIncomingWSConfigs = auto() + ListNegativeTrustAnchors = auto() + ListProtobufServers = auto() + ListProxyMappings = auto() + ListRPZs = auto(); + ListSocketAddresses = auto() + ListSortLists = auto() + ListStrings = auto() + ListSubnets = auto() + ListTrustAnchors = auto() + ListZoneToCaches = auto() + ListOutgoingTLSConfigurations = auto() + ListOpenTelemetryTraceConditions = auto() + String = auto() + Uint64 = auto() + +listOfStringTypes = (LType.ListSocketAddresses, LType.ListStrings, LType.ListSubnets) +listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors, + LType.ListProtobufServers, LType.ListDNSTapFrameStreamServers, LType.ListDNSTapNODFrameStreamServers, + LType.ListSortLists, LType.ListRPZs, LType.ListZoneToCaches, LType.ListAllowedAdditionalQTypes, + LType.ListProxyMappings, LType.ListForwardingCatalogZones, LType.ListIncomingWSConfigs, + LType.ListOutgoingTLSConfigurations, LType.ListOpenTelemetryTraceConditions) + +def get_olddoc_typename(typ): + """Given a type from table.py, return the old-style type name""" + if typ == LType.Bool: + return 'Boolean' + if typ == LType.Uint64: + return 'Integer' + if typ == LType.Double: + return 'Double' + if typ == LType.String: + return 'String' + if typ == LType.ListSocketAddresses: + return 'Comma separated list or IPs of IP:port combinations' + if typ == LType.ListSubnets: + return 'Comma separated list of IP addresses or subnets, negation supported' + if typ == LType.ListStrings: + return 'Comma separated list of strings' + if typ == LType.ListForwardZones: + return 'Comma separated list of \'zonename=IP\' pairs' + if typ == LType.ListAuthZones: + return 'Comma separated list of \'zonename=filename\' pairs' + return 'Unknown1' + str(typ) + +def get_newdoc_typename(typ): + """Given a type from table.py, return the new-style type name""" + if typ == LType.Bool: + return 'Boolean' + if typ == LType.Uint64: + return 'Integer' + if typ == LType.Double: + return 'Double' + if typ == LType.String: + return 'String' + if typ == LType.ListSocketAddresses: + return 'Sequence of `Socket Address`_ (IP or IP:port combinations)' + if typ == LType.ListSubnets: + return 'Sequence of `Subnet`_ (IP addresses or subnets, negation supported)' + if typ == LType.ListStrings: + return 'Sequence of strings' + if typ == LType.ListForwardZones: + return 'Sequence of `Forward Zone`_' + if typ == LType.ListAuthZones: + return 'Sequence of `Auth Zone`_' + if typ == LType.ListTrustAnchors: + return 'Sequence of `TrustAnchor`_' + if typ == LType.ListNegativeTrustAnchors: + return 'Sequence of `NegativeTrustAnchor`_' + if typ == LType.ListProtobufServers: + return 'Sequence of `ProtobufServer`_' + if typ == LType.ListDNSTapFrameStreamServers: + return 'Sequence of `DNSTapFrameStreamServers`_' + if typ == LType.ListDNSTapNODFrameStreamServers: + return 'Sequence of `DNSTapNODFrameStreamServers`_' + if typ == LType.ListSortLists: + return 'Sequence of `Sortlist`_' + if typ == LType.ListRPZs: + return 'Sequence of `RPZ`_' + if typ == LType.ListZoneToCaches: + return 'Sequence of `ZoneToCache`_' + if typ == LType.ListAllowedAdditionalQTypes: + return 'Sequence of `AllowedAdditionalQType`_' + if typ == LType.ListProxyMappings: + return 'Sequence of `ProxyMapping`_' + if typ == LType.ListForwardingCatalogZones: + return 'Sequence of `ForwardingCatalogZone`_' + if typ == LType.ListIncomingWSConfigs: + return 'Sequence of `IncomingWSConfig`_' + if typ == LType.ListOutgoingTLSConfigurations: + return 'Sequence of `OutgoingTLSConfiguration`_' + if typ == LType.ListOpenTelemetryTraceConditions: + return 'Sequence of `OpenTelemetryTraceCondition`_' + return 'Unknown2' + str(typ) + +def get_default_olddoc_value(typ, val): + """Given a type and a value from table.py return the old doc representation of the value""" + if typ == LType.Bool: + if val == 'false': + return 'no' + return 'yes' + if val == '': + return '(empty)' + return val + +def get_default_newdoc_value(typ, val): + """Given a type and a value from table.py return the new doc representation of the value""" + if typ in (LType.Bool, LType.Uint64, LType.Double): + return '``' + val + '``' + if typ == LType.String and val == '': + return '(empty)' + if typ == LType.String: + return '``' + val + '``' + parts = re.split('[ \t,]+', val) + if len(parts) > 0: + ret = '' + for part in parts: + if part == '': + continue + if ret != '': + ret += ', ' + if ':' in part or '!' in part: + ret += "'" + part + "'" + else: + ret += part + else: + ret = '' + return '``[' + ret + ']``' + +def list_to_base_type(typ): + typeName = typ.name + if typeName.startswith('List') and typeName.endswith('s'): + baseName = typeName[4:len(typeName) - 1] + return baseName + return 'Unknown3: ' + typeName + +def get_rust_type(typ): + """Determine which Rust type is used for a logical type""" + if typ == LType.Bool: + return 'bool' + if typ == LType.Uint64: + return 'u64' + if typ == LType.Double: + return 'f64' + if typ == LType.String: + return 'String' + # These vectors map to Vec + if typ == LType.ListSocketAddresses: + return 'Vec' + if typ == LType.ListSubnets: + return 'Vec' + if typ == LType.ListStrings: + return 'Vec' + # These vectors map to Vec + return 'Vec<' + list_to_base_type(typ) + '>' + +def quote(arg): + """Return a quoted string""" + return '"' + arg + '"' + +def isEnvVar(name): + return name in ('SYSCONFDIR', 'NODCACHEDIRNOD', 'NODCACHEDIRUDR') + +def gen_cxx_defineoldsettings(file, entries): + """Generate C++ code to declare old-style settings""" + file.write('void pdns::settings::rec::defineOldStyleSettings()\n{\n') + for entry in entries: + helptxt = quote(entry['help']) + oldname = quote(entry['oldname']) + if entry['type'] == LType.Bool: + if entry['default'] == "true": + cxxdef = "yes" + else: + cxxdef = "no" + cxxdef = quote(cxxdef) + file.write(f" ::arg().setSwitch({oldname}, {helptxt}) = {cxxdef};\n") + elif entry['type'] == LType.Command: + file.write(f" ::arg().setCmd({oldname}, {helptxt});\n") + else: + cxxdef = entry['default'] if isEnvVar(entry['default']) else quote(entry['default']) + file.write(f" ::arg().set({oldname}, {helptxt}) = {cxxdef};\n") + file.write('}\n\n') + +def gen_cxx_oldstylesettingstobridgestruct(file, entries): + """Generate C++ code the convert old-style settings to new-style struct""" + file.write('void pdns::settings::rec::oldStyleSettingsToBridgeStruct') + file.write('(Recursorsettings& settings)\n{\n') + for entry in entries: + if entry['type'] == LType.Command: + continue + if 'skip-yaml' in entry: + continue + if 'skip-old' in entry: + continue + rust_type = get_rust_type(entry['type']) + name = entry['name'] + oldname = entry['oldname'] + section = entry['section'] + file.write(f' settings.{section}.{name} = ') + if rust_type == 'bool': + file.write(f'arg().mustDo("{oldname}")') + elif rust_type == 'u64': + file.write(f'static_cast(arg().asNum("{oldname}"))') + elif rust_type == 'f64': + file.write(f'arg().asDouble("{oldname}")') + elif rust_type == 'String': + file.write(f'arg()["{oldname}"]') + elif rust_type == 'Vec': + file.write(f'getStrings("{oldname}")') + elif rust_type == 'Vec': + file.write(f'getForwardZones("{oldname}")') + elif rust_type == 'Vec': + file.write(f'getAuthZones("{oldname}")') + else: + file.write(f'Unknown3 type {rust_type}\n') + file.write(';\n') + file.write('}\n\n') + +def gen_cxx_oldkvtobridgestruct(file, entries): + """Generate C++ code for oldKVToBridgeStruct""" + file.write('// Inefficient, but only meant to be used for one-time conversion purposes\n') + file.write('bool pdns::settings::rec::oldKVToBridgeStruct(std::string& key, ') + file.write('const std::string& value, ::rust::String& section, ::rust::String& fieldname, ') + file.write('::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue)') + file.write('{ // NOLINT(readability-function-cognitive-complexity)\n') + file.write(' if (const auto& newname = arg().isDeprecated(key); !newname.empty()) {\n') + file.write(' key = newname;\n') + file.write(' }\n') + for entry in entries: + if entry['type'] == LType.Command: + continue + if 'skip-yaml' in entry: + continue + if 'skip-old' in entry: + continue + rust_type = get_rust_type(entry['type']) + extra = '' + if entry['oldname'] == 'forward-zones-recurse': + extra = ', true' + name = entry['name'] + section = entry['section'] + oldname = entry['oldname'] + file.write(f' if (key == "{oldname}") {{\n') + file.write(f' section = "{section}";\n') + file.write(f' fieldname = "{name}";\n') + file.write(f' type_name = "{rust_type}";\n') + if rust_type == 'bool': + file.write(f' to_yaml(rustvalue.bool_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'u64': + file.write(f' to_yaml(rustvalue.u64_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'f64': + file.write(f' to_yaml(rustvalue.f64_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'String': + file.write(f' to_yaml(rustvalue.string_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'Vec': + file.write(f' to_yaml(rustvalue.vec_string_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'Vec': + file.write(f' to_yaml(rustvalue.vec_forwardzone_val, value{extra});\n') + file.write(' return true;\n }\n') + elif rust_type == 'Vec': + file.write(f' to_yaml(rustvalue.vec_authzone_val, value{extra});\n') + file.write(' return true;\n }\n') + else: + file.write(f'Unknown4 type {rust_type}\n') + file.write(' return false;\n') + file.write('}\n\n') + +def gen_cxx_brigestructtoldstylesettings(file, entries): + """Generate C++ Code for bridgeStructToOldStyleSettings""" + file.write('void pdns::settings::rec::bridgeStructToOldStyleSettings') + file.write('(const Recursorsettings& settings)\n{\n') + for entry in entries: + if entry['type'] == LType.Command: + continue + if 'skip-yaml' in entry: + continue + if 'skip-old' in entry: + continue + section = entry['section'].lower() + name = entry['name'] + oldname = entry['oldname'] + file.write(f' ::arg().set("{oldname}") = ') + file.write(f'to_arg(settings.{section}.{name});\n') + file.write('}\n') + +def gen_cxx(gendir, entries): + """Generate the C++ code from the defs in table.py""" + 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') + file.write('#include "cxxsettings-private.hh"\n\n') + gen_cxx_defineoldsettings(file, entries) + gen_cxx_oldstylesettingstobridgestruct(file, entries) + gen_cxx_oldkvtobridgestruct(file, entries) + gen_cxx_brigestructtoldstylesettings(file, entries) + +def is_value_rust_default(typ, value): + """Is a value (represented as string) the same as its corresponding Rust default?""" + if typ == 'bool': + return value == 'false' + if typ == 'u64': + return value in ('0', '') + if typ == 'f64': + return value == '0.0' + if typ == 'String': + return value == '' + return False + +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 {{\n' + ret += f' let msg = "default value defined for `{name}\' should be valid YAML";' + ret += f' let deserialized: Vec = serde_yaml::from_str({quote(defvalue)}).expect(msg);\n' + ret += f' deserialized\n' + ret += '}\n' + ret += f'fn default_value_equal_{name}(value: &Vec)' + ret += '-> bool {\n' + ret += f' let def = default_value_{name}();\n' + ret += ' &def == value\n' + ret += '}\n\n' + return ret + +# Example snippet generated +# fn default_value_general_query_local_address() -> Vec { +# vec![String::from("0.0.0.0"), ] +#} +#fn default_value_equal_general_query_local_address(value: &Vec) -> bool { +# let def = default_value_general_query_local_address(); +# &def == value +#} +def gen_rust_stringvec_default_functions(entry, name): + """Generate Rust code for the default handling of a vector for Strings""" + ret = f'// DEFAULT HANDLING for {name}\n' + ret += f'fn default_value_{name}() -> Vec {{\n' + parts = re.split('[ \t,]+', entry['default']) + if len(parts) > 0: + ret += ' vec![\n' + for part in parts: + if part == '': + continue + ret += f' String::from({quote(part)}),\n' + ret += ' ]\n' + else: + ret += ' vec![]\n' + ret += '}\n' + ret += f'fn default_value_equal_{name}(value: &Vec) -> bool {{\n' + ret += f' let def = default_value_{name}();\n' + ret += ' &def == value\n' + ret += '}\n\n' + return ret + +def gen_rust_default_functions(entry, name, rust_type): + """Generate Rust code for the default handling""" + defvalue = entry['default'] + if entry['type'] in listOfStringTypes: + return gen_rust_stringvec_default_functions(entry, name) + if entry['type'] in listOfStructuredTypes: + baseName = list_to_base_type(entry['type']) + return gen_rust_vec_default_functions(name, baseName, defvalue) + ret = f'// DEFAULT HANDLING for {name}\n' + ret += f'fn default_value_{name}() -> {rust_type} {{\n' + rustdef = f'env!("{defvalue}")' if isEnvVar(defvalue) else quote(defvalue) + ret += f" String::from({rustdef})\n" + ret += '}\n' + if rust_type == 'String': + rust_type = 'str' + ret += f'fn default_value_equal_{name}(value: &{rust_type})' + ret += '-> bool {\n' + ret += f' value == default_value_{name}()\n' + ret += '}\n\n' + return ret + +def write_rust_field(file, entry, default_funcs): + """Generate Rust code for a field with Serde annotations""" + rust_type = get_rust_type(entry['type']) + the_default = entry['default'] + is_rust_default = is_value_rust_default(rust_type, the_default) + if is_rust_default: + file.write(' #[serde(default, skip_serializing_if = "crate::is_default")]\n') + else: + if entry['type'] == LType.Bool: + file.write(' #[serde(default = "crate::Bool::::value", ') + file.write('skip_serializing_if = "crate::if_true")]\n') + elif entry['type'] == LType.Uint64: + file.write(f' #[serde(default = "crate::U64::<{the_default}>::value", ') + file.write(f'skip_serializing_if = "crate::U64::<{the_default}>::is_equal")]\n') + else: + basename = entry['section'] + '_' + entry['name'] + file.write(f' #[serde(default = "crate::default_value_{basename}", ') + file.write(f'skip_serializing_if = "crate::default_value_equal_{basename}")]\n') + default_funcs.append(gen_rust_default_functions(entry, basename, rust_type)) + file.write(f" {entry['name']}: {rust_type},\n\n") + +def write_rust_section(file, section, entries, default_funcs): + """Generate Rust code for a Section with Serde annotations""" + file.write(f' // SECTION {section.capitalize()}\n') + file.write(' #[derive(Deserialize, Serialize, Debug, PartialEq)]\n') + file.write(' #[serde(deny_unknown_fields)]\n') + file.write(f' pub struct {section.capitalize()} {{\n') + for entry in entries: + if entry['section'] != section: + continue + if entry['type'] == LType.Command: + continue + if 'skip-yaml' in entry: + continue + write_rust_field(file, entry, default_funcs) + file.write(f' }}\n // END SECTION {section.capitalize()}\n\n') + +# +# Each section als has a Default implementation, so that a section with all entries having a default +# value does not get generated into a yaml section. Such a trait looks like: +# +#impl Default for recsettings::ForwardZone { +# fn default() -> Self { +# let deserialized: recsettings::ForwardZone = serde_yaml::from_str("").unwrap(); +# deserialized +# } +#} + +def write_rust_default_trait_impl(file, section): + """Generate Rust code for the default Trait for a section""" + file.write(f'impl Default for recsettings::{section.capitalize()} {{\n') + file.write(' fn default() -> Self {\n') + file.write(' let deserialized: recsettings::') + file.write(f'{section.capitalize()} = serde_yaml::from_str("").unwrap();\n') + file.write(' deserialized\n') + file.write(' }\n') + file.write('}\n\n') + +def write_validator(file, section, entries): + """Generate Rust code for the Validator Trait for a section""" + file.write(f'impl Validate for recsettings::{section.capitalize()} {{\n') + file.write(' fn validate(&self) -> Result<(), ValidationError> {\n') + for entry in entries: + if entry['section'] != section: + continue + name = entry['name'].lower() + typ = entry['type'] + if typ == LType.ListSubnets: + validator = 'validate_subnet' + elif typ == LType.ListSocketAddresses: + validator = 'validate_socket_address' + elif typ in listOfStructuredTypes: + validator = '|field, element| element.validate(field)' + else: + continue + file.write(f' let fieldname = "{section.lower()}.{name}".to_string();\n') + file.write(f' validate_vec(&fieldname, &self.{name}, {validator})?;\n') + file.write(f' validate_{section.lower()}(self)\n') + file.write(' }\n') + file.write('}\n\n') + +def write_rust_merge_trait_impl(file, section, entries): + """Generate Rust code for the Merge Trait for a section""" + file.write(f'impl Merge for recsettings::{section.capitalize()} {{\n') + file.write(' fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n') + file.write(' if let Some(m) = map {\n') + for entry in entries: + if entry['section'] != section: + continue + if 'skip-yaml' in entry: + continue + rtype = get_rust_type(entry['type']) + name = entry['name'] + file.write(f' if m.contains_key("{name}") {{\n') + if rtype in ('bool', 'u64', 'f64', 'String'): + 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') + file.write(f' self.{name}.clear();\n') + file.write(' }\n') + file.write(f' merge_vec(&mut self.{name}, &mut rhs.{name});\n') + file.write(' }\n') + file.write(' }\n') + file.write(' }\n') + file.write('}\n\n') + +def gen_rust(srcdir, entries): + """Generate Rust code all entries""" + def_functions = [] + sections = {} + 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-preamble-in.rs\n') + 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(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) + + file.write(' // END INCLUDE rust-bridge-in.rs\n\n') + for entry in entries: + if entry['section'] == 'commands': + continue + sections[entry['section']] = entry['section'] + + for section in sections: + write_rust_section(file, section, entries, def_functions) + + file.write(' #[derive(Serialize, Deserialize, Debug)]\n') + file.write(' #[serde(deny_unknown_fields)]\n') + file.write(' pub struct Recursorsettings {\n') + for section in sections: + file.write(' #[serde(default, skip_serializing_if = "crate::is_default")]\n') + file.write(f' {section.lower()}: {section.capitalize()},\n') + file.write('} // End of generated structs\n') + file.write('}\n') + + for section in sections: + write_rust_default_trait_impl(file, section) + write_rust_default_trait_impl(file, 'Recursorsettings') + + for section in sections: + write_validator(file, section, entries) + + file.write('impl crate::recsettings::Recursorsettings {\n') + file.write(' fn validate(&self) -> Result<(), ValidationError> {\n') + for section in sections: + file.write(f' self.{section.lower()}.validate()?;\n') + file.write(' Ok(())\n') + file.write(' }\n') + file.write('}\n\n') + + for section in sections: + write_rust_merge_trait_impl(file, section, entries) + + file.write('impl Merge for crate::recsettings::Recursorsettings {\n') + file.write(' fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n') + file.write(' if let Some(m) = map {\n') + for section in sections: + file.write(f' if let Some(s) = m.get("{section}") {{\n') + file.write(' if s.is_mapping() {\n') + file.write((f' self.{section}.merge(&mut rhs.{section},' + ' s.as_mapping());\n')) + file.write(' }\n') + file.write(' }\n') + file.write(' }\n') + file.write(' }\n') + file.write('}\n\n') + + for entry in def_functions: + file.write(entry) + file.close() + +def gen_docs_meta(file, entry, name, is_tuple): + """Write .. versionadded:: and related entries""" + if name in entry: + val = entry[name] + if not isinstance(val, list): + val = [val] + for vers in val: + if is_tuple: + file.write(f'.. {name}:: {vers[0]}\n\n') + file.write(f' {vers[1].strip()}\n') + else: + file.write(f'.. {name}:: {vers}\n') + +def gen_oldstyle_docs(srcdir, entries): + """Write old style docs""" + 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(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') + + for entry in entries: + if entry['type'] == LType.Command: + continue + if entry['doc'].strip() == 'SKIP': + continue + if 'skip-old' in entry: + continue + oldname = entry['oldname'] + section = entry['section'] + file.write(f'.. _setting-{oldname}:\n\n') + file.write(f'``{oldname}``\n') + dots = '~' * (len(entry['oldname']) + 4) + file.write(f'{dots}\n') + gen_docs_meta(file, entry, 'versionadded', False) + gen_docs_meta(file, entry, 'versionchanged', True) + gen_docs_meta(file, entry, 'deprecated', True) + if 'doc-rst' in entry: + file.write(entry['doc-rst'].strip()) + file.write('\n') + file.write('\n') + typ = get_olddoc_typename(entry['type']) + file.write(f'- {typ}\n') + if 'docdefault' in entry: + file.write(f"- Default: {entry['docdefault']}\n\n") + else: + file.write((f"- Default: " + f"{get_default_olddoc_value(entry['type'], entry['default'])}\n\n")) + if 'skip-yaml' in entry: + file.write('- YAML setting does not exist\n\n') + else: + file.write(f"- YAML setting: :ref:`setting-yaml-{section}.{entry['name']}`\n\n") + if 'runtime' in entry: + runtime = entry['runtime'] + if not isinstance(runtime, list): + runtime = [runtime] + li = [] + for v in runtime: + if v == 'reload-yaml': + continue + li.append('``' + v + '``') + file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n") + file.write(entry['doc'].strip()) + file.write('\n\n') + +def fixxrefs(entries, arg): + """Docs in table refer to old style names, we modify them to ref to new style""" + matches = re.findall(':ref:`setting-(.*?)`', arg) + # We want to replace longest match first, to avoid a short match modifying a long one + matches = sorted(matches, key = lambda x: -len(x)) + for match in matches: + for entry in entries: + if entry['oldname'] == match: + key = ':ref:`setting-' + match + repl = ':ref:`setting-yaml-' + entry['section'] + '.' + entry['name'] + arg = arg.replace(key, repl) + return arg + +def gen_newstyle_docs(srcdir, argentries): + """Write new style docs""" + entries = sorted(argentries, key = lambda entry: [entry['section'], entry['name']]) + 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(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') + + for entry in entries: + if entry['type'] == LType.Command: + continue + if entry['doc'].strip() == 'SKIP': + continue + if 'skip-yaml' in entry: + continue + section = entry['section'] + name = entry['name'] + fullname = section + '.' + name + file.write(f'.. _setting-yaml-{fullname}:\n\n') + file.write(f'``{fullname}``\n') + dots = '^' * (len(fullname) + 4) + file.write(f'{dots}\n') + gen_docs_meta(file, entry, 'versionadded', False) + gen_docs_meta(file, entry, 'versionchanged', True) + gen_docs_meta(file, entry, 'deprecated', True) + if 'doc-rst' in entry: + file.write(fixxrefs(entries, entry['doc-rst'].strip())) + file.write('\n') + file.write('\n') + file.write(f"- {get_newdoc_typename(entry['type'])}\n") + if 'docdefault' in entry: + file.write(f"- Default: {entry['docdefault']}\n\n") + else: + file.write((f"- Default: " + f"{get_default_newdoc_value(entry['type'], entry['default'])}\n\n")) + if 'skip-old' in entry: + file.write(f"- {entry['skip-old']}\n\n") + else: + file.write(f"- Old style setting: :ref:`setting-{entry['oldname']}`\n\n") + if 'runtime' in entry: + runtime = entry['runtime'] + if not isinstance(runtime, list): + runtime = [runtime] + li = [] + for v in runtime: + vv = '``' + v + '``' + if v == 'reload-yaml': + vv = 'since 5.2.0: ' + vv + li.append(vv) + file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n") + if 'doc-new' in entry: + file.write(fixxrefs(entries, entry['doc-new'].strip())) + else: + file.write(fixxrefs(entries, entry['doc'].strip())) + file.write('\n\n') + +RUNTIME = '*runtime determined*' + +def unlinkMissingOK(path): + try: + path.unlink() + except FileNotFoundError: + pass + +def generate(): + """Read table, validate and generate C++, Rust and .rst files""" + srcdir = '.' + gendir = '.' + if len(sys.argv) == 3: + print("Generate: using srcdir and gendir from arguments") + 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(srcdir + '/table.py', mode='r', encoding="utf-8") as file: + entries = eval(file.read()) + + for entry in entries: + the_oldname = entry['name'].replace('_', '-') + if 'oldname' in entry: + if entry['oldname'] == the_oldname: + sys.stderr.write(f"Redundant old name {entry['oldname']}\n") + else: + entry['oldname'] = the_oldname + + dupcheck1 = {} + dupcheck2 = {} + for entry in entries: + if entry['oldname'] in dupcheck1: + sys.stderr.write(f"duplicate entries with oldname = {entry['oldname']}\n") + sys.exit(1) + if entry['section'] + '.' + entry['name'] in dupcheck2: + sys.stderr.write((f"duplicate entries with section.name = " + f"{entry['section']}.{ entry['name']}\n")) + sys.exit(1) + dupcheck1[entry['oldname']] = True + dupcheck2[entry['section'] + '.' + entry['name']] = True + # And generate C++, Rust and docs code based on table + # 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(srcdir + '/../docs'): + gen_oldstyle_docs(srcdir, entries) + gen_newstyle_docs(srcdir, entries) + # Remove cxx generated files, they need to be re-generated after a table change and the rust dependency tracking does + # not do that in some cases. + unlinkMissingOK(Path(gendir, 'rust', 'librecrust.a')) + unlinkMissingOK(Path(gendir, 'rust', 'lib.rs.h')) + unlinkMissingOK(Path(gendir, 'rust', 'web.rs.h')) + unlinkMissingOK(Path(gendir, 'rust', 'cxx.h')) + unlinkMissingOK(Path(gendir, 'rust', 'misc.rs.h')) + # Path.walk exists only in very recent versions of Python + # With meson, target is in toplevel build dir + # With autotools, target exists in rec-rust-lib/rust and this Python script is executed with cwd rec-rust-lib + for topdir in ['target', 'rust/target']: + for root, dirs, files in os.walk(topdir, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + +generate() diff -Nru pdns-recursor-5.2.13/rec-rust-lib/meson.build pdns-recursor-5.4.9/rec-rust-lib/meson.build --- pdns-recursor-5.2.13/rec-rust-lib/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/meson.build 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,36 @@ +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') + +recrust = custom_target( + 'rec-rust-sources', + command: [python, '@INPUT0@', '@SOURCE_ROOT@/rec-rust-lib', '@BUILD_ROOT@/rec-rust-lib'], + input: sources, + output: generated, +) + +# librec_common depends on this, so the sources get linked +dep_recrust_ch = declare_dependency( + sources: [recrust, '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_recrust) +dep_recrust = declare_dependency( + include_directories: [include_directories('.'), ] +) + +subdir('rust') + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/Cargo.lock pdns-recursor-5.4.9/rec-rust-lib/rust/Cargo.lock --- pdns-recursor-5.2.13/rec-rust-lib/rust/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/Cargo.lock 2026-10-26 09:47:09.877306500 +0000 @@ -0,0 +1,864 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "cxx" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6f8908ed0826ab0aec7c8358a4de3a9b26c5ed391a5dc5135765d2fd1aa8fb" +dependencies = [ + "cc", + "cxx-build", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ae25c0ce72ac21a77b5deec4f49b452238ef97072f697dd6fd752b1355ecd" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d53791812143bd27f74ab6055f22e875f04c59bbef0ca03d714ebec6f6f484" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd557619f7dc2252bf7373f6bec5600ce60a2b477e5b3b84eb4e074bb297795e" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe465fc5b9d0231ea141c4fae714a08f4f907855e1a7ca10cc90ab6c8b12ece" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "link-cplusplus" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" +dependencies = [ + "cc", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "recrust" +version = "5.4.9" +dependencies = [ + "base64", + "bytes", + "cxx", + "cxx-build", + "form_urlencoded", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "once_cell", + "ring", + "rustls", + "rustls-pki-types", + "serde", + "serde_yaml", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scratch" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/Cargo.toml pdns-recursor-5.4.9/rec-rust-lib/rust/Cargo.toml --- pdns-recursor-5.2.13/rec-rust-lib/rust/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/Cargo.toml 2026-10-26 09:47:09.383297000 +0000 @@ -0,0 +1,38 @@ +[package] +name = "recrust" +edition = "2021" +description = "Rust-based static library for PowerDNS recursor" +license = "GPL-2.0-only" +# Convention: major/minor is equal to rec's major/minor +# Note that this line will be automatically updated to the value +# BUILDER_VERSION when a release tarball is built +# See builder-support/helpers/update-rust-library-version.py +# called from meson-dist-script.sh +version = "5.4.9" + +[lib] +name = "recrust" +crate-type = ["staticlib"] + +[dependencies] +cxx = "1.0.181" # issue #16101 +serde = { version = "1.0", features = ["derive"] } +serde_yaml = { version = "0.9.34" } +ipnet = "2.8" +once_cell = "1.18.0" +base64 = "0.22" +hyper = { version = "1", features = ["server", "http1"]} +tokio = { version = "1" , features = ["rt", "net"]} +http-body-util = "0.1" +hyper-util = { version = "0.1", features = ["tokio"]} +bytes = "1.11" +form_urlencoded = "1.2" +hyper-rustls = { version = "0.27", default-features = false } +ring = "0.17.13" +rustls = { version = "0.23", default-features = false, features = ["ring"] } +pki-types = { package = "rustls-pki-types", version = "1.10" } +tokio-rustls = { version = "0.26", default-features = false } + +[build-dependencies] +cxx-build = "1.0" + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/Makefile.am pdns-recursor-5.4.9/rec-rust-lib/rust/Makefile.am --- pdns-recursor-5.2.13/rec-rust-lib/rust/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/Makefile.am 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,32 @@ +CARGO ?= cargo + +all install: librecrust.a + +EXTRA_DIST = \ + Cargo.lock \ + Cargo.toml \ + build.rs \ + src/bridge.rs \ + src/helpers.rs \ + src/misc.rs \ + src/web.rs + +# should actually end up in a target specific dir... +librecrust.a lib.rs.h web.rs.h misc.rs.h: \ + Cargo.lock \ + Cargo.toml \ + build.rs \ + src/bridge.rs \ + src/helpers.rs \ + src/lib.rs \ + src/misc.rs \ + src/web.rs + SYSCONFDIR=$(sysconfdir) NODCACHEDIRNOD=$(localstatedir)/nod NODCACHEDIRUDR=$(localstatedir)/udr $(CARGO) build --release $(RUST_TARGET) --target-dir=$(builddir)/target --manifest-path ${srcdir}/Cargo.toml + cp -pv target/$(RUSTC_TARGET_ARCH)/release/librecrust.a librecrust.a + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/lib.rs.h lib.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/web.rs.h web.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/misc.rs.h misc.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/rust/cxx.h cxx.h + +clean-local: + rm -rf librecrust.a src/lib.rs lib.rs.h web.rs.h cxx.h misc.rs.h target diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/Makefile.in pdns-recursor-5.4.9/rec-rust-lib/rust/Makefile.in --- pdns-recursor-5.2.13/rec-rust-lib/rust/Makefile.in 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/Makefile.in 2026-10-26 09:47:08.892369300 +0000 @@ -0,0 +1,610 @@ +# Makefile.in generated by automake 1.17 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2024 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +am__rm_f = rm -f $(am__rm_f_notfound) +am__rm_rf = rm -rf $(am__rm_f_notfound) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = rec-rust-lib/rust +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \ + $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ + $(top_srcdir)/m4/ax_check_sign.m4 \ + $(top_srcdir)/m4/ax_compare_version.m4 \ + $(top_srcdir)/m4/ax_compile_check_sizeof.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \ + $(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \ + $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/pdns_check_cargo.m4 \ + $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \ + $(top_srcdir)/m4/pdns_check_curl.m4 \ + $(top_srcdir)/m4/pdns_check_dnstap.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ + $(top_srcdir)/m4/pdns_check_libcrypto_eddsa.m4 \ + $(top_srcdir)/m4/pdns_check_libcurl.m4 \ + $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ + $(top_srcdir)/m4/pdns_check_network_libs.m4 \ + $(top_srcdir)/m4/pdns_check_os.m4 \ + $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ + $(top_srcdir)/m4/pdns_check_python_venv.m4 \ + $(top_srcdir)/m4/pdns_check_ragel.m4 \ + $(top_srcdir)/m4/pdns_check_secure_memset.m4 \ + $(top_srcdir)/m4/pdns_check_time_t.m4 \ + $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ + $(top_srcdir)/m4/pdns_enable_coverage.m4 \ + $(top_srcdir)/m4/pdns_enable_lto.m4 \ + $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ + $(top_srcdir)/m4/pdns_enable_nod.m4 \ + $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ + $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ + $(top_srcdir)/m4/pdns_enable_tls.m4 \ + $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ + $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ + $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ + $(top_srcdir)/m4/pdns_init_auto_vars.m4 \ + $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ + $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ + $(top_srcdir)/m4/pdns_stack_protector.m4 \ + $(top_srcdir)/m4/pdns_with_libcap.m4 \ + $(top_srcdir)/m4/pdns_with_libsodium.m4 \ + $(top_srcdir)/m4/pdns_with_libssl.m4 \ + $(top_srcdir)/m4/pdns_with_lua.m4 \ + $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ + $(top_srcdir)/m4/pdns_with_service_user.m4 \ + $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ +BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ +BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ +BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ +BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@ +BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@ +BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@ +BOOST_LDPATH = @BOOST_LDPATH@ +BOOST_ROOT = @BOOST_ROOT@ +BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ +BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ +BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ +BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ +BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ +BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ +BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ +BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ +BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ +CARGO = @CARGO@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CURL = @CURL@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DYNLINKFLAGS = @DYNLINKFLAGS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FSTRM_CFLAGS = @FSTRM_CFLAGS@ +FSTRM_LIBS = @FSTRM_LIBS@ +GREP = @GREP@ +HAVE_CXX17 = @HAVE_CXX17@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCAP_CFLAGS = @LIBCAP_CFLAGS@ +LIBCAP_LIBS = @LIBCAP_LIBS@ +LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ +LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ +LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBDL = @LIBDL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ +LIBSSL_LIBS = @LIBSSL_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NET_SNMP_LIBS = @NET_SNMP_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RAGEL = @RAGEL@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RT_LIBS = @RT_LIBS@ +SANITIZER_FLAGS = @SANITIZER_FLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSTEMCTL = @SYSTEMCTL@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ +THREADFLAGS = @THREADFLAGS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ +YAHTTP_LIBS = @YAHTTP_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__rm_f_notfound = @am__rm_f_notfound@ +am__tar = @am__tar@ +am__untar = @am__untar@ +am__xargs_n = @am__xargs_n@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nodcachedir = @nodcachedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pdns_configure_args = @pdns_configure_args@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +service_group = @service_group@ +service_user = @service_user@ +sharedstatedir = @sharedstatedir@ +socketdir = @socketdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemd = @systemd@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = \ + Cargo.lock \ + Cargo.toml \ + build.rs \ + src/bridge.rs \ + src/helpers.rs \ + src/misc.rs \ + src/web.rs + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign rec-rust-lib/rust/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign rec-rust-lib/rust/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -$(am__rm_f) $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +CARGO ?= cargo + +all install: librecrust.a + +# should actually end up in a target specific dir... +librecrust.a lib.rs.h web.rs.h misc.rs.h: \ + Cargo.lock \ + Cargo.toml \ + build.rs \ + src/bridge.rs \ + src/helpers.rs \ + src/lib.rs \ + src/misc.rs \ + src/web.rs + SYSCONFDIR=$(sysconfdir) NODCACHEDIRNOD=$(localstatedir)/nod NODCACHEDIRUDR=$(localstatedir)/udr $(CARGO) build --release $(RUST_TARGET) --target-dir=$(builddir)/target --manifest-path ${srcdir}/Cargo.toml + cp -pv target/$(RUSTC_TARGET_ARCH)/release/librecrust.a librecrust.a + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/lib.rs.h lib.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/web.rs.h web.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/recrust/src/misc.rs.h misc.rs.h + cp -pv target/$(RUSTC_TARGET_ARCH)/cxxbridge/rust/cxx.h cxx.h + +clean-local: + rm -rf librecrust.a src/lib.rs lib.rs.h web.rs.h cxx.h misc.rs.h target + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + +# Tell GNU make to disable its built-in pattern rules. +%:: %,v +%:: RCS/%,v +%:: RCS/% +%:: s.% +%:: SCCS/s.% diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/build.rs pdns-recursor-5.4.9/rec-rust-lib/rust/build.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/build.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/build.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,13 @@ +fn main() { + let sources = vec!["src/lib.rs", "src/web.rs", "src/misc.rs"]; + cxx_build::bridges(sources) + // .file("src/source.cc") Code callable from Rust is in ../cxxsupport.cc + .std("c++17") + .flag("-Isrc") + .flag("-I../..") + .compile("recrust"); + + // lib.rs is generated and taken care of by parent Makefile + println!("cargo:rerun-if-changed=src/misc.rs"); + println!("cargo:rerun-if-changed=src/web.rs"); +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/build_recrust pdns-recursor-5.4.9/rec-rust-lib/rust/build_recrust --- pdns-recursor-5.2.13/rec-rust-lib/rust/build_recrust 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/build_recrust 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,37 @@ +#!/bin/sh -e + +export CARGO="${CARGO:-$_defaultCARGO}" + +#echo "PWD=$PWD" +#echo "srcdir=$srcdir" +#echo "builddir=$builddir" +# cxx/cxxbridge generate the files lib.rs.h and cxx.h inside $CARGO_TARGET_DIR if it is set +# otherwise it uses target +#echo "CARGO_TARGET_DIR=${CARGO_TARGET_DIR}" +mytarget=${CARGO_TARGET_DIR-target} +#echo "mytarget=${mytarget}" + +CARGO_PROFILE="--release" +if [ -n "${CARGO_USE_DEV}" ]; then + CARGO_PROFILE="" + if [ -n "${CARGO_USE_CLIPPY}" ]; then + $CARGO clippy --manifest-path $srcdir/Cargo.toml + fi +fi + +$CARGO build ${CARGO_PROFILE} $RUST_TARGET --target-dir=$builddir/target --manifest-path $srcdir/Cargo.toml + +if [ -n "${CARGO_USE_DEV}" ]; then + cp -p target/$RUSTC_TARGET_ARCH/debug/librecrust.a $builddir/rec-rust-lib/rust/librecrust.a +else + cp -p target/$RUSTC_TARGET_ARCH/release/librecrust.a $builddir/rec-rust-lib/rust/librecrust.a +fi + +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/lib.rs.h $srcdir/lib.rs.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/lib.rs.h $builddir/rec-rust-lib/rust/lib.rs.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $srcdir/cxx.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/rust/cxx.h $builddir/rec-rust-lib/rust/cxx.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/web.rs.h $srcdir/web.rs.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/web.rs.h $builddir/rec-rust-lib/rust/web.rs.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/misc.rs.h $srcdir/misc.rs.h +cp -p $mytarget/$RUSTC_TARGET_ARCH/cxxbridge/recrust/src/misc.rs.h $builddir/rec-rust-lib/rust/misc.rs.h diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/meson.build pdns-recursor-5.4.9/rec-rust-lib/rust/meson.build --- pdns-recursor-5.2.13/rec-rust-lib/rust/meson.build 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/meson.build 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,42 @@ + +build = find_program('build_recrust') +cargo = find_program('cargo') +infile = 'Cargo.toml' +outfile = 'librecrust.a' + + +env = environment() +env.set('_defaultCARGO', cargo.full_path()) +env.set('SYSCONFDIR', conf.get('SYSCONFDIR').strip('"')) +env.set('NODCACHEDIRNOD', conf.get('NODCACHEDIRNOD').strip('"')) +env.set('NODCACHEDIRUDR', conf.get('NODCACHEDIRUDR').strip('"')) +env.set('builddir', '.') +env.set('srcdir', meson.current_source_dir()) +# The two calls below set the env var to the empty string if it does not exist already and leave it alone otherwise +env.append('RUST_TARGET', '', separator: '') +env.append('RUSTC_TARGET_ARCH', '', separator: '') + +lib_recrust = custom_target('librecrust.a', + output: [outfile, 'cxx.h', 'lib.rs.h', 'misc.rs.h', 'web.rs.h'], + input: infile, + command: [build, + ], + depend_files: [ + 'Cargo.toml', + 'Cargo.lock', + 'src/bridge.hh', + 'src/bridge.rs', + 'src/helpers.rs', + 'src/misc.rs', + 'src/web.rs', + ], + depends: recrust, + env: env, + console: true, +) + +dep_rust_recrust = declare_dependency( + link_with: lib_recrust[0], + sources: lib_recrust[1], + include_directories: [include_directories('.'), include_directories('src')], +) diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/bridge.hh pdns-recursor-5.4.9/rec-rust-lib/rust/src/bridge.hh --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/bridge.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/bridge.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * 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 + +#include "rust/cxx.h" +#include "credentials.hh" +#include "logr.hh" + +class NetmaskGroup; +union ComboAddress; + +namespace pdns::rust::misc +{ +enum class Priority : uint8_t; +enum class LogLevel : uint8_t; +using Logger = ::Logr::Logger; +struct KeyValue; + +template +class Wrapper +{ +public: + Wrapper(const A& arg); + ~Wrapper(); // out-of-line definition, to keep A opaque + + Wrapper() = delete; + Wrapper(const Wrapper&) = delete; + Wrapper(Wrapper&&) = delete; + Wrapper& operator=(const Wrapper&) = delete; + Wrapper& operator=(Wrapper&&) = delete; + + [[nodiscard]] const A& get() const; + +private: + std::unique_ptr d_ptr; +}; + +using NetmaskGroup = Wrapper<::NetmaskGroup>; +using ComboAddress = Wrapper<::ComboAddress>; + +uint16_t qTypeStringToCode(::rust::Str str); +bool isValidHostname(::rust::Str str); +std::unique_ptr comboaddress(::rust::Str str); +bool matches(const std::unique_ptr& nmg, const std::unique_ptr& address); +std::shared_ptr withValue(const std::shared_ptr& logger, ::rust::Str key, ::rust::Str val); +void log(const std::shared_ptr& logger, Priority log_level, ::rust::Str msg, const ::rust::Vec& values); +void error(const std::shared_ptr& logger, Priority log_level, ::rust::Str err, ::rust::Str msg, const ::rust::Vec& values); +::rust::String getUUID(); +} + +namespace pdns::rust::web::rec +{ +using CredentialsHolder = ::CredentialsHolder; +struct KeyValue; +struct Request; +struct Response; +struct IncomingWSConfig; + +void apiServer(const Request& rustRequest, Response& rustResponse); +void apiDiscovery(const Request& rustRequest, Response& rustResponse); +void apiDiscoveryV1(const Request& rustRequest, Response& rustResponse); +void apiServerCacheFlush(const Request& rustRequest, Response& rustResponse); +void apiServerDetail(const Request& rustRequest, Response& rustResponse); +void apiServerStatistics(const Request& rustRequest, Response& rustResponse); +void apiServerZonesGET(const Request& rustRequest, Response& rustResponse); +void apiServerZonesPOST(const Request& rustRequest, Response& rustResponse); +void prometheusMetrics(const Request& rustRequest, Response& rustResponse); +void serveStuff(const Request& rustRequest, Response& rustResponse); +void jsonstat(const Request& rustRequest, Response& rustResponse); +void apiServerConfigAllowFromPUT(const Request& rustRequest, Response& rustResponse); +void apiServerConfigAllowFromGET(const Request& rustRequest, Response& rustResponse); +void apiServerConfigAllowNotifyFromGET(const Request& rustRequest, Response& rustResponse); +void apiServerConfigAllowNotifyFromPUT(const Request& rustRequest, Response& rustResponse); +void apiServerConfig(const Request& rustRequest, Response& rustResponse); +void apiServerRPZStats(const Request& rustRequest, Response& rustResponse); +void apiServerSearchData(const Request& rustRequest, Response& rustResponse); +void apiServerZoneDetailGET(const Request& rustRequest, Response& rustResponse); +void apiServerZoneDetailPUT(const Request& rustRequest, Response& rustResponse); +void apiServerZoneDetailDELETE(const Request& rustRequest, Response& rustResponse); +void apiServerOTConditionsGET(const Request& rustRequest, Response& rustResponse); +void apiServerOTConditionDetailGET(const Request& rustRequest, Response& rustResponse); +void apiServerOTConditionDetailDELETE(const Request& rustRequest, Response& rustResponse); +void apiServerOTConditionDetailPOST(const Request& rustRequest, Response& rustResponse); +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/bridge.rs pdns-recursor-5.4.9/rec-rust-lib/rust/src/bridge.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/bridge.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/bridge.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,1457 @@ +/* + * 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. + */ + +use base64::prelude::*; +use once_cell::sync::Lazy; +use std::fs::File; +use std::io::{BufReader, BufWriter, ErrorKind, Write}; +use std::net::{IpAddr, SocketAddr}; +use std::str::FromStr; +use std::sync::Mutex; + +use crate::helpers::OVERRIDE_TAG; +use crate::misc::rustmisc; +use crate::recsettings::{self, *}; +use crate::{Merge, ValidationError}; + +impl Default for ForwardZone { + fn default() -> Self { + let deserialized: ForwardZone = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for AuthZone { + fn default() -> Self { + let deserialized: AuthZone = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for TrustAnchor { + fn default() -> Self { + let deserialized: TrustAnchor = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for NegativeTrustAnchor { + fn default() -> Self { + let deserialized: NegativeTrustAnchor = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for ApiZones { + fn default() -> Self { + let deserialized: ApiZones = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for XFR { + fn default() -> Self { + let deserialized: XFR = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for FCZDefault { + fn default() -> Self { + let deserialized: FCZDefault = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for ForwardingCatalogZone { + fn default() -> Self { + let deserialized: ForwardingCatalogZone = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for IncomingTLS { + fn default() -> Self { + let deserialized: IncomingTLS = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for IncomingWSConfig { + fn default() -> Self { + let deserialized: IncomingWSConfig = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +pub fn validate_socket_address(field: &str, val: &String) -> Result<(), ValidationError> { + let sa = SocketAddr::from_str(val); + if sa.is_err() { + let ip = IpAddr::from_str(val); + if ip.is_err() { + let msg = format!( + "{}: value `{}' is not an IP or IP:port combination", + field, val + ); + return Err(ValidationError { msg }); + } + } + Ok(()) +} + +fn is_port_number(str: &str) -> bool { + str.parse::().is_ok() +} + +pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), ValidationError> { + let sa = validate_socket_address(field, val); + if sa.is_err() && !rustmisc::isValidHostname(val) { + let parts: Vec<&str> = val.split(':').collect(); + if parts.len() != 2 || !rustmisc::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(()) +} + +fn validate_qtype(field: &str, val: &String) -> Result<(), ValidationError> { + let code = rustmisc::qTypeStringToCode(val); + if code == 0 { + let msg = format!("{}: value `{}' is not a qtype", field, val); + return Err(ValidationError { msg }); + } + Ok(()) +} + +fn validate_name(field: &str, val: &String) -> Result<(), ValidationError> { + if val.is_empty() { + let msg = format!("{}: value may not be empty", field); + return Err(ValidationError { msg }); + } + if val == "." { + return Ok(()); + } + // Strip potential dot at end + let mut testval = val.as_str(); + if testval.ends_with('.') { + testval = &testval[0..testval.len() - 1]; + } + for label in testval.split('.') { + if label.is_empty() { + let msg = format!("{}: `{}' has empty label", field, val); + return Err(ValidationError { msg }); + } + // XXX Too liberal, should check for alnum, - and proper \ddd + if !label.is_ascii() { + let msg = format!("{}: `{}' contains non-ascii character", field, val); + return Err(ValidationError { msg }); + } + } + Ok(()) +} + +pub fn validate_subnet(field: &str, val: &String) -> Result<(), ValidationError> { + if val.is_empty() { + let msg = format!("{}: value `{}' is not a subnet or IP", field, val); + return Err(ValidationError { msg }); + } + let mut ip = val.as_str(); + if val.starts_with('!') { + ip = &ip[1..]; + } + let subnet = ipnet::IpNet::from_str(ip); + if subnet.is_err() { + let ip = IpAddr::from_str(ip); + if ip.is_err() { + let msg = format!("{}: value `{}' is not a subnet or IP", field, val); + return Err(ValidationError { msg }); + } + } + Ok(()) +} + +fn validate_address_family( + addrfield: &str, + localfield: &str, + vec: &[String], + local_address: &String, +) -> Result<(), ValidationError> { + if vec.is_empty() { + let msg = format!("{}: cannot be empty", addrfield); + return Err(ValidationError { msg }); + } + validate_vec(addrfield, vec, validate_socket_address_or_name)?; + if local_address.is_empty() { + return Ok(()); + } + let local = IpAddr::from_str(local_address); + if local.is_err() { + let msg = format!("{}: value `{}' is not an IP", localfield, local_address); + return Err(ValidationError { msg }); + } + let local = local.unwrap(); + for addr_str in vec { + let mut wrong = false; + let sa = SocketAddr::from_str(addr_str); + if let Ok(address) = sa { + if local.is_ipv4() != address.is_ipv4() || local.is_ipv6() != address.is_ipv6() { + wrong = true; + } + } + else { + let ip = IpAddr::from_str(addr_str); + if ip.is_err() { + // It is likely a name + continue; + } + let ip = ip.unwrap(); + if local.is_ipv4() != ip.is_ipv4() || local.is_ipv6() != ip.is_ipv6() { + wrong = true; + } + } + if wrong { + let msg = format!( + "{}: value `{}' and `{}' differ in address family", + localfield, local_address, addr_str + ); + return Err(ValidationError { msg }); + } + } + Ok(()) +} + +pub fn validate_vec(field: &str, vec: &[T], func: F) -> Result<(), ValidationError> +where + F: Fn(&str, &T) -> Result<(), ValidationError>, +{ + vec.iter().try_for_each(|element| func(field, element)) +} + +pub fn parse_yaml_string(str: &str) -> Result { + serde_yaml::from_str(str) +} + +pub fn parse_yaml_string_to_allow_from(str: &str) -> Result, serde_yaml::Error> { + serde_yaml::from_str(str) +} + +pub fn parse_yaml_string_to_forward_zones( + str: &str, +) -> Result, serde_yaml::Error> { + serde_yaml::from_str(str) +} + +pub fn parse_yaml_string_to_api_zones(str: &str) -> Result { + serde_yaml::from_str(str) +} + +pub fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result, serde_yaml::Error> { + serde_yaml::from_str(str) +} + +pub fn forward_zones_to_yaml_string(vec: &Vec) -> Result { + serde_yaml::to_string(vec) +} + +fn insertb(map: &mut serde_yaml::Mapping, name: &str, val: bool) { + map.insert( + serde_yaml::Value::String(name.to_owned()), + serde_yaml::Value::Bool(val), + ); +} + +fn insertu(map: &mut serde_yaml::Mapping, name: &str, val: u64) { + map.insert( + serde_yaml::Value::String(name.to_owned()), + serde_yaml::Value::Number(serde_yaml::Number::from(val)), + ); +} + +fn insertu32(map: &mut serde_yaml::Mapping, name: &str, val: u32) { + map.insert( + serde_yaml::Value::String(name.to_owned()), + serde_yaml::Value::Number(serde_yaml::Number::from(val)), + ); +} + +fn inserts(map: &mut serde_yaml::Mapping, name: &str, val: &str) { + map.insert( + serde_yaml::Value::String(name.to_owned()), + serde_yaml::Value::String(val.to_owned()), + ); +} + +fn insertseq(map: &mut serde_yaml::Mapping, name: &str, val: &serde_yaml::Sequence) { + map.insert( + serde_yaml::Value::String(name.to_owned()), + serde_yaml::Value::Sequence(val.to_owned()), + ); +} + +impl ForwardZone { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_name(&(field.to_owned() + ".zone"), &self.zone)?; + if self.forwarders.is_empty() { + let msg = format!("{}.forwarders cannot be empty", field); + return Err(ValidationError { msg }); + } + validate_vec( + &(field.to_owned() + ".forwarders"), + &self.forwarders, + validate_socket_address_or_name, + )?; + + let expected = match field { + "recursor.forward_zones" => Some(false), + // We cannot do the check below here as the override to true takes place later, the validation + // is run immediately after parsing + // "recursor.forward_zones_recurse" => Some(true), + _ => None, + }; + if expected.is_some() && self.recurse != expected.unwrap() { + let msg = format!("{}.recurse has wrong value in this context", field); + return Err(ValidationError { msg }); + } + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.forwarders { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "zone", &self.zone); + insertb(&mut map, "recurse", self.recurse); + map.insert( + serde_yaml::Value::String("forwarders".to_owned()), + serde_yaml::Value::Sequence(seq), + ); + serde_yaml::Value::Mapping(map) + } +} + +impl AuthZone { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_name(&(field.to_owned() + ".zone"), &self.zone)?; + if self.file.is_empty() { + let msg = format!("{}.file cannot be empty", field); + return Err(ValidationError { msg }); + } + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "zone", &self.zone); + inserts(&mut map, "file", &self.file); + serde_yaml::Value::Mapping(map) + } +} + +impl TrustAnchor { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.dsrecords { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "name", &self.name); + insertseq(&mut map, "dsrecords", &seq); + serde_yaml::Value::Mapping(map) + } +} + +impl NegativeTrustAnchor { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "name", &self.name); + inserts(&mut map, "reason", &self.reason); + serde_yaml::Value::Mapping(map) + } +} + +impl ProtobufServer { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_vec( + &(field.to_owned() + ".servers"), + &self.servers, + validate_socket_address, + )?; + validate_vec( + &(field.to_owned() + ".exportTypes"), + &self.exportTypes, + validate_qtype, + )?; + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.servers { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + let mut map = serde_yaml::Mapping::new(); + insertseq(&mut map, "servers", &seq); + insertu(&mut map, "timeout", self.timeout); + insertu(&mut map, "maxQueuedEntries", self.maxQueuedEntries); + insertu(&mut map, "reconnectWaitTime", self.reconnectWaitTime); + insertb(&mut map, "taggedOnly", self.taggedOnly); + insertb(&mut map, "asyncConnect", self.asyncConnect); + insertb(&mut map, "logQueries", self.logQueries); + insertb(&mut map, "logResponses", self.logResponses); + let mut seq2 = serde_yaml::Sequence::new(); + for entry in &self.exportTypes { + seq2.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "exportTypes", &seq2); + insertb(&mut map, "logMappedFrom", self.logMappedFrom); + serde_yaml::Value::Mapping(map) + } +} + +impl DNSTapFrameStreamServer { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.servers { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + let mut map = serde_yaml::Mapping::new(); + insertseq(&mut map, "servers", &seq); + insertb(&mut map, "logQueries", self.logQueries); + insertb(&mut map, "logResponses", self.logResponses); + insertu(&mut map, "bufferHint", self.bufferHint); + insertu(&mut map, "flushTimeout", self.flushTimeout); + insertu(&mut map, "inputQueueSize", self.inputQueueSize); + insertu(&mut map, "outputQueueSize", self.outputQueueSize); + insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold); + insertu(&mut map, "reopenInterval", self.reopenInterval); + serde_yaml::Value::Mapping(map) + } +} + +impl DNSTapNODFrameStreamServer { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.servers { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + let mut map = serde_yaml::Mapping::new(); + insertseq(&mut map, "servers", &seq); + insertb(&mut map, "logNODs", self.logNODs); + insertb(&mut map, "logUDRs", self.logUDRs); + insertu(&mut map, "bufferHint", self.bufferHint); + insertu(&mut map, "flushTimeout", self.flushTimeout); + insertu(&mut map, "inputQueueSize", self.inputQueueSize); + insertu(&mut map, "outputQueueSize", self.outputQueueSize); + insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold); + insertu(&mut map, "reopenInterval", self.reopenInterval); + serde_yaml::Value::Mapping(map) + } +} + +impl SortList { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "key", &self.key); + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.subnets { + let mut submap = serde_yaml::Mapping::new(); + inserts(&mut submap, "subnet", &entry.subnet); + insertu32(&mut submap, "order", entry.order); + seq.push(serde_yaml::Value::Mapping(submap)); + } + insertseq(&mut map, "subnets", &seq); + serde_yaml::Value::Mapping(map) + } +} + +impl RPZ { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + if self.extendedErrorCode > u16::MAX as u32 && self.extendedErrorCode != u32::MAX { + let msg = format!( + "{}: value `{}' is no a valid extendedErrorCode", + field, self.extendedErrorCode + ); + return Err(ValidationError { msg }); + } + self.tsig.validate(&(field.to_owned() + ".tsig"))?; + if !self.addresses.is_empty() { + validate_address_family( + &(field.to_owned() + ".addresses"), + &(field.to_owned() + ".localAddress"), + &self.addresses, + &self.localAddress, + )?; + } + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + let mut seq1 = serde_yaml::Sequence::new(); + for entry in &self.addresses { + seq1.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "addresses", &seq1); + inserts(&mut map, "name", &self.name); + inserts(&mut map, "defcontent", &self.defcontent); + inserts(&mut map, "defpol", &self.defpol); + insertb( + &mut map, + "defpolOverrideLocalData", + self.defpolOverrideLocalData, + ); + insertu32(&mut map, "defttl", self.defttl); + insertu32(&mut map, "extendedErrorCode", self.extendedErrorCode); + insertb(&mut map, "includeSOA", self.includeSOA); + insertb(&mut map, "ignoreDuplicates", self.ignoreDuplicates); + insertu32(&mut map, "maxTTL", self.maxTTL); + inserts(&mut map, "policyName", &self.policyName); + let mut seq2 = serde_yaml::Sequence::new(); + for entry in &self.tags { + seq2.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "tags", &seq2); + insertb(&mut map, "overridesGettag", self.overridesGettag); + insertu32(&mut map, "zoneSizeHint", self.zoneSizeHint); + + let mut tsigmap = serde_yaml::Mapping::new(); + inserts(&mut tsigmap, "name", &self.tsig.name); + inserts(&mut tsigmap, "algo", &self.tsig.algo); + inserts(&mut tsigmap, "secret", &self.tsig.secret); + map.insert( + serde_yaml::Value::String("tsig".to_owned()), + serde_yaml::Value::Mapping(tsigmap), + ); + + insertu32(&mut map, "refresh", self.refresh); + insertu32(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes); + inserts(&mut map, "localAddress", &self.localAddress); + insertu32(&mut map, "axfrTimeout", self.axfrTimeout); + inserts(&mut map, "dumpFile", &self.dumpFile); + inserts(&mut map, "seedFile", &self.seedFile); + serde_yaml::Value::Mapping(map) + } +} + +impl ZoneToCache { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + match self.method.as_str() { + "axfr" | "url" | "file" => {} + _ => { + let msg = format!( + "{}: must be one of axfr, url, file", + &(field.to_string() + ".method") + ); + return Err(ValidationError { msg }); + } + } + if self.sources.is_empty() { + let msg = format!( + "{}: at least one source required", + &(field.to_string() + ".sources") + ); + return Err(ValidationError { msg }); + } + if self.method == "axfr" { + validate_vec( + &(field.to_string() + ".sources"), + &self.sources, + validate_socket_address, + )?; + validate_address_family( + &(field.to_string() + ".sources"), + &(field.to_string() + ".localAddress"), + &self.sources, + &self.localAddress, + )?; + } + self.tsig.validate(&(field.to_owned() + ".tsig"))?; + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "zone", &self.zone); + inserts(&mut map, "method", &self.method); + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.sources { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "sources", &seq); + insertu(&mut map, "timeout", self.timeout); + + let mut tsigmap = serde_yaml::Mapping::new(); + inserts(&mut tsigmap, "name", &self.tsig.name); + inserts(&mut tsigmap, "algo", &self.tsig.algo); + inserts(&mut tsigmap, "secret", &self.tsig.secret); + map.insert( + serde_yaml::Value::String("tsig".to_owned()), + serde_yaml::Value::Mapping(tsigmap), + ); + + insertu(&mut map, "refreshPeriod", self.refreshPeriod); + insertu(&mut map, "retryOnErrorPeriod", self.retryOnErrorPeriod); + insertu(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes); + inserts(&mut map, "localAddress", &self.localAddress); + inserts(&mut map, "zonemd", &self.zonemd); + inserts(&mut map, "dnssec", &self.dnssec); + + serde_yaml::Value::Mapping(map) + } +} + +impl AllowedAdditionalQType { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "qtype", &self.qtype); + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.targets { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "targets", &seq); + inserts(&mut map, "mode", &self.mode); + serde_yaml::Value::Mapping(map) + } +} + +impl ProxyMapping { + pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "subnet", &self.subnet); + inserts(&mut map, "address", &self.address); + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.domains { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "domains", &seq); + serde_yaml::Value::Mapping(map) + } +} + +impl TSIGTriplet { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + let namelen = self.name.len(); + let algolen = self.algo.len(); + let secretlen = self.secret.len(); + if namelen == 0 && algolen == 0 && secretlen == 0 { + return Ok(()); + } + if namelen == 0 || algolen == 0 || secretlen == 0 { + let msg = format!("{}: a field value is missing", field); + return Err(ValidationError { msg }); + } + if BASE64_STANDARD.decode(&self.secret).is_err() { + let msg = format!("{}.secret: `{}' is not a Base64 string", field, self.secret); + return Err(ValidationError { msg }); + } + Ok(()) + } +} + +impl ForwardingCatalogZone { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + self.xfr.tsig.validate(&(field.to_owned() + ".xfr.tsig"))?; + if !self.xfr.addresses.is_empty() { + validate_address_family( + &(field.to_owned() + ".xfr.addresses"), + &(field.to_owned() + ".xfr.localAddress"), + &self.xfr.addresses, + &self.xfr.localAddress, + )?; + } else { + let msg = format!("{}.xfr.addresses: at least one address required", field); + return Err(ValidationError { msg }); + } + Ok(()) + } + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "zone", &self.zone); + insertb(&mut map, "notify_allowed", self.notify_allowed); + + let mut xfrmap = serde_yaml::Mapping::new(); + let mut addrs = serde_yaml::Sequence::new(); + for address in &self.xfr.addresses { + addrs.push(serde_yaml::Value::String(address.to_owned())); + } + insertseq(&mut xfrmap, "addresses", &addrs); + insertu32(&mut xfrmap, "zoneSizeHint", self.xfr.zoneSizeHint); + let mut tsigmap = serde_yaml::Mapping::new(); + inserts(&mut tsigmap, "name", &self.xfr.tsig.name); + inserts(&mut tsigmap, "algo", &self.xfr.tsig.algo); + inserts(&mut tsigmap, "secret", &self.xfr.tsig.secret); + xfrmap.insert( + serde_yaml::Value::String("tsig".to_owned()), + serde_yaml::Value::Mapping(tsigmap), + ); + insertu32(&mut xfrmap, "refresh", self.xfr.refresh); + insertu32(&mut xfrmap, "maxReceivedMBytes", self.xfr.maxReceivedMBytes); + inserts(&mut xfrmap, "localAddress", &self.xfr.localAddress); + insertu32(&mut xfrmap, "axfrTimeout", self.xfr.axfrTimeout); + map.insert( + serde_yaml::Value::String("xfr".to_owned()), + serde_yaml::Value::Mapping(xfrmap), + ); + + let mut groupseq = serde_yaml::Sequence::new(); + for entry in &self.groups { + let mut submap = serde_yaml::Mapping::new(); + inserts(&mut submap, "name", &entry.name); + let mut fwseq = serde_yaml::Sequence::new(); + for forwarder in &entry.forwarders { + fwseq.push(serde_yaml::Value::String(forwarder.to_owned())); + } + insertseq(&mut submap, "forwarders", &fwseq); + insertb(&mut submap, "recurse", entry.recurse); + insertb(&mut submap, "notify_allowed", entry.notify_allowed); + groupseq.push(serde_yaml::Value::Mapping(submap)); + } + insertseq(&mut map, "groups", &groupseq); + serde_yaml::Value::Mapping(map) + } +} + +impl IncomingWSConfig { + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + let mut seq = serde_yaml::Sequence::new(); + for entry in &self.addresses { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "addresses", &seq); + let mut tls = serde_yaml::Mapping::new(); + inserts(&mut tls, "certificate", &self.tls.certificate); + inserts(&mut tls, "key", &self.tls.key); + map.insert( + serde_yaml::Value::String("tls".to_owned()), + serde_yaml::Value::Mapping(tls), + ); + serde_yaml::Value::Mapping(map) + } + + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_vec( + &(field.to_string() + ".addresses"), + &self.addresses, + validate_socket_address, + )?; + Ok(()) + } +} + +impl OutgoingTLSConfiguration { + + fn to_yaml_map(&self) -> serde_yaml::Value { + let mut map = serde_yaml::Mapping::new(); + inserts(&mut map, "name", &self.name); + inserts(&mut map, "provider", &self.provider); + let mut suffixes = serde_yaml::Sequence::new(); + for entry in &self.suffixes { + suffixes.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "suffixes", &suffixes); + let mut subnets = serde_yaml::Sequence::new(); + for entry in &self.subnets { + subnets.push(serde_yaml::Value::String(entry.to_owned())); + } + insertseq(&mut map, "subnets", &subnets); + insertb(&mut map, "validate_certificate", self.validate_certificate); + inserts(&mut map, "ca_store", &self.ca_store); + insertb(&mut map, "verbose_logging", self.verbose_logging); + inserts(&mut map, "subject_name", &self.subject_name); + inserts(&mut map, "subject_address", &self.subject_address); + inserts(&mut map, "ciphers", &self.ciphers); + inserts(&mut map, "ciphers_tls", &self.ciphers_tls_13); + serde_yaml::Value::Mapping(map) + } + + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + if self.name.is_empty() { + let msg = format!("{}: value may not be empty", field); + return Err(ValidationError { msg }); + } + validate_vec( + &(field.to_string() + ".suffixes"), + &self.suffixes, + validate_name, + )?; + validate_vec( + &(field.to_string() + ".subnets"), + &self.subnets, + validate_subnet, + )?; + Ok(()) + } +} + +impl OpenTelemetryTraceCondition { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_vec( + &(field.to_string() + ".acls"), + &self.acls, + validate_subnet, + )?; + validate_vec( + &(field.to_string() + ".qnames"), + &self.qnames, + validate_name, + )?; + validate_vec( + &(field.to_string() + ".qtypes"), + &self.qtypes, + validate_qtype, + )?; + if self.qid != u32::MAX && self.qid > u16::MAX.into() { + let msg = format!("{}.qid: must be between 0 and 2^16", field); + return Err(ValidationError { msg }); + } + Ok(()) + } +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_auth_zones(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, |field, element| element.validate(field)) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_forward_zones(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, |field, element| element.validate(field)) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_trustanchors(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, |field, element| element.validate(field)) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_negativetrustanchors( + field: &str, + vec: &Vec, +) -> Result<(), ValidationError> { + validate_vec(field, vec, |field, element| element.validate(field)) +} + +pub fn allow_from_to_yaml_string(vec: &Vec) -> Result { + let mut seq = serde_yaml::Sequence::new(); + for entry in vec { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + let val = serde_yaml::Value::Sequence(seq); + + serde_yaml::to_string(&val) +} + +pub fn allow_from_to_yaml_string_incoming( + key: &String, + filekey: &String, + vec: &Vec, +) -> Result { + // Produce + // incoming: + // allow-from-file: '' + // allow-from: !override + // - ... + let mut seq = serde_yaml::Sequence::new(); + for entry in vec { + seq.push(serde_yaml::Value::String(entry.to_owned())); + } + + let mut innermap = serde_yaml::Mapping::new(); + innermap.insert( + serde_yaml::Value::String(filekey.to_owned()), + serde_yaml::Value::String("".to_owned()), + ); + let af = Box::new(serde_yaml::value::TaggedValue { + tag: serde_yaml::value::Tag::new(OVERRIDE_TAG), + value: serde_yaml::Value::Sequence(seq), + }); + innermap.insert( + serde_yaml::Value::String(key.to_owned()), + serde_yaml::Value::Tagged(af), + ); + + let mut outermap = serde_yaml::Mapping::new(); + outermap.insert( + serde_yaml::Value::String("incoming".to_owned()), + serde_yaml::Value::Mapping(innermap), + ); + let outerval = serde_yaml::Value::Mapping(outermap); + + serde_yaml::to_string(&outerval) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_allow_from(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, validate_subnet) +} + +pub fn allow_for_to_yaml_string(vec: &Vec) -> Result { + // For purpose of generating yaml allow-for is no different than allow-from as we're handling a + // vector of Strings + allow_from_to_yaml_string(vec) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_allow_for(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, validate_name) +} + +#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. +pub fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<(), ValidationError> { + validate_vec(field, vec, validate_name) +} + +impl Recursorsettings { + pub fn to_yaml_string(&self) -> Result { + serde_yaml::to_string(self) + } + + fn get_value_from_map(map: &serde_yaml::Mapping, fields: &[String]) -> Result { + match fields.len() { + 0 => { + Ok(serde_yaml::Value::Mapping(map.clone())) + } + 1 => { + if let Some(found) = map.get(&fields[0]) { + Ok(found.clone()) + } + else { + Err(std::io::Error::other(fields[0].to_owned() + ": not found")) + } + } + _ => { + if let Some(found) = map.get(&fields[0]) { + if let Some(map) = found.as_mapping() { + Self::get_value_from_map(map, &fields[1..]) + } + else { + Err(std::io::Error::other(fields[0].to_owned() + ": not a mapping")) + } + } + else { + Err(std::io::Error::other(fields[0].to_owned() + ": not found")) + } + } + } + } + + fn get_value1(value: &serde_yaml::Value, field: &[String]) -> Result { + if let Some(map) = value.as_mapping() { + match field.len() { + 0 => { + return Self::get_value_from_map(map, field); + } + _ => { + if let Some(found) = map.get(&field[0]) { + let submap = serde_yaml::from_value(found.clone()); + let submap = match submap { + Ok(submap) => submap, + Err(error) => return Err(std::io::Error::other(error.to_string())) + }; + return Self::get_value_from_map(&submap, &field[1..]); + } + return Err(std::io::Error::other(field[0].to_owned() + ": not found")); + } + } + } + Err(std::io::Error::other(field[0].to_owned() + ": not a map")) + } + + fn buildnestedmaps(field: &[String], leaf: &serde_yaml::Value) -> serde_yaml::Value { + if field.is_empty() { + return leaf.clone(); + } + let submap = Self::buildnestedmaps(&field[1..], leaf); + let mut map = serde_yaml::Mapping::new(); + map.insert(serde_yaml::Value::String(field[0].clone()), + submap); + serde_yaml::Value::Mapping(map) + } + + pub fn get_value(&self, field: &[String], defaults: &str, with_comment: bool) -> Result { + let value = serde_yaml::to_value(self); + let value = match value { + Ok(value) => value, + Err(error) => return Err(std::io::Error::other(error.to_string())) + }; + match Self::get_value1(&value, field) { + Ok(yaml) => { + let map = Self::buildnestedmaps(field, &yaml); + Ok(serde_yaml::to_string(&map).unwrap()) + } + Err(_) => { + let defaults_value: serde_yaml::Value = serde_yaml::from_str(defaults).unwrap(); + let value = Self::get_value1(&defaults_value, field); + match value { + Ok(value) => { + let map = Self::buildnestedmaps(field, &value); + let res = serde_yaml::to_string(&map).unwrap(); + if with_comment { + let name = field.join("."); + let msg = format!("# {}: not explicitly set, default value(s) listed below:\n{}", name, res); + Ok(msg) + } + else { + Ok(res) + } + }, + Err(x) => Err(x) + } + } + } + } + + // validate() is implemented in the (generated) lib.rs +} + +pub static DEFAULT_CONFIG: Lazy = Lazy::new(Recursorsettings::default); + +pub fn merge_vec(lhs: &mut Vec, rhs: &mut Vec) { + lhs.append(rhs); +} + +// This is used for conversion, where we want to have !override tags in some cases, so we craft a YAML Mapping by hand +pub fn map_to_yaml_string(vec: &Vec) -> Result { + let mut map = serde_yaml::Mapping::new(); + for entry in vec { + let section = entry.section.as_str(); + if !map.contains_key(section) { + let newmap = serde_yaml::Mapping::new(); + map.insert( + serde_yaml::Value::String(section.to_string()), + serde_yaml::Value::Mapping(newmap), + ); + } + if let Some(mapentry) = map.get_mut(section) { + if let Some(mapping) = mapentry.as_mapping_mut() { + let val = match entry.type_name.as_str() { + "bool" => serde_yaml::Value::Bool(entry.value.bool_val), + "u64" => { + serde_yaml::Value::Number(serde_yaml::Number::from(entry.value.u64_val)) + } + "f64" => { + serde_yaml::Value::Number(serde_yaml::Number::from(entry.value.f64_val)) + } + "String" => serde_yaml::Value::String(entry.value.string_val.to_owned()), + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_string_val { + seq.push(serde_yaml::Value::String(element.to_owned())) + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_forwardzone_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_authzone_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_trustanchor_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_negativetrustanchor_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_protobufserver_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_dnstap_framestream_server_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_dnstap_nod_framestream_server_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_rpz_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_sortlist_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_zonetocache_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_allowedadditionalqtype_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_proxymapping_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_forwardingcatalogzone_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_outgoingtlsconfiguration_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + "Vec" => { + let mut seq = serde_yaml::Sequence::new(); + for element in &entry.value.vec_incomingwsconfig_val { + seq.push(element.to_yaml_map()); + } + serde_yaml::Value::Sequence(seq) + } + other => serde_yaml::Value::String( + "map_to_yaml_string: Unknown type: ".to_owned() + other, + ), + }; + if entry.overriding { + let tagged_value = Box::new(serde_yaml::value::TaggedValue { + tag: serde_yaml::value::Tag::new(OVERRIDE_TAG), + value: val, + }); + mapping.insert( + serde_yaml::Value::String(entry.name.to_owned()), + serde_yaml::Value::Tagged(tagged_value), + ); + } else { + mapping.insert(serde_yaml::Value::String(entry.name.to_owned()), val); + } + } + } + } + serde_yaml::to_string(&map) +} + +pub fn merge(lhs: &mut Recursorsettings, yaml_str: &str) -> Result<(), serde_yaml::Error> { + // Parse the yaml for the values + let mut rhs: Recursorsettings = serde_yaml::from_str(yaml_str)?; + // Parse again for the map containing the keys present, which is used to only override specific values, + // taking into account !override tags + let map: serde_yaml::Value = serde_yaml::from_str(yaml_str)?; + if map.is_mapping() { + lhs.merge(&mut rhs, map.as_mapping()); + } + + Ok(()) +} + +// API zones maintenance. In contrast to the old settings code, which creates a settings file per +// zone, we maintain a single yaml file with all settings. File locking is no issue, as we are the +// single process managing this dir. So we only use process specific locking. + +impl ApiZones { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_auth_zones(&(field.to_owned() + ".auth_zones"), &self.auth_zones)?; + validate_forward_zones(&(field.to_owned() + ".forward_zones"), &self.forward_zones)?; + Ok(()) + } +} + +static LOCK: Mutex = Mutex::new(false); + +// Assume we hold the lock +fn api_read_zones_locked( + path: &str, + create: bool, +) -> Result, std::io::Error> { + let zones = match File::open(path) { + Ok(file) => { + let data: Result = + serde_yaml::from_reader(BufReader::new(file)); + match data { + Err(error) => return Err(std::io::Error::other(error.to_string())), + Ok(yaml) => yaml, + } + } + Err(error) => match error.kind() { + // If the file does not exist we return an empty struct + ErrorKind::NotFound => { + if create { + ApiZones::default() + } else { + return Err(error); + } + } + // Any other error is fatal + _ => return Err(error), + }, + }; + Ok(cxx::UniquePtr::new(zones)) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_read_zones(path: &str) -> Result, std::io::Error> { + let _lock = LOCK.lock().unwrap(); + api_read_zones_locked(path, false) +} + +// Assume we hold the lock +fn api_write_zones(path: &str, zones: &ApiZones) -> Result<(), std::io::Error> { + let mut tmpfile = path.to_owned(); + tmpfile.push_str(".tmp"); + + let file = File::create(tmpfile.as_str())?; + let mut buffered_writer = BufWriter::new(&file); + if let Err(error) = serde_yaml::to_writer(&mut buffered_writer, &zones) { + return Err(std::io::Error::other(error.to_string())); + } + buffered_writer.flush()?; + file.sync_all()?; + drop(buffered_writer); + std::fs::rename(tmpfile.as_str(), path) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_add_auth_zone(path: &str, authzone: AuthZone) -> Result<(), std::io::Error> { + let _lock = LOCK.lock().unwrap(); + let mut zones = api_read_zones_locked(path, true)?; + zones.auth_zones.push(authzone); + api_write_zones(path, &zones) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_add_forward_zone(path: &str, forwardzone: ForwardZone) -> Result<(), std::io::Error> { + let _lock = LOCK.lock().unwrap(); + let mut zones = api_read_zones_locked(path, true)?; + zones.forward_zones.push(forwardzone); + api_write_zones(path, &zones) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_add_forward_zones( + path: &str, + forwardzones: &mut Vec, +) -> Result<(), std::io::Error> { + let _lock = LOCK.lock().unwrap(); + let mut zones = api_read_zones_locked(path, true)?; + zones.forward_zones.append(forwardzones); + api_write_zones(path, &zones) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_delete_zone(path: &str, zone: &str) -> Result<(), std::io::Error> { + let _lock = LOCK.lock().unwrap(); + let mut zones = api_read_zones_locked(path, true)?; + zones.auth_zones.retain(|x| x.zone != zone); + // Zone data file is unlinked in the C++ caller ws-recursor.cc:doDeleteZone() + zones.forward_zones.retain(|x| x.zone != zone); + api_write_zones(path, &zones) +} + +// This function is called from C++, it needs to acquire the lock +pub fn api_delete_zones(path: &str) -> Result<(), std::io::Error> { + let _lock = LOCK.lock().unwrap(); + let mut zones = api_read_zones_locked(path, true)?; + zones.forward_zones.clear(); + api_write_zones(path, &zones) +} + +pub fn def_pb_export_qtypes() -> Vec { + vec![ + String::from("A"), + String::from("CNAME"), + String::from("AAAA"), + ] +} + +pub fn default_value_equal_pb_export_qtypes(value: &Vec) -> bool { + &def_pb_export_qtypes() == value +} + +pub fn def_ztc_validate() -> String { + String::from("validate") +} + +pub fn def_value_equals_ztc_validate(value: &String) -> bool { + &def_ztc_validate() == value +} + +pub fn def_additional_mode() -> String { + String::from("CacheOnlyRequireAuth") +} + +pub fn default_value_equals_additional_mode(value: &String) -> bool { + &def_additional_mode() == value +} + +pub fn validate_dnssec(dnssec: &recsettings::Dnssec) -> Result<(), ValidationError> { + let val = dnssec.validation.as_str(); + match val { + "off" | "process-no-validate" | "process" | "log-fail" | "validate" => {} + _ => { + let msg = format!("dnssec.validation: value `{}' is unknown", val); + return Err(ValidationError { msg }); + } + }; + Ok(()) +} + +pub fn validate_incoming(_incoming: &recsettings::Incoming) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_recursor(_recursor: &recsettings::Recursor) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_webservice(_webservice: &recsettings::Webservice) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_carbon(_carbon: &recsettings::Carbon) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_outgoing(_outgoing: &recsettings::Outgoing) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_packetcache( + _packetcache: &recsettings::Packetcache, +) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_logging(logging: &recsettings::Logging) -> Result<(), ValidationError> { + if logging.protobuf_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of protobuf_servers must be <= 1"), + }); + } + if logging.outgoing_protobuf_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of outgoing_protobuf_servers must be <= 1"), + }); + } + if logging.dnstap_framestream_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of dnstap_framestream_servers must be <= 1"), + }); + } + if logging.dnstap_nod_framestream_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of dnstap_nod_framestream_servers must be <= 1"), + }); + } + Ok(()) +} + +pub fn validate_ecs(_ecs: &recsettings::Ecs) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_nod(_nod: &recsettings::Nod) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_recordcache( + _recordcache: &recsettings::Recordcache, +) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_snmp(_snmp: &recsettings::Snmp) -> Result<(), ValidationError> { + Ok(()) +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/helpers.rs pdns-recursor-5.4.9/rec-rust-lib/rust/src/helpers.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/helpers.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/helpers.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,82 @@ +/* + * 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. + */ + +use crate::ValidationError; +use std::{error::Error, fmt}; + +/* Helper code for validation */ +impl Error for ValidationError {} +impl fmt::Display for ValidationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg) + } +} + +// Generic helpers + +// A helper to define a function returning a constant value and an equal function as a Rust path */ +pub struct U64; +impl U64 { + pub const fn value() -> u64 { + U + } + pub fn is_equal(v: &u64) -> bool { + v == &U + } +} + +pub struct U32; +impl U32 { + pub const fn value() -> u32 { + U + } + pub fn is_equal(v: &u32) -> bool { + v == &U + } +} + +// A helper to define constant value as a Rust path */ +pub struct Bool; +impl Bool { + pub const fn value() -> bool { + U + } +} + +// A helper used to decide if a bool value should be skipped +pub fn if_true(v: &bool) -> bool { + *v +} + +/* Helper to decide if a value has a default value, as defined by Default trait */ +pub fn is_default(t: &T) -> bool { + t == &T::default() +} + +pub const OVERRIDE_TAG: &str = "!override"; + +pub fn is_overriding(m: &serde_yaml::Mapping, key: &str) -> bool { + if let Some(serde_yaml::Value::Tagged(vvv)) = m.get(key) { + return vvv.tag == OVERRIDE_TAG; + } + false +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/lib.rs pdns-recursor-5.4.9/rec-rust-lib/rust/src/lib.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/lib.rs 2026-10-26 09:47:09.000000000 +0000 @@ -0,0 +1,3921 @@ +// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir +// START INCLUDE rust-preamble-in.rs +/* + * 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. + */ + +// This file (rust-preamble-in.rs) is included at the start of lib.rs + +// rustc complains serde Serialize/Deserialize are not used on toplevel, while they *are* used plenty +// in mod recsettings. Disable the warning for the line below only. +#[allow(unused_imports)] +use serde::{Deserialize, Serialize}; + +mod helpers; +use helpers::*; + +mod bridge; +use bridge::*; + +mod misc; + +mod web; // leaving this out causes link issues + +trait Validate { + fn validate(&self) -> Result<(), ValidationError>; +} + +#[derive(Debug)] +pub struct ValidationError { + msg: String, +} + +trait Merge { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>); +} +// END INCLUDE rust-preamble-in.rs + +#[cxx::bridge(namespace = "pdns::rust::settings::rec")] +mod recsettings { + // START INCLUDE rust-bridge-in.rs + // This file (rust-bridge-in.rs) is included into lib.rs inside the bridge module + /* + * Implement non-generated structs that need to be handled by Serde and CXX + */ + + // A single forward zone + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ForwardZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + forwarders: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + recurse: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, + } + + // A single auth zone + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct AuthZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + file: String, + } + + // A single trust anchor + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct TrustAnchor { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + dsrecords: Vec, + } + + // A single negative trust anchor + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct NegativeTrustAnchor { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + reason: String, + } + + // A protobuf logging server + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ProtobufServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + timeout: u64, + #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal", alias = "max_queued_entries")] + maxQueuedEntries: u64, + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal", alias = "reconnect_wait_time")] + reconnectWaitTime: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "tagged_only")] + taggedOnly: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "async_connect")] + asyncConnect: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_queries")] + logQueries: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_responses")] + logResponses: bool, + #[serde(default = "crate::def_pb_export_qtypes", skip_serializing_if = "crate::default_value_equal_pb_export_qtypes", alias = "export_types")] + exportTypes: Vec, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "log_mapped_from")] + logMappedFrom: bool, + } + + // A dnstap logging server + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct DNSTapFrameStreamServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_queries")] + logQueries: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_responses")] + logResponses: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "buffer_hint")] + bufferHint: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "flush_timeout")] + flushTimeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "input_queue_size")] + inputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "output_queue_size")] + outputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "queue_notify_threshold")] + queueNotifyThreshold: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "reopen_interval")] + reopenInterval: u64, + } + + // A dnstap logging NOD server + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct DNSTapNODFrameStreamServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_nods")] + logNODs: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "log_udrs")] + logUDRs: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "buffer_hint")] + bufferHint: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "flush_timeout")] + flushTimeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "input_queue_size")] + inputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "output_queue_size")] + outputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "queue_notify_threshold")] + queueNotifyThreshold: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "reopen_interval")] + reopenInterval: u64, + } + + #[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct TSIGTriplet { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + algo: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + secret: String, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct RPZ { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + defcontent: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + defpol: String, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "defpol_override_local_data")] + defpolOverrideLocalData: bool, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] + defttl: u32, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal", alias = "extended_error_code")] + extendedErrorCode: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "extended_error_extra")] + extendedErrorExtra: String, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "include_soa")] + includeSOA: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "ignore_duplicates")] + ignoreDuplicates: bool, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal", alias = "max_ttl")] + maxTTL: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "policy_name")] + policyName: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + tags: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "overrides_gettag")] + overridesGettag: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "zone_size_hint")] + zoneSizeHint: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default, skip_serializing_if = "crate::is_default")] + refresh: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal", alias = "axfr_timeout")] + axfrTimeout: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "dump_file")] + dumpFile: String, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "seed_file")] + seedFile: String, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ZoneToCache { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + method: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + sources: Vec, + #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] + timeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal", alias = "refresh_period")] + refreshPeriod: u64, + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal", alias = "retry_on_error_period")] + retryOnErrorPeriod: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] + zonemd: String, + #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] + dnssec: String, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct SubnetOrder { + #[serde(default, skip_serializing_if = "crate::is_default")] + subnet: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + order: u32, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct SortList { + #[serde(default, skip_serializing_if = "crate::is_default")] + key: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + subnets: Vec, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct AllowedAdditionalQType { + #[serde(default, skip_serializing_if = "crate::is_default")] + qtype: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + targets: Vec, + #[serde(default = "crate::def_additional_mode", skip_serializing_if = "crate::default_value_equals_additional_mode")] + mode: String, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ProxyMapping { + #[serde(default, skip_serializing_if = "crate::is_default")] + subnet: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + address: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + domains: Vec, + } + + // A struct holding both a vector of forward zones and a vector of auth zones, used by REST API code + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ApiZones { + #[serde(default, skip_serializing_if = "crate::is_default")] + auth_zones: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + forward_zones: Vec, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct XFR { + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "zone_size_hint")] + zoneSizeHint: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default, skip_serializing_if = "crate::is_default")] + refresh: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal", alias = "axfr_timeout")] + axfrTimeout: u32, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct FCZDefault { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + forwarders: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + recurse: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct ForwardingCatalogZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + xfr: XFR, + #[serde(default, skip_serializing_if = "crate::is_default")] + groups: Vec, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct IncomingTLS { + #[serde(default, skip_serializing_if = "crate::is_default")] + certificate: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + key: String, + // #[serde(default, skip_serializing_if = "crate::is_default")] + // password: String, Not currently supported, as rusttls does not support this out of the box + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct IncomingWSConfig { + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + tls: IncomingTLS, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + struct OutgoingTLSConfiguration { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + provider: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + suffixes: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + subnets: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + validate_certificate: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + ca_store: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + verbose_logging: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + subject_name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + subject_address: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + ciphers: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + ciphers_tls_13: String, + } + + #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + struct OpenTelemetryTraceCondition { + #[serde(default, skip_serializing_if = "crate::is_default")] + acls: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + qnames: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + qtypes: Vec, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] + qid: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + edns_option_required: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + traceid_only: bool, + } + + // Two structs used to generated YAML based on a vector of name to value mappings + // Cannot use Enum as CXX has only very basic Enum support + struct Value { + bool_val: bool, + u64_val: u64, + f64_val: f64, + string_val: String, + vec_string_val: Vec, + vec_forwardzone_val: Vec, + vec_authzone_val: Vec, + vec_trustanchor_val: Vec, + vec_negativetrustanchor_val: Vec, + vec_protobufserver_val: Vec, + vec_dnstap_framestream_server_val: Vec, + vec_dnstap_nod_framestream_server_val: Vec, + vec_rpz_val: Vec, + vec_sortlist_val: Vec, + vec_zonetocache_val: Vec, + vec_allowedadditionalqtype_val: Vec, + vec_proxymapping_val: Vec, + vec_forwardingcatalogzone_val: Vec, + vec_incomingwsconfig_val: Vec, + vec_outgoingtlsconfiguration_val: Vec, + } + + struct OldStyle { + section: String, + name: String, + old_name: String, + type_name: String, + value: Value, + overriding: bool, + } + + /* + * Functions callable from C++ + */ + extern "Rust" { + // Parse a string representing YAML text and produce the corresponding data structure known to Serde + // The settings that can be stored in individual files get their own parse function + // Main recursor settings + fn parse_yaml_string(str: &str) -> Result; + // Allow from sequence + fn parse_yaml_string_to_allow_from(str: &str) -> Result>; + // Forward zones sequence + fn parse_yaml_string_to_forward_zones(str: &str) -> Result>; + // Allow notify for sequence + fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result>; + // REST API zones + fn parse_yaml_string_to_api_zones(str: &str) -> Result; + + // Produce a YAML formatted string given a data structure known to Serde + fn to_yaml_string(self: &Recursorsettings) -> Result; + fn get_value(self: &Recursorsettings, field: &[String], defaults: &str, with_comment: bool) -> Result; + // When doing a conversion of old-style to YAML style we use a vector of OldStyle structs + fn map_to_yaml_string(map: &Vec) -> Result; + fn forward_zones_to_yaml_string(vec: &Vec) -> Result; + fn allow_from_to_yaml_string(vec: &Vec) -> Result; + fn allow_from_to_yaml_string_incoming(key: &String, filekey: &String, vec: &Vec) -> Result; + fn allow_for_to_yaml_string(vec: &Vec) -> Result; + + // Merge a string representing YAML settings into an existing settings struct + fn merge(lhs: &mut Recursorsettings, rhs: &str) -> Result<()>; + + // Validate the sections inside the main settings struct, sections themselves will validate their fields + fn validate(self: &Recursorsettings) -> Result<()>; + // The validate function below are "hand-crafted" as their structs are not generated + fn validate(self: &AuthZone, field: &str) -> Result<()>; + fn validate(self: &ForwardZone, field: &str) -> Result<()>; + fn validate(self: &TrustAnchor, field: &str) -> Result<()>; + fn validate(self: &NegativeTrustAnchor, field: &str) -> Result<()>; + fn validate(self: &ApiZones, field: &str) -> Result<()>; + + // Helper functions to call the proper validate function on vectors of various kinds + fn validate_auth_zones(field: &str, vec: &Vec) -> Result<()>; + fn validate_forward_zones(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_for(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_from(field: &str, vec: &Vec) -> Result<()>; + + // The functions to maintain REST API managed zones + fn api_read_zones(path: &str) -> Result>; + fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>; + fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>; + fn api_add_forward_zones(file: &str, forwardzones: &mut Vec) -> Result<()>; + fn validate_trustanchors(field: &str, vec: &Vec) -> Result<()>; + fn validate_negativetrustanchors(field: &str, vec: &Vec) -> Result<()>; + fn api_delete_zone(file: &str, zone: &str) -> Result<()>; + fn api_delete_zones(file: &str) -> Result<()>; + } + + // END INCLUDE rust-bridge-in.rs + + // SECTION Dnssec + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Dnssec { + #[serde(default = "crate::U64::<100000>::value", skip_serializing_if = "crate::U64::<100000>::is_equal")] + aggressive_nsec_cache_size: u64, + + #[serde(default = "crate::U64::<2000>::value", skip_serializing_if = "crate::U64::<2000>::is_equal")] + aggressive_cache_min_nsec3_hit_ratio: u64, + + #[serde(default = "crate::default_value_dnssec_validation", skip_serializing_if = "crate::default_value_equal_dnssec_validation")] + validation: String, + + #[serde(default = "crate::default_value_dnssec_disabled_algorithms", skip_serializing_if = "crate::default_value_equal_dnssec_disabled_algorithms")] + disabled_algorithms: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + log_bogus: bool, + + #[serde(default = "crate::U64::<50>::value", skip_serializing_if = "crate::U64::<50>::is_equal")] + nsec3_max_iterations: u64, + + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + max_rrsigs_per_record: u64, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + max_nsec3s_per_record: u64, + + #[serde(default = "crate::U64::<30>::value", skip_serializing_if = "crate::U64::<30>::is_equal")] + max_signature_validations_per_query: u64, + + #[serde(default = "crate::U64::<600>::value", skip_serializing_if = "crate::U64::<600>::is_equal")] + max_nsec3_hash_computations_per_query: u64, + + #[serde(default = "crate::U64::<150>::value", skip_serializing_if = "crate::U64::<150>::is_equal")] + aggressive_cache_max_nsec3_hash_cost: u64, + + #[serde(default = "crate::U64::<8>::value", skip_serializing_if = "crate::U64::<8>::is_equal")] + max_ds_per_zone: u64, + + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + max_dnskeys: u64, + + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] + signature_inception_skew: u64, + + #[serde(default = "crate::default_value_dnssec_x_dnssec_names", skip_serializing_if = "crate::default_value_equal_dnssec_x_dnssec_names")] + x_dnssec_names: Vec, + + #[serde(default = "crate::default_value_dnssec_trustanchors", skip_serializing_if = "crate::default_value_equal_dnssec_trustanchors")] + trustanchors: Vec, + + #[serde(default = "crate::default_value_dnssec_negative_trustanchors", skip_serializing_if = "crate::default_value_equal_dnssec_negative_trustanchors")] + negative_trustanchors: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + trustanchorfile: String, + + #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] + trustanchorfile_interval: u64, + + } + // END SECTION Dnssec + + // SECTION Incoming + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Incoming { + #[serde(default = "crate::default_value_incoming_allow_from", skip_serializing_if = "crate::default_value_equal_incoming_allow_from")] + allow_from: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + allow_from_file: String, + + #[serde(default = "crate::default_value_incoming_allow_notify_for", skip_serializing_if = "crate::default_value_equal_incoming_allow_notify_for")] + allow_notify_for: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + allow_notify_for_file: String, + + #[serde(default = "crate::default_value_incoming_allow_notify_from", skip_serializing_if = "crate::default_value_equal_incoming_allow_notify_from")] + allow_notify_from: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + allow_notify_from_file: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + allow_no_rd: bool, + + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + tcp_timeout: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + distribution_load_factor: f64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + distribution_pipe_buffer_size: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + distributor_threads: u64, + + #[serde(default = "crate::default_value_incoming_edns_padding_from", skip_serializing_if = "crate::default_value_equal_incoming_edns_padding_from")] + edns_padding_from: Vec, + + #[serde(default = "crate::default_value_incoming_edns_padding_mode", skip_serializing_if = "crate::default_value_equal_incoming_edns_padding_mode")] + edns_padding_mode: String, + + #[serde(default = "crate::U64::<7830>::value", skip_serializing_if = "crate::U64::<7830>::is_equal")] + edns_padding_tag: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + gettag_needs_edns_options: bool, + + #[serde(default = "crate::default_value_incoming_listen", skip_serializing_if = "crate::default_value_equal_incoming_listen")] + listen: Vec, + + #[serde(default = "crate::U64::<53>::value", skip_serializing_if = "crate::U64::<53>::is_equal")] + port: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + non_local_bind: bool, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + max_concurrent_requests_per_tcp_connection: u64, + + #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] + max_tcp_clients: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + max_tcp_per_client: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + max_tcp_queries_per_connection: u64, + + #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] + max_udp_queries_per_round: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + pdns_distributes_queries: bool, + + #[serde(default = "crate::default_value_incoming_proxy_protocol_from", skip_serializing_if = "crate::default_value_equal_incoming_proxy_protocol_from")] + proxy_protocol_from: Vec, + + #[serde(default = "crate::default_value_incoming_proxy_protocol_exceptions", skip_serializing_if = "crate::default_value_equal_incoming_proxy_protocol_exceptions")] + proxy_protocol_exceptions: Vec, + + #[serde(default = "crate::U64::<512>::value", skip_serializing_if = "crate::U64::<512>::is_equal")] + proxy_protocol_maximum_size: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + reuseport: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + tcp_fast_open: u64, + + #[serde(default = "crate::U64::<1232>::value", skip_serializing_if = "crate::U64::<1232>::is_equal")] + udp_truncation_threshold: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + use_incoming_edns_subnet: bool, + + #[serde(default = "crate::default_value_incoming_proxymappings", skip_serializing_if = "crate::default_value_equal_incoming_proxymappings")] + proxymappings: Vec, + + } + // END SECTION Incoming + + // SECTION Recursor + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Recursor { + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + any_to_tcp: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + allow_trust_anchor_query: bool, + + #[serde(default = "crate::default_value_recursor_auth_zones", skip_serializing_if = "crate::default_value_equal_recursor_auth_zones")] + auth_zones: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + chroot: String, + + #[serde(default = "crate::default_value_recursor_config_dir", skip_serializing_if = "crate::default_value_equal_recursor_config_dir")] + config_dir: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + config_name: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + cpu_map: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + daemon: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + devonly_regression_test_mode: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + dns64_prefix: String, + + #[serde(default = "crate::default_value_recursor_etc_hosts_file", skip_serializing_if = "crate::default_value_equal_recursor_etc_hosts_file")] + etc_hosts_file: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + event_trace_enabled: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + export_etc_hosts: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + export_etc_hosts_search_suffix: String, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + extended_resolution_errors: bool, + + #[serde(default = "crate::default_value_recursor_forward_zones", skip_serializing_if = "crate::default_value_equal_recursor_forward_zones")] + forward_zones: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + forward_zones_file: String, + + #[serde(default = "crate::default_value_recursor_forward_zones_recurse", skip_serializing_if = "crate::default_value_equal_recursor_forward_zones_recurse")] + forward_zones_recurse: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + hint_file: String, + + #[serde(default = "crate::default_value_recursor_ignore_unknown_settings", skip_serializing_if = "crate::default_value_equal_recursor_ignore_unknown_settings")] + ignore_unknown_settings: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + include_dir: String, + + #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] + latency_statistic_size: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lua_config_file: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lua_global_include_dir: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lua_dns_script: String, + + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] + lua_maintenance_interval: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + max_chain_length: u64, + + #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] + max_include_depth: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + max_generate_steps: u64, + + #[serde(default = "crate::U64::<2048>::value", skip_serializing_if = "crate::U64::<2048>::is_equal")] + max_mthreads: u64, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + max_cnames_followed: u64, + + #[serde(default = "crate::U64::<16>::value", skip_serializing_if = "crate::U64::<16>::is_equal")] + max_recursion_depth: u64, + + #[serde(default = "crate::U64::<7000>::value", skip_serializing_if = "crate::U64::<7000>::is_equal")] + max_total_msec: u64, + + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] + minimum_ttl_override: u64, + + #[serde(default = "crate::default_value_recursor_nothing_below_nxdomain", skip_serializing_if = "crate::default_value_equal_recursor_nothing_below_nxdomain")] + nothing_below_nxdomain: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + public_suffix_list_file: String, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + qname_minimization: bool, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + qname_max_minimize_count: u64, + + #[serde(default = "crate::U64::<4>::value", skip_serializing_if = "crate::U64::<4>::is_equal")] + qname_minimize_one_label: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + root_nx_trust: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + save_parent_ns_set: bool, + + #[serde(default = "crate::default_value_recursor_security_poll_suffix", skip_serializing_if = "crate::default_value_equal_recursor_security_poll_suffix")] + security_poll_suffix: String, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + serve_rfc1918: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + serve_rfc6303: bool, + + #[serde(default = "crate::default_value_recursor_server_id", skip_serializing_if = "crate::default_value_equal_recursor_server_id")] + server_id: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + setgid: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + setuid: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + socket_dir: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + socket_group: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + socket_mode: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + socket_owner: String, + + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] + spoof_nearmiss_max: u64, + + #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] + stack_cache_size: u64, + + #[serde(default = "crate::U64::<200000>::value", skip_serializing_if = "crate::U64::<200000>::is_equal")] + stack_size: u64, + + #[serde(default = "crate::default_value_recursor_stats_api_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_api_disabled_list")] + stats_api_disabled_list: Vec, + + #[serde(default = "crate::default_value_recursor_stats_carbon_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_carbon_disabled_list")] + stats_carbon_disabled_list: Vec, + + #[serde(default = "crate::default_value_recursor_stats_rec_control_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_rec_control_disabled_list")] + stats_rec_control_disabled_list: Vec, + + #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] + stats_ringbuffer_entries: u64, + + #[serde(default = "crate::default_value_recursor_stats_snmp_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_snmp_disabled_list")] + stats_snmp_disabled_list: Vec, + + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + threads: u64, + + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] + tcp_threads: u64, + + #[serde(default = "crate::default_value_recursor_version_string", skip_serializing_if = "crate::default_value_equal_recursor_version_string")] + version_string: String, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + write_pid: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + system_resolver_ttl: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + system_resolver_interval: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + system_resolver_self_resolve_check: bool, + + #[serde(default = "crate::default_value_recursor_sortlists", skip_serializing_if = "crate::default_value_equal_recursor_sortlists")] + sortlists: Vec, + + #[serde(default = "crate::default_value_recursor_rpzs", skip_serializing_if = "crate::default_value_equal_recursor_rpzs")] + rpzs: Vec, + + #[serde(default = "crate::default_value_recursor_allowed_additional_qtypes", skip_serializing_if = "crate::default_value_equal_recursor_allowed_additional_qtypes")] + allowed_additional_qtypes: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lua_start_stop_script: String, + + #[serde(default = "crate::default_value_recursor_forwarding_catalog_zones", skip_serializing_if = "crate::default_value_equal_recursor_forwarding_catalog_zones")] + forwarding_catalog_zones: Vec, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + max_pointers_per_name: u64, + + #[serde(default = "crate::U64::<4>::value", skip_serializing_if = "crate::U64::<4>::is_equal")] + max_pointers_per_packet_byte: u64, + + #[serde(default = "crate::U64::<4>::value", skip_serializing_if = "crate::U64::<4>::is_equal")] + max_pointers_to_pointers: u64, + + } + // END SECTION Recursor + + // SECTION Outgoing + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Outgoing { + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + any_to_tcp: bool, + + #[serde(default = "crate::default_value_outgoing_dont_throttle_names", skip_serializing_if = "crate::default_value_equal_outgoing_dont_throttle_names")] + dont_throttle_names: Vec, + + #[serde(default = "crate::default_value_outgoing_dont_throttle_netmasks", skip_serializing_if = "crate::default_value_equal_outgoing_dont_throttle_netmasks")] + dont_throttle_netmasks: Vec, + + #[serde(default = "crate::default_value_outgoing_dot_to_auth_names", skip_serializing_if = "crate::default_value_equal_outgoing_dot_to_auth_names")] + dot_to_auth_names: Vec, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + dot_to_port_853: bool, + + #[serde(default = "crate::default_value_outgoing_dont_query", skip_serializing_if = "crate::default_value_equal_outgoing_dont_query")] + dont_query: Vec, + + #[serde(default = "crate::U64::<1232>::value", skip_serializing_if = "crate::U64::<1232>::is_equal")] + edns_bufsize: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + edns_padding: bool, + + #[serde(default = "crate::default_value_outgoing_edns_subnet_allow_list", skip_serializing_if = "crate::default_value_equal_outgoing_edns_subnet_allow_list")] + edns_subnet_allow_list: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + edns_subnet_harden: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lowercase: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + max_busy_dot_probes: u64, + + #[serde(default = "crate::U64::<50>::value", skip_serializing_if = "crate::U64::<50>::is_equal")] + max_qperq: u64, + + #[serde(default = "crate::U64::<100000>::value", skip_serializing_if = "crate::U64::<100000>::is_equal")] + max_bytesperq: u64, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + max_ns_address_qperq: u64, + + #[serde(default = "crate::U64::<13>::value", skip_serializing_if = "crate::U64::<13>::is_equal")] + max_ns_per_resolve: u64, + + #[serde(default = "crate::U64::<1500>::value", skip_serializing_if = "crate::U64::<1500>::is_equal")] + network_timeout: u64, + + #[serde(default = "crate::U64::<5>::value", skip_serializing_if = "crate::U64::<5>::is_equal")] + non_resolving_ns_max_fails: u64, + + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] + non_resolving_ns_throttle_time: u64, + + #[serde(default = "crate::default_value_outgoing_source_address", skip_serializing_if = "crate::default_value_equal_outgoing_source_address")] + source_address: Vec, + + #[serde(default = "crate::U64::<64>::value", skip_serializing_if = "crate::U64::<64>::is_equal")] + server_down_max_fails: u64, + + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] + server_down_throttle_time: u64, + + #[serde(default = "crate::U64::<25>::value", skip_serializing_if = "crate::U64::<25>::is_equal")] + bypass_server_throttling_probability: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + single_socket: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + tcp_fast_open_connect: bool, + + #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] + tcp_max_idle_ms: u64, + + #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] + tcp_max_idle_per_auth: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + tcp_max_queries: u64, + + #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] + tcp_max_idle_per_thread: u64, + + #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] + udp_source_port_min: u64, + + #[serde(default = "crate::U64::<65535>::value", skip_serializing_if = "crate::U64::<65535>::is_equal")] + udp_source_port_max: u64, + + #[serde(default = "crate::default_value_outgoing_udp_source_port_avoid", skip_serializing_if = "crate::default_value_equal_outgoing_udp_source_port_avoid")] + udp_source_port_avoid: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + cookies: bool, + + #[serde(default = "crate::default_value_outgoing_cookies_unsupported", skip_serializing_if = "crate::default_value_equal_outgoing_cookies_unsupported")] + cookies_unsupported: Vec, + + #[serde(default = "crate::default_value_outgoing_tls_configurations", skip_serializing_if = "crate::default_value_equal_outgoing_tls_configurations")] + tls_configurations: Vec, + + } + // END SECTION Outgoing + + // SECTION Webservice + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Webservice { + #[serde(default, skip_serializing_if = "crate::is_default")] + api_dir: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + api_key: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + webserver: bool, + + #[serde(default = "crate::default_value_webservice_address", skip_serializing_if = "crate::default_value_equal_webservice_address")] + address: String, + + #[serde(default = "crate::default_value_webservice_listen", skip_serializing_if = "crate::default_value_equal_webservice_listen")] + listen: Vec, + + #[serde(default = "crate::default_value_webservice_allow_from", skip_serializing_if = "crate::default_value_equal_webservice_allow_from")] + allow_from: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + hash_plaintext_credentials: bool, + + #[serde(default = "crate::default_value_webservice_loglevel", skip_serializing_if = "crate::default_value_equal_webservice_loglevel")] + loglevel: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + password: String, + + #[serde(default = "crate::U64::<8082>::value", skip_serializing_if = "crate::U64::<8082>::is_equal")] + port: u64, + + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + max_request_size: u64, + + } + // END SECTION Webservice + + // SECTION Carbon + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Carbon { + #[serde(default = "crate::U64::<30>::value", skip_serializing_if = "crate::U64::<30>::is_equal")] + interval: u64, + + #[serde(default = "crate::default_value_carbon_ns", skip_serializing_if = "crate::default_value_equal_carbon_ns")] + ns: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + ourname: String, + + #[serde(default = "crate::default_value_carbon_instance", skip_serializing_if = "crate::default_value_equal_carbon_instance")] + instance: String, + + #[serde(default = "crate::default_value_carbon_server", skip_serializing_if = "crate::default_value_equal_carbon_server")] + server: Vec, + + } + // END SECTION Carbon + + // SECTION Packetcache + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Packetcache { + #[serde(default, skip_serializing_if = "crate::is_default")] + disable: bool, + + #[serde(default = "crate::U64::<500000>::value", skip_serializing_if = "crate::U64::<500000>::is_equal")] + max_entries: u64, + + #[serde(default = "crate::U64::<8192>::value", skip_serializing_if = "crate::U64::<8192>::is_equal")] + max_entry_size: u64, + + #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] + ttl: u64, + + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] + negative_ttl: u64, + + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] + servfail_ttl: u64, + + #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] + shards: u64, + + } + // END SECTION Packetcache + + // SECTION Logging + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Logging { + #[serde(default, skip_serializing_if = "crate::is_default")] + disable_syslog: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + timestamp: bool, + + #[serde(default = "crate::U64::<6>::value", skip_serializing_if = "crate::U64::<6>::is_equal")] + loglevel: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + common_errors: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + rpz_changes: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + facility: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + protobuf_use_kernel_timestamp: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + quiet: bool, + + #[serde(default = "crate::U64::<1800>::value", skip_serializing_if = "crate::U64::<1800>::is_equal")] + statistics_interval: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + structured_logging: bool, + + #[serde(default = "crate::default_value_logging_structured_logging_backend", skip_serializing_if = "crate::default_value_equal_logging_structured_logging_backend")] + structured_logging_backend: String, + + #[serde(default = "crate::default_value_logging_trace", skip_serializing_if = "crate::default_value_equal_logging_trace")] + trace: String, + + #[serde(default = "crate::default_value_logging_protobuf_servers", skip_serializing_if = "crate::default_value_equal_logging_protobuf_servers")] + protobuf_servers: Vec, + + #[serde(default = "crate::default_value_logging_outgoing_protobuf_servers", skip_serializing_if = "crate::default_value_equal_logging_outgoing_protobuf_servers")] + outgoing_protobuf_servers: Vec, + + #[serde(default = "crate::U64::<32>::value", skip_serializing_if = "crate::U64::<32>::is_equal")] + protobuf_mask_v4: u64, + + #[serde(default = "crate::U64::<128>::value", skip_serializing_if = "crate::U64::<128>::is_equal")] + protobuf_mask_v6: u64, + + #[serde(default = "crate::default_value_logging_dnstap_framestream_servers", skip_serializing_if = "crate::default_value_equal_logging_dnstap_framestream_servers")] + dnstap_framestream_servers: Vec, + + #[serde(default = "crate::default_value_logging_dnstap_nod_framestream_servers", skip_serializing_if = "crate::default_value_equal_logging_dnstap_nod_framestream_servers")] + dnstap_nod_framestream_servers: Vec, + + #[serde(default = "crate::default_value_logging_opentelemetry_trace_conditions", skip_serializing_if = "crate::default_value_equal_logging_opentelemetry_trace_conditions")] + opentelemetry_trace_conditions: Vec, + + } + // END SECTION Logging + + // SECTION Ecs + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Ecs { + #[serde(default = "crate::default_value_ecs_add_for", skip_serializing_if = "crate::default_value_equal_ecs_add_for")] + add_for: Vec, + + #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] + ipv4_bits: u64, + + #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] + ipv4_cache_bits: u64, + + #[serde(default = "crate::U64::<56>::value", skip_serializing_if = "crate::U64::<56>::is_equal")] + ipv6_bits: u64, + + #[serde(default = "crate::U64::<56>::value", skip_serializing_if = "crate::U64::<56>::is_equal")] + ipv6_cache_bits: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + ipv4_never_cache: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + ipv6_never_cache: bool, + + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] + minimum_ttl_override: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + cache_limit_ttl: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + scope_zero_address: String, + + } + // END SECTION Ecs + + // SECTION Recordcache + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Recordcache { + #[serde(default = "crate::U64::<3600>::value", skip_serializing_if = "crate::U64::<3600>::is_equal")] + max_cache_bogus_ttl: u64, + + #[serde(default = "crate::U64::<1000000>::value", skip_serializing_if = "crate::U64::<1000000>::is_equal")] + max_entries: u64, + + #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] + max_ttl: u64, + + #[serde(default = "crate::U64::<8192>::value", skip_serializing_if = "crate::U64::<8192>::is_equal")] + max_entry_size: u64, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + limit_qtype_any: bool, + + #[serde(default = "crate::U64::<256>::value", skip_serializing_if = "crate::U64::<256>::is_equal")] + max_rrset_size: u64, + + #[serde(default = "crate::U64::<3600>::value", skip_serializing_if = "crate::U64::<3600>::is_equal")] + max_negative_ttl: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + locked_ttl_perc: u64, + + #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] + shards: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + refresh_on_ttl_perc: u64, + + #[serde(default, skip_serializing_if = "crate::is_default")] + serve_stale_extensions: u64, + + #[serde(default = "crate::default_value_recordcache_zonetocaches", skip_serializing_if = "crate::default_value_equal_recordcache_zonetocaches")] + zonetocaches: Vec, + + } + // END SECTION Recordcache + + // SECTION Nod + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Nod { + #[serde(default, skip_serializing_if = "crate::is_default")] + tracking: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + log: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + lookup: String, + + #[serde(default = "crate::U64::<67108864>::value", skip_serializing_if = "crate::U64::<67108864>::is_equal")] + db_size: u64, + + #[serde(default = "crate::default_value_nod_history_dir", skip_serializing_if = "crate::default_value_equal_nod_history_dir")] + history_dir: String, + + #[serde(default = "crate::U64::<600>::value", skip_serializing_if = "crate::U64::<600>::is_equal")] + db_snapshot_interval: u64, + + #[serde(default = "crate::default_value_nod_ignore_list", skip_serializing_if = "crate::default_value_equal_nod_ignore_list")] + ignore_list: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + ignore_list_file: String, + + #[serde(default = "crate::default_value_nod_pb_tag", skip_serializing_if = "crate::default_value_equal_nod_pb_tag")] + pb_tag: String, + + #[serde(default, skip_serializing_if = "crate::is_default")] + unique_response_tracking: bool, + + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] + unique_response_log: bool, + + #[serde(default = "crate::U64::<67108864>::value", skip_serializing_if = "crate::U64::<67108864>::is_equal")] + unique_response_db_size: u64, + + #[serde(default = "crate::default_value_nod_unique_response_history_dir", skip_serializing_if = "crate::default_value_equal_nod_unique_response_history_dir")] + unique_response_history_dir: String, + + #[serde(default = "crate::default_value_nod_unique_response_pb_tag", skip_serializing_if = "crate::default_value_equal_nod_unique_response_pb_tag")] + unique_response_pb_tag: String, + + #[serde(default = "crate::default_value_nod_unique_response_ignore_list", skip_serializing_if = "crate::default_value_equal_nod_unique_response_ignore_list")] + unique_response_ignore_list: Vec, + + #[serde(default, skip_serializing_if = "crate::is_default")] + unique_response_ignore_list_file: String, + + } + // END SECTION Nod + + // SECTION Snmp + #[derive(Deserialize, Serialize, Debug, PartialEq)] + #[serde(deny_unknown_fields)] + pub struct Snmp { + #[serde(default, skip_serializing_if = "crate::is_default")] + agent: bool, + + #[serde(default, skip_serializing_if = "crate::is_default")] + daemon_socket: String, + + } + // END SECTION Snmp + + #[derive(Serialize, Deserialize, Debug)] + #[serde(deny_unknown_fields)] + pub struct Recursorsettings { + #[serde(default, skip_serializing_if = "crate::is_default")] + dnssec: Dnssec, + #[serde(default, skip_serializing_if = "crate::is_default")] + incoming: Incoming, + #[serde(default, skip_serializing_if = "crate::is_default")] + recursor: Recursor, + #[serde(default, skip_serializing_if = "crate::is_default")] + outgoing: Outgoing, + #[serde(default, skip_serializing_if = "crate::is_default")] + webservice: Webservice, + #[serde(default, skip_serializing_if = "crate::is_default")] + carbon: Carbon, + #[serde(default, skip_serializing_if = "crate::is_default")] + packetcache: Packetcache, + #[serde(default, skip_serializing_if = "crate::is_default")] + logging: Logging, + #[serde(default, skip_serializing_if = "crate::is_default")] + ecs: Ecs, + #[serde(default, skip_serializing_if = "crate::is_default")] + recordcache: Recordcache, + #[serde(default, skip_serializing_if = "crate::is_default")] + nod: Nod, + #[serde(default, skip_serializing_if = "crate::is_default")] + snmp: Snmp, +} // End of generated structs +} +impl Default for recsettings::Dnssec { + fn default() -> Self { + let deserialized: recsettings::Dnssec = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Incoming { + fn default() -> Self { + let deserialized: recsettings::Incoming = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Recursor { + fn default() -> Self { + let deserialized: recsettings::Recursor = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Outgoing { + fn default() -> Self { + let deserialized: recsettings::Outgoing = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Webservice { + fn default() -> Self { + let deserialized: recsettings::Webservice = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Carbon { + fn default() -> Self { + let deserialized: recsettings::Carbon = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Packetcache { + fn default() -> Self { + let deserialized: recsettings::Packetcache = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Logging { + fn default() -> Self { + let deserialized: recsettings::Logging = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Ecs { + fn default() -> Self { + let deserialized: recsettings::Ecs = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Recordcache { + fn default() -> Self { + let deserialized: recsettings::Recordcache = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Nod { + fn default() -> Self { + let deserialized: recsettings::Nod = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Snmp { + fn default() -> Self { + let deserialized: recsettings::Snmp = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Default for recsettings::Recursorsettings { + fn default() -> Self { + let deserialized: recsettings::Recursorsettings = serde_yaml::from_str("").unwrap(); + deserialized + } +} + +impl Validate for recsettings::Dnssec { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "dnssec.trustanchors".to_string(); + validate_vec(&fieldname, &self.trustanchors, |field, element| element.validate(field))?; + let fieldname = "dnssec.negative_trustanchors".to_string(); + validate_vec(&fieldname, &self.negative_trustanchors, |field, element| element.validate(field))?; + validate_dnssec(self) + } +} + +impl Validate for recsettings::Incoming { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "incoming.allow_from".to_string(); + validate_vec(&fieldname, &self.allow_from, validate_subnet)?; + let fieldname = "incoming.allow_notify_from".to_string(); + validate_vec(&fieldname, &self.allow_notify_from, validate_subnet)?; + let fieldname = "incoming.edns_padding_from".to_string(); + validate_vec(&fieldname, &self.edns_padding_from, validate_subnet)?; + let fieldname = "incoming.listen".to_string(); + validate_vec(&fieldname, &self.listen, validate_socket_address)?; + let fieldname = "incoming.proxy_protocol_from".to_string(); + validate_vec(&fieldname, &self.proxy_protocol_from, validate_subnet)?; + let fieldname = "incoming.proxy_protocol_exceptions".to_string(); + validate_vec(&fieldname, &self.proxy_protocol_exceptions, validate_socket_address)?; + let fieldname = "incoming.proxymappings".to_string(); + validate_vec(&fieldname, &self.proxymappings, |field, element| element.validate(field))?; + validate_incoming(self) + } +} + +impl Validate for recsettings::Recursor { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "recursor.auth_zones".to_string(); + validate_vec(&fieldname, &self.auth_zones, |field, element| element.validate(field))?; + let fieldname = "recursor.forward_zones".to_string(); + validate_vec(&fieldname, &self.forward_zones, |field, element| element.validate(field))?; + let fieldname = "recursor.forward_zones_recurse".to_string(); + validate_vec(&fieldname, &self.forward_zones_recurse, |field, element| element.validate(field))?; + let fieldname = "recursor.sortlists".to_string(); + validate_vec(&fieldname, &self.sortlists, |field, element| element.validate(field))?; + let fieldname = "recursor.rpzs".to_string(); + validate_vec(&fieldname, &self.rpzs, |field, element| element.validate(field))?; + let fieldname = "recursor.allowed_additional_qtypes".to_string(); + validate_vec(&fieldname, &self.allowed_additional_qtypes, |field, element| element.validate(field))?; + let fieldname = "recursor.forwarding_catalog_zones".to_string(); + validate_vec(&fieldname, &self.forwarding_catalog_zones, |field, element| element.validate(field))?; + validate_recursor(self) + } +} + +impl Validate for recsettings::Outgoing { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "outgoing.dont_throttle_netmasks".to_string(); + validate_vec(&fieldname, &self.dont_throttle_netmasks, validate_subnet)?; + let fieldname = "outgoing.dont_query".to_string(); + validate_vec(&fieldname, &self.dont_query, validate_subnet)?; + let fieldname = "outgoing.source_address".to_string(); + validate_vec(&fieldname, &self.source_address, validate_subnet)?; + let fieldname = "outgoing.cookies_unsupported".to_string(); + validate_vec(&fieldname, &self.cookies_unsupported, validate_socket_address)?; + let fieldname = "outgoing.tls_configurations".to_string(); + validate_vec(&fieldname, &self.tls_configurations, |field, element| element.validate(field))?; + validate_outgoing(self) + } +} + +impl Validate for recsettings::Webservice { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "webservice.listen".to_string(); + validate_vec(&fieldname, &self.listen, |field, element| element.validate(field))?; + let fieldname = "webservice.allow_from".to_string(); + validate_vec(&fieldname, &self.allow_from, validate_subnet)?; + validate_webservice(self) + } +} + +impl Validate for recsettings::Carbon { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "carbon.server".to_string(); + validate_vec(&fieldname, &self.server, validate_socket_address)?; + validate_carbon(self) + } +} + +impl Validate for recsettings::Packetcache { + fn validate(&self) -> Result<(), ValidationError> { + validate_packetcache(self) + } +} + +impl Validate for recsettings::Logging { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "logging.protobuf_servers".to_string(); + validate_vec(&fieldname, &self.protobuf_servers, |field, element| element.validate(field))?; + let fieldname = "logging.outgoing_protobuf_servers".to_string(); + validate_vec(&fieldname, &self.outgoing_protobuf_servers, |field, element| element.validate(field))?; + let fieldname = "logging.dnstap_framestream_servers".to_string(); + validate_vec(&fieldname, &self.dnstap_framestream_servers, |field, element| element.validate(field))?; + let fieldname = "logging.dnstap_nod_framestream_servers".to_string(); + validate_vec(&fieldname, &self.dnstap_nod_framestream_servers, |field, element| element.validate(field))?; + let fieldname = "logging.opentelemetry_trace_conditions".to_string(); + validate_vec(&fieldname, &self.opentelemetry_trace_conditions, |field, element| element.validate(field))?; + validate_logging(self) + } +} + +impl Validate for recsettings::Ecs { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "ecs.add_for".to_string(); + validate_vec(&fieldname, &self.add_for, validate_subnet)?; + validate_ecs(self) + } +} + +impl Validate for recsettings::Recordcache { + fn validate(&self) -> Result<(), ValidationError> { + let fieldname = "recordcache.zonetocaches".to_string(); + validate_vec(&fieldname, &self.zonetocaches, |field, element| element.validate(field))?; + validate_recordcache(self) + } +} + +impl Validate for recsettings::Nod { + fn validate(&self) -> Result<(), ValidationError> { + validate_nod(self) + } +} + +impl Validate for recsettings::Snmp { + fn validate(&self) -> Result<(), ValidationError> { + validate_snmp(self) + } +} + +impl crate::recsettings::Recursorsettings { + fn validate(&self) -> Result<(), ValidationError> { + self.dnssec.validate()?; + self.incoming.validate()?; + self.recursor.validate()?; + self.outgoing.validate()?; + self.webservice.validate()?; + self.carbon.validate()?; + self.packetcache.validate()?; + self.logging.validate()?; + self.ecs.validate()?; + self.recordcache.validate()?; + self.nod.validate()?; + self.snmp.validate()?; + Ok(()) + } +} + +impl Merge for recsettings::Dnssec { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("aggressive_nsec_cache_size") { + rhs.aggressive_nsec_cache_size.clone_into(&mut self.aggressive_nsec_cache_size); + } + if m.contains_key("aggressive_cache_min_nsec3_hit_ratio") { + rhs.aggressive_cache_min_nsec3_hit_ratio.clone_into(&mut self.aggressive_cache_min_nsec3_hit_ratio); + } + if m.contains_key("validation") { + rhs.validation.clone_into(&mut self.validation); + } + if m.contains_key("disabled_algorithms") { + if is_overriding(m, "disabled_algorithms") || self.disabled_algorithms == DEFAULT_CONFIG.dnssec.disabled_algorithms { + self.disabled_algorithms.clear(); + } + merge_vec(&mut self.disabled_algorithms, &mut rhs.disabled_algorithms); + } + if m.contains_key("log_bogus") { + rhs.log_bogus.clone_into(&mut self.log_bogus); + } + if m.contains_key("nsec3_max_iterations") { + rhs.nsec3_max_iterations.clone_into(&mut self.nsec3_max_iterations); + } + if m.contains_key("max_rrsigs_per_record") { + rhs.max_rrsigs_per_record.clone_into(&mut self.max_rrsigs_per_record); + } + if m.contains_key("max_nsec3s_per_record") { + rhs.max_nsec3s_per_record.clone_into(&mut self.max_nsec3s_per_record); + } + if m.contains_key("max_signature_validations_per_query") { + rhs.max_signature_validations_per_query.clone_into(&mut self.max_signature_validations_per_query); + } + if m.contains_key("max_nsec3_hash_computations_per_query") { + rhs.max_nsec3_hash_computations_per_query.clone_into(&mut self.max_nsec3_hash_computations_per_query); + } + if m.contains_key("aggressive_cache_max_nsec3_hash_cost") { + rhs.aggressive_cache_max_nsec3_hash_cost.clone_into(&mut self.aggressive_cache_max_nsec3_hash_cost); + } + if m.contains_key("max_ds_per_zone") { + rhs.max_ds_per_zone.clone_into(&mut self.max_ds_per_zone); + } + if m.contains_key("max_dnskeys") { + rhs.max_dnskeys.clone_into(&mut self.max_dnskeys); + } + if m.contains_key("signature_inception_skew") { + rhs.signature_inception_skew.clone_into(&mut self.signature_inception_skew); + } + if m.contains_key("x_dnssec_names") { + if is_overriding(m, "x_dnssec_names") || self.x_dnssec_names == DEFAULT_CONFIG.dnssec.x_dnssec_names { + self.x_dnssec_names.clear(); + } + merge_vec(&mut self.x_dnssec_names, &mut rhs.x_dnssec_names); + } + if m.contains_key("trustanchors") { + if is_overriding(m, "trustanchors") || self.trustanchors == DEFAULT_CONFIG.dnssec.trustanchors { + self.trustanchors.clear(); + } + merge_vec(&mut self.trustanchors, &mut rhs.trustanchors); + } + if m.contains_key("negative_trustanchors") { + if is_overriding(m, "negative_trustanchors") || self.negative_trustanchors == DEFAULT_CONFIG.dnssec.negative_trustanchors { + self.negative_trustanchors.clear(); + } + merge_vec(&mut self.negative_trustanchors, &mut rhs.negative_trustanchors); + } + if m.contains_key("trustanchorfile") { + rhs.trustanchorfile.clone_into(&mut self.trustanchorfile); + } + if m.contains_key("trustanchorfile_interval") { + rhs.trustanchorfile_interval.clone_into(&mut self.trustanchorfile_interval); + } + } + } +} + +impl Merge for recsettings::Incoming { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("allow_from") { + if is_overriding(m, "allow_from") || self.allow_from == DEFAULT_CONFIG.incoming.allow_from { + self.allow_from.clear(); + } + merge_vec(&mut self.allow_from, &mut rhs.allow_from); + } + if m.contains_key("allow_from_file") { + rhs.allow_from_file.clone_into(&mut self.allow_from_file); + } + if m.contains_key("allow_notify_for") { + if is_overriding(m, "allow_notify_for") || self.allow_notify_for == DEFAULT_CONFIG.incoming.allow_notify_for { + self.allow_notify_for.clear(); + } + merge_vec(&mut self.allow_notify_for, &mut rhs.allow_notify_for); + } + if m.contains_key("allow_notify_for_file") { + rhs.allow_notify_for_file.clone_into(&mut self.allow_notify_for_file); + } + if m.contains_key("allow_notify_from") { + if is_overriding(m, "allow_notify_from") || self.allow_notify_from == DEFAULT_CONFIG.incoming.allow_notify_from { + self.allow_notify_from.clear(); + } + merge_vec(&mut self.allow_notify_from, &mut rhs.allow_notify_from); + } + if m.contains_key("allow_notify_from_file") { + rhs.allow_notify_from_file.clone_into(&mut self.allow_notify_from_file); + } + if m.contains_key("allow_no_rd") { + rhs.allow_no_rd.clone_into(&mut self.allow_no_rd); + } + if m.contains_key("tcp_timeout") { + rhs.tcp_timeout.clone_into(&mut self.tcp_timeout); + } + if m.contains_key("distribution_load_factor") { + rhs.distribution_load_factor.clone_into(&mut self.distribution_load_factor); + } + if m.contains_key("distribution_pipe_buffer_size") { + rhs.distribution_pipe_buffer_size.clone_into(&mut self.distribution_pipe_buffer_size); + } + if m.contains_key("distributor_threads") { + rhs.distributor_threads.clone_into(&mut self.distributor_threads); + } + if m.contains_key("edns_padding_from") { + if is_overriding(m, "edns_padding_from") || self.edns_padding_from == DEFAULT_CONFIG.incoming.edns_padding_from { + self.edns_padding_from.clear(); + } + merge_vec(&mut self.edns_padding_from, &mut rhs.edns_padding_from); + } + if m.contains_key("edns_padding_mode") { + rhs.edns_padding_mode.clone_into(&mut self.edns_padding_mode); + } + if m.contains_key("edns_padding_tag") { + rhs.edns_padding_tag.clone_into(&mut self.edns_padding_tag); + } + if m.contains_key("gettag_needs_edns_options") { + rhs.gettag_needs_edns_options.clone_into(&mut self.gettag_needs_edns_options); + } + if m.contains_key("listen") { + if is_overriding(m, "listen") || self.listen == DEFAULT_CONFIG.incoming.listen { + self.listen.clear(); + } + merge_vec(&mut self.listen, &mut rhs.listen); + } + if m.contains_key("port") { + rhs.port.clone_into(&mut self.port); + } + if m.contains_key("non_local_bind") { + rhs.non_local_bind.clone_into(&mut self.non_local_bind); + } + if m.contains_key("max_concurrent_requests_per_tcp_connection") { + rhs.max_concurrent_requests_per_tcp_connection.clone_into(&mut self.max_concurrent_requests_per_tcp_connection); + } + if m.contains_key("max_tcp_clients") { + rhs.max_tcp_clients.clone_into(&mut self.max_tcp_clients); + } + if m.contains_key("max_tcp_per_client") { + rhs.max_tcp_per_client.clone_into(&mut self.max_tcp_per_client); + } + if m.contains_key("max_tcp_queries_per_connection") { + rhs.max_tcp_queries_per_connection.clone_into(&mut self.max_tcp_queries_per_connection); + } + if m.contains_key("max_udp_queries_per_round") { + rhs.max_udp_queries_per_round.clone_into(&mut self.max_udp_queries_per_round); + } + if m.contains_key("pdns_distributes_queries") { + rhs.pdns_distributes_queries.clone_into(&mut self.pdns_distributes_queries); + } + if m.contains_key("proxy_protocol_from") { + if is_overriding(m, "proxy_protocol_from") || self.proxy_protocol_from == DEFAULT_CONFIG.incoming.proxy_protocol_from { + self.proxy_protocol_from.clear(); + } + merge_vec(&mut self.proxy_protocol_from, &mut rhs.proxy_protocol_from); + } + if m.contains_key("proxy_protocol_exceptions") { + if is_overriding(m, "proxy_protocol_exceptions") || self.proxy_protocol_exceptions == DEFAULT_CONFIG.incoming.proxy_protocol_exceptions { + self.proxy_protocol_exceptions.clear(); + } + merge_vec(&mut self.proxy_protocol_exceptions, &mut rhs.proxy_protocol_exceptions); + } + if m.contains_key("proxy_protocol_maximum_size") { + rhs.proxy_protocol_maximum_size.clone_into(&mut self.proxy_protocol_maximum_size); + } + if m.contains_key("reuseport") { + rhs.reuseport.clone_into(&mut self.reuseport); + } + if m.contains_key("tcp_fast_open") { + rhs.tcp_fast_open.clone_into(&mut self.tcp_fast_open); + } + if m.contains_key("udp_truncation_threshold") { + rhs.udp_truncation_threshold.clone_into(&mut self.udp_truncation_threshold); + } + if m.contains_key("use_incoming_edns_subnet") { + rhs.use_incoming_edns_subnet.clone_into(&mut self.use_incoming_edns_subnet); + } + if m.contains_key("proxymappings") { + if is_overriding(m, "proxymappings") || self.proxymappings == DEFAULT_CONFIG.incoming.proxymappings { + self.proxymappings.clear(); + } + merge_vec(&mut self.proxymappings, &mut rhs.proxymappings); + } + } + } +} + +impl Merge for recsettings::Recursor { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("any_to_tcp") { + rhs.any_to_tcp.clone_into(&mut self.any_to_tcp); + } + if m.contains_key("allow_trust_anchor_query") { + rhs.allow_trust_anchor_query.clone_into(&mut self.allow_trust_anchor_query); + } + if m.contains_key("auth_zones") { + if is_overriding(m, "auth_zones") || self.auth_zones == DEFAULT_CONFIG.recursor.auth_zones { + self.auth_zones.clear(); + } + merge_vec(&mut self.auth_zones, &mut rhs.auth_zones); + } + if m.contains_key("chroot") { + rhs.chroot.clone_into(&mut self.chroot); + } + if m.contains_key("config_dir") { + rhs.config_dir.clone_into(&mut self.config_dir); + } + if m.contains_key("config_name") { + rhs.config_name.clone_into(&mut self.config_name); + } + if m.contains_key("cpu_map") { + rhs.cpu_map.clone_into(&mut self.cpu_map); + } + if m.contains_key("daemon") { + rhs.daemon.clone_into(&mut self.daemon); + } + if m.contains_key("devonly_regression_test_mode") { + rhs.devonly_regression_test_mode.clone_into(&mut self.devonly_regression_test_mode); + } + if m.contains_key("dns64_prefix") { + rhs.dns64_prefix.clone_into(&mut self.dns64_prefix); + } + if m.contains_key("etc_hosts_file") { + rhs.etc_hosts_file.clone_into(&mut self.etc_hosts_file); + } + if m.contains_key("event_trace_enabled") { + rhs.event_trace_enabled.clone_into(&mut self.event_trace_enabled); + } + if m.contains_key("export_etc_hosts") { + rhs.export_etc_hosts.clone_into(&mut self.export_etc_hosts); + } + if m.contains_key("export_etc_hosts_search_suffix") { + rhs.export_etc_hosts_search_suffix.clone_into(&mut self.export_etc_hosts_search_suffix); + } + if m.contains_key("extended_resolution_errors") { + rhs.extended_resolution_errors.clone_into(&mut self.extended_resolution_errors); + } + if m.contains_key("forward_zones") { + if is_overriding(m, "forward_zones") || self.forward_zones == DEFAULT_CONFIG.recursor.forward_zones { + self.forward_zones.clear(); + } + merge_vec(&mut self.forward_zones, &mut rhs.forward_zones); + } + if m.contains_key("forward_zones_file") { + rhs.forward_zones_file.clone_into(&mut self.forward_zones_file); + } + if m.contains_key("forward_zones_recurse") { + if is_overriding(m, "forward_zones_recurse") || self.forward_zones_recurse == DEFAULT_CONFIG.recursor.forward_zones_recurse { + self.forward_zones_recurse.clear(); + } + merge_vec(&mut self.forward_zones_recurse, &mut rhs.forward_zones_recurse); + } + if m.contains_key("hint_file") { + rhs.hint_file.clone_into(&mut self.hint_file); + } + if m.contains_key("ignore_unknown_settings") { + if is_overriding(m, "ignore_unknown_settings") || self.ignore_unknown_settings == DEFAULT_CONFIG.recursor.ignore_unknown_settings { + self.ignore_unknown_settings.clear(); + } + merge_vec(&mut self.ignore_unknown_settings, &mut rhs.ignore_unknown_settings); + } + if m.contains_key("include_dir") { + rhs.include_dir.clone_into(&mut self.include_dir); + } + if m.contains_key("latency_statistic_size") { + rhs.latency_statistic_size.clone_into(&mut self.latency_statistic_size); + } + if m.contains_key("lua_config_file") { + rhs.lua_config_file.clone_into(&mut self.lua_config_file); + } + if m.contains_key("lua_global_include_dir") { + rhs.lua_global_include_dir.clone_into(&mut self.lua_global_include_dir); + } + if m.contains_key("lua_dns_script") { + rhs.lua_dns_script.clone_into(&mut self.lua_dns_script); + } + if m.contains_key("lua_maintenance_interval") { + rhs.lua_maintenance_interval.clone_into(&mut self.lua_maintenance_interval); + } + if m.contains_key("max_chain_length") { + rhs.max_chain_length.clone_into(&mut self.max_chain_length); + } + if m.contains_key("max_include_depth") { + rhs.max_include_depth.clone_into(&mut self.max_include_depth); + } + if m.contains_key("max_generate_steps") { + rhs.max_generate_steps.clone_into(&mut self.max_generate_steps); + } + if m.contains_key("max_mthreads") { + rhs.max_mthreads.clone_into(&mut self.max_mthreads); + } + if m.contains_key("max_cnames_followed") { + rhs.max_cnames_followed.clone_into(&mut self.max_cnames_followed); + } + if m.contains_key("max_recursion_depth") { + rhs.max_recursion_depth.clone_into(&mut self.max_recursion_depth); + } + if m.contains_key("max_total_msec") { + rhs.max_total_msec.clone_into(&mut self.max_total_msec); + } + if m.contains_key("minimum_ttl_override") { + rhs.minimum_ttl_override.clone_into(&mut self.minimum_ttl_override); + } + if m.contains_key("nothing_below_nxdomain") { + rhs.nothing_below_nxdomain.clone_into(&mut self.nothing_below_nxdomain); + } + if m.contains_key("public_suffix_list_file") { + rhs.public_suffix_list_file.clone_into(&mut self.public_suffix_list_file); + } + if m.contains_key("qname_minimization") { + rhs.qname_minimization.clone_into(&mut self.qname_minimization); + } + if m.contains_key("qname_max_minimize_count") { + rhs.qname_max_minimize_count.clone_into(&mut self.qname_max_minimize_count); + } + if m.contains_key("qname_minimize_one_label") { + rhs.qname_minimize_one_label.clone_into(&mut self.qname_minimize_one_label); + } + if m.contains_key("root_nx_trust") { + rhs.root_nx_trust.clone_into(&mut self.root_nx_trust); + } + if m.contains_key("save_parent_ns_set") { + rhs.save_parent_ns_set.clone_into(&mut self.save_parent_ns_set); + } + if m.contains_key("security_poll_suffix") { + rhs.security_poll_suffix.clone_into(&mut self.security_poll_suffix); + } + if m.contains_key("serve_rfc1918") { + rhs.serve_rfc1918.clone_into(&mut self.serve_rfc1918); + } + if m.contains_key("serve_rfc6303") { + rhs.serve_rfc6303.clone_into(&mut self.serve_rfc6303); + } + if m.contains_key("server_id") { + rhs.server_id.clone_into(&mut self.server_id); + } + if m.contains_key("setgid") { + rhs.setgid.clone_into(&mut self.setgid); + } + if m.contains_key("setuid") { + rhs.setuid.clone_into(&mut self.setuid); + } + if m.contains_key("socket_dir") { + rhs.socket_dir.clone_into(&mut self.socket_dir); + } + if m.contains_key("socket_group") { + rhs.socket_group.clone_into(&mut self.socket_group); + } + if m.contains_key("socket_mode") { + rhs.socket_mode.clone_into(&mut self.socket_mode); + } + if m.contains_key("socket_owner") { + rhs.socket_owner.clone_into(&mut self.socket_owner); + } + if m.contains_key("spoof_nearmiss_max") { + rhs.spoof_nearmiss_max.clone_into(&mut self.spoof_nearmiss_max); + } + if m.contains_key("stack_cache_size") { + rhs.stack_cache_size.clone_into(&mut self.stack_cache_size); + } + if m.contains_key("stack_size") { + rhs.stack_size.clone_into(&mut self.stack_size); + } + if m.contains_key("stats_api_disabled_list") { + if is_overriding(m, "stats_api_disabled_list") || self.stats_api_disabled_list == DEFAULT_CONFIG.recursor.stats_api_disabled_list { + self.stats_api_disabled_list.clear(); + } + merge_vec(&mut self.stats_api_disabled_list, &mut rhs.stats_api_disabled_list); + } + if m.contains_key("stats_carbon_disabled_list") { + if is_overriding(m, "stats_carbon_disabled_list") || self.stats_carbon_disabled_list == DEFAULT_CONFIG.recursor.stats_carbon_disabled_list { + self.stats_carbon_disabled_list.clear(); + } + merge_vec(&mut self.stats_carbon_disabled_list, &mut rhs.stats_carbon_disabled_list); + } + if m.contains_key("stats_rec_control_disabled_list") { + if is_overriding(m, "stats_rec_control_disabled_list") || self.stats_rec_control_disabled_list == DEFAULT_CONFIG.recursor.stats_rec_control_disabled_list { + self.stats_rec_control_disabled_list.clear(); + } + merge_vec(&mut self.stats_rec_control_disabled_list, &mut rhs.stats_rec_control_disabled_list); + } + if m.contains_key("stats_ringbuffer_entries") { + rhs.stats_ringbuffer_entries.clone_into(&mut self.stats_ringbuffer_entries); + } + if m.contains_key("stats_snmp_disabled_list") { + if is_overriding(m, "stats_snmp_disabled_list") || self.stats_snmp_disabled_list == DEFAULT_CONFIG.recursor.stats_snmp_disabled_list { + self.stats_snmp_disabled_list.clear(); + } + merge_vec(&mut self.stats_snmp_disabled_list, &mut rhs.stats_snmp_disabled_list); + } + if m.contains_key("threads") { + rhs.threads.clone_into(&mut self.threads); + } + if m.contains_key("tcp_threads") { + rhs.tcp_threads.clone_into(&mut self.tcp_threads); + } + if m.contains_key("version_string") { + rhs.version_string.clone_into(&mut self.version_string); + } + if m.contains_key("write_pid") { + rhs.write_pid.clone_into(&mut self.write_pid); + } + if m.contains_key("system_resolver_ttl") { + rhs.system_resolver_ttl.clone_into(&mut self.system_resolver_ttl); + } + if m.contains_key("system_resolver_interval") { + rhs.system_resolver_interval.clone_into(&mut self.system_resolver_interval); + } + if m.contains_key("system_resolver_self_resolve_check") { + rhs.system_resolver_self_resolve_check.clone_into(&mut self.system_resolver_self_resolve_check); + } + if m.contains_key("sortlists") { + if is_overriding(m, "sortlists") || self.sortlists == DEFAULT_CONFIG.recursor.sortlists { + self.sortlists.clear(); + } + merge_vec(&mut self.sortlists, &mut rhs.sortlists); + } + if m.contains_key("rpzs") { + if is_overriding(m, "rpzs") || self.rpzs == DEFAULT_CONFIG.recursor.rpzs { + self.rpzs.clear(); + } + merge_vec(&mut self.rpzs, &mut rhs.rpzs); + } + if m.contains_key("allowed_additional_qtypes") { + if is_overriding(m, "allowed_additional_qtypes") || self.allowed_additional_qtypes == DEFAULT_CONFIG.recursor.allowed_additional_qtypes { + self.allowed_additional_qtypes.clear(); + } + merge_vec(&mut self.allowed_additional_qtypes, &mut rhs.allowed_additional_qtypes); + } + if m.contains_key("lua_start_stop_script") { + rhs.lua_start_stop_script.clone_into(&mut self.lua_start_stop_script); + } + if m.contains_key("forwarding_catalog_zones") { + if is_overriding(m, "forwarding_catalog_zones") || self.forwarding_catalog_zones == DEFAULT_CONFIG.recursor.forwarding_catalog_zones { + self.forwarding_catalog_zones.clear(); + } + merge_vec(&mut self.forwarding_catalog_zones, &mut rhs.forwarding_catalog_zones); + } + if m.contains_key("max_pointers_per_name") { + rhs.max_pointers_per_name.clone_into(&mut self.max_pointers_per_name); + } + if m.contains_key("max_pointers_per_packet_byte") { + rhs.max_pointers_per_packet_byte.clone_into(&mut self.max_pointers_per_packet_byte); + } + if m.contains_key("max_pointers_to_pointers") { + rhs.max_pointers_to_pointers.clone_into(&mut self.max_pointers_to_pointers); + } + } + } +} + +impl Merge for recsettings::Outgoing { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("any_to_tcp") { + rhs.any_to_tcp.clone_into(&mut self.any_to_tcp); + } + if m.contains_key("dont_throttle_names") { + if is_overriding(m, "dont_throttle_names") || self.dont_throttle_names == DEFAULT_CONFIG.outgoing.dont_throttle_names { + self.dont_throttle_names.clear(); + } + merge_vec(&mut self.dont_throttle_names, &mut rhs.dont_throttle_names); + } + if m.contains_key("dont_throttle_netmasks") { + if is_overriding(m, "dont_throttle_netmasks") || self.dont_throttle_netmasks == DEFAULT_CONFIG.outgoing.dont_throttle_netmasks { + self.dont_throttle_netmasks.clear(); + } + merge_vec(&mut self.dont_throttle_netmasks, &mut rhs.dont_throttle_netmasks); + } + if m.contains_key("dot_to_auth_names") { + if is_overriding(m, "dot_to_auth_names") || self.dot_to_auth_names == DEFAULT_CONFIG.outgoing.dot_to_auth_names { + self.dot_to_auth_names.clear(); + } + merge_vec(&mut self.dot_to_auth_names, &mut rhs.dot_to_auth_names); + } + if m.contains_key("dot_to_port_853") { + rhs.dot_to_port_853.clone_into(&mut self.dot_to_port_853); + } + if m.contains_key("dont_query") { + if is_overriding(m, "dont_query") || self.dont_query == DEFAULT_CONFIG.outgoing.dont_query { + self.dont_query.clear(); + } + merge_vec(&mut self.dont_query, &mut rhs.dont_query); + } + if m.contains_key("edns_bufsize") { + rhs.edns_bufsize.clone_into(&mut self.edns_bufsize); + } + if m.contains_key("edns_padding") { + rhs.edns_padding.clone_into(&mut self.edns_padding); + } + if m.contains_key("edns_subnet_allow_list") { + if is_overriding(m, "edns_subnet_allow_list") || self.edns_subnet_allow_list == DEFAULT_CONFIG.outgoing.edns_subnet_allow_list { + self.edns_subnet_allow_list.clear(); + } + merge_vec(&mut self.edns_subnet_allow_list, &mut rhs.edns_subnet_allow_list); + } + if m.contains_key("edns_subnet_harden") { + rhs.edns_subnet_harden.clone_into(&mut self.edns_subnet_harden); + } + if m.contains_key("lowercase") { + rhs.lowercase.clone_into(&mut self.lowercase); + } + if m.contains_key("max_busy_dot_probes") { + rhs.max_busy_dot_probes.clone_into(&mut self.max_busy_dot_probes); + } + if m.contains_key("max_qperq") { + rhs.max_qperq.clone_into(&mut self.max_qperq); + } + if m.contains_key("max_bytesperq") { + rhs.max_bytesperq.clone_into(&mut self.max_bytesperq); + } + if m.contains_key("max_ns_address_qperq") { + rhs.max_ns_address_qperq.clone_into(&mut self.max_ns_address_qperq); + } + if m.contains_key("max_ns_per_resolve") { + rhs.max_ns_per_resolve.clone_into(&mut self.max_ns_per_resolve); + } + if m.contains_key("network_timeout") { + rhs.network_timeout.clone_into(&mut self.network_timeout); + } + if m.contains_key("non_resolving_ns_max_fails") { + rhs.non_resolving_ns_max_fails.clone_into(&mut self.non_resolving_ns_max_fails); + } + if m.contains_key("non_resolving_ns_throttle_time") { + rhs.non_resolving_ns_throttle_time.clone_into(&mut self.non_resolving_ns_throttle_time); + } + if m.contains_key("source_address") { + if is_overriding(m, "source_address") || self.source_address == DEFAULT_CONFIG.outgoing.source_address { + self.source_address.clear(); + } + merge_vec(&mut self.source_address, &mut rhs.source_address); + } + if m.contains_key("server_down_max_fails") { + rhs.server_down_max_fails.clone_into(&mut self.server_down_max_fails); + } + if m.contains_key("server_down_throttle_time") { + rhs.server_down_throttle_time.clone_into(&mut self.server_down_throttle_time); + } + if m.contains_key("bypass_server_throttling_probability") { + rhs.bypass_server_throttling_probability.clone_into(&mut self.bypass_server_throttling_probability); + } + if m.contains_key("single_socket") { + rhs.single_socket.clone_into(&mut self.single_socket); + } + if m.contains_key("tcp_fast_open_connect") { + rhs.tcp_fast_open_connect.clone_into(&mut self.tcp_fast_open_connect); + } + if m.contains_key("tcp_max_idle_ms") { + rhs.tcp_max_idle_ms.clone_into(&mut self.tcp_max_idle_ms); + } + if m.contains_key("tcp_max_idle_per_auth") { + rhs.tcp_max_idle_per_auth.clone_into(&mut self.tcp_max_idle_per_auth); + } + if m.contains_key("tcp_max_queries") { + rhs.tcp_max_queries.clone_into(&mut self.tcp_max_queries); + } + if m.contains_key("tcp_max_idle_per_thread") { + rhs.tcp_max_idle_per_thread.clone_into(&mut self.tcp_max_idle_per_thread); + } + if m.contains_key("udp_source_port_min") { + rhs.udp_source_port_min.clone_into(&mut self.udp_source_port_min); + } + if m.contains_key("udp_source_port_max") { + rhs.udp_source_port_max.clone_into(&mut self.udp_source_port_max); + } + if m.contains_key("udp_source_port_avoid") { + if is_overriding(m, "udp_source_port_avoid") || self.udp_source_port_avoid == DEFAULT_CONFIG.outgoing.udp_source_port_avoid { + self.udp_source_port_avoid.clear(); + } + merge_vec(&mut self.udp_source_port_avoid, &mut rhs.udp_source_port_avoid); + } + if m.contains_key("cookies") { + rhs.cookies.clone_into(&mut self.cookies); + } + if m.contains_key("cookies_unsupported") { + if is_overriding(m, "cookies_unsupported") || self.cookies_unsupported == DEFAULT_CONFIG.outgoing.cookies_unsupported { + self.cookies_unsupported.clear(); + } + merge_vec(&mut self.cookies_unsupported, &mut rhs.cookies_unsupported); + } + if m.contains_key("tls_configurations") { + if is_overriding(m, "tls_configurations") || self.tls_configurations == DEFAULT_CONFIG.outgoing.tls_configurations { + self.tls_configurations.clear(); + } + merge_vec(&mut self.tls_configurations, &mut rhs.tls_configurations); + } + } + } +} + +impl Merge for recsettings::Webservice { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("api_dir") { + rhs.api_dir.clone_into(&mut self.api_dir); + } + if m.contains_key("api_key") { + rhs.api_key.clone_into(&mut self.api_key); + } + if m.contains_key("webserver") { + rhs.webserver.clone_into(&mut self.webserver); + } + if m.contains_key("address") { + rhs.address.clone_into(&mut self.address); + } + if m.contains_key("listen") { + if is_overriding(m, "listen") || self.listen == DEFAULT_CONFIG.webservice.listen { + self.listen.clear(); + } + merge_vec(&mut self.listen, &mut rhs.listen); + } + if m.contains_key("allow_from") { + if is_overriding(m, "allow_from") || self.allow_from == DEFAULT_CONFIG.webservice.allow_from { + self.allow_from.clear(); + } + merge_vec(&mut self.allow_from, &mut rhs.allow_from); + } + if m.contains_key("hash_plaintext_credentials") { + rhs.hash_plaintext_credentials.clone_into(&mut self.hash_plaintext_credentials); + } + if m.contains_key("loglevel") { + rhs.loglevel.clone_into(&mut self.loglevel); + } + if m.contains_key("password") { + rhs.password.clone_into(&mut self.password); + } + if m.contains_key("port") { + rhs.port.clone_into(&mut self.port); + } + if m.contains_key("max_request_size") { + rhs.max_request_size.clone_into(&mut self.max_request_size); + } + } + } +} + +impl Merge for recsettings::Carbon { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("interval") { + rhs.interval.clone_into(&mut self.interval); + } + if m.contains_key("ns") { + rhs.ns.clone_into(&mut self.ns); + } + if m.contains_key("ourname") { + rhs.ourname.clone_into(&mut self.ourname); + } + if m.contains_key("instance") { + rhs.instance.clone_into(&mut self.instance); + } + if m.contains_key("server") { + if is_overriding(m, "server") || self.server == DEFAULT_CONFIG.carbon.server { + self.server.clear(); + } + merge_vec(&mut self.server, &mut rhs.server); + } + } + } +} + +impl Merge for recsettings::Packetcache { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("disable") { + rhs.disable.clone_into(&mut self.disable); + } + if m.contains_key("max_entries") { + rhs.max_entries.clone_into(&mut self.max_entries); + } + if m.contains_key("max_entry_size") { + rhs.max_entry_size.clone_into(&mut self.max_entry_size); + } + if m.contains_key("ttl") { + rhs.ttl.clone_into(&mut self.ttl); + } + if m.contains_key("negative_ttl") { + rhs.negative_ttl.clone_into(&mut self.negative_ttl); + } + if m.contains_key("servfail_ttl") { + rhs.servfail_ttl.clone_into(&mut self.servfail_ttl); + } + if m.contains_key("shards") { + rhs.shards.clone_into(&mut self.shards); + } + } + } +} + +impl Merge for recsettings::Logging { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("disable_syslog") { + rhs.disable_syslog.clone_into(&mut self.disable_syslog); + } + if m.contains_key("timestamp") { + rhs.timestamp.clone_into(&mut self.timestamp); + } + if m.contains_key("loglevel") { + rhs.loglevel.clone_into(&mut self.loglevel); + } + if m.contains_key("common_errors") { + rhs.common_errors.clone_into(&mut self.common_errors); + } + if m.contains_key("rpz_changes") { + rhs.rpz_changes.clone_into(&mut self.rpz_changes); + } + if m.contains_key("facility") { + rhs.facility.clone_into(&mut self.facility); + } + if m.contains_key("protobuf_use_kernel_timestamp") { + rhs.protobuf_use_kernel_timestamp.clone_into(&mut self.protobuf_use_kernel_timestamp); + } + if m.contains_key("quiet") { + rhs.quiet.clone_into(&mut self.quiet); + } + if m.contains_key("statistics_interval") { + rhs.statistics_interval.clone_into(&mut self.statistics_interval); + } + if m.contains_key("structured_logging") { + rhs.structured_logging.clone_into(&mut self.structured_logging); + } + if m.contains_key("structured_logging_backend") { + rhs.structured_logging_backend.clone_into(&mut self.structured_logging_backend); + } + if m.contains_key("trace") { + rhs.trace.clone_into(&mut self.trace); + } + if m.contains_key("protobuf_servers") { + if is_overriding(m, "protobuf_servers") || self.protobuf_servers == DEFAULT_CONFIG.logging.protobuf_servers { + self.protobuf_servers.clear(); + } + merge_vec(&mut self.protobuf_servers, &mut rhs.protobuf_servers); + } + if m.contains_key("outgoing_protobuf_servers") { + if is_overriding(m, "outgoing_protobuf_servers") || self.outgoing_protobuf_servers == DEFAULT_CONFIG.logging.outgoing_protobuf_servers { + self.outgoing_protobuf_servers.clear(); + } + merge_vec(&mut self.outgoing_protobuf_servers, &mut rhs.outgoing_protobuf_servers); + } + if m.contains_key("protobuf_mask_v4") { + rhs.protobuf_mask_v4.clone_into(&mut self.protobuf_mask_v4); + } + if m.contains_key("protobuf_mask_v6") { + rhs.protobuf_mask_v6.clone_into(&mut self.protobuf_mask_v6); + } + if m.contains_key("dnstap_framestream_servers") { + if is_overriding(m, "dnstap_framestream_servers") || self.dnstap_framestream_servers == DEFAULT_CONFIG.logging.dnstap_framestream_servers { + self.dnstap_framestream_servers.clear(); + } + merge_vec(&mut self.dnstap_framestream_servers, &mut rhs.dnstap_framestream_servers); + } + if m.contains_key("dnstap_nod_framestream_servers") { + if is_overriding(m, "dnstap_nod_framestream_servers") || self.dnstap_nod_framestream_servers == DEFAULT_CONFIG.logging.dnstap_nod_framestream_servers { + self.dnstap_nod_framestream_servers.clear(); + } + merge_vec(&mut self.dnstap_nod_framestream_servers, &mut rhs.dnstap_nod_framestream_servers); + } + if m.contains_key("opentelemetry_trace_conditions") { + if is_overriding(m, "opentelemetry_trace_conditions") || self.opentelemetry_trace_conditions == DEFAULT_CONFIG.logging.opentelemetry_trace_conditions { + self.opentelemetry_trace_conditions.clear(); + } + merge_vec(&mut self.opentelemetry_trace_conditions, &mut rhs.opentelemetry_trace_conditions); + } + } + } +} + +impl Merge for recsettings::Ecs { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("add_for") { + if is_overriding(m, "add_for") || self.add_for == DEFAULT_CONFIG.ecs.add_for { + self.add_for.clear(); + } + merge_vec(&mut self.add_for, &mut rhs.add_for); + } + if m.contains_key("ipv4_bits") { + rhs.ipv4_bits.clone_into(&mut self.ipv4_bits); + } + if m.contains_key("ipv4_cache_bits") { + rhs.ipv4_cache_bits.clone_into(&mut self.ipv4_cache_bits); + } + if m.contains_key("ipv6_bits") { + rhs.ipv6_bits.clone_into(&mut self.ipv6_bits); + } + if m.contains_key("ipv6_cache_bits") { + rhs.ipv6_cache_bits.clone_into(&mut self.ipv6_cache_bits); + } + if m.contains_key("ipv4_never_cache") { + rhs.ipv4_never_cache.clone_into(&mut self.ipv4_never_cache); + } + if m.contains_key("ipv6_never_cache") { + rhs.ipv6_never_cache.clone_into(&mut self.ipv6_never_cache); + } + if m.contains_key("minimum_ttl_override") { + rhs.minimum_ttl_override.clone_into(&mut self.minimum_ttl_override); + } + if m.contains_key("cache_limit_ttl") { + rhs.cache_limit_ttl.clone_into(&mut self.cache_limit_ttl); + } + if m.contains_key("scope_zero_address") { + rhs.scope_zero_address.clone_into(&mut self.scope_zero_address); + } + } + } +} + +impl Merge for recsettings::Recordcache { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("max_cache_bogus_ttl") { + rhs.max_cache_bogus_ttl.clone_into(&mut self.max_cache_bogus_ttl); + } + if m.contains_key("max_entries") { + rhs.max_entries.clone_into(&mut self.max_entries); + } + if m.contains_key("max_ttl") { + rhs.max_ttl.clone_into(&mut self.max_ttl); + } + if m.contains_key("max_entry_size") { + rhs.max_entry_size.clone_into(&mut self.max_entry_size); + } + if m.contains_key("limit_qtype_any") { + rhs.limit_qtype_any.clone_into(&mut self.limit_qtype_any); + } + if m.contains_key("max_rrset_size") { + rhs.max_rrset_size.clone_into(&mut self.max_rrset_size); + } + if m.contains_key("max_negative_ttl") { + rhs.max_negative_ttl.clone_into(&mut self.max_negative_ttl); + } + if m.contains_key("locked_ttl_perc") { + rhs.locked_ttl_perc.clone_into(&mut self.locked_ttl_perc); + } + if m.contains_key("shards") { + rhs.shards.clone_into(&mut self.shards); + } + if m.contains_key("refresh_on_ttl_perc") { + rhs.refresh_on_ttl_perc.clone_into(&mut self.refresh_on_ttl_perc); + } + if m.contains_key("serve_stale_extensions") { + rhs.serve_stale_extensions.clone_into(&mut self.serve_stale_extensions); + } + if m.contains_key("zonetocaches") { + if is_overriding(m, "zonetocaches") || self.zonetocaches == DEFAULT_CONFIG.recordcache.zonetocaches { + self.zonetocaches.clear(); + } + merge_vec(&mut self.zonetocaches, &mut rhs.zonetocaches); + } + } + } +} + +impl Merge for recsettings::Nod { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("tracking") { + rhs.tracking.clone_into(&mut self.tracking); + } + if m.contains_key("log") { + rhs.log.clone_into(&mut self.log); + } + if m.contains_key("lookup") { + rhs.lookup.clone_into(&mut self.lookup); + } + if m.contains_key("db_size") { + rhs.db_size.clone_into(&mut self.db_size); + } + if m.contains_key("history_dir") { + rhs.history_dir.clone_into(&mut self.history_dir); + } + if m.contains_key("db_snapshot_interval") { + rhs.db_snapshot_interval.clone_into(&mut self.db_snapshot_interval); + } + if m.contains_key("ignore_list") { + if is_overriding(m, "ignore_list") || self.ignore_list == DEFAULT_CONFIG.nod.ignore_list { + self.ignore_list.clear(); + } + merge_vec(&mut self.ignore_list, &mut rhs.ignore_list); + } + if m.contains_key("ignore_list_file") { + rhs.ignore_list_file.clone_into(&mut self.ignore_list_file); + } + if m.contains_key("pb_tag") { + rhs.pb_tag.clone_into(&mut self.pb_tag); + } + if m.contains_key("unique_response_tracking") { + rhs.unique_response_tracking.clone_into(&mut self.unique_response_tracking); + } + if m.contains_key("unique_response_log") { + rhs.unique_response_log.clone_into(&mut self.unique_response_log); + } + if m.contains_key("unique_response_db_size") { + rhs.unique_response_db_size.clone_into(&mut self.unique_response_db_size); + } + if m.contains_key("unique_response_history_dir") { + rhs.unique_response_history_dir.clone_into(&mut self.unique_response_history_dir); + } + if m.contains_key("unique_response_pb_tag") { + rhs.unique_response_pb_tag.clone_into(&mut self.unique_response_pb_tag); + } + if m.contains_key("unique_response_ignore_list") { + if is_overriding(m, "unique_response_ignore_list") || self.unique_response_ignore_list == DEFAULT_CONFIG.nod.unique_response_ignore_list { + self.unique_response_ignore_list.clear(); + } + merge_vec(&mut self.unique_response_ignore_list, &mut rhs.unique_response_ignore_list); + } + if m.contains_key("unique_response_ignore_list_file") { + rhs.unique_response_ignore_list_file.clone_into(&mut self.unique_response_ignore_list_file); + } + } + } +} + +impl Merge for recsettings::Snmp { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if m.contains_key("agent") { + rhs.agent.clone_into(&mut self.agent); + } + if m.contains_key("daemon_socket") { + rhs.daemon_socket.clone_into(&mut self.daemon_socket); + } + } + } +} + +impl Merge for crate::recsettings::Recursorsettings { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { + if let Some(m) = map { + if let Some(s) = m.get("dnssec") { + if s.is_mapping() { + self.dnssec.merge(&mut rhs.dnssec, s.as_mapping()); + } + } + if let Some(s) = m.get("incoming") { + if s.is_mapping() { + self.incoming.merge(&mut rhs.incoming, s.as_mapping()); + } + } + if let Some(s) = m.get("recursor") { + if s.is_mapping() { + self.recursor.merge(&mut rhs.recursor, s.as_mapping()); + } + } + if let Some(s) = m.get("outgoing") { + if s.is_mapping() { + self.outgoing.merge(&mut rhs.outgoing, s.as_mapping()); + } + } + if let Some(s) = m.get("webservice") { + if s.is_mapping() { + self.webservice.merge(&mut rhs.webservice, s.as_mapping()); + } + } + if let Some(s) = m.get("carbon") { + if s.is_mapping() { + self.carbon.merge(&mut rhs.carbon, s.as_mapping()); + } + } + if let Some(s) = m.get("packetcache") { + if s.is_mapping() { + self.packetcache.merge(&mut rhs.packetcache, s.as_mapping()); + } + } + if let Some(s) = m.get("logging") { + if s.is_mapping() { + self.logging.merge(&mut rhs.logging, s.as_mapping()); + } + } + if let Some(s) = m.get("ecs") { + if s.is_mapping() { + self.ecs.merge(&mut rhs.ecs, s.as_mapping()); + } + } + if let Some(s) = m.get("recordcache") { + if s.is_mapping() { + self.recordcache.merge(&mut rhs.recordcache, s.as_mapping()); + } + } + if let Some(s) = m.get("nod") { + if s.is_mapping() { + self.nod.merge(&mut rhs.nod, s.as_mapping()); + } + } + if let Some(s) = m.get("snmp") { + if s.is_mapping() { + self.snmp.merge(&mut rhs.snmp, s.as_mapping()); + } + } + } + } +} + +// DEFAULT HANDLING for dnssec_validation +fn default_value_dnssec_validation() -> String { + String::from("process") +} +fn default_value_equal_dnssec_validation(value: &str)-> bool { + value == default_value_dnssec_validation() +} + +// DEFAULT HANDLING for dnssec_disabled_algorithms +fn default_value_dnssec_disabled_algorithms() -> Vec { + vec![ + ] +} +fn default_value_equal_dnssec_disabled_algorithms(value: &Vec) -> bool { + let def = default_value_dnssec_disabled_algorithms(); + &def == value +} + +// DEFAULT HANDLING for dnssec_x_dnssec_names +fn default_value_dnssec_x_dnssec_names() -> Vec { + vec![ + ] +} +fn default_value_equal_dnssec_x_dnssec_names(value: &Vec) -> bool { + let def = default_value_dnssec_x_dnssec_names(); + &def == value +} + +// DEFAULT HANDLING for dnssec_trustanchors +fn default_value_dnssec_trustanchors() -> Vec { + let msg = "default value defined for `dnssec_trustanchors' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("[{name: ., dsrecords: ['20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d', '38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16']}]").expect(msg); + deserialized +} +fn default_value_equal_dnssec_trustanchors(value: &Vec)-> bool { + let def = default_value_dnssec_trustanchors(); + &def == value +} + +// DEFAULT HANDLING for dnssec_negative_trustanchors +fn default_value_dnssec_negative_trustanchors() -> Vec { + let msg = "default value defined for `dnssec_negative_trustanchors' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_dnssec_negative_trustanchors(value: &Vec)-> bool { + let def = default_value_dnssec_negative_trustanchors(); + &def == value +} + +// DEFAULT HANDLING for incoming_allow_from +fn default_value_incoming_allow_from() -> Vec { + vec![ + String::from("127.0.0.0/8"), + String::from("10.0.0.0/8"), + String::from("100.64.0.0/10"), + String::from("169.254.0.0/16"), + String::from("192.168.0.0/16"), + String::from("172.16.0.0/12"), + String::from("::1/128"), + String::from("fc00::/7"), + String::from("fe80::/10"), + ] +} +fn default_value_equal_incoming_allow_from(value: &Vec) -> bool { + let def = default_value_incoming_allow_from(); + &def == value +} + +// DEFAULT HANDLING for incoming_allow_notify_for +fn default_value_incoming_allow_notify_for() -> Vec { + vec![ + ] +} +fn default_value_equal_incoming_allow_notify_for(value: &Vec) -> bool { + let def = default_value_incoming_allow_notify_for(); + &def == value +} + +// DEFAULT HANDLING for incoming_allow_notify_from +fn default_value_incoming_allow_notify_from() -> Vec { + vec![ + ] +} +fn default_value_equal_incoming_allow_notify_from(value: &Vec) -> bool { + let def = default_value_incoming_allow_notify_from(); + &def == value +} + +// DEFAULT HANDLING for incoming_edns_padding_from +fn default_value_incoming_edns_padding_from() -> Vec { + vec![ + ] +} +fn default_value_equal_incoming_edns_padding_from(value: &Vec) -> bool { + let def = default_value_incoming_edns_padding_from(); + &def == value +} + +// DEFAULT HANDLING for incoming_edns_padding_mode +fn default_value_incoming_edns_padding_mode() -> String { + String::from("padded-queries-only") +} +fn default_value_equal_incoming_edns_padding_mode(value: &str)-> bool { + value == default_value_incoming_edns_padding_mode() +} + +// DEFAULT HANDLING for incoming_listen +fn default_value_incoming_listen() -> Vec { + vec![ + String::from("127.0.0.1"), + String::from("::1"), + ] +} +fn default_value_equal_incoming_listen(value: &Vec) -> bool { + let def = default_value_incoming_listen(); + &def == value +} + +// DEFAULT HANDLING for incoming_proxy_protocol_from +fn default_value_incoming_proxy_protocol_from() -> Vec { + vec![ + ] +} +fn default_value_equal_incoming_proxy_protocol_from(value: &Vec) -> bool { + let def = default_value_incoming_proxy_protocol_from(); + &def == value +} + +// DEFAULT HANDLING for incoming_proxy_protocol_exceptions +fn default_value_incoming_proxy_protocol_exceptions() -> Vec { + vec![ + ] +} +fn default_value_equal_incoming_proxy_protocol_exceptions(value: &Vec) -> bool { + let def = default_value_incoming_proxy_protocol_exceptions(); + &def == value +} + +// DEFAULT HANDLING for incoming_proxymappings +fn default_value_incoming_proxymappings() -> Vec { + let msg = "default value defined for `incoming_proxymappings' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_incoming_proxymappings(value: &Vec)-> bool { + let def = default_value_incoming_proxymappings(); + &def == value +} + +// DEFAULT HANDLING for recursor_auth_zones +fn default_value_recursor_auth_zones() -> Vec { + let msg = "default value defined for `recursor_auth_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_auth_zones(value: &Vec)-> bool { + let def = default_value_recursor_auth_zones(); + &def == value +} + +// DEFAULT HANDLING for recursor_config_dir +fn default_value_recursor_config_dir() -> String { + String::from(env!("SYSCONFDIR")) +} +fn default_value_equal_recursor_config_dir(value: &str)-> bool { + value == default_value_recursor_config_dir() +} + +// DEFAULT HANDLING for recursor_etc_hosts_file +fn default_value_recursor_etc_hosts_file() -> String { + String::from("/etc/hosts") +} +fn default_value_equal_recursor_etc_hosts_file(value: &str)-> bool { + value == default_value_recursor_etc_hosts_file() +} + +// DEFAULT HANDLING for recursor_forward_zones +fn default_value_recursor_forward_zones() -> Vec { + let msg = "default value defined for `recursor_forward_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_forward_zones(value: &Vec)-> bool { + let def = default_value_recursor_forward_zones(); + &def == value +} + +// DEFAULT HANDLING for recursor_forward_zones_recurse +fn default_value_recursor_forward_zones_recurse() -> Vec { + let msg = "default value defined for `recursor_forward_zones_recurse' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_forward_zones_recurse(value: &Vec)-> bool { + let def = default_value_recursor_forward_zones_recurse(); + &def == value +} + +// DEFAULT HANDLING for recursor_ignore_unknown_settings +fn default_value_recursor_ignore_unknown_settings() -> Vec { + vec![ + ] +} +fn default_value_equal_recursor_ignore_unknown_settings(value: &Vec) -> bool { + let def = default_value_recursor_ignore_unknown_settings(); + &def == value +} + +// DEFAULT HANDLING for recursor_nothing_below_nxdomain +fn default_value_recursor_nothing_below_nxdomain() -> String { + String::from("dnssec") +} +fn default_value_equal_recursor_nothing_below_nxdomain(value: &str)-> bool { + value == default_value_recursor_nothing_below_nxdomain() +} + +// DEFAULT HANDLING for recursor_security_poll_suffix +fn default_value_recursor_security_poll_suffix() -> String { + String::from("secpoll.powerdns.com.") +} +fn default_value_equal_recursor_security_poll_suffix(value: &str)-> bool { + value == default_value_recursor_security_poll_suffix() +} + +// DEFAULT HANDLING for recursor_server_id +fn default_value_recursor_server_id() -> String { + String::from("*runtime determined*") +} +fn default_value_equal_recursor_server_id(value: &str)-> bool { + value == default_value_recursor_server_id() +} + +// DEFAULT HANDLING for recursor_stats_api_disabled_list +fn default_value_recursor_stats_api_disabled_list() -> Vec { + vec![ + String::from("cache-bytes"), + String::from("packetcache-bytes"), + String::from("special-memory-usage"), + String::from("ecs-v4-response-bits-1"), + String::from("ecs-v4-response-bits-2"), + String::from("ecs-v4-response-bits-3"), + String::from("ecs-v4-response-bits-4"), + String::from("ecs-v4-response-bits-5"), + String::from("ecs-v4-response-bits-6"), + String::from("ecs-v4-response-bits-7"), + String::from("ecs-v4-response-bits-8"), + String::from("ecs-v4-response-bits-9"), + String::from("ecs-v4-response-bits-10"), + String::from("ecs-v4-response-bits-11"), + String::from("ecs-v4-response-bits-12"), + String::from("ecs-v4-response-bits-13"), + String::from("ecs-v4-response-bits-14"), + String::from("ecs-v4-response-bits-15"), + String::from("ecs-v4-response-bits-16"), + String::from("ecs-v4-response-bits-17"), + String::from("ecs-v4-response-bits-18"), + String::from("ecs-v4-response-bits-19"), + String::from("ecs-v4-response-bits-20"), + String::from("ecs-v4-response-bits-21"), + String::from("ecs-v4-response-bits-22"), + String::from("ecs-v4-response-bits-23"), + String::from("ecs-v4-response-bits-24"), + String::from("ecs-v4-response-bits-25"), + String::from("ecs-v4-response-bits-26"), + String::from("ecs-v4-response-bits-27"), + String::from("ecs-v4-response-bits-28"), + String::from("ecs-v4-response-bits-29"), + String::from("ecs-v4-response-bits-30"), + String::from("ecs-v4-response-bits-31"), + String::from("ecs-v4-response-bits-32"), + String::from("ecs-v6-response-bits-1"), + String::from("ecs-v6-response-bits-2"), + String::from("ecs-v6-response-bits-3"), + String::from("ecs-v6-response-bits-4"), + String::from("ecs-v6-response-bits-5"), + String::from("ecs-v6-response-bits-6"), + String::from("ecs-v6-response-bits-7"), + String::from("ecs-v6-response-bits-8"), + String::from("ecs-v6-response-bits-9"), + String::from("ecs-v6-response-bits-10"), + String::from("ecs-v6-response-bits-11"), + String::from("ecs-v6-response-bits-12"), + String::from("ecs-v6-response-bits-13"), + String::from("ecs-v6-response-bits-14"), + String::from("ecs-v6-response-bits-15"), + String::from("ecs-v6-response-bits-16"), + String::from("ecs-v6-response-bits-17"), + String::from("ecs-v6-response-bits-18"), + String::from("ecs-v6-response-bits-19"), + String::from("ecs-v6-response-bits-20"), + String::from("ecs-v6-response-bits-21"), + String::from("ecs-v6-response-bits-22"), + String::from("ecs-v6-response-bits-23"), + String::from("ecs-v6-response-bits-24"), + String::from("ecs-v6-response-bits-25"), + String::from("ecs-v6-response-bits-26"), + String::from("ecs-v6-response-bits-27"), + String::from("ecs-v6-response-bits-28"), + String::from("ecs-v6-response-bits-29"), + String::from("ecs-v6-response-bits-30"), + String::from("ecs-v6-response-bits-31"), + String::from("ecs-v6-response-bits-32"), + String::from("ecs-v6-response-bits-33"), + String::from("ecs-v6-response-bits-34"), + String::from("ecs-v6-response-bits-35"), + String::from("ecs-v6-response-bits-36"), + String::from("ecs-v6-response-bits-37"), + String::from("ecs-v6-response-bits-38"), + String::from("ecs-v6-response-bits-39"), + String::from("ecs-v6-response-bits-40"), + String::from("ecs-v6-response-bits-41"), + String::from("ecs-v6-response-bits-42"), + String::from("ecs-v6-response-bits-43"), + String::from("ecs-v6-response-bits-44"), + String::from("ecs-v6-response-bits-45"), + String::from("ecs-v6-response-bits-46"), + String::from("ecs-v6-response-bits-47"), + String::from("ecs-v6-response-bits-48"), + String::from("ecs-v6-response-bits-49"), + String::from("ecs-v6-response-bits-50"), + String::from("ecs-v6-response-bits-51"), + String::from("ecs-v6-response-bits-52"), + String::from("ecs-v6-response-bits-53"), + String::from("ecs-v6-response-bits-54"), + String::from("ecs-v6-response-bits-55"), + String::from("ecs-v6-response-bits-56"), + String::from("ecs-v6-response-bits-57"), + String::from("ecs-v6-response-bits-58"), + String::from("ecs-v6-response-bits-59"), + String::from("ecs-v6-response-bits-60"), + String::from("ecs-v6-response-bits-61"), + String::from("ecs-v6-response-bits-62"), + String::from("ecs-v6-response-bits-63"), + String::from("ecs-v6-response-bits-64"), + String::from("ecs-v6-response-bits-65"), + String::from("ecs-v6-response-bits-66"), + String::from("ecs-v6-response-bits-67"), + String::from("ecs-v6-response-bits-68"), + String::from("ecs-v6-response-bits-69"), + String::from("ecs-v6-response-bits-70"), + String::from("ecs-v6-response-bits-71"), + String::from("ecs-v6-response-bits-72"), + String::from("ecs-v6-response-bits-73"), + String::from("ecs-v6-response-bits-74"), + String::from("ecs-v6-response-bits-75"), + String::from("ecs-v6-response-bits-76"), + String::from("ecs-v6-response-bits-77"), + String::from("ecs-v6-response-bits-78"), + String::from("ecs-v6-response-bits-79"), + String::from("ecs-v6-response-bits-80"), + String::from("ecs-v6-response-bits-81"), + String::from("ecs-v6-response-bits-82"), + String::from("ecs-v6-response-bits-83"), + String::from("ecs-v6-response-bits-84"), + String::from("ecs-v6-response-bits-85"), + String::from("ecs-v6-response-bits-86"), + String::from("ecs-v6-response-bits-87"), + String::from("ecs-v6-response-bits-88"), + String::from("ecs-v6-response-bits-89"), + String::from("ecs-v6-response-bits-90"), + String::from("ecs-v6-response-bits-91"), + String::from("ecs-v6-response-bits-92"), + String::from("ecs-v6-response-bits-93"), + String::from("ecs-v6-response-bits-94"), + String::from("ecs-v6-response-bits-95"), + String::from("ecs-v6-response-bits-96"), + String::from("ecs-v6-response-bits-97"), + String::from("ecs-v6-response-bits-98"), + String::from("ecs-v6-response-bits-99"), + String::from("ecs-v6-response-bits-100"), + String::from("ecs-v6-response-bits-101"), + String::from("ecs-v6-response-bits-102"), + String::from("ecs-v6-response-bits-103"), + String::from("ecs-v6-response-bits-104"), + String::from("ecs-v6-response-bits-105"), + String::from("ecs-v6-response-bits-106"), + String::from("ecs-v6-response-bits-107"), + String::from("ecs-v6-response-bits-108"), + String::from("ecs-v6-response-bits-109"), + String::from("ecs-v6-response-bits-110"), + String::from("ecs-v6-response-bits-111"), + String::from("ecs-v6-response-bits-112"), + String::from("ecs-v6-response-bits-113"), + String::from("ecs-v6-response-bits-114"), + String::from("ecs-v6-response-bits-115"), + String::from("ecs-v6-response-bits-116"), + String::from("ecs-v6-response-bits-117"), + String::from("ecs-v6-response-bits-118"), + String::from("ecs-v6-response-bits-119"), + String::from("ecs-v6-response-bits-120"), + String::from("ecs-v6-response-bits-121"), + String::from("ecs-v6-response-bits-122"), + String::from("ecs-v6-response-bits-123"), + String::from("ecs-v6-response-bits-124"), + String::from("ecs-v6-response-bits-125"), + String::from("ecs-v6-response-bits-126"), + String::from("ecs-v6-response-bits-127"), + String::from("ecs-v6-response-bits-128"), + ] +} +fn default_value_equal_recursor_stats_api_disabled_list(value: &Vec) -> bool { + let def = default_value_recursor_stats_api_disabled_list(); + &def == value +} + +// DEFAULT HANDLING for recursor_stats_carbon_disabled_list +fn default_value_recursor_stats_carbon_disabled_list() -> Vec { + vec![ + String::from("cache-bytes"), + String::from("packetcache-bytes"), + String::from("special-memory-usage"), + String::from("ecs-v4-response-bits-1"), + String::from("ecs-v4-response-bits-2"), + String::from("ecs-v4-response-bits-3"), + String::from("ecs-v4-response-bits-4"), + String::from("ecs-v4-response-bits-5"), + String::from("ecs-v4-response-bits-6"), + String::from("ecs-v4-response-bits-7"), + String::from("ecs-v4-response-bits-8"), + String::from("ecs-v4-response-bits-9"), + String::from("ecs-v4-response-bits-10"), + String::from("ecs-v4-response-bits-11"), + String::from("ecs-v4-response-bits-12"), + String::from("ecs-v4-response-bits-13"), + String::from("ecs-v4-response-bits-14"), + String::from("ecs-v4-response-bits-15"), + String::from("ecs-v4-response-bits-16"), + String::from("ecs-v4-response-bits-17"), + String::from("ecs-v4-response-bits-18"), + String::from("ecs-v4-response-bits-19"), + String::from("ecs-v4-response-bits-20"), + String::from("ecs-v4-response-bits-21"), + String::from("ecs-v4-response-bits-22"), + String::from("ecs-v4-response-bits-23"), + String::from("ecs-v4-response-bits-24"), + String::from("ecs-v4-response-bits-25"), + String::from("ecs-v4-response-bits-26"), + String::from("ecs-v4-response-bits-27"), + String::from("ecs-v4-response-bits-28"), + String::from("ecs-v4-response-bits-29"), + String::from("ecs-v4-response-bits-30"), + String::from("ecs-v4-response-bits-31"), + String::from("ecs-v4-response-bits-32"), + String::from("ecs-v6-response-bits-1"), + String::from("ecs-v6-response-bits-2"), + String::from("ecs-v6-response-bits-3"), + String::from("ecs-v6-response-bits-4"), + String::from("ecs-v6-response-bits-5"), + String::from("ecs-v6-response-bits-6"), + String::from("ecs-v6-response-bits-7"), + String::from("ecs-v6-response-bits-8"), + String::from("ecs-v6-response-bits-9"), + String::from("ecs-v6-response-bits-10"), + String::from("ecs-v6-response-bits-11"), + String::from("ecs-v6-response-bits-12"), + String::from("ecs-v6-response-bits-13"), + String::from("ecs-v6-response-bits-14"), + String::from("ecs-v6-response-bits-15"), + String::from("ecs-v6-response-bits-16"), + String::from("ecs-v6-response-bits-17"), + String::from("ecs-v6-response-bits-18"), + String::from("ecs-v6-response-bits-19"), + String::from("ecs-v6-response-bits-20"), + String::from("ecs-v6-response-bits-21"), + String::from("ecs-v6-response-bits-22"), + String::from("ecs-v6-response-bits-23"), + String::from("ecs-v6-response-bits-24"), + String::from("ecs-v6-response-bits-25"), + String::from("ecs-v6-response-bits-26"), + String::from("ecs-v6-response-bits-27"), + String::from("ecs-v6-response-bits-28"), + String::from("ecs-v6-response-bits-29"), + String::from("ecs-v6-response-bits-30"), + String::from("ecs-v6-response-bits-31"), + String::from("ecs-v6-response-bits-32"), + String::from("ecs-v6-response-bits-33"), + String::from("ecs-v6-response-bits-34"), + String::from("ecs-v6-response-bits-35"), + String::from("ecs-v6-response-bits-36"), + String::from("ecs-v6-response-bits-37"), + String::from("ecs-v6-response-bits-38"), + String::from("ecs-v6-response-bits-39"), + String::from("ecs-v6-response-bits-40"), + String::from("ecs-v6-response-bits-41"), + String::from("ecs-v6-response-bits-42"), + String::from("ecs-v6-response-bits-43"), + String::from("ecs-v6-response-bits-44"), + String::from("ecs-v6-response-bits-45"), + String::from("ecs-v6-response-bits-46"), + String::from("ecs-v6-response-bits-47"), + String::from("ecs-v6-response-bits-48"), + String::from("ecs-v6-response-bits-49"), + String::from("ecs-v6-response-bits-50"), + String::from("ecs-v6-response-bits-51"), + String::from("ecs-v6-response-bits-52"), + String::from("ecs-v6-response-bits-53"), + String::from("ecs-v6-response-bits-54"), + String::from("ecs-v6-response-bits-55"), + String::from("ecs-v6-response-bits-56"), + String::from("ecs-v6-response-bits-57"), + String::from("ecs-v6-response-bits-58"), + String::from("ecs-v6-response-bits-59"), + String::from("ecs-v6-response-bits-60"), + String::from("ecs-v6-response-bits-61"), + String::from("ecs-v6-response-bits-62"), + String::from("ecs-v6-response-bits-63"), + String::from("ecs-v6-response-bits-64"), + String::from("ecs-v6-response-bits-65"), + String::from("ecs-v6-response-bits-66"), + String::from("ecs-v6-response-bits-67"), + String::from("ecs-v6-response-bits-68"), + String::from("ecs-v6-response-bits-69"), + String::from("ecs-v6-response-bits-70"), + String::from("ecs-v6-response-bits-71"), + String::from("ecs-v6-response-bits-72"), + String::from("ecs-v6-response-bits-73"), + String::from("ecs-v6-response-bits-74"), + String::from("ecs-v6-response-bits-75"), + String::from("ecs-v6-response-bits-76"), + String::from("ecs-v6-response-bits-77"), + String::from("ecs-v6-response-bits-78"), + String::from("ecs-v6-response-bits-79"), + String::from("ecs-v6-response-bits-80"), + String::from("ecs-v6-response-bits-81"), + String::from("ecs-v6-response-bits-82"), + String::from("ecs-v6-response-bits-83"), + String::from("ecs-v6-response-bits-84"), + String::from("ecs-v6-response-bits-85"), + String::from("ecs-v6-response-bits-86"), + String::from("ecs-v6-response-bits-87"), + String::from("ecs-v6-response-bits-88"), + String::from("ecs-v6-response-bits-89"), + String::from("ecs-v6-response-bits-90"), + String::from("ecs-v6-response-bits-91"), + String::from("ecs-v6-response-bits-92"), + String::from("ecs-v6-response-bits-93"), + String::from("ecs-v6-response-bits-94"), + String::from("ecs-v6-response-bits-95"), + String::from("ecs-v6-response-bits-96"), + String::from("ecs-v6-response-bits-97"), + String::from("ecs-v6-response-bits-98"), + String::from("ecs-v6-response-bits-99"), + String::from("ecs-v6-response-bits-100"), + String::from("ecs-v6-response-bits-101"), + String::from("ecs-v6-response-bits-102"), + String::from("ecs-v6-response-bits-103"), + String::from("ecs-v6-response-bits-104"), + String::from("ecs-v6-response-bits-105"), + String::from("ecs-v6-response-bits-106"), + String::from("ecs-v6-response-bits-107"), + String::from("ecs-v6-response-bits-108"), + String::from("ecs-v6-response-bits-109"), + String::from("ecs-v6-response-bits-110"), + String::from("ecs-v6-response-bits-111"), + String::from("ecs-v6-response-bits-112"), + String::from("ecs-v6-response-bits-113"), + String::from("ecs-v6-response-bits-114"), + String::from("ecs-v6-response-bits-115"), + String::from("ecs-v6-response-bits-116"), + String::from("ecs-v6-response-bits-117"), + String::from("ecs-v6-response-bits-118"), + String::from("ecs-v6-response-bits-119"), + String::from("ecs-v6-response-bits-120"), + String::from("ecs-v6-response-bits-121"), + String::from("ecs-v6-response-bits-122"), + String::from("ecs-v6-response-bits-123"), + String::from("ecs-v6-response-bits-124"), + String::from("ecs-v6-response-bits-125"), + String::from("ecs-v6-response-bits-126"), + String::from("ecs-v6-response-bits-127"), + String::from("ecs-v6-response-bits-128"), + String::from("cumul-clientanswers"), + String::from("cumul-authanswers"), + String::from("policy-hits"), + String::from("proxy-mapping-total"), + String::from("remote-logger-count"), + ] +} +fn default_value_equal_recursor_stats_carbon_disabled_list(value: &Vec) -> bool { + let def = default_value_recursor_stats_carbon_disabled_list(); + &def == value +} + +// DEFAULT HANDLING for recursor_stats_rec_control_disabled_list +fn default_value_recursor_stats_rec_control_disabled_list() -> Vec { + vec![ + String::from("cache-bytes"), + String::from("packetcache-bytes"), + String::from("special-memory-usage"), + String::from("ecs-v4-response-bits-1"), + String::from("ecs-v4-response-bits-2"), + String::from("ecs-v4-response-bits-3"), + String::from("ecs-v4-response-bits-4"), + String::from("ecs-v4-response-bits-5"), + String::from("ecs-v4-response-bits-6"), + String::from("ecs-v4-response-bits-7"), + String::from("ecs-v4-response-bits-8"), + String::from("ecs-v4-response-bits-9"), + String::from("ecs-v4-response-bits-10"), + String::from("ecs-v4-response-bits-11"), + String::from("ecs-v4-response-bits-12"), + String::from("ecs-v4-response-bits-13"), + String::from("ecs-v4-response-bits-14"), + String::from("ecs-v4-response-bits-15"), + String::from("ecs-v4-response-bits-16"), + String::from("ecs-v4-response-bits-17"), + String::from("ecs-v4-response-bits-18"), + String::from("ecs-v4-response-bits-19"), + String::from("ecs-v4-response-bits-20"), + String::from("ecs-v4-response-bits-21"), + String::from("ecs-v4-response-bits-22"), + String::from("ecs-v4-response-bits-23"), + String::from("ecs-v4-response-bits-24"), + String::from("ecs-v4-response-bits-25"), + String::from("ecs-v4-response-bits-26"), + String::from("ecs-v4-response-bits-27"), + String::from("ecs-v4-response-bits-28"), + String::from("ecs-v4-response-bits-29"), + String::from("ecs-v4-response-bits-30"), + String::from("ecs-v4-response-bits-31"), + String::from("ecs-v4-response-bits-32"), + String::from("ecs-v6-response-bits-1"), + String::from("ecs-v6-response-bits-2"), + String::from("ecs-v6-response-bits-3"), + String::from("ecs-v6-response-bits-4"), + String::from("ecs-v6-response-bits-5"), + String::from("ecs-v6-response-bits-6"), + String::from("ecs-v6-response-bits-7"), + String::from("ecs-v6-response-bits-8"), + String::from("ecs-v6-response-bits-9"), + String::from("ecs-v6-response-bits-10"), + String::from("ecs-v6-response-bits-11"), + String::from("ecs-v6-response-bits-12"), + String::from("ecs-v6-response-bits-13"), + String::from("ecs-v6-response-bits-14"), + String::from("ecs-v6-response-bits-15"), + String::from("ecs-v6-response-bits-16"), + String::from("ecs-v6-response-bits-17"), + String::from("ecs-v6-response-bits-18"), + String::from("ecs-v6-response-bits-19"), + String::from("ecs-v6-response-bits-20"), + String::from("ecs-v6-response-bits-21"), + String::from("ecs-v6-response-bits-22"), + String::from("ecs-v6-response-bits-23"), + String::from("ecs-v6-response-bits-24"), + String::from("ecs-v6-response-bits-25"), + String::from("ecs-v6-response-bits-26"), + String::from("ecs-v6-response-bits-27"), + String::from("ecs-v6-response-bits-28"), + String::from("ecs-v6-response-bits-29"), + String::from("ecs-v6-response-bits-30"), + String::from("ecs-v6-response-bits-31"), + String::from("ecs-v6-response-bits-32"), + String::from("ecs-v6-response-bits-33"), + String::from("ecs-v6-response-bits-34"), + String::from("ecs-v6-response-bits-35"), + String::from("ecs-v6-response-bits-36"), + String::from("ecs-v6-response-bits-37"), + String::from("ecs-v6-response-bits-38"), + String::from("ecs-v6-response-bits-39"), + String::from("ecs-v6-response-bits-40"), + String::from("ecs-v6-response-bits-41"), + String::from("ecs-v6-response-bits-42"), + String::from("ecs-v6-response-bits-43"), + String::from("ecs-v6-response-bits-44"), + String::from("ecs-v6-response-bits-45"), + String::from("ecs-v6-response-bits-46"), + String::from("ecs-v6-response-bits-47"), + String::from("ecs-v6-response-bits-48"), + String::from("ecs-v6-response-bits-49"), + String::from("ecs-v6-response-bits-50"), + String::from("ecs-v6-response-bits-51"), + String::from("ecs-v6-response-bits-52"), + String::from("ecs-v6-response-bits-53"), + String::from("ecs-v6-response-bits-54"), + String::from("ecs-v6-response-bits-55"), + String::from("ecs-v6-response-bits-56"), + String::from("ecs-v6-response-bits-57"), + String::from("ecs-v6-response-bits-58"), + String::from("ecs-v6-response-bits-59"), + String::from("ecs-v6-response-bits-60"), + String::from("ecs-v6-response-bits-61"), + String::from("ecs-v6-response-bits-62"), + String::from("ecs-v6-response-bits-63"), + String::from("ecs-v6-response-bits-64"), + String::from("ecs-v6-response-bits-65"), + String::from("ecs-v6-response-bits-66"), + String::from("ecs-v6-response-bits-67"), + String::from("ecs-v6-response-bits-68"), + String::from("ecs-v6-response-bits-69"), + String::from("ecs-v6-response-bits-70"), + String::from("ecs-v6-response-bits-71"), + String::from("ecs-v6-response-bits-72"), + String::from("ecs-v6-response-bits-73"), + String::from("ecs-v6-response-bits-74"), + String::from("ecs-v6-response-bits-75"), + String::from("ecs-v6-response-bits-76"), + String::from("ecs-v6-response-bits-77"), + String::from("ecs-v6-response-bits-78"), + String::from("ecs-v6-response-bits-79"), + String::from("ecs-v6-response-bits-80"), + String::from("ecs-v6-response-bits-81"), + String::from("ecs-v6-response-bits-82"), + String::from("ecs-v6-response-bits-83"), + String::from("ecs-v6-response-bits-84"), + String::from("ecs-v6-response-bits-85"), + String::from("ecs-v6-response-bits-86"), + String::from("ecs-v6-response-bits-87"), + String::from("ecs-v6-response-bits-88"), + String::from("ecs-v6-response-bits-89"), + String::from("ecs-v6-response-bits-90"), + String::from("ecs-v6-response-bits-91"), + String::from("ecs-v6-response-bits-92"), + String::from("ecs-v6-response-bits-93"), + String::from("ecs-v6-response-bits-94"), + String::from("ecs-v6-response-bits-95"), + String::from("ecs-v6-response-bits-96"), + String::from("ecs-v6-response-bits-97"), + String::from("ecs-v6-response-bits-98"), + String::from("ecs-v6-response-bits-99"), + String::from("ecs-v6-response-bits-100"), + String::from("ecs-v6-response-bits-101"), + String::from("ecs-v6-response-bits-102"), + String::from("ecs-v6-response-bits-103"), + String::from("ecs-v6-response-bits-104"), + String::from("ecs-v6-response-bits-105"), + String::from("ecs-v6-response-bits-106"), + String::from("ecs-v6-response-bits-107"), + String::from("ecs-v6-response-bits-108"), + String::from("ecs-v6-response-bits-109"), + String::from("ecs-v6-response-bits-110"), + String::from("ecs-v6-response-bits-111"), + String::from("ecs-v6-response-bits-112"), + String::from("ecs-v6-response-bits-113"), + String::from("ecs-v6-response-bits-114"), + String::from("ecs-v6-response-bits-115"), + String::from("ecs-v6-response-bits-116"), + String::from("ecs-v6-response-bits-117"), + String::from("ecs-v6-response-bits-118"), + String::from("ecs-v6-response-bits-119"), + String::from("ecs-v6-response-bits-120"), + String::from("ecs-v6-response-bits-121"), + String::from("ecs-v6-response-bits-122"), + String::from("ecs-v6-response-bits-123"), + String::from("ecs-v6-response-bits-124"), + String::from("ecs-v6-response-bits-125"), + String::from("ecs-v6-response-bits-126"), + String::from("ecs-v6-response-bits-127"), + String::from("ecs-v6-response-bits-128"), + String::from("cumul-clientanswers"), + String::from("cumul-authanswers"), + String::from("policy-hits"), + String::from("proxy-mapping-total"), + String::from("remote-logger-count"), + ] +} +fn default_value_equal_recursor_stats_rec_control_disabled_list(value: &Vec) -> bool { + let def = default_value_recursor_stats_rec_control_disabled_list(); + &def == value +} + +// DEFAULT HANDLING for recursor_stats_snmp_disabled_list +fn default_value_recursor_stats_snmp_disabled_list() -> Vec { + vec![ + String::from("cache-bytes"), + String::from("packetcache-bytes"), + String::from("special-memory-usage"), + String::from("ecs-v4-response-bits-1"), + String::from("ecs-v4-response-bits-2"), + String::from("ecs-v4-response-bits-3"), + String::from("ecs-v4-response-bits-4"), + String::from("ecs-v4-response-bits-5"), + String::from("ecs-v4-response-bits-6"), + String::from("ecs-v4-response-bits-7"), + String::from("ecs-v4-response-bits-8"), + String::from("ecs-v4-response-bits-9"), + String::from("ecs-v4-response-bits-10"), + String::from("ecs-v4-response-bits-11"), + String::from("ecs-v4-response-bits-12"), + String::from("ecs-v4-response-bits-13"), + String::from("ecs-v4-response-bits-14"), + String::from("ecs-v4-response-bits-15"), + String::from("ecs-v4-response-bits-16"), + String::from("ecs-v4-response-bits-17"), + String::from("ecs-v4-response-bits-18"), + String::from("ecs-v4-response-bits-19"), + String::from("ecs-v4-response-bits-20"), + String::from("ecs-v4-response-bits-21"), + String::from("ecs-v4-response-bits-22"), + String::from("ecs-v4-response-bits-23"), + String::from("ecs-v4-response-bits-24"), + String::from("ecs-v4-response-bits-25"), + String::from("ecs-v4-response-bits-26"), + String::from("ecs-v4-response-bits-27"), + String::from("ecs-v4-response-bits-28"), + String::from("ecs-v4-response-bits-29"), + String::from("ecs-v4-response-bits-30"), + String::from("ecs-v4-response-bits-31"), + String::from("ecs-v4-response-bits-32"), + String::from("ecs-v6-response-bits-1"), + String::from("ecs-v6-response-bits-2"), + String::from("ecs-v6-response-bits-3"), + String::from("ecs-v6-response-bits-4"), + String::from("ecs-v6-response-bits-5"), + String::from("ecs-v6-response-bits-6"), + String::from("ecs-v6-response-bits-7"), + String::from("ecs-v6-response-bits-8"), + String::from("ecs-v6-response-bits-9"), + String::from("ecs-v6-response-bits-10"), + String::from("ecs-v6-response-bits-11"), + String::from("ecs-v6-response-bits-12"), + String::from("ecs-v6-response-bits-13"), + String::from("ecs-v6-response-bits-14"), + String::from("ecs-v6-response-bits-15"), + String::from("ecs-v6-response-bits-16"), + String::from("ecs-v6-response-bits-17"), + String::from("ecs-v6-response-bits-18"), + String::from("ecs-v6-response-bits-19"), + String::from("ecs-v6-response-bits-20"), + String::from("ecs-v6-response-bits-21"), + String::from("ecs-v6-response-bits-22"), + String::from("ecs-v6-response-bits-23"), + String::from("ecs-v6-response-bits-24"), + String::from("ecs-v6-response-bits-25"), + String::from("ecs-v6-response-bits-26"), + String::from("ecs-v6-response-bits-27"), + String::from("ecs-v6-response-bits-28"), + String::from("ecs-v6-response-bits-29"), + String::from("ecs-v6-response-bits-30"), + String::from("ecs-v6-response-bits-31"), + String::from("ecs-v6-response-bits-32"), + String::from("ecs-v6-response-bits-33"), + String::from("ecs-v6-response-bits-34"), + String::from("ecs-v6-response-bits-35"), + String::from("ecs-v6-response-bits-36"), + String::from("ecs-v6-response-bits-37"), + String::from("ecs-v6-response-bits-38"), + String::from("ecs-v6-response-bits-39"), + String::from("ecs-v6-response-bits-40"), + String::from("ecs-v6-response-bits-41"), + String::from("ecs-v6-response-bits-42"), + String::from("ecs-v6-response-bits-43"), + String::from("ecs-v6-response-bits-44"), + String::from("ecs-v6-response-bits-45"), + String::from("ecs-v6-response-bits-46"), + String::from("ecs-v6-response-bits-47"), + String::from("ecs-v6-response-bits-48"), + String::from("ecs-v6-response-bits-49"), + String::from("ecs-v6-response-bits-50"), + String::from("ecs-v6-response-bits-51"), + String::from("ecs-v6-response-bits-52"), + String::from("ecs-v6-response-bits-53"), + String::from("ecs-v6-response-bits-54"), + String::from("ecs-v6-response-bits-55"), + String::from("ecs-v6-response-bits-56"), + String::from("ecs-v6-response-bits-57"), + String::from("ecs-v6-response-bits-58"), + String::from("ecs-v6-response-bits-59"), + String::from("ecs-v6-response-bits-60"), + String::from("ecs-v6-response-bits-61"), + String::from("ecs-v6-response-bits-62"), + String::from("ecs-v6-response-bits-63"), + String::from("ecs-v6-response-bits-64"), + String::from("ecs-v6-response-bits-65"), + String::from("ecs-v6-response-bits-66"), + String::from("ecs-v6-response-bits-67"), + String::from("ecs-v6-response-bits-68"), + String::from("ecs-v6-response-bits-69"), + String::from("ecs-v6-response-bits-70"), + String::from("ecs-v6-response-bits-71"), + String::from("ecs-v6-response-bits-72"), + String::from("ecs-v6-response-bits-73"), + String::from("ecs-v6-response-bits-74"), + String::from("ecs-v6-response-bits-75"), + String::from("ecs-v6-response-bits-76"), + String::from("ecs-v6-response-bits-77"), + String::from("ecs-v6-response-bits-78"), + String::from("ecs-v6-response-bits-79"), + String::from("ecs-v6-response-bits-80"), + String::from("ecs-v6-response-bits-81"), + String::from("ecs-v6-response-bits-82"), + String::from("ecs-v6-response-bits-83"), + String::from("ecs-v6-response-bits-84"), + String::from("ecs-v6-response-bits-85"), + String::from("ecs-v6-response-bits-86"), + String::from("ecs-v6-response-bits-87"), + String::from("ecs-v6-response-bits-88"), + String::from("ecs-v6-response-bits-89"), + String::from("ecs-v6-response-bits-90"), + String::from("ecs-v6-response-bits-91"), + String::from("ecs-v6-response-bits-92"), + String::from("ecs-v6-response-bits-93"), + String::from("ecs-v6-response-bits-94"), + String::from("ecs-v6-response-bits-95"), + String::from("ecs-v6-response-bits-96"), + String::from("ecs-v6-response-bits-97"), + String::from("ecs-v6-response-bits-98"), + String::from("ecs-v6-response-bits-99"), + String::from("ecs-v6-response-bits-100"), + String::from("ecs-v6-response-bits-101"), + String::from("ecs-v6-response-bits-102"), + String::from("ecs-v6-response-bits-103"), + String::from("ecs-v6-response-bits-104"), + String::from("ecs-v6-response-bits-105"), + String::from("ecs-v6-response-bits-106"), + String::from("ecs-v6-response-bits-107"), + String::from("ecs-v6-response-bits-108"), + String::from("ecs-v6-response-bits-109"), + String::from("ecs-v6-response-bits-110"), + String::from("ecs-v6-response-bits-111"), + String::from("ecs-v6-response-bits-112"), + String::from("ecs-v6-response-bits-113"), + String::from("ecs-v6-response-bits-114"), + String::from("ecs-v6-response-bits-115"), + String::from("ecs-v6-response-bits-116"), + String::from("ecs-v6-response-bits-117"), + String::from("ecs-v6-response-bits-118"), + String::from("ecs-v6-response-bits-119"), + String::from("ecs-v6-response-bits-120"), + String::from("ecs-v6-response-bits-121"), + String::from("ecs-v6-response-bits-122"), + String::from("ecs-v6-response-bits-123"), + String::from("ecs-v6-response-bits-124"), + String::from("ecs-v6-response-bits-125"), + String::from("ecs-v6-response-bits-126"), + String::from("ecs-v6-response-bits-127"), + String::from("ecs-v6-response-bits-128"), + String::from("cumul-clientanswers"), + String::from("cumul-authanswers"), + String::from("policy-hits"), + String::from("proxy-mapping-total"), + String::from("remote-logger-count"), + ] +} +fn default_value_equal_recursor_stats_snmp_disabled_list(value: &Vec) -> bool { + let def = default_value_recursor_stats_snmp_disabled_list(); + &def == value +} + +// DEFAULT HANDLING for recursor_version_string +fn default_value_recursor_version_string() -> String { + String::from("*runtime determined*") +} +fn default_value_equal_recursor_version_string(value: &str)-> bool { + value == default_value_recursor_version_string() +} + +// DEFAULT HANDLING for recursor_sortlists +fn default_value_recursor_sortlists() -> Vec { + let msg = "default value defined for `recursor_sortlists' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_sortlists(value: &Vec)-> bool { + let def = default_value_recursor_sortlists(); + &def == value +} + +// DEFAULT HANDLING for recursor_rpzs +fn default_value_recursor_rpzs() -> Vec { + let msg = "default value defined for `recursor_rpzs' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_rpzs(value: &Vec)-> bool { + let def = default_value_recursor_rpzs(); + &def == value +} + +// DEFAULT HANDLING for recursor_allowed_additional_qtypes +fn default_value_recursor_allowed_additional_qtypes() -> Vec { + let msg = "default value defined for `recursor_allowed_additional_qtypes' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_allowed_additional_qtypes(value: &Vec)-> bool { + let def = default_value_recursor_allowed_additional_qtypes(); + &def == value +} + +// DEFAULT HANDLING for recursor_forwarding_catalog_zones +fn default_value_recursor_forwarding_catalog_zones() -> Vec { + let msg = "default value defined for `recursor_forwarding_catalog_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recursor_forwarding_catalog_zones(value: &Vec)-> bool { + let def = default_value_recursor_forwarding_catalog_zones(); + &def == value +} + +// DEFAULT HANDLING for outgoing_dont_throttle_names +fn default_value_outgoing_dont_throttle_names() -> Vec { + vec![ + ] +} +fn default_value_equal_outgoing_dont_throttle_names(value: &Vec) -> bool { + let def = default_value_outgoing_dont_throttle_names(); + &def == value +} + +// DEFAULT HANDLING for outgoing_dont_throttle_netmasks +fn default_value_outgoing_dont_throttle_netmasks() -> Vec { + vec![ + ] +} +fn default_value_equal_outgoing_dont_throttle_netmasks(value: &Vec) -> bool { + let def = default_value_outgoing_dont_throttle_netmasks(); + &def == value +} + +// DEFAULT HANDLING for outgoing_dot_to_auth_names +fn default_value_outgoing_dot_to_auth_names() -> Vec { + vec![ + ] +} +fn default_value_equal_outgoing_dot_to_auth_names(value: &Vec) -> bool { + let def = default_value_outgoing_dot_to_auth_names(); + &def == value +} + +// DEFAULT HANDLING for outgoing_dont_query +fn default_value_outgoing_dont_query() -> Vec { + vec![ + String::from("127.0.0.0/8"), + String::from("10.0.0.0/8"), + String::from("100.64.0.0/10"), + String::from("169.254.0.0/16"), + String::from("192.168.0.0/16"), + String::from("172.16.0.0/12"), + String::from("::1/128"), + String::from("fc00::/7"), + String::from("fe80::/10"), + String::from("0.0.0.0/8"), + String::from("192.0.0.0/24"), + String::from("192.0.2.0/24"), + String::from("198.51.100.0/24"), + String::from("203.0.113.0/24"), + String::from("240.0.0.0/4"), + String::from("::/96"), + String::from("::ffff:0:0/96"), + String::from("100::/64"), + String::from("2001:db8::/32"), + ] +} +fn default_value_equal_outgoing_dont_query(value: &Vec) -> bool { + let def = default_value_outgoing_dont_query(); + &def == value +} + +// DEFAULT HANDLING for outgoing_edns_subnet_allow_list +fn default_value_outgoing_edns_subnet_allow_list() -> Vec { + vec![ + ] +} +fn default_value_equal_outgoing_edns_subnet_allow_list(value: &Vec) -> bool { + let def = default_value_outgoing_edns_subnet_allow_list(); + &def == value +} + +// DEFAULT HANDLING for outgoing_source_address +fn default_value_outgoing_source_address() -> Vec { + vec![ + String::from("0.0.0.0"), + ] +} +fn default_value_equal_outgoing_source_address(value: &Vec) -> bool { + let def = default_value_outgoing_source_address(); + &def == value +} + +// DEFAULT HANDLING for outgoing_udp_source_port_avoid +fn default_value_outgoing_udp_source_port_avoid() -> Vec { + vec![ + String::from("4791"), + String::from("11211"), + ] +} +fn default_value_equal_outgoing_udp_source_port_avoid(value: &Vec) -> bool { + let def = default_value_outgoing_udp_source_port_avoid(); + &def == value +} + +// DEFAULT HANDLING for outgoing_cookies_unsupported +fn default_value_outgoing_cookies_unsupported() -> Vec { + vec![ + ] +} +fn default_value_equal_outgoing_cookies_unsupported(value: &Vec) -> bool { + let def = default_value_outgoing_cookies_unsupported(); + &def == value +} + +// DEFAULT HANDLING for outgoing_tls_configurations +fn default_value_outgoing_tls_configurations() -> Vec { + let msg = "default value defined for `outgoing_tls_configurations' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_outgoing_tls_configurations(value: &Vec)-> bool { + let def = default_value_outgoing_tls_configurations(); + &def == value +} + +// DEFAULT HANDLING for webservice_address +fn default_value_webservice_address() -> String { + String::from("127.0.0.1") +} +fn default_value_equal_webservice_address(value: &str)-> bool { + value == default_value_webservice_address() +} + +// DEFAULT HANDLING for webservice_listen +fn default_value_webservice_listen() -> Vec { + let msg = "default value defined for `webservice_listen' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_webservice_listen(value: &Vec)-> bool { + let def = default_value_webservice_listen(); + &def == value +} + +// DEFAULT HANDLING for webservice_allow_from +fn default_value_webservice_allow_from() -> Vec { + vec![ + String::from("127.0.0.1"), + String::from("::1"), + ] +} +fn default_value_equal_webservice_allow_from(value: &Vec) -> bool { + let def = default_value_webservice_allow_from(); + &def == value +} + +// DEFAULT HANDLING for webservice_loglevel +fn default_value_webservice_loglevel() -> String { + String::from("normal") +} +fn default_value_equal_webservice_loglevel(value: &str)-> bool { + value == default_value_webservice_loglevel() +} + +// DEFAULT HANDLING for carbon_ns +fn default_value_carbon_ns() -> String { + String::from("pdns") +} +fn default_value_equal_carbon_ns(value: &str)-> bool { + value == default_value_carbon_ns() +} + +// DEFAULT HANDLING for carbon_instance +fn default_value_carbon_instance() -> String { + String::from("recursor") +} +fn default_value_equal_carbon_instance(value: &str)-> bool { + value == default_value_carbon_instance() +} + +// DEFAULT HANDLING for carbon_server +fn default_value_carbon_server() -> Vec { + vec![ + ] +} +fn default_value_equal_carbon_server(value: &Vec) -> bool { + let def = default_value_carbon_server(); + &def == value +} + +// DEFAULT HANDLING for logging_structured_logging_backend +fn default_value_logging_structured_logging_backend() -> String { + String::from("default") +} +fn default_value_equal_logging_structured_logging_backend(value: &str)-> bool { + value == default_value_logging_structured_logging_backend() +} + +// DEFAULT HANDLING for logging_trace +fn default_value_logging_trace() -> String { + String::from("no") +} +fn default_value_equal_logging_trace(value: &str)-> bool { + value == default_value_logging_trace() +} + +// DEFAULT HANDLING for logging_protobuf_servers +fn default_value_logging_protobuf_servers() -> Vec { + let msg = "default value defined for `logging_protobuf_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_logging_protobuf_servers(value: &Vec)-> bool { + let def = default_value_logging_protobuf_servers(); + &def == value +} + +// DEFAULT HANDLING for logging_outgoing_protobuf_servers +fn default_value_logging_outgoing_protobuf_servers() -> Vec { + let msg = "default value defined for `logging_outgoing_protobuf_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_logging_outgoing_protobuf_servers(value: &Vec)-> bool { + let def = default_value_logging_outgoing_protobuf_servers(); + &def == value +} + +// DEFAULT HANDLING for logging_dnstap_framestream_servers +fn default_value_logging_dnstap_framestream_servers() -> Vec { + let msg = "default value defined for `logging_dnstap_framestream_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_logging_dnstap_framestream_servers(value: &Vec)-> bool { + let def = default_value_logging_dnstap_framestream_servers(); + &def == value +} + +// DEFAULT HANDLING for logging_dnstap_nod_framestream_servers +fn default_value_logging_dnstap_nod_framestream_servers() -> Vec { + let msg = "default value defined for `logging_dnstap_nod_framestream_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_logging_dnstap_nod_framestream_servers(value: &Vec)-> bool { + let def = default_value_logging_dnstap_nod_framestream_servers(); + &def == value +} + +// DEFAULT HANDLING for logging_opentelemetry_trace_conditions +fn default_value_logging_opentelemetry_trace_conditions() -> Vec { + let msg = "default value defined for `logging_opentelemetry_trace_conditions' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_logging_opentelemetry_trace_conditions(value: &Vec)-> bool { + let def = default_value_logging_opentelemetry_trace_conditions(); + &def == value +} + +// DEFAULT HANDLING for ecs_add_for +fn default_value_ecs_add_for() -> Vec { + vec![ + String::from("0.0.0.0/0"), + String::from("::/0"), + String::from("!127.0.0.0/8"), + String::from("!10.0.0.0/8"), + String::from("!100.64.0.0/10"), + String::from("!169.254.0.0/16"), + String::from("!192.168.0.0/16"), + String::from("!172.16.0.0/12"), + String::from("!::1/128"), + String::from("!fc00::/7"), + String::from("!fe80::/10"), + ] +} +fn default_value_equal_ecs_add_for(value: &Vec) -> bool { + let def = default_value_ecs_add_for(); + &def == value +} + +// DEFAULT HANDLING for recordcache_zonetocaches +fn default_value_recordcache_zonetocaches() -> Vec { + let msg = "default value defined for `recordcache_zonetocaches' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); + deserialized +} +fn default_value_equal_recordcache_zonetocaches(value: &Vec)-> bool { + let def = default_value_recordcache_zonetocaches(); + &def == value +} + +// DEFAULT HANDLING for nod_history_dir +fn default_value_nod_history_dir() -> String { + String::from(env!("NODCACHEDIRNOD")) +} +fn default_value_equal_nod_history_dir(value: &str)-> bool { + value == default_value_nod_history_dir() +} + +// DEFAULT HANDLING for nod_ignore_list +fn default_value_nod_ignore_list() -> Vec { + vec![ + ] +} +fn default_value_equal_nod_ignore_list(value: &Vec) -> bool { + let def = default_value_nod_ignore_list(); + &def == value +} + +// DEFAULT HANDLING for nod_pb_tag +fn default_value_nod_pb_tag() -> String { + String::from("pdns-nod") +} +fn default_value_equal_nod_pb_tag(value: &str)-> bool { + value == default_value_nod_pb_tag() +} + +// DEFAULT HANDLING for nod_unique_response_history_dir +fn default_value_nod_unique_response_history_dir() -> String { + String::from(env!("NODCACHEDIRUDR")) +} +fn default_value_equal_nod_unique_response_history_dir(value: &str)-> bool { + value == default_value_nod_unique_response_history_dir() +} + +// DEFAULT HANDLING for nod_unique_response_pb_tag +fn default_value_nod_unique_response_pb_tag() -> String { + String::from("pdns-udr") +} +fn default_value_equal_nod_unique_response_pb_tag(value: &str)-> bool { + value == default_value_nod_unique_response_pb_tag() +} + +// DEFAULT HANDLING for nod_unique_response_ignore_list +fn default_value_nod_unique_response_ignore_list() -> Vec { + vec![ + ] +} +fn default_value_equal_nod_unique_response_ignore_list(value: &Vec) -> bool { + let def = default_value_nod_unique_response_ignore_list(); + &def == value +} + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/misc.rs pdns-recursor-5.4.9/rec-rust-lib/rust/src/misc.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/misc.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/misc.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#[cxx::bridge(namespace = "pdns::rust::misc")] +pub mod rustmisc { + + pub enum LogLevel { + None, + Normal, + Detailed, + } + enum Priority { + Absent = 0, + Alert = 1, + Critical = 2, + Error = 3, + Warning = 4, + Notice = 5, + Info = 6, + Debug = 7, + } + struct KeyValue { + key: String, + value: String, + } + + extern "C++" { + type NetmaskGroup; + type ComboAddress; + type Logger; + } + + unsafe extern "C++" { + include!("bridge.hh"); + fn qTypeStringToCode(name: &str) -> u16; + fn isValidHostname(name: &str) -> bool; + fn comboaddress(address: &str) -> UniquePtr; + fn matches(nmg: &UniquePtr, address: &UniquePtr) -> bool; // match is a keyword + fn withValue(logger: &SharedPtr, key: &str, val: &str) -> SharedPtr; + fn log(logger: &SharedPtr, prio: Priority, msg: &str, values: &Vec); + fn error( + logger: &SharedPtr, + prio: Priority, + err: &str, + msg: &str, + values: &Vec, + ); + fn getUUID() -> String; + } +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust/src/web.rs pdns-recursor-5.4.9/rec-rust-lib/rust/src/web.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust/src/web.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust/src/web.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,1234 @@ +/* + * 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. + */ + +/* +TODO +- Table based routing? +- Ripping out yahttp stuff, providing some basic classes only. ATM we do use a few yahttp include files (but no .cc) +- Some classes (NetmaskGroup, ComboAddress) need a UniquePtr Wrapper to keep them opaque (iputils + cannot be included without big headaches in bridge.hh at the moment). We could separate + NetmaskGroup, but I expect ComboAddress to not work as it is union. +- Avoid unsafe? Can it be done? +*/ + +use std::net::SocketAddr; + +use base64::prelude::*; +use bytes::Bytes; +use http_body_util::{BodyExt, Full}; +use hyper::server::conn::http1; +use hyper::service::service_fn; +use hyper::{body::Incoming as IncomingBody, header, Method, Request, Response, StatusCode}; +use hyper::body::Body; +use hyper_util::rt::TokioIo; +use pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer}; +use std::str::FromStr; +use std::sync::Arc; +use tokio::net::TcpListener; +use tokio::runtime::Builder; +use tokio::task::JoinSet; + +use crate::misc::rustmisc; + +type GenericError = Box; +type MyResult = std::result::Result; +type BoxBody = http_body_util::combinators::BoxBody; + +static NOTFOUND: &[u8] = b"Not Found"; + +fn full>(chunk: T) -> BoxBody { + Full::new(chunk.into()) + .map_err(|never| match never {}) + .boxed() +} + +type Func = fn(&rustweb::Request, &mut rustweb::Response) -> Result<(), cxx::Exception>; + +fn compare_authorization(ctx: &Context, reqheaders: &header::HeaderMap) -> bool { + let mut auth_ok = false; + if !ctx.password_ch.is_null() { + if let Some(authorization) = reqheaders.get("authorization") { + let mut lcase = authorization.as_bytes().to_owned(); + lcase.make_ascii_lowercase(); + if lcase.starts_with(b"basic ") { + let cookie = &authorization.as_bytes()[6..]; + if let Ok(plain) = BASE64_STANDARD.decode(cookie) { + let mut split = plain.split(|i| *i == b':'); + if split.next().is_some() { + if let Some(split) = split.next() { + cxx::let_cxx_string!(s = &split); + if let Some(pw) = ctx.password_ch.as_ref() { + auth_ok = pw.matches(&s); + } + } + } + } + } + } + } else { + auth_ok = true; + } + auth_ok +} + +fn unauthorized(response: &mut rustweb::Response, headers: &mut header::HeaderMap, auth: &str) { + let status = StatusCode::UNAUTHORIZED; + response.status = status.as_u16(); + let val = format!("{} realm=\"PowerDNS\"", auth); + if let Ok(data) = header::HeaderValue::from_str(&val) { + headers.insert(header::WWW_AUTHENTICATE, data); + } + if let Some(body) = status.canonical_reason() { + response.body = body.as_bytes().to_vec(); + } +} + +fn nonapi_wrapper( + ctx: &Context, + handler: Func, + request: &rustweb::Request, + response: &mut rustweb::Response, + reqheaders: &header::HeaderMap, + headers: &mut header::HeaderMap, +) { + let auth_ok = compare_authorization(ctx, reqheaders); + if !auth_ok { + rustmisc::log( + request.logger, + rustweb::Priority::Debug, + "Authentication failed", + &vec![rustmisc::KeyValue { + key: "urlpath".to_string(), + value: request.uri.to_owned(), + }], + ); + unauthorized(response, headers, "Basic"); + return; + } + match handler(request, response) { + Ok(_) => {} + Err(_) => { + let status = StatusCode::UNPROCESSABLE_ENTITY; // 422 + response.status = status.as_u16(); + if let Some(body) = status.canonical_reason() { + response.body = body.as_bytes().to_vec(); + } + } + } +} + +#[allow(clippy::too_many_arguments)] +fn file_wrapper( + ctx: &Context, + handler: FileFunc, + method: &Method, + path: &str, + request: &rustweb::Request, + response: &mut rustweb::Response, + reqheaders: &header::HeaderMap, + headers: &mut header::HeaderMap, +) { + let auth_ok = compare_authorization(ctx, reqheaders); + if !auth_ok { + rustmisc::log( + request.logger, + rustweb::Priority::Debug, + "Authentication failed", + &vec![rustmisc::KeyValue { + key: "urlpath".to_string(), + value: request.uri.to_owned(), + }], + ); + unauthorized(response, headers, "Basic"); + return; + } + handler(method, path, request, response); +} + +#[allow(clippy::too_many_arguments)] +fn api_wrapper( + logger: &cxx::SharedPtr, + ctx: &Context, + handler: Func, + request: &rustweb::Request, + response: &mut rustweb::Response, + reqheaders: &header::HeaderMap, + headers: &mut header::HeaderMap, + allow_password: bool, +) { + // security headers + headers.insert( + header::ACCESS_CONTROL_ALLOW_ORIGIN, + header::HeaderValue::from_static("*"), + ); + + // XXX AUDIT! + + let mut auth_ok = false; + if !ctx.api_ch.is_null() { + if let Some(api) = reqheaders.get("x-api-key") { + cxx::let_cxx_string!(s = &api.as_bytes()); + if let Some(pw) = ctx.api_ch.as_ref() { + auth_ok = pw.matches(&s); + } + } + } + + if !auth_ok && allow_password { + auth_ok = compare_authorization(ctx, reqheaders); + if !auth_ok { + rustmisc::log( + logger, + rustweb::Priority::Debug, + "Authentication failed", + &vec![rustmisc::KeyValue { + key: "urlpath".to_string(), + value: request.uri.to_owned(), + }], + ); + unauthorized(response, headers, "Basic"); + return; + } + } + if !auth_ok { + if ctx.api_ch.is_null() { + rustmisc::log( + logger, + rustweb::Priority::Error, + "Authentication failed, API Key missing in config", + &vec![rustmisc::KeyValue { + key: "urlpath".to_string(), + value: request.uri.to_owned(), + }], + ); + unauthorized(response, headers, "X-API-Key"); + return; + } + + rustmisc::log( + logger, + rustweb::Priority::Error, + "Authentication failed", + &vec![rustmisc::KeyValue { + key: "urlpath".to_string(), + value: request.uri.to_owned(), + }], + ); + unauthorized(response, headers, "X-API-Key"); + return; + } + response.status = StatusCode::OK.as_u16(); // 200; + + headers.insert( + header::X_CONTENT_TYPE_OPTIONS, + header::HeaderValue::from_static("nosniff"), + ); + headers.insert( + header::X_FRAME_OPTIONS, + header::HeaderValue::from_static("deny"), + ); + headers.insert( + header::HeaderName::from_static("x-permitted-cross-domain-policies"), + header::HeaderValue::from_static("none"), + ); + headers.insert( + header::X_XSS_PROTECTION, + header::HeaderValue::from_static("1; mode=block"), + ); + headers.insert( + header::CONTENT_SECURITY_POLICY, + header::HeaderValue::from_static("default-src 'self'; style-src 'self' 'unsafe-inline'"), + ); + + // This calls into C++ + match handler(request, response) { + Ok(_) => {} + Err(_) => { + let status = StatusCode::UNPROCESSABLE_ENTITY; // 422 + response.status = status.as_u16(); + if let Some(body) = status.canonical_reason() { + response.body = body.as_bytes().to_vec(); + } + } + } +} + +// Data used by requests handlers, if you add a r/w variable, make sure it's safe for concurrent access! +struct Context { + password_ch: cxx::UniquePtr, + api_ch: cxx::UniquePtr, + acl: cxx::UniquePtr, + logger: cxx::SharedPtr, + loglevel: rustmisc::LogLevel, + max_request_size: u64, +} + +// Serve a file +fn file(method: &Method, path: &str, request: &rustweb::Request, response: &mut rustweb::Response) { + // This calls into C++ + if rustweb::serveStuff(request, response).is_err() { + // Return 404 not found response. + response.status = StatusCode::NOT_FOUND.as_u16(); + response.body = NOTFOUND.to_vec(); + rustmisc::log( + request.logger, + rustweb::Priority::Debug, + "Not found", + &vec![ + rustmisc::KeyValue { + key: "method".to_string(), + value: method.to_string(), + }, + rustmisc::KeyValue { + key: "path".to_string(), + value: path.to_string(), + }, + ], + ); + } +} + +type FileFunc = + fn(method: &Method, path: &str, request: &rustweb::Request, response: &mut rustweb::Response); + +// Match a request and return the function that implements it, this should probably be table based. +fn matcher( + method: &Method, + path: &str, + apifunc: &mut Option, + rawfunc: &mut Option, + filefunc: &mut Option, + allow_password: &mut bool, + request: &mut rustweb::Request, +) { + let path: Vec<_> = path.split('/').skip(1).collect(); + match (method, &*path) { + (&Method::GET, ["jsonstat"]) => { + *allow_password = true; + *apifunc = Some(rustweb::jsonstat); + } + (&Method::PUT, ["api", "v1", "servers", "localhost", "cache", "flush"]) => { + *apifunc = Some(rustweb::apiServerCacheFlush) + } + (&Method::PUT, ["api", "v1", "servers", "localhost", "config", "allow-from"]) => { + *apifunc = Some(rustweb::apiServerConfigAllowFromPUT) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "config", "allow-from"]) => { + *apifunc = Some(rustweb::apiServerConfigAllowFromGET) + } + (&Method::PUT, ["api", "v1", "servers", "localhost", "config", "allow-notify-from"]) => { + *apifunc = Some(rustweb::apiServerConfigAllowNotifyFromPUT) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "config", "allow-notify-from"]) => { + *apifunc = Some(rustweb::apiServerConfigAllowNotifyFromGET) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "config"]) => { + *apifunc = Some(rustweb::apiServerConfig) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "rpzstatistics"]) => { + *apifunc = Some(rustweb::apiServerRPZStats) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "search-data"]) => { + *apifunc = Some(rustweb::apiServerSearchData) + } + (&Method::GET, ["api", "v1", "servers", "localhost", "zones", id]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("id"), + value: String::from(*id), + }); + *apifunc = Some(rustweb::apiServerZoneDetailGET); + } + (&Method::PUT, ["api", "v1", "servers", "localhost", "zones", id]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("id"), + value: String::from(*id), + }); + *apifunc = Some(rustweb::apiServerZoneDetailPUT); + } + (&Method::DELETE, ["api", "v1", "servers", "localhost", "zones", id]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("id"), + value: String::from(*id), + }); + *apifunc = Some(rustweb::apiServerZoneDetailDELETE); + } + (&Method::GET, ["api", "v1", "servers", "localhost", "statistics"]) => { + *allow_password = true; + *apifunc = Some(rustweb::apiServerStatistics); + } + (&Method::GET, ["api", "v1", "servers", "localhost", "zones"]) => { + *apifunc = Some(rustweb::apiServerZonesGET) + } + (&Method::POST, ["api", "v1", "servers", "localhost", "zones"]) => { + *apifunc = Some(rustweb::apiServerZonesPOST) + } + (&Method::GET, ["api", "v1", "servers", "localhost"]) => { + *allow_password = true; + *apifunc = Some(rustweb::apiServerDetail); + } + (&Method::GET, ["api", "v1", "servers"]) => *apifunc = Some(rustweb::apiServer), + (&Method::GET, ["api", "v1"]) => *apifunc = Some(rustweb::apiDiscoveryV1), + (&Method::GET, ["api"]) => *apifunc = Some(rustweb::apiDiscovery), + (&Method::GET, ["metrics"]) => *rawfunc = Some(rustweb::prometheusMetrics), + (&Method::GET, ["api", "v1", "servers", "localhost", "ottraceconditions"]) => { + *apifunc = Some(rustweb::apiServerOTConditionsGET); + } + (&Method::GET, ["api", "v1", "servers", "localhost", "ottraceconditions", ip, pflen]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("acl"), + value: String::from(*ip) + "/" + *pflen, + }); + *apifunc = Some(rustweb::apiServerOTConditionDetailGET) + } + (&Method::DELETE, ["api", "v1", "servers", "localhost", "ottraceconditions", ip, pflen]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("acl"), + value: String::from(*ip) + "/" + *pflen, + }); + *apifunc = Some(rustweb::apiServerOTConditionDetailDELETE) + } + (&Method::POST, ["api", "v1", "servers", "localhost", "ottraceconditions"]) => { + *apifunc = Some(rustweb::apiServerOTConditionDetailPOST) + } + _ => *filefunc = Some(file), + } +} + +// This constructs the answer to an OPTIONS query +fn collect_options( + path: &str, + response: &mut rustweb::Response, + my_logger: &cxx::SharedPtr, +) { + let mut methods = vec![]; + for method in [Method::GET, Method::POST, Method::PUT, Method::DELETE] { + let mut apifunc: Option = None; + let mut rawfunc: Option<_> = None; + let mut filefunc: Option<_> = None; + let mut allow_password = false; + let mut request = rustweb::Request { + body: vec![], + uri: String::from(""), + vars: vec![], + parameters: vec![], + logger: my_logger, + }; + matcher( + &method, + path, + &mut apifunc, + &mut rawfunc, + &mut filefunc, + &mut allow_password, + &mut request, + ); + if apifunc.is_some() || rawfunc.is_some() + /* || filefunc.is_some() */ + { + methods.push(method.to_string()); + } + } + if methods.is_empty() { + response.status = 404; + return; + } + response.status = 200; + methods.push(Method::OPTIONS.to_string()); + response.headers.push(rustweb::KeyValue { + key: String::from("access-control-allow-origin"), + value: String::from("*"), + }); + response.headers.push(rustweb::KeyValue { + key: String::from("access-control-allow-headers"), + value: String::from("Content-Type, X-API-Key"), + }); + response.headers.push(rustweb::KeyValue { + key: String::from("access-control-max-age"), + value: String::from("3600"), + }); + response.headers.push(rustweb::KeyValue { + key: String::from("access-control-allow-methods"), + value: methods.join(", "), + }); + response.headers.push(rustweb::KeyValue { + key: String::from("content-type"), + value: String::from("text/plain"), + }); +} + +fn log_request(loglevel: rustmisc::LogLevel, request: &rustweb::Request, remote: SocketAddr) { + if loglevel != rustmisc::LogLevel::Detailed { + return; + } + let body = std::str::from_utf8(&request.body).unwrap_or("error: body is not utf8"); + let mut vec = vec![ + rustmisc::KeyValue { + key: "remote".to_string(), + value: remote.to_string(), + }, + rustmisc::KeyValue { + key: "body".to_string(), + value: body.to_string(), + }, + ]; + let mut first = true; + let mut str = "".to_string(); + for var in &request.vars { + if !first { + str.push(' '); + } + first = false; + let snippet = var.key.to_owned() + "=" + &var.value; + str.push_str(&snippet); + } + vec.push(rustmisc::KeyValue { + key: "getVars".to_string(), + value: str.to_string(), + }); + rustmisc::log( + request.logger, + rustmisc::Priority::Info, + "Request details", + &vec, + ); +} + +fn log_response( + loglevel: rustmisc::LogLevel, + logger: &cxx::SharedPtr, + response: &rustweb::Response, + remote: SocketAddr, +) { + if loglevel != rustmisc::LogLevel::Detailed { + return; + } + let body = std::str::from_utf8(&response.body).unwrap_or("error: body is not utf8"); + let mut vec = vec![ + rustmisc::KeyValue { + key: "remote".to_string(), + value: remote.to_string(), + }, + rustmisc::KeyValue { + key: "body".to_string(), + value: body.to_string(), + }, + ]; + let mut first = true; + let mut str = "".to_string(); + for var in &response.headers { + if !first { + str.push(' '); + } + first = false; + let snippet = var.key.to_owned() + "=" + &var.value; + str.push_str(&snippet); + } + vec.push(rustmisc::KeyValue { + key: "headers".to_string(), + value: str.to_string(), + }); + rustmisc::log(logger, rustmisc::Priority::Info, "Response details", &vec); +} + +// Main entry point after a request arrived +async fn process_request( + rust_request: Request, + ctx: Arc, + remote: SocketAddr, +) -> MyResult> { + let unique = rustmisc::getUUID(); + let my_logger = rustmisc::withValue(&ctx.logger, "uniqueid", &unique); + + // Convert query part of URI into vars table + let mut vars: Vec = vec![]; + if let Some(query) = rust_request.uri().query() { + for (k, v) in form_urlencoded::parse(query.as_bytes()) { + if k == "_" { + // jQuery cache buster + continue; + } + let kv = rustweb::KeyValue { + key: k.to_string(), + value: v.to_string(), + }; + vars.push(kv); + } + } + + // Fill request and response structs with default values. + let mut request = rustweb::Request { + body: vec![], + uri: rust_request.uri().to_string(), + vars, + parameters: vec![], + logger: &my_logger, + }; + + log_request(ctx.loglevel, &request, remote); + + let mut response = rustweb::Response { + status: 0, + body: vec![], + headers: vec![], + }; + let mut apifunc: Option = None; + let mut rawfunc: Option<_> = None; + let mut filefunc: Option<_> = None; + let method = rust_request.method().to_owned(); + let mut allow_password = false; + let mut rust_response = Response::builder(); + + let path = rust_request.uri().path().to_owned(); + let version = rust_request.version().to_owned(); + + if method == Method::OPTIONS { + collect_options(&path, &mut response, &my_logger); + } else { + // Find the right function implementing what the request wants + let mut matchmethod = method.clone(); + if method == Method::HEAD { + matchmethod = Method::GET; + } + matcher( + &matchmethod, + &path, + &mut apifunc, + &mut rawfunc, + &mut filefunc, + &mut allow_password, + &mut request, + ); + + if let Some(func) = apifunc { + let reqheaders = rust_request.headers().clone(); + if rust_request.method() == Method::POST || rust_request.method() == Method::PUT { + let body_size = rust_request.size_hint().upper(); + // From observation, hyper handles invalid or missing content length in a safe way + // by making the value 0. The actual body collect() is limited by the promised + // content length in the request + if body_size.is_none_or(|x| x > ctx.max_request_size) { + let mut body = vec![]; + let status = StatusCode::PAYLOAD_TOO_LARGE; // 413 + if let Some(reason) = status.canonical_reason() { + body = reason.as_bytes().to_vec(); + } + if ctx.loglevel != rustmisc::LogLevel::None { + let version = format!("{:?}", version); + rustmisc::log( + &my_logger, + rustweb::Priority::Warning, + "Request", + &vec![ + rustmisc::KeyValue { + key: "remote".to_string(), + value: remote.to_string(), + }, + rustmisc::KeyValue { + key: "method".to_string(), + value: method.to_string(), + }, + rustmisc::KeyValue { + key: "urlpath".to_string(), + value: path.to_string(), + }, + rustmisc::KeyValue { + key: "HTTPVersion".to_string(), + value: version, + }, + rustmisc::KeyValue { + key: "status".to_string(), + value: status.as_u16().to_string(), + }, + rustmisc::KeyValue { + key: "respsize".to_string(), + value: body.len().to_string(), + }, + ], + ); + } + let rust_response = rust_response + .status(status) + .body(full(body))?; + return Ok(rust_response); + } + request.body = rust_request.collect().await?.to_bytes().to_vec(); + } + // This calls indirectly into C++ + api_wrapper( + &my_logger, + &ctx, + func, + &request, + &mut response, + &reqheaders, + rust_response.headers_mut().expect("no headers?"), + allow_password, + ); + } else if let Some(func) = rawfunc { + // Non-API func + let reqheaders = rust_request.headers().clone(); + nonapi_wrapper( + &ctx, + func, + &request, + &mut response, + &reqheaders, + rust_response.headers_mut().expect("no headers?"), + ); + } else if let Some(func) = filefunc { + // Server static file + let reqheaders = rust_request.headers().clone(); + file_wrapper( + &ctx, + func, + &method, + rust_request.uri().path(), + &request, + &mut response, + &reqheaders, + rust_response.headers_mut().expect("no headers?"), + ); + } + } + + let mut len = response.body.len(); + if method == Method::HEAD { + len = 0; + } + log_response(ctx.loglevel, &my_logger, &response, remote); + // Throw away body for HEAD call + let mut body = full(response.body); + if method == Method::HEAD { + body = full(vec![]); + } + + // Construct response based on what C++ gave us + let mut rust_response = rust_response + .status(StatusCode::from_u16(response.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)) + .body(body)?; + for kv in response.headers { + if let Ok(key) = header::HeaderName::from_bytes(kv.key.as_bytes()) { + if let Ok(value) = header::HeaderValue::from_str(kv.value.as_str()) { + rust_response.headers_mut().insert(key, value); + } + } + } + + if let Ok(close) = header::HeaderValue::from_str("close") { + rust_response + .headers_mut() + .insert(header::CONNECTION, close); + } + if ctx.loglevel != rustmisc::LogLevel::None { + let version = format!("{:?}", version); + rustmisc::log( + &my_logger, + rustweb::Priority::Notice, + "Request", + &vec![ + rustmisc::KeyValue { + key: "remote".to_string(), + value: remote.to_string(), + }, + rustmisc::KeyValue { + key: "method".to_string(), + value: method.to_string(), + }, + rustmisc::KeyValue { + key: "urlpath".to_string(), + value: path.to_string(), + }, + rustmisc::KeyValue { + key: "HTTPVersion".to_string(), + value: version, + }, + rustmisc::KeyValue { + key: "status".to_string(), + value: response.status.to_string(), + }, + rustmisc::KeyValue { + key: "respsize".to_string(), + value: len.to_string(), + }, + ], + ); + } + + Ok(rust_response) +} + +async fn serveweb_async( + listener: TcpListener, + config: crate::web::rustweb::IncomingTLS, + ctx: Arc, +) -> MyResult<()> { + if !config.certificate.is_empty() { + let certs = load_certs(&config.certificate, &ctx)?; + let key = load_private_key(&config.key, &ctx)?; + let mut server_config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key) + .map_err(|e| std::io::Error::other(e.to_string()))?; + server_config.alpn_protocols = vec![b"http/1.1".to_vec(), b"http/1.0".to_vec()]; // b"h2".to_vec() + let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); + // We start a loop to continuously accept incoming connections + loop { + let ctx = Arc::clone(&ctx); + let (stream, _) = listener.accept().await?; + + let address; + match stream.peer_addr() { + Ok(addr) => { + address = addr; + let combo = rustmisc::comboaddress(&address.to_string()); + if !rustmisc::matches(&ctx.acl, &combo) { + rustmisc::log( + &ctx.logger, + rustweb::Priority::Debug, + "No ACL match", + &vec![rustmisc::KeyValue { + key: "address".to_string(), + value: address.to_string(), + }], + ); + continue; + } + } + Err(err) => { + rustmisc::error( + &ctx.logger, + rustweb::Priority::Error, + &err.to_string(), + "Can't get peer address", + &vec![], + ); + continue; // If we can't determine the peer address, don't + } + } + // Use an adapter to access something implementing `tokio::io` traits as if they implement + // `hyper::rt` IO traits. + let tls_acceptor = tls_acceptor.clone(); + let shaker = tokio::time::timeout( + std::time::Duration::from_secs(30), + tls_acceptor.accept(stream)); + tokio::task::spawn(async move { + let tls_stream = match shaker.await { + Ok(Ok(tls_stream)) => tls_stream, + Ok(Err(err)) => { + rustmisc::error( + &ctx.logger, + rustweb::Priority::Notice, + &err.to_string(), + "Failed to perform TLS handshake", + &vec![], + ); + return; + } + Err(_) => { + rustmisc::log( + &ctx.logger, + rustweb::Priority::Notice, + "TLS handshake timeout", + &vec![], + ); + return; + } + }; + let io = TokioIo::new(tls_stream); + let my_logger = rustmisc::withValue(&ctx.logger, "tls", "true"); + let fut = http1::Builder::new().serve_connection( + io, + service_fn(move |req| { + let ctx = Arc::clone(&ctx); + process_request(req, ctx, address) + }), + ); + + // Spawn a tokio task to serve the request + tokio::task::spawn(async move { + // Finally, we bind the incoming connection to our `process_request` service + if let Err(err) = fut.await { + rustmisc::error( + &my_logger, + rustweb::Priority::Notice, + &err.to_string(), + "Error serving web connection", + &vec![], + ); + } + }); + }); // TLS handshake + } + } else { + // We start a loop to continuously accept incoming connections + loop { + let ctx = Arc::clone(&ctx); + let (stream, _) = listener.accept().await?; + + let address; + match stream.peer_addr() { + Ok(addr) => { + address = addr; + let combo = rustmisc::comboaddress(&address.to_string()); + if !rustmisc::matches(&ctx.acl, &combo) { + rustmisc::log( + &ctx.logger, + rustweb::Priority::Debug, + "No ACL match", + &vec![rustmisc::KeyValue { + key: "address".to_string(), + value: address.to_string(), + }], + ); + continue; + } + } + Err(err) => { + rustmisc::error( + &ctx.logger, + rustmisc::Priority::Error, + &err.to_string(), + "Can't get peer address", + &vec![], + ); + continue; // If we can't determine the peer address, don't + } + } + let io = TokioIo::new(stream); + let my_logger = rustmisc::withValue(&ctx.logger, "tls", "false"); + let fut = http1::Builder::new().serve_connection( + io, + service_fn(move |req| { + let ctx = Arc::clone(&ctx); + process_request(req, ctx, address) + }), + ); + + // Spawn a tokio task to serve the request + tokio::task::spawn(async move { + // Finally, we bind the incoming connection to our `process_request` service + if let Err(err) = fut.await { + rustmisc::error( + &my_logger, + rustmisc::Priority::Notice, + &err.to_string(), + "Error serving web connection", + &vec![], + ); + } + }); + } + } +} + +pub fn serveweb( + incoming: &Vec, + password_ch: cxx::UniquePtr, + api_ch: cxx::UniquePtr, + acl: cxx::UniquePtr, + logger: cxx::SharedPtr, + loglevel: rustmisc::LogLevel, + max_request_size: u64, +) -> Result<(), std::io::Error> { + // Context, atomically reference counted + let ctx = Arc::new(Context { + password_ch, + api_ch, + acl, + logger, + loglevel, + max_request_size, + }); + + // We use a single thread to handle all the requests, letting the runtime abstracts from this + let runtime = Builder::new_current_thread() + .worker_threads(1) + .thread_name("rec/web") + .enable_io() + .enable_time() + .build()?; + + // For each listening address we spawn a tokio handler and then a single Posix thread is created that + // waits (forever) for all of them to complete by joining them all. + let mut set = JoinSet::new(); + for config in incoming { + for addr_str in &config.addresses { + let addr = match SocketAddr::from_str(addr_str) { + Ok(val) => val, + Err(err) => { + let msg = format!("`{}' is not a IP:port combination: {}", addr_str, err); + return Err(std::io::Error::other(msg)); + } + }; + + let listener = runtime.block_on(async { TcpListener::bind(addr).await }); + let ctx = Arc::clone(&ctx); + match listener { + Ok(val) => { + let mut tls_enabled = false; + let tls = crate::web::rustweb::IncomingTLS { + certificate: config.tls.certificate.clone(), + key: config.tls.key.clone(), + // password: config.tls.password.clone(), not supported (yet), rusttls does not handle it + }; + if !tls.certificate.is_empty() { + tls_enabled = true; + } + rustmisc::log( + &ctx.logger, + rustweb::Priority::Info, + "Web service listening", + &vec![ + rustmisc::KeyValue { + key: "address".to_string(), + value: addr.to_string(), + }, + rustmisc::KeyValue { + key: "tls".to_string(), + value: tls_enabled.to_string(), + }, + ], + ); + set.spawn_on(serveweb_async(val, tls, ctx), runtime.handle()); + } + Err(err) => { + rustmisc::error( + &ctx.logger, + rustweb::Priority::Error, + &err.to_string(), + "Unable to bind to web socket", + &vec![rustmisc::KeyValue { + key: "address".to_string(), + value: addr.to_string(), + }], + ); + let msg = format!("Unable to bind web socket: {}", err); + return Err(std::io::Error::other(msg)); + } + } + } + } + std::thread::Builder::new() + .name(String::from("rec/rustweb")) + .spawn(move || { + runtime.block_on(async { + while let Some(res) = set.join_next().await { + let msg = match res { + Ok(Err(wrapped)) => wrapped.to_string(), + _ => format!("{:?}", res), + }; + rustmisc::error( + &ctx.logger, + rustmisc::Priority::Error, + &msg, + "Rustweb thread exited", + &vec![], + ); + } + }); + })?; + Ok(()) +} + +// Load public certificates from file. +fn load_certs( + filename: &str, + ctx: &Arc, +) -> std::io::Result>> { + let certsfromfile = CertificateDer::pem_file_iter(filename); + match certsfromfile { + Ok(certs) => { + let mut ret = vec![]; + for cert in certs { + match cert { + Ok(cert) => ret.push(cert), + Err(cert) => { + rustmisc::error( + &ctx.logger, + rustmisc::Priority::Error, + &cert.to_string(), + "Failed to parse certificate", + &vec![rustmisc::KeyValue { + key: "filename".to_string(), + value: filename.to_string(), + }], + ); + return Err(std::io::Error::other(format!( + "Failed to parse a certificate from `{}'", + filename + ))); + } + } + } + Ok(ret) + } + Err(err) => { + let msg = "Failed to parse certificate file"; + rustmisc::error( + &ctx.logger, + rustmisc::Priority::Error, + &err.to_string(), + msg, + &vec![rustmisc::KeyValue { + key: "filename".to_string(), + value: filename.to_string(), + }], + ); + Err(std::io::Error::other(msg)) + } + } +} + +// Load private key from file. +fn load_private_key( + filename: &str, + ctx: &Arc, +) -> std::io::Result> { + let key = PrivateKeyDer::from_pem_file(filename); + match key { + Ok(key) => Ok(key), + Err(err) => { + let msg = "Failed to parse private key file"; + rustmisc::error( + &ctx.logger, + rustmisc::Priority::Error, + &err.to_string(), + msg, + &vec![rustmisc::KeyValue { + key: "filename".to_string(), + value: filename.to_string(), + }], + ); + Err(std::io::Error::other(msg)) + } + } +} + +// impl below needed because the classes are used in the Context, which gets passed around. +unsafe impl Send for rustweb::CredentialsHolder {} +unsafe impl Sync for rustweb::CredentialsHolder {} +unsafe impl Send for rustmisc::NetmaskGroup {} +unsafe impl Sync for rustmisc::NetmaskGroup {} +unsafe impl Send for rustmisc::Logger {} +unsafe impl Sync for rustmisc::Logger {} + +#[cxx::bridge(namespace = "pdns::rust::web::rec")] +#[allow(clippy::needless_lifetimes)] // Needed to avoid clippy warning for Request +mod rustweb { + extern "C++" { + type CredentialsHolder; + #[namespace = "pdns::rust::misc"] + type NetmaskGroup = crate::misc::rustmisc::NetmaskGroup; + #[namespace = "pdns::rust::misc"] + type Priority = crate::misc::rustmisc::Priority; + #[namespace = "pdns::rust::misc"] + type LogLevel = crate::misc::rustmisc::LogLevel; + #[namespace = "pdns::rust::misc"] + type Logger = crate::misc::rustmisc::Logger; + } + + pub struct IncomingTLS { + certificate: String, + key: String, + // password: String, Not currently supported, as rusttls does not support that out of the box + } + + struct IncomingWSConfig { + addresses: Vec, + tls: IncomingTLS, + } + /* + * Functions callable from C++ + */ + extern "Rust" { + // The main entry point, This function will return, but will setup thread(s) and tokio runtime to handle requests. + fn serveweb( + incoming: &Vec, + pwch: UniquePtr, + apikeych: UniquePtr, + acl: UniquePtr, + logger: SharedPtr, + loglevel: LogLevel, + max_request_size: u64, + ) -> Result<()>; + } + + struct KeyValue { + key: String, + value: String, + } + + // Clippy does not seem to understand what cxx does and complains about needless_lifetimes + // The warning is silenced above + struct Request<'a> { + body: Vec, + uri: String, + vars: Vec, + parameters: Vec, + logger: &'a SharedPtr, + } + + struct Response { + status: u16, + body: Vec, + headers: Vec, + } + + /* + * Functions callable from Rust + */ + unsafe extern "C++" { + include!("bridge.hh"); + fn matches(self: &CredentialsHolder, str: &CxxString) -> bool; + fn apiDiscovery(request: &Request, response: &mut Response) -> Result<()>; + fn apiDiscoveryV1(request: &Request, response: &mut Response) -> Result<()>; + fn apiServer(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerCacheFlush(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerConfig(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerConfigAllowFromGET(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerConfigAllowFromPUT(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerConfigAllowNotifyFromGET( + request: &Request, + response: &mut Response, + ) -> Result<()>; + fn apiServerConfigAllowNotifyFromPUT( + request: &Request, + response: &mut Response, + ) -> Result<()>; + fn apiServerDetail(requst: &Request, response: &mut Response) -> Result<()>; + fn apiServerRPZStats(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerSearchData(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerStatistics(requst: &Request, response: &mut Response) -> Result<()>; + fn apiServerZoneDetailDELETE(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerZoneDetailGET(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerZoneDetailPUT(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerZonesGET(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerZonesPOST(requst: &Request, response: &mut Response) -> Result<()>; + fn apiServerOTConditionsGET(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerOTConditionDetailGET(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerOTConditionDetailDELETE(request: &Request, response: &mut Response) -> Result<()>; + fn apiServerOTConditionDetailPOST(request: &Request, response: &mut Response) -> Result<()>; + fn jsonstat(request: &Request, response: &mut Response) -> Result<()>; + fn prometheusMetrics(request: &Request, response: &mut Response) -> Result<()>; + fn serveStuff(request: &Request, response: &mut Response) -> Result<()>; + } +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust-bridge-in.rs pdns-recursor-5.4.9/rec-rust-lib/rust-bridge-in.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust-bridge-in.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust-bridge-in.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,460 @@ +// This file (rust-bridge-in.rs) is included into lib.rs inside the bridge module +/* + * Implement non-generated structs that need to be handled by Serde and CXX + */ + +// A single forward zone +#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ForwardZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + forwarders: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + recurse: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, +} + +// A single auth zone +#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct AuthZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + file: String, +} + +// A single trust anchor +#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct TrustAnchor { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + dsrecords: Vec, +} + +// A single negative trust anchor +#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct NegativeTrustAnchor { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + reason: String, +} + +// A protobuf logging server +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ProtobufServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] + timeout: u64, + #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal", alias = "max_queued_entries")] + maxQueuedEntries: u64, + #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal", alias = "reconnect_wait_time")] + reconnectWaitTime: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "tagged_only")] + taggedOnly: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "async_connect")] + asyncConnect: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_queries")] + logQueries: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_responses")] + logResponses: bool, + #[serde(default = "crate::def_pb_export_qtypes", skip_serializing_if = "crate::default_value_equal_pb_export_qtypes", alias = "export_types")] + exportTypes: Vec, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "log_mapped_from")] + logMappedFrom: bool, +} + +// A dnstap logging server +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct DNSTapFrameStreamServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_queries")] + logQueries: bool, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_responses")] + logResponses: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "buffer_hint")] + bufferHint: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "flush_timeout")] + flushTimeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "input_queue_size")] + inputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "output_queue_size")] + outputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "queue_notify_threshold")] + queueNotifyThreshold: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "reopen_interval")] + reopenInterval: u64, +} + +// A dnstap logging NOD server +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct DNSTapNODFrameStreamServer { + #[serde(default, skip_serializing_if = "crate::is_default")] + servers: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "log_nods")] + logNODs: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "log_udrs")] + logUDRs: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "buffer_hint")] + bufferHint: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "flush_timeout")] + flushTimeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "input_queue_size")] + inputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "output_queue_size")] + outputQueueSize: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "queue_notify_threshold")] + queueNotifyThreshold: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "reopen_interval")] + reopenInterval: u64, +} + +#[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct TSIGTriplet { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + algo: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + secret: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct RPZ { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + defcontent: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + defpol: String, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "defpol_override_local_data")] + defpolOverrideLocalData: bool, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] + defttl: u32, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal", alias = "extended_error_code")] + extendedErrorCode: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "extended_error_extra")] + extendedErrorExtra: String, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "include_soa")] + includeSOA: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "ignore_duplicates")] + ignoreDuplicates: bool, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal", alias = "max_ttl")] + maxTTL: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "policy_name")] + policyName: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + tags: Vec, + #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true", alias = "overrides_gettag")] + overridesGettag: bool, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "zone_size_hint")] + zoneSizeHint: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default, skip_serializing_if = "crate::is_default")] + refresh: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal", alias = "axfr_timeout")] + axfrTimeout: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "dump_file")] + dumpFile: String, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "seed_file")] + seedFile: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ZoneToCache { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + method: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + sources: Vec, + #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] + timeout: u64, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal", alias = "refresh_period")] + refreshPeriod: u64, + #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal", alias = "retry_on_error_period")] + retryOnErrorPeriod: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u64, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] + zonemd: String, + #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] + dnssec: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct SubnetOrder { + #[serde(default, skip_serializing_if = "crate::is_default")] + subnet: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + order: u32, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct SortList { + #[serde(default, skip_serializing_if = "crate::is_default")] + key: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + subnets: Vec, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct AllowedAdditionalQType { + #[serde(default, skip_serializing_if = "crate::is_default")] + qtype: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + targets: Vec, + #[serde(default = "crate::def_additional_mode", skip_serializing_if = "crate::default_value_equals_additional_mode")] + mode: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ProxyMapping { + #[serde(default, skip_serializing_if = "crate::is_default")] + subnet: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + address: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + domains: Vec, +} + +// A struct holding both a vector of forward zones and a vector of auth zones, used by REST API code +#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ApiZones { + #[serde(default, skip_serializing_if = "crate::is_default")] + auth_zones: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + forward_zones: Vec, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct XFR { + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "zone_size_hint")] + zoneSizeHint: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + tsig: TSIGTriplet, + #[serde(default, skip_serializing_if = "crate::is_default")] + refresh: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "max_received_mbytes")] + maxReceivedMBytes: u32, + #[serde(default, skip_serializing_if = "crate::is_default", alias = "local_address")] + localAddress: String, + #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal", alias = "axfr_timeout")] + axfrTimeout: u32, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct FCZDefault { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + forwarders: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + recurse: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, + } + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct ForwardingCatalogZone { + #[serde(default, skip_serializing_if = "crate::is_default")] + zone: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + notify_allowed: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + xfr: XFR, + #[serde(default, skip_serializing_if = "crate::is_default")] + groups: Vec, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct IncomingTLS { + #[serde(default, skip_serializing_if = "crate::is_default")] + certificate: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + key: String, + // #[serde(default, skip_serializing_if = "crate::is_default")] + // password: String, Not currently supported, as rusttls does not support this out of the box +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct IncomingWSConfig { + #[serde(default, skip_serializing_if = "crate::is_default")] + addresses: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + tls: IncomingTLS, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +struct OutgoingTLSConfiguration { + #[serde(default, skip_serializing_if = "crate::is_default")] + name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + provider: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + suffixes: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + subnets: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + validate_certificate: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + ca_store: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + verbose_logging: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + subject_name: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + subject_address: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + ciphers: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + ciphers_tls_13: String, +} + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +struct OpenTelemetryTraceCondition { + #[serde(default, skip_serializing_if = "crate::is_default")] + acls: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + qnames: Vec, + #[serde(default, skip_serializing_if = "crate::is_default")] + qtypes: Vec, + #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] + qid: u32, + #[serde(default, skip_serializing_if = "crate::is_default")] + edns_option_required: bool, + #[serde(default, skip_serializing_if = "crate::is_default")] + traceid_only: bool, +} + +// Two structs used to generated YAML based on a vector of name to value mappings +// Cannot use Enum as CXX has only very basic Enum support +struct Value { + bool_val: bool, + u64_val: u64, + f64_val: f64, + string_val: String, + vec_string_val: Vec, + vec_forwardzone_val: Vec, + vec_authzone_val: Vec, + vec_trustanchor_val: Vec, + vec_negativetrustanchor_val: Vec, + vec_protobufserver_val: Vec, + vec_dnstap_framestream_server_val: Vec, + vec_dnstap_nod_framestream_server_val: Vec, + vec_rpz_val: Vec, + vec_sortlist_val: Vec, + vec_zonetocache_val: Vec, + vec_allowedadditionalqtype_val: Vec, + vec_proxymapping_val: Vec, + vec_forwardingcatalogzone_val: Vec, + vec_incomingwsconfig_val: Vec, + vec_outgoingtlsconfiguration_val: Vec, +} + +struct OldStyle { + section: String, + name: String, + old_name: String, + type_name: String, + value: Value, + overriding: bool, +} + +/* + * Functions callable from C++ + */ +extern "Rust" { + // Parse a string representing YAML text and produce the corresponding data structure known to Serde + // The settings that can be stored in individual files get their own parse function + // Main recursor settings + fn parse_yaml_string(str: &str) -> Result; + // Allow from sequence + fn parse_yaml_string_to_allow_from(str: &str) -> Result>; + // Forward zones sequence + fn parse_yaml_string_to_forward_zones(str: &str) -> Result>; + // Allow notify for sequence + fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result>; + // REST API zones + fn parse_yaml_string_to_api_zones(str: &str) -> Result; + + // Produce a YAML formatted string given a data structure known to Serde + fn to_yaml_string(self: &Recursorsettings) -> Result; + fn get_value(self: &Recursorsettings, field: &[String], defaults: &str, with_comment: bool) -> Result; + // When doing a conversion of old-style to YAML style we use a vector of OldStyle structs + fn map_to_yaml_string(map: &Vec) -> Result; + fn forward_zones_to_yaml_string(vec: &Vec) -> Result; + fn allow_from_to_yaml_string(vec: &Vec) -> Result; + fn allow_from_to_yaml_string_incoming(key: &String, filekey: &String, vec: &Vec) -> Result; + fn allow_for_to_yaml_string(vec: &Vec) -> Result; + + // Merge a string representing YAML settings into an existing settings struct + fn merge(lhs: &mut Recursorsettings, rhs: &str) -> Result<()>; + + // Validate the sections inside the main settings struct, sections themselves will validate their fields + fn validate(self: &Recursorsettings) -> Result<()>; + // The validate function below are "hand-crafted" as their structs are not generated + fn validate(self: &AuthZone, field: &str) -> Result<()>; + fn validate(self: &ForwardZone, field: &str) -> Result<()>; + fn validate(self: &TrustAnchor, field: &str) -> Result<()>; + fn validate(self: &NegativeTrustAnchor, field: &str) -> Result<()>; + fn validate(self: &ApiZones, field: &str) -> Result<()>; + + // Helper functions to call the proper validate function on vectors of various kinds + fn validate_auth_zones(field: &str, vec: &Vec) -> Result<()>; + fn validate_forward_zones(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_for(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<()>; + fn validate_allow_from(field: &str, vec: &Vec) -> Result<()>; + + // The functions to maintain REST API managed zones + fn api_read_zones(path: &str) -> Result>; + fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>; + fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>; + fn api_add_forward_zones(file: &str, forwardzones: &mut Vec) -> Result<()>; + fn validate_trustanchors(field: &str, vec: &Vec) -> Result<()>; + fn validate_negativetrustanchors(field: &str, vec: &Vec) -> Result<()>; + fn api_delete_zone(file: &str, zone: &str) -> Result<()>; + fn api_delete_zones(file: &str) -> Result<()>; +} + diff -Nru pdns-recursor-5.2.13/rec-rust-lib/rust-preamble-in.rs pdns-recursor-5.4.9/rec-rust-lib/rust-preamble-in.rs --- pdns-recursor-5.2.13/rec-rust-lib/rust-preamble-in.rs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/rust-preamble-in.rs 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * 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. + */ + +// This file (rust-preamble-in.rs) is included at the start of lib.rs + +// rustc complains serde Serialize/Deserialize are not used on toplevel, while they *are* used plenty +// in mod recsettings. Disable the warning for the line below only. +#[allow(unused_imports)] +use serde::{Deserialize, Serialize}; + +mod helpers; +use helpers::*; + +mod bridge; +use bridge::*; + +mod misc; + +mod web; // leaving this out causes link issues + +trait Validate { + fn validate(&self) -> Result<(), ValidationError>; +} + +#[derive(Debug)] +pub struct ValidationError { + msg: String, +} + +trait Merge { + fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>); +} diff -Nru pdns-recursor-5.2.13/rec-rust-lib/table.py pdns-recursor-5.4.9/rec-rust-lib/table.py --- pdns-recursor-5.2.13/rec-rust-lib/table.py 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-rust-lib/table.py 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,3678 @@ +# This file contains the table used to generate old and new-style settings code +# +# Example: +# { +# 'name' : 'allow_from', +# 'section' : 'incoming', +# 'oldname' : 'allow-from' +# 'type' : LType.ListSubnets, +# 'default' : '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', +# 'help' : 'If set, only allow these comma separated netmasks to recurse', +# 'doc' : ''' +# ''' +# } +# +# See generate.py for a description of the fields. +# +# Sections +# - incoming +# - outgoing +# - packetcache +# - recursor +# - recordcache +# - dnssec +# - webservice +# - carbon +# - ecs +# - logging +# - nod +# - snmp + +[ + { + 'name' : 'aggressive_nsec_cache_size', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '100000', + 'help' : 'The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198', + 'doc' : ''' +The number of records to cache in the aggressive cache. If set to a value greater than 0, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in :rfc:`8198`. +To use this, DNSSEC processing or validation must be enabled by setting :ref:`setting-dnssec` to ``process``, ``log-fail`` or ``validate``. + ''', + 'versionadded': '4.5.0', + 'runtime': 'set-max-aggr-nsec-cache-size', + }, + { + 'name' : 'aggressive_cache_min_nsec3_hit_ratio', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '2000', + 'help' : 'The minimum expected hit ratio to store NSEC3 records into the aggressive cache', + 'doc' : ''' +The limit for which to put NSEC3 records into the aggressive cache. +A value of ``n`` means that an NSEC3 record is only put into the aggressive cache if the estimated probability of a random name hitting the NSEC3 record is higher than ``1/n``. +A higher ``n`` will cause more records to be put into the aggressive cache, e.g. a value of 4000 will cause records to be put in the aggressive cache even if the estimated probability of hitting them is twice as low as would be the case for ``n=2000``. +A value of 0 means no NSEC3 records will be put into the aggressive cache. + +For large zones the effectiveness of the NSEC3 cache is reduced since each NSEC3 record only covers a randomly distributed subset of all possible names. +This setting avoids doing unnecessary work for such large zones. + ''', + 'versionadded' : '4.9.0', + }, + { + 'name' : 'allow_from', + 'section' : 'incoming', + 'type' : LType.ListSubnets, + 'default' : '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', + 'help' : 'If set, only allow these comma separated netmasks to recurse', + 'doc' : ''' +Netmasks (both IPv4 and IPv6) that are allowed to use the server. +The default allows access only from :rfc:`1918` private IP addresses. +An empty value means no checking is done, all clients are allowed. +Due to the aggressive nature of the internet these days, it is highly recommended to not open up the recursor for the entire internet. +Questions from IP addresses not listed here are ignored and do not get an answer. + +When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the recursor will check the address of the client IP advertised in the Proxy Protocol header instead of the one of the proxy. + +Note that specifying an IP address without a netmask uses an implicit netmask of /32 or /128. + ''', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_from_file', + 'section' : 'incoming', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, load allowed netmasks from this file', + 'doc' : ''' +Like :ref:`setting-allow-from`, except reading from file. +Overrides the :ref:`setting-allow-from` setting. To use this feature, supply one netmask per line, with optional comments preceded by a '#'. + ''', + 'doc-new' : ''' +Like :ref:`setting-allow-from`, except reading a sequence of `Subnet`_ from file. +Overrides the :ref:`setting-allow-from` setting. Example content of th specified file: + +.. code-block:: yaml + + - 127.0.0.1 + - ::1 + + ''', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_notify_for', + 'section' : 'incoming', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'If set, NOTIFY requests for these zones will be allowed', + 'doc' : ''' +Domain names specified in this list are used to permit incoming +NOTIFY operations to wipe any cache entries that match the domain +name. If this list is empty, all NOTIFY operations will be ignored. +Matching is done using suffix matching, it is allowed to NOTIFY a subdomain of a listed domain. + ''', + 'versionadded': '4.6.0', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_notify_for_file', + 'section' : 'incoming', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, load NOTIFY-allowed zones from this file', + 'doc' : ''' +Like :ref:`setting-allow-notify-for`, except reading from file. To use this +feature, supply one domain name per line, with optional comments +preceded by a '#'. + +NOTIFY-allowed zones can also be specified using :ref:`setting-forward-zones-file`. + ''', + 'doc-new' : ''' +Like :ref:`setting-allow-notify-for`, except reading a sequence of names from file. Example contents of specified file: + +.. code-block:: yaml + + - example.com + - example.org + + ''', + 'versionadded': '4.6.0', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_notify_from', + 'section' : 'incoming', + 'type' : LType.ListSubnets, + 'default' : '', + 'help' : 'If set, NOTIFY requests from these comma separated netmasks will be allowed', + 'doc' : ''' +Netmasks (both IPv4 and IPv6) that are allowed to issue NOTIFY operations +to the server. NOTIFY operations from IP addresses not listed here are +ignored and do not get an answer. + +When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the +recursor will check the address of the client IP advertised in the +Proxy Protocol header instead of the one of the proxy. + +Note that specifying an IP address without a netmask uses an implicit +netmask of /32 or /128. + +NOTIFY operations received from a client listed in one of these netmasks +will be accepted and used to wipe any cache entries whose zones match +the zone specified in the NOTIFY operation, but only if that zone (or +one of its parents) is included in :ref:`setting-allow-notify-for`, +:ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a '^' prefix. + ''', + 'doc-new' : ''' +Subnets (both IPv4 and IPv6) that are allowed to issue NOTIFY operations +to the server. NOTIFY operations from IP addresses not listed here are +ignored and do not get an answer. + +When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the +recursor will check the address of the client IP advertised in the +Proxy Protocol header instead of the one of the proxy. + +Note that specifying an IP address without a netmask uses an implicit +netmask of /32 or /128. + +NOTIFY operations received from a client listed in one of these netmasks +will be accepted and used to initiate a freshness check for an RPZ zone or wipe any cache entries whose zones match +the zone specified in the NOTIFY operation, but only if that zone (or +one of its parents) is included in :ref:`setting-allow-notify-for`, +:ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a ``allow_notify`` set to ``true``. + ''', + 'versionadded': '4.6.0', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_notify_from_file', + 'section' : 'incoming', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, load NOTIFY-allowed netmasks from this file', + 'doc' : ''' +Like :ref:`setting-allow-notify-from`, except reading from file. To use this +feature, supply one netmask per line, with optional comments preceded +by a '#'. + ''', + 'doc-new' : ''' +Like :ref:`setting-allow-notify-from`, except reading a sequence of `Subnet`_ from file. + ''', + 'versionadded': '4.6.0', + 'runtime': ['reload-acls'], + }, + { + 'name' : 'allow_no_rd', + 'section' : 'incoming', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Allow \'no recursion desired (RD=0)\' queries.', + 'doc' : ''' +Allow ``no recursion desired (RD=0) queries`` to query cache contents. +If not set (the default), these queries are answered with rcode ``Refused``. + ''', + 'versionadded': '5.0.0' + }, + { + 'name' : 'any_to_tcp', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Answer ANY queries with tc=1, shunting to TCP', + 'doc' : ''' +Answer questions for the ANY type on UDP with a truncated packet that refers the remote client to TCP. +Useful for mitigating ANY reflection attacks. + ''', + 'versionchanged': ('5.4.0', 'Default is enabled now, was disabled before 5.4.0'), + }, + { + 'name' : 'any_to_tcp', + 'oldname': 'out-any-to-tcp', + 'section' : 'outgoing', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Use TCP for ANY queries to authoritative servers', + 'doc' : ''' +Send out requests with qtype `ANY` using TCP. + ''', + 'versionadded': '5.4.0', + }, + { + 'name' : 'allow_trust_anchor_query', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT', + 'doc' : ''' +Allow ``trustanchor.server CH TXT`` and ``negativetrustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC ` (negative) trust anchors. + ''', + 'versionadded': '4.3.0' + }, + { + 'name' : 'api_dir', + 'section' : 'webservice', + 'oldname' : 'api-config-dir', + 'type' : LType.String, + 'default' : '', + 'help' : 'Directory where REST API stores config and zones', + 'doc' : ''' +Directory where the REST API stores its configuration and zones. +For configuration updates to work, :ref:`setting-include-dir` should have the same value when using old-style settings. +When using YAML settings :ref:`setting-yaml-recursor.include_dir` and :ref:`setting-yaml-webservice.api_dir` must have a different value. + ''', + 'versionadded': '4.0.0' + }, + { + 'name' : 'api_key', + 'section' : 'webservice', + 'type' : LType.String, + 'default' : '', + 'help' : 'Static pre-shared authentication key for access to the REST API', + 'doc' : ''' +Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password`` instead of being stored in the configuration in plaintext, but the plaintext version is still supported. + ''', + 'versionadded': '4.0.0', + 'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.') + }, + { + 'name' : 'auth_zones', + 'section' : 'recursor', + 'type' : LType.ListAuthZones, + 'default' : '', + 'help' : 'Zones for which we have authoritative data, comma separated domain=file pairs', + 'doc' : ''' +Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses). +DNSSEC is not supported. Example: + +.. code-block:: none + + auth-zones=example.org=/var/zones/example.org, powerdns.com=/var/zones/powerdns.com + ''', + 'doc-new' : ''' +Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses). +DNSSEC is not supported. Example: + +.. code-block:: yaml + + recursor: + auth_zones: + - zone: example.org + file: /var/zones/example.org + - zone: powerdns.com + file: /var/zones/powerdns.com + ''', + 'runtime': ['reload-zones'], + }, + { + 'name' : 'interval', + 'section' : 'carbon', + 'oldname' : 'carbon-interval', + 'type' : LType.Uint64, + 'default' : '30', + 'help' : 'Number of seconds between carbon (graphite) updates', + 'doc' : ''' +If sending carbon updates, this is the interval between them in seconds. +See :doc:`metrics`. + ''', + }, + { + 'name' : 'ns', + 'section' : 'carbon', + 'oldname' : 'carbon-namespace', + 'type' : LType.String, + 'default' : 'pdns', + 'help' : 'If set overwrites the first part of the carbon string', + 'doc' : ''' +Change the namespace or first string of the metric key. The default is pdns. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'ourname', + 'section' : 'carbon', + 'oldname' : 'carbon-ourname', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, overrides our reported hostname for carbon stats', + 'doc' : ''' +If sending carbon updates, if set, this will override our hostname. +Be careful not to include any dots in this setting, unless you know what you are doing. +See :ref:`metricscarbon`. + ''', + }, + { + 'name' : 'instance', + 'section' : 'carbon', + 'oldname' : 'carbon-instance', + 'type' : LType.String, + 'default' : 'recursor', + 'help' : 'If set overwrites the instance name default', + 'doc' : ''' +Change the instance or third string of the metric key. The default is recursor. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'server', + 'section' : 'carbon', + 'oldname' : 'carbon-server', + 'type' : LType.ListSocketAddresses, + 'default' : '', + 'help' : 'If set, send metrics in carbon (graphite) format to this server IP address', + 'doc' : ''' +If set to an IP or IPv6 address, will send all available metrics to this server via the carbon protocol, which is used by graphite and metronome. Moreover you can specify more than one server using a comma delimited list, ex: carbon-server=10.10.10.10,10.10.10.20. +You may specify an alternate port by appending :port, for example: ``127.0.0.1:2004``. +See :doc:`metrics`. + ''', + 'doc-new' : ''' +Will send all available metrics to these servers via the carbon protocol, which is used by graphite and metronome. +See :doc:`metrics`. + ''', + 'runtime': 'set-carbon-server', + }, + { + 'name' : 'chroot', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'switch to chroot jail', + 'doc' : ''' +If set, chroot to this directory for more security. +This is not recommended; instead, we recommend containing PowerDNS using operating system features. +We ship systemd unit files with our packages to make this easy. + +Make sure that ``/dev/log`` is available from within the chroot. +Logging will silently fail over time otherwise (on logrotate). + +When using ``chroot``, all other paths (except for :ref:`setting-config-dir`) set in the configuration are relative to the new root. + +When running on a system where systemd manages services, ``chroot`` does not work out of the box, as PowerDNS cannot use the ``NOTIFY_SOCKET``. +Either do not ``chroot`` on these systems or set the 'Type' of this service to 'simple' instead of 'notify' (refer to the systemd documentation on how to modify unit-files). + ''', + }, + { + 'name' : 'tcp_timeout', + 'section' : 'incoming', + 'oldname' : 'client-tcp-timeout', + 'type' : LType.Uint64, + 'default' : '2', + 'help' : 'Timeout in seconds when talking to TCP clients', + 'doc' : ''' +Time to wait for data from TCP clients. + ''', + }, + { + 'name' : 'config', + 'section' : 'commands', + 'type' : LType.Command, + 'default' : 'no', + 'help' : 'Output blank configuration. You can use --config=check to test the config file and command line arguments.', + 'doc' : ''' +EMPTY? ''' + }, + { + 'name' : 'config_dir', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : 'SYSCONFDIR', + 'docdefault': 'Determined by distribution', + 'help' : 'Location of configuration directory (recursor.conf or recursor.yml)', + 'doc' : ''' +Location of configuration directory (where ``recursor.conf`` or ``recursor.yml`` is stored). +Usually ``/etc/powerdns``, but this depends on ``SYSCONFDIR`` during compile-time. +Use default or set on command line. + ''', + }, + { + 'name' : 'config_name', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Name of this virtual configuration - will rename the binary image', + 'doc' : ''' +When running multiple recursors on the same server, read settings from :file:`recursor-{name}.conf`, this will also rename the binary image. + ''', + }, + { + 'name' : 'cpu_map', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs', + 'doc' : ''' +Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs. +This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N. +For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2:: + + cpu-map=0=0 1=1,2 + +The thread handling the control channel, the webserver and other internal stuff has been assigned id 0, the distributor +threads if any are assigned id 1 and counting, and the worker threads follow behind. +The number of distributor threads is determined by :ref:`setting-distributor-threads`, the number of worker threads is determined by the :ref:`setting-threads` setting. + +This parameter is only available if the OS provides the ``pthread_setaffinity_np()`` function. + +Note that, depending on the configuration, the Recursor can start more threads. +Typically these threads will sleep most of the time. +These threads cannot be specified in this setting as their thread-ids are left unspecified. + ''', + 'doc-new' : ''' +Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs. +This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N. +For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2: + +.. code-block:: yaml + + recursor: + cpu_map: 0=0 1=1,2 + +The thread handling the control channel, the webserver and other internal stuff has been assigned id 0, the distributor +threads if any are assigned id 1 and counting, and the worker threads follow behind. +The number of distributor threads is determined by :ref:`setting-distributor-threads`, the number of worker threads is determined by the :ref:`setting-threads` setting. + +This parameter is only available if the OS provides the ``pthread_setaffinity_np()`` function. + +Note that, depending on the configuration, the Recursor can start more threads. +Typically these threads will sleep most of the time. +These threads cannot be specified in this setting as their thread-ids are left unspecified. + ''', + }, + { + 'name' : 'daemon', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Operate as a daemon', + 'doc' : ''' +Operate in the background. + ''', + 'versionchanged': ('4.0.0', 'Default is now ``no``, was ``yes`` before.') + }, + { + 'name' : 'dont_throttle_names', + 'section' : 'outgoing', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'Do not throttle nameservers with this name or suffix', + 'doc' : ''' +When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled. +Any servers' name suffix-matching the supplied names will never be throttled. + +.. warning:: + Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-names`` could make this load on the upstream server even higher, resulting in further service degradation. + ''', + 'versionadded': '4.2.0', + 'runtime': ['add-dont-throttle-names', 'clear-dont-throttle-names'], + }, + { + 'name' : 'dont_throttle_netmasks', + 'section' : 'outgoing', + 'type' : LType.ListSubnets, + 'default' : '', + 'help' : 'Do not throttle nameservers with this IP netmask', + 'doc' : ''' +When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled. +Any servers matching the supplied netmasks will never be throttled. + +This can come in handy on lossy networks when forwarding, where the same server is configured multiple times (e.g. with ``forward-zones-recurse=example.com=192.0.2.1;192.0.2.1``). +By default, the PowerDNS Recursor would throttle the 'first' server on a timeout and hence not retry the 'second' one. +In this case, ``dont-throttle-netmasks`` could be set to ``192.0.2.1``. + +.. warning:: + Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation. + ''', + 'doc-new' : ''' +When an authoritative server does not answer a query or sends a reply that the recursor does not like, it is throttled. +Any servers matching the supplied netmasks will never be throttled. + +This can come in handy on lossy networks when forwarding, where the same server is configured multiple times (e.g. with ``forward_zones_recurse: [ {zone: example.com, forwarders: [ 192.0.2.1, 192.0.2.1 ] } ]``. +By default, the PowerDNS Recursor would throttle the 'first' server on a timeout and hence not retry the 'second' one. +In this case, :ref:`setting-dont-throttle-netmasks` could be set to include ``192.0.2.1``. + +.. warning:: + Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation. + ''', + 'versionadded': '4.2.0', + 'runtime': ['rec_control add-dont-throttle-netmasks', 'rec_control clear-dont-throttle-netmask'], + }, + { + 'name' : 'devonly_regression_test_mode', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'internal use only', + 'doc' : 'SKIP', + }, + { + 'name' : 'disable', + 'section' : 'packetcache', + 'oldname' : 'disable-packetcache', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Disable packetcache', + 'doc' : ''' +Turn off the packet cache. Useful when running with Lua scripts that modify answers in such a way they cannot be cached, though individual answer caching can be controlled from Lua as well. + ''', + }, + { + 'name' : 'disable_syslog', + 'section' : 'logging', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Disable logging to syslog, useful when running inside a supervisor that logs stderr', + 'doc' : ''' +Do not log to syslog, only to stderr. +Use this setting when running inside a supervisor that handles logging (like systemd). +**Note**: do not use this setting in combination with :ref:`setting-daemon` as all logging will disappear. + ''', + }, + { + 'name' : 'distribution_load_factor', + 'section' : 'incoming', + 'type' : LType.Double, + 'default' : '0.0', + 'help' : 'The load factor used when PowerDNS is distributing queries to worker threads', + 'doc' : ''' +If :ref:`setting-pdns-distributes-queries` is set and this setting is set to another value +than 0, the distributor thread will use a bounded load-balancing algorithm while +distributing queries to worker threads, making sure that no thread is assigned +more queries than distribution-load-factor times the average number of queries +currently processed by all the workers. +For example, with a value of 1.25, no server should get more than 125 % of the +average load. This helps making sure that all the workers have roughly the same +share of queries, even if the incoming traffic is very skewed, with a larger +number of requests asking for the same qname. + ''', + 'versionadded': '4.1.12' + }, + { + 'name' : 'distribution_pipe_buffer_size', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread', + 'doc' : ''' +Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread. +Requires support for `F_SETPIPE_SZ` which is present in Linux since 2.6.35. The actual size might be rounded up to +a multiple of a page size. 0 means that the OS default size is used. +A large buffer might allow the recursor to deal with very short-lived load spikes during which a worker thread gets +overloaded, but it will be at the cost of an increased latency. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'distributor_threads', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '0', + 'docdefault' : '1 if :ref:`setting-pdns-distributes-queries` is set, 0 otherwise', + 'help' : 'Launch this number of distributor threads, distributing queries to other threads', + 'doc' : ''' +If :ref:`setting-pdns-distributes-queries` is set, spawn this number of distributor threads on startup. Distributor threads +handle incoming queries and distribute them to other threads based on a hash of the query. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'dot_to_auth_names', + 'section' : 'outgoing', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'Use DoT to authoritative servers with these names or suffixes', + 'doc' : ''' +Force DoT to the listed authoritative nameservers. For this to work, DoT support has to be compiled in. +Currently, the certificate is not checked for validity in any way. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'dot_to_port_853', + 'section' : 'outgoing', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Force DoT connection to target port 853 if DoT compiled in', + 'doc' : ''' +Enable DoT to forwarders that specify port 853. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'dns64_prefix', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'DNS64 prefix', + 'doc' : ''' +Enable DNS64 (:rfc:`6147`) support using the supplied /96 IPv6 prefix. This will generate 'fake' ``AAAA`` records for names +with only ``A`` records, as well as 'fake' ``PTR`` records to make sure that reverse lookup of DNS64-generated IPv6 addresses +generate the right name. +See :doc:`dns64` for more flexible but slower alternatives using Lua. + ''', + 'versionadded': '4.4.0' + }, + { + 'name' : 'validation', + 'section' : 'dnssec', + 'oldname' : 'dnssec', + 'type' : LType.String, + 'default' : 'process', + 'help' : 'DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate', + 'doc' : ''' +One of ``off``, ``process-no-validate``, ``process``, ``log-fail``, ``validate`` + +Set the mode for DNSSEC processing, as detailed in :doc:`dnssec`. + +``off`` + No DNSSEC processing whatsoever. + Ignore DO-bits in queries, don't request any DNSSEC information from authoritative servers. + This behaviour is similar to PowerDNS Recursor pre-4.0. +``process-no-validate`` + Respond with DNSSEC records to clients that ask for it, set the DO bit on all outgoing queries. + Don't do any validation. +``process`` + Respond with DNSSEC records to clients that ask for it, set the DO bit on all outgoing queries. + Do validation for clients that request it (by means of the AD- bit or DO-bit in the query). +``log-fail`` + Similar behaviour to ``process``, but validate RRSIGs on responses and log bogus responses. +``validate`` + Full blown DNSSEC validation. Send SERVFAIL to clients on bogus responses. + ''', + 'versionadded': '4.0.0', + 'versionchanged': ('4.5.0', + 'The default changed from ``process-no-validate`` to ``process``') + }, + { + 'name' : 'disabled_algorithms', + 'section' : 'dnssec', + 'oldname' : 'dnssec-disabled-algorithms', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'List of DNSSEC algorithm numbers that are considered unsupported', + 'doc' : ''' +A list of DNSSEC algorithm numbers that should be considered disabled. +These algorithms will not be used to validate DNSSEC signatures. +Zones (only) signed with these algorithms will be considered ``Insecure``. + +If this setting is empty (the default), :program:`Recursor` will determine which algorithms to disable automatically. +This is done for specific algorithms only, currently algorithms 5 (``RSASHA1``) and 7 (``RSASHA1NSEC3SHA1``). + +This is important on systems that have a default strict crypto policy, like RHEL9 derived systems. +On such systems not disabling some algorithms (or changing the security policy) will make affected zones to be considered ``Bogus`` as using these algorithms fails. + ''', + 'versionadded': '4.9.0' + }, + { + 'name' : 'log_bogus', + 'section' : 'dnssec', + 'oldname' : 'dnssec-log-bogus', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Log DNSSEC bogus validations', + 'doc' : ''' +Log every DNSSEC validation failure. +**Note**: This is not logged per-query but every time records are validated as Bogus. + ''', + 'runtime': 'set-dnssec-log-bogus', + }, + { + 'name' : 'dont_query', + 'section' : 'outgoing', + 'type' : LType.ListSubnets, + 'default' : '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, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32', + 'help' : 'If set, do not query these netmasks for DNS data', + 'doc' : ''' +The DNS is a public database, but sometimes contains delegations to private IP addresses, like for example 127.0.0.1. +This can have odd effects, depending on your network, and may even be a security risk. +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. 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. + ''', + }, + { + 'name' : 'add_for', + 'section' : 'ecs', + 'oldname' : 'ecs-add-for', + 'type' : LType.ListSubnets, + 'default' : '0.0.0.0/0, ::/0, !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', + 'help' : 'List of client netmasks for which EDNS Client Subnet will be added', + 'doc' : ''' +List of requestor netmasks for which the requestor IP Address should be used as the :rfc:`EDNS Client Subnet <7871>` for outgoing queries. Outgoing queries for requestors that do not match this list will use the :ref:`setting-ecs-scope-zero-address` instead. +Valid incoming ECS values from :ref:`setting-use-incoming-edns-subnet` are not replaced. + +Regardless of the value of this setting, ECS values are only sent for outgoing queries matching the conditions in the :ref:`setting-edns-subnet-allow-list` setting. This setting only controls the actual value being sent. + +This defaults to not using the requestor address inside RFC1918 and similar 'private' IP address spaces. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'ipv4_bits', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv4-bits', + 'type' : LType.Uint64, + 'default' : '24', + 'help' : 'Number of bits of IPv4 address to pass for EDNS Client Subnet', + 'doc' : ''' +Number of bits of client IPv4 address to pass when sending EDNS Client Subnet address information. + ''', + 'versionadded': '4.1.0', + }, + { + 'name' : 'ipv4_cache_bits', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv4-cache-bits', + 'type' : LType.Uint64, + 'default' : '24', + 'help' : 'Maximum number of bits of IPv4 mask to cache ECS response', + 'doc' : ''' +Maximum number of bits of client IPv4 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``. +That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. + ''', + 'versionadded': '4.1.12' + }, + { + 'name' : 'ipv6_bits', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv6-bits', + 'type' : LType.Uint64, + 'default' : '56', + 'help' : 'Number of bits of IPv6 address to pass for EDNS Client Subnet', + 'doc' : ''' +Number of bits of client IPv6 address to pass when sending EDNS Client Subnet address information. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'ipv6_cache_bits', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv6-cache-bits', + 'type' : LType.Uint64, + 'default' : '56', + 'help' : 'Maximum number of bits of IPv6 mask to cache ECS response', + 'doc' : ''' +Maximum number of bits of client IPv6 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``. +That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. + ''', + 'versionadded': '4.1.12' + }, + { + 'name' : 'ipv4_never_cache', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv4-never-cache', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If we should never cache IPv4 ECS responses', + 'doc' : ''' +When set, never cache replies carrying EDNS IPv4 Client Subnet scope in the record cache. +In this case the decision made by ``ecs-ipv4-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'ipv6_never_cache', + 'section' : 'ecs', + 'oldname' : 'ecs-ipv6-never-cache', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If we should never cache IPv6 ECS responses', + 'doc' : ''' +When set, never cache replies carrying EDNS IPv6 Client Subnet scope in the record cache. +In this case the decision made by ``ecs-ipv6-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'minimum_ttl_override', + 'section' : 'ecs', + 'oldname' : 'ecs-minimum-ttl-override', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'The minimum TTL for records in ECS-specific answers', + 'doc' : ''' +This setting artificially raises the TTLs of records in the ANSWER section of ECS-specific answers to be at least this long. +Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot. +Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact +authoritative servers every time a client requests them. + ''', + 'versionchanged': ('4.5.0', 'Old versions used default 0.'), + 'runtime': 'set-ecs-minimum-ttl', + }, + { + 'name' : 'cache_limit_ttl', + 'section' : 'ecs', + 'oldname' : 'ecs-cache-limit-ttl', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Minimum TTL to cache ECS response', + 'doc' : ''' +The minimum TTL for an ECS-specific answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-ipv4-cache-bits`` or ``ecs-ipv6-cache-bits``. +That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. + ''', + 'versionadded': '4.1.12' + }, + { + 'name' : 'scope_zero_address', + 'section' : 'ecs', + 'oldname' : 'ecs-scope-zero-address', + 'type' : LType.String, + 'default' : '', + 'help' : 'Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0', + 'doc' : ''' +The IP address sent via EDNS Client Subnet to authoritative servers listed in +:ref:`setting-edns-subnet-allow-list` when :ref:`setting-use-incoming-edns-subnet` is set and the query has +an ECS source prefix-length set to 0. +The default is to look for the first usable (not an ``any`` one) address in +:ref:`setting-query-local-address` (starting with IPv4). If no suitable address is +found, the recursor fallbacks to sending 127.0.0.1. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'edns_bufsize', + 'section' : 'outgoing', + 'oldname' : 'edns-outgoing-bufsize', + 'type' : LType.Uint64, + 'default' : '1232', + 'help' : 'Outgoing EDNS buffer size', + 'doc' : ''' +.. note:: Why 1232? + + 1232 is the largest number of payload bytes that can fit in the smallest IPv6 packet. + IPv6 has a minimum MTU of 1280 bytes (:rfc:`RFC 8200, section 5 <8200#section-5>`), minus 40 bytes for the IPv6 header, minus 8 bytes for the UDP header gives 1232, the maximum payload size for the DNS response. + +This is the value set for the EDNS0 buffer size in outgoing packets. +Lower this if you experience timeouts. + ''', + 'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680') + }, + { + 'name' : 'edns_padding_from', + 'section' : 'incoming', + 'type' : LType.ListSubnets, + 'default' : '', + 'help' : 'List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that \'edns-padding-mode\' applies', + 'doc' : ''' +List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that :ref:`setting-edns-padding-mode` applies. + ''', + 'versionadded' : '4.5.0', + 'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence') + }, + { + 'name' : 'edns_padding_mode', + 'section' : 'incoming', + 'type' : LType.String, + 'default' : 'padded-queries-only', + 'help' : 'Whether to add EDNS padding to all responses (\'always\') or only to responses for queries containing the EDNS padding option (\'padded-queries-only\', the default). In both modes, padding will only be added to responses for queries coming from \'setting-edns-padding-from\' sources', + 'doc' : ''' +One of ``always``, ``padded-queries-only``. +Whether to add EDNS padding to all responses (``always``) or only to responses for queries containing the EDNS padding option (``padded-queries-only``, the default). +In both modes, padding will only be added to responses for queries coming from :ref:`setting-edns-padding-from` sources. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'edns_padding', + 'section' : 'outgoing', + 'oldname' : 'edns-padding-out', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Whether to add EDNS padding to outgoing DoT messages', + 'doc' : ''' +Whether to add EDNS padding to outgoing DoT queries. + ''', + 'versionadded': '4.8.0' + }, + { + 'name' : 'edns_padding_tag', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '7830', + 'help' : 'Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.', + 'doc' : ''' +The packetcache tag to use for padded responses, to prevent a client not allowed by the :ref:`setting-edns-padding-from` list to be served a cached answer generated for an allowed one. This +effectively divides the packet cache in two when :ref:`setting-edns-padding-from` is used. Note that this will not override a tag set from one of the ``Lua`` hooks. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'edns_subnet_allow_list', + 'section' : 'outgoing', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'List of netmasks and domains that we should enable EDNS subnet for', + 'doc' : ''' +List of netmasks and domains that :rfc:`EDNS Client Subnet <7871>` should be enabled for in outgoing queries. + +For example, an EDNS Client Subnet option containing the address of the initial requestor (but see :ref:`setting-ecs-add-for`) will be added to an outgoing query sent to server 192.0.2.1 for domain X if 192.0.2.1 matches one of the supplied netmasks, or if X matches one of the supplied domains. +The initial requestor address will be truncated to 24 bits for IPv4 (see :ref:`setting-ecs-ipv4-bits`) and to 56 bits for IPv6 (see :ref:`setting-ecs-ipv6-bits`), as recommended in the privacy section of RFC 7871. + + +Note that this setting describes the destination of outgoing queries, not the sources of incoming queries, nor the subnets described in the EDNS Client Subnet option. + +By default, this option is empty, meaning no EDNS Client Subnet information is sent. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'edns_subnet_harden', + 'section' : 'outgoing', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Do more strict checking or EDNS Client Subnet information returned by authoritative servers', + 'doc' : ''' +Do more strict checking or EDNS Client Subnet information returned by authoritative servers. +Answers missing ECS information will be ignored and followed up by an ECS-less query. + ''', + 'versionadded': ['5.2.4', '5.1.6', '5.0.12'] + }, + { + 'name' : 'enable_old_settings', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Enable (deprecated) parsing of old-style settings', + 'doc' : ''' +Enable the deprecated parsing of old-style settings. +Only makes sense to set on the command line. + ''', + 'skip-yaml': True, + 'versionadded': '5.2.0', + }, + { + 'name' : 'entropy_source', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '/dev/urandom', + 'help' : '', + 'doc' : ''' + ''', + 'skip-yaml': True, + 'versionchanged': ('4.9.0', 'This setting is no longer used.'), + }, + { + 'name' : 'etc_hosts_file', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '/etc/hosts', + 'help' : 'Path to \'hosts\' file', + 'doc' : ''' +The path to the /etc/hosts file, or equivalent. +This file can be used to serve data authoritatively using :ref:`setting-export-etc-hosts`. + ''', + }, + { + 'name' : 'event_trace_enabled', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'If set, event traces are collected and send out via protobuf logging (1), logfile (2), opentelemetry trace data (4) or a combination', + 'doc' : ''' +Enable the recording and logging of ref:`event traces`. This is an experimental feature and subject to change. +Possible values are 0: (disabled), 1 (add information to protobuf logging messages), 2 (write to log), 4 (output OpenTelemetry Trace data in protobuf logging messages, since version 5.3.0). Values can be added to get multiple types of logging simultaneously. +For example, 6 means: write to log and output OpenTelemetry Trace data in the protobuf stream. + ''', + 'versionadded': '4.6.0', + 'versionchanged': ('5.3.0', 'A value to generate OpenTelemetry Trace data was added'), + 'runtime': 'set-event-trace-enabled', + }, + { + 'name' : 'export_etc_hosts', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If we should serve up contents from /etc/hosts', + 'doc' : ''' +If set, this flag will export the host names and IP addresses mentioned in ``/etc/hosts``. + ''', + }, + { + 'name' : 'export_etc_hosts_search_suffix', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Also serve up the contents of /etc/hosts with this suffix', + 'doc' : ''' +If set, all hostnames in the :ref:`setting-export-etc-hosts` file are loaded in canonical form, based on this suffix, unless the name contains a '.', in which case the name is unchanged. +So an entry called 'pc' with ``export-etc-hosts-search-suffix='home.com'`` will lead to the generation of 'pc.home.com' within the recursor. +An entry called 'server1.home' will be stored as 'server1.home', regardless of this setting. + ''', + }, + { + 'name' : 'extended_resolution_errors', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors', + 'doc' : ''' +If set, the recursor will add an EDNS Extended Error (:rfc:`8914`) to responses when resolution failed, like DNSSEC validation errors, explaining the reason it failed. This setting is not needed to allow setting custom error codes from Lua or from a RPZ hit. + ''', + 'versionadded': '4.5.0', + 'versionchanged': ('5.0.0', 'Default changed to enabled, previously it was disabled.'), + }, + { + 'name' : 'forward_zones', + 'section' : 'recursor', + 'type' : LType.ListForwardZones, + 'default' : '', + 'help' : 'Zones for which we forward queries, comma separated domain=ip pairs', + 'doc' : ''' +Queries for zones listed here will be forwarded to the IP address listed. i.e. + +.. code-block:: none + + forward-zones=example.org=203.0.113.210, powerdns.com=2001:DB8::BEEF:5 + +Multiple IP addresses can be specified and port numbers other than 53 can be configured: + +.. code-block:: none + + forward-zones=example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;198.51.100.10:530;[2001:DB8::1:3]:5300 + +Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning that this setting is intended to forward queries to authoritative servers. +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`. +See the :doc:`dnssec` information. + ''', + 'doc-new' : ''' +Queries for zones listed here will be forwarded to the IP address listed. i.e. + +.. code-block:: yaml + + recursor: + forward_zones: + - zone: example.org + forwarders: + - 203.0.113.210 + - zone: powerdns.com + forwarders: + - 2001:DB8::BEEF:5 + +Multiple IP addresses can be specified and port numbers other than 53 can be configured: + +.. code-block:: yaml + + recursor: + forward_zones: + - zone: example.org + forwarders: + - 203.0.113.210:5300 + - 127.0.0.1 + - zone: powerdns.com + forwarders: + - 127.0.0.1 + - 198.51.100.10:530 + - '[2001:DB8::1:3]:5300' + +Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning that this setting is intended to forward queries to authoritative servers. +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. +To forward to a recursive resolver use :ref:`setting-yaml-recursor.forward_zones_recurse`. + +.. warning:: + 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 :func:`addNTA`. + If this forwarded zone is signed, instead of adding NTA, add the DS record to the :ref:`setting-lua-config-file` using :func:`addTA`. + See the :doc:`dnssec` information. + When using trust anchors listed in a YAML settings file, use the :ref:`setting-yaml-dnssec.trustanchors` and :ref:`setting-yaml-dnssec.negative_trustanchors` clauses. + +.. note:: + The ``recurse`` field of a `Forward Zone`_ is fixed to ``false`` in the context of :ref:`setting-yaml-recursor.forward_zones`. + +.. 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. + ''', + 'versionchanged' : ('5.2.0', 'Zones having ``notify_allowed`` set will be added to :ref:`setting-yaml-incoming.allow_notify_for`.'), + 'runtime': ['reload-zones'], + }, + { + 'name' : 'forward_zones_file', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'File with (+)domain=ip pairs for forwarding', + 'doc' : ''' +Same as :ref:`setting-forward-zones`, parsed from a file. Only 1 zone is allowed per line, specified as follows: + +.. code-block:: none + + example.org=203.0.113.210, 192.0.2.4:5300 + +Zones prefixed with a ``+`` are treated as with +:ref:`setting-forward-zones-recurse`. Default behaviour without ``+`` is as with +:ref:`setting-forward-zones`. + +The DNSSEC notes from :ref:`setting-forward-zones` apply here as well. + ''', + 'doc-new' : ''' + Same as :ref:`setting-forward-zones`, parsed from a file as a sequence of `Forward Zone`_. + The filename MUST end in ``.yml`` for the content to be parsed as YAML. + +.. code-block:: yaml + + - zone: example1.com + forwarders: + - 127.0.0.1 + - 127.0.0.1:5353 + - '[::1]:53' + - zone: example2.com + forwarders: + - ::1 + recurse: true + notify_allowed: true + +The DNSSEC notes from :ref:`setting-forward-zones` apply here as well. + ''', + 'versionchanged': [('4.0.0', '(Old style settings only) Comments are allowed, everything behind ``#`` is ignored.'), + ('4.6.0', '(Old style settings only) Zones prefixed with a ``^`` are added to the :ref:`setting-allow-notify-for` list. Both prefix characters can be used if desired, in any order.')], + 'runtime': ['reload-zones'], + }, + { + 'name' : 'forward_zones_recurse', + 'section' : 'recursor', + 'type' : LType.ListForwardZones, + 'default' : '', + 'help' : 'Zones for which we forward queries with recursion bit, comma separated domain=ip pairs', + 'doc' : ''' +Like regular :ref:`setting-forward-zones`, but forwarded queries have the ``recursion desired (RD)`` bit set to ``1``, meaning that this setting is intended to forward queries to other recursive resolvers. +In contrast to regular forwarding, the rule that delegations of the forwarded subzones are respected is not active. +This is because we rely on the forwarder to resolve the query fully. + +See :ref:`setting-forward-zones` for additional options (such as supplying multiple recursive servers) and an important note about DNSSEC. + ''', + 'doc-new' : ''' +Like regular :ref:`setting-forward-zones`, but forwarded queries have the ``recursion desired (RD)`` bit set to ``1``, meaning that this setting is intended to forward queries to other recursive resolvers. +In contrast to regular forwarding, the rule that delegations of the forwarded subzones are respected is not active. +This is because we rely on the forwarder to resolve the query fully. + +.. note:: + The `recurse` field of a `Forward Zone`_ is fixed to ``true`` in the context of :ref:`setting-yaml-recursor.forward_zones_recurse`. + +See :ref:`setting-forward-zones` for additional options (such as supplying multiple recursive servers) and an important note about DNSSEC. + ''', + 'runtime': ['reload-zones'], + }, + { + 'name' : 'gettag_needs_edns_options', + 'section' : 'incoming', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If EDNS Options should be extracted before calling the gettag() hook', + 'doc' : ''' +If set, EDNS options in incoming queries are extracted and passed to the :func:`gettag` hook in the ``ednsoptions`` table. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'help', + 'section' : 'commands', + 'type' : LType.Command, + 'default' : 'no', + 'help' : 'Provide a helpful message', + 'doc' : ''' +EMPTY? ''' + }, + { + 'name' : 'hint_file', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, load root hints from this file', + 'doc' : ''' +If set, the root-hints are read from this file. If empty, the default built-in root hints are used. + +In some special cases, processing the root hints is not needed, for example when forwarding all queries to another recursor. +For these special cases, it is possible to disable the processing of root hints by setting the value to ``no`` or ``no-refresh``. +See :ref:`handling-of-root-hints` for more information on root hints handling. + ''', + 'versionchanged': [('4.6.2', 'Introduced the value ``no`` to disable root-hints processing.'), + ('4.9.0', 'Introduced the value ``no-refresh`` to disable both root-hints processing and periodic refresh of the cached root `NS` records.')] + }, + { + 'name' : 'ignore_unknown_settings', + 'section' : 'recursor', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'Configuration settings to ignore if they are unknown', + 'doc' : ''' +Names of settings to be ignored while parsing configuration files, if the setting +name is unknown to PowerDNS. + +Useful during upgrade testing. + ''', + }, + { + 'name' : 'include_dir', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + '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. + ''', + 'doc-new' : ''' +Directory to scan for additional config files. All files that end with ``.yml`` are loaded in order using ``POSIX`` as locale. + ''', + }, + { + 'name' : 'latency_statistic_size', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '10000', + 'help' : 'Number of latency values to calculate the qa-latency average', + 'doc' : ''' +Indication of how many queries will be averaged to get the average latency reported by the 'qa-latency' metric. + ''', + }, + { + 'name' : 'listen', + 'section' : 'incoming', + 'oldname' : 'local-address', + 'type' : LType.ListSocketAddresses, + 'default' : '127.0.0.1, ::1', + 'help' : 'IP addresses to listen on, separated by spaces or commas. Also accepts ports.', + 'versionchanged': ('5.3.0', '::1 was added to the list'), + 'doc' : ''' +Local IP addresses to which we bind. Each address specified can +include a port number; if no port is included then the +:ref:`setting-local-port` port will be used for that address. If a +port number is specified, it must be separated from the address with a +':'; for an IPv6 address the address must be enclosed in square +brackets. + +Examples:: + + local-address=127.0.0.1 ::1 + local-address=0.0.0.0:5353 + local-address=[::]:8053 + local-address=127.0.0.1:53, [::1]:5353 + ''', + 'doc-new' : ''' +Local IP addresses to which we bind. Each address specified can +include a port number; if no port is included then the +:ref:`setting-local-port` port will be used for that address. If a +port number is specified, it must be separated from the address with a +':'; for an IPv6 address the address must be enclosed in square +brackets. + +Example: + +.. code-block:: yaml + + incoming: + listen: + - 127.0.0.1 + - '[::1]:5353' + - '::' + ''', + }, + { + 'name' : 'port', + 'section' : 'incoming', + 'oldname' : 'local-port', + 'type' : LType.Uint64, + 'default' : '53', + 'help' : 'port to listen on', + 'doc' : ''' +Local port to bind to. +If an address in :ref:`setting-local-address` does not have an explicit port, this port is used. + ''', + }, + { + 'name' : 'timestamp', + 'section' : 'logging', + 'oldname' : 'log-timestamp', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Print timestamps in log lines, useful to disable when running with a tool that timestamps stderr already', + 'doc' : ''' + + ''', + }, + { + 'name' : 'non_local_bind', + 'section' : 'incoming', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Enable binding to non-local addresses by using FREEBIND / BINDANY socket options', + 'doc' : ''' +Bind to addresses even if one or more of the :ref:`setting-local-address`'s do not exist on this server. +Setting this option will enable the needed socket options to allow binding to non-local addresses. +This feature is intended to facilitate ip-failover setups, but it may also mask configuration issues and for this reason it is disabled by default. + ''', + }, + { + 'name' : 'loglevel', + 'section' : 'logging', + 'type' : LType.Uint64, + 'default' : '6', + 'help' : 'Amount of logging. Higher is more. Do not set below 3', + 'doc' : ''' +Amount of logging. The higher the number, the more lines logged. +Corresponds to ``syslog`` level values (e.g. 0 = ``emergency``, 1 = ``alert``, 2 = ``critical``, 3 = ``error``, 4 = ``warning``, 5 = ``notice``, 6 = ``info``, 7 = ``debug``). +Each level includes itself plus the lower levels before it. +Not recommended to set this below 3. +If :ref:`setting-quiet` is ``no/false``, :ref:`setting-loglevel` will be minimally set to ``6 (info)``. + ''', + 'versionchanged': ('5.0.0', 'Previous version would not allow setting a level below ``3 (error)``.') + }, + { + 'name' : 'common_errors', + 'section' : 'logging', + 'oldname' : 'log-common-errors', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If we should log rather common errors', + 'doc' : ''' +Some DNS errors occur rather frequently and are no cause for alarm. + ''', + }, + { + 'name' : 'rpz_changes', + 'section' : 'logging', + 'oldname' : 'log-rpz-changes', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Log additions and removals to RPZ zones at Info level', + 'doc' : ''' +Log additions and removals to RPZ zones at Info (6) level instead of Debug (7). + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'facility', + 'section' : 'logging', + 'oldname' : 'logging-facility', + 'type' : LType.String, + 'default' : '', + 'help' : 'Facility to log messages as. 0 corresponds to local0', + 'doc' : ''' +If set to a digit, logging is performed under this LOCAL facility. +See :ref:`logging`. +Do not pass names like 'local0'! + ''', + }, + { + 'name' : 'lowercase', + 'section' : 'outgoing', + 'oldname' : 'lowercase-outgoing', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Force outgoing questions to lowercase', + 'doc' : ''' +Set to true to lowercase the outgoing queries. +When set to 'no' (the default) a query from a client using mixed case in the DNS labels (such as a user entering mixed-case names or `draft-vixie-dnsext-dns0x20-00 `_), PowerDNS preserves the case of the query. +Broken authoritative servers might give a wrong or broken answer on this encoding. +Setting ``lowercase-outgoing`` to 'yes' makes the PowerDNS Recursor lowercase all the labels in the query to the authoritative servers, but still return the proper case to the client requesting. + ''', + }, + { + 'name' : 'lua_config_file', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'More powerful configuration options', + '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. + ''', + }, + { + 'name' : 'lua_dns_script', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Filename containing an optional Lua script that will be used to modify dns answers', + 'doc' : ''' +Path to a lua file to manipulate the Recursor's answers. See :doc:`lua-scripting/index` for more information. + ''', + }, + { + 'name' : 'lua_maintenance_interval', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'Number of seconds between calls to the lua user defined maintenance() function', + 'doc' : ''' +The interval between calls to the Lua user defined `maintenance()` function in seconds. +See :ref:`hooks-maintenance-callback` + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'max_busy_dot_probes', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Maximum number of concurrent DoT probes', + 'doc' : ''' +Limit the maximum number of simultaneous DoT probes the Recursor will schedule. +The default value 0 means no DoT probes are scheduled. + +DoT probes are used to check if an authoritative server's IP address supports DoT. +If the probe determines an IP address supports DoT, the Recursor will use DoT to contact it for subsequent queries until a failure occurs. +After a failure, the Recursor will stop using DoT for that specific IP address for a while. +The results of probes are remembered and can be viewed by the ``rec_control dump-dot-probe-map`` command. +If the maximum number of pending probes is reached, no probes will be scheduled, even if no DoT status is known for an address. +If the result of a probe is not yet available, the Recursor will contact the authoritative server in the regular way, unless an authoritative server is configured to be contacted over DoT always using :ref:`setting-dot-to-auth-names`. +In that case no probe will be scheduled. + +.. note:: + DoT probing is an experimental feature. + Please test thoroughly to determine if it is suitable in your specific production environment before enabling. + ''', + 'versionadded': '4.7.0' + }, + { + 'name' : 'max_cache_bogus_ttl', + 'section' : 'recordcache', + 'type' : LType.Uint64, + 'default' : '3600', + 'help' : 'maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory', + 'doc' : ''' +Maximum number of seconds to cache an item in the DNS cache (negative or positive) if its DNSSEC validation failed, no matter what the original TTL specified, to reduce the impact of a broken domain. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'max_entries', + 'section' : 'recordcache', + 'oldname' : 'max-cache-entries', + 'type' : LType.Uint64, + 'default' : '1000000', + 'help' : 'If set, maximum number of entries in the main cache', + 'doc' : ''' +Maximum number of DNS record cache entries, shared by all threads since 4.4.0. +Each entry associates a name and type with a record set. +The size of the negative cache is 10% of this number. + ''', + 'runtime': 'set-max-cache-entries', + }, + { + 'name' : 'max_ttl', + 'section' : 'recordcache', + 'oldname' : 'max-cache-ttl', + 'type' : LType.Uint64, + 'default' : '86400', + 'help' : 'maximum number of seconds to keep a cached entry in memory', + 'doc' : ''' +Maximum number of seconds to cache an item in the DNS cache, no matter what the original TTL specified. +This value also controls the refresh period of cached root data. +See :ref:`handling-of-root-hints` for more information on this. + ''', + 'versionchanged': ('4.1.0', 'The minimum value of this setting is 15. i.e. setting this to lower than 15 will make this value 15.') + }, + { + 'name' : 'max_entry_size', + 'section' : 'recordcache', + 'oldname': 'max-recordcache-entry-size', + 'type' : LType.Uint64, + 'default' : '8192', + 'help' : 'maximum storage size of a recordset stored in record cache', + 'doc' : ''' +Maximum size of storage used by a single record cache entry. Entries larger than this number will not be stored. +Zero means no limit. +''', + 'versionadded': ['5.1.10', '5.2.8', '5.3.5'], + }, + { + 'name' : 'max_concurrent_requests_per_tcp_connection', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '10', + 'help' : 'Maximum number of requests handled concurrently per TCP connection', + 'doc' : ''' +Maximum number of incoming requests handled concurrently per tcp +connection. This number must be larger than 0 and smaller than 65536 +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', + 'type' : LType.Uint64, + 'default' : '20', + 'help' : 'Maximum nested $INCLUDE depth when loading a zone from a file', + 'doc' : ''' +Maximum number of nested ``$INCLUDE`` directives while processing a zone file. +Zero mean no ``$INCLUDE`` directives will be accepted. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'max_generate_steps', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Maximum number of $GENERATE steps when loading a zone from a file', + 'doc' : ''' +Maximum number of steps for a '$GENERATE' directive when parsing a +zone file. This is a protection measure to prevent consuming a lot of +CPU and memory when untrusted zones are loaded. Default to 0 which +means unlimited. + ''', + 'versionadded': '4.3.0' + }, + { + 'name' : 'max_mthreads', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '2048', + 'help' : 'Maximum number of simultaneous Mtasker threads', + 'doc' : ''' +Maximum number of simultaneous MTasker threads, per worker thread. + ''', + }, + { + 'name' : 'max_entries', + 'section' : 'packetcache', + 'oldname' : 'max-packetcache-entries', + 'type' : LType.Uint64, + 'default' : '500000', + 'help' : 'maximum number of entries to keep in the packetcache', + 'doc' : ''' +Maximum number of Packet Cache entries. Sharded and shared by all threads since 4.9.0. +''', + 'runtime': 'set-max-packetcache-entries', + }, + { + 'name' : 'max_entry_size', + 'section' : 'packetcache', + 'oldname' : 'max-packetcache-entry-size', + 'type' : LType.Uint64, + 'default' : '8192', + 'help' : 'maximum size of a packet stored in the the packet cache', + 'doc' : ''' +Maximum size of packets stored in the packet cache. Packets larger than this number will not be stored. +Zero means no limit. +''', + 'versionadded': ['5.1.10', '5.2.8', '5.3.5'], + }, + { + 'name' : 'max_qperq', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '50', + 'help' : 'Maximum outgoing queries per client query', + 'doc' : ''' +The maximum number of outgoing queries that will be sent out during the resolution of a single client query. +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_bytesperq', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '100000', + 'help' : 'Maximum number of received bytes per client query', + 'doc' : ''' +The maximum number of cumulative bytes that will be accepted during the resolution of a single client query. +This is useful to limit amplification attacks. + ''', + 'versionadded': ['5.1.10', '5.2.8', '5.3.5'], + }, + { + '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' : 'limit_qtype_any', + 'section' : 'recordcache', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Limit answers to ANY queries in size', + 'doc' : ''' +Limit answers to ANY queries constructed from the record cache in size. +Trying to retrieve more than :ref:`setting-max-rrset-size` records will result in a ``ServFail``', + ''', + 'versionadded': ['4.9.9', '5.0.9', '5.1.2'] + }, + { + 'name' : 'max_rrset_size', + 'section' : 'recordcache', + 'type' : LType.Uint64, + 'default' : '256', + 'help' : 'Maximum size of RRSet in cache', + 'doc' : ''' +Maximum size of RRSets in cache. +Trying to retrieve larger RRSets will result in a ``ServFail``.', + ''', + 'versionadded': ['4.9.9', '5.0.9', '5.1.2'] + }, + { + 'name' : 'max_ns_address_qperq', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '10', + 'help' : 'Maximum outgoing NS address queries per query', + 'doc' : ''' +The maximum number of outgoing queries with empty replies for +resolving nameserver names to addresses we allow during the resolution +of a single client query. If IPv6 is enabled, an A and a AAAA query +for a name counts as 1. If a zone publishes more than this number of +NS records, the limit is further reduced for that zone by lowering +it by the number of NS records found above the +:ref:`setting-max-ns-address-qperq` value. The limit will not be reduced to a +number lower than 5. + ''', + 'versionadded' : ['4.1.16', '4.2.2', '4.3.1'] + }, + { + 'name' : 'max_ns_per_resolve', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '13', + 'help' : 'Maximum number of NS records to consider to resolve a name, 0 is no limit', + 'doc' : ''' +The maximum number of NS records that will be considered to select a nameserver to contact to resolve a name. +If a zone has more than :ref:`setting-max-ns-per-resolve` NS records, a random sample of this size will be used. +If :ref:`setting-max-ns-per-resolve` is zero, no limit applies. + ''', + 'versionadded': ['4.8.0', '4.7.3', '4.6.4', '4.5.11'] + }, + { + 'name' : 'max_negative_ttl', + 'section' : 'recordcache', + 'type' : LType.Uint64, + 'default' : '3600', + 'help' : 'maximum number of seconds to keep a negative cached entry in memory', + 'doc' : ''' +A query for which there is authoritatively no answer is cached to quickly deny a record's existence later on, without putting a heavy load on the remote server. +In practice, caches can become saturated with hundreds of thousands of hosts which are tried only once. +This setting, which defaults to 3600 seconds, puts a maximum on the amount of time negative entries are cached. + ''', + }, + { + 'name' : 'max_recursion_depth', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '16', + 'help' : 'Maximum number of internal recursion calls per query, 0 for unlimited', + 'doc' : ''' +Total maximum number of internal recursion calls the server may use to answer a single query. +0 means unlimited. +The value of :ref:`setting-stack-size` should be increased together with this one to prevent the stack from overflowing. +If :ref:`setting-qname-minimization` is enabled, the fallback code in case of a failing resolve is allowed an additional `max-recursion-depth/2`. + ''', + 'versionchanged': [('4.1.0', 'Before 4.1.0, this settings was unlimited.'), + ('4.9.0', "Before 4.9.0 this setting's default was 40 and the limit on ``CNAME`` chains (fixed at 16) acted as a bound on he recursion depth.")] + }, + { + 'name' : 'max_tcp_clients', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '1024', + 'help' : 'Maximum number of simultaneous TCP clients', + 'doc' : ''' +Maximum number of simultaneous incoming TCP connections allowed. + ''', + 'versionchanged': ('5.2.0', 'Before 5.2.0 the default was 128.'), + }, + { + 'name' : 'max_tcp_per_client', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'If set, maximum number of TCP sessions per client (IP address)', + 'doc' : ''' +Maximum number of simultaneous incoming TCP connections allowed per client (remote IP address). +0 means unlimited. + ''', + }, + { + 'name' : 'max_tcp_queries_per_connection', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'If set, maximum number of TCP queries in a TCP connection', + 'doc' : ''' +Maximum number of DNS queries in a TCP connection. +0 means unlimited. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'max_total_msec', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '7000', + 'help' : 'Maximum total wall-clock time per query in milliseconds, 0 for unlimited', + 'doc' : ''' +Total maximum number of milliseconds of wallclock time the server may use to answer a single query. +0 means unlimited. + ''', + }, + { + 'name' : 'max_udp_queries_per_round', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '10000', + 'help' : 'Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing', + 'doc' : ''' +Under heavy load the recursor might be busy processing incoming UDP queries for a long while before there is no more of these, and might therefore +neglect scheduling new ``mthreads``, handling responses from authoritative servers or responding to :doc:`rec_control ` +requests. +This setting caps the maximum number of incoming UDP DNS queries processed in a single round of looping on ``recvmsg()`` after being woken up by the multiplexer, before +returning back to normal processing and handling other events. + ''', + 'versionadded': '4.1.4' + }, + { + 'name' : 'minimum_ttl_override', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'The minimum TTL', + 'doc' : ''' +This setting artificially raises all TTLs to be at least this long. +Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot. +Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact +authoritative servers each time a client requests them. + ''', + 'versionchanged': ('4.5.0', 'Old versions used default 0.'), + 'runtime': 'set-minimum-ttl', + }, + { + 'name' : 'tracking', + 'section' : 'nod', + 'oldname' : 'new-domain-tracking', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Track newly observed domains (i.e. never seen before).', + 'doc' : ''' +Whether to track newly observed domains, i.e. never seen before. This +is a probabilistic algorithm, using a stable bloom filter to store +records of previously seen domains. When enabled for the first time, +all domains will appear to be newly observed, so the feature is best +left enabled for e.g. a week or longer before using the results. Note +that this feature is optional and must be enabled at compile-time, +thus it may not be available in all pre-built packages. +If protobuf is enabled and configured, then the newly observed domain +status will appear as a flag in Response messages. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'log', + 'section' : 'nod', + 'oldname' : 'new-domain-log', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Log newly observed domains.', + 'doc' : ''' +If a newly observed domain is detected, log that domain in the +recursor log file. The log line looks something like:: + + Jul 18 11:31:25 Newly observed domain nod=sdfoijdfio.com + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'lookup', + 'section' : 'nod', + 'oldname' : 'new-domain-lookup', + 'type' : LType.String, + 'default' : '', + 'help' : 'Perform a DNS lookup newly observed domains as a subdomain of the configured domain', + 'doc' : ''' +If a domain is specified, then each time a newly observed domain is +detected, the recursor will perform an A record lookup of '.'. For example if 'new-domain-lookup' +is configured as 'nod.powerdns.com', and a new domain 'example.com' is +detected, then an A record lookup will be made for +'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. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'db_size', + 'section' : 'nod', + 'oldname' : 'new-domain-db-size', + 'type' : LType.Uint64, + 'default' : '67108864', + 'help' : 'Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864', + 'doc' : ''' +The default size of the stable bloom filter used to store previously +observed domains is 67108864. To change the number of cells, use this +setting. For each cell, the SBF uses 1 bit of memory, and one byte of +disk for the persistent file. +If there are already persistent files saved to disk, this setting will +have no effect unless you remove the existing files. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'history_dir', + 'section' : 'nod', + 'oldname' : 'new-domain-history-dir', + 'type' : LType.String, + 'default' : 'NODCACHEDIRNOD', + 'docdefault': 'Determined by distribution', + 'help' : 'Persist new domain tracking data here to persist between restarts', + 'doc' : ''' +This setting controls which directory is used to store the on-disk +cache of previously observed domains. + +The default depends on ``LOCALSTATEDIR`` when building the software. +Usually this comes down to ``/var/lib/pdns-recursor/nod`` or ``/usr/local/var/lib/pdns-recursor/nod``). + +The newly observed domain feature uses a stable bloom filter to store +a history of previously observed domains. The data structure is +synchronized to disk every 10 minutes, and is also initialized from +disk on startup. This ensures that previously observed domains are +preserved across recursor restarts. +If you change the new-domain-db-size setting, you must remove any files +from this directory. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'db_snapshot_interval', + 'section' : 'nod', + 'oldname' : 'new-domain-db-snapshot-interval', + 'type' : LType.Uint64, + 'default' : '600', + 'help' : 'Interval (in seconds) to write the NOD and UDR DB snapshots', + 'doc' : ''' +Interval (in seconds) to write the NOD and UDR DB snapshots. +Set to zero to disable snapshot writing.', + ''', + 'versionadded': '5.1.0' + }, + { + 'name' : 'ignore_list', + 'section' : 'nod', + 'oldname' : 'new-domain-ignore-list', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'List of domains (and implicitly all subdomains) which will never be considered a new domain', + '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 +'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', + 'oldname' : 'new-domain-pb-tag', + 'type' : LType.String, + 'default' : 'pdns-nod', + 'help' : 'If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to \'pdns-nod\'', + 'doc' : ''' +If protobuf is configured, then this tag will be added to all protobuf response messages when +a new domain is observed. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'network_timeout', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '1500', + '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. + ''', + }, + { + 'name' : 'no_shuffle', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Don\'t change', + 'doc' : 'SKIP', + 'skip-yaml': True, + }, + { + 'name' : 'non_resolving_ns_max_fails', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '5', + 'help' : 'Number of failed address resolves of a nameserver to start throttling it, 0 is disabled', + 'doc' : ''' +Number of failed address resolves of a nameserver name to start throttling it, 0 is disabled. +Nameservers matching :ref:`setting-dont-throttle-names` will not be throttled. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'non_resolving_ns_throttle_time', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '60', + 'help' : 'Number of seconds to throttle a nameserver with a name failing to resolve', + 'doc' : ''' +Number of seconds to throttle a nameserver with a name failing to resolve. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'nothing_below_nxdomain', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : 'dnssec', + 'help' : 'When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)', + 'doc' : ''' +- One of ``no``, ``dnssec``, ``yes``. + +The type of :rfc:`8020` handling using cached NXDOMAIN responses. +This RFC specifies that NXDOMAIN means that the DNS tree under the denied name MUST be empty. +When an NXDOMAIN exists in the cache for a shorter name than the qname, no lookup is done and an NXDOMAIN is sent to the client. + +For instance, when ``foo.example.net`` is negatively cached, any query +matching ``*.foo.example.net`` will be answered with NXDOMAIN directly +without consulting authoritative servers. + +``no`` + No :rfc:`8020` processing is done. + +``dnssec`` + :rfc:`8020` processing is only done using cached NXDOMAIN records that are + DNSSEC validated. + +``yes`` + :rfc:`8020` processing is done using any non-Bogus NXDOMAIN record + available in the cache. + ''', + 'versionadded': '4.3.0' + }, + { + 'name' : 'nsec3_max_iterations', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '50', + 'help' : 'Maximum number of iterations allowed for an NSEC3 record', + 'doc' : ''' +Maximum number of iterations allowed for an NSEC3 record. +If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as ``Insecure``. + ''', + 'versionadded': '4.1.0', + 'versionchanged': [('4.5.2', 'Default is now 150, was 2500 before.'), + ('5.0.0', 'Default is now 50, was 150 before.')] + }, + { + 'name' : 'max_rrsigs_per_record', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '2', + 'help' : 'Maximum number of RRSIGs to consider when validating a given record', + 'doc' : ''' +Maximum number of RRSIGs we are willing to cryptographically check when validating a given record. Expired or not yet incepted RRSIGs do not count toward to this limit. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'max_nsec3s_per_record', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '10', + 'help' : 'Maximum number of NSEC3s to consider when validating a given denial of existence', + 'doc' : ''' +Maximum number of NSEC3s to consider when validating a given denial of existence. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'max_signature_validations_per_query', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '30', + 'help' : 'Maximum number of RRSIG signatures we are willing to validate per incoming query', + 'doc' : ''' +Maximum number of RRSIG signatures we are willing to validate per incoming query. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'max_nsec3_hash_computations_per_query', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '600', + 'help' : 'Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query', + 'doc' : ''' +Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'aggressive_cache_max_nsec3_hash_cost', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '150', + 'help' : 'Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache', + 'doc' : ''' +Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache. The cost is estimated based on a heuristic taking the zone's NSEC3 salt and iterations parameters into account, as well at the number of labels of the requested name. For example a query for a name like a.b.c.d.e.f.example.com. in an example.com zone. secured with NSEC3 and 10 iterations (NSEC3 iterations count of 9) and an empty salt will have an estimated worst-case cost of 10 (iterations) * 6 (number of labels) = 60. The aggressive NSEC cache is an optimization to reduce the number of queries to authoritative servers, which is especially useful when a zone is under pseudo-random subdomain attack, and we want to skip it the zone parameters make it expensive. +''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'max_ds_per_zone', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '8', + 'help' : 'Maximum number of DS records to consider per zone', + 'doc' : ''' +Maximum number of DS records to consider when validating records inside a zone. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'max_dnskeys', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '2', + 'help' : 'Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record', + 'doc' : ''' +Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record. Setting this value to 1 effectively denies DNSKEY tag collisions in a zone. + ''', + 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], + }, + { + 'name' : 'ttl', + 'section' : 'packetcache', + 'oldname' : 'packetcache-ttl', + 'type' : LType.Uint64, + 'default' : '86400', + 'help' : 'maximum number of seconds to keep a cached entry in packetcache', + 'doc' : ''' +Maximum number of seconds to cache an item in the packet cache, no matter what the original TTL specified. + ''', + 'versionchanged': ('4.9.0', 'The default was changed from 3600 (1 hour) to 86400 (24 hours).') + }, + { + 'name' : 'negative_ttl', + 'section' : 'packetcache', + 'oldname' : 'packetcache-negative-ttl', + 'type' : LType.Uint64, + 'default' : '60', + 'help' : 'maximum number of seconds to keep a cached NxDomain or NoData entry in packetcache', + 'doc' : ''' +Maximum number of seconds to cache an ``NxDomain`` or ``NoData`` answer in the packetcache. +This setting's maximum is capped to :ref:`setting-packetcache-ttl`. +i.e. setting ``packetcache-ttl=15`` and keeping ``packetcache-negative-ttl`` at the default will lower ``packetcache-negative-ttl`` to ``15``. + ''', + 'versionadded': '4.9.0' + }, + { + 'name' : 'servfail_ttl', + 'section' : 'packetcache', + 'oldname' : 'packetcache-servfail-ttl', + 'type' : LType.Uint64, + 'default' : '60', + 'help' : 'maximum number of seconds to keep a cached servfail entry in packetcache', + 'doc' : ''' +Maximum number of seconds to cache an answer indicating a failure to resolve in the packet cache. +Before version 4.6.0 only ``ServFail`` answers were considered as such. Starting with 4.6.0, all responses with a code other than ``NoError`` and ``NXDomain``, or without records in the answer and authority sections, are considered as a failure to resolve. +Since 4.9.0, negative answers are handled separately from resolving failures. + ''', + 'doc-rst' : ''' + 'versionchanged': ('4.0.0', "This setting's maximum is capped to :ref:`setting-packetcache-ttl`. + i.e. setting ``packetcache-ttl=15`` and keeping ``packetcache-servfail-ttl`` at the default will lower ``packetcache-servfail-ttl`` to ``15``.") + ''' + }, + { + 'name' : 'shards', + 'section' : 'packetcache', + 'oldname' : 'packetcache-shards', + 'type' : LType.Uint64, + 'default' : '1024', + 'help' : 'Number of shards in the packet cache', + 'doc' : ''' +Sets the number of shards in the packet cache. If you have high contention as reported by ``packetcache-contented/packetcache-acquired``, +you can try to enlarge this value or run with fewer threads. + ''', + 'versionadded': '4.9.0' + }, + { + 'name' : 'pdns_distributes_queries', + 'section' : 'incoming', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If PowerDNS itself should distribute queries over threads', + 'doc' : ''' +If set, PowerDNS will use distinct threads to listen to client sockets and distribute that work to worker-threads using a hash of the query. +This feature should maximize the cache hit ratio on versions before 4.9.0. +To use more than one thread set :ref:`setting-distributor-threads` in version 4.2.0 or newer. +Enabling should improve performance on systems where :ref:`setting-reuseport` does not have the effect of +balancing the queries evenly over multiple worker threads. + ''', + 'versionchanged': ('4.9.0', 'Default changed to ``no``, previously it was ``yes``.') + }, + { + 'name' : 'processes', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)', + 'doc' : '''SKIP''', + 'skip-yaml': True, + }, + { + 'name' : 'protobuf_use_kernel_timestamp', + 'section' : 'logging', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)', + 'doc' : ''' +Whether to compute the latency of responses in protobuf messages using the timestamp set by the kernel when the query packet was received (when available), instead of computing it based on the moment we start processing the query. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'proxy_protocol_from', + 'section' : 'incoming', + 'type' : LType.ListSubnets, + 'default' : '', + 'help' : 'A Proxy Protocol header is required from these subnets', + 'doc' : ''' +Ranges that are required to send a Proxy Protocol version 2 header in front of UDP and TCP queries, to pass the original source and destination addresses and ports to the recursor, as well as custom values. +Queries that are not prefixed with such a header will not be accepted from clients in these ranges. Queries prefixed by headers from clients that are not listed in these ranges will be dropped. + +Note that once a Proxy Protocol header has been received, the source address from the proxy header instead of the address of the proxy will be checked against the :ref:`setting-allow-from` ACL. + +The dnsdist docs have `more information about the PROXY protocol `_. + ''', + 'versionadded' : '4.4.0', + 'versionchanged' : [('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence'), + ('5.3.0', '``rec_control reload-acls`` reloads this setting')], + 'runtime': ['reload-acls (since 5.3.0)'], + }, + { + 'name' : 'proxy_protocol_exceptions', + 'section' : 'incoming', + 'type' : LType.ListSocketAddresses, + 'default' : '', + 'help' : 'A Proxy Protocol header should not be used for these listen addresses.', + 'doc' : ''' +If set, clients sending from an address in :ref:`setting-proxy-protocol-from` to an address:port listed here are excluded from using the Proxy Protocol. +If no port is specified, port 53 is assumed. +This is typically used to provide an easy to use address and port to send debug queries to. + ''', + 'versionadded' : '5.1.0', + 'versionchanged' : ('5.3.0', '``rec_control reload-acls`` reloads this setting'), + 'runtime': ['reload-acls (since 5.3.0)'], + }, + { + 'name' : 'proxy_protocol_maximum_size', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '512', + 'help' : 'The maximum size of a proxy protocol payload, including the TLV values', + 'doc' : ''' +The maximum size, in bytes, of a Proxy Protocol payload (header, addresses and ports, and TLV values). Queries with a larger payload will be dropped. + ''', + 'versionadded': '4.4.0' + }, + { + 'name' : 'public_suffix_list_file', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Path to the Public Suffix List file, if any', + 'doc' : ''' +Path to the Public Suffix List file, if any. If set, PowerDNS will try to load the Public Suffix List from this file instead of using the built-in list. The PSL is used to group the queries by relevant domain names when displaying the top queries. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'qname_minimization', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Use Query Name Minimization', + 'doc' : ''' +Enable Query Name Minimization. This implements a relaxed form of Query Name Mimimization as +described in :rfc:`9156`. + ''', + 'versionadded': '4.3.0' + }, + { + 'name' : 'qname_max_minimize_count', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '10', + 'help' : 'RFC9156 max minimize count', + 'doc' : ''' +``Max minimize count`` parameter, described in :rfc:`9156`. This is the maximum number of iterations +of the Query Name Minimization Algorithm. + ''', + 'versionadded': '5.0.0' + }, + { + 'name' : 'qname_minimize_one_label', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '4', + 'help' : 'RFC9156 minimize one label parameter', + 'doc' : ''' +``Minimize one label`` parameter, described in :rfc:`9156`. +The value for the number of iterations of the Query Name Minimization Algorithm that should only have one label appended. +This value has precedence over :ref:`setting-qname-max-minimize-count`. + ''', + 'versionadded': '5.0.0' + }, + { + 'name' : 'source_address', + 'section' : 'outgoing', + 'oldname' : 'query-local-address', + 'type' : LType.ListSubnets, + 'default' : '0.0.0.0', + 'help' : 'Source IP address for sending queries', + 'doc' : ''' +.. note:: + While subnets and their negations are mentioned as accepted, the handling of subnets has not been implemented yet. + Only individual IP addresses can be listed. + +Send out local queries from this address, or addresses. By adding multiple +addresses, increased spoofing resilience is achieved. When no address of a certain +address family is configured, there are *no* queries sent with that address family. +In the default configuration this means that IPv6 is not used for outgoing queries. + ''', + 'versionchanged': ('4.4.0', 'IPv6 addresses can be set with this option as well.') + }, + { + 'name' : 'quiet', + 'section' : 'logging', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Suppress logging of questions and answers', + 'doc' : ''' +Don't log queries. + ''', + }, + { + 'name' : 'locked_ttl_perc', + 'section' : 'recordcache', + 'oldname' : 'record-cache-locked-ttl-perc', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Replace records in record cache only after this % of original TTL has passed', + 'doc' : ''' +Replace record sets in the record cache only after this percentage of the original TTL has passed. +The PowerDNS Recursor already has several mechanisms to protect against spoofing attempts. +This adds an extra layer of protection---as it limits the window of time cache updates are accepted---at the cost of a less efficient record cache. + +The default value of 0 means no extra locking occurs. +When non-zero, record sets received (e.g. in the Additional Section) will not replace existing record sets in the record cache until the given percentage of the original TTL has expired. +A value of 100 means only expired record sets will be replaced. + +There are a few cases where records will be replaced anyway: + +- Record sets that are expired will always be replaced. +- Authoritative record sets will replace unauthoritative record sets unless DNSSEC validation of the new record set failed. +- If the new record set belongs to a DNSSEC-secure zone and successfully passed validation it will replace an existing entry. +- Record sets produced by :ref:`setting-refresh-on-ttl-perc` tasks will also replace existing record sets. + ''', + 'versionadded': '4.8.0' + }, + { + 'name' : 'shards', + 'section' : 'recordcache', + 'oldname' : 'record-cache-shards', + 'type' : LType.Uint64, + 'default' : '1024', + 'help' : 'Number of shards in the record cache', + 'doc' : ''' +Sets the number of shards in the record cache. If you have high +contention as reported by +``record-cache-contented/record-cache-acquired``, you can try to +enlarge this value or run with fewer threads. + ''', + 'versionadded': '4.4.0' + }, + { + 'name' : 'refresh_on_ttl_perc', + 'section' : 'recordcache', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'If a record is requested from the cache and only this % of original TTL remains, refetch', + 'doc' : ''' +Sets the 'refresh almost expired' percentage of the record cache. Whenever a record is fetched from the packet or record cache +and only ``refresh-on-ttl-perc`` percent or less of its original TTL is left, a task is queued to refetch the name/type combination to +update the record cache. In most cases this causes future queries to always see a non-expired record cache entry. +A typical value is 10. If the value is zero, this functionality is disabled. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'reuseport', + 'section' : 'incoming', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address', + 'doc' : ''' +If ``SO_REUSEPORT`` support is available, allows multiple threads and processes to open listening sockets for the same port. + +Since 4.1.0, when :ref:`setting-pdns-distributes-queries` is disabled and :ref:`setting-reuseport` is enabled, every worker-thread will open a separate listening socket to let the kernel distribute the incoming queries instead of running a distributor thread (which could otherwise be a bottleneck) and avoiding thundering herd issues, thus leading to much higher performance on multi-core boxes. + ''', + 'versionchanged': ('4.9.0', 'The default is changed to ``yes``, previously it was ``no``. If ``SO_REUSEPORT`` support is not available, the setting defaults to ``no``.') + }, + { + 'name' : 'rng', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : 'auto', + 'help' : '', + 'doc' : ''' + ''', + 'skip-yaml': True, + 'versionchanged': ('4.9.0', 'This setting is no longer used.') + }, + { + 'name' : 'root_nx_trust', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'If set, believe that an NXDOMAIN from the root means the TLD does not exist', + 'doc' : ''' +If set, an NXDOMAIN from the root-servers will serve as a blanket NXDOMAIN for the entire TLD the query belonged to. +The effect of this is far fewer queries to the root-servers. + ''', + 'versionchanged': ('4.0.0', "Default is ``yes`` now, was ``no`` before 4.0.0") + }, + { + 'name' : 'save_parent_ns_set', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Save parent NS set to be used if child NS set fails', + 'doc' : ''' +If set, a parent (non-authoritative) ``NS`` set is saved if it contains more entries than a newly encountered child (authoritative) ``NS`` set for the same domain. +The saved parent ``NS`` set is tried if resolution using the child ``NS`` set fails. + ''', + 'versionadded': '4.7.0' + }, + { + 'name' : 'security_poll_suffix', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : 'secpoll.powerdns.com.', + 'help' : 'Domain name from which to query security update notifications', + 'doc' : ''' +Domain name from which to query security update notifications. +Setting this to an empty string disables secpoll. + ''', + }, + { + 'name' : 'serve_rfc1918', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'If we should be authoritative for RFC 1918 private IP space', + 'doc' : ''' +This makes the server authoritatively aware of: ``10.in-addr.arpa``, ``168.192.in-addr.arpa``, ``16-31.172.in-addr.arpa``, which saves load on the AS112 servers. +Individual parts of these zones can still be loaded or forwarded. + ''', + 'runtime': ['reload-zones'], + }, + { + 'name' : 'serve_rfc6303', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'If we should be authoritative for RFC 6303 private IP space', + 'doc' : ''' +This makes the server authoritatively aware of the zones in RFC 6303 not covered by RFC 1918. +Individual parts of these zones can still be loaded or forwarded. +:ref:`setting-serve-rfc1918` must be enabled for this option to take effect. +''', + 'versionadded': ['5.1.3', '5.2.0'], + 'runtime': ['reload-zones'], + }, + { + 'name' : 'serve_stale_extensions', + 'section' : 'recordcache', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Number of times a record\'s ttl is extended by 30s to be served stale', + 'doc' : ''' +Maximum number of times an expired record's TTL is extended by 30s when serving stale. +Extension only occurs if a record cannot be refreshed. +A value of 0 means the ``Serve Stale`` mechanism is not used. +To allow records becoming stale to be served for an hour, use a value of 120. +See :ref:`serve-stale` for a description of the Serve Stale mechanism. + ''', + 'versionadded': '4.8.0' + }, + { + 'name' : 'server_down_max_fails', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '64', + 'help' : 'Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )', + 'doc' : ''' +If a server has not responded in any way this many times in a row, no longer send it any queries for :ref:`setting-server-down-throttle-time` seconds. +Afterwards, we will try a new packet, and if that also gets no response at all, we again throttle for :ref:`setting-server-down-throttle-time` seconds. +Even a single response packet will drop the block. + ''', + }, + { + 'name' : 'server_down_throttle_time', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '60', + 'help' : 'Number of seconds to throttle all queries to a server after being marked as down', + 'doc' : ''' +Throttle a server that has failed to respond :ref:`setting-server-down-max-fails` times for this many seconds. + ''', + }, + { + 'name' : 'bypass_server_throttling_probability', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '25', + 'help' : 'Determines the probability of a server marked down to be used anyway', + 'doc' : ''' +This setting determines the probability of a server marked down to be used anyway. +A value of ``n`` means that the chance of a server marked down still being used after it wins speed selection is is ``1/n``. +If this setting is zero throttled servers will never be selected to be used anyway. + ''', + 'versionadded': '5.0.0' + }, + { + 'name' : 'server_id', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : RUNTIME, + 'help' : 'Returned when queried for \'id.server\' TXT or NSID, defaults to hostname, set custom or \'disabled\'', + 'doc' : ''' +The reply given by The PowerDNS recursor to a query for 'id.server' with its hostname, useful for in clusters. +When a query contains the :rfc:`NSID EDNS0 Option <5001>`, this value is returned in the response as the NSID value. + +This setting can be used to override the answer given to these queries. +Set to 'disabled' to disable NSID and 'id.server' answers. + +Query example (where 192.0.2.14 is your server): + +.. code-block:: sh + + dig @192.0.2.14 CHAOS TXT id.server. + dig @192.0.2.14 example.com IN A +nsid + ''', + }, + { + 'name' : 'setgid', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, change group id to this gid for more security', + 'doc' : ''' +PowerDNS can change its user and group id after binding to its socket. +Can be used for better :doc:`security `. + ''' + }, + { + 'name' : 'setuid', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set, change user id to this uid for more security', + 'doc' : ''' +PowerDNS can change its user and group id after binding to its socket. +Can be used for better :doc:`security `. + ''' + }, + { + 'name' : 'signature_inception_skew', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '60', + 'help' : 'Allow the signature inception to be off by this number of seconds', + 'doc' : ''' +Allow the signature inception to be off by this number of seconds. Negative values are not allowed. + ''', + 'versionadded': '4.1.5', + 'versionchanged': ('4.2.0', 'Default is now 60, was 0 before.') + }, + { + 'name' : 'single_socket', + 'section' : 'outgoing', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If set, only use a single socket for outgoing queries', + 'doc' : ''' +Use only a single socket for outgoing queries. + ''', + }, + { + 'name' : 'agent', + 'section' : 'snmp', + 'oldname' : 'snmp-agent', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'If set, register as an SNMP agent', + 'doc' : ''' +If set to true and PowerDNS has been compiled with SNMP support, it will register as an SNMP agent to provide statistics and be able to send traps. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'daemon_socket', + 'section' : 'snmp', + 'oldname' : 'snmp-daemon-socket', + 'type' : LType.String, + 'default' : '', + 'help' : 'If set and snmp-agent is set, the socket to use to register to the SNMP daemon', + 'doc' : ''' +If not empty and ``snmp-agent`` is set to true, indicates how PowerDNS should contact the SNMP daemon to register as an SNMP agent. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'soa_minimum_ttl', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Don\'t change', + 'doc' : '''SKIP''', + 'skip-yaml': True, + }, + { + 'name' : 'socket_dir', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Where the controlsocket will live, /var/run/pdns-recursor when unset and not chrooted', + 'doc' : ''' +Where to store the control socket and pidfile. +The default depends on ``LOCALSTATEDIR`` or the ``--with-socketdir`` setting when building (usually ``/var/run`` or ``/run``). + +When using :ref:`setting-chroot` the default becomes ``/``. +The default value is overruled by the ``RUNTIME_DIRECTORY`` environment variable when that variable has a value (e.g. under systemd). + ''', + }, + { + 'name' : 'socket_group', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Group of socket', + 'doc' : ''' +Group and mode of the controlsocket. +Owner and group can be specified by name, mode is in octal. +''' + }, + { + 'name' : 'socket_mode', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Permissions for socket', + 'doc' : ''' +Mode of the controlsocket. +Owner and group can be specified by name, mode is in octal. + ''' + }, + { + 'name' : 'socket_owner', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Owner of socket', + 'doc' : ''' +Owner of the controlsocket. +Owner and group can be specified by name, mode is in octal. + ''' + }, + { + 'name' : 'spoof_nearmiss_max', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'If non-zero, assume spoofing after this many near misses', + 'doc' : ''' +If set to non-zero, PowerDNS will assume it is being subjected to a spoofing attack after seeing this many answers with the wrong id. + ''', + 'versionchanged': ('4.5.0', 'Older versions used 20 as the default value.') + }, + { + 'name' : 'stack_cache_size', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '100', + 'help' : 'Size of the stack cache, per mthread', + 'doc' : ''' +Maximum number of mthread stacks that can be cached for later reuse, per thread. Caching these stacks reduces the CPU load at the cost of a slightly higher memory usage, each cached stack consuming `stack-size` bytes of memory. +It makes no sense to cache more stacks than the value of `max-mthreads`, since there will never be more stacks than that in use at a given time. + ''', + 'versionadded': '4.9.0' + }, + { + 'name' : 'stack_size', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '200000', + 'help' : 'stack size per mthread', + 'doc' : ''' +Size in bytes of the stack of each mthread. + ''', + }, + { + 'name' : 'statistics_interval', + 'section' : 'logging', + 'type' : LType.Uint64, + 'default' : '1800', + 'help' : 'Number of seconds between printing of recursor statistics, 0 to disable', + 'doc' : ''' +Interval between logging statistical summary on recursor performance. +Use 0 to disable. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'stats_api_disabled_list', + 'section' : 'recursor', + 'type' : LType.ListStrings, + 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128', + 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*', + 'help' : 'List of statistics that are disabled when retrieving the complete list of statistics via the API', + 'doc' : ''' +A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons. +These statistics can still be retrieved individually by specifically asking for it. + ''', + 'doc-new' : ''' +A sequence of statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons. +These statistics can still be retrieved individually by specifically asking for it. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'stats_carbon_disabled_list', + 'section' : 'recursor', + 'type' : LType.ListStrings, + 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', + 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*', + 'help' : 'List of statistics that are prevented from being exported via Carbon', + 'doc' : ''' +A list of comma-separated statistic names, that are prevented from being exported via carbon for performance reasons. + ''', + 'doc-new' : ''' +A sequence of statistic names, that are prevented from being exported via carbon for performance reasons. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'stats_rec_control_disabled_list', + 'section' : 'recursor', + 'type' : LType.ListStrings, + 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', + 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*', + 'help' : 'List of statistics that are prevented from being exported via rec_control get-all', + 'doc' : ''' +A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons. +These statistics can still be retrieved individually. + ''', + 'doc-new' : ''' +A sequence of statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons. +These statistics can still be retrieved individually. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'stats_ringbuffer_entries', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '10000', + 'help' : 'maximum number of packets to store statistics for', + 'doc' : ''' +Number of entries in the remotes ringbuffer, which keeps statistics on who is querying your server. +Can be read out using ``rec_control top-remotes``. + ''', + }, + { + 'name' : 'stats_snmp_disabled_list', + 'section' : 'recursor', + 'type' : LType.ListStrings, + 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', + 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*', + 'help' : 'List of statistics that are prevented from being exported via SNMP', + 'doc' : ''' +A list of comma-separated statistic names, that are prevented from being exported via SNMP, for performance reasons. + ''', + 'doc-new' : ''' +A sequence of statistic names, that are prevented from being exported via SNMP, for performance reasons. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'structured_logging', + 'section' : 'logging', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Prefer structured logging', + 'doc' : ''' +Prefer structured logging when both an old style and a structured log messages is available. + ''', + 'versionadded': '4.6.0', + 'versionchanged': [('5.0.0', 'Disabling structured logging is deprecated'), + ('5.1.0', 'Disabling structured logging is not supported')] + }, + { + 'name' : 'structured_logging_backend', + 'section' : 'logging', + 'type' : LType.String, + 'default' : 'default', + 'help' : 'Structured logging backend', + 'doc' : ''' +The backend used for structured logging output. +This setting must be set on the command line (``--structured-logging-backend=...``) to be effective. +Available backends are: + +- ``default``: use the traditional logging system to output structured logging information. +- ``systemd-journal``: use systemd-journal. + When using this backend, provide ``-o verbose`` or simular output option to ``journalctl`` to view the full information. +- ``json``: JSON objects are written to the standard error stream. + +See :doc:`appendices/structuredlogging` for more details. + ''', + 'versionadded': '4.8.0', + 'versionchanged': ('5.1.0', 'The JSON backend was added') + }, + { + 'name' : 'tcp_fast_open', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size', + 'doc' : ''' +Enable TCP Fast Open support, if available, on the listening sockets. +The numerical value supplied is used as the queue size, 0 meaning disabled. See :ref:`tcp-fast-open-support`. + ''', + 'versionadded': '4.1.0' + }, + { + 'name' : 'tcp_fast_open_connect', + 'section' : 'outgoing', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Enable TCP Fast Open support on outgoing sockets', + 'doc' : ''' +Enable TCP Fast Open Connect support, if available, on the outgoing connections to authoritative servers. See :ref:`tcp-fast-open-support`. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'tcp_max_idle_ms', + 'section' : 'outgoing', + 'oldname' : 'tcp-out-max-idle-ms', + 'type' : LType.Uint64, + 'default' : '10000', + 'help' : 'Time TCP/DoT connections are left idle in milliseconds or 0 if no limit', + 'doc' : ''' +Time outgoing TCP/DoT connections are left idle in milliseconds or 0 if no limit. After having been idle for this time, the connection is eligible for closing. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'tcp_max_idle_per_auth', + 'section' : 'outgoing', + 'oldname' : 'tcp-out-max-idle-per-auth', + 'type' : LType.Uint64, + 'default' : '10', + 'help' : 'Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open', + 'doc' : ''' +Maximum number of idle outgoing TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'tcp_max_queries', + 'section' : 'outgoing', + 'oldname' : 'tcp-out-max-queries', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Maximum total number of queries per TCP/DoT connection, 0 means no limit', + 'doc' : ''' +Maximum total number of queries per outgoing TCP/DoT connection, 0 means no limit. After this number of queries, the connection is +closed and a new one will be created if needed. + ''', + }, + { + 'name' : 'tcp_max_idle_per_thread', + 'section' : 'outgoing', + 'oldname' : 'tcp-out-max-idle-per-thread', + 'type' : LType.Uint64, + 'default' : '100', + 'help' : 'Maximum number of idle TCP/DoT connections per thread', + 'doc' : ''' +Maximum number of idle outgoing TCP/DoT connections per thread, 0 means do not keep idle connections open. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'threads', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '2', + 'help' : 'Launch this number of threads', + 'doc' : ''' +Spawn this number of threads on startup. + ''', + }, + { + 'name' : 'tcp_threads', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '1', + 'help' : 'Launch this number of threads listening for and processing TCP queries', + 'doc' : ''' +Spawn this number of TCP processing threads on startup. + ''', + 'versionadded': '5.0.0' + }, + { + 'name' : 'trace', + 'section' : 'logging', + 'type' : LType.String, + 'default' : 'no', + 'help' : 'if we should output heaps of logging. set to \'fail\' to only log failing domains', + 'doc' : ''' +One of ``no``, ``yes`` or ``fail``. +If turned on, output impressive heaps of logging. +May destroy performance under load. +To log only queries resulting in a ``ServFail`` answer from the resolving process, this value can be set to ``fail``, but note that the performance impact is still large. +Also note that queries that do produce a result but with a failing DNSSEC validation are not written to the log + ''', + }, + { + 'name' : 'udp_source_port_min', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '1024', + 'help' : 'Minimum UDP port to bind on', + 'doc' : ''' +This option sets the low limit of UDP port number to bind on. + +In combination with :ref:`setting-udp-source-port-max` it configures the UDP +port range to use. Port numbers are randomized within this range on +initialization, and exceptions can be configured with :ref:`setting-udp-source-port-avoid` + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'udp_source_port_max', + 'section' : 'outgoing', + 'type' : LType.Uint64, + 'default' : '65535', + 'help' : 'Maximum UDP port to bind on', + 'doc' : ''' +This option sets the maximum limit of UDP port number to bind on. + +See :ref:`setting-udp-source-port-min`. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'udp_source_port_avoid', + 'section' : 'outgoing', + 'type' : LType.ListStrings, + 'default' : '4791,11211', + 'help' : 'List of comma separated UDP port numbers to avoid', + 'doc' : ''' +A list of comma-separated UDP port numbers to avoid when binding. +Ex: `4791,5300,11211` + +See :ref:`setting-udp-source-port-min`. + ''', + 'doc-new' : ''' +A sequence of UDP port numbers to avoid when binding. For example: + +.. code-block:: yaml + + outgoing: + udp_source_port_avoid: + - 4791 + - 5300 + - 11211 + +See :ref:`setting-udp-source-port-min`. + ''', + 'versionadded': '4.2.0', + 'versionchanged': ('5.2.0', 'port 4791 was added to the default list'), + }, + { + 'name' : 'udp_truncation_threshold', + 'section' : 'incoming', + 'type' : LType.Uint64, + 'default' : '1232', + 'help' : 'Maximum UDP response size before we truncate', + 'doc' : ''' +EDNS0 allows for large UDP response datagrams, which can potentially raise performance. +Large responses however also have downsides in terms of reflection attacks. +This setting limits the accepted size. +Maximum value is 65535, but values above 4096 should probably not be attempted. + +To know why 1232, see the note at :ref:`setting-edns-outgoing-bufsize`. + ''', + 'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680.') + }, + { + 'name' : 'unique_response_tracking', + 'section' : 'nod', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Track unique responses (tuple of query name, type and RR).', + 'doc' : ''' +Whether to track unique DNS responses, i.e. never seen before combinations +of the triplet (query name, query type, RR[rrname, rrtype, rrdata]). +This can be useful for tracking potentially suspicious domains and +behaviour, e.g. DNS fast-flux. +If protobuf is enabled and configured, then the Protobuf Response message +will contain a flag with udr set to true for each RR that is considered +unique, i.e. never seen before. +This feature uses a probabilistic data structure (stable bloom filter) to +track unique responses, which can have false positives as well as false +negatives, thus it is a best-effort feature. Increasing the number of cells +in the SBF using the unique-response-db-size setting can reduce FPs and FNs. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'unique_response_log', + 'section' : 'nod', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Log unique responses', + 'doc' : ''' +Whether to log when a unique response is detected. The log line +looks something like: + +Oct 24 12:11:27 Unique response observed: qname=foo.com qtype=A rrtype=AAAA rrname=foo.com rrcontent=1.2.3.4 + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'unique_response_db_size', + 'section' : 'nod', + 'type' : LType.Uint64, + 'default' : '67108864', + 'help' : 'Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864', + 'doc' : ''' +The default size of the stable bloom filter used to store previously +observed responses is 67108864. To change the number of cells, use this +setting. For each cell, the SBF uses 1 bit of memory, and one byte of +disk for the persistent file. +If there are already persistent files saved to disk, this setting will +have no effect unless you remove the existing files. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'unique_response_history_dir', + 'section' : 'nod', + 'type' : LType.String, + 'default' : 'NODCACHEDIRUDR', + 'docdefault': 'Determined by distribution', + 'help' : 'Persist unique response tracking data here to persist between restarts', + 'doc' : ''' +This setting controls which directory is used to store the on-disk +cache of previously observed responses. + +The default depends on ``LOCALSTATEDIR`` when building the software. +Usually this comes down to ``/var/lib/pdns-recursor/udr`` or ``/usr/local/var/lib/pdns-recursor/udr``). + +The newly observed domain feature uses a stable bloom filter to store +a history of previously observed responses. The data structure is +synchronized to disk every 10 minutes, and is also initialized from +disk on startup. This ensures that previously observed responses are +preserved across recursor restarts. If you change the +unique-response-db-size, you must remove any files from this directory. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'unique_response_pb_tag', + 'section' : 'nod', + 'type' : LType.String, + 'default' : 'pdns-udr', + 'help' : 'If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to \'pdns-udr\'', + 'doc' : ''' +If protobuf is configured, then this tag will be added to all protobuf response messages when +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', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Pass along received EDNS Client Subnet information', + 'doc' : ''' +Whether to process and pass along a received EDNS Client Subnet to authoritative servers. +The ECS information will only be sent for netmasks and domains listed in :ref:`setting-edns-subnet-allow-list` and will be truncated if the received scope exceeds :ref:`setting-ecs-ipv4-bits` for IPv4 or :ref:`setting-ecs-ipv6-bits` for IPv6. + ''', + }, + { + 'name' : 'version', + 'section' : 'commands', + 'type' : LType.Command, + 'default' : 'no', + 'help' : 'Print version string', + 'doc' : ''' +Print version of this binary. Useful for checking which version of the PowerDNS recursor is installed on a system. + ''', + }, + { + 'name' : 'version_string', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : RUNTIME, + 'help' : 'string reported on version.pdns or version.bind', + 'doc' : ''' +By default, PowerDNS replies to the 'version.bind' query with its version number. +Security conscious users may wish to override the reply PowerDNS issues. + ''', + }, + { + 'name' : 'webserver', + 'section' : 'webservice', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Start a webserver (for REST API)', + 'doc' : ''' +Start the webserver (for REST API). + ''', + }, + { + 'name' : 'address', + 'section' : 'webservice', + 'oldname' : 'webserver-address', + 'type' : LType.String, + 'default' : '127.0.0.1', + 'help' : 'IP Address of webserver to listen on', + 'doc' : ''' +IP address for the webserver to listen on. +''', + 'doc-new' : ''' +IP address for the webserver to listen on. +This field is ignored if :ref:`setting-yaml-webservice.listen` is set. +''', + }, + { + 'name' : 'listen', + 'section' : 'webservice', + 'type' : LType.ListIncomingWSConfigs, + 'default' : '', + 'help' : 'IP addresses and associated attributes for the webserver to listen on', + 'doc' : ''' +IP addresses and associated attributes for the webserver to listen on. +If this setting has a non-default value, :ref:`setting-yaml-webservice.address` and :ref:`setting-yaml-webservice.port` will be ignored. Note multiple listen addresses can be configured and https is supported as well, in contrast to earlier (pre 5.3.0) versions. + ''', + 'skip-old': 'No equivalent old-style setting', + 'versionadded': '5.3.0', + }, + { + 'name' : 'allow_from', + 'section' : 'webservice', + 'oldname' : 'webserver-allow-from', + 'type' : LType.ListSubnets, + 'default' : '127.0.0.1, ::1', + 'help' : 'Webserver access is only allowed from these subnets', + 'doc' : ''' +These IPs and subnets are allowed to access the webserver. Note that +specifying an IP address without a netmask uses an implicit netmask +of /32 or /128. + ''', + 'versionchanged': ('4.1.0', 'Default is now 127.0.0.1,::1, was 0.0.0.0/0,::/0 before.') + }, + { + 'name' : 'hash_plaintext_credentials', + 'section' : 'webservice', + 'oldname': 'webserver-hash-plaintext-credentials', + 'type' : LType.Bool, + 'default' : 'false', + 'help' : 'Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime', + 'doc' : ''' +Whether passwords and API keys supplied in the configuration as plaintext should be hashed during startup, to prevent the plaintext versions from staying in memory. Doing so increases significantly the cost of verifying credentials and is thus disabled by default. +Note that this option only applies to credentials stored in the configuration as plaintext, but hashed credentials are supported without enabling this option. + ''', + 'versionadded': '4.6.0' + }, + { + 'name' : 'loglevel', + 'section' : 'webservice', + 'oldname' : 'webserver-loglevel', + 'type' : LType.String, + 'default' : 'normal', + 'help' : 'Amount of logging in the webserver (none, normal, detailed)', + 'doc' : ''' +One of ``none``, ``normal``, ``detailed``. +The amount of logging the webserver must do. ``none`` means no useful webserver information will be logged. +When set to ``normal``, the webserver will log a line per request:: + + Feb 03 14:54:00 msg="Request" subsystem="webserver" level="0" prio="Notice" tid="0" ts="1738590840.208" HTTPVersion="HTTP/1.1" method="GET" remote="[::1]:49880" respsize="5418" status="200" uniqueid="a31a280d-29de-4db8-828f-edc862eb8653" urlpath="/" + +When set to ``detailed``, all available information about the request and response is logged. + +.. note:: + 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. + ''', + 'versionadded': '4.2.0' + }, + { + 'name' : 'password', + 'section' : 'webservice', + 'oldname' : 'webserver-password', + 'type' : LType.String, + 'default' : '', + 'help' : 'Password required for accessing the webserver', + 'doc' : ''' +Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``rec_control hash-password`` instead of being present in the configuration in plaintext, but the plaintext version is still supported. + ''', + 'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.') + }, + { + 'name' : 'port', + 'section' : 'webservice', + 'type' : LType.Uint64, + 'oldname': 'webserver-port', + 'default' : '8082', + 'help' : 'Port of webserver to listen on', + 'doc' : ''' +TCP port where the webserver should listen on. + ''', + 'doc-new' : ''' +TCP port where the webserver should listen on. +This field is ignored if :ref:`setting-yaml-webservice.listen` is set. + ''', + }, + { + 'name': 'max_request_size', + 'section': 'webservice', + 'type': LType.Uint64, + 'oldname': 'webserver-max-request-size', + 'default': '2', + 'help': 'Maximum size for webserver requests in megabytes', + 'doc': ''' +Maximum size of incoming webserver requests in megabytes. + ''', + 'versionadded': '5.5.0', + }, + { + 'name' : 'write_pid', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Write a PID file', + 'doc' : ''' +If a PID file should be written to :ref:`setting-socket-dir` + ''', + }, + { + 'name' : 'x_dnssec_names', + 'section' : 'dnssec', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters', + 'doc' : ''' +List of names whose DNSSEC validation metrics will be counted in a separate set of metrics that start +with ``x-dnssec-result-``. +The names are suffix-matched. +This can be used to not count known failing (test) name validations in the ordinary DNSSEC metrics. + ''', + 'versionadded': '4.5.0' + }, + { + 'name' : 'system_resolver_ttl', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Set TTL of system resolver feature, 0 (default) is disabled', + 'doc' : ''' +Sets TTL in seconds of the system resolver feature. +If not equal to zero names can be used for forwarding targets. +The names will be resolved by the system resolver configured in the OS. + +The TTL is used as a time to live to see if the names used in forwarding resolve to a different address than before. +If the TTL is expired, a re-resolve will be done by the next iteration of the check function; +if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``. + +Make sure the recursor itself is not used by the system resolver! Default is 0 (not enabled). +A suggested value is 60. +''', + 'versionadded': '5.1.0' + }, + { + 'name' : 'system_resolver_interval', + 'section' : 'recursor', + 'type' : LType.Uint64, + 'default' : '0', + 'help' : 'Set interval (in seconds) of the re-resolve checks of system resolver subsystem.', + 'doc' : ''' +Sets the check interval (in seconds) of the system resolver feature. +All names known by the system resolver subsystem are periodically checked for changing values. + +If the TTL of a name has expired, it is checked by re-resolving it. +if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``. + +This settings sets the interval between the checks. +If set to zero (the default), the value :ref:`setting-system-resolver-ttl` is used. +''', + 'versionadded': '5.1.0' + }, + { + 'name' : 'system_resolver_self_resolve_check', + 'section' : 'recursor', + 'type' : LType.Bool, + 'default' : 'true', + 'help' : 'Check for potential self-resolve, default enabled.', + 'doc' : ''' +Warn on potential self-resolve. +If this check draws the wrong conclusion, you can disable it. +''', + 'versionadded': '5.1.0' + }, + { + 'name' : 'trustanchors', + 'section' : 'dnssec', + 'type' : LType.ListTrustAnchors, + 'default' : '[{name: ., dsrecords: [\'20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d\', \'38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16\']}]', + 'docdefault' : ''' + +.. code-block:: yaml + + dnssec: + - name: . + dsrecords: + - 20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d + - 38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16 + +''', + 'help' : 'Sequence of trust anchors', + 'doc' : ''' +Sequence of trust anchors. If the sequence contains an entry for the root zone, the default root zone trust anchor is not included. +If a zone appears multiple times, the entries in ``dsrecords`` are merged. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', + 'versionadded': '5.1.0', + 'runtime': ['add-ta', 'clear-ta', 'reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'negative_trustanchors', + 'section' : 'dnssec', + 'type' : LType.ListNegativeTrustAnchors, + 'default' : '', + 'help' : 'A sequence of negative trust anchors', + 'doc' : ''' +Sequence of negative trust anchors. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', + 'versionadded': '5.1.0', + 'runtime': ['add-nta', 'clear-nta', 'reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'trustanchorfile', + 'section' : 'dnssec', + 'type' : LType.String, + 'default' : '', + 'help' : 'A path to a zone file containing trust anchors', + 'doc' : ''' +A path to a zone file to read trust anchors from. +This can be used to read distribution provided trust anchors, as for instance ``/usr/share/dns/root.key`` from Debian's ``dns-root-data`` package. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'trustanchorfile_interval', + 'section' : 'dnssec', + 'type' : LType.Uint64, + 'default' : '24', + 'help' : 'Interval (in hours) to read the trust anchors file', + 'doc' : ''' +Interval (in hours) to re-read the ``trustanchorfile``. Zero disables periodic re-reads. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', + 'versionadded': '5.1.0', + }, + { + 'name' : 'protobuf_servers', + 'section' : 'logging', + 'type' : LType.ListProtobufServers, + 'default' : '', + 'help' : 'Sequence of protobuf servers', + 'doc' : ''' +Sequence of outgoing protobuf servers. Currently the maximum size of this list is one. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'outgoing_protobuf_servers', + 'section' : 'logging', + 'type' : LType.ListProtobufServers, + 'default' : '', + 'help' : 'List of outgoing protobuf servers', + 'doc' : ''' +Sequence of outgoing protobuf servers. Currently the maximum size of this list is one. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'protobuf_mask_v4', + 'section' : 'logging', + 'type' : LType.Uint64, + 'default' : '32', + 'help' : 'Network mask to apply for client IPv4 addresses in protobuf messages', + 'doc' : ''' +Network mask to apply to the client IPv4 addresses, for anonymization purposes. The default of 32 means no anonymization. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + }, + { + 'name' : 'protobuf_mask_v6', + 'section' : 'logging', + 'type' : LType.Uint64, + 'default' : '128', + 'help' : 'Network mask to apply for client IPv6 addresses in protobuf messages', + 'doc' : ''' +Network mask to apply to the client IPv6 addresses, for anonymization purposes. The default of 128 means no anonymization. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + }, + { + 'name' : 'dnstap_framestream_servers', + 'section' : 'logging', + 'type' : LType.ListDNSTapFrameStreamServers, + 'default' : '', + 'help' : 'Sequence of dnstap servers', + 'doc' : ''' +Sequence of dnstap servers. Currently the maximum size of this list is one. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'dnstap_nod_framestream_servers', + 'section' : 'logging', + 'type' : LType.ListDNSTapNODFrameStreamServers, + 'default' : '', + 'help' : 'Sequence of NOD dnstap servers', + 'doc' : ''' +Sequence of NOD dnstap servers. Currently the maximum size of this list is one. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'sortlists', + 'section' : 'recursor', + 'type' : LType.ListSortLists, + 'default' : '', + 'help' : 'Sequence of sort lists', + 'doc' : ''' +Sequence of sort lists. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/sortlist`', + 'versionadded': '5.1.0', + }, + { + 'name' : 'rpzs', + 'section' : 'recursor', + 'type' : LType.ListRPZs, + 'default' : '', + 'help' : 'Sequence of RPZ entries', + 'doc' : ''' +Sequence of RPZ entries. + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/rpz`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'zonetocaches', + 'section' : 'recordcache', + 'type' : LType.ListZoneToCaches, + 'default' : '', + 'help' : 'Sequence of ZoneToCache entries ', + 'doc' : ''' +Sequence of ZoneToCache entries + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/ztc`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'allowed_additional_qtypes', + 'section' : 'recursor', + 'type' : LType.ListAllowedAdditionalQTypes, + 'default' : '', + 'help' : 'Sequence of AllowedAdditionalQType', + 'doc' : ''' +Sequence of AllowedAdditionalQType + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/additionals`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'proxymappings', + 'section' : 'incoming', + 'type' : LType.ListProxyMappings, + 'default' : '', + 'help' : 'Sequence of ProxyMapping', + 'doc' : ''' +Sequence of ProxyMapping + ''', + 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/proxymapping`', + 'versionadded': '5.1.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'lua_start_stop_script', + 'section' : 'recursor', + 'type' : LType.String, + 'default' : '', + 'help' : 'Lua script containing functions to run on startup and shutdown', + 'doc' : ''' +Load this Lua script on startup and shutdown and run the Lua function ``on_recursor_start`` on startup and the Lua function ``on_recursor_stop`` on a ``nice`` shutdown (using ``rec_control quit-nicely`` of the :program:`Recursor` process. + ''', + 'skip-old' : 'No equivalent old-style setting', + 'versionadded': '5.2.0', + }, + { + 'name' : 'forwarding_catalog_zones', + 'section' : 'recursor', + 'type' : LType.ListForwardingCatalogZones, + 'default' : '', + 'help' : 'Sequence of ForwardingCatalogZone', + 'doc' : ''' +Sequence of ForwardingCatalogZone. This setting cannot be combined with :ref:`setting-lua-config-file`. + ''', + 'skip-old' : 'No equivalent old style setting', + 'versionadded': '5.2.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'cookies', + 'section' : 'outgoing', + 'oldname': 'outgoing-cookies', + 'type': LType.Bool, + 'default': 'false', + 'help': 'Enable DNS cookies when contacting authoritative servers or forwarders', + 'doc': ''' +Enable DNS cookies (:rfc:`7873`, :rfc:`9018`) when contacting authoritative servers or forwarders. +''', + 'versionadded': '5.4.0', + }, + { + 'name' : 'cookies_unsupported', + 'section' : 'outgoing', + 'oldname': 'outgoing-cookies-unsupported', + 'type': LType.ListSocketAddresses, + 'default': '', + 'help': 'Addresses (with optional port) of authoritative servers that do not support cookies', + 'doc': ''' +Addresses of servers that do not properly support DNS cookies (:rfc:`7873`, :rfc:`9018`). Recursor will not even try to probe these servers for cookie support. If no port is specified port 53 is used. +''', + 'versionadded': '5.4.0', + }, + { + 'name' : 'tls_configurations', + 'section' : 'outgoing', + 'type' : LType.ListOutgoingTLSConfigurations, + 'default' : '', + 'help' : 'Sequence of OutgoingTLSConfiguration', + 'doc' : ''' +Configurations used for outgoing DoT connections. +A DoT connection is matched against the subnets lists (using the remote IP) and if that does not provide a match, the nameserver name is matched against the suffixes lists. When a match is found, the corresponding DoT configuration is used. + ''', + 'skip-old' : 'No equivalent old style setting', + 'versionadded': '5.4.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + 'name' : 'opentelemetry_trace_conditions', + 'section' : 'logging', + 'type' : LType.ListOpenTelemetryTraceConditions, + 'default' : '', + 'help' : 'Sequence of OpenTelemetryTraceCondition', + 'doc' : ''' + List of conditions specifying when to generate :ref:`opentelemetry_tracing`. + ''', + 'skip-old' : 'No equivalent old style setting', + 'versionadded': '5.4.0', + 'runtime': ['reload-lua-config', 'reload-yaml'], + }, + { + "name": "max_pointers_per_name", + "section": "recursor", + "type": LType.Uint64, + "default": "10", + "help": "Maximum number of name pointers followed per name.", + "doc": """ +Maximum number of name pointers followed per name. +DNS packets needing more than the limit will fail to parse and be rejected. +See :ref:`pointers`. +""", + "versionadded": ["5.5.0", "5.4.x", "5.3.x"] + }, + { + "name": "max_pointers_per_packet_byte", + "section": "recursor", + "type": LType.Uint64, + "default": "4", + "help": "Maximum number of name pointers per DNS packet byte followed.", + "doc": """ +Maximum number of name pointers per DNS packet byte followed. +DNS packets needing more than the limit will fail to parse and be rejected. +See :ref:`pointers`. +""", + "versionadded": ["5.5.0", "5.4.x", "5.3.x"] + }, + { + "name": "max_pointers_to_pointers", + "section": "recursor", + "type": LType.Uint64, + "default": "4", + "help": "Maximum number of name pointers pointing directly to another pointer per name.", + "doc": """ +Maximum number of name pointers pointing to directly another pointer per name. +DNS packets needing more than the limit will fail to parse and be rejected. +See :ref:`pointers`. +""", + "versionadded": ["5.5.0", "5.4.x", "5.3.x"] + }, + +] diff -Nru pdns-recursor-5.2.13/rec-snmp-gen.h pdns-recursor-5.4.9/rec-snmp-gen.h --- pdns-recursor-5.2.13/rec-snmp-gen.h 2026-08-05 12:02:08.000000000 +0000 +++ pdns-recursor-5.4.9/rec-snmp-gen.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py -registerCounter64Stat("questions", questionsOID); -registerCounter64Stat("ipv6-questions", ipv6QuestionsOID); -registerCounter64Stat("tcp-questions", tcpQuestionsOID); -registerCounter64Stat("cache-hits", cacheHitsOID); -registerCounter64Stat("cache-misses", cacheMissesOID); -registerCounter64Stat("cache-entries", cacheEntriesOID); -registerCounter64Stat("cache-bytes", cacheBytesOID); -registerCounter64Stat("packetcache-hits", packetcacheHitsOID); -registerCounter64Stat("packetcache-misses", packetcacheMissesOID); -registerCounter64Stat("packetcache-entries", packetcacheEntriesOID); -registerCounter64Stat("packetcache-bytes", packetcacheBytesOID); -registerCounter64Stat("malloc-bytes", mallocBytesOID); -registerCounter64Stat("servfail-answers", servfailAnswersOID); -registerCounter64Stat("nxdomain-answers", nxdomainAnswersOID); -registerCounter64Stat("noerror-answers", noerrorAnswersOID); -registerCounter64Stat("unauthorized-udp", unauthorizedUdpOID); -registerCounter64Stat("unauthorized-tcp", unauthorizedTcpOID); -registerCounter64Stat("tcp-client-overflow", tcpClientOverflowOID); -registerCounter64Stat("client-parse-errors", clientParseErrorsOID); -registerCounter64Stat("server-parse-errors", serverParseErrorsOID); -registerCounter64Stat("too-old-drops", tooOldDropsOID); -registerCounter64Stat("answers0-1", answers01OID); -registerCounter64Stat("answers1-10", answers110OID); -registerCounter64Stat("answers10-100", answers10100OID); -registerCounter64Stat("answers100-1000", answers1001000OID); -registerCounter64Stat("answers-slow", answersSlowOID); -registerCounter64Stat("auth4-answers0-1", auth4Answers01OID); -registerCounter64Stat("auth4-answers1-10", auth4Answers110OID); -registerCounter64Stat("auth4-answers10-100", auth4Answers10100OID); -registerCounter64Stat("auth4-answers100-1000", auth4Answers1001000OID); -registerCounter64Stat("auth4-answers-slow", auth4AnswersSlowOID); -registerCounter64Stat("auth6-answers0-1", auth6Answers01OID); -registerCounter64Stat("auth6-answers1-10", auth6Answers110OID); -registerCounter64Stat("auth6-answers10-100", auth6Answers10100OID); -registerCounter64Stat("auth6-answers100-1000", auth6Answers1001000OID); -registerCounter64Stat("auth6-answers-slow", auth6AnswersSlowOID); -registerCounter64Stat("qa-latency", qaLatencyOID); -registerCounter64Stat("unexpected-packets", unexpectedPacketsOID); -registerCounter64Stat("case-mismatches", caseMismatchesOID); -registerCounter64Stat("spoof-prevents", spoofPreventsOID); -registerCounter64Stat("nsset-invalidations", nssetInvalidationsOID); -registerCounter64Stat("resource-limits", resourceLimitsOID); -registerCounter64Stat("over-capacity-drops", overCapacityDropsOID); -registerCounter64Stat("policy-drops", policyDropsOID); -registerCounter64Stat("no-packet-error", noPacketErrorOID); -registerCounter64Stat("dlg-only-drops", dlgOnlyDropsOID); -registerCounter64Stat("ignored-packets", ignoredPacketsOID); -registerCounter64Stat("max-mthread-stack", maxMthreadStackOID); -registerCounter64Stat("negcache-entries", negcacheEntriesOID); -registerCounter64Stat("throttle-entries", throttleEntriesOID); -registerCounter64Stat("nsspeeds-entries", nsspeedsEntriesOID); -registerCounter64Stat("failed-host-entries", failedHostEntriesOID); -registerCounter64Stat("concurrent-queries", concurrentQueriesOID); -registerCounter64Stat("security-status", securityStatusOID); -registerCounter64Stat("outgoing-timeouts", outgoingTimeoutsOID); -registerCounter64Stat("outgoing4-timeouts", outgoing4TimeoutsOID); -registerCounter64Stat("outgoing6-timeouts", outgoing6TimeoutsOID); -registerCounter64Stat("tcp-outqueries", tcpOutqueriesOID); -registerCounter64Stat("all-outqueries", allOutqueriesOID); -registerCounter64Stat("ipv6-outqueries", ipv6OutqueriesOID); -registerCounter64Stat("throttled-outqueries", throttledOutqueriesOID); -registerCounter64Stat("dont-outqueries", dontOutqueriesOID); -registerCounter64Stat("unreachables", unreachablesOID); -registerCounter64Stat("chain-resends", chainResendsOID); -registerCounter64Stat("tcp-clients", tcpClientsOID); -#ifdef __linux -registerCounter64Stat("udp-recvbuf-errors", udpRecvbufErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp-sndbuf-errors", udpSndbufErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp-noport-errors", udpNoportErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp-in-errors", udpInErrorsOID); -#endif -registerCounter64Stat("edns-ping-matches", ednsPingMatchesOID); -registerCounter64Stat("edns-ping-mismatches", ednsPingMismatchesOID); -registerCounter64Stat("dnssec-queries", dnssecQueriesOID); -registerCounter64Stat("noping-outqueries", nopingOutqueriesOID); -registerCounter64Stat("noedns-outqueries", noednsOutqueriesOID); -registerCounter64Stat("uptime", uptimeOID); -registerCounter64Stat("real-memory-usage", realMemoryUsageOID); -registerCounter64Stat("fd-usage", fdUsageOID); -registerCounter64Stat("user-msec", userMsecOID); -registerCounter64Stat("sys-msec", sysMsecOID); -registerCounter64Stat("dnssec-validations", dnssecValidationsOID); -registerCounter64Stat("dnssec-result-insecure", dnssecResultInsecureOID); -registerCounter64Stat("dnssec-result-secure", dnssecResultSecureOID); -registerCounter64Stat("dnssec-result-bogus", dnssecResultBogusOID); -registerCounter64Stat("dnssec-result-indeterminate", dnssecResultIndeterminateOID); -registerCounter64Stat("dnssec-result-nta", dnssecResultNtaOID); -registerCounter64Stat("policy-result-noaction", policyResultNoactionOID); -registerCounter64Stat("policy-result-drop", policyResultDropOID); -registerCounter64Stat("policy-result-nxdomain", policyResultNxdomainOID); -registerCounter64Stat("policy-result-nodata", policyResultNodataOID); -registerCounter64Stat("policy-result-truncate", policyResultTruncateOID); -registerCounter64Stat("policy-result-custom", policyResultCustomOID); -registerCounter64Stat("query-pipe-full-drops", queryPipeFullDropsOID); -registerCounter64Stat("truncated-drops", truncatedDropsOID); -registerCounter64Stat("empty-queries", emptyQueriesOID); -registerCounter64Stat("dnssec-authentic-data-queries", dnssecAuthenticDataQueriesOID); -registerCounter64Stat("dnssec-check-disabled-queries", dnssecCheckDisabledQueriesOID); -registerCounter64Stat("variable-responses", variableResponsesOID); -registerCounter64Stat("special-memory-usage", specialMemoryUsageOID); -registerCounter64Stat("rebalanced-queries", rebalancedQueriesOID); -registerCounter64Stat("qname-min-fallback-success", qnameMinFallbackSuccessOID); -registerCounter64Stat("proxy-protocol-invalid", proxyProtocolInvalidOID); -registerCounter64Stat("record-cache-contended", recordCacheContendedOID); -registerCounter64Stat("record-cache-acquired", recordCacheAcquiredOID); -registerCounter64Stat("nod-lookups-dropped-oversize", nodLookupsDroppedOversizeOID); -registerCounter64Stat("taskqueue-pushed", taskqueuePushedOID); -registerCounter64Stat("taskqueue-expired", taskqueueExpiredOID); -registerCounter64Stat("taskqueue-size", taskqueueSizeOID); -registerCounter64Stat("aggressive-nsec-cache-entries", aggressiveNSECCacheEntriesOID); -registerCounter64Stat("aggressive-nsec-cache-nsec-hits", aggressiveNSECCacheNSECHitsOID); -registerCounter64Stat("aggressive-nsec-cache-nsec3-hits", aggressiveNSECCacheNSEC3HitsOID); -registerCounter64Stat("aggressive-nsec-cache-nsec-wc-hits", aggressiveNSECCacheNSECWcHitsOID); -registerCounter64Stat("aggressive-nsec-cache-nsec3-wc-hits", aggressiveNSECCacheNSEC3WcHitsOID); -registerCounter64Stat("dot-outqueries", dotOutqueriesOID); -registerCounter64Stat("dns64-prefix-answers", dns64PrefixAnswersOID); -registerCounter64Stat("almost-expired-pushed", almostExpiredPushedOID); -registerCounter64Stat("almost-expired-run", almostExpiredRunOID); -registerCounter64Stat("almost-expired-exceptions", almostExpiredExceptionsOID); -#ifdef __linux -registerCounter64Stat("udp-in-csum-errors", udpInCsumErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp6-recvbuf-errors", udp6RecvbufErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp6-sndbuf-errors", udp6SndbufErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp6-noport-errors", udp6NoportErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp6-in-errors", udp6InErrorsOID); -#endif -#ifdef __linux -registerCounter64Stat("udp6-in-csum-errors", udp6InCsumErrorsOID); -#endif -registerCounter64Stat("source-disallowed-notify", sourceDisallowedNotifyOID); -registerCounter64Stat("zone-disallowed-notify", zoneDisallowedNotifyOID); -registerCounter64Stat("non-resolving-nameserver-entries", nonResolvingNameserverEntriesOID); -registerCounter64Stat("maintenance-usec", maintenanceUsecOID); -registerCounter64Stat("maintenance-calls", maintenanceCallsOID); -registerCounter64Stat("auth-noerror-answers", authNoerrorAnswersOID); -registerCounter64Stat("auth-formerr-answers", authFormerrAnswersOID); -registerCounter64Stat("auth-servfail-answers", authServfailAnswersOID); -registerCounter64Stat("auth-nxdomain-answers", authNxdomainAnswersOID); -registerCounter64Stat("auth-notimp-answers", authNotimpAnswersOID); -registerCounter64Stat("auth-refused-answers", authRefusedAnswersOID); -registerCounter64Stat("auth-yxdomain-answers", authYxdomainAnswersOID); -registerCounter64Stat("auth-yxrrset-answers", authYxrrsetAnswersOID); -registerCounter64Stat("auth-nxrrset-answers", authNxrrsetAnswersOID); -registerCounter64Stat("auth-notauth-answers", authNotauthAnswersOID); -registerCounter64Stat("auth-rcode10-answers", authRcode10AnswersOID); -registerCounter64Stat("auth-rcode11-answers", authRcode11AnswersOID); -registerCounter64Stat("auth-rcode12-answers", authRcode12AnswersOID); -registerCounter64Stat("auth-rcode13-answers", authRcode13AnswersOID); -registerCounter64Stat("auth-rcode14-answers", authRcode14AnswersOID); -registerCounter64Stat("auth-rcode15-answers", authRcode15AnswersOID); -registerCounter64Stat("packetcache-contended", packetcacheContendedOID); -registerCounter64Stat("packetcache-acquired", packetcacheAcquiredOID); -registerCounter64Stat("nod-events", nodEventsOID); -registerCounter64Stat("udr-events", udrEventsOID); -registerCounter64Stat("max-chain-length", maxChainLengthOID); -registerCounter64Stat("max-chain-weight", maxChainWeightOID); -registerCounter64Stat("chain-limits", chainLimitsOID); -registerCounter64Stat("tcp-overflow", tcpOverflowOID); -registerCounter64Stat("ecs-missing", ecsMissingOID); diff -Nru pdns-recursor-5.2.13/rec-snmp.cc pdns-recursor-5.4.9/rec-snmp.cc --- pdns-recursor-5.2.13/rec-snmp.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-snmp.cc 2026-10-26 08:26:51.000000000 +0000 @@ -54,7 +54,7 @@ /* We are never called for a GETNEXT if it's registered as a "instance", as it's "magically" handled for us. */ -/* a instance handler also only hands us one request at a time, so +/* an instance handler also only hands us one request at a time, so we don't need to loop over a list of requests; we'll only get one. */ static int handleCounter64Stats(netsnmp_mib_handler* /* handler */, @@ -101,14 +101,12 @@ static void registerCounter64Stat(const std::string& name, const oid10& statOID) { if (statOID.size() != OID_LENGTH(questionsOID)) { - SLOG(g_log << Logger::Error << "Invalid OID for SNMP Counter64 statistic " << name << endl, - g_slog->withName("snmp")->info(Logr::Error, "Invalid OID for SNMP Counter64 statistic", "name", Logging::Loggable(name))); + g_slog->withName("snmp")->info(Logr::Error, "Invalid OID for SNMP Counter64 statistic", "name", Logging::Loggable(name)); return; } if (s_statsMap.find(statOID.at(statOID.size() - 1)) != s_statsMap.end()) { - SLOG(g_log << Logger::Error << "OID for SNMP Counter64 statistic " << name << " has already been registered" << endl, - g_slog->withName("snmp")->info(Logr::Error, "OID for SNMP Counter64 statistic has already been registered", "name", Logging::Loggable(name))); + g_slog->withName("snmp")->info(Logr::Error, "OID for SNMP Counter64 statistic has already been registered", "name", Logging::Loggable(name)); return; } diff -Nru pdns-recursor-5.2.13/rec-system-resolve.cc pdns-recursor-5.4.9/rec-system-resolve.cc --- pdns-recursor-5.2.13/rec-system-resolve.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-system-resolve.cc 2026-10-26 08:26:51.000000000 +0000 @@ -56,6 +56,7 @@ vec.emplace_back(address); } catch (...) { + ; } res = res->ai_next; } @@ -80,7 +81,7 @@ return answer; } -// do a id.server/CH/TXT query +// do an id.server/CH/TXT query std::string serverID() { auto buffer = resolve("id.server", QClass::CHAOS, QType::TXT); @@ -88,21 +89,26 @@ return {}; } - MOADNSParser parser(false, static_cast(static_cast(buffer.data())), buffer.size()); - if (parser.d_header.rcode != RCode::NoError || parser.d_answers.size() != 1) { - return {}; - } - const auto& dnsrecord = parser.d_answers.at(0); - if (dnsrecord.d_type == QType::TXT) { - if (auto txt = getRR(dnsrecord); txt != nullptr) { - const auto& text = txt->d_text; - if (text.size() >= 2 && text.at(0) == '"' && text.at(text.size() - 1) == '"') { - // remove quotes around text - return txt->d_text.substr(1, txt->d_text.size() - 2); + try { + MOADNSParser parser(false, static_cast(static_cast(buffer.data())), buffer.size()); + if (parser.d_header.rcode != RCode::NoError || parser.d_answers.size() != 1) { + return {}; + } + const auto& dnsrecord = parser.d_answers.at(0); + if (dnsrecord.d_type == QType::TXT) { + if (auto txt = getRR(dnsrecord); txt != nullptr) { + const auto& text = txt->d_text; + if (text.size() >= 2 && text.at(0) == '"' && text.at(text.size() - 1) == '"') { + // remove quotes around text + return txt->d_text.substr(1, txt->d_text.size() - 2); + } + return txt->d_text; } - return txt->d_text; } } + catch (const MOADNSException&) { + ; + } return {}; } } // anonymous namespace @@ -253,7 +259,7 @@ while (!stop) { const time_t startTime = time(nullptr); time_t wakeTime = startTime; - // The expresion wakeTime - startTime is equal to the total amount of time slept + // The expression wakeTime - startTime is equal to the total amount of time slept while (wakeTime - startTime < d_interval) { std::unique_lock lock(mutex); time_t remaining = d_interval - (wakeTime - startTime); diff -Nru pdns-recursor-5.2.13/rec-tcounters.cc pdns-recursor-5.4.9/rec-tcounters.cc --- pdns-recursor-5.2.13/rec-tcounters.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-tcounters.cc 2026-10-26 08:26:51.000000000 +0000 @@ -38,7 +38,7 @@ auto& lhs = doubleWAvg.at(i); const auto& rhs = data.doubleWAvg.at(i); auto weight = lhs.weight + rhs.weight; - auto avg = lhs.avg * static_cast(lhs.weight) + rhs.avg * static_cast(rhs.weight); + auto avg = (lhs.avg * static_cast(lhs.weight)) + (rhs.avg * static_cast(rhs.weight)); avg = weight == 0 ? 0 : avg / static_cast(weight); lhs.avg = avg; lhs.weight = weight; diff -Nru pdns-recursor-5.2.13/rec-tcounters.hh pdns-recursor-5.4.9/rec-tcounters.hh --- pdns-recursor-5.2.13/rec-tcounters.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-tcounters.hh 2026-10-26 08:26:51.000000000 +0000 @@ -99,6 +99,14 @@ maxChainWeight, chainLimits, ecsMissingCount, + cookieMalformed, + cookieMatched, + cookieMismatchedOverTCP, + cookieMismatchedOverUDP, + cookieNotInReply, + cookieRetry, + cookieProbeSupported, + cookieProbeUnsupported, numberOfCounters }; @@ -181,7 +189,7 @@ void addToRollingAvg(double value, uint64_t rollsize) { - add((1.0 - 1.0 / static_cast(rollsize)) * avg + value / static_cast(rollsize)); + add(((1.0 - 1.0 / static_cast(rollsize)) * avg) + (value / static_cast(rollsize))); } }; // And an array of weighted averaged values @@ -196,11 +204,11 @@ } return *this; } - static const size_t numberoOfRCodes = 16; - std::array rcodeCounters; + static const size_t numberOfRCodes = 16; + std::array rcodeCounters{}; }; // An RCodes histogram - RCodeCounters auth{}; + RCodeCounters auth; std::array(Histogram::numberOfCounters)> histograms = { pdns::Histogram{"answers", {1000, 10000, 100000, 1000000}}, @@ -212,7 +220,7 @@ pdns::Histogram{"cumul-authanswers-", 1000, 13}}; // Response stats - RecResponseStats responseStats{}; + RecResponseStats responseStats; // DNSSEC stats struct DNSSECCounters @@ -228,7 +236,7 @@ { return counts.at(static_cast(index)); } - std::array(vState::BogusInvalidDNSKEYProtocol) + 1> counts; + std::array(vState::BogusInvalidDNSKEYProtocol) + 1> counts{}; }; std::array(DNSSECHistogram::numberOfCounters)> dnssecCounters{}; @@ -246,9 +254,9 @@ { return counts.at(static_cast(index)); } - std::array(DNSFilterEngine::PolicyKind::Custom) + 1> counts; + std::array(DNSFilterEngine::PolicyKind::Custom) + 1> counts{}; }; - PolicyCounters policyCounters{}; + PolicyCounters policyCounters; // Policy hits by name struct PolicyNameCounters @@ -264,27 +272,16 @@ }; PolicyNameCounters policyNameHits; - Counters() - { - for (auto& elem : uint64Count) { - elem = 0; - } - // doubleWAvg has a default constructor that initializes - for (auto& elem : auth.rcodeCounters) { - elem = 0; - } - // Histogram has a constructor that initializes - // RecResponseStats has a default constructor that initializes - for (auto& histogram : dnssecCounters) { - for (auto& elem : histogram.counts) { - elem = 0; - } - } - for (auto& elem : policyCounters.counts) { - elem = 0; - } - // PolicyNameCounters has a default constuctor that initializes - } + Counters() = default; + // { + // // uint64Count field has initializer + // // doubleWAvg has a default constructor that initializes + // // auth.RCodeCounters field is initialized + // // Histogram has a constructor that initializes + // // RecResponseStats has a default constructor that initializes + // // dnssecCounters field is initialized + // // PolicyNameCounters has a default constructor that initializes + // } // Merge a set of counters into an existing set of counters. For simple counters, that will be additions // for averages, we should take the weights into account. Histograms need to sum all individual counts. @@ -324,7 +321,7 @@ } // We only have a single PolicyHistogram indexed PolicyCounters, so no need to select a specific one - PolicyCounters& at(PolicyHistogram) + PolicyCounters& at(PolicyHistogram /* unused */) { return policyCounters; } diff -Nru pdns-recursor-5.2.13/rec-tcp.cc pdns-recursor-5.4.9/rec-tcp.cc --- pdns-recursor-5.2.13/rec-tcp.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-tcp.cc 2026-10-26 08:26:51.000000000 +0000 @@ -68,7 +68,22 @@ uint16_t TCPConnection::s_maxInFlight; -thread_local std::unique_ptr t_tcpClientCounts; +using tcpClientCounts_t = map; + +static void tcpClientCountsDt([[maybe_unused]] tcpClientCounts_t* ptr) +{ + // One some systems (Suse 15.7 using gcc13 is a known example) the order of thread local objects + // teardown is such that the destruction of t_tcpClientCounts happens before running client TCP + // connections are torn down. That causes a Use After Free of tcpClientCounts and consequently a + // Double Free when erase() is called in the TCPConnection destructor. To avoid this order + // dependency, as a workaround we explictly do not destroy the object managed by the + // tcpClientCounts unique pointer on exit. + + // delete ptr +} + +using uniqueClientTCPCounts_t = std::unique_ptr; +static thread_local uniqueClientTCPCounts_t t_tcpClientCounts(new tcpClientCounts_t, tcpClientCountsDt); static void handleRunningTCPQuestion(int fileDesc, FDMultiplexer::funcparam_t& var); @@ -98,16 +113,14 @@ { try { if (closesocket(d_fd) < 0) { - SLOG(g_log << Logger::Error << "Error closing socket for TCPConnection" << endl, - g_slogtcpin->info(Logr::Error, "Error closing socket for TCPConnection")); + g_slogtcpin->info(Logr::Error, "Error closing socket for TCPConnection"); } } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error closing TCPConnection socket: " << e.reason << endl, - g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCPConnection socket", "exception", Logging::Loggable("PDNSException"))); + g_slogtcpin->error(Logr::Error, e.reason, "Error closing TCPConnection socket", "exception", Logging::Loggable("PDNSException")); } - if (t_tcpClientCounts->count(d_remote) != 0 && (*t_tcpClientCounts)[d_remote]-- == 0) { + if (t_tcpClientCounts && t_tcpClientCounts->count(d_remote) != 0 && --(*t_tcpClientCounts)[d_remote] == 0) { t_tcpClientCounts->erase(d_remote); } --s_currentConnections; @@ -254,8 +267,7 @@ { if (!t_allowNotifyFrom || !t_allowNotifyFrom->match(comboWriter->d_mappedSource)) { if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP NOTIFY from " << comboWriter->d_mappedSource.toString() << ", address not matched by allow-notify-from" << endl, - g_slogtcpin->info(Logr::Error, "Dropping TCP NOTIFY, address not matched by allow-notify-from", "source", Logging::Loggable(comboWriter->d_mappedSource))); + g_slogtcpin->info(Logr::Error, "Dropping TCP NOTIFY, address not matched by allow-notify-from", "source", Logging::Loggable(comboWriter->d_mappedSource)); } t_Counters.at(rec::Counter::sourceDisallowedNotify)++; @@ -264,8 +276,7 @@ if (!isAllowNotifyForZone(qname)) { if (!g_quiet) { - SLOG(g_log << Logger::Error << "[" << g_multiTasker->getTid() << "] dropping TCP NOTIFY from " << comboWriter->d_mappedSource.toString() << ", for " << qname.toLogString() << ", zone not matched by allow-notify-for" << endl, - g_slogtcpin->info(Logr::Error, "Dropping TCP NOTIFY, zone not matched by allow-notify-for", "source", Logging::Loggable(comboWriter->d_mappedSource), "zone", Logging::Loggable(qname))); + g_slogtcpin->info(Logr::Error, "Dropping TCP NOTIFY, zone not matched by allow-notify-for", "source", Logging::Loggable(comboWriter->d_mappedSource), "zone", Logging::Loggable(qname)); } t_Counters.at(rec::Counter::zoneDisallowedNotify)++; @@ -274,42 +285,55 @@ return true; } -static void doProtobufLogQuery(bool logQuery, LocalStateHolder& luaconfsLocal, const std::unique_ptr& comboWriter, const DNSName& qname, QType qtype, QClass qclass, const dnsheader* dnsheader, const shared_ptr& conn, const boost::optional& ednsVersion) +static void doProtobufLogQuery(bool logQuery, LocalStateHolder& luaconfsLocal, const std::unique_ptr& comboWriter, const DNSName& qname, QType qtype, QClass qclass, const dnsheader* dnsheader, const shared_ptr& conn, const std::optional& ednsVersion) { try { if (logQuery && !(luaconfsLocal->protobufExportConfig.taggedOnly && comboWriter->d_policyTags.empty())) { - protobufLogQuery(luaconfsLocal, comboWriter->d_uuid, comboWriter->d_source, comboWriter->d_destination, comboWriter->d_mappedSource, comboWriter->d_ednssubnet.source, true, conn->qlen, qname, qtype, qclass, comboWriter->d_policyTags, comboWriter->d_requestorId, comboWriter->d_deviceId, comboWriter->d_deviceName, comboWriter->d_meta, ednsVersion, *dnsheader); + protobufLogQuery(luaconfsLocal, comboWriter->d_uuid, comboWriter->d_source, comboWriter->d_destination, comboWriter->d_mappedSource, comboWriter->d_ednssubnet.getSource(), true, conn->qlen, qname, qtype, qclass, comboWriter->d_policyTags, comboWriter->d_requestorId, comboWriter->d_deviceId, comboWriter->d_deviceName, comboWriter->d_meta, ednsVersion, *dnsheader, comboWriter->d_otTrace.trace_id); } } catch (const std::exception& e) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Warning << "Error parsing a TCP query packet for edns subnet: " << e.what() << endl, - g_slogtcpin->error(Logr::Warning, e.what(), "Error parsing a TCP query packet for edns subnet", "exception", Logging::Loggable("std::exception"), "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->error(Logr::Warning, e.what(), "Error parsing a TCP query packet for edns subnet", "exception", Logging::Loggable("std::exception"), "remote", Logging::Loggable(conn->d_remote)); } } } -static void doProcessTCPQuestion(std::unique_ptr& comboWriter, shared_ptr& conn, RunningTCPQuestionGuard& tcpGuard, int fileDesc) +static void doProcessTCPQuestion(std::unique_ptr& comboWriter, shared_ptr& conn, RunningTCPQuestionGuard& tcpGuard, int fileDesc) // NOLINT(readability-function-cognitive-complexity) will fix one day { RecThreadInfo::self().incNumberOfDistributedQueries(); - struct timeval start - { - }; + struct timeval start{}; Utility::gettimeofday(&start, nullptr); DNSName qname; uint16_t qtype = 0; uint16_t qclass = 0; - bool needEDNSParse = false; + bool needEDNSParse = g_useIncomingECS; string requestorId; string deviceId; string deviceName; bool logQuery = false; bool qnameParsed = false; - boost::optional ednsVersion; + std::optional ednsVersion; comboWriter->d_eventTrace.setEnabled(SyncRes::s_event_trace_enabled != 0); + if (comboWriter->d_eventTrace.enabled() && !matchOTConditions(t_OTConditions, comboWriter->d_mappedSource) && SyncRes::eventTraceEnabledOnly(SyncRes::event_trace_to_ot)) { + comboWriter->d_eventTrace.setEnabled(false); + } + + // eventTrace uses monotonic time, while OpenTelemetry uses absolute time. setEnabled() + // established the reference point, get an absolute TS as close as possible to the + // eventTrace start of trace time. + auto traceTS = pdns::trace::timestamp(); comboWriter->d_eventTrace.add(RecEventTrace::ReqRecv); + if (SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + comboWriter->d_otTrace.clear(); + comboWriter->d_otTrace.start_time_unix_nano = traceTS; + } + auto newParent = comboWriter->d_eventTrace.add(RecEventTrace::ProcessTCP); + auto oldParent = comboWriter->d_eventTrace.setParent(newParent); + RecEventTrace::EventScope traceScope(oldParent, comboWriter->d_eventTrace); + auto luaconfsLocal = g_luaconfs.getLocal(); if (checkProtobufExport(luaconfsLocal)) { needEDNSParse = true; @@ -320,25 +344,34 @@ if (needEDNSParse || (t_pdl && (t_pdl->hasGettagFFIFunc() || t_pdl->hasGettagFunc())) || comboWriter->d_mdp.d_header.opcode == static_cast(Opcode::Notify)) { try { + auto parseMatch = comboWriter->d_eventTrace.add(RecEventTrace::PacketParse); EDNSOptionViewMap ednsOptions; comboWriter->d_ecsParsed = true; comboWriter->d_ecsFound = false; getQNameAndSubnet(conn->data, &qname, &qtype, &qclass, - comboWriter->d_ecsFound, &comboWriter->d_ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr, ednsVersion); + comboWriter->d_ecsFound, &comboWriter->d_ednssubnet, + (g_gettagNeedsEDNSOptions || SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) ? &ednsOptions : nullptr, ednsVersion); + comboWriter->d_eventTrace.add(RecEventTrace::PacketParse, 0, false, parseMatch); qnameParsed = true; + if (SyncRes::eventTraceEnabled(SyncRes::event_trace_to_ot)) { + bool ednsFound = pdns::trace::extractOTraceIDs(ednsOptions, EDNSOptionCode::TRACEPARENT, comboWriter->d_otTrace); + if (SyncRes::eventTraceEnabledOnly(SyncRes::event_trace_to_ot) && !matchOTConditions(comboWriter->d_eventTrace, t_OTConditions, comboWriter->d_mappedSource, qname, qtype, ntohs(comboWriter->d_mdp.d_header.id), ednsFound)) { + comboWriter->d_eventTrace.setEnabled(false); + } + } 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_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); + RecursorLua4::FFIParams params(qname, qtype, comboWriter->d_local, comboWriter->d_remote, comboWriter->d_destination, comboWriter->d_source, comboWriter->d_ednssubnet.getSource(), 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); + auto match = comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI); comboWriter->d_tag = t_pdl->gettag_ffi(params); - comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI, comboWriter->d_tag, false); + comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTagFFI, comboWriter->d_tag, false, match); } 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_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); + auto match = comboWriter->d_eventTrace.add(RecEventTrace::LuaGetTag); + comboWriter->d_tag = t_pdl->gettag(comboWriter->d_source, comboWriter->d_ednssubnet.getSource(), 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, match); } // 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 @@ -350,7 +383,7 @@ } catch (const MOADNSException& moadnsexception) { if (g_logCommonErrors) { - g_slogtcpin->error(moadnsexception.what(), "Error parsing a query packet for tag determination", "qname", Logging::Loggable(qname), "excepion", Logging::Loggable("MOADNSException")); + g_slogtcpin->error(moadnsexception.what(), "Error parsing a query packet for tag determination", "qname", Logging::Loggable(qname), "exception", Logging::Loggable("MOADNSException")); } } catch (const std::exception& stdException) { @@ -385,8 +418,7 @@ bool ipf = t_pdl->ipfilter(comboWriter->d_source, comboWriter->d_destination, *dnsheader, comboWriter->d_eventTrace); if (ipf) { if (!g_quiet) { - SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " [" << g_multiTasker->getTid() << "/" << g_multiTasker->numProcesses() << "] DROPPED TCP question from " << comboWriter->d_source.toStringWithPort() << (comboWriter->d_source != comboWriter->d_remote ? " (via " + comboWriter->d_remote.toStringWithPort() + ")" : "") << " based on policy" << endl, - g_slogtcpin->info(Logr::Info, "Dropped TCP question based on policy", "remote", Logging::Loggable(conn->d_remote), "source", Logging::Loggable(comboWriter->d_source))); + g_slogtcpin->info(Logr::Info, "Dropped TCP question based on policy", "remote", Logging::Loggable(conn->d_remote), "source", Logging::Loggable(comboWriter->d_source)); } t_Counters.at(rec::Counter::policyDrops)++; return; @@ -396,16 +428,14 @@ if (comboWriter->d_mdp.d_header.qr) { t_Counters.at(rec::Counter::ignoredCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring answer from TCP client " << comboWriter->getRemote() << " on server socket!" << endl, - g_slogtcpin->info(Logr::Error, "Ignoring answer from TCP client on server socket", "remote", Logging::Loggable(comboWriter->getRemote()))); + g_slogtcpin->info(Logr::Error, "Ignoring answer from TCP client on server socket", "remote", Logging::Loggable(comboWriter->getRemote())); } return; } if (comboWriter->d_mdp.d_header.opcode != static_cast(Opcode::Query) && comboWriter->d_mdp.d_header.opcode != static_cast(Opcode::Notify)) { t_Counters.at(rec::Counter::ignoredCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring unsupported opcode " << Opcode::to_s(comboWriter->d_mdp.d_header.opcode) << " from TCP client " << comboWriter->getRemote() << " on server socket!" << endl, - g_slogtcpin->info(Logr::Error, "Ignoring unsupported opcode from TCP client", "remote", Logging::Loggable(comboWriter->getRemote()), "opcode", Logging::Loggable(Opcode::to_s(comboWriter->d_mdp.d_header.opcode)))); + g_slogtcpin->info(Logr::Error, "Ignoring unsupported opcode from TCP client", "remote", Logging::Loggable(comboWriter->getRemote()), "opcode", Logging::Loggable(Opcode::to_s(comboWriter->d_mdp.d_header.opcode))); } sendErrorOverTCP(comboWriter, RCode::NotImp); tcpGuard.keep(); @@ -414,8 +444,7 @@ if (dnsheader->qdcount == 0U) { t_Counters.at(rec::Counter::emptyQueriesCount)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Ignoring empty (qdcount == 0) query from " << comboWriter->getRemote() << " on server socket!" << endl, - g_slogtcpin->info(Logr::Error, "Ignoring empty (qdcount == 0) query on server socket", "remote", Logging::Loggable(comboWriter->getRemote()))); + g_slogtcpin->info(Logr::Error, "Ignoring empty (qdcount == 0) query on server socket", "remote", Logging::Loggable(comboWriter->getRemote())); } sendErrorOverTCP(comboWriter, RCode::NotImp); tcpGuard.keep(); @@ -436,45 +465,41 @@ } string response; - RecursorPacketCache::OptPBData pbData{boost::none}; + RecursorPacketCache::OptPBData pbData{std::nullopt}; if (comboWriter->d_mdp.d_header.opcode == static_cast(Opcode::Query)) { /* It might seem like a good idea to skip the packet cache lookup if we know that the answer is not cacheable, but it means that the hash would not be computed. If some script decides at a later time to mark back the answer as cacheable we would cache it with a wrong tag, so better safe than sorry. */ - comboWriter->d_eventTrace.add(RecEventTrace::PCacheCheck); - bool cacheHit = checkForCacheHit(qnameParsed, comboWriter->d_tag, conn->data, qname, qtype, qclass, g_now, response, comboWriter->d_qhash, pbData, true, comboWriter->d_source, comboWriter->d_mappedSource); - comboWriter->d_eventTrace.add(RecEventTrace::PCacheCheck, cacheHit, false); + auto match = comboWriter->d_eventTrace.add(RecEventTrace::PCacheCheck); + bool cacheHit = checkForCacheHit(qnameParsed, comboWriter->d_tag, conn->data, qname, qtype, qclass, g_now, response, comboWriter->d_qhash, pbData, true, comboWriter->d_source, comboWriter->d_mappedSource, comboWriter->d_ecsFound, comboWriter->d_ednssubnet); + comboWriter->d_eventTrace.add(RecEventTrace::PCacheCheck, cacheHit, false, match); if (cacheHit) { if (!g_quiet) { - SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " TCP question answered from packet cache tag=" << comboWriter->d_tag << " from " << comboWriter->d_source.toStringWithPort() << (comboWriter->d_source != comboWriter->d_remote ? " (via " + comboWriter->d_remote.toStringWithPort() + ")" : "") << endl, - g_slogtcpin->info(Logr::Notice, "TCP question answered from packet cache", "tag", Logging::Loggable(comboWriter->d_tag), - "qname", Logging::Loggable(qname), "qtype", Logging::Loggable(QType(qtype)), - "source", Logging::Loggable(comboWriter->d_source), "remote", Logging::Loggable(comboWriter->d_remote))); + g_slogtcpin->info(Logr::Notice, "TCP question answered from packet cache", "tag", Logging::Loggable(comboWriter->d_tag), + "qname", Logging::Loggable(qname), "qtype", Logging::Loggable(QType(qtype)), + "source", Logging::Loggable(comboWriter->d_source), "remote", Logging::Loggable(comboWriter->d_remote)); } + auto answerMatch = comboWriter->d_eventTrace.add(RecEventTrace::AnswerSent); bool hadError = sendResponseOverTCP(comboWriter, response); finishTCPReply(comboWriter, hadError, false); - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now, nullptr); uint64_t spentUsec = uSec(now - start); t_Counters.at(rec::Histogram::cumulativeAnswers)(spentUsec); - comboWriter->d_eventTrace.add(RecEventTrace::AnswerSent); + comboWriter->d_eventTrace.add(RecEventTrace::AnswerSent, 0, false, answerMatch); + traceScope.close(0); if (t_protobufServers.servers && comboWriter->d_logResponse && (!luaconfsLocal->protobufExportConfig.taggedOnly || (pbData && pbData->d_tagged))) { - struct timeval tval - { - 0, 0 - }; - protobufLogResponse(dnsheader, luaconfsLocal, pbData, tval, true, comboWriter->d_source, comboWriter->d_destination, comboWriter->d_mappedSource, comboWriter->d_ednssubnet, comboWriter->d_uuid, comboWriter->d_requestorId, comboWriter->d_deviceId, comboWriter->d_deviceName, comboWriter->d_meta, comboWriter->d_eventTrace, comboWriter->d_policyTags); + struct timeval tval{ + 0, 0}; + protobufLogResponse(qname, qtype, dnsheader, luaconfsLocal, pbData, tval, true, comboWriter->d_source, comboWriter->d_destination, comboWriter->d_mappedSource, comboWriter->d_ednssubnet, comboWriter->d_uuid, comboWriter->d_requestorId, comboWriter->d_deviceId, comboWriter->d_deviceName, comboWriter->d_meta, comboWriter->d_eventTrace, comboWriter->d_otTrace, comboWriter->d_policyTags); } - if (comboWriter->d_eventTrace.enabled() && (SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_log) != 0) { - SLOG(g_log << Logger::Info << comboWriter->d_eventTrace.toString() << endl, - g_slogtcpin->info(Logr::Info, comboWriter->d_eventTrace.toString())); // More fancy? + if (comboWriter->d_eventTrace.enabled() && SyncRes::eventTraceEnabled(SyncRes::event_trace_to_log)) { + g_slogtcpin->info(Logr::Info, comboWriter->d_eventTrace.toString()); // More fancy? } tcpGuard.keep(); t_Counters.updateSnap(g_regressionTestMode); @@ -484,8 +509,7 @@ if (comboWriter->d_mdp.d_header.opcode == static_cast(Opcode::Notify)) { if (!g_quiet) { - SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " got NOTIFY for " << qname.toLogString() << " from " << comboWriter->d_source.toStringWithPort() << (comboWriter->d_source != comboWriter->d_remote ? " (via " + comboWriter->d_remote.toStringWithPort() + ")" : "") << endl, - g_slogtcpin->info(Logr::Notice, "Got NOTIFY", "qname", Logging::Loggable(qname), "source", Logging::Loggable(comboWriter->d_source), "remote", Logging::Loggable(comboWriter->d_remote))); + g_slogtcpin->info(Logr::Notice, "Got NOTIFY", "qname", Logging::Loggable(qname), "source", Logging::Loggable(comboWriter->d_source), "remote", Logging::Loggable(comboWriter->d_remote)); } requestWipeCaches(qname); @@ -508,6 +532,7 @@ t_fdm->setReadTTD(fileDesc, ttd, g_tcpTimeout); } tcpGuard.keep(); + traceScope.close(0); g_multiTasker->makeThread(startDoResolve, comboWriter.release()); // deletes dc } // good query } @@ -530,8 +555,7 @@ ssize_t remaining = isProxyHeaderComplete(conn->data); if (remaining == 0) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to consume proxy protocol header in packet from TCP client " << conn->d_remote.toStringWithPort() << endl, - g_slogtcpin->info(Logr::Error, "Unable to consume proxy protocol header in packet from TCP client", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "Unable to consume proxy protocol header in packet from TCP client", "remote", Logging::Loggable(conn->d_remote)); } ++t_Counters.at(rec::Counter::proxyProtocolInvalidCount); return; @@ -551,16 +575,14 @@ size_t used = parseProxyHeader(conn->data, proxy, conn->d_source, conn->d_destination, tcp, conn->proxyProtocolValues); if (used <= 0) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to parse proxy protocol header in packet from TCP client " << conn->d_remote.toStringWithPort() << endl, - g_slogtcpin->info(Logr::Error, "Unable to parse proxy protocol header in packet from TCP client", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "Unable to parse proxy protocol header in packet from TCP client", "remote", Logging::Loggable(conn->d_remote)); } ++t_Counters.at(rec::Counter::proxyProtocolInvalidCount); return; } if (static_cast(used) > g_proxyProtocolMaximumSize) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Proxy protocol header in packet from TCP client " << conn->d_remote.toStringWithPort() << " is larger than proxy-protocol-maximum-size (" << used << "), dropping" << endl, - g_slogtcpin->info(Logr::Error, "Proxy protocol header in packet from TCP client is larger than proxy-protocol-maximum-size", "remote", Logging::Loggable(conn->d_remote), "size", Logging::Loggable(used))); + g_slogtcpin->info(Logr::Error, "Proxy protocol header in packet from TCP client is larger than proxy-protocol-maximum-size", "remote", Logging::Loggable(conn->d_remote), "size", Logging::Loggable(used)); } ++t_Counters.at(rec::Counter::proxyProtocolInvalidCount); return; @@ -581,8 +603,7 @@ } 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, - g_slogtcpin->info(Logr::Error, "Dropping TCP query, address not matched by allow-from", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "Dropping TCP query, address not matched by allow-from", "remote", Logging::Loggable(conn->d_remote)); } ++t_Counters.at(rec::Counter::unauthorizedTCP); @@ -622,8 +643,7 @@ if (bytes <= 0) { if (!tcpGuard.handleTCPReadResult(fileDesc, bytes)) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "TCP client " << conn->d_remote.toStringWithPort() << " disconnected after first byte" << endl, - g_slogtcpin->info(Logr::Error, "TCP client disconnected after first byte", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "TCP client disconnected after first byte", "remote", Logging::Loggable(conn->d_remote)); } } return; @@ -635,16 +655,14 @@ if (bytes <= 0) { if (!tcpGuard.handleTCPReadResult(fileDesc, bytes)) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "TCP client " << conn->d_remote.toStringWithPort() << " disconnected while reading question body" << endl, - g_slogtcpin->info(Logr::Error, "TCP client disconnected while reading question body", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "TCP client disconnected while reading question body", "remote", Logging::Loggable(conn->d_remote)); } } return; } if (bytes > std::numeric_limits::max()) { if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "TCP client " << conn->d_remote.toStringWithPort() << " sent an invalid question size while reading question body" << endl, - g_slogtcpin->info(Logr::Error, "TCP client sent an invalid question size while reading question body", "remote", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "TCP client sent an invalid question size while reading question body", "remote", Logging::Loggable(conn->d_remote)); } return; } @@ -658,8 +676,7 @@ catch (const MOADNSException& mde) { t_Counters.at(rec::Counter::clientParseError)++; if (g_logCommonErrors) { - SLOG(g_log << Logger::Error << "Unable to parse packet from TCP client " << conn->d_remote.toStringWithPort() << endl, - g_slogtcpin->info(Logr::Error, "Unable to parse packet from TCP client", "remte", Logging::Loggable(conn->d_remote))); + g_slogtcpin->info(Logr::Error, "Unable to parse packet from TCP client", "remte", Logging::Loggable(conn->d_remote)); } return; } @@ -667,7 +684,7 @@ comboWriter->d_tcpConnection = conn; // carry the torch comboWriter->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd comboWriter->d_tcp = true; - comboWriter->setRemote(conn->d_remote); // the address the query was received from + comboWriter->setRemote(conn->d_remote); // the address from which the query was received comboWriter->setSource(conn->d_source); // the address we assume the query is coming from, might be set by proxy protocol ComboAddress dest; dest.reset(); @@ -734,8 +751,7 @@ } 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))); + 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; @@ -773,7 +789,7 @@ static void TCPIOHandlerStateChange(IOState oldstate, IOState newstate, std::shared_ptr& pid) { - TCPLOG(pid->tcpsock, "State transation " << int(oldstate) << "->" << int(newstate) << endl); + TCPLOG(pid->tcpsock, "State transition " << int(oldstate) << "->" << int(newstate) << endl); pid->lowState = newstate; @@ -936,21 +952,17 @@ if (readFileIfThere("/proc/sys/net/ipv4/tcp_fastopen", &line)) { int flag = std::stoi(line); if (active && !(flag & 1)) { - SLOG(g_log << Logger::Error << "tcp-fast-open-connect enabled but net.ipv4.tcp_fastopen does not allow it" << endl, - log->info(Logr::Error, "tcp-fast-open-connect enabled but net.ipv4.tcp_fastopen does not allow it")); + log->info(Logr::Error, "tcp-fast-open-connect enabled but net.ipv4.tcp_fastopen does not allow it"); } if (!active && !(flag & 2)) { - SLOG(g_log << Logger::Error << "tcp-fast-open enabled but net.ipv4.tcp_fastopen does not allow it" << endl, - log->info(Logr::Error, "tcp-fast-open enabled but net.ipv4.tcp_fastopen does not allow it")); + log->info(Logr::Error, "tcp-fast-open enabled but net.ipv4.tcp_fastopen does not allow it"); } } else { - SLOG(g_log << Logger::Notice << "Cannot determine if kernel settings allow fast-open" << endl, - log->info(Logr::Notice, "Cannot determine if kernel settings allow fast-open")); + log->info(Logr::Notice, "Cannot determine if kernel settings allow fast-open"); } #else - SLOG(g_log << Logger::Notice << "Cannot determine if kernel settings allow fast-open" << endl, - log->info(Logr::Notice, "Cannot determine if kernel settings allow fast-open")); + log->info(Logr::Notice, "Cannot determine if kernel settings allow fast-open"); #endif } @@ -962,8 +974,7 @@ socket.setFastOpenConnect(); } catch (const NetworkError& e) { - SLOG(g_log << Logger::Error << "tcp-fast-open-connect enabled but returned error: " << e.what() << endl, - log->error(Logr::Error, e.what(), "tcp-fast-open-connect enabled but returned error")); + log->error(Logr::Error, e.what(), "tcp-fast-open-connect enabled but returned error"); } } @@ -1011,7 +1022,7 @@ } if (packet.size() != data.size()) { // main loop tells us what it sent out, or empty in case of an error // fd housekeeping done by TCPIOHandlerIO - TCPLOG(pident->tcpsock, "PermanentError size mismatch" << endl); + TCPLOG(pident->tcpsock, "PermanentError size mismatch " << endl); return LWResult::Result::PermanentError; } @@ -1030,13 +1041,13 @@ try { TCPLOG(handler->getDescriptor(), "calling tryRead() " << len << endl); state = handler->tryRead(data, pos, len); - TCPLOG(handler->getDescriptor(), "arcvtcp tryRead() returned " << int(state) << ' ' << pos << '/' << len << endl); + TCPLOG(handler->getDescriptor(), "arecvtcp tryRead() returned " << int(state) << ' ' << pos << '/' << len << endl); switch (state) { case IOState::Done: case IOState::NeedRead: if (pos == len || (incompleteOkay && pos > 0)) { data.resize(pos); - TCPLOG(handler->getDescriptor(), "acecvtcp success A" << endl); + TCPLOG(handler->getDescriptor(), "arecvtcp success A" << endl); return LWResult::Result::Success; } break; @@ -1104,33 +1115,32 @@ auto first = true; #endif const uint16_t defaultLocalPort = ::arg().asNum("local-port"); + const vector defaultVector = {"127.0.0.1", "::1"}; + const auto configIsDefault = localAddresses == defaultVector; + for (const auto& localAddress : localAddresses) { ComboAddress address{localAddress, defaultLocalPort}; - const int socketFd = socket(address.sin6.sin6_family, SOCK_STREAM, 0); + auto socketFd = FDWrapper(socket(address.sin6.sin6_family, SOCK_STREAM, 0)); if (socketFd < 0) { throw PDNSException("Making a TCP server socket for resolver: " + stringerror()); } - logVec.emplace_back(address.toStringWithPort()); setCloseOnExec(socketFd); int tmp = 1; if (setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp) < 0) { int err = errno; - SLOG(g_log << Logger::Error << "Setsockopt failed for TCP listening socket" << endl, - log->error(Logr::Critical, err, "Setsockopt failed for TCP listening socket")); + log->error(Logr::Critical, err, "Setsockopt failed for TCP listening socket"); _exit(1); } if (address.sin6.sin6_family == AF_INET6 && setsockopt(socketFd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) { int err = errno; - SLOG(g_log << Logger::Error << "Failed to set IPv6 socket to IPv6 only, continuing anyhow: " << stringerror(err) << endl, - log->error(Logr::Warning, err, "Failed to set IPv6 socket to IPv6 only, continuing anyhow")); + log->error(Logr::Warning, err, "Failed to set IPv6 socket to IPv6 only, continuing anyhow"); } #ifdef TCP_DEFER_ACCEPT if (setsockopt(socketFd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &tmp, sizeof tmp) >= 0) { if (first) { - SLOG(g_log << Logger::Info << "Enabled TCP data-ready filter for (slight) DoS protection" << endl, - log->info(Logr::Info, "Enabled TCP data-ready filter for (slight) DoS protection")); + log->info(Logr::Info, "Enabled TCP data-ready filter for (slight) DoS protection"); } } #endif @@ -1162,18 +1172,21 @@ #ifdef TCP_FASTOPEN if (setsockopt(socketFd, IPPROTO_TCP, TCP_FASTOPEN, &SyncRes::s_tcp_fast_open, sizeof SyncRes::s_tcp_fast_open) < 0) { int err = errno; - SLOG(g_log << Logger::Error << "Failed to enable TCP Fast Open for listening socket: " << stringerror(err) << endl, - log->error(Logr::Error, err, "Failed to enable TCP Fast Open for listening socket")); + log->error(Logr::Error, err, "Failed to enable TCP Fast Open for listening socket"); } #else - SLOG(g_log << Logger::Warning << "TCP Fast Open configured but not supported for listening socket" << endl, - log->info(Logr::Warning, "TCP Fast Open configured but not supported for listening socket")); + log->info(Logr::Warning, "TCP Fast Open configured but not supported for listening socket"); #endif } socklen_t socklen = address.sin4.sin_family == AF_INET ? sizeof(address.sin4) : sizeof(address.sin6); if (::bind(socketFd, reinterpret_cast(&address), socklen) < 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - throw PDNSException("Binding TCP server socket for " + address.toStringWithPort() + ": " + stringerror()); + int err = errno; + if (!configIsDefault || address != ComboAddress{"::1", defaultLocalPort}) { + throw PDNSException("Binding TCP server socket for " + address.toStringWithPort() + ": " + stringerror(err)); + } + log->info(Logr::Warning, "Cannot listen on this address, skipping", "proto", Logging::Loggable("TCP"), "address", Logging::Loggable(address), "error", Logging::Loggable(stringerror(err))); + continue; } setNonBlocking(socketFd); @@ -1181,13 +1194,13 @@ setSocketSendBuffer(socketFd, 65000); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << e.what() << endl, - log->error(Logr::Error, e.what(), "Exception while setting socket send buffer")); + log->error(Logr::Error, e.what(), "Exception while setting socket send buffer"); } listen(socketFd, 128); deferredAdds.emplace_back(socketFd, handleNewTCPQuestion); tcpSockets.insert(socketFd); + logVec.emplace_back(address.toStringWithPort()); // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP: // - fd is not that which we know here, but returned from accept() @@ -1195,6 +1208,7 @@ #ifdef TCP_DEFER_ACCEPT first = false; #endif + socketFd.release(); // to avoid auto-close by FDWrapper } if (doLog) { log->info(Logr::Info, "Listening for queries", "protocol", Logging::Loggable("TCP"), "addresses", Logging::IterLoggable(logVec.cbegin(), logVec.cend()), "socketInstances", Logging::Loggable(instances), "reuseport", Logging::Loggable(g_reusePort)); diff -Nru pdns-recursor-5.2.13/rec-tcpout.cc pdns-recursor-5.4.9/rec-tcpout.cc --- pdns-recursor-5.2.13/rec-tcpout.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-tcpout.cc 2026-10-26 08:26:51.000000000 +0000 @@ -27,6 +27,10 @@ #undef CERT #include "syncres.hh" +#include "dnsname.hh" +#include "rec-main.hh" + +#include "cxxsettings.hh" timeval TCPOutConnectionManager::s_maxIdleTime; size_t TCPOutConnectionManager::s_maxQueries; @@ -51,37 +55,98 @@ } } -void TCPOutConnectionManager::store(const struct timeval& now, const ComboAddress& ip, Connection&& connection) +void TCPOutConnectionManager::store(const struct timeval& now, const endpoints_t& endpoints, Connection&& connection) { ++connection.d_numqueries; if (s_maxQueries > 0 && connection.d_numqueries >= s_maxQueries) { return; } - if (d_idle_connections.size() >= s_maxIdlePerThread || d_idle_connections.count(ip) >= s_maxIdlePerAuth) { + if (d_idle_connections.size() >= s_maxIdlePerThread || d_idle_connections.count(endpoints) >= s_maxIdlePerAuth) { cleanup(now); } if (d_idle_connections.size() >= s_maxIdlePerThread) { return; } - if (d_idle_connections.count(ip) >= s_maxIdlePerAuth) { + if (d_idle_connections.count(endpoints) >= s_maxIdlePerAuth) { return; } gettimeofday(&connection.d_last_used, nullptr); - d_idle_connections.emplace(ip, std::move(connection)); + d_idle_connections.emplace(endpoints, std::move(connection)); } -TCPOutConnectionManager::Connection TCPOutConnectionManager::get(const ComboAddress& ip) +TCPOutConnectionManager::Connection TCPOutConnectionManager::get(const endpoints_t& pair) { - if (d_idle_connections.count(ip) > 0) { - auto h = d_idle_connections.extract(ip); - return h.mapped(); + if (d_idle_connections.count(pair) > 0) { + auto connection = d_idle_connections.extract(pair); + return connection.mapped(); } return Connection{}; } +struct OutgoingTLSConfigTable +{ + SuffixMatchTree d_suffixToConfig; + NetmaskTree d_netmaskToConfig; +}; + +static LockGuarded s_outgoingTLSConfigTable; + +void TCPOutConnectionManager::setupOutgoingTLSConfigTables(pdns::rust::settings::rec::Recursorsettings& settings) +{ + auto& vec = settings.outgoing.tls_configurations; + auto table = s_outgoingTLSConfigTable.lock(); + table->d_suffixToConfig = SuffixMatchTree(); // no clear? + table->d_netmaskToConfig.clear(); + for (const auto& entry : vec) { + for (const auto& element : entry.suffixes) { + DNSName name = DNSName(std::string(element)); + auto copy = entry; + table->d_suffixToConfig.add(name, std::move(copy)); + } + for (const auto& element : entry.subnets) { + table->d_netmaskToConfig.insert(std::string(element)).second = entry; + } + } +} + +std::shared_ptr TCPOutConnectionManager::getTLSContext(const std::string& name, const ComboAddress& address, bool& verboseLogging, std::string& subjectName, std::string& subjectAddress, std::string& configName) +{ + TLSContextParameters tlsParams; + tlsParams.d_provider = "openssl"; + tlsParams.d_validateCertificates = false; + const pdns::rust::settings::rec::OutgoingTLSConfiguration* config{nullptr}; + + { + configName = ""; + auto table = s_outgoingTLSConfigTable.lock(); + if (auto* node = table->d_netmaskToConfig.lookup(address); node != nullptr) { + config = &node->second; + } + else if (const auto* found = table->d_suffixToConfig.lookup(DNSName(name)); found != nullptr) { + config = found; + } + if (config != nullptr) { + configName = std::string(config->name); + tlsParams.d_provider = std::string(config->provider); + tlsParams.d_validateCertificates = config->validate_certificate; + tlsParams.d_caStore = std::string(config->ca_store); + if (!config->subject_name.empty()) { + subjectName = std::string(config->subject_name); + }; + if (!config->subject_address.empty()) { + subjectAddress = std::string(config->subject_address); + }; + verboseLogging = config->verbose_logging; + tlsParams.d_ciphers = std::string(config->ciphers); + tlsParams.d_ciphers13 = std::string(config->ciphers_tls_13); + } + } + return ::getTLSContext(tlsParams); +} + uint64_t getCurrentIdleTCPConnections() { return broadcastAccFunction([] { return t_tcp_manager.getSize(); }); diff -Nru pdns-recursor-5.2.13/rec-tcpout.hh pdns-recursor-5.4.9/rec-tcpout.hh --- pdns-recursor-5.2.13/rec-tcpout.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-tcpout.hh 2026-10-26 08:26:51.000000000 +0000 @@ -25,6 +25,11 @@ #include "iputils.hh" #include "tcpiohandler.hh" +namespace pdns::rust::settings::rec +{ +struct Recursorsettings; +} + class TCPOutConnectionManager { public: @@ -39,7 +44,7 @@ struct Connection { - std::string toString() const + [[nodiscard]] std::string toString() const { if (d_handler) { return std::to_string(d_handler->getDescriptor()) + ' ' + std::to_string(d_handler.use_count()); @@ -48,27 +53,34 @@ } std::shared_ptr d_handler; + std::optional d_local; timeval d_last_used{0, 0}; size_t d_numqueries{0}; + bool d_verboseLogging{false}; }; - void store(const struct timeval& now, const ComboAddress& ip, Connection&& connection); - Connection get(const ComboAddress& ip); + using endpoints_t = std::pair>; + + void store(const struct timeval& now, const endpoints_t& endpoints, Connection&& connection); + Connection get(const endpoints_t& pair); void cleanup(const struct timeval& now); - size_t size() const + [[nodiscard]] size_t size() const { return d_idle_connections.size(); } - uint64_t* getSize() const + [[nodiscard]] uint64_t* getSize() const { - return new uint64_t(size()); + return new uint64_t(size()); // NOLINT(cppcoreguidelines-owning-memory): it's the API } + static void setupOutgoingTLSConfigTables(pdns::rust::settings::rec::Recursorsettings& settings); + static std::shared_ptr getTLSContext(const std::string& name, const ComboAddress& address, bool& verboseLogging, std::string& subjectName, std::string& subjectAddress, std::string& configName); + private: // This does not take into account that we can have multiple connections with different hosts (via SNI) to the same IP. // That is OK, since we are connecting by IP only at the moment. - std::multimap d_idle_connections; + std::multimap d_idle_connections; }; extern thread_local TCPOutConnectionManager t_tcp_manager; diff -Nru pdns-recursor-5.2.13/rec-web-stubs.hh pdns-recursor-5.4.9/rec-web-stubs.hh --- pdns-recursor-5.2.13/rec-web-stubs.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/rec-web-stubs.hh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,38 @@ +namespace pdns::rust::web::rec +{ +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define WRAPPER(A) \ + void A(const Request& /* unused */, Response& /* unused */); \ + void A(const Request& /* unused */, Response& /* unused */) {} + +class Request; +class Response; + +WRAPPER(apiDiscovery) +WRAPPER(apiDiscoveryV1) +WRAPPER(apiServer) +WRAPPER(apiServerCacheFlush) +WRAPPER(apiServerConfig) +WRAPPER(apiServerConfigAllowFromGET) +WRAPPER(apiServerConfigAllowFromPUT) +WRAPPER(apiServerConfigAllowNotifyFromGET) +WRAPPER(apiServerConfigAllowNotifyFromPUT) +WRAPPER(apiServerDetail) +WRAPPER(apiServerRPZStats) +WRAPPER(apiServerSearchData) +WRAPPER(apiServerStatistics) +WRAPPER(apiServerZoneDetailDELETE) +WRAPPER(apiServerZoneDetailGET) +WRAPPER(apiServerZoneDetailPUT) +WRAPPER(apiServerZonesGET) +WRAPPER(apiServerZonesPOST) +WRAPPER(apiServerOTConditionsGET) +WRAPPER(apiServerOTConditionDetailGET) +WRAPPER(apiServerOTConditionDetailDELETE) +WRAPPER(apiServerOTConditionDetailPOST) +WRAPPER(jsonstat) +WRAPPER(prometheusMetrics) +WRAPPER(serveStuff) + +#undef WRAPPER +} diff -Nru pdns-recursor-5.2.13/rec-xfr.cc pdns-recursor-5.4.9/rec-xfr.cc --- pdns-recursor-5.2.13/rec-xfr.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-xfr.cc 2026-10-26 08:26:51.000000000 +0000 @@ -243,7 +243,7 @@ for (const auto& nameOrIp : d_params.primaries) { try { auto primary = pdns::fromNameOrIP(nameOrIp, 53, logger); - d_params.soaRecordContent = loadZoneFromServer(logger, primary, zoneName, newZone, d_params.tsigtriplet, d_params.maxReceivedMBytes, d_params.localAddress, d_params.xfrTimeout); + d_params.soaRecordContent = loadZoneFromServer(logger, primary, zoneName, newZone, d_params.tsigtriplet, d_params.maxReceivedMBytes * 1024U * 1024U, d_params.localAddress, d_params.xfrTimeout); newZone->setSerial(d_params.soaRecordContent->d_st.serial); newZone->setRefresh(d_params.soaRecordContent->d_st.refresh); refresh = std::max(d_params.refreshFromConf != 0 ? d_params.refreshFromConf : newZone->getRefresh(), 1U); @@ -335,7 +335,7 @@ } try { - deltas = getIXFRDeltas(primary, zoneName, soaRecord, d_params.xfrTimeout, true, d_params.tsigtriplet, &local, d_params.maxReceivedMBytes); + deltas = getIXFRDeltas(primary, zoneName, soaRecord, d_params.xfrTimeout, true, d_params.tsigtriplet, &local, d_params.maxReceivedMBytes * 1024U * 1024U); /* no need to try another primary */ break; diff -Nru pdns-recursor-5.2.13/rec-zonetocache.cc pdns-recursor-5.4.9/rec-zonetocache.cc --- pdns-recursor-5.2.13/rec-zonetocache.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec-zonetocache.cc 2026-10-26 08:26:51.000000000 +0000 @@ -102,18 +102,18 @@ case QType::NSEC3: break; case QType::RRSIG: { - const auto rrsig = getRR(dnsRecord); + auto rrsig = getRR(dnsRecord); if (rrsig == nullptr) { break; } const auto sigkey = pair(key.first, rrsig->d_type); auto found = d_sigs.find(sigkey); if (found != d_sigs.end()) { - found->second.push_back(rrsig); + found->second.push_back(std::move(rrsig)); } else { vector> sigsrr; - sigsrr.push_back(rrsig); + sigsrr.push_back(std::move(rrsig)); d_sigs.insert({sigkey, sigsrr}); } break; @@ -199,7 +199,7 @@ return lines; } -static std::vector getURL(const RecZoneToCache::Config& config) +static std::vector getURL([[maybe_unused]] const RecZoneToCache::Config& config) { std::vector lines; #ifdef HAVE_LIBCURL diff -Nru pdns-recursor-5.2.13/rec_channel.cc pdns-recursor-5.4.9/rec_channel.cc --- pdns-recursor-5.2.13/rec_channel.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec_channel.cc 2026-10-26 08:26:51.000000000 +0000 @@ -1,90 +1,117 @@ -#ifdef HAVE_CONFIG_H +/* + * 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" -#endif + #include "rec_channel.hh" -#include "utility.hh" + #include #include -#include "misc.hh" -#include #include #include #include #include -#include -#include - -#include "pdnsexception.hh" +#include "misc.hh" #include "namespaces.hh" +#include "pdnsexception.hh" +#include "sanitizer.hh" std::atomic RecursorControlChannel::stop = false; -RecursorControlChannel::RecursorControlChannel() +RecursorControlChannel::RecursorControlChannel() : + d_fd(-1) { - d_fd = -1; - *d_local.sun_path = 0; - d_local.sun_family = 0; + memset(&d_local, 0, sizeof(d_local)); } RecursorControlChannel::~RecursorControlChannel() { - if (d_fd > 0) + if (d_fd > 0) { close(d_fd); - if (*d_local.sun_path) - unlink(d_local.sun_path); + } + if (d_local.sun_path[0] != '\0') { + unlink(d_local.sun_path); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay) + } } -int RecursorControlChannel::listen(const string& fname) +int RecursorControlChannel::listen(const string& filename) { d_fd = socket(AF_UNIX, SOCK_STREAM, 0); - setCloseOnExec(d_fd); - if (d_fd < 0) + if (d_fd < 0) { throw PDNSException("Creating UNIX domain socket: " + stringerror()); + } + setCloseOnExec(d_fd); int tmp = 1; - if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) + if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp) < 0) { throw PDNSException("Setsockopt failed: " + stringerror()); + } - int err = unlink(fname.c_str()); - if (err < 0 && errno != ENOENT) - throw PDNSException("Can't remove (previous) controlsocket '" + fname + "': " + stringerror() + " (try --socket-dir)"); + int err = unlink(filename.c_str()); + if (err < 0 && errno != ENOENT) { + throw PDNSException("Can't remove (previous) controlsocket '" + filename + "': " + stringerror() + " (try --socket-dir)"); + } - if (makeUNsockaddr(fname, &d_local)) - throw PDNSException("Unable to bind to controlsocket, path '" + fname + "' is not a valid UNIX socket path."); + if (makeUNsockaddr(filename, &d_local) != 0) { + throw PDNSException("Unable to bind to controlsocket, path '" + filename + "' is not a valid UNIX socket path."); + } - if (bind(d_fd, (sockaddr*)&d_local, sizeof(d_local)) < 0) - throw PDNSException("Unable to bind to controlsocket '" + fname + "': " + stringerror()); + if (bind(d_fd, reinterpret_cast(&d_local), sizeof(d_local)) < 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + throw PDNSException("Unable to bind to controlsocket '" + filename + "': " + stringerror()); + } if (::listen(d_fd, 0) == -1) { - throw PDNSException("Unable to listen on controlsocket '" + fname + "': " + stringerror()); + throw PDNSException("Unable to listen on controlsocket '" + filename + "': " + stringerror()); } return d_fd; } -void RecursorControlChannel::connect(const string& path, const string& fname) +void RecursorControlChannel::connect(const string& path, const string& filename) { - struct sockaddr_un remote; + struct sockaddr_un remote{}; d_fd = socket(AF_UNIX, SOCK_STREAM, 0); setCloseOnExec(d_fd); - if (d_fd < 0) + if (d_fd < 0) { throw PDNSException("Creating UNIX domain socket: " + stringerror()); - + } try { int tmp = 1; - if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, sizeof tmp) < 0) + if (setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof tmp) < 0) { throw PDNSException("Setsockopt failed: " + stringerror()); + } - string remotename = path + "/" + fname; - if (makeUNsockaddr(remotename, &remote)) + string remotename = path + "/" + filename; + if (makeUNsockaddr(remotename, &remote) != 0) { throw PDNSException("Unable to connect to controlsocket, path '" + remotename + "' is not a valid UNIX socket path."); + } - if (::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) { - if (*d_local.sun_path) - unlink(d_local.sun_path); - throw PDNSException("Unable to connect to remote '" + string(remote.sun_path) + "': " + stringerror()); + if (::connect(d_fd, reinterpret_cast(&remote), sizeof(remote)) < 0) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + if (d_local.sun_path[0] != '\0') { + unlink(d_local.sun_path); // NOLINT + } + throw PDNSException("Unable to connect to remote '" + remotename + "': " + stringerror()); } } catch (...) { @@ -95,72 +122,72 @@ } } -static void sendfd(int s, int fd) +static void sendfd(int socket, int fd_to_pass) { - struct msghdr msg; - struct cmsghdr* cmsg; + struct msghdr msg{}; + struct cmsghdr* cmsg{}; union { struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(int))]; - } cmsgbuf; - struct iovec io_vector[1]; - char ch = 'X'; + std::array buf; + } cmsgbuf{}; + std::array io_vector{}; + char character = 'X'; - io_vector[0].iov_base = &ch; + io_vector[0].iov_base = &character; io_vector[0].iov_len = 1; memset(&msg, 0, sizeof(msg)); - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - msg.msg_iov = io_vector; - msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf.buf.data(); + msg.msg_controllen = cmsgbuf.buf.size(); + msg.msg_iov = io_vector.data(); + msg.msg_iovlen = io_vector.size(); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - *(int*)CMSG_DATA(cmsg) = fd; + *reinterpret_cast(CMSG_DATA(cmsg)) = fd_to_pass; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - if (sendmsg(s, &msg, 0) == -1) { + if (sendmsg(socket, &msg, 0) == -1) { throw PDNSException("Unable to send fd message over control channel: " + stringerror()); } } -void RecursorControlChannel::send(int fd, const Answer& msg, unsigned int timeout, int fd_to_pass) +void RecursorControlChannel::send(int fileDesc, const Answer& msg, unsigned int timeout, int fd_to_pass) { - int ret = waitForRWData(fd, false, timeout, 0); + int ret = waitForRWData(fileDesc, false, static_cast(timeout), 0); if (ret == 0) { throw PDNSException("Timeout sending message over control channel"); } - else if (ret < 0) { + if (ret < 0) { throw PDNSException("Error sending message over control channel:" + stringerror()); } - if (::send(fd, &msg.d_ret, sizeof(msg.d_ret), 0) < 0) { + if (::send(fileDesc, &msg.d_ret, sizeof(msg.d_ret), 0) < 0) { throw PDNSException("Unable to send return code over control channel: " + stringerror()); } size_t len = msg.d_str.length(); - if (::send(fd, &len, sizeof(len), 0) < 0) { + if (::send(fileDesc, &len, sizeof(len), 0) < 0) { throw PDNSException("Unable to send length over control channel: " + stringerror()); } - if (::send(fd, msg.d_str.c_str(), len, 0) != static_cast(len)) { + if (::send(fileDesc, msg.d_str.c_str(), len, 0) != static_cast(len)) { throw PDNSException("Unable to send message over control channel: " + stringerror()); } if (fd_to_pass != -1) { - sendfd(fd, fd_to_pass); + sendfd(fileDesc, fd_to_pass); } } -static void waitForRead(int fd, unsigned int timeout, time_t start) +static void waitForRead(int fileDesc, unsigned int timeout, time_t start) { time_t elapsed = time(nullptr) - start; if (elapsed >= timeout) { throw PDNSException("Timeout waiting for control channel data"); } // coverity[store_truncates_time_t] - int ret = waitForData(fd, timeout - elapsed, 0); + int ret = waitForData(fileDesc, static_cast(timeout - static_cast(elapsed)), 0); if (ret == 0) { throw PDNSException("Timeout waiting for control channel data"); } @@ -182,20 +209,27 @@ return 4096; } -RecursorControlChannel::Answer RecursorControlChannel::recv(int fd, unsigned int timeout) +RecursorControlChannel::Answer RecursorControlChannel::recv(int fileDesc, unsigned int timeout) { // timeout covers the operation of all read ops combined const time_t start = time(nullptr); - waitForRead(fd, timeout, start); - int err; - if (::recv(fd, &err, sizeof(err), 0) != sizeof(err)) { + waitForRead(fileDesc, timeout, start); + int err{}; + auto ret = ::recv(fileDesc, &err, sizeof(err), 0); + if (ret == 0) { +#if defined(__SANITIZE_THREAD__) + return {0, "bye nicely\n"}; // Hack because TSAN enabled build justs _exits on quit-nicely +#endif + throw PDNSException("Unable to receive status over control connection: EOF"); + } + if (ret != sizeof(err)) { throw PDNSException("Unable to receive return status over control channel: " + stringerror()); } - waitForRead(fd, timeout, start); - size_t len; - if (::recv(fd, &len, sizeof(len), 0) != sizeof(len)) { + waitForRead(fileDesc, timeout, start); + size_t len{}; + if (::recv(fileDesc, &len, sizeof(len), 0) != sizeof(len)) { throw PDNSException("Unable to receive length over control channel: " + stringerror()); } @@ -206,15 +240,15 @@ string str; str.reserve(len); while (str.length() < len) { - char buffer[1024]; - waitForRead(fd, timeout, start); - size_t toRead = std::min(len - str.length(), sizeof(buffer)); - ssize_t recvd = ::recv(fd, buffer, toRead, 0); + std::array buffer{}; + waitForRead(fileDesc, timeout, start); + size_t toRead = std::min(len - str.length(), buffer.size()); + ssize_t recvd = ::recv(fileDesc, buffer.data(), toRead, 0); if (recvd <= 0) { // EOF means we have a length error throw PDNSException("Unable to receive message over control channel: " + stringerror()); } - str.append(buffer, recvd); + str.append(buffer.data(), recvd); } return {err, std::move(str)}; diff -Nru pdns-recursor-5.2.13/rec_channel.hh pdns-recursor-5.4.9/rec_channel.hh --- pdns-recursor-5.2.13/rec_channel.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec_channel.hh 2026-10-26 08:26:51.000000000 +0000 @@ -26,13 +26,12 @@ #include #include #include -#include #include -#include #include #include "iputils.hh" #include "dnsname.hh" #include "sholder.hh" +#include "rec_metrics.hh" #include extern GlobalStateHolder g_dontThrottleNames; @@ -44,6 +43,10 @@ public: RecursorControlChannel(); + RecursorControlChannel(const RecursorControlChannel&) = delete; + RecursorControlChannel(RecursorControlChannel&&) = delete; + RecursorControlChannel& operator=(const RecursorControlChannel&) = delete; + RecursorControlChannel& operator=(RecursorControlChannel&&) = delete; ~RecursorControlChannel(); int listen(const std::string& filename); @@ -65,14 +68,19 @@ std::string d_str; }; - void send(int remote, const Answer&, unsigned int timeout = 5, int fd_to_pass = -1); - RecursorControlChannel::Answer recv(int fd, unsigned int timeout = 5); + static void send(int fileDesc, const Answer&, unsigned int timeout = 5, int fd_to_pass = -1); + static RecursorControlChannel::Answer recv(int fileDesc, unsigned int timeout = 5); - int d_fd; static std::atomic stop; + [[nodiscard]] int getDescriptor() const + { + return d_fd; + } + private: - struct sockaddr_un d_local; + int d_fd; + struct sockaddr_un d_local{}; }; class RecursorControlParser @@ -85,7 +93,7 @@ static RecursorControlChannel::Answer getAnswer(int socket, const std::string& question, func_t** command); }; -enum class StatComponent +enum class StatComponent : uint8_t { API, Carbon, @@ -97,18 +105,20 @@ { std::string d_prometheusName; std::string d_value; + std::optional d_prometheusType = std::nullopt; + std::optional d_prometheusDescr = std::nullopt; }; class PrefixDashNumberCompare { private: - static std::pair prefixAndTrailingNum(const std::string& a); + static std::pair prefixAndTrailingNum(const std::string& arg); public: - bool operator()(const std::string& a, const std::string& b) const; + bool operator()(const std::string& lhs, const std::string& rhs) const; }; -typedef std::map StatsMap; +using StatsMap = std::map; StatsMap getAllStatsMap(StatComponent component); @@ -131,7 +141,7 @@ std::vector* pleaseGetLargeAnswerRemotes(); std::vector* pleaseGetTimeouts(); DNSName getRegisteredName(const DNSName& dom); -std::atomic* getDynMetric(const std::string& str, const std::string& prometheusName); +std::atomic* getDynMetric(const std::string& str, const std::string& prometheusName, const std::string& prometheusTypeName, const std::string& prometheusDescr); std::optional getStatByName(const std::string& name); bool isStatDisabled(StatComponent component, const std::string& name); void disableStat(StatComponent component, const string& name); @@ -139,8 +149,8 @@ void registerAllStats(); -void doExitGeneric(bool nicely); -void doExit(); void doExitNicely(); RecursorControlChannel::Answer doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end); RecursorControlChannel::Answer luaconfig(bool broadcast); +struct OpenTelemetryTraceCondition; +void updateOTConditions(const NetmaskTree& conditions); diff -Nru pdns-recursor-5.2.13/rec_channel_rec.cc pdns-recursor-5.4.9/rec_channel_rec.cc --- pdns-recursor-5.2.13/rec_channel_rec.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec_channel_rec.cc 2026-10-26 08:26:51.000000000 +0000 @@ -1,6 +1,27 @@ -#ifdef HAVE_CONFIG_H +/* + * 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" -#endif + #include "utility.hh" #include "rec_channel.hh" @@ -14,6 +35,7 @@ #include "negcache.hh" #include #include +#include #include "version.hh" #include @@ -40,65 +62,53 @@ #include "rec-main.hh" #include "rec-system-resolve.hh" -#include "settings/cxxsettings.hh" - -/* 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 -#if __has_feature(address_sanitizer) -#define __SANITIZE_ADDRESS__ 1 -#endif -#endif +#include "rec-rust-lib/cxxsettings.hh" +#include "sanitizer.hh" #if defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE) #include #endif -std::pair PrefixDashNumberCompare::prefixAndTrailingNum(const std::string& a) +std::pair PrefixDashNumberCompare::prefixAndTrailingNum(const std::string& arg) { - auto i = a.length(); - if (i == 0) { - return {a, ""}; - } - --i; - if (!std::isdigit(a[i])) { - return {a, ""}; + auto length = arg.length(); + if (length == 0) { + return {arg, ""}; + } + --length; + if (std::isdigit(arg[length]) == 0) { + return {arg, ""}; } - while (i > 0) { - if (!std::isdigit(a[i])) { + while (length > 0) { + if (std::isdigit(arg[length]) == 0) { break; } - --i; + --length; } - return {a.substr(0, i + 1), a.substr(i + 1, a.size() - i - 1)}; + return {arg.substr(0, length + 1), arg.substr(length + 1, arg.size() - length - 1)}; } -bool PrefixDashNumberCompare::operator()(const std::string& a, const std::string& b) const +bool PrefixDashNumberCompare::operator()(const std::string& lhs, const std::string& rhs) const { - auto [aprefix, anum] = prefixAndTrailingNum(a); - auto [bprefix, bnum] = prefixAndTrailingNum(b); + auto [aprefix, anum] = prefixAndTrailingNum(lhs); + auto [bprefix, bnum] = prefixAndTrailingNum(rhs); if (aprefix != bprefix || anum.length() == 0 || bnum.length() == 0) { - return a < b; + return lhs < rhs; } - auto aa = std::stoull(anum); - auto bb = std::stoull(bnum); - return aa < bb; + return std::stoull(anum) < std::stoull(bnum); } -static map d_get32bitpointers; static map d_getatomics; static map> d_get64bitmembers; static map> d_getmultimembers; struct dynmetrics { - std::atomic* d_ptr; + std::unique_ptr> d_ptr; std::string d_prometheusName; + std::optional d_prometheusType; + std::optional d_prometheusDescr; }; static LockGuarded> d_dynmetrics; @@ -120,16 +130,8 @@ std::vector disabledStats; stringtok(disabledStats, stats, ", "); auto& map = s_disabledStats[component]; - for (const auto& st : disabledStats) { - map.insert(st); - } -} - -static void addGetStat(const string& name, const uint32_t* place) -{ - if (!d_get32bitpointers.emplace(name, place).second) { - cerr << "addGetStat: double def " << name << endl; - _exit(1); + for (const auto& stat : disabledStats) { + map.insert(stat); } } @@ -161,47 +163,56 @@ { std::string name = arg; std::replace_if( - name.begin(), name.end(), [](char c) { return !isalnum(static_cast(c)); }, '_'); + name.begin(), name.end(), [](char letter) { return isalnum(static_cast(letter)) == 0; }, '_'); return "pdns_recursor_" + name; } -std::atomic* getDynMetric(const std::string& str, const std::string& prometheusName) +std::atomic* getDynMetric(const std::string& str, const std::string& prometheusName, const std::string& prometheusTypeName, const std::string& prometheusDescr) { - auto dm = d_dynmetrics.lock(); - auto f = dm->find(str); - if (f != dm->end()) { - return f->second.d_ptr; + auto locked = d_dynmetrics.lock(); + auto iter = locked->find(str); + if (iter != locked->end()) { + return iter->second.d_ptr.get(); } - std::string name(str); - if (!prometheusName.empty()) { - name = prometheusName; + std::string name = prometheusName.empty() ? getPrometheusName(str) : prometheusName; + + std::optional metricType; + if (prometheusTypeName == "counter") { + metricType = PrometheusMetricType::counter; } - else { - name = getPrometheusName(name); + else if (prometheusTypeName == "gauge") { + metricType = PrometheusMetricType::gauge; + } + + std::optional descr; + if (!prometheusDescr.empty()) { + descr = prometheusDescr; } - auto ret = dynmetrics{new std::atomic(), std::move(name)}; - (*dm)[str] = ret; - return ret.d_ptr; + auto uptr = std::make_unique>(0); + auto* ptr = uptr.get(); + auto ret = dynmetrics{std::move(uptr), std::move(name), metricType, std::move(descr)}; + (*locked)[str] = std::move(ret); + return ptr; } static std::optional get(const string& name) { std::optional ret; - if (d_get32bitpointers.count(name)) - return *d_get32bitpointers.find(name)->second; - if (d_getatomics.count(name)) + if (d_getatomics.count(name) != 0) { return d_getatomics.find(name)->second->load(); - if (d_get64bitmembers.count(name)) + } + if (d_get64bitmembers.count(name) != 0) { return d_get64bitmembers.find(name)->second(); + } { - auto dm = d_dynmetrics.lock(); - auto f = rplookup(*dm, name); - if (f) { - return f->d_ptr->load(); + auto locked = d_dynmetrics.lock(); + const auto* ptr = rplookup(*locked, name); + if (ptr != nullptr) { + return ptr->d_ptr->load(); } } @@ -226,11 +237,6 @@ StatsMap ret; const auto& disabledlistMap = s_disabledStats.at(component); - for (const auto& the32bits : d_get32bitpointers) { - if (disabledlistMap.count(the32bits.first) == 0) { - ret.emplace(the32bits.first, StatsMapEntry{getPrometheusName(the32bits.first), std::to_string(*the32bits.second)}); - } - } for (const auto& atomic : d_getatomics) { if (disabledlistMap.count(atomic.first) == 0) { ret.emplace(atomic.first, StatsMapEntry{getPrometheusName(atomic.first), std::to_string(atomic.second->load())}); @@ -250,9 +256,9 @@ } { - for (const auto& a : *(d_dynmetrics.lock())) { - if (disabledlistMap.count(a.first) == 0) { - ret.emplace(a.first, StatsMapEntry{a.second.d_prometheusName, std::to_string(*a.second.d_ptr)}); + for (const auto& value : *(d_dynmetrics.lock())) { + if (disabledlistMap.count(value.first) == 0) { + ret.emplace(value.first, StatsMapEntry{value.second.d_prometheusName, std::to_string(*value.second.d_ptr), value.second.d_prometheusType, value.second.d_prometheusDescr}); } } } @@ -260,98 +266,167 @@ return ret; } -static string getAllStats() +using ArgIterator = vector::iterator; +using Answer = RecursorControlChannel::Answer; + +static Answer getAllStats(ArgIterator /* begin */, ArgIterator /* end */) { auto varmap = getAllStatsMap(StatComponent::RecControl); string ret; for (const auto& tup : varmap) { ret += tup.first + "\t" + tup.second.d_value + "\n"; } - return ret; + return {0, std::move(ret)}; } -template -static string doGet(T begin, T end) +static Answer doGet(ArgIterator begin, ArgIterator end) { string ret; - for (T i = begin; i != end; ++i) { + for (auto i = begin; i != end; ++i) { std::optional num = get(*i); - if (num) + if (num) { ret += std::to_string(*num) + "\n"; - else + } + else { ret += "UNKNOWN\n"; + } } - return ret; + return {0, std::move(ret)}; } -template -string static doGetParameter(T begin, T end) +static Answer doGetParameter(ArgIterator begin, ArgIterator end) { - string ret; - string parm; - using boost::replace_all; - for (T i = begin; i != end; ++i) { - if (::arg().parmIsset(*i)) { - parm = ::arg()[*i]; - replace_all(parm, "\\", "\\\\"); - replace_all(parm, "\"", "\\\""); - replace_all(parm, "\n", "\\n"); - ret += *i + "=\"" + parm + "\"\n"; + std::stringstream ret; + int err = 0; + + if (!g_yamlSettings) { + for (auto i = begin; i != end; ++i) { + if (::arg().parmIsset(*i)) { + const auto& parm = arg()[*i]; + ret << *i << '=' << parm << endl; + } + else { + ret << *i << " not known" << endl; + err = 1; + } } - else - ret += *i + " not known\n"; + return {err, ret.str()}; } - return ret; + + auto settings = g_yamlStruct.lock(); + + if (begin == end) { + auto yaml = settings->get_value({}, pdns::settings::rec::defaultsToYaml(false), true); + ret << std::string(yaml); + return {err, ret.str()}; + } + + for (auto i = begin; i != end; ++i) { + rust::Vec<::rust::String> field; + stringtok(field, *i, "."); + rust::Slice slice{field}; + try { + auto yaml = settings->get_value(slice, pdns::settings::rec::defaultsToYaml(false), true); + ret << std::string(yaml); + } + catch (const std::exception& stdex) { + ret << std::string(stdex.what()) << endl; + err = 1; + } + } + return {err, ret.str()}; +} + +static Answer doGetDefaultParameter(ArgIterator begin, ArgIterator end) +{ + std::stringstream ret; + int err = 0; + + if (!g_yamlSettings) { + for (auto i = begin; i != end; ++i) { + if (::arg().parmIsset(*i)) { + ret << *i << '=' << ::arg().getDefault(*i) << endl; + } + else { + ret << *i << " not known" << endl; + err = 1; + } + } + } + else { + auto settings = g_yamlStruct.lock(); + auto defaults = pdns::rust::settings::rec::parse_yaml_string(""); + if (begin == end) { + auto yaml = pdns::settings::rec::defaultsToYaml(false); + ret << std::string(std::move(yaml)); + } + else { + for (auto i = begin; i != end; ++i) { + rust::Vec<::rust::String> field; + stringtok(field, *i, "."); + rust::Slice slice{field}; + try { + auto yaml = defaults.get_value(slice, pdns::settings::rec::defaultsToYaml(false), false); + ret << std::string(yaml); + } + catch (const std::exception& stdex) { + ret << std::string(stdex.what()) << endl; + err = 1; + } + } + } + } + return {err, ret.str()}; } /* Read an (open) fd from the control channel */ static FDWrapper -getfd(int s) +getfd(int socket) { - int fd = -1; - struct msghdr msg; - struct cmsghdr* cmsg; + int fileDesc = -1; + struct msghdr msg{}; + struct cmsghdr* cmsg{}; union { struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(int))]; + std::array buf{}; } cmsgbuf; - struct iovec io_vector[1]; - char ch; + std::array io_vector{}; + char character = 0; - io_vector[0].iov_base = &ch; + io_vector[0].iov_base = &character; io_vector[0].iov_len = 1; memset(&msg, 0, sizeof(msg)); - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - msg.msg_iov = io_vector; - msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf.buf.data(); + msg.msg_controllen = cmsgbuf.buf.size(); + msg.msg_iov = io_vector.data(); + msg.msg_iovlen = io_vector.size(); - if (recvmsg(s, &msg, 0) == -1) { + if (recvmsg(socket, &msg, 0) == -1) { throw PDNSException("recvmsg"); } - if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) { + if ((msg.msg_flags & MSG_TRUNC) != 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { throw PDNSException("control message truncated"); } - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - fd = *(int*)CMSG_DATA(cmsg); + fileDesc = *reinterpret_cast(CMSG_DATA(cmsg)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) break; } } - return FDWrapper(fd); + return fileDesc; } -static uint64_t dumpAggressiveNSECCache(int fd) +static uint64_t dumpAggressiveNSECCache(int fileDesc) { if (!g_aggressiveNSECCache) { return 0; } - int newfd = dup(fd); + int newfd = dup(fileDesc); if (newfd == -1) { return 0; } @@ -361,50 +436,57 @@ } fprintf(filePtr.get(), "; aggressive NSEC cache dump follows\n;\n"); - struct timeval now; + struct timeval now{}; Utility::gettimeofday(&now, nullptr); return g_aggressiveNSECCache->dumpToFile(filePtr, now); } -static uint64_t* pleaseDumpEDNSMap(int fd) +// NOLINTBEGIN(cppcoreguidelines-owning-memory) +static uint64_t* pleaseDumpCookiesMap(int fileDesc) +{ + return new uint64_t(dumpCookies(fileDesc)); +} + +static uint64_t* pleaseDumpEDNSMap(int fileDesc) { - return new uint64_t(SyncRes::doEDNSDump(fd)); + return new uint64_t(SyncRes::doEDNSDump(fileDesc)); } -static uint64_t* pleaseDumpNSSpeeds(int fd) +static uint64_t* pleaseDumpNSSpeeds(int fileDesc) { - return new uint64_t(SyncRes::doDumpNSSpeeds(fd)); + return new uint64_t(SyncRes::doDumpNSSpeeds(fileDesc)); } -static uint64_t* pleaseDumpThrottleMap(int fd) +static uint64_t* pleaseDumpThrottleMap(int fileDesc) { - return new uint64_t(SyncRes::doDumpThrottleMap(fd)); + return new uint64_t(SyncRes::doDumpThrottleMap(fileDesc)); } -static uint64_t* pleaseDumpFailedServers(int fd) +static uint64_t* pleaseDumpFailedServers(int fileDesc) { - return new uint64_t(SyncRes::doDumpFailedServers(fd)); + return new uint64_t(SyncRes::doDumpFailedServers(fileDesc)); } -static uint64_t* pleaseDumpSavedParentNSSets(int fd) +static uint64_t* pleaseDumpSavedParentNSSets(int fileDesc) { - return new uint64_t(SyncRes::doDumpSavedParentNSSets(fd)); + return new uint64_t(SyncRes::doDumpSavedParentNSSets(fileDesc)); } -static uint64_t* pleaseDumpNonResolvingNS(int fd) +static uint64_t* pleaseDumpNonResolvingNS(int fileDesc) { - return new uint64_t(SyncRes::doDumpNonResolvingNS(fd)); + return new uint64_t(SyncRes::doDumpNonResolvingNS(fileDesc)); } -static uint64_t* pleaseDumpDoTProbeMap(int fd) +static uint64_t* pleaseDumpDoTProbeMap(int fileDesc) { - return new uint64_t(SyncRes::doDumpDoTProbeMap(fd)); + return new uint64_t(SyncRes::doDumpDoTProbeMap(fileDesc)); } +// NOLINTEND(cppcoreguidelines-owning-memory) // Generic dump to file command -static RecursorControlChannel::Answer doDumpToFile(int s, uint64_t* (*function)(int s), const string& name, bool threads = true) +static RecursorControlChannel::Answer doDumpToFile(int socket, uint64_t* (*function)(int), const string& name, bool threads = true) { - auto fdw = getfd(s); + auto fdw = getfd(socket); if (fdw < 0) { return {1, name + ": error opening dump file for writing: " + stringerror() + "\n"}; @@ -413,13 +495,13 @@ uint64_t total = 0; try { if (threads) { - int fd = fdw; - total = broadcastAccFunction([function, fd] { return function(fd); }); + int fileDesc = fdw; + total = broadcastAccFunction([function, fileDesc] { return function(fileDesc); }); } else { - auto ret = function(fdw); + auto* ret = function(fdw); total = *ret; - delete ret; + delete ret; // NOLINT(cppcoreguidelines-owning-memory) } } catch (std::exception& e) { @@ -433,8 +515,7 @@ } // Does not follow the generic dump to file pattern, has a more complex lambda -template -static RecursorControlChannel::Answer doDumpCache(int socket, T begin, T end) +static RecursorControlChannel::Answer doDumpCache(int socket, ArgIterator begin, ArgIterator end) { auto fdw = getfd(socket); @@ -481,27 +562,27 @@ } } catch (...) { + ; } return {0, "dumped " + std::to_string(total) + " records\n"}; } // Does not follow the generic dump to file pattern, has an argument -template -static RecursorControlChannel::Answer doDumpRPZ(int s, T begin, T end) +static RecursorControlChannel::Answer doDumpRPZ(int socket, ArgIterator begin, ArgIterator end) { - auto fdw = getfd(s); + auto fdw = getfd(socket); if (fdw < 0) { return {1, "Error opening dump file for writing: " + stringerror() + "\n"}; } - T i = begin; + auto iter = begin; - if (i == end) { + if (iter == end) { return {1, "No zone name specified\n"}; } - string zoneName = *i; + const string& zoneName = *iter; auto luaconf = g_luaconfs.getLocal(); const auto zone = luaconf->dfe.getZone(zoneName); @@ -520,11 +601,10 @@ return {0, "done\n"}; } -template -static string doWipeCache(T begin, T end, uint16_t qtype) +static Answer doWipeCache(ArgIterator begin, ArgIterator end, uint16_t qtype) { vector> toWipe; - for (T i = begin; i != end; ++i) { + for (auto i = begin; i != end; ++i) { DNSName canon; bool subtree = false; @@ -538,12 +618,14 @@ } } catch (std::exception& e) { - return "Error: " + std::string(e.what()) + ", nothing wiped\n"; + return {1, "Error: " + std::string(e.what()) + ", nothing wiped\n"}; } toWipe.emplace_back(canon, subtree); } - int count = 0, pcount = 0, countNeg = 0; + int count = 0; + int pcount = 0; + int countNeg = 0; for (const auto& wipe : toWipe) { try { auto res = wipeCaches(wipe.first, wipe.second, qtype); @@ -556,92 +638,115 @@ } } - return "wiped " + std::to_string(count) + " records, " + std::to_string(countNeg) + " negative records, " + std::to_string(pcount) + " packets\n"; + return {0, "wiped " + std::to_string(count) + " records, " + std::to_string(countNeg) + " negative records, " + std::to_string(pcount) + " packets\n"}; +} + +template +static void setBothYamlAndOldStyleInt(T& yamlSetting, U& oldstyle, const string& value) +{ + pdns::checked_stoi_into(oldstyle, value); + if (g_yamlSettings) { + yamlSetting = oldstyle; + } } -template -static string doSetCarbonServer(T begin, T end) +static Answer doSetCarbonServer(ArgIterator begin, ArgIterator end) { auto config = g_carbonConfig.getCopy(); if (begin == end) { config.servers.clear(); + if (g_yamlSettings) { + g_yamlStruct.lock()->carbon.server.clear(); + } g_carbonConfig.setState(std::move(config)); - return "cleared carbon-server setting\n"; + return {0, "cleared carbon-server setting\n"}; } string ret; stringtok(config.servers, *begin, ", "); + if (g_yamlSettings) { + g_yamlStruct.lock()->carbon.server.emplace_back(*begin); + } ret = "set carbon-server to '" + *begin + "'\n"; ++begin; if (begin != end) { config.hostname = *begin; + if (g_yamlSettings) { + g_yamlStruct.lock()->carbon.ourname = *begin; + } ret += "set carbon-ourname to '" + *begin + "'\n"; } else { g_carbonConfig.setState(std::move(config)); - return ret; + return {0, std::move(ret)}; } ++begin; if (begin != end) { config.namespace_name = *begin; + if (g_yamlSettings) { + g_yamlStruct.lock()->carbon.ns = *begin; + } ret += "set carbon-namespace to '" + *begin + "'\n"; } else { g_carbonConfig.setState(std::move(config)); - return ret; + return {0, std::move(ret)}; } ++begin; if (begin != end) { config.instance_name = *begin; + if (g_yamlSettings) { + g_yamlStruct.lock()->carbon.instance = *begin; + } ret += "set carbon-instance to '" + *begin + "'\n"; } g_carbonConfig.setState(std::move(config)); - return ret; + return {0, std::move(ret)}; } -template -static string doSetDnssecLogBogus(T begin, T end) +static Answer doSetDnssecLogBogus(ArgIterator begin, ArgIterator end) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration, not changing the Bogus logging setting\n"; - - if (begin == end) - return "No DNSSEC Bogus logging setting specified\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration, not changing the Bogus logging setting\n"}; + } + if (begin == end) { + return {1, "No DNSSEC Bogus logging setting specified\n"}; + } if (pdns_iequals(*begin, "on") || pdns_iequals(*begin, "yes")) { + auto lock = g_yamlStruct.lock(); if (!g_dnssecLogBogus) { g_log << Logger::Warning << "Enabling DNSSEC Bogus logging, requested via control channel" << endl; - g_dnssecLogBogus = true; - return "DNSSEC Bogus logging enabled\n"; + lock->dnssec.log_bogus = g_dnssecLogBogus = true; + return {0, "DNSSEC Bogus logging enabled\n"}; } - return "DNSSEC Bogus logging was already enabled\n"; + return {0, "DNSSEC Bogus logging was already enabled\n"}; } if (pdns_iequals(*begin, "off") || pdns_iequals(*begin, "no")) { + auto lock = g_yamlStruct.lock(); if (g_dnssecLogBogus) { g_log << Logger::Warning << "Disabling DNSSEC Bogus logging, requested via control channel" << endl; - g_dnssecLogBogus = false; - return "DNSSEC Bogus logging disabled\n"; + lock->dnssec.log_bogus = g_dnssecLogBogus = false; + return {0, "DNSSEC Bogus logging disabled\n"}; } - return "DNSSEC Bogus logging was already disabled\n"; + return {0, "DNSSEC Bogus logging was already disabled\n"}; } - return "Unknown DNSSEC Bogus setting: '" + *begin + "'\n"; + return {1, "Unknown DNSSEC Bogus setting: '" + *begin + "'\n"}; } -template -static string doAddNTA(T begin, T end) +static Answer doAddNTA(ArgIterator begin, ArgIterator end) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration, not adding a Negative Trust Anchor\n"; - - if (begin == end) - return "No NTA specified, doing nothing\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration, not adding a Negative Trust Anchor\n"}; + } + if (begin == end) { + return {1, "No NTA specified, doing nothing\n"}; + } DNSName who; try { who = DNSName(*begin); @@ -650,16 +755,17 @@ string ret("Can't add Negative Trust Anchor: "); ret += e.what(); ret += "\n"; - return ret; + return {1, std::move(ret)}; } begin++; - string why(""); + string why; while (begin != end) { why += *begin; begin++; - if (begin != end) + if (begin != end) { why += " "; + } } g_log << Logger::Warning << "Adding Negative Trust Anchor for " << who << " with reason '" << why << "', requested via control channel" << endl; g_luaconfs.modify([who, why](LuaConfigItems& lci) { @@ -670,33 +776,41 @@ } catch (std::exception& e) { g_log << Logger::Warning << ", failed: " << e.what() << endl; - return "Unable to clear caches while adding Negative Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"; + return {1, "Unable to clear caches while adding Negative Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"}; } - return "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n"; + return {0, "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n"}; } -template -static string doClearNTA(T begin, T end) +static Answer doClearNTA(ArgIterator begin, ArgIterator end) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration, not removing a Negative Trust Anchor\n"; - - if (begin == end) - return "No Negative Trust Anchor specified, doing nothing.\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration, not removing a Negative Trust Anchor\n"}; + } + if (begin == end) { + return {1, "No Negative Trust Anchor specified, doing nothing.\n"}; + } if (begin + 1 == end && *begin == "*") { g_log << Logger::Warning << "Clearing all Negative Trust Anchors, requested via control channel" << endl; - g_luaconfs.modify([](LuaConfigItems& lci) { + std::vector names; + g_luaconfs.modify([&names](LuaConfigItems& lci) { + names.reserve(lci.negAnchors.size()); + for (const auto& negAnchor : lci.negAnchors) { + names.emplace_back(negAnchor.first); + } lci.negAnchors.clear(); }); - return "Cleared all Negative Trust Anchors.\n"; + for (const auto& name : names) { + wipeCaches(name, true, 0xffff); + } + return {0, "Cleared all Negative Trust Anchors.\n"}; } vector toRemove; DNSName who; while (begin != end) { - if (*begin == "*") - return "Don't mix all Negative Trust Anchor removal with multiple Negative Trust Anchor removal. Nothing removed\n"; + if (*begin == "*") { + return {1, "Don't mix all Negative Trust Anchor removal with multiple Negative Trust Anchor removal. Nothing removed\n"}; + } try { who = DNSName(*begin); } @@ -704,13 +818,13 @@ string ret("Error: "); ret += e.what(); ret += ". No Negative Anchors removed\n"; - return ret; + return {1, std::move(ret)}; } toRemove.push_back(who); begin++; } - string removed(""); + string removed; bool first(true); try { for (auto const& entry : toRemove) { @@ -728,33 +842,33 @@ } catch (std::exception& e) { g_log << Logger::Warning << ", failed: " << e.what() << endl; - return "Unable to clear caches while clearing Negative Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"; + return {1, "Unable to clear caches while clearing Negative Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"}; } - return "Removed Negative Trust Anchors for " + removed + "\n"; + return {0, "Removed Negative Trust Anchors for " + removed + "\n"}; } -static string getNTAs() +static Answer getNTAs(ArgIterator /* begin */, ArgIterator /* end */) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration\n"}; + } string ret("Configured Negative Trust Anchors:\n"); auto luaconf = g_luaconfs.getLocal(); - for (const auto& negAnchor : luaconf->negAnchors) + for (const auto& negAnchor : luaconf->negAnchors) { ret += negAnchor.first.toLogString() + "\t" + negAnchor.second + "\n"; - return ret; + } + return {0, std::move(ret)}; } -template -static string doAddTA(T begin, T end) +static Answer doAddTA(ArgIterator begin, ArgIterator end) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration, not adding a Trust Anchor\n"; - - if (begin == end) - return "No TA specified, doing nothing\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration, not adding a Trust Anchor\n"}; + } + if (begin == end) { + return {1, "No TA specified, doing nothing\n"}; + } DNSName who; try { who = DNSName(*begin); @@ -763,11 +877,11 @@ string ret("Can't add Trust Anchor: "); ret += e.what(); ret += "\n"; - return ret; + return {1, std::move(ret)}; } begin++; - string what(""); + string what; while (begin != end) { what += *begin + " "; begin++; @@ -776,28 +890,27 @@ try { g_log << Logger::Warning << "Adding Trust Anchor for " << who << " with data '" << what << "', requested via control channel"; g_luaconfs.modify([who, what](LuaConfigItems& lci) { - auto ds = std::dynamic_pointer_cast(DSRecordContent::make(what)); - lci.dsAnchors[who].insert(*ds); + auto dsRecord = std::dynamic_pointer_cast(DSRecordContent::make(what)); + lci.dsAnchors[who].insert(*dsRecord); }); wipeCaches(who, true, 0xffff); g_log << Logger::Warning << endl; - return "Added Trust Anchor for " + who.toStringRootDot() + " with data " + what + "\n"; + return {0, "Added Trust Anchor for " + who.toStringRootDot() + " with data " + what + "\n"}; } catch (std::exception& e) { g_log << Logger::Warning << ", failed: " << e.what() << endl; - return "Unable to add Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"; + return {1, "Unable to add Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"}; } } -template -static string doClearTA(T begin, T end) +static Answer doClearTA(ArgIterator begin, ArgIterator end) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration, not removing a Trust Anchor\n"; - - if (begin == end) - return "No Trust Anchor to clear\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration, not removing a Trust Anchor\n"}; + } + if (begin == end) { + return {1, "No Trust Anchor to clear\n"}; + } vector toRemove; DNSName who; while (begin != end) { @@ -808,16 +921,17 @@ string ret("Error: "); ret += e.what(); ret += ". No Anchors removed\n"; - return ret; + return {1, std::move(ret)}; + } + if (who.isRoot()) { + return {1, "Refusing to remove root Trust Anchor, no Anchors removed\n"}; } - if (who.isRoot()) - return "Refusing to remove root Trust Anchor, no Anchors removed\n"; toRemove.push_back(who); begin++; } - string removed(""); - bool first(true); + string removed; + bool first = true; try { for (auto const& entry : toRemove) { g_log << Logger::Warning << "Removing Trust Anchor for " << entry << ", requested via control channel" << endl; @@ -834,91 +948,94 @@ } catch (std::exception& e) { g_log << Logger::Warning << ", failed: " << e.what() << endl; - return "Unable to clear caches while clearing Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"; + return {1, "Unable to clear caches while clearing Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n"}; } - return "Removed Trust Anchor(s) for" + removed + "\n"; + return {0, "Removed Trust Anchor(s) for" + removed + "\n"}; } -static string getTAs() +static Answer getTAs(ArgIterator /* begin */, ArgIterator /* end */) { - if (checkDNSSECDisabled()) - return "DNSSEC is disabled in the configuration\n"; - + if (checkDNSSECDisabled()) { + return {1, "DNSSEC is disabled in the configuration\n"}; + } string ret("Configured Trust Anchors:\n"); auto luaconf = g_luaconfs.getLocal(); for (const auto& anchor : luaconf->dsAnchors) { ret += anchor.first.toLogString() + "\n"; - for (const auto& e : anchor.second) { - ret += "\t\t" + e.getZoneRepresentation() + "\n"; + for (const auto& entry : anchor.second) { + ret += "\t\t" + entry.getZoneRepresentation() + "\n"; } } - return ret; + return {0, std::move(ret)}; } -template -static string setMinimumTTL(T begin, T end) +static Answer setMinimumTTL(ArgIterator begin, ArgIterator end) { - if (end - begin != 1) - return "Need to supply new minimum TTL number\n"; + if (end - begin != 1) { + return {1, "Need to supply new minimum TTL number\n"}; + } try { - pdns::checked_stoi_into(SyncRes::s_minimumTTL, *begin); - return "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n"; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->recursor.minimum_ttl_override, SyncRes::s_minimumTTL, *begin); + return {0, "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n"}; } catch (const std::exception& e) { - return "Error parsing the new minimum TTL number: " + std::string(e.what()) + "\n"; + return {1, "Error parsing the new minimum TTL number: " + std::string(e.what()) + "\n"}; } } -template -static string setMinimumECSTTL(T begin, T end) +static Answer setMinimumECSTTL(ArgIterator begin, ArgIterator end) { - if (end - begin != 1) - return "Need to supply new ECS minimum TTL number\n"; + if (end - begin != 1) { + return {1, "Need to supply new ECS minimum TTL number\n"}; + } try { - pdns::checked_stoi_into(SyncRes::s_minimumECSTTL, *begin); - return "New minimum ECS TTL: " + std::to_string(SyncRes::s_minimumECSTTL) + "\n"; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->ecs.minimum_ttl_override, SyncRes::s_minimumECSTTL, *begin); + return {0, "New minimum ECS TTL: " + std::to_string(SyncRes::s_minimumECSTTL) + "\n"}; } catch (const std::exception& e) { - return "Error parsing the new ECS minimum TTL number: " + std::string(e.what()) + "\n"; + return {1, "Error parsing the new ECS minimum TTL number: " + std::string(e.what()) + "\n"}; } } -template -static string setMaxCacheEntries(T begin, T end) +static Answer setMaxCacheEntries(ArgIterator begin, ArgIterator end) { - if (end - begin != 1) - return "Need to supply new cache size\n"; + if (end - begin != 1) { + return {1, "Need to supply new cache size\n"}; + } try { - g_maxCacheEntries = pdns::checked_stoi(*begin); - return "New max cache entries: " + std::to_string(g_maxCacheEntries) + "\n"; + uint32_t val{}; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->recordcache.max_entries, val, *begin); + g_maxCacheEntries = val; + return {0, "New max cache entries: " + std::to_string(g_maxCacheEntries) + "\n"}; } catch (const std::exception& e) { - return "Error parsing the new cache size: " + std::string(e.what()) + "\n"; + return {1, "Error parsing the new cache size: " + std::string(e.what()) + "\n"}; } } -template -static string setMaxPacketCacheEntries(T begin, T end) +static Answer setMaxPacketCacheEntries(ArgIterator begin, ArgIterator end) { - if (end - begin != 1) - return "Need to supply new packet cache size\n"; + if (end - begin != 1) { + return {0, "Need to supply new packet cache size\n"}; + } if (::arg().mustDo("disable-packetcache")) { - return "Packet cache is disabled\n"; + return {1, "Packet cache is disabled\n"}; } try { - g_maxPacketCacheEntries = pdns::checked_stoi(*begin); + uint32_t val{}; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->packetcache.max_entries, val, *begin); + g_maxPacketCacheEntries = val; g_packetCache->setMaxSize(g_maxPacketCacheEntries); - return "New max packetcache entries: " + std::to_string(g_maxPacketCacheEntries) + "\n"; + return {0, "New max packetcache entries: " + std::to_string(g_maxPacketCacheEntries) + "\n"}; } catch (const std::exception& e) { - return "Error parsing the new packet cache size: " + std::string(e.what()) + "\n"; + return {1, "Error parsing the new packet cache size: " + std::string(e.what()) + "\n"}; } } -template -static RecursorControlChannel::Answer setAggrNSECCacheSize(T begin, T end) +static RecursorControlChannel::Answer setAggrNSECCacheSize(ArgIterator begin, ArgIterator end) { if (end - begin != 1) { return {1, "Need to supply new aggressive NSEC cache size\n"}; @@ -927,7 +1044,8 @@ return {1, "Aggressive NSEC cache is disabled by startup config\n"}; } try { - auto newmax = pdns::checked_stoi(*begin); + uint64_t newmax{}; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->dnssec.aggressive_nsec_cache_size, newmax, *begin); g_aggressiveNSECCache->setMaxEntries(newmax); return {0, "New aggressive NSEC cache size: " + std::to_string(newmax) + "\n"}; } @@ -938,16 +1056,16 @@ static uint64_t getSysTimeMsec() { - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (ru.ru_stime.tv_sec * 1000ULL + ru.ru_stime.tv_usec / 1000); + struct rusage usage{}; + getrusage(RUSAGE_SELF, &usage); + return (usage.ru_stime.tv_sec * 1000ULL) + (usage.ru_stime.tv_usec / 1000); } static uint64_t getUserTimeMsec() { - struct rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (ru.ru_utime.tv_sec * 1000ULL + ru.ru_utime.tv_usec / 1000); + struct rusage usage{}; + getrusage(RUSAGE_SELF, &usage); + return (usage.ru_utime.tv_sec * 1000ULL) + (usage.ru_utime.tv_usec / 1000); } /* This is a pretty weird set of functions. To get per-thread cpu usage numbers, @@ -968,7 +1086,7 @@ ret = (ru.ru_utime.tv_sec * 1000ULL + ru.ru_utime.tv_usec / 1000); ret += (ru.ru_stime.tv_sec * 1000ULL + ru.ru_stime.tv_usec / 1000); #endif - return new ThreadTimes{ret, vector()}; + return new ThreadTimes{ret, vector()}; // NOLINT(cppcoreguidelines-owning-memory) } /* Next up, when you want msec data for a specific thread, we check @@ -977,24 +1095,24 @@ We then answer you from the (re)fresh(ed) ThreadTimes. */ -static uint64_t doGetThreadCPUMsec(int n) +static uint64_t doGetThreadCPUMsec(unsigned int n) { static std::mutex s_mut; static time_t last = 0; - static ThreadTimes tt; + static ThreadTimes threadTimes; - std::lock_guard l(s_mut); + auto lock = std::scoped_lock(s_mut); if (last != time(nullptr)) { - tt = broadcastAccFunction(pleaseGetThreadCPUMsec); + threadTimes = broadcastAccFunction(pleaseGetThreadCPUMsec); last = time(nullptr); } - return tt.times.at(n); + return threadTimes.times.at(n); } static ProxyMappingStats_t* pleaseGetProxyMappingStats() { - auto ret = new ProxyMappingStats_t; + auto* ret = new ProxyMappingStats_t; // NOLINT(cppcoreguidelines-owning-memory) if (t_proxyMapping) { for (const auto& [key, entry] : *t_proxyMapping) { ret->emplace(key, ProxyMappingCounts{entry.stats.netmaskMatches, entry.stats.suffixMatches}); @@ -1005,7 +1123,7 @@ static RemoteLoggerStats_t* pleaseGetRemoteLoggerStats() { - auto ret = make_unique(); + auto ret = make_unique(); // NOLINT(cppcoreguidelines-owning-memory) if (t_protobufServers.servers) { for (const auto& server : *t_protobufServers.servers) { @@ -1015,7 +1133,7 @@ return ret.release(); } -static string doGetProxyMappingStats() +static Answer doGetProxyMappingStats(ArgIterator /* begin */, ArgIterator /* end */) { ostringstream ret; ret << "subnet\t\t\tmatches\tsuffixmatches" << endl; @@ -1023,7 +1141,7 @@ for (const auto& [key, entry] : proxyMappingStats) { ret << key.toString() << '\t' << entry.netmaskMatches << '\t' << entry.suffixMatches << endl; } - return ret.str(); + return {0, ret.str()}; } static RemoteLoggerStats_t* pleaseGetOutgoingRemoteLoggerStats() @@ -1074,7 +1192,7 @@ } } -static string getRemoteLoggerStats() +static Answer getRemoteLoggerStats(ArgIterator /* begin */, ArgIterator /* end */) { ostringstream outputStream; outputStream << "Queued\tPipe-\tToo-\tOther-\tAddress\tType" << endl; @@ -1089,40 +1207,41 @@ stats = broadcastAccFunction(pleaseGetNODFramestreamLoggerStats); remoteLoggerStats("dnstapNODFrameStream", stats, outputStream); #endif - return outputStream.str(); + return {0, outputStream.str()}; } static string* pleaseGetCurrentQueries() { ostringstream ostr; - struct timeval now; - gettimeofday(&now, 0); + struct timeval now{}; + gettimeofday(&now, nullptr); ostr << getMT()->getWaiters().size() << " currently outstanding questions\n"; boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5% %|78t|%6%\n"); ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained" % "spent(ms)"); - unsigned int n = 0; + unsigned int count = 0; for (const auto& mthread : getMT()->getWaiters()) { const std::shared_ptr& pident = mthread.key; const double spent = g_networkTimeoutMsec - (DiffTime(now, mthread.ttd) * 1000); ostr << (fmt % pident->domain.toLogString() /* ?? */ % DNSRecordContent::NumberToType(pident->type) - % pident->remote.toString() % (pident->tcpsock ? 'Y' : 'n') + % pident->remote.toString() % ((pident->tcpsock != 0) ? 'Y' : 'n') % (pident->fd == -1 ? 'Y' : 'n') % (spent > 0 ? spent : '0')); - ++n; - if (n >= 100) + ++count; + if (count >= 100) { break; + } } ostr << " - done\n"; - return new string(ostr.str()); + return new string(ostr.str()); // NOLINT(cppcoreguidelines-owning-memory) } -static string doCurrentQueries() +static Answer doCurrentQueries(ArgIterator /* begin */, ArgIterator /* end */) { - return broadcastAccFunction(pleaseGetCurrentQueries); + return {0, broadcastAccFunction(pleaseGetCurrentQueries)}; } static uint64_t getNegCacheSize() @@ -1132,7 +1251,7 @@ uint64_t* pleaseGetConcurrentQueries() { - return new uint64_t(getMT() ? getMT()->numProcesses() : 0); + return new uint64_t((getMT() != nullptr) ? getMT()->numProcesses() : 0); // NOLINT(cppcoreguidelines-owning-memory) } static uint64_t getConcurrentQueries() @@ -1163,16 +1282,16 @@ const auto& data = histogram.getCumulativeBuckets(); const string pbasename = getPrometheusName(name); StatsMap entries; - char buf[32]; + std::array buf{}; for (const auto& bucket : data) { - snprintf(buf, sizeof(buf), "%g", bucket.d_boundary / 1e6); - std::string pname = pbasename + "seconds_bucket{" + "le=\"" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf) + "\"}"; + snprintf(buf.data(), buf.size(), "%g", static_cast(bucket.d_boundary) / 1e6); + std::string pname = pbasename + "seconds_bucket{" + "le=\"" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf.data()) + "\"}"; entries.emplace(bucket.d_name, StatsMapEntry{std::move(pname), std::to_string(bucket.d_count)}); } - snprintf(buf, sizeof(buf), "%g", histogram.getSum() / 1e6); - entries.emplace(name + "sum", StatsMapEntry{pbasename + "seconds_sum", buf}); + snprintf(buf.data(), buf.size(), "%g", static_cast(histogram.getSum()) / 1e6); + entries.emplace(name + "sum", StatsMapEntry{pbasename + "seconds_sum", buf.data()}); entries.emplace(name + "count", StatsMapEntry{pbasename + "seconds_count", std::to_string(data.back().d_count)}); return entries; @@ -1182,27 +1301,27 @@ { const string pbasename = getPrometheusName(name); StatsMap entries; - char buf[32]; + std::array buf{}; std::string pname; const auto& data4 = histogram4.getCumulativeBuckets(); for (const auto& bucket : data4) { - snprintf(buf, sizeof(buf), "%g", bucket.d_boundary / 1e6); - pname = pbasename + "seconds_bucket{ipversion=\"v4\",le=\"" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf) + "\"}"; + snprintf(buf.data(), buf.size(), "%g", static_cast(bucket.d_boundary) / 1e6); + pname = pbasename + R"(seconds_bucket{ipversion="v4",le=")" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf.data()) + "\"}"; entries.emplace(bucket.d_name + "4", StatsMapEntry{pname, std::to_string(bucket.d_count)}); } - snprintf(buf, sizeof(buf), "%g", histogram4.getSum() / 1e6); - entries.emplace(name + "sum4", StatsMapEntry{pbasename + "seconds_sum{ipversion=\"v4\"}", buf}); + snprintf(buf.data(), buf.size(), "%g", static_cast(histogram4.getSum()) / 1e6); + entries.emplace(name + "sum4", StatsMapEntry{pbasename + "seconds_sum{ipversion=\"v4\"}", buf.data()}); entries.emplace(name + "count4", StatsMapEntry{pbasename + "seconds_count{ipversion=\"v4\"}", std::to_string(data4.back().d_count)}); const auto& data6 = histogram6.getCumulativeBuckets(); for (const auto& bucket : data6) { - snprintf(buf, sizeof(buf), "%g", bucket.d_boundary / 1e6); - pname = pbasename + "seconds_bucket{ipversion=\"v6\",le=\"" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf) + "\"}"; + snprintf(buf.data(), buf.size(), "%g", static_cast(bucket.d_boundary) / 1e6); + pname = pbasename + R"(seconds_bucket{ipversion="v6",le=")" + (bucket.d_boundary == std::numeric_limits::max() ? "+Inf" : buf.data()) + "\"}"; entries.emplace(bucket.d_name + "6", StatsMapEntry{pname, std::to_string(bucket.d_count)}); } - snprintf(buf, sizeof(buf), "%g", histogram6.getSum() / 1e6); - entries.emplace(name + "sum6", StatsMapEntry{pbasename + "seconds_sum{ipversion=\"v6\"}", buf}); + snprintf(buf.data(), buf.size(), "%g", static_cast(histogram6.getSum()) / 1e6); + entries.emplace(name + "sum6", StatsMapEntry{pbasename + "seconds_sum{ipversion=\"v6\"}", buf.data()}); entries.emplace(name + "count6", StatsMapEntry{pbasename + "seconds_count{ipversion=\"v6\"}", std::to_string(data6.back().d_count)}); return entries; @@ -1213,13 +1332,14 @@ const string pbasename = getPrometheusName(name); StatsMap entries; - uint8_t n = 0; + uint8_t count = 0; auto rcodes = g_Counters.sum(rec::RCode::auth).rcodeCounters; for (const auto& entry : rcodes) { - const auto key = RCode::to_short_s(n); - std::string pname = pbasename + "{rcode=\"" + key + "\"}"; + const auto key = RCode::to_short_s(count); + std::string pname = pbasename; + pname += "{rcode=\"" + key + "\"}"; entries.emplace("auth-" + key + "-answers", StatsMapEntry{std::move(pname), std::to_string(entry)}); - n++; + count++; } return entries; } @@ -1230,10 +1350,10 @@ StatsMap entries; // Handler is not reported - for (unsigned int n = 0; n < RecThreadInfo::numRecursorThreads() - 1; ++n) { - uint64_t tm = doGetThreadCPUMsec(n); - std::string pname = pbasename + "{thread=\"" + std::to_string(n) + "\"}"; - entries.emplace(name + "-thread-" + std::to_string(n), StatsMapEntry{std::move(pname), std::to_string(tm)}); + for (unsigned int thread = 0; thread < RecThreadInfo::numRecursorThreads() - 1; ++thread) { + uint64_t timeTaken = doGetThreadCPUMsec(thread); + std::string pname = pbasename + "{thread=\"" + std::to_string(thread) + "\"}"; + entries.emplace(name + "-thread-" + std::to_string(thread), StatsMapEntry{std::move(pname), std::to_string(timeTaken)}); } return entries; } @@ -1247,14 +1367,17 @@ for (const auto& entry : map) { const auto& key = entry.first; auto count = entry.second; - std::string sname, pname; + std::string sname; + std::string pname; if (key.empty()) { sname = name + "-filter"; pname = pbasename + "{type=\"filter\"}"; } else { - sname = name + "-rpz-" + key; - pname = pbasename + "{type=\"rpz\",policyname=\"" + key + "\"}"; + sname = name; + sname += "-rpz-" + key; + pname = pbasename; + pname += R"({type="rpz",policyname=")" + key + "\"}"; } entries.emplace(sname, StatsMapEntry{std::move(pname), std::to_string(count)}); total += count; @@ -1302,7 +1425,9 @@ uint64_t count = 0; for (const auto& [stats, type] : list) { for (const auto& [key, entry] : stats) { - auto keyname = pbasename + "{address=\"" + key + "\",type=\"" + type + "\",count=\""; + auto keyname = pbasename; + keyname += "{address=\"" + key + "\",type=\""; + keyname += type + "\",count=\""; auto sname1 = name + "-q-" + std::to_string(count); auto pname1 = keyname + "queued\"}"; entries.emplace(sname1, StatsMapEntry{std::move(pname1), std::to_string(entry.d_queued)}); @@ -1362,24 +1487,24 @@ } catch (...) { g_log << Logger::Critical << "Could not add stat entries" << endl; - exit(1); + exit(1); // NOLINT(concurrency-mt-unsafe) } } -static auto clearLuaScript() +static auto clearLuaScript(ArgIterator /* begin */, ArgIterator /* end */) { vector empty; empty.emplace_back(); return doQueueReloadLuaScript(empty.begin(), empty.end()); } -void doExitGeneric(bool nicely) +// This code SHOUD *NOT* BE CALLED BY SIGNAL HANDLERS anymore +static void doExitGeneric(bool nicely) { #if defined(__SANITIZE_THREAD__) _exit(0); // regression test check for exit 0 #endif - g_log << Logger::Error << "Exiting on user request" << endl; - g_rcc.~RecursorControlChannel(); + g_slog->withName("runtime")->info(Logr::Notice, "Exiting on user request", "nicely", Logging::Loggable(nicely)); if (!g_pidfname.empty()) { unlink(g_pidfname.c_str()); // we can at least try.. @@ -1387,10 +1512,18 @@ if (nicely) { RecursorControlChannel::stop = true; + { + std::unique_lock lock(g_doneRunning.mutex); + g_doneRunning.condVar.wait(lock, [] { return g_doneRunning.done.load(); }); + } + // g_rcc.~RecursorControlChannel() do not call, caller still needs it! + // Caller will continue doing the orderly shutdown } else { + // rec_control quit case. Is that still used by test code? bulktests and regression test use quit-nicely + g_rcc.~RecursorControlChannel(); #if defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE) - clearLuaScript(); + clearLuaScript(ArgIterator{}, ArgIterator{}); pdns::coverage::dumpCoverageData(); __lsan_do_leak_check(); _exit(0); // let the regression test distinguish between leaks and no leaks as __lsan_do_leak_check() exits 1 on leaks @@ -1401,7 +1534,7 @@ } } -void doExit() +static void doExit() { doExitGeneric(false); } @@ -1411,114 +1544,123 @@ doExitGeneric(true); } +// NOLINTBEGIN(cppcoreguidelines-owning-memory) vector>* pleaseGetQueryRing() { - typedef pair query_t; - vector* ret = new vector(); - if (!t_queryring) + using query_t = pair; + auto* ret = new vector(); + if (!t_queryring) { return ret; + } ret->reserve(t_queryring->size()); - for (const query_t& q : *t_queryring) { - ret->push_back(q); + for (const query_t& query : *t_queryring) { + ret->emplace_back(query); } return ret; } vector>* pleaseGetServfailQueryRing() { - typedef pair query_t; - vector* ret = new vector(); - if (!t_servfailqueryring) + using query_t = pair; + auto* ret = new vector(); + if (!t_servfailqueryring) { return ret; + } ret->reserve(t_servfailqueryring->size()); - for (const query_t& q : *t_servfailqueryring) { - ret->push_back(q); + for (const query_t& query : *t_servfailqueryring) { + ret->emplace_back(query); } return ret; } vector>* pleaseGetBogusQueryRing() { - typedef pair query_t; - vector* ret = new vector(); - if (!t_bogusqueryring) + using query_t = pair; + auto* ret = new vector(); + if (!t_bogusqueryring) { return ret; + } ret->reserve(t_bogusqueryring->size()); - for (const query_t& q : *t_bogusqueryring) { - ret->push_back(q); + for (const query_t& query : *t_bogusqueryring) { + ret->emplace_back(query); } return ret; } -typedef std::function*()> pleaseremotefunc_t; -typedef std::function>*()> pleasequeryfunc_t; +using pleaseremotefunc_t = std::function*()>; +using pleasequeryfunc_t = std::function>*()>; vector* pleaseGetRemotes() { - vector* ret = new vector(); - if (!t_remotes) + auto* ret = new vector(); + if (!t_remotes) { return ret; - + } ret->reserve(t_remotes->size()); - for (const ComboAddress& ca : *t_remotes) { - ret->push_back(ca); + for (const ComboAddress& address : *t_remotes) { + ret->emplace_back(address); } return ret; } vector* pleaseGetServfailRemotes() { - vector* ret = new vector(); - if (!t_servfailremotes) + auto* ret = new vector(); + if (!t_servfailremotes) { return ret; + } ret->reserve(t_servfailremotes->size()); - for (const ComboAddress& ca : *t_servfailremotes) { - ret->push_back(ca); + for (const ComboAddress& address : *t_servfailremotes) { + ret->push_back(address); } return ret; } vector* pleaseGetBogusRemotes() { - vector* ret = new vector(); - if (!t_bogusremotes) + auto* ret = new vector(); + if (!t_bogusremotes) { return ret; + } ret->reserve(t_bogusremotes->size()); - for (const ComboAddress& ca : *t_bogusremotes) { - ret->push_back(ca); + for (const ComboAddress& address : *t_bogusremotes) { + ret->emplace_back(address); } return ret; } vector* pleaseGetLargeAnswerRemotes() { - vector* ret = new vector(); - if (!t_largeanswerremotes) + auto* ret = new vector(); + if (!t_largeanswerremotes) { return ret; + } ret->reserve(t_largeanswerremotes->size()); - for (const ComboAddress& ca : *t_largeanswerremotes) { - ret->push_back(ca); + for (const ComboAddress& address : *t_largeanswerremotes) { + ret->emplace_back(address); } return ret; } vector* pleaseGetTimeouts() { - vector* ret = new vector(); - if (!t_timeouts) + auto* ret = new vector(); + if (!t_timeouts) { return ret; + } ret->reserve(t_timeouts->size()); - for (const ComboAddress& ca : *t_timeouts) { - ret->push_back(ca); + for (const ComboAddress& address : *t_timeouts) { + ret->emplace_back(address); } return ret; } +// NOLINTEND(cppcoreguidelines-owning-memory) -static string doGenericTopRemotes(const pleaseremotefunc_t& func) +static Answer doGenericTopRemotes(const pleaseremotefunc_t& func) { auto remotes = broadcastAccFunction>(func); const unsigned int total = remotes.size(); if (total == 0) { - return "No qualifying data available\n"; + return {0, "No qualifying data available\n"}; } std::map counts; @@ -1542,15 +1684,16 @@ } ret << '\n' << fmt % (100.0 * (total - accounted) / total) % "rest"; - return ret.str(); + return {0, ret.str()}; } // XXX DNSName Pain - this function should benefit from native DNSName methods DNSName getRegisteredName(const DNSName& dom) { auto parts = dom.getRawLabels(); - if (parts.size() <= 2) + if (parts.size() <= 2) { return dom; + } reverse(parts.begin(), parts.end()); for (string& str : parts) { str = toLower(str); @@ -1561,12 +1704,12 @@ while (!parts.empty()) { if (parts.size() == 1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) { - string ret = last; - if (!ret.empty()) + string ret = std::move(last); + if (!ret.empty()) { ret += "."; - - for (auto p = parts.crbegin(); p != parts.crend(); ++p) { - ret += (*p) + "."; + } + for (auto part = parts.crbegin(); part != parts.crend(); ++part) { + ret += (*part) + "."; } return DNSName(ret); } @@ -1582,13 +1725,13 @@ return name; } -static string doGenericTopQueries(const pleasequeryfunc_t& func, const std::function& filter = nopFilter) +static Answer doGenericTopQueries(const pleasequeryfunc_t& func, const std::function& filter = nopFilter) { using query_t = pair; auto queries = broadcastAccFunction>(func); const unsigned int total = queries.size(); if (total == 0) { - return "No qualifying data available\n"; + return {0, "No qualifying data available\n"}; } map counts; @@ -1613,40 +1756,39 @@ ret << '\n' << fmt % (100.0 * (total - accounted) / total) % "rest"; - return ret.str(); + return {0, ret.str()}; } static string* nopFunction() { - return new string("pong " + RecThreadInfo::self().getName() + '\n'); + return new string("pong " + RecThreadInfo::self().getName() + '\n'); // NOLINT(cppcoreguidelines-owning-memory) } -static string getDontThrottleNames() +static Answer getDontThrottleNames(ArgIterator /* begin */, ArgIterator /* end */) { auto dtn = g_dontThrottleNames.getLocal(); - return dtn->toString() + "\n"; + return {0, dtn->toString() + "\n"}; } -static string getDontThrottleNetmasks() +static Answer getDontThrottleNetmasks(ArgIterator /* begin */, ArgIterator /* end */) { auto dtn = g_dontThrottleNetmasks.getLocal(); - return dtn->toString() + "\n"; + return {0, dtn->toString() + "\n"}; } -template -static string addDontThrottleNames(T begin, T end) +static Answer addDontThrottleNames(ArgIterator begin, ArgIterator end) { if (begin == end) { - return "No names specified, keeping existing list\n"; + return {1, "No names specified, keeping existing list\n"}; } vector toAdd; while (begin != end) { try { - auto d = DNSName(*begin); - toAdd.push_back(d); + auto name = DNSName(*begin); + toAdd.emplace_back(std::move(name)); } catch (const std::exception& e) { - return "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"; + return {1, "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"}; } begin++; } @@ -1654,39 +1796,38 @@ string ret = "Added"; auto dnt = g_dontThrottleNames.getCopy(); bool first = true; - for (auto const& d : toAdd) { + for (auto const& name : toAdd) { if (!first) { ret += ","; } first = false; - ret += " " + d.toLogString(); - dnt.add(d); + ret += " " + name.toLogString(); + dnt.add(name); } g_dontThrottleNames.setState(std::move(dnt)); ret += " to the list of nameservers that may not be throttled"; g_log << Logger::Info << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } -template -static string addDontThrottleNetmasks(T begin, T end) +static Answer addDontThrottleNetmasks(ArgIterator begin, ArgIterator end) { if (begin == end) { - return "No netmasks specified, keeping existing list\n"; + return {1, "No netmasks specified, keeping existing list\n"}; } vector toAdd; while (begin != end) { try { - auto n = Netmask(*begin); - toAdd.push_back(n); + auto netmask = Netmask(*begin); + toAdd.push_back(netmask); } catch (const std::exception& e) { - return "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"; + return {1, "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"}; } catch (const PDNSException& e) { - return "Problem parsing '" + *begin + "': " + e.reason + ", nothing added\n"; + return {1, "Problem parsing '" + *begin + "': " + e.reason + ", nothing added\n"}; } begin++; } @@ -1694,46 +1835,45 @@ string ret = "Added"; auto dnt = g_dontThrottleNetmasks.getCopy(); bool first = true; - for (auto const& t : toAdd) { + for (auto const& netmask : toAdd) { if (!first) { ret += ","; } first = false; - ret += " " + t.toString(); - dnt.addMask(t); + ret += " " + netmask.toString(); + dnt.addMask(netmask); } g_dontThrottleNetmasks.setState(std::move(dnt)); ret += " to the list of nameserver netmasks that may not be throttled"; g_log << Logger::Info << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } -template -static string clearDontThrottleNames(T begin, T end) +static Answer clearDontThrottleNames(ArgIterator begin, ArgIterator end) { - if (begin == end) - return "No names specified, doing nothing.\n"; - + if (begin == end) { + return {0, "No names specified, doing nothing.\n"}; + } if (begin + 1 == end && *begin == "*") { SuffixMatchNode smn; g_dontThrottleNames.setState(std::move(smn)); string ret = "Cleared list of nameserver names that may not be throttled"; g_log << Logger::Warning << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } vector toRemove; while (begin != end) { try { if (*begin == "*") { - return "Please don't mix '*' with other names, nothing removed\n"; + return {1, "Please don't mix '*' with other names, nothing removed\n"}; } - toRemove.push_back(DNSName(*begin)); + toRemove.emplace_back(*begin); } catch (const std::exception& e) { - return "Problem parsing '" + *begin + "': " + e.what() + ", nothing removed\n"; + return {1, "Problem parsing '" + *begin + "': " + e.what() + ", nothing removed\n"}; } begin++; } @@ -1754,15 +1894,14 @@ ret += " from the list of nameservers that may not be throttled"; g_log << Logger::Info << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } -template -static string clearDontThrottleNetmasks(T begin, T end) +static Answer clearDontThrottleNetmasks(ArgIterator begin, ArgIterator end) { - if (begin == end) - return "No netmasks specified, doing nothing.\n"; - + if (begin == end) { + return {1, "No netmasks specified, doing nothing.\n"}; + } if (begin + 1 == end && *begin == "*") { auto nmg = g_dontThrottleNetmasks.getCopy(); nmg.clear(); @@ -1770,23 +1909,23 @@ string ret = "Cleared list of nameserver addresses that may not be throttled"; g_log << Logger::Warning << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } std::vector toRemove; while (begin != end) { try { if (*begin == "*") { - return "Please don't mix '*' with other netmasks, nothing removed\n"; + return {1, "Please don't mix '*' with other netmasks, nothing removed\n"}; } - auto n = Netmask(*begin); - toRemove.push_back(n); + auto netmask = Netmask(*begin); + toRemove.push_back(netmask); } catch (const std::exception& e) { - return "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"; + return {1, "Problem parsing '" + *begin + "': " + e.what() + ", nothing added\n"}; } catch (const PDNSException& e) { - return "Problem parsing '" + *begin + "': " + e.reason + ", nothing added\n"; + return {1, "Problem parsing '" + *begin + "': " + e.reason + ", nothing added\n"}; } begin++; } @@ -1807,33 +1946,32 @@ ret += " from the list of nameservers that may not be throttled"; g_log << Logger::Info << ret << ", requested via control channel" << endl; - return ret + "\n"; + return {0, ret + "\n"}; } -template -static string setEventTracing(T begin, T end) +static Answer setEventTracing(ArgIterator begin, ArgIterator end) { if (begin == end) { - return "No event trace enabled value specified\n"; + return {1, "No event trace enabled value specified\n"}; } try { - pdns::checked_stoi_into(SyncRes::s_event_trace_enabled, *begin); - return "New event trace enabled value: " + std::to_string(SyncRes::s_event_trace_enabled) + "\n"; + setBothYamlAndOldStyleInt(g_yamlStruct.lock()->recursor.event_trace_enabled, SyncRes::s_event_trace_enabled, *begin); + return {0, "New event trace enabled value: " + std::to_string(SyncRes::s_event_trace_enabled) + "\n"}; } catch (const std::exception& e) { - return "Error parsing the new event trace enabled value: " + std::string(e.what()) + "\n"; + return {1, "Error parsing the new event trace enabled value: " + std::string(e.what()) + "\n"}; } } -static void* pleaseSupplantProxyMapping(const ProxyMapping& pm) +static void* pleaseSupplantProxyMapping(const ProxyMapping& proxyMapping) { - if (pm.empty()) { + if (proxyMapping.empty()) { t_proxyMapping = nullptr; } else { // Copy the existing stats values, for the new config items also present in the old auto newmapping = make_unique(); - for (const auto& [nm, entry] : pm) { + for (const auto& [nm, entry] : proxyMapping) { auto& newentry = newmapping->insert(nm); newentry.second = entry; if (t_proxyMapping) { @@ -1847,77 +1985,124 @@ return nullptr; } -static RecursorControlChannel::Answer help() +static void* pleaseSupplantOTConditions(const OpenTelemetryTraceConditions& conditions) +{ + if (conditions.empty()) { + t_OTConditions = nullptr; + } + else { + t_OTConditions = std::make_unique(conditions); + } + return nullptr; +} + +void updateOTConditions(const OpenTelemetryTraceConditions& conditions) +{ + // XXX YAML settings are not updated, so rec_control get-parameter won't show runtime updated conditions + broadcastFunction([conditions] { return pleaseSupplantOTConditions(conditions); }); +} + +static RecursorControlChannel::Answer help(ArgIterator /* begin */, ArgIterator /* end */) +{ + static const std::map commands = { + {"add-cookies-unsupported [IP...]", "Add non-expiring 'Unsupported' entry for IP to cookie table"}, + {"add-dont-throttle-names [N...]", "Add names that are not allowed to be throttled"}, + {"add-dont-throttle-netmasks [N...]", "Add netmasks that are not allowed to be throttled"}, + {"add-nta DOMAIN [REASON]", "Add a Negative Trust Anchor for DOMAIN with the comment REASON"}, + {"add-ta DOMAIN DSRECORD", "Add a Trust Anchor for DOMAIN with data DSRECORD"}, + {"current-queries", "Show currently active queries"}, + {"clear-cookies [IP...]", "Clear entries from cookie table, if IP is '*' remove all entries"}, + {"clear-dont-throttle-names [N...]", "Remove names that are not allowed to be throttled. If N is '*', remove all"}, + {"clear-dont-throttle-netmasks [N...]", "Remove netmasks that are not allowed to be throttled. If N is '*', remove all"}, + {"clear-nta [DOMAIN]...", "Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all"}, + {"clear-ta [DOMAIN]...", "Clear the Trust Anchor for DOMAINs"}, + {"dump-cache [type...]", "Dump cache contents to the named file, type is r, n, p or a"}, + {"dump-cookies ", "Dump the contents of the cookie jar to the named file"}, + {"dump-dot-probe-map ", "Dump the contents of the DoT probe map to the named file"}, + {"dump-edns [status] ", "Dump EDNS status to the named file"}, + {"dump-failedservers ", "Dump the failed servers to the named file"}, + {"dump-non-resolving ", "Dump non-resolving nameservers addresses to the named file"}, + {"dump-nsspeeds ", "Dump nsspeeds statistics to the named file"}, + {"dump-saved-parent-ns-sets ", "Dump saved parent ns sets that were successfully used as fallback"}, + {"dump-rpz ", "Dump the content of a RPZ zone to the named file"}, + {"dump-throttlemap ", "Dump the contents of the throttle map to the named file"}, + {"get [key1] [key2] ..", "Get specific statistics"}, + {"get-all", "Get all statistics"}, + {"get-dont-throttle-names", "Get the list of names that are not allowed to be throttled"}, + {"get-dont-throttle-netmasks", "Get the list of netmasks that are not allowed to be throttled"}, + {"get-ntas", "Get all configured Negative Trust Anchors"}, + {"get-tas", "Get all configured Trust Anchors"}, + {"get-parameter [key1] ..", "Get configuration parameters"}, + {"get-default-parameter [key1] ..", "Get default configuration parameters"}, + {"get-proxymapping-stats", "Get proxy mapping statistics"}, + {"get-qtypelist", "Get QType statistics. Note queries from cache aren't being counted yet"}, + {"get-remotelogger-stats", "Get remote logger statistics"}, + {"hash-password [work-factor]", "Ask for a password then return the hashed version"}, + {"help", "Get this list (from the running recursor)"}, + {"list-dnssec-algos", "List supported DNSSEC algorithms"}, + {"ping", "Check that all threads are alive"}, + {"quit", "Stop the recursor daemon"}, + {"quit-nicely or stop", "Stop the recursor daemon nicely"}, + {"reload-acls", "Reload ACLS"}, + {"reload-lua-script [filename]", "Reload Lua script"}, + {"reload-yaml", "Reload runtime settable parts of YAML settings"}, + {"reload-lua-config [filename]", "Reload Lua configuration file or equivalent YAML clauses"}, + {"reload-zones", "Reload all auth and forward zones"}, + {"set-ecs-minimum-ttl value", "Set ecs-minimum-ttl-override"}, + {"set-max-aggr-nsec-cache-size value", "Set new maximum aggressive NSEC cache size"}, + {"set-max-cache-entries value", "Set new maximum record cache size"}, + {"set-max-packetcache-entries value", "Set new maximum packet cache size"}, + {"set-minimum-ttl value", "Set minimum-ttl-override"}, + {"set-carbon-server", "Set a carbon server for telemetry"}, + {"set-dnssec-log-bogus SETTING", "Enable (yes) or disable (no) logging of DNSSEC validation failures"}, + {"set-event-trace-enabled SETTING", "Set logging of event traces, 0=disabled, 1=protobuf, 2=log file, 4=opentelemetry, combine by adding"}, + {"show-yaml [file]", "Show yaml config derived from old-style config"}, + {"trace-regex [regex file]", "Emit resolution trace for matching queries (no arguments clears tracing)"}, + {"top-largeanswer-remotes", "Show top remotes receiving large answers"}, + {"top-queries", "Show top queries"}, + {"top-pub-queries", "Show top queries grouped by public suffix list"}, + {"top-remotes", "Show top remotes"}, + {"top-timeouts", "Show top downstream timeouts"}, + {"top-servfail-queries", "Show top queries receiving servfail answers"}, + {"top-bogus-queries", "Show top queries validating as bogus"}, + {"top-pub-servfail-queries", "Show top queries receiving servfail answers grouped by public suffix list"}, + {"top-pub-bogus-queries", "Show top queries validating as bogus grouped by public suffix list"}, + {"top-servfail-remotes", "Show top remotes receiving servfail answers"}, + {"top-bogus-remotes", "Show top remotes receiving bogus answers"}, + {"unload-lua-script", "Unload Lua script"}, + {"version", "Return version number of running Recursor"}, + {"wipe-cache domain0 [domain1] ..", "Wipe domain data from cache"}, + {"wipe-cache-typed type domain0 [domain1] ..", "Wipe domain data with qtype from cache"}, + + }; + ostringstream str; + for (const auto& command : commands) { + str << command.first << endl; + str << std::setw(8) << ' ' << command.second << endl; + } + return {0, str.str()}; +} + +// The common part of activating the newly read config +static void activateLua(LuaConfigItems& lci, bool broadcast, ProxyMapping&& proxyMapping, OpenTelemetryTraceConditions&& conditions) { - return {0, - "add-dont-throttle-names [N...] add names that are not allowed to be throttled\n" - "add-dont-throttle-netmasks [N...]\n" - " add netmasks that are not allowed to be throttled\n" - "add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n" - "add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n" - "current-queries show currently active queries\n" - "clear-dont-throttle-names [N...] remove names that are not allowed to be throttled. If N is '*', remove all\n" - "clear-dont-throttle-netmasks [N...]\n" - " remove netmasks that are not allowed to be throttled. If N is '*', remove all\n" - "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n" - "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n" - "dump-cache [type...] dump cache contents to the named file, type is r, n, p or a\n" - "dump-dot-probe-map dump the contents of the DoT probe map to the named file\n" - "dump-edns [status] dump EDNS status to the named file\n" - "dump-failedservers dump the failed servers to the named file\n" - "dump-non-resolving dump non-resolving nameservers addresses to the named file\n" - "dump-nsspeeds dump nsspeeds statistics to the named file\n" - "dump-saved-parent-ns-sets \n" - " dump saved parent ns sets that were successfully used as fallback\n" - "dump-rpz dump the content of a RPZ zone to the named file\n" - "dump-throttlemap dump the contents of the throttle map to the named file\n" - "get [key1] [key2] .. get specific statistics\n" - "get-all get all statistics\n" - "get-dont-throttle-names get the list of names that are not allowed to be throttled\n" - "get-dont-throttle-netmasks get the list of netmasks that are not allowed to be throttled\n" - "get-ntas get all configured Negative Trust Anchors\n" - "get-tas get all configured Trust Anchors\n" - "get-parameter [key1] [key2] .. get configuration parameters\n" - "get-proxymapping-stats get proxy mapping statistics\n" - "get-qtypelist get QType statistics\n" - " notice: queries from cache aren't being counted yet\n" - "get-remotelogger-stats get remote logger statistics\n" - "hash-password [work-factor] ask for a password then return the hashed version\n" - "help get this list (from the running recursor)\n" - "list-dnssec-algos list supported DNSSEC algorithms\n" - "ping check that all threads are alive\n" - "quit stop the recursor daemon\n" - "quit-nicely stop the recursor daemon nicely\n" - "reload-acls reload ACLS\n" - "reload-lua-script [filename] (re)load Lua script\n" - "reload-yaml Reload runtime settable parts of YAML settings\n" - "reload-lua-config [filename] (re)load Lua configuration file or equivalent YAML clauses\n" - "reload-zones reload all auth and forward zones\n" - "set-ecs-minimum-ttl value set ecs-minimum-ttl-override\n" - "set-max-aggr-nsec-cache-size value set new maximum aggressive NSEC cache size\n" - "set-max-cache-entries value set new maximum record cache size\n" - "set-max-packetcache-entries val set new maximum packet cache size\n" - "set-minimum-ttl value set minimum-ttl-override\n" - "set-carbon-server set a carbon server for telemetry\n" - "set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n" - "set-event-trace-enabled SETTING set logging of event trace messages, 0 = disabled, 1 = protobuf, 2 = log file, 3 = both\n" - "show-yaml [file] show yaml config derived from old-style config\n" - "trace-regex [regex file] emit resolution trace for matching queries (no arguments clears tracing)\n" - "top-largeanswer-remotes show top remotes receiving large answers\n" - "top-queries show top queries\n" - "top-pub-queries show top queries grouped by public suffix list\n" - "top-remotes show top remotes\n" - "top-timeouts show top downstream timeouts\n" - "top-servfail-queries show top queries receiving servfail answers\n" - "top-bogus-queries show top queries validating as bogus\n" - "top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n" - "top-pub-bogus-queries show top queries validating as bogus grouped by public suffix list\n" - "top-servfail-remotes show top remotes receiving servfail answers\n" - "top-bogus-remotes show top remotes receiving bogus answers\n" - "unload-lua-script unload Lua script\n" - "version return version number of running Recursor\n" - "wipe-cache domain0 [domain1] .. wipe domain data from cache\n" - "wipe-cache-typed type domain0 [domain1] .. wipe domain data with qtype from cache\n"}; + extern std::unique_ptr g_proxyMapping; + + activateLuaConfig(lci); + lci = g_luaconfs.getCopy(); + if (broadcast) { + startLuaConfigDelayedThreads(lci, lci.generation); + broadcastFunction([pmap = std::move(proxyMapping)] { return pleaseSupplantProxyMapping(pmap); }); + broadcastFunction([conds = std::move(conditions)] { return pleaseSupplantOTConditions(conds); }); + } + else { + // Initial proxy mapping and OT conditions + g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); + *g_initialOpenTelemetryConditions.lock() = conditions.empty() ? nullptr : std::make_unique(conditions); + } + if (broadcast) { + g_slog->withName("config")->info(Logr::Info, "Reloaded"); + } } RecursorControlChannel::Answer luaconfig(bool broadcast) @@ -1925,28 +2110,42 @@ ProxyMapping proxyMapping; LuaConfigItems lci; lci.d_slog = g_slog; - extern std::unique_ptr g_proxyMapping; + pdns::rust::settings::rec::Recursorsettings settings; + OpenTelemetryTraceConditions conditions; + pdns::settings::rec::YamlSettingsStatus yamlstat = pdns::settings::rec::YamlSettingsStatus::CannotOpen; + + // If we have a YAML file read it to be able to use (parts of it) later + if (g_yamlSettings) { + string configname = ::arg()["config-dir"] + "/recursor"; + if (!::arg()["config-name"].empty()) { + configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"]; + } + bool dummy1{}; + bool dummy2{}; + yamlstat = pdns::settings::rec::tryReadYAML(configname + g_yamlSettingsSuffix, false, dummy1, dummy2, settings, g_slog, Logr::Error); + } + if (!g_luaSettingsInYAML) { + // We might have a lua config file, but also process dynamic YAML parts if applicable, currently those are: + // - the OT trace conditions + // - the outgoing TLS config try { - if (::arg()["lua-config-file"].empty()) { - return {0, "No Lua or corresponding YAML configuration active\n"}; + if (yamlstat == pdns::settings::rec::YamlSettingsStatus::OK) { + // YAML read above succeeded + ProxyMapping dummyProxyMapping; // taken from lua, so ignore YAML + LuaConfigItems dummyLuaConfig; // we do not use the converted from YAML LuaConfigItems, but the "real thing" + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, dummyLuaConfig, dummyProxyMapping, conditions); + TCPOutConnectionManager::setupOutgoingTLSConfigTables(settings); } - loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci); - activateLuaConfig(lci); - lci = g_luaconfs.getCopy(); - if (broadcast) { - startLuaConfigDelayedThreads(lci, lci.generation); - broadcastFunction([=] { return pleaseSupplantProxyMapping(proxyMapping); }); + if (!::arg()["lua-config-file"].empty()) { + loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci); // will bump generation } - else { - // Initial proxy mapping - g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); - } - if (broadcast) { - SLOG(g_log << Logger::Notice << "Reloaded Lua configuration file '" << ::arg()["lua-config-file"] << "', requested via control channel" << endl, - g_slog->withName("config")->info(Logr::Info, "Reloaded")); + activateLua(lci, broadcast, std::move(proxyMapping), std::move(conditions)); + string msg = "Reloaded dynamic parts of YAML configuration"; + if (!::arg()["lua-config-file"].empty()) { + msg += " and Lua configuration file '" + ::arg()["lua-config-file"] + "'"; } - return {0, "Reloaded Lua configuration file '" + ::arg()["lua-config-file"] + "'\n"}; + return {0, msg + "\n"}; } catch (std::exception& e) { return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.what() + "\n"}; @@ -1955,31 +2154,16 @@ return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.reason + "\n"}; } } + // More simple case: we don't have any Lua config try { - string configname = ::arg()["config-dir"] + "/recursor"; - if (!::arg()["config-name"].empty()) { - configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"]; - } - bool dummy1{}; - bool dummy2{}; - pdns::rust::settings::rec::Recursorsettings settings; - 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"}; + return {1, "Reloading dynamic part of YAML configuration failed\n"}; } auto generation = g_luaconfs.getLocal()->generation; lci.generation = generation + 1; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping); - activateLuaConfig(lci); - lci = g_luaconfs.getCopy(); - if (broadcast) { - startLuaConfigDelayedThreads(lci, lci.generation); - broadcastFunction([pmap = std::move(proxyMapping)] { return pleaseSupplantProxyMapping(pmap); }); - } - else { - // Initial proxy mapping - g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); - } + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping, conditions); + activateLua(lci, broadcast, std::move(proxyMapping), std::move(conditions)); + TCPOutConnectionManager::setupOutgoingTLSConfigTables(settings); return {0, "Reloaded dynamic part of YAML configuration\n"}; } @@ -1991,8 +2175,7 @@ } } -template -static RecursorControlChannel::Answer luaconfig(T begin, T end) +static RecursorControlChannel::Answer luaconfig1(ArgIterator begin, ArgIterator end) { if (begin != end) { if (g_luaSettingsInYAML) { @@ -2003,7 +2186,7 @@ return luaconfig(true); } -static RecursorControlChannel::Answer reloadACLs() +static RecursorControlChannel::Answer reloadACLs(ArgIterator /* begin */, ArgIterator /* end */) { if (!::arg()["chroot"].empty()) { g_log << Logger::Error << "Unable to reload ACL when chroot()'ed, requested via control channel" << endl; @@ -2034,7 +2217,7 @@ return ret; } -RecursorControlChannel::Answer RecursorControlParser::getAnswer(int socket, const string& question, RecursorControlParser::func_t** command) +RecursorControlChannel::Answer RecursorControlParser::getAnswer(int socket, const string& question, RecursorControlParser::func_t** command) // NOLINT(readability-function-cognitive-complexity) { *command = nop; vector words; @@ -2044,210 +2227,175 @@ return {1, "invalid command\n"}; } - string cmd = toLower(words[0]); - auto begin = words.begin() + 1; - auto end = words.end(); + string cmd = toLower(words.at(0)); - // should probably have a smart dispatcher here, like auth has - if (cmd == "help") { - return help(); - } - if (cmd == "get-all") { - return {0, getAllStats()}; - } - if (cmd == "get") { - return {0, doGet(begin, end)}; - } - if (cmd == "get-parameter") { - return {0, doGetParameter(begin, end)}; - } - if (cmd == "quit") { - *command = &doExit; - return {0, "bye\n"}; - } - if (cmd == "version") { - return {0, getPDNSVersion() + "\n"}; - } - if (cmd == "quit-nicely") { - *command = &doExitNicely; - return {0, "bye nicely\n"}; - } - if (cmd == "dump-cache") { - return doDumpCache(socket, begin, end); - } - if (cmd == "dump-dot-probe-map") { - return doDumpToFile(socket, pleaseDumpDoTProbeMap, cmd, false); - } - if (cmd == "dump-ednsstatus" || cmd == "dump-edns") { - return doDumpToFile(socket, pleaseDumpEDNSMap, cmd, false); - } - if (cmd == "dump-nsspeeds") { - return doDumpToFile(socket, pleaseDumpNSSpeeds, cmd, false); - } - if (cmd == "dump-failedservers") { - return doDumpToFile(socket, pleaseDumpFailedServers, cmd, false); - } - if (cmd == "dump-saved-parent-ns-sets") { - return doDumpToFile(socket, pleaseDumpSavedParentNSSets, cmd, false); - } - if (cmd == "dump-rpz") { - return doDumpRPZ(socket, begin, end); - } - if (cmd == "dump-throttlemap") { - return doDumpToFile(socket, pleaseDumpThrottleMap, cmd, false); - } - if (cmd == "dump-non-resolving") { - return doDumpToFile(socket, pleaseDumpNonResolvingNS, cmd, false); - } - if (cmd == "wipe-cache" || cmd == "flushname") { - return {0, doWipeCache(begin, end, 0xffff)}; - } - if (cmd == "wipe-cache-typed") { - if (begin == end) { - return {1, "Need a qtype\n"}; - } - uint16_t qtype = QType::chartocode(begin->c_str()); - if (qtype == 0) { - return {1, "Unknown qtype " + *begin + "\n"}; - } - ++begin; - return {0, doWipeCache(begin, end, qtype)}; - } - if (cmd == "reload-lua-script") { - return doQueueReloadLuaScript(begin, end); - } - if (cmd == "reload-lua-config") { - return luaconfig(begin, end); - } - if (cmd == "reload-yaml") { - return luaconfig(begin, end); - } - if (cmd == "set-carbon-server") { - return {0, doSetCarbonServer(begin, end)}; - } - if (cmd == "trace-regex") { - return {0, doTraceRegex(begin == end ? FDWrapper(-1) : getfd(socket), begin, end)}; - } - if (cmd == "unload-lua-script") { - return clearLuaScript(); - } - if (cmd == "reload-acls") { - return reloadACLs(); - } - if (cmd == "top-remotes") { - return {0, doGenericTopRemotes(pleaseGetRemotes)}; - } - if (cmd == "top-queries") { - return {0, doGenericTopQueries(pleaseGetQueryRing)}; - } - if (cmd == "top-pub-queries") { - return {0, doGenericTopQueries(pleaseGetQueryRing, getRegisteredName)}; - } - if (cmd == "top-servfail-queries") { - return {0, doGenericTopQueries(pleaseGetServfailQueryRing)}; - } - if (cmd == "top-pub-servfail-queries") { - return {0, doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName)}; - } - if (cmd == "top-bogus-queries") { - return {0, doGenericTopQueries(pleaseGetBogusQueryRing)}; - } - if (cmd == "top-pub-bogus-queries") { - return {0, doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName)}; - } - if (cmd == "top-servfail-remotes") { - return {0, doGenericTopRemotes(pleaseGetServfailRemotes)}; - } - if (cmd == "top-bogus-remotes") { - return {0, doGenericTopRemotes(pleaseGetBogusRemotes)}; - } - if (cmd == "top-largeanswer-remotes") { - return {0, doGenericTopRemotes(pleaseGetLargeAnswerRemotes)}; - } - if (cmd == "top-timeouts") { - return {0, doGenericTopRemotes(pleaseGetTimeouts)}; - } - if (cmd == "current-queries") { - return {0, doCurrentQueries()}; - } - if (cmd == "ping") { - return {0, broadcastAccFunction(nopFunction)}; - } - if (cmd == "reload-zones") { - if (!::arg()["chroot"].empty()) { - g_log << Logger::Error << "Unable to reload zones and forwards when chroot()'ed, requested via control channel" << endl; - return {1, "Unable to reload zones and forwards when chroot()'ed, please restart\n"}; - } - return {0, reloadZoneConfigurationWithSysResolveReset()}; - } - if (cmd == "set-ecs-minimum-ttl") { - return {0, setMinimumECSTTL(begin, end)}; - } - if (cmd == "set-max-cache-entries") { - return {0, setMaxCacheEntries(begin, end)}; - } - if (cmd == "set-max-packetcache-entries") { - return {0, setMaxPacketCacheEntries(begin, end)}; - } - if (cmd == "set-minimum-ttl") { - return {0, setMinimumTTL(begin, end)}; - } - if (cmd == "get-qtypelist") { - return {0, g_Counters.sum(rec::ResponseStats::responseStats).getQTypeReport()}; - } - if (cmd == "add-nta") { - return {0, doAddNTA(begin, end)}; - } - if (cmd == "clear-nta") { - return {0, doClearNTA(begin, end)}; - } - if (cmd == "get-ntas") { - return {0, getNTAs()}; - } - if (cmd == "add-ta") { - return {0, doAddTA(begin, end)}; - } - if (cmd == "clear-ta") { - return {0, doClearTA(begin, end)}; - } - if (cmd == "get-tas") { - return {0, getTAs()}; - } - if (cmd == "set-dnssec-log-bogus") { - return {0, doSetDnssecLogBogus(begin, end)}; - } - if (cmd == "get-dont-throttle-names") { - return {0, getDontThrottleNames()}; - } - if (cmd == "get-dont-throttle-netmasks") { - return {0, getDontThrottleNetmasks()}; - } - if (cmd == "add-dont-throttle-names") { - return {0, addDontThrottleNames(begin, end)}; - } - if (cmd == "add-dont-throttle-netmasks") { - return {0, addDontThrottleNetmasks(begin, end)}; - } - if (cmd == "clear-dont-throttle-names") { - return {0, clearDontThrottleNames(begin, end)}; - } - if (cmd == "clear-dont-throttle-netmasks") { - return {0, clearDontThrottleNetmasks(begin, end)}; - } - if (cmd == "set-event-trace-enabled") { - return {0, setEventTracing(begin, end)}; - } - if (cmd == "get-proxymapping-stats") { - return {0, doGetProxyMappingStats()}; - } - if (cmd == "get-remotelogger-stats") { - return {0, getRemoteLoggerStats()}; - } - if (cmd == "list-dnssec-algos") { - return {0, DNSCryptoKeyEngine::listSupportedAlgoNames()}; - } - if (cmd == "set-aggr-nsec-cache-size") { - return setAggrNSECCacheSize(begin, end); + // The standard command function signature is (ArgIterator, ArgIterator) -> Answer + // Answer is a pair of a status code and a message. + // If you need to + // specify a different signature, define a lambda, potentially capturing the socket and cmd by ref + + static const std::unordered_map> commands = { + {"help", help}, + {"get-all", getAllStats}, + {"get", doGet}, + {"get-parameter", doGetParameter}, + {"get-default-parameter", doGetDefaultParameter}, + {"quit", [&](ArgIterator, ArgIterator) -> Answer { *command = doExit; return {0, "bye\n"}; }}, + {"version", [&](ArgIterator, ArgIterator) -> Answer { return {0, getPDNSVersion() + "\n"}; }}, + {"quit-nicely", [&](ArgIterator, ArgIterator) -> Answer { *command = doExitNicely; return {0, "bye nicely\n"}; }}, + {"stop", [&](ArgIterator, ArgIterator) -> Answer { *command = doExitNicely; return {0, "bye nicely\n"}; }}, + {"dump-cache", [&](ArgIterator begin, ArgIterator end) { + return doDumpCache(socket, begin, end); + }}, + {"clear-cookies", [](ArgIterator begin, ArgIterator end) -> Answer { + string errors; + auto count = clearCookies(begin, end, errors); + if (errors.empty()) { + return {0, "Cleared " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " from cookies table\n"}; + } + return {1, "Cleared " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " from cookies table, errors: " + errors + "\n"}; + }}, + {"add-cookies-unsupported", [](ArgIterator begin, ArgIterator end) -> Answer { + string errors; + auto count = addCookiesUnsupported(begin, end, errors); + if (errors.empty()) { + return {0, "Added " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " to cookies table\n"}; + } + return {1, "Added " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " to cookies table, errors: " + errors + "\n"}; + }}, + {"dump-cookies", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpCookiesMap, cmd, false); + }}, + {"dump-dot-probe-map", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpDoTProbeMap, cmd, false); + }}, + {"dump-ednsstatus", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpEDNSMap, cmd, false); + }}, + {"dump-edns", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpEDNSMap, cmd, false); + }}, + {"dump-nsspeeds", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpNSSpeeds, cmd, false); + }}, + {"dump-failedservers", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpFailedServers, cmd, false); + }}, + {"dump-saved-parent-ns-sets", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpSavedParentNSSets, cmd, false); + }}, + {"dump-rpz", [&](ArgIterator begin, ArgIterator end) -> Answer { + return doDumpRPZ(socket, begin, end); + }}, + {"dump-throttlemap", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpThrottleMap, cmd, false); + }}, + {"dump-non-resolving", [&](ArgIterator, ArgIterator) -> Answer { + return doDumpToFile(socket, pleaseDumpNonResolvingNS, cmd, false); + }}, + {"wipe-cache", [](ArgIterator begin, ArgIterator end) -> Answer { + return doWipeCache(begin, end, 0xffff); + }}, + {"flushname", [](ArgIterator begin, ArgIterator end) -> Answer { + return doWipeCache(begin, end, 0xffff); + }}, + {"wipe-cache-typed", [](ArgIterator begin, ArgIterator end) -> Answer { + if (begin == end) { + return {1, "Need a qtype\n"}; + } + uint16_t qtype = QType::chartocode(begin->c_str()); + if (qtype == 0) { + return {1, "Unknown qtype " + *begin + "\n"}; + } + ++begin; + return doWipeCache(begin, end, qtype); + }}, + {"reload-lua-script", doQueueReloadLuaScript}, + {"reload-lua-config", luaconfig1}, + {"reload-yaml", luaconfig1}, + {"set-carbon-server", doSetCarbonServer}, + {"trace-regex", [&](ArgIterator begin, ArgIterator end) -> Answer { + return {0, doTraceRegex(begin == end ? FDWrapper(-1) : getfd(socket), begin, end)}; + }}, + {"unload-lua-script", clearLuaScript}, + {"reload-acls", reloadACLs}, + {"top-remotes", [](ArgIterator, ArgIterator) -> Answer { + return doGenericTopRemotes(pleaseGetRemotes); + }}, + {"top-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetQueryRing); + }}, + {"top-pub-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetQueryRing, getRegisteredName); + }}, + {"top-servfail-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetServfailQueryRing); + }}, + {"top-pub-servfail-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName); + }}, + {"top-bogus-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetBogusQueryRing); + }}, + {"top-pub-bogus-queries", [](ArgIterator, ArgIterator) { + return doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName); + }}, + {"top-servfail-remotes", [](ArgIterator, ArgIterator) { + return doGenericTopRemotes(pleaseGetServfailRemotes); + }}, + {"top-bogus-remotes", [](ArgIterator, ArgIterator) { + return doGenericTopRemotes(pleaseGetBogusRemotes); + }}, + {"top-largeanswer-remotes", [](ArgIterator, ArgIterator) { + return doGenericTopRemotes(pleaseGetLargeAnswerRemotes); + }}, + {"top-timeouts", [](ArgIterator, ArgIterator) { + return doGenericTopRemotes(pleaseGetTimeouts); + }}, + {"current-queries", doCurrentQueries}, + {"ping", [](ArgIterator, ArgIterator) -> Answer { + return {0, broadcastAccFunction(nopFunction)}; + }}, + {"reload-zones", [](ArgIterator, ArgIterator) -> Answer { + if (!::arg()["chroot"].empty()) { + g_log << Logger::Error << "Unable to reload zones and forwards when chroot()'ed, requested via control channel" << endl; + return {1, "Unable to reload zones and forwards when chroot()'ed, please restart\n"}; + } + return {0, reloadZoneConfigurationWithSysResolveReset()}; + }}, + {"set-ecs-minimum-ttl", setMinimumECSTTL}, + {"set-max-cache-entries", setMaxCacheEntries}, + {"set-max-packetcache-entries", setMaxPacketCacheEntries}, + {"set-minimum-ttl", setMinimumTTL}, + {"get-qtypelist", [](ArgIterator, ArgIterator) -> Answer { + return {0, g_Counters.sum(rec::ResponseStats::responseStats).getQTypeReport()}; + }}, + {"add-nta", doAddNTA}, + {"clear-nta", doClearNTA}, + {"get-ntas", getNTAs}, + {"add-ta", doAddTA}, + {"clear-ta", doClearTA}, + {"get-tas", getTAs}, + {"set-dnssec-log-bogus", doSetDnssecLogBogus}, + {"get-dont-throttle-names", getDontThrottleNames}, + {"get-dont-throttle-netmasks", getDontThrottleNetmasks}, + {"add-dont-throttle-names", addDontThrottleNames}, + {"add-dont-throttle-netmasks", addDontThrottleNetmasks}, + {"clear-dont-throttle-names", clearDontThrottleNames}, + {"clear-dont-throttle-netmasks", clearDontThrottleNetmasks}, + {"set-event-trace-enabled", setEventTracing}, + {"get-proxymapping-stats", doGetProxyMappingStats}, + {"get-remotelogger-stats", getRemoteLoggerStats}, + {"list-dnssec-algos", [](ArgIterator, ArgIterator) -> Answer { + return {0, DNSCryptoKeyEngine::listSupportedAlgoNames()}; + }}, + {"set-aggr-nsec-cache-size", setAggrNSECCacheSize}, + }; + + if (const auto entry = commands.find(cmd); entry != commands.end()) { + auto begin = words.begin() + 1; + auto end = words.end(); + return entry->second(begin, end); } return {1, "Unknown command '" + cmd + "', try 'help'\n"}; diff -Nru pdns-recursor-5.2.13/rec_control.1 pdns-recursor-5.4.9/rec_control.1 --- pdns-recursor-5.2.13/rec_control.1 2026-08-05 12:02:34.000000000 +0000 +++ pdns-recursor-5.4.9/rec_control.1 2026-10-26 09:47:32.000000000 +0000 @@ -27,7 +27,7 @@ .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "REC_CONTROL" "1" "Aug 05, 2026" "" "PowerDNS Recursor" +.TH "REC_CONTROL" "1" "Oct 26, 2026" "" "PowerDNS Recursor" .SH NAME rec_control \- Command line tool to control a running Recursor .SH SYNOPSIS @@ -119,6 +119,11 @@ .SH COMMANDS .INDENT 0.0 .TP +.B add\-cookies\-unsupported \fIIP\fP [\fIIP\fP\&...] +Add non\-expiring IPs of servers that do not support cookies to the cookie table. +Optionally \fIIP:port\fP can be specified, the default is to use port 53. +The listed addresses will be placed as \fBUnsupported\fP in the cookie support table and will not be pruned. +.TP .B add\-dont\-throttle\-names \fINAME\fP [\fINAME\fP\&...] Add names for nameserver domains that may not be throttled. .TP @@ -136,6 +141,10 @@ .B current\-queries Shows the currently active queries. .TP +.B clear\-cookies [\fIIP\fP\&...] +Remove entries from cookie table. If \fIIP\fP is \fB*\fP, remove all. +Optionally \fIIP:port\fP can be specified, the default is to use port 53. +.TP .B clear\-dont\-throttle\-names \fINAME\fP [\fINAME\fP\&...] Remove names that are not allowed to be throttled. If \fINAME\fP is \fB*\fP, remove all .TP @@ -160,6 +169,9 @@ select specific caches specify one or more \fITYPE*s, separated by spaces. The value of *TYPE\fP can be r, n, p or a. .TP +.B dump\-cookies \fIFILENAME\fP +Dump the cookie store. +.TP .B dump\-dot\-probe\-map \fIFILENAME\fP Dump the contents of the DoT probe map to the \fIFILENAME\fP mentioned. .TP @@ -226,8 +238,15 @@ .B get\-tas Get a list of the currently configured Trust Anchors. .TP -.B get\-parameter \fIKEY\fP [\fIKEY\fP]... -Retrieves the specified configuration parameter(s). +.B get\-parameter [\fIKEY\fP]... +Retrieves the configuration parameter(s). +From version 5.4.0 and if YAML configuration is active, \fIKEY\fP is of the form \fBsection[.name]\fP +and no keys produces a full dump. +.TP +.B get\-default\-parameter [\fIKEY\fP]... +Retrieves the default values of configuration parameter(s). +If YAML configuration is active, \fIKEY\fP is of the form \fBsection[.name]\fP +and no keys produces a full dump. .TP .B get\-proxymapping\-stats Get the list of proxy\-mapped subnets and associated counters. @@ -323,7 +342,7 @@ \fB2\fP = log file, \fB3\fP = protobuf and log file. .TP .B show\-yaml [\fIFILE\fP] -Show Yaml representation of odl\-style config. +Show Yaml representation of old\-style config. .TP .B top\-queries Shows the top\-20 queries. Statistics are over the last diff -Nru pdns-recursor-5.2.13/rec_control.cc pdns-recursor-5.4.9/rec_control.cc --- pdns-recursor-5.2.13/rec_control.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rec_control.cc 2026-10-26 08:26:51.000000000 +0000 @@ -32,7 +32,7 @@ #include "credentials.hh" #include "namespaces.hh" #include "rec_channel.hh" -#include "settings/cxxsettings.hh" +#include "rec-rust-lib/cxxsettings.hh" #include "logger.hh" #include "logging.hh" @@ -57,14 +57,14 @@ arg().laxParse(argc, argv); if (arg().mustDo("version")) { cout << "rec_control version " << VERSION << endl; - exit(0); + exit(0); // NOLINT(concurrency-mt-unsafe) } if (arg().mustDo("help") || arg().getCommands().empty()) { cout << "syntax: rec_control [options] command, options as below: " << endl << endl; cout << arg().helpstring(arg()["help"]) << endl; cout << "In addition, 'rec_control help' can be used to retrieve a list\nof available commands from PowerDNS" << endl; - exit(arg().mustDo("help") ? 0 : 99); + exit(arg().mustDo("help") ? 0 : 99); // NOLINT(concurrency-mt-unsafe) } string configname = ::arg()["config-dir"] + "/recursor"; @@ -299,11 +299,11 @@ buf.str(""); buf << "msg=" << std::quoted(entry.message); if (entry.error) { - buf << " error=" << std::quoted(entry.error.get()); + buf << " error=" << std::quoted(entry.error.value()); } if (entry.name) { - buf << " subsystem=" << std::quoted(entry.name.get()); + buf << " subsystem=" << std::quoted(entry.name.value()); } buf << " level=" << std::quoted(std::to_string(entry.level)); if (entry.d_priority != 0) { @@ -329,6 +329,7 @@ const set fileCommands = { "dump-cache", + "dump-cookies", "dump-edns", "dump-ednsstatus", "dump-nsspeeds", @@ -341,15 +342,17 @@ "trace-regex", }; try { + // needed to be able to parse (and convert to YAML) custom RPZ entries + reportAllTypes(); initArguments(argc, argv, log); string sockname = "pdns_recursor"; - if (arg()["config-name"] != "") + if (!empty(arg()["config-name"])) { sockname += "-" + arg()["config-name"]; - - if (!arg()["process"].empty()) + } + if (!arg()["process"].empty()) { sockname += "." + arg()["process"]; - + } sockname.append(".controlsocket"); const vector& commands = arg().getCommands(); @@ -385,39 +388,39 @@ } string command; - int fd = -1; - unsigned int i = 0; - while (i < commands.size()) { - if (i > 0) { + int fileDesc = -1; + unsigned int iteration = 0; + while (iteration < commands.size()) { + if (iteration > 0) { command += " "; } - command += commands[i]; + command += commands[iteration]; // special case: trace-regex with no arguments is clear regex auto traceregexClear = command == "trace-regex" && commands.size() == 1; - if (fileCommands.count(commands[i]) > 0 && !traceregexClear) { - if (i + 1 < commands.size()) { + if (fileCommands.count(commands[iteration]) > 0 && !traceregexClear) { + if (iteration + 1 < commands.size()) { // dump-rpz is different, it also has a zonename as argument // trace-regex is different, it also has a regexp as argument - if (commands[i] == "dump-rpz" || commands[i] == "trace-regex") { - if (i + 2 < commands.size()) { - ++i; + if (commands[iteration] == "dump-rpz" || commands[iteration] == "trace-regex") { + if (iteration + 2 < commands.size()) { + ++iteration; command += " "; - command += commands[i]; // add rpzname/regex and continue with filename + command += commands[iteration]; // add rpzname/regex and continue with filename } else { throw PDNSException("Command needs two arguments"); } } - ++i; - if (commands[i] == "-") { - fd = STDOUT_FILENO; + ++iteration; + if (commands[iteration] == "-") { + fileDesc = STDOUT_FILENO; } else { - fd = open(commands[i].c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + fileDesc = open(commands[iteration].c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); } - if (fd == -1) { + if (fileDesc == -1) { int err = errno; throw PDNSException("Error opening dump file for writing: " + stringerror(err)); } @@ -426,15 +429,15 @@ throw PDNSException("Command needs a file argument"); } } - ++i; + ++iteration; } auto timeout = arg().asNum("timeout"); RecursorControlChannel rccS; rccS.connect(arg()["socket-dir"], sockname); - rccS.send(rccS.d_fd, {0, std::move(command)}, timeout, fd); + RecursorControlChannel::send(rccS.getDescriptor(), {0, std::move(command)}, timeout, fileDesc); - auto receive = rccS.recv(rccS.d_fd, timeout); + auto receive = RecursorControlChannel::recv(rccS.getDescriptor(), timeout); if (receive.d_ret != 0) { cerr << receive.d_str; } @@ -448,3 +451,4 @@ return 1; } } +#include "rec-web-stubs.hh" diff -Nru pdns-recursor-5.2.13/recpacketcache.cc pdns-recursor-5.4.9/recpacketcache.cc --- pdns-recursor-5.2.13/recpacketcache.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/recpacketcache.cc 2026-10-26 08:26:51.000000000 +0000 @@ -104,6 +104,8 @@ return count; } +static const std::unordered_set s_skipOptions = {EDNSOptionCode::ECS, EDNSOptionCode::COOKIE, EDNSOptionCode::TRACEPARENT}; + bool RecursorPacketCache::qrMatch(const packetCache_t::index::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass) { // this ignores checking on the EDNS subnet flags! @@ -111,11 +113,10 @@ return false; } - static const std::unordered_set optionsToSkip{EDNSOptionCode::COOKIE, EDNSOptionCode::ECS}; - return queryMatches(iter->d_query, queryPacket, qname, optionsToSkip); + return queryMatches(iter->d_query, queryPacket, qname, s_skipOptions); } -bool RecursorPacketCache::checkResponseMatches(MapCombo::LockedContent& shard, std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata) +bool RecursorPacketCache::checkResponseMatches(MapCombo::LockedContent& shard, std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata, ECSInfo& ecsInfo) { for (auto iter = range.first; iter != range.second; ++iter) { // the possibility is VERY real that we get hits that are not right - birthday paradox @@ -157,10 +158,10 @@ *pbdata = iter->d_pbdata; } else { - *pbdata = boost::none; + *pbdata = std::nullopt; } } - + ecsInfo = iter->d_ecsInfo; return true; } // We used to move the item to the front of "the to be deleted" sequence, @@ -172,10 +173,8 @@ return false; } -static const std::unordered_set s_skipOptions = {EDNSOptionCode::ECS, EDNSOptionCode::COOKIE}; - bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, - std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp) + std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp, ECSInfo& ecsInfo) { *qhash = canHashPacket(queryPacket, s_skipOptions); auto& map = getMap(tag, *qhash, tcp); @@ -188,11 +187,11 @@ return false; } - return checkResponseMatches(*shard, range, queryPacket, qname, qtype, qclass, now, responsePacket, age, valState, pbdata); + return checkResponseMatches(*shard, range, queryPacket, qname, qtype, qclass, now, responsePacket, age, valState, pbdata, ecsInfo); } bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, - std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp) + std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp, ECSInfo& ecsInfo) { *qhash = canHashPacket(queryPacket, s_skipOptions); auto& map = getMap(tag, *qhash, tcp); @@ -207,10 +206,10 @@ qname = DNSName(queryPacket.c_str(), static_cast(queryPacket.length()), sizeof(dnsheader), false, qtype, qclass); - return checkResponseMatches(*shard, range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, valState, pbdata); + return checkResponseMatches(*shard, range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, valState, pbdata, ecsInfo); } -void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, OptPBData&& pbdata, bool tcp) +void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, vState valState, OptPBData&& pbdata, bool tcp, ECSInfo ecsInfo) { auto& map = getMap(tag, qhash, tcp); auto shard = map.lock(); @@ -233,11 +232,11 @@ if (pbdata) { iter->d_pbdata = std::move(*pbdata); } - + iter->d_ecsInfo = ecsInfo; return; } - struct Entry entry(DNSName(qname), qtype, qclass, std::move(responsePacket), std::move(query), tcp, qhash, now + ttl, now, tag, valState); + struct Entry entry(DNSName(qname), qtype, qclass, std::move(responsePacket), std::move(query), tcp, qhash, now + ttl, now, tag, valState, ecsInfo); if (pbdata) { entry.d_pbdata = std::move(*pbdata); } diff -Nru pdns-recursor-5.2.13/recpacketcache.hh pdns-recursor-5.4.9/recpacketcache.hh --- pdns-recursor-5.2.13/recpacketcache.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/recpacketcache.hh 2026-10-26 08:26:51.000000000 +0000 @@ -30,7 +30,6 @@ #include #include #include -#include #include "packetcache.hh" #include "validate.hh" @@ -55,7 +54,8 @@ std::string d_response; bool d_tagged; }; - using OptPBData = boost::optional; + using OptPBData = std::optional; + using ECSInfo = std::pair; RecursorPacketCache(size_t maxsize, size_t shards = 1024) : d_maps(shards) @@ -70,20 +70,22 @@ uint16_t qtype{0}; uint16_t qclass{0}; vState valState{vState::Indeterminate}; - return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, qhash, nullptr, false); + ECSInfo ecsInfo; + return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, qhash, nullptr, false, ecsInfo); } bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, uint32_t* qhash) { vState valState{vState::Indeterminate}; - return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, qhash, nullptr, false); + ECSInfo ecsInfo; + return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, qhash, nullptr, false, ecsInfo); } - bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp); - bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp, ECSInfo& ecsInfo); + bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp, ECSInfo& ecsInfo); - void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, OptPBData&& pbdata, bool tcp); + void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, vState valState, OptPBData&& pbdata, bool tcp, ECSInfo ecsInfo = {0, 0}); void doPruneTo(time_t now, size_t maxSize); uint64_t doDump(int file); uint64_t doWipePacketCache(const DNSName& name, uint16_t qtype = 0xffff, bool subtree = false); @@ -107,7 +109,7 @@ { Entry(DNSName&& qname, uint16_t qtype, uint16_t qclass, std::string&& packet, std::string&& query, bool tcp, // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - uint32_t qhash, time_t ttd, time_t now, uint32_t tag, vState vstate) : + uint32_t qhash, time_t ttd, time_t now, uint32_t tag, vState vstate, ECSInfo ecsInfo) : d_name(std::move(qname)), d_packet(std::move(packet)), d_query(std::move(query)), @@ -115,6 +117,7 @@ d_creation(now), d_qhash(qhash), d_tag(tag), + d_ecsInfo(ecsInfo), d_type(qtype), d_class(qclass), d_vstate(vstate), @@ -130,6 +133,7 @@ mutable time_t d_creation; // so we can 'age' our packets uint32_t d_qhash; uint32_t d_tag; + mutable ECSInfo d_ecsInfo; uint16_t d_type; uint16_t d_class; mutable vState d_vstate; @@ -240,7 +244,7 @@ } static bool qrMatch(const packetCache_t::index::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass); - static bool checkResponseMatches(MapCombo::LockedContent& shard, std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata); + static bool checkResponseMatches(MapCombo::LockedContent& shard, std::pair::type::iterator, packetCache_t::index::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata, ECSInfo& ecsInfo); void setShardSizes(size_t shardSize); }; diff -Nru pdns-recursor-5.2.13/recursor_cache.cc pdns-recursor-5.4.9/recursor_cache.cc --- pdns-recursor-5.2.13/recursor_cache.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/recursor_cache.cc 2026-10-26 08:26:51.000000000 +0000 @@ -34,6 +34,7 @@ #include "cachecleaner.hh" #include "rec-taskqueue.hh" #include "version.hh" +#include "protozero-helpers.hh" /* * SERVE-STALE: the general approach @@ -77,6 +78,10 @@ bool MemRecursorCache::s_limitQTypeAny = true; uint32_t MemRecursorCache::s_maxEntrySize = 8192; +const MemRecursorCache::AuthRecs MemRecursorCache::s_emptyAuthRecs = std::make_shared(); +const MemRecursorCache::SigRecs MemRecursorCache::s_emptySigRecs = std::make_shared(); +const MemRecursorCache::OptTag MemRecursorCache::NOTAG{""}; + void MemRecursorCache::resetStaticsForTests() { s_maxServedStaleExtensions = 0; @@ -125,6 +130,41 @@ return count; } +size_t MemRecursorCache::CacheEntry::authRecsSizeEstimate() const +{ + size_t ret = 0; + if (d_authorityRecs) { + for (const auto& record : *d_authorityRecs) { + ret += record.sizeEstimate(); + } + } + return ret; +} + +size_t MemRecursorCache::CacheEntry::sigRecsSizeEstimate() const +{ + size_t ret = 0; + if (d_signatures) { + for (const auto& record : *d_signatures) { + ret += record->sizeEstimate(); + } + } + return ret; +} + +size_t MemRecursorCache::CacheEntry::sizeEstimate() const +{ + auto ret = sizeof(struct CacheEntry); + ret += d_qname.sizeEstimate(); + ret += d_authZone.sizeEstimate(); + for (const auto& record : d_records) { + ret += record->sizeEstimate(); + } + ret += authRecsSizeEstimate(); + ret += sigRecsSizeEstimate(); + return ret; +} + // this function is too slow to poll! size_t MemRecursorCache::bytes() { @@ -132,20 +172,16 @@ for (auto& shard : d_maps) { auto lockedShard = shard.lock(); for (const auto& entry : lockedShard->d_map) { - ret += sizeof(struct CacheEntry); - ret += entry.d_qname.toString().length(); - for (const auto& record : entry.d_records) { - ret += sizeof(record); // XXX WRONG we don't know the stored size! - } + ret += entry.sizeEstimate(); } } return ret; } -static void updateDNSSECValidationStateFromCache(boost::optional& state, const vState stateUpdate) +static void updateDNSSECValidationStateFromCache(std::optional& state, const vState stateUpdate) { // if there was no state it's easy */ - if (state == boost::none) { + if (state == std::nullopt) { state = stateUpdate; return; } @@ -174,7 +210,9 @@ } } -time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP) +// If the authorityRecs is non-null, it should refer to a un-set shared_ptr, or a shared_ptr pointing to an empty vector +// See the assert in the processing of authorityRecs. +time_t MemRecursorCache::handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, std::optional& state, bool* wasAuth, DNSName* fromAuthZone, Extra* extra) { // MUTEX SHOULD BE ACQUIRED (as indicated by the reference to the content which is protected by a lock) if (entry->d_tooBig) { @@ -188,7 +226,7 @@ } origTTL = entry->d_orig_ttl; - if (!entry->d_netmask.empty() || entry->d_rtag) { + if (!entry->d_netmask.empty() || !entry->d_rtag.empty()) { ptrAssign(variable, true); } @@ -213,11 +251,21 @@ } if (signatures != nullptr) { - signatures->insert(signatures->end(), entry->d_signatures.begin(), entry->d_signatures.end()); + if (*signatures && !(*signatures)->empty() && entry->d_signatures && !entry->d_signatures->empty()) { + // Return a new vec if we need to append to a non-empty vector + SigRecsVec vec(**signatures); + vec.insert(vec.end(), entry->d_signatures->cbegin(), entry->d_signatures->cend()); + *signatures = std::make_shared(std::move(vec)); + } + else { + *signatures = entry->d_signatures ? entry->d_signatures : s_emptySigRecs; + } } if (authorityRecs != nullptr) { - authorityRecs->insert(authorityRecs->end(), entry->d_authorityRecs.begin(), entry->d_authorityRecs.end()); + // XXX Might need to be adapted like sigs to handle a non-empty incoming authorityRecs + assert(*authorityRecs == nullptr || (*authorityRecs)->empty()); + *authorityRecs = entry->d_authorityRecs ? entry->d_authorityRecs : s_emptyAuthRecs; } updateDNSSECValidationStateFromCache(state, entry->d_state); @@ -226,7 +274,10 @@ *wasAuth = *wasAuth && entry->d_auth; } ptrAssign(fromAuthZone, entry->d_authZone); - ptrAssign(fromAuthIP, entry->d_from); + if (extra != nullptr) { + extra->d_address = entry->d_from; + extra->d_tcp = entry->d_tcp; + } moveCacheItemToBack(content.d_map, entry); @@ -246,7 +297,7 @@ void MemRecursorCache::updateStaleEntry(time_t now, MemRecursorCache::OrderedTagIterator_t& entry) { - // We need to take care a infrequently access stale item cannot be extended past + // We need to take care an infrequently access stale item cannot be extended past // s_maxServedStaleExtension * s_serveStaleExtensionPeriod // We look how old the entry is, and increase d_servedStale accordingly, taking care not to overflow const time_t howlong = std::max(static_cast(1), now - entry->d_ttd); @@ -280,7 +331,7 @@ /* we have nothing more specific for you */ break; } - auto key = std::tuple(qname, qtype, boost::none, best); + auto key = std::tuple(qname, qtype, NOTAG, best); auto entry = map.d_map.find(key); if (entry == map.d_map.end()) { /* ecsIndex is not up-to-date */ @@ -312,7 +363,7 @@ } /* we have nothing specific, let's see if we have a generic one */ - auto key = std::tuple(qname, qtype, boost::none, Netmask()); + auto key = std::tuple(qname, qtype, MemRecursorCache::NOTAG, Netmask()); auto entry = map.d_map.find(key); if (entry != map.d_map.end()) { handleServeStaleBookkeeping(now, serveStale, entry); @@ -384,13 +435,13 @@ } // returns -1 for no hits -time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype, Flags flags, vector* res, const ComboAddress& who, const OptTag& routingTag, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, ComboAddress* fromAuthIP) // NOLINT(readability-function-cognitive-complexity) +time_t MemRecursorCache::get(time_t now, const DNSName& qname, const QType qtype, Flags flags, vector* res, const ComboAddress& who, const OptTag& routingTag, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone, Extra* extra) // NOLINT(readability-function-cognitive-complexity) { bool requireAuth = (flags & RequireAuth) != 0; bool refresh = (flags & Refresh) != 0; bool serveStale = (flags & ServeStale) != 0; - boost::optional cachedState{boost::none}; + std::optional cachedState{std::nullopt}; uint32_t origTTL = 0; if (res != nullptr) { @@ -406,17 +457,21 @@ /* If we don't have any netmask-specific entries at all, let's just skip this to be able to use the nice d_cachecache hack. */ - if (qtype != QType::ANY && !lockedShard->d_ecsIndex.empty() && !routingTag) { + if (qtype != QType::ANY && !lockedShard->d_ecsIndex.empty() && routingTag.empty()) { if (qtype == QType::ADDR) { time_t ret = -1; auto entryA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::A, requireAuth, who, serveStale); if (entryA != lockedShard->d_map.end()) { - ret = handleHit(now, *lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP); + ret = handleHit(now, *lockedShard, entryA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra); } auto entryAAAA = getEntryUsingECSIndex(*lockedShard, now, qname, QType::AAAA, requireAuth, who, serveStale); if (entryAAAA != lockedShard->d_map.end()) { - time_t ttdAAAA = handleHit(now, *lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP); + if (authorityRecs != nullptr) { + // For the case the first call filled authorityRecs + *authorityRecs = s_emptyAuthRecs; + } + time_t ttdAAAA = handleHit(now, *lockedShard, entryAAAA, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra); if (ret > 0) { ret = std::min(ret, ttdAAAA); } @@ -433,7 +488,7 @@ } auto entry = getEntryUsingECSIndex(*lockedShard, now, qname, qtype, requireAuth, who, serveStale); if (entry != lockedShard->d_map.end()) { - time_t ret = handleHit(now, *lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP); + time_t ret = handleHit(now, *lockedShard, entry, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra); if (cachedState && ret > now) { ptrAssign(state, *cachedState); } @@ -442,7 +497,7 @@ return -1; } - if (routingTag) { + if (!routingTag.empty()) { auto entries = getEntries(*lockedShard, qname, qtype, routingTag); unsigned int found = 0; time_t ttd{}; @@ -465,7 +520,12 @@ handleServeStaleBookkeeping(now, serveStale, firstIndexIterator); - ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP); + if (authorityRecs != nullptr) { + // For the case the loop iterates multiple times + *authorityRecs = s_emptyAuthRecs; + } + + ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra); if (qtype == QType::ADDR && found == 2) { break; @@ -484,7 +544,7 @@ } } // Try (again) without tag - auto entries = getEntries(*lockedShard, qname, qtype, boost::none); + auto entries = getEntries(*lockedShard, qname, qtype, NOTAG); if (entries.first != entries.second) { OrderedTagIterator_t firstIndexIterator; @@ -507,7 +567,11 @@ handleServeStaleBookkeeping(now, serveStale, firstIndexIterator); - ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, fromAuthIP); + if (authorityRecs != nullptr) { + // For the case the loop iterates multiple times + *authorityRecs = s_emptyAuthRecs; + } + ttd = handleHit(now, *lockedShard, firstIndexIterator, qname, origTTL, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone, extra); if (qtype == QType::ADDR && found == 2) { break; @@ -571,7 +635,7 @@ bool MemRecursorCache::replace(CacheEntry&& entry) { - if (!entry.d_netmask.empty() || entry.d_rtag) { + if (!entry.d_netmask.empty() || !entry.d_rtag.empty()) { // We don't handle that yet return false; } @@ -587,19 +651,21 @@ return false; } -void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qtype, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, const DNSName& authZone, boost::optional ednsmask, const OptTag& routingTag, vState state, boost::optional from, bool refresh, time_t ttl_time) +void MemRecursorCache::replace(time_t now, const DNSName& qname, const QType qtype, const vector& content, const SigRecsVec& signatures, const AuthRecsVec& authorityRecs, bool auth, const DNSName& authZone, const std::optional& ednsmaskArg, const OptTag& routingTag, vState state, const std::optional& extra, bool refresh, time_t ttl_time) { auto& shard = getMap(qname); auto lockedShard = shard.lock(); lockedShard->d_cachecachevalid = false; - if (ednsmask) { - ednsmask = ednsmask->getNormalized(); + + std::optional ednsmask; + if (ednsmaskArg) { + ednsmask = ednsmaskArg->getNormalized(); } // We only store with a tag if we have an ednsmask and the tag is available // We only store an ednsmask if we do not have a tag and we do have a mask. - auto key = std::tuple(qname, qtype.getCode(), ednsmask ? routingTag : boost::none, (ednsmask && !routingTag) ? *ednsmask : Netmask()); + auto key = std::tuple(qname, qtype.getCode(), ednsmask ? routingTag : NOTAG, (ednsmask && routingTag.empty()) ? *ednsmask : Netmask()); bool isNew = false; cache_t::iterator stored = lockedShard->d_map.find(key); if (stored == lockedShard->d_map.end()) { @@ -615,7 +681,7 @@ */ if (isNew || stored->d_ttd <= now) { /* don't bother building an ecsIndex if we don't have any netmask-specific entries */ - if (!routingTag && ednsmask && !ednsmask->empty()) { + if (routingTag.empty() && ednsmask && !ednsmask->empty()) { auto ecsIndexKey = std::tuple(qname, qtype.getCode()); auto ecsIndex = lockedShard->d_ecsIndex.find(ecsIndexKey); if (ecsIndex == lockedShard->d_ecsIndex.end()) { @@ -647,15 +713,27 @@ cacheEntry.d_auth = true; } - cacheEntry.d_signatures = signatures; - cacheEntry.d_authorityRecs = authorityRecs; + if (!signatures.empty()) { + cacheEntry.d_signatures = std::make_shared(signatures); + } + else { + cacheEntry.d_signatures = nullptr; + } + if (!authorityRecs.empty()) { + cacheEntry.d_authorityRecs = std::make_shared(authorityRecs); + } + else { + cacheEntry.d_authorityRecs = nullptr; + } cacheEntry.d_records.clear(); cacheEntry.d_authZone = authZone; - if (from) { - cacheEntry.d_from = *from; + if (extra) { + cacheEntry.d_from = extra->d_address; + cacheEntry.d_tcp = extra->d_tcp; } else { cacheEntry.d_from = ComboAddress(); + cacheEntry.d_tcp = false; } size_t toStore = content.size(); @@ -667,7 +745,6 @@ cacheEntry.d_tooBig = true; } cacheEntry.d_records.reserve(toStore); - size_t storeSize = sizeof(CacheEntry) + qname.getStorage().size(); // rough estimate for (const auto& record : content) { /* Yes, we have altered the d_ttl value by adding time(nullptr) to it prior to calling this function, so the TTL actually holds a TTD. */ @@ -677,17 +754,17 @@ cacheEntry.d_orig_ttl = cacheEntry.d_ttd - ttl_time; // Even though we record the time the ttd was computed, there still seems to be a case where the computed // d_orig_ttl can wrap. - // So santize the computed ce.d_orig_ttl to be on the safe side + // So sanitize the computed ce.d_orig_ttl to be on the safe side if (cacheEntry.d_orig_ttl < SyncRes::s_minimumTTL || cacheEntry.d_orig_ttl > SyncRes::s_maxcachettl) { cacheEntry.d_orig_ttl = SyncRes::s_minimumTTL; } cacheEntry.d_records.push_back(record.getContent()); - storeSize += record.d_clen; // again, rough estimate if (--toStore == 0) { break; } } + auto storeSize = cacheEntry.sizeEstimate(); if (s_maxEntrySize > 0 && storeSize > s_maxEntrySize) { return; } @@ -798,7 +875,7 @@ return false; } -bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName& qname, const QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional capTTD) +bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName& qname, const QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, std::optional capTTD) { if (qtype == QType::ANY) { throw std::runtime_error("Trying to update the DNSSEC validation status of all (via ANY) records for " + qname.toLogString()); @@ -811,7 +888,7 @@ auto map = content.lock(); bool updated = false; - if (!map->d_ecsIndex.empty() && !routingTag) { + if (!map->d_ecsIndex.empty() && routingTag.empty()) { auto entry = getEntryUsingECSIndex(*map, now, qname, qtype, requireAuth, who, false); // XXX serveStale? if (entry == map->d_map.end()) { return false; @@ -865,7 +942,11 @@ for (auto& shard : d_maps) { auto lockedShard = shard.lock(); const auto shardSize = lockedShard->d_map.size(); - fprintf(filePtr.get(), "; record cache shard %zu; size %zu\n", shardNumber, shardSize); + size_t bytes = 0; + for (const auto& entry : lockedShard->d_map) { + bytes += entry.sizeEstimate(); + } + fprintf(filePtr.get(), "; record cache shard %zu; size %zu bytes %zu\n", shardNumber, shardSize, bytes); min = std::min(min, shardSize); max = std::max(max, shardSize); shardNumber++; @@ -875,19 +956,21 @@ for (const auto& record : recordSet.d_records) { count++; try { - fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s nm=%s rtag=%s ss=%hd%s\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast(recordSet.d_ttd - now), recordSet.d_qtype.toString().c_str(), record->getZoneRepresentation().c_str(), vStateToString(recordSet.d_state).c_str(), static_cast(recordSet.d_auth), recordSet.d_authZone.toLogString().c_str(), recordSet.d_from.toString().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str(), !recordSet.d_rtag ? "" : recordSet.d_rtag.get().c_str(), recordSet.d_servedStale, recordSet.d_tooBig ? " (too big!)" : ""); + fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s nm=%s rtag=%s ss=%hd%s%s\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast(recordSet.d_ttd - now), recordSet.d_qtype.toString().c_str(), record->getZoneRepresentation().c_str(), vStateToString(recordSet.d_state).c_str(), static_cast(recordSet.d_auth), recordSet.d_authZone.toLogString().c_str(), recordSet.d_from.toString().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str(), recordSet.d_rtag.c_str(), recordSet.d_servedStale, recordSet.d_tooBig ? " (too big!)" : "", recordSet.d_tcp ? " tcp" : ""); } catch (...) { fprintf(filePtr.get(), "; error printing '%s'\n", recordSet.d_qname.empty() ? "EMPTY" : recordSet.d_qname.toString().c_str()); } } - for (const auto& sig : recordSet.d_signatures) { - count++; - try { - fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN RRSIG %s ; %s\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast(recordSet.d_ttd - now), sig->getZoneRepresentation().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str()); - } - catch (...) { - fprintf(filePtr.get(), "; error printing '%s'\n", recordSet.d_qname.empty() ? "EMPTY" : recordSet.d_qname.toString().c_str()); + if (recordSet.d_signatures) { + for (const auto& sig : *recordSet.d_signatures) { + count++; + try { + fprintf(filePtr.get(), "%s %" PRIu32 " %" PRId64 " IN RRSIG %s ; %s\n", recordSet.d_qname.toString().c_str(), recordSet.d_orig_ttl, static_cast(recordSet.d_ttd - now), sig->getZoneRepresentation().c_str(), recordSet.d_netmask.empty() ? "" : recordSet.d_netmask.toString().c_str()); + } + catch (...) { + fprintf(filePtr.get(), "; error printing '%s'\n", recordSet.d_qname.empty() ? "EMPTY" : recordSet.d_qname.toString().c_str()); + } } } } @@ -930,12 +1013,7 @@ required_bool_auth = 14, required_bool_submitted = 15, required_bool_tooBig = 16, -}; - -enum class PBComboAddress : protozero::pbf_tag_type -{ - required_uint32_port = 1, - required_bytes_address = 2, // family implicit + optional_bool_tcp = 17, }; enum class PBAuthRecord : protozero::pbf_tag_type @@ -949,71 +1027,6 @@ required_uint32_clen = 7, }; -template -static void encodeComboAddress(protozero::pbf_builder& writer, T type, const ComboAddress& address) -{ - protozero::pbf_builder message(writer, type); - - // Skip all parts except address and port - message.add_uint32(PBComboAddress::required_uint32_port, address.getPort()); - if (address.sin4.sin_family == AF_INET) { - message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast(&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 (address.sin4.sin_family == AF_INET6) { - message.add_bytes(PBComboAddress::required_bytes_address, reinterpret_cast(&address.sin6.sin6_addr.s6_addr), sizeof(address.sin6.sin6_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API - } -} - -template -static void decodeComboAddress(protozero::pbf_message& reader, ComboAddress& address) -{ - address.reset(); - protozero::pbf_message message(reader.get_message()); - - // Skip all parts except address and port - if (message.next(PBComboAddress::required_uint32_port)) { - address.setPort(message.get_uint32()); - } - else { - throw std::runtime_error("expected port in protobuf data"); - } - constexpr auto inet4size = sizeof(address.sin4.sin_addr); - constexpr auto inet6size = sizeof(address.sin6.sin6_addr); - if (message.next(PBComboAddress::required_bytes_address)) { - auto data = message.get_bytes(); - address.sin4.sin_family = data.size() == inet4size ? AF_INET : AF_INET6; - if (data.size() == inet4size) { - address.sin4.sin_family = AF_INET; - memcpy(&address.sin4.sin_addr, data.data(), data.size()); - } - else if (data.size() == inet6size) { - address.sin6.sin6_family = AF_INET6; - memcpy(&address.sin6.sin6_addr, data.data(), data.size()); - } - else { - throw std::runtime_error("unexpected address family in protobuf data"); - } - } - else { - throw std::runtime_error("expected address bytes in protobuf data"); - } -} - -template -static void encodeNetmask(protozero::pbf_builder& writer, T type, const Netmask& subnet) -{ - if (!subnet.empty()) { - writer.add_bytes(type, reinterpret_cast(&subnet), sizeof(Netmask)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API - } -} - -template -static void decodeNetmask(protozero::pbf_message& message, Netmask& subnet) -{ - auto data = message.get_bytes(); - memcpy(&subnet, data.data(), data.size()); -} - template void MemRecursorCache::getRecordSet(T& message, U recordSet) { @@ -1023,25 +1036,29 @@ for (const auto& record : recordSet->d_records) { message.add_bytes(PBCacheEntry::repeated_bytes_record, record->serialize(recordSet->d_qname, true)); } - for (const auto& record : recordSet->d_signatures) { - message.add_bytes(PBCacheEntry::repeated_bytes_sig, record->serialize(recordSet->d_qname, true)); - } - for (const auto& authRec : recordSet->d_authorityRecs) { - protozero::pbf_builder auth(message, PBCacheEntry::repeated_message_authRecord); - auth.add_bytes(PBAuthRecord::required_bytes_name, authRec->d_name.toString()); - auth.add_uint32(PBAuthRecord::required_uint32_type, authRec->d_type); - auth.add_uint32(PBAuthRecord::required_uint32_class, authRec->d_class); - auth.add_uint32(PBAuthRecord::required_uint32_ttl, authRec->d_ttl); - auth.add_uint32(PBAuthRecord::required_uint32_place, authRec->d_place); - auth.add_uint32(PBAuthRecord::required_uint32_clen, authRec->d_clen); - /* content needs to be done last otherwise we have a problem when deserializing because we don't know the correct type! */ - auth.add_bytes(PBAuthRecord::required_bytes_rdata, authRec->getContent()->serialize(authRec->d_name, true)); + if (recordSet->d_signatures) { + for (const auto& record : *recordSet->d_signatures) { + message.add_bytes(PBCacheEntry::repeated_bytes_sig, record->serialize(recordSet->d_qname, true)); + } + } + if (recordSet->d_authorityRecs) { + for (const auto& authRec : *recordSet->d_authorityRecs) { + protozero::pbf_builder auth(message, PBCacheEntry::repeated_message_authRecord); + auth.add_bytes(PBAuthRecord::required_bytes_name, authRec.d_name.toString()); + auth.add_uint32(PBAuthRecord::required_uint32_type, authRec.d_type); + auth.add_uint32(PBAuthRecord::required_uint32_class, authRec.d_class); + auth.add_uint32(PBAuthRecord::required_uint32_ttl, authRec.d_ttl); + auth.add_uint32(PBAuthRecord::required_uint32_place, authRec.d_place); + auth.add_uint32(PBAuthRecord::required_uint32_clen, authRec.d_clen); + /* content needs to be done last otherwise we have a problem when deserializing because we don't know the correct type! */ + auth.add_bytes(PBAuthRecord::required_bytes_rdata, authRec.getContent()->serialize(authRec.d_name, true)); + } } message.add_bytes(PBCacheEntry::required_bytes_authZone, recordSet->d_authZone.toString()); encodeComboAddress(message, PBCacheEntry::required_message_from, recordSet->d_from); encodeNetmask(message, PBCacheEntry::optional_bytes_netmask, recordSet->d_netmask); - if (recordSet->d_rtag) { - message.add_bytes(PBCacheEntry::optional_bytes_rtag, *recordSet->d_rtag); + if (!recordSet->d_rtag.empty()) { + message.add_bytes(PBCacheEntry::optional_bytes_rtag, recordSet->d_rtag); } message.add_uint32(PBCacheEntry::required_uint32_state, static_cast(recordSet->d_state)); message.add_int64(PBCacheEntry::required_int64_ttd, recordSet->d_ttd); @@ -1050,6 +1067,7 @@ message.add_bool(PBCacheEntry::required_bool_auth, recordSet->d_auth); message.add_bool(PBCacheEntry::required_bool_submitted, recordSet->d_submitted); message.add_bool(PBCacheEntry::required_bool_tooBig, recordSet->d_tooBig); + message.add_bool(PBCacheEntry::optional_bool_tcp, recordSet->d_tcp); } size_t MemRecursorCache::getRecordSets(size_t perShard, size_t maxSize, std::string& ret) @@ -1100,7 +1118,7 @@ return count; } -static void putAuthRecord(protozero::pbf_message& message, const DNSName& qname, std::vector>& authRecs) +static void putAuthRecord(protozero::pbf_message& message, const DNSName& qname, std::vector& authRecs) { protozero::pbf_message auth = message.get_message(); DNSRecord authRecord; @@ -1130,16 +1148,19 @@ authRecord.d_clen = auth.get_uint32(); break; default: + auth.skip(); break; } } - authRecs.emplace_back(std::make_shared(authRecord)); + authRecs.emplace_back(authRecord); } template bool MemRecursorCache::putRecordSet(T& message) { - CacheEntry cacheEntry{{g_rootdnsname, QType::A, boost::none, Netmask()}, false}; + AuthRecsVec authRecs; + SigRecsVec sigRecs; + CacheEntry cacheEntry{{g_rootdnsname, QType::A, NOTAG, Netmask()}, false}; while (message.next()) { switch (message.tag()) { case PBCacheEntry::repeated_bytes_record: { @@ -1149,11 +1170,11 @@ } case PBCacheEntry::repeated_bytes_sig: { auto ptr = DNSRecordContent::deserialize(cacheEntry.d_qname, QType::RRSIG, message.get_bytes()); - cacheEntry.d_signatures.emplace_back(std::dynamic_pointer_cast(ptr)); + sigRecs.emplace_back(std::dynamic_pointer_cast(ptr)); break; } case PBCacheEntry::repeated_message_authRecord: - putAuthRecord(message, cacheEntry.d_qname, cacheEntry.d_authorityRecs); + putAuthRecord(message, cacheEntry.d_qname, authRecs); break; case PBCacheEntry::required_bytes_name: cacheEntry.d_qname = DNSName(message.get_bytes()); @@ -1195,10 +1216,20 @@ case PBCacheEntry::required_bool_tooBig: cacheEntry.d_tooBig = message.get_bool(); break; + case PBCacheEntry::optional_bool_tcp: + cacheEntry.d_tcp = message.get_bool(); + break; default: + message.skip(); break; } } + if (!authRecs.empty()) { + cacheEntry.d_authorityRecs = std::make_shared(std::move(authRecs)); + } + if (!sigRecs.empty()) { + cacheEntry.d_signatures = std::make_shared(std::move(sigRecs)); + } return replace(std::move(cacheEntry)); } @@ -1258,6 +1289,9 @@ ++count; break; } + default: + full.skip(); + break; } } log->info(Logr::Info, "Processed cache dump", "processed", Logging::Loggable(count), "inserted", Logging::Loggable(inserted)); @@ -1274,11 +1308,3 @@ } return 0; } - -namespace boost -{ -size_t hash_value(const MemRecursorCache::OptTag& rtag) -{ - return rtag ? hash_value(rtag.get()) : 0xcafebaaf; -} -} diff -Nru pdns-recursor-5.2.13/recursor_cache.hh pdns-recursor-5.4.9/recursor_cache.hh --- pdns-recursor-5.2.13/recursor_cache.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/recursor_cache.hh 2026-10-26 08:26:51.000000000 +0000 @@ -66,7 +66,8 @@ size_t getRecordSets(size_t perShard, size_t maxSize, std::string& ret); size_t putRecordSets(const std::string& pbuf); - using OptTag = boost::optional; + using OptTag = std::string; + const static OptTag NOTAG; using Flags = uint8_t; static constexpr Flags None = 0; @@ -74,16 +75,45 @@ static constexpr Flags Refresh = 1 << 1; static constexpr Flags ServeStale = 1 << 2; - [[nodiscard]] time_t get(time_t, const DNSName& qname, QType qtype, Flags flags, vector* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector>* signatures = nullptr, std::vector>* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, ComboAddress* fromAuthIP = nullptr); + // The type used to pass auth record data to replace(); If the vector is non-empty, the cache will + // store a shared pointer to the copied data. The shared pointer will be returned by get(). There + // are optimizations: an empty vector will be stored as a nullptr, but get() will return a pointer + // to an already existing empty vector in that case, this is more convenient for the caller, since + // it avoid checking for nullptr, just iterate as for the non-empty case. + // + // get() will return a shared vector to a const vector of shared pointers. Only a single shared + // pointer gets copied, while earlier code would copy all shared pointer in the vector. + // + // In the current SyncRes code, AuthRecs never get appended to a non-empty vector while SigRecs do + // get appended in some cases; the handleHit() code will take measures. In the future we might + // want a more specialized data structure than a vector, it would require another level of + // indirection though, so for now we construct a new shared vector if appending is needed. See + // handleHit() for details. + using AuthRecsVec = std::vector; + using AuthRecs = std::shared_ptr; // const to avoid modifying the vector, which would be bad for shared data + const static AuthRecs s_emptyAuthRecs; + + // Use same setup as AuthRecs. + using SigRecsVec = std::vector>; + using SigRecs = std::shared_ptr; // Also const as it is shared + const static SigRecs s_emptySigRecs; - void replace(time_t, const DNSName& qname, QType qtype, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, const DNSName& authZone, boost::optional ednsmask = boost::none, const OptTag& routingTag = boost::none, vState state = vState::Indeterminate, boost::optional from = boost::none, bool refresh = false, time_t ttl_time = time(nullptr)); + struct Extra + { + ComboAddress d_address; + bool d_tcp{false}; + }; + + [[nodiscard]] time_t get(time_t, const DNSName& qname, QType qtype, Flags flags, vector* res, const ComboAddress& who, const OptTag& routingTag = NOTAG, SigRecs* signatures = nullptr, AuthRecs* authorityRecs = nullptr, bool* variable = nullptr, vState* state = nullptr, bool* wasAuth = nullptr, DNSName* fromAuthZone = nullptr, Extra* extra = nullptr); + + void replace(time_t, const DNSName& qname, QType qtype, const vector& content, const SigRecsVec& signatures, const AuthRecsVec& authorityRecs, bool auth, const DNSName& authZone, const std::optional& ednsmask = std::nullopt, const OptTag& routingTag = NOTAG, vState state = vState::Indeterminate, const std::optional& extra = std::nullopt, bool refresh = false, time_t ttl_time = time(nullptr)); void doPrune(time_t now, size_t keep); uint64_t doDump(int fileDesc, size_t maxCacheEntries); size_t doWipeCache(const DNSName& name, bool sub, QType qtype = 0xffff); bool doAgeCache(time_t now, const DNSName& name, QType qtype, uint32_t newTTL); - bool updateValidationStatus(time_t now, const DNSName& qname, QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, boost::optional capTTD); + bool updateValidationStatus(time_t now, const DNSName& qname, QType qtype, const ComboAddress& who, const OptTag& routingTag, bool requireAuth, vState newState, std::optional capTTD); static void resetStaticsForTests(); @@ -111,7 +141,11 @@ struct CacheEntry { CacheEntry(const std::tuple& key, bool auth) : - d_qname(std::get<0>(key)), d_netmask(std::get<3>(key).getNormalized()), d_rtag(std::get<2>(key)), d_qtype(std::get<1>(key)), d_auth(auth) + d_rtag(std::get<2>(key)), + d_netmask(std::get<3>(key).getNormalized()), + d_qname(std::get<0>(key)), + d_qtype(std::get<1>(key)), + d_auth(auth) { } @@ -134,22 +168,27 @@ bool shouldReplace(time_t now, bool auth, vState state, bool refresh); - records_t d_records; - std::vector> d_signatures; - std::vector> d_authorityRecs; - DNSName d_qname; - DNSName d_authZone; - ComboAddress d_from; - Netmask d_netmask; - OptTag d_rtag; - mutable vState d_state{vState::Indeterminate}; - mutable time_t d_ttd{0}; - uint32_t d_orig_ttl{0}; - mutable uint16_t d_servedStale{0}; - QType d_qtype; - bool d_auth; - mutable bool d_submitted{false}; // whether this entry has been queued for refetch - bool d_tooBig{false}; + [[nodiscard]] size_t sizeEstimate() const; + [[nodiscard]] size_t authRecsSizeEstimate() const; + [[nodiscard]] size_t sigRecsSizeEstimate() const; + + OptTag d_rtag; // 40 (sizes for typical 64 bit system) + Netmask d_netmask; // 36 + ComboAddress d_from; // 28 + records_t d_records; // 24 + DNSName d_qname; // 24 + DNSName d_authZone; // 24 + SigRecs d_signatures; // 16 + AuthRecs d_authorityRecs; // 16 + mutable time_t d_ttd{0}; // 8 + uint32_t d_orig_ttl{0}; // 4 + mutable uint16_t d_servedStale{0}; // 2 + QType d_qtype; // 2 + mutable vState d_state{vState::Indeterminate}; // 1 + bool d_auth; // 1 + mutable bool d_submitted{false}; // 1, whether this entry has been queued for refetch + bool d_tooBig{false}; // 1 + bool d_tcp{false}; // 1 was entry received over TCP? }; bool replace(CacheEntry&& entry); @@ -348,12 +387,7 @@ static Entries getEntries(MapCombo::LockedContent& map, const DNSName& qname, QType qtype, const OptTag& rtag); static cache_t::const_iterator getEntryUsingECSIndex(MapCombo::LockedContent& map, time_t now, const DNSName& qname, QType qtype, bool requireAuth, const ComboAddress& who, bool serveStale); - static time_t handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth, DNSName* authZone, ComboAddress* fromAuthIP); + static time_t handleHit(time_t now, MapCombo::LockedContent& content, OrderedTagIterator_t& entry, const DNSName& qname, uint32_t& origTTL, vector* res, SigRecs* signatures, AuthRecs* authorityRecs, bool* variable, std::optional& state, bool* wasAuth, DNSName* authZone, Extra* extra); static void updateStaleEntry(time_t now, OrderedTagIterator_t& entry); static void handleServeStaleBookkeeping(time_t, bool, OrderedTagIterator_t&); }; - -namespace boost -{ -size_t hash_value(const MemRecursorCache::OptTag& rtag); -} diff -Nru pdns-recursor-5.2.13/reczones-helpers.cc pdns-recursor-5.4.9/reczones-helpers.cc --- pdns-recursor-5.2.13/reczones-helpers.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/reczones-helpers.cc 2026-10-26 08:26:51.000000000 +0000 @@ -41,7 +41,7 @@ // Put non-default root hints into cache as authoritative. As argued below in // putDefaultHintsIntoCache, this is actually wrong, but people might depend on it by having // root-hints that refer to servers that aren't actually capable or willing to serve root data. - g_recCache->replace(now, name, qtype, aset, {}, {}, true, g_rootdnsname, boost::none, boost::none, state, from); + g_recCache->replace(now, name, qtype, aset, {}, {}, true, g_rootdnsname, std::nullopt, MemRecursorCache::NOTAG, state, MemRecursorCache::Extra{from, false}); } } @@ -104,18 +104,15 @@ auto log = g_slog->withName("config"); if (SyncRes::s_doIPv4 && !SyncRes::s_doIPv6 && !reachableA) { - SLOG(g_log << Logger::Error << "Running IPv4 only but no IPv4 root hints" << endl, - log->info(Logr::Error, "Running IPv4 only but no IPv4 root hints")); + log->info(Logr::Error, "Running IPv4 only but no IPv4 root hints"); return false; } if (!SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableAAAA) { - SLOG(g_log << Logger::Error << "Running IPv6 only but no IPv6 root hints" << endl, - log->info(Logr::Error, "Running IPv6 only but no IPv6 root hints")); + log->info(Logr::Error, "Running IPv6 only but no IPv6 root hints"); return false; } if (SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableA && !reachableAAAA) { - SLOG(g_log << Logger::Error << "No valid root hints" << endl, - log->info(Logr::Error, "No valid root hints")); + log->info(Logr::Error, "No valid root hints"); return false; } return true; @@ -161,11 +158,11 @@ * auth and will expire at the same time. A re-prime is then triggered, as before, when the * records were inserted with the auth bit set and the TTD comes. */ - g_recCache->replace(now, DNSName(templ), QType::A, {arr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from); + g_recCache->replace(now, DNSName(templ), QType::A, {arr}, {}, {}, false, g_rootdnsname, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, MemRecursorCache::Extra{from, false}); } if (!rootIps6.at(letter).empty()) { aaaarr.setContent(std::make_shared(ComboAddress(rootIps6.at(letter)))); - g_recCache->replace(now, DNSName(templ), QType::AAAA, {aaaarr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from); + g_recCache->replace(now, DNSName(templ), QType::AAAA, {aaaarr}, {}, {}, false, g_rootdnsname, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, MemRecursorCache::Extra{from, false}); } } } @@ -198,15 +195,13 @@ const bool reverse = false) { if (newMap.count(name) != 0) { - SLOG(g_log << Logger::Warning << "Will not overwrite zone '" << name << "' already loaded" << endl, - log->info(Logr::Warning, "Will not overwrite already loaded zone", "zone", - Logging::Loggable(name))); + log->info(Logr::Warning, "Will not overwrite already loaded zone", "zone", + Logging::Loggable(name)); } else { if (!partial) { const auto direction = reverse ? std::string{"reverse"} : std::string{"forward"}; - SLOG(g_log << Logger::Warning << "Inserting " << direction << " zone '" << name << "' based on hosts file" << endl, - log->info(Logr::Notice, "Inserting " + direction + " zone based on hosts file", "zone", Logging::Loggable(name))); + log->info(Logr::Notice, "Inserting " + direction + " zone based on hosts file", "zone", Logging::Loggable(name)); } ad.d_name = name; newMap[ad.d_name] = ad; diff -Nru pdns-recursor-5.2.13/reczones.cc pdns-recursor-5.4.9/reczones.cc --- pdns-recursor-5.2.13/reczones.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/reczones.cc 2026-10-26 08:26:51.000000000 +0000 @@ -32,13 +32,9 @@ #include "logger.hh" #include "syncres.hh" #include "zoneparser-tng.hh" -#include "settings/cxxsettings.hh" +#include "rec-rust-lib/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; +#include "rec-main.hh" bool primeHints(time_t now) { @@ -48,8 +44,7 @@ if (hintfile == "no" || hintfile == "no-refresh") { auto log = g_slog->withName("config"); - SLOG(g_log << Logger::Debug << "Priming root disabled by hint-file setting" << endl, - log->info(Logr::Debug, "Priming root disabled by hint-file setting")); + log->info(Logr::Debug, "Priming root disabled by hint-file setting"); return ret; } @@ -61,7 +56,7 @@ } g_recCache->doWipeCache(g_rootdnsname, false, QType::NS); - g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, ComboAddress("255.255.255.255")); // and stuff in the cache + g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, MemRecursorCache::Extra{ComboAddress("255.255.255.255"), false}); // and stuff in the cache return ret; } @@ -69,6 +64,9 @@ { vector servers; stringtok(servers, input, sepa); + if (servers.empty()) { + throw PDNSException("empty list of forwarders for domain '" + zone + '"'); + } authDomain.d_servers.clear(); vector addresses; @@ -80,27 +78,7 @@ } } if (verbose) { - if (!g_slogStructured) { - g_log << Logger::Info << "Redirecting queries for zone '" << zone << "' "; - if (authDomain.d_rdForward) { - g_log << "with recursion "; - } - g_log << "to: "; - bool first = true; - for (const auto& address : addresses) { - if (!first) { - g_log << ", "; - } - else { - first = false; - } - g_log << address; - } - g_log << endl; - } - else { - log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(authDomain.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end())); - } + log->info(Logr::Info, "Redirecting queries", "zone", Logging::Loggable(zone), "recursion", Logging::Loggable(authDomain.d_rdForward), "addresses", Logging::IterLoggable(addresses.begin(), addresses.end())); } } @@ -112,7 +90,6 @@ string reloadZoneConfiguration(bool yaml) { - std::shared_ptr original = SyncRes::getDomainMap(); auto log = g_slog->withName("config"); string configname = ::arg()["config-dir"] + "/recursor"; @@ -122,8 +99,7 @@ cleanSlashes(configname); try { - SLOG(g_log << Logger::Warning << "Reloading zones, purging data from cache" << endl, - log->info(Logr::Notice, "Reloading zones, purging data from cache")); + log->info(Logr::Notice, "Reloading zones, purging data from cache"); if (yaml) { configname += g_yamlSettingsSuffix; @@ -199,9 +175,12 @@ oldAndNewDomains.insert(entry.first); } - if (original) { - for (const auto& entry : *original) { - oldAndNewDomains.insert(entry.first); + { + auto lock = g_initialDomainMap.lock(); + if (*lock) { + for (const auto& entry : **lock) { + oldAndNewDomains.insert(entry.first); + } } } @@ -217,27 +196,25 @@ for (const auto& entry : oldAndNewDomains) { wipeCaches(entry, true, 0xffff); } + *g_initialDomainMap.lock() = std::move(newDomainMap); + *g_initialAllowNotifyFor.lock() = std::move(newNotifySet); return "ok\n"; } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << e.what() << endl, - log->error(Logr::Error, e.what(), "Encountered error reloading zones, keeping original data")); + log->error(Logr::Error, e.what(), "Encountered error reloading zones, keeping original data"); } catch (const PDNSException& ae) { - SLOG(g_log << Logger::Error << "Encountered error reloading zones, keeping original data: " << ae.reason << endl, - log->error(Logr::Error, ae.reason, "Encountered error reloading zones, keeping original data")); + log->error(Logr::Error, ae.reason, "Encountered error reloading zones, keeping original data"); } catch (...) { - SLOG(g_log << Logger::Error << "Encountered unknown error reloading zones, keeping original data" << endl, - log->error(Logr::Error, "Exception", "Encountered error reloading zones, keeping original data")); + log->error(Logr::Error, "Exception", "Encountered error reloading zones, keeping original data"); } return "reloading failed, see log\n"; } static void readAuthZoneData(SyncRes::AuthDomain& authDomain, const pair& headers, Logr::log_t log) { - SLOG(g_log << Logger::Notice << "Parsing authoritative data for zone '" << headers.first << "' from file '" << headers.second << "'" << endl, - log->info(Logr::Notice, "Parsing authoritative data from file", "zone", Logging::Loggable(headers.first), "file", Logging::Loggable(headers.second))); + log->info(Logr::Notice, "Parsing authoritative data from file", "zone", Logging::Loggable(headers.first), "file", Logging::Loggable(headers.second)); ZoneParserTNG zpt(headers.second, DNSName(headers.first)); zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); zpt.setMaxIncludes(::arg().asNum("max-include-depth")); @@ -296,16 +273,13 @@ return; } const auto filename = ::arg()["api-config-dir"] + "/" + file; - struct stat statStruct - { - }; + struct stat statStruct{}; // It's a TOCTU, but a harmless one if (stat(filename.c_str(), &statStruct) != 0) { return; } - SLOG(g_log << Logger::Notice << "Processing ApiZones YAML settings from " << filename << endl, - log->info(Logr::Notice, "Processing ApiZones YAML settings", "path", Logging::Loggable(filename))); + log->info(Logr::Notice, "Processing ApiZones YAML settings", "path", Logging::Loggable(filename)); const uint64_t before = newMap->size(); @@ -331,12 +305,9 @@ readAuthZoneData(authDomain, {string(auth.zone), string(auth.file)}, log); (*newMap)[authDomain.d_name] = authDomain; } - SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before - << " ApiZones YAML settings from file '" - << filename << "'" << endl, - log->info(Logr::Notice, "Done parsing ApiZones YAML from file", "file", - Logging::Loggable(filename), "count", - Logging::Loggable(newMap->size() - before))); + log->info(Logr::Notice, "Done parsing ApiZones YAML from file", "file", + Logging::Loggable(filename), "count", + Logging::Loggable(newMap->size() - before)); } static void processForwardZonesFile(shared_ptr& newMap, shared_ptr& newSet, Logr::log_t log) @@ -365,8 +336,7 @@ } } else { - SLOG(g_log << Logger::Warning << "Reading zone forwarding information from '" << filename << "'" << endl, - log->info(Logr::Notice, "Reading zone forwarding information", "file", Logging::Loggable(filename))); + log->info(Logr::Notice, "Reading zone forwarding information", "file", Logging::Loggable(filename)); auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r")); if (!filePtr) { int err = errno; @@ -415,6 +385,9 @@ try { convertServersForAD(domain, instructions, authDomain, ",; ", log, false); } + catch (const PDNSException& e) { + throw PDNSException(e.reason + "on line " + std::to_string(linenum) + " of " + filename); + } catch (...) { throw PDNSException("Conversion error parsing line " + std::to_string(linenum) + " of " + filename); } @@ -426,12 +399,9 @@ } } } - SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before - << " forwarding instructions from file '" - << filename << "'" << endl, - log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file", - Logging::Loggable(filename), "count", - Logging::Loggable(newMap->size() - before))); + log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file", + Logging::Loggable(filename), "count", + Logging::Loggable(newMap->size() - before)); } static void processExportEtcHosts(std::shared_ptr& newMap, Logr::log_t log) @@ -442,8 +412,7 @@ string fname = ::arg()["etc-hosts-file"]; ifstream ifs(fname); if (!ifs) { - SLOG(g_log << Logger::Warning << "Could not open " << fname << " for reading" << endl, - log->error(Logr::Warning, "Could not open file for reading", "file", Logging::Loggable(fname))); + log->error(Logr::Warning, "Could not open file for reading", "file", Logging::Loggable(fname)); return; } vector parts; @@ -458,15 +427,10 @@ addForwardAndReverseLookupEntries(*newMap, searchSuffix, parts, log); } catch (const PDNSException& ex) { - SLOG(g_log << Logger::Warning - << "The line `" << line << "` " - << "in the provided etc-hosts file `" << fname << "` " - << "could not be added: " << ex.reason << ". Going to skip it." - << endl, - log->info(Logr::Notice, "Skipping line in etc-hosts file", - "line", Logging::Loggable(line), - "hosts-file", Logging::Loggable(fname), - "reason", Logging::Loggable(ex.reason))); + log->info(Logr::Notice, "Skipping line in etc-hosts file", + "line", Logging::Loggable(line), + "hosts-file", Logging::Loggable(fname), + "reason", Logging::Loggable(ex.reason)); } } } @@ -476,8 +440,7 @@ if (!::arg().mustDo("serve-rfc1918")) { return; } - SLOG(g_log << Logger::Warning << "Inserting rfc 1918 private space zones" << endl, - log->info(Logr::Notice, "Inserting rfc 1918 private space zones")); + log->info(Logr::Notice, "Inserting rfc 1918 private space zones"); makePartialIPZone(*newMap, {"127"}, log); makePartialIPZone(*newMap, {"10"}, log); @@ -496,8 +459,7 @@ if (!::arg().mustDo("serve-rfc1918")) { return; } - SLOG(g_log << Logger::Warning << "Inserting rfc 6303 private space zones" << endl, - log->info(Logr::Notice, "Inserting rfc 6303 private space zones")); + log->info(Logr::Notice, "Inserting rfc 6303 private space zones"); // Section 4.2 makePartialIPZone(*newMap, {"0"}, log); // makePartialIPZone(*newMap, { "127" }, log) already done in processServeRFC1918 @@ -546,8 +508,7 @@ } } else { - SLOG(g_log << Logger::Warning << "Reading NOTIFY-allowed zones from '" << filename << "'" << endl, - log->info(Logr::Notice, "Reading NOTIFY-allowed zones from file", "file", Logging::Loggable(filename))); + log->info(Logr::Notice, "Reading NOTIFY-allowed zones from file", "file", Logging::Loggable(filename)); auto filePtr = pdns::UniqueFilePtr(fopen(filename.c_str(), "r")); if (!filePtr) { throw PDNSException("Error opening allow-notify-for-file '" + filename + "': " + stringerror()); @@ -562,8 +523,7 @@ newSet->insert(DNSName(line)); } } - SLOG(g_log << Logger::Warning << "Done parsing " << newSet->size() - before << " NOTIFY-allowed zones from file '" << filename << "'" << endl, - log->info(Logr::Notice, "Done parsing NOTIFY-allowed zones from file", "file", Logging::Loggable(filename), "count", Logging::Loggable(newSet->size() - before))); + log->info(Logr::Notice, "Done parsing NOTIFY-allowed zones from file", "file", Logging::Loggable(filename), "count", Logging::Loggable(newSet->size() - before)); } std::tuple, std::shared_ptr> parseZoneConfiguration(bool yaml) diff -Nru pdns-recursor-5.2.13/remote_logger.cc pdns-recursor-5.4.9/remote_logger.cc --- pdns-recursor-5.2.13/remote_logger.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/remote_logger.cc 2026-10-26 09:46:36.000000000 +0000 @@ -5,12 +5,14 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef PDNS_CONFIG_ARGS +#ifdef RECURSOR #include "logger.hh" -#define WE_ARE_RECURSOR -#else +#else /* !RECURSOR */ #include "dolog.hh" -#endif +#if defined(DNSDIST) +#include "dnsdist-logging.hh" +#endif /* DNSDIST */ +#endif /* !RECURSOR */ #include "logging.hh" bool CircularWriteBuffer::hasRoomFor(const std::string& str) const @@ -132,11 +134,13 @@ } } catch (const std::exception& e) { -#ifdef WE_ARE_RECURSOR +#ifdef RECURSOR SLOG(g_log<withName("protobuf")->error(Logr::Error, e.what(), "Exception while connecting to remote logger", "address", Logging::Loggable(d_remote))); #else - warnlog("Error connecting to remote logger %s: %s", d_remote.toStringWithPort(), e.what()); + SLOG(warnlog("Error connecting to remote logger %s: %s", d_remote.toStringWithPort(), e.what()), + dnsdist::logging::getTopLogger("protobuf")->error(e.what(), "Exception while connecting to remote logger", "address", Logging::Loggable(d_remote)) + ); #endif return false; @@ -183,14 +187,20 @@ } runtime->d_writer.write(data); +#ifdef RECURSOR + extern bool g_regressionTestMode; + if (g_regressionTestMode) { + runtime->d_writer.flush(runtime->d_socket->getHandle()); + } +#endif ++runtime->d_stats.d_queued; return Result::Queued; } -void RemoteLogger::maintenanceThread() +void RemoteLogger::maintenanceThread() { try { -#ifdef WE_ARE_RECURSOR +#ifdef RECURSOR string threadName = "rec/remlog"; #else string threadName = "dnsdist/remLog"; @@ -239,12 +249,24 @@ } catch (const std::exception& e) { +#ifdef RECURSOR SLOG(cerr << "Remote Logger's maintenance thread died on: " << e.what() << endl, g_slog->withName("protobuf")->error(Logr::Error, e.what(), "Remote Logger's maintenance thread died")); +#else + SLOG(errlog("Remote Logger's maintenance thread died on: %s", e.what()), + dnsdist::logging::getTopLogger("protobuf")->error(e.what(), "Remote Logger's maintenance thread died") + ); +#endif } catch (...) { +#ifdef RECURSOR SLOG(cerr << "Remote Logger's maintenance thread died on unknown exception" << endl, g_slog->withName("protobuf")->info(Logr::Error, "Remote Logger's maintenance thread died")); +#else + SLOG(errlog("Remote Logger's maintenance thread died on: %s"), + dnsdist::logging::getTopLogger("protobuf")->info(Logr::Error, "Remote Logger's maintenance thread died") + ); +#endif } } @@ -254,4 +276,3 @@ d_thread.join(); } - diff -Nru pdns-recursor-5.2.13/resolve-context.hh pdns-recursor-5.4.9/resolve-context.hh --- pdns-recursor-5.2.13/resolve-context.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/resolve-context.hh 2026-10-26 08:26:51.000000000 +0000 @@ -32,8 +32,8 @@ struct ResolveContext { - ResolveContext(const boost::optional& uuid, DNSName name) : - d_initialRequestId(uuid), d_nsName(std::move(name)) + ResolveContext(const boost::optional& uuid, DNSName name, const DNSName& auth) : + d_initialRequestId(uuid), d_nsName(std::move(name)), d_auth(auth) {} ~ResolveContext() = default; @@ -44,7 +44,5 @@ boost::optional d_initialRequestId; DNSName d_nsName; -#ifdef HAVE_FSTRM - boost::optional d_auth; -#endif + DNSName d_auth; }; diff -Nru pdns-recursor-5.2.13/resolver.cc pdns-recursor-5.4.9/resolver.cc --- pdns-recursor-5.2.13/resolver.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/resolver.cc 2026-10-26 09:46:36.000000000 +0000 @@ -144,10 +144,12 @@ if(!tsigkeyname.empty()) { // cerr<<"Adding TSIG to notification, key name: '"<& zone, bool addOrRemove, const boost::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL, Logr::log_t log) +static void RPZRecordToPolicy(const DNSRecord& dnsRecord, const std::shared_ptr& zone, bool addOrRemove, const std::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL, Logr::log_t log) { static const DNSName drop("rpz-drop."); static const DNSName truncate("rpz-tcp-only."); @@ -145,10 +147,9 @@ + a child of a top level domain starting with "rpz-". */ else if (!crcTarget.empty() && !crcTarget.isRoot() && crcTarget.getRawLabel(crcTarget.countLabels() - 1).compare(0, rpzPrefix.length(), rpzPrefix) == 0) { - /* this is very likely an higher format number or a configuration error, + /* this is very likely a higher format number or a configuration error, let's just ignore it. */ - SLOG(g_log << Logger::Info << "Discarding unsupported RPZ entry " << crcTarget << " for " << dnsRecord.d_name << endl, - log->info(Logr::Info, "Discarding unsupported RPZ entry", "target", Logging::Loggable(crcTarget), "name", Logging::Loggable(dnsRecord.d_name))); + log->info(Logr::Info, "Discarding unsupported RPZ entry", "target", Logging::Loggable(crcTarget), "name", Logging::Loggable(dnsRecord.d_name)); return; } else { @@ -237,15 +238,13 @@ } } -static shared_ptr loadRPZFromServer(Logr::log_t plogger, const ComboAddress& primary, const DNSName& zoneName, const std::shared_ptr& zone, const boost::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL, const TSIGTriplet& tsigTriplet, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout) +static shared_ptr loadRPZFromServer(Logr::log_t plogger, const ComboAddress& primary, const DNSName& zoneName, const std::shared_ptr& zone, const std::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL, const TSIGTriplet& tsigTriplet, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout) { auto logger = plogger->withValues("primary", Logging::Loggable(primary)); - SLOG(g_log << Logger::Warning << "Loading RPZ zone '" << zoneName << "' from " << primary.toStringWithPort() << endl, - logger->info(Logr::Info, "Loading RPZ from nameserver")); + logger->info(Logr::Info, "Loading RPZ from nameserver"); if (!tsigTriplet.name.empty()) { - SLOG(g_log << Logger::Warning << "With TSIG key '" << tsigTriplet.name << "' of algorithm '" << tsigTriplet.algo << "'" << endl, - logger->info(Logr::Info, "Using TSIG key for authentication", "tsig_key_name", Logging::Loggable(tsigTriplet.name), "tsig_key_algorithm", Logging::Loggable(tsigTriplet.algo))); + logger->info(Logr::Info, "Using TSIG key for authentication", "tsig_key_name", Logging::Loggable(tsigTriplet.name), "tsig_key_algorithm", Logging::Loggable(tsigTriplet.algo)); } ComboAddress local(localAddress); @@ -264,7 +263,7 @@ // coverity[store_truncates_time_t] while (axfr.getChunk(nop, &chunk, (axfrStart + axfrTimeout - axfrNow)) != 0) { for (auto& dnsRecord : chunk) { - if (dnsRecord.d_type == QType::NS || dnsRecord.d_type == QType::TSIG) { + if (dnsRecord.d_type == QType::NS || dnsRecord.d_type == QType::TSIG || dnsRecord.d_type == QType::ZONEMD) { continue; } @@ -286,19 +285,15 @@ throw PDNSException("Total AXFR time exceeded!"); } if (last != time(nullptr)) { - SLOG(g_log << Logger::Info << "Loaded & indexed " << nrecords << " policy records so far for RPZ zone '" << zoneName << "'" << endl, - logger->info(Logr::Info, "RPZ load in progress", "nrecords", Logging::Loggable(nrecords))); + logger->info(Logr::Info, "RPZ load in progress", "nrecords", Logging::Loggable(nrecords)); last = time(nullptr); } } - if (!soaRecordContent) { throw PDNSException("No valid SOA found"); } - - SLOG(g_log << Logger::Info << "Done: " << nrecords << " policy records active, SOA: " << soaRecordContent->getZoneRepresentation() << endl, - logger->info(Logr::Info, "RPZ load completed", "nrecords", Logging::Loggable(nrecords), "soa", Logging::Loggable(soaRecordContent->getZoneRepresentation()))); + logger->info(Logr::Info, "RPZ load completed", "nrecords", Logging::Loggable(nrecords), "soa", Logging::Loggable(soaRecordContent->getZoneRepresentation())); return soaRecordContent; } @@ -342,7 +337,7 @@ } // this function is silent - you do the logging -std::shared_ptr loadRPZFromFile(const std::string& fname, const std::shared_ptr& zone, const boost::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL) +std::shared_ptr loadRPZFromFile(const std::string& fname, const std::shared_ptr& zone, const std::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL) { shared_ptr soaRecordContent = nullptr; ZoneParserTNG zpt(fname); @@ -364,7 +359,7 @@ zone->setDomain(domain); soaRecord = std::move(dnsRecord); } - else if (dnsRecord.d_type == QType::NS) { + else if (dnsRecord.d_type == QType::NS || dnsRecord.d_type == QType::ZONEMD) { continue; } else { @@ -385,6 +380,21 @@ return soaRecordContent; } +struct FilenameDeleter +{ + void operator()(const string* name) const noexcept + { + if (name != nullptr) { + if (!name->empty()) { + unlink(name->c_str()); + } + delete name; // NOLINT(cppcoreguidelines-owning-memory) + } + } +}; + +using UniqueFilenameDeleterPtr = std::unique_ptr; + static bool dumpZoneToDisk(Logr::log_t logger, const std::shared_ptr& newZone, const std::string& dumpZoneFileName) { logger->info(Logr::Debug, "Dumping zone to disk", "destination_file", Logging::Loggable(dumpZoneFileName)); @@ -401,11 +411,11 @@ if (newZone->getDomain() != soa.d_name) { logger->info(Logr::Error, "Inconsistency of internal name and SOA name", "zone", Logging::Loggable(newZone->getDomain()), "soaname", Logging::Loggable(soa.d_name)); } - std::string temp = dumpZoneFileName + "XXXXXX"; - int fileDesc = mkstemp(&temp.at(0)); + auto tempFile = UniqueFilenameDeleterPtr(new string(dumpZoneFileName + "XXXXXX")); + int fileDesc = mkstemp(tempFile->data()); if (fileDesc < 0) { - SLOG(g_log << Logger::Warning << "Unable to open a file to dump the content of the RPZ zone " << zoneName << endl, - logger->error(Logr::Error, errno, "Unable to create temporary file")); + logger->error(Logr::Error, errno, "Unable to create temporary file"); + tempFile->clear(); // file has not been created, no need to unlink return false; } @@ -413,8 +423,7 @@ if (!filePtr) { int err = errno; close(fileDesc); - SLOG(g_log << Logger::Warning << "Unable to open a file pointer to dump the content of the RPZ zone " << zoneName << endl, - logger->error(Logr::Error, err, "Unable to open file pointer")); + logger->error(Logr::Error, err, "Unable to open file pointer"); return false; } @@ -422,35 +431,30 @@ newZone->dump(filePtr.get()); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Error while dumping the content of the RPZ zone " << zoneName << ": " << e.what() << endl, - logger->error(Logr::Error, e.what(), "Error while dumping the content of the RPZ")); + logger->error(Logr::Error, e.what(), "Error while dumping the content of the RPZ"); return false; } if (fflush(filePtr.get()) != 0) { - SLOG(g_log << Logger::Warning << "Error while flushing the content of the RPZ zone " << zoneName << " to the dump file: " << stringerror() << endl, - logger->error(Logr::Warning, errno, "Error while flushing the content of the RPZ")); + logger->error(Logr::Warning, errno, "Error while flushing the content of the RPZ"); return false; } if (fsync(fileno(filePtr.get())) != 0) { - SLOG(g_log << Logger::Warning << "Error while syncing the content of the RPZ zone " << zoneName << " to the dump file: " << stringerror() << endl, - logger->error(Logr::Error, errno, "Error while syncing the content of the RPZ")); + logger->error(Logr::Error, errno, "Error while syncing the content of the RPZ"); return false; } if (fclose(filePtr.release()) != 0) { - SLOG(g_log << Logger::Warning << "Error while writing the content of the RPZ zone " << zoneName << " to the dump file: " << stringerror() << endl, - logger->error(Logr::Error, errno, "Error while writing the content of the RPZ")); + logger->error(Logr::Error, errno, "Error while writing the content of the RPZ"); return false; } - if (rename(temp.c_str(), dumpZoneFileName.c_str()) != 0) { - SLOG(g_log << Logger::Warning << "Error while moving the content of the RPZ zone " << zoneName << " to the dump file: " << stringerror() << endl, - logger->error(Logr::Error, errno, "Error while moving the content of the RPZ", "destination_file", Logging::Loggable(dumpZoneFileName))); + if (rename(tempFile->c_str(), dumpZoneFileName.c_str()) != 0) { + logger->error(Logr::Error, errno, "Error while moving the content of the RPZ", "destination_file", Logging::Loggable(dumpZoneFileName)); return false; } - + tempFile->clear(); // file has been renamed, no need to unlink return true; } @@ -464,7 +468,7 @@ for (const auto& primary : params.zoneXFRParams.primaries) { try { auto combo = pdns::fromNameOrIP(primary, 53, logger); - params.zoneXFRParams.soaRecordContent = loadRPZFromServer(logger, combo, zoneName, newZone, params.defpol, params.defpolOverrideLocal, params.maxTTL, params.zoneXFRParams.tsigtriplet, params.zoneXFRParams.maxReceivedMBytes, params.zoneXFRParams.localAddress, params.zoneXFRParams.xfrTimeout); + params.zoneXFRParams.soaRecordContent = loadRPZFromServer(logger, combo, zoneName, newZone, params.defpol, params.defpolOverrideLocal, params.maxTTL, params.zoneXFRParams.tsigtriplet, params.zoneXFRParams.maxReceivedMBytes * 1024U * 1024U, params.zoneXFRParams.localAddress, params.zoneXFRParams.xfrTimeout); newZone->setSerial(params.zoneXFRParams.soaRecordContent->d_st.serial); newZone->setRefresh(params.zoneXFRParams.soaRecordContent->d_st.refresh); refresh = std::max(params.zoneXFRParams.refreshFromConf != 0 ? params.zoneXFRParams.refreshFromConf : newZone->getRefresh(), 1U); @@ -482,13 +486,11 @@ break; } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Unable to load RPZ zone '" << zoneName << "' from '" << primary << "': '" << e.what() << "'. (Will try again in " << refresh << " seconds...)" << endl, - logger->error(Logr::Warning, e.what(), "Unable to load RPZ zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("std::exception"), "refresh", Logging::Loggable(refresh))); + logger->error(Logr::Warning, e.what(), "Unable to load RPZ zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("std::exception"), "refresh", Logging::Loggable(refresh)); incRPZFailedTransfers(polName); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Warning << "Unable to load RPZ zone '" << zoneName << "' from '" << primary << "': '" << e.reason << "'. (Will try again in " << refresh << " seconds...)" << endl, - logger->error(Logr::Warning, e.reason, "Unable to load RPZ zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("PDNSException"), "refresh", Logging::Loggable(refresh))); + logger->error(Logr::Warning, e.reason, "Unable to load RPZ zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("PDNSException"), "refresh", Logging::Loggable(refresh)); incRPZFailedTransfers(polName); } } @@ -543,8 +545,7 @@ /* the configuration has been reloaded, meaning that a new thread has been started to handle that zone and we are now obsolete. */ - SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl, - logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread")); + logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"); return false; } @@ -553,8 +554,7 @@ auto primary = pdns::fromNameOrIP(ipOrName, 53, logger); auto soa = getRR(dnsRecord); auto serial = soa ? soa->d_st.serial : 0; - SLOG(g_log << Logger::Info << "Getting IXFR deltas for " << zoneName << " from " << primary.toStringWithPort() << ", our serial: " << serial << endl, - logger->info(Logr::Info, "Getting IXFR deltas", "address", Logging::Loggable(primary), "ourserial", Logging::Loggable(serial))); + logger->info(Logr::Info, "Getting IXFR deltas", "address", Logging::Loggable(primary), "ourserial", Logging::Loggable(serial)); ComboAddress local(params.zoneXFRParams.localAddress); if (local == ComboAddress()) { @@ -562,14 +562,13 @@ } try { - deltas = getIXFRDeltas(primary, zoneName, dnsRecord, params.zoneXFRParams.xfrTimeout, true, params.zoneXFRParams.tsigtriplet, &local, params.zoneXFRParams.maxReceivedMBytes); + deltas = getIXFRDeltas(primary, zoneName, dnsRecord, params.zoneXFRParams.xfrTimeout, true, params.zoneXFRParams.tsigtriplet, &local, params.zoneXFRParams.maxReceivedMBytes * 1024U * 1024U); /* no need to try another primary */ break; } catch (const std::runtime_error& e) { - SLOG(g_log << Logger::Warning << e.what() << endl, - logger->error(Logr::Warning, e.what(), "Exception during retrieval of delta", "exception", Logging::Loggable("std::runtime_error"))); + logger->error(Logr::Warning, e.what(), "Exception during retrieval of delta", "exception", Logging::Loggable("std::runtime_error")); incRPZFailedTransfers(polName); continue; } @@ -580,18 +579,15 @@ } try { - SLOG(g_log << Logger::Info << "Processing " << deltas.size() << " delta" << addS(deltas) << " for RPZ " << zoneName << endl, - logger->info(Logr::Info, "Processing deltas", "size", Logging::Loggable(deltas.size()))); + logger->info(Logr::Info, "Processing deltas", "size", Logging::Loggable(deltas.size())); if (luaconfsLocal->generation != configGeneration) { - SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl, - logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread")); + logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"); return false; } oldZone = luaconfsLocal->dfe.getZone(params.zoneXFRParams.zoneIdx); if (!oldZone || oldZone->getDomain() != zoneName) { - SLOG(g_log << Logger::Info << "This policy is no more, stopping the existing RPZ update thread for " << zoneName << endl, - logger->info(Logr::Info, "This policy is no more, stopping the existing RPZ update thread")); + logger->info(Logr::Info, "This policy is no more, stopping the existing RPZ update thread"); return false; } /* we need to make a _full copy_ of the zone we are going to work on */ @@ -606,8 +602,7 @@ const auto& remove = delta.first; const auto& add = delta.second; if (remove.empty()) { - SLOG(g_log << Logger::Warning << "IXFR update is a whole new zone" << endl, - logger->info(Logr::Warning, "IXFR update is a whole new zone")); + logger->info(Logr::Warning, "IXFR update is a whole new zone"); newZone->clear(); fullUpdate = true; } @@ -629,14 +624,13 @@ } else { totremove++; - SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had removal of " << resourceRecord.d_name << " from RPZ zone " << zoneName << endl, - logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Remove from RPZ zone", "name", Logging::Loggable(resourceRecord.d_name))); + logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Remove from RPZ zone", "name", Logging::Loggable(resourceRecord.d_name)); RPZRecordToPolicy(resourceRecord, newZone, false, params.defpol, params.defpolOverrideLocal, params.maxTTL, logger); } } for (const auto& resourceRecord : add) { // should always contain the new SOA - if (resourceRecord.d_type == QType::NS) { + if (resourceRecord.d_type == QType::NS || resourceRecord.d_type == QType::ZONEMD) { continue; } if (resourceRecord.d_type == QType::SOA) { @@ -649,8 +643,7 @@ } else { totadd++; - SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had addition of " << resourceRecord.d_name << " to RPZ zone " << zoneName << endl, - logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Addition to RPZ zone", "name", Logging::Loggable(resourceRecord.d_name))); + logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Addition to RPZ zone", "name", Logging::Loggable(resourceRecord.d_name)); RPZRecordToPolicy(resourceRecord, newZone, true, params.defpol, params.defpolOverrideLocal, params.maxTTL, logger); } } @@ -661,8 +654,7 @@ newZone->setSOA(std::move(dnsRecord)); params.zoneXFRParams.soaRecordContent = std::move(currentSR); } - SLOG(g_log << Logger::Info << "Had " << totremove << " RPZ removal" << addS(totremove) << ", " << totadd << " addition" << addS(totadd) << " for " << zoneName << " New serial: " << params.soaRecordContent->d_st.serial << endl, - logger->info(Logr::Info, "RPZ mutations", "removals", Logging::Loggable(totremove), "additions", Logging::Loggable(totadd), "newserial", Logging::Loggable(params.zoneXFRParams.soaRecordContent->d_st.serial))); + logger->info(Logr::Info, "RPZ mutations", "removals", Logging::Loggable(totremove), "additions", Logging::Loggable(totadd), "newserial", Logging::Loggable(params.zoneXFRParams.soaRecordContent->d_st.serial)); newZone->setSerial(params.zoneXFRParams.soaRecordContent->d_st.serial); newZone->setRefresh(params.zoneXFRParams.soaRecordContent->d_st.refresh); setRPZZoneNewState(polName, params.zoneXFRParams.soaRecordContent->d_st.serial, newZone->size(), false, fullUpdate); @@ -672,8 +664,7 @@ since they might have been updated by another RPZ IXFR tracker thread. */ if (luaconfsLocal->generation != configGeneration) { - SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl, - logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread")); + logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"); return false; } g_luaconfs.modify([zoneIdx = params.zoneXFRParams.zoneIdx, &newZone](LuaConfigItems& lci) { @@ -686,12 +677,10 @@ refresh = std::max(params.zoneXFRParams.refreshFromConf != 0 ? params.zoneXFRParams.refreshFromConf : newZone->getRefresh(), 1U); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.what() << endl, - logger->error(Logr::Error, e.what(), "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("std::exception"))); + logger->error(Logr::Error, e.what(), "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("std::exception")); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.reason << endl, - logger->error(Logr::Error, e.reason, "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("PDNSException"))); + logger->error(Logr::Error, e.reason, "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("PDNSException")); } return true; } @@ -707,8 +696,7 @@ /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */ std::shared_ptr oldZone = g_luaconfs.getLocal()->dfe.getZone(params.zoneXFRParams.zoneIdx); if (!oldZone) { - SLOG(g_log << Logger::Error << "Unable to retrieve RPZ zone with index " << params.zoneIdx << " from the configuration, exiting" << endl, - logger->error(Logr::Error, "Unable to retrieve RPZ zone from configuration", "index", Logging::Loggable(params.zoneXFRParams.zoneIdx))); + logger->error(Logr::Error, "Unable to retrieve RPZ zone from configuration", "index", Logging::Loggable(params.zoneXFRParams.zoneIdx)); return; } diff -Nru pdns-recursor-5.2.13/rpzloader.hh pdns-recursor-5.4.9/rpzloader.hh --- pdns-recursor-5.2.13/rpzloader.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/rpzloader.hh 2026-10-26 08:26:51.000000000 +0000 @@ -31,7 +31,7 @@ struct RPZTrackerParams { ZoneXFRParams zoneXFRParams; - boost::optional defpol; + std::optional defpol; std::string defcontent; bool defpolOverrideLocal{true}; uint32_t maxTTL = std::numeric_limits::max(); @@ -45,7 +45,7 @@ bool ignoreDuplicates{false}; }; -std::shared_ptr loadRPZFromFile(const std::string& fname, const std::shared_ptr& zone, const boost::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL); +std::shared_ptr loadRPZFromFile(const std::string& fname, const std::shared_ptr& zone, const std::optional& defpol, bool defpolOverrideLocal, uint32_t maxTTL); void RPZIXFRTracker(RPZTrackerParams params, uint64_t configGeneration); struct rpzStats diff -Nru pdns-recursor-5.2.13/sanitizer.hh pdns-recursor-5.4.9/sanitizer.hh --- pdns-recursor-5.2.13/sanitizer.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/sanitizer.hh 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * 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. + */ +#pragma once + +/* 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 +#if __has_feature(address_sanitizer) +#define __SANITIZE_ADDRESS__ 1 +#endif +#endif + +#if __SANITIZE_THREAD__ +#if defined(__has_include) +#if __has_include() +#include +#else /* __has_include() */ +extern "C" void __tsan_acquire(void* addr); +extern "C" void __tsan_release(void* addr); +#endif /* __has_include() */ +#else /* defined(__has_include) */ +extern "C" void __tsan_acquire(void* addr); +extern "C" void __tsan_release(void* addr); +#endif /* defined(__has_include) */ +#else +#define __tsan_acquire(x) +#define __tsan_release(x) +#endif /* __SANITIZE_THREAD__ */ diff -Nru pdns-recursor-5.2.13/secpoll-recursor.cc pdns-recursor-5.4.9/secpoll-recursor.cc --- pdns-recursor-5.2.13/secpoll-recursor.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/secpoll-recursor.cc 2026-10-26 08:26:51.000000000 +0000 @@ -14,8 +14,7 @@ #define PACKAGEVERSION getPDNSVersion() #endif -uint32_t g_security_status; -string g_security_message; +pdns::stat_t g_security_status; void doSecPoll(time_t* last_secpoll, Logr::log_t log) { @@ -24,9 +23,7 @@ } string pkgv(PACKAGEVERSION); - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now); /* update last_secpoll right now, even if it fails @@ -49,8 +46,8 @@ qstring += '.'; } - boost::replace_all(qstring, "+", "_"); - boost::replace_all(qstring, "~", "_"); + std::replace(qstring.begin(), qstring.end(), '+', '_'); + std::replace(qstring.begin(), qstring.end(), '~', '_'); vState state = vState::Indeterminate; DNSName query(qstring); @@ -62,8 +59,7 @@ auto vlog = log->withValues("version", Logging::Loggable(pkgv), "query", Logging::Loggable(query)); if (vStateIsBogus(state)) { - SLOG(g_log << Logger::Error << "Failed to retrieve security status update for '" + pkgv + "' on '" << query << "', DNSSEC validation result was Bogus!" << endl, - vlog->info(Logr::Error, "Failed to retrieve security status update", "validationResult", Logging::Loggable(vStateToString(state)))); + vlog->info(Logr::Error, "Failed to retrieve security status update", "validationResult", Logging::Loggable(vStateToString(state))); if (g_security_status == 1) { // If we were OK, go to unknown g_security_status = 0; } @@ -71,8 +67,7 @@ } if (res == RCode::NXDomain && !isReleaseVersion(pkgv)) { - SLOG(g_log << Logger::Warning << "Not validating response for security status update, this is a non-release version" << endl, - vlog->info(Logr::Warning, "Not validating response for security status update, this is a non-release version")); + vlog->info(Logr::Warning, "Not validating response for security status update, this is a non-release version"); return; } @@ -84,25 +79,19 @@ } catch (const PDNSException& pe) { g_security_status = security_status; - SLOG(g_log << Logger::Warning << "Failed to retrieve security status update for '" << pkgv << "' on '" << query << "': " << pe.reason << endl, - vlog->error(Logr::Warning, pe.reason, "Failed to retrieve security status update")); + vlog->error(Logr::Warning, pe.reason, "Failed to retrieve security status update"); return; } - g_security_message = std::move(security_message); - - auto rlog = vlog->withValues("securitymessage", Logging::Loggable(g_security_message), "status", Logging::Loggable(security_status)); + auto rlog = vlog->withValues("securitymessage", Logging::Loggable(security_message), "status", Logging::Loggable(security_status)); if (g_security_status != 1 && security_status == 1) { - SLOG(g_log << Logger::Warning << "Polled security status of version " << pkgv << ", no known issues reported: " << g_security_message << endl, - rlog->info(Logr::Notice, "Polled security status of version, no known issues reported")); + rlog->info(Logr::Notice, "Polled security status of version, no known issues reported"); } if (security_status == 2) { - SLOG(g_log << Logger::Error << "PowerDNS Security Update Recommended: " << g_security_message << endl, - rlog->info(Logr::Error, "PowerDNS Security Update Recommended")); + rlog->info(Logr::Error, "PowerDNS Security Update Recommended"); } if (security_status == 3) { - SLOG(g_log << Logger::Error << "PowerDNS Security Update Mandatory: " << g_security_message << endl, - rlog->info(Logr::Error, "PowerDNS Security Update Mandatory")); + rlog->info(Logr::Error, "PowerDNS Security Update Mandatory"); } g_security_status = security_status; diff -Nru pdns-recursor-5.2.13/secpoll-recursor.hh pdns-recursor-5.4.9/secpoll-recursor.hh --- pdns-recursor-5.2.13/secpoll-recursor.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/secpoll-recursor.hh 2026-10-26 08:26:51.000000000 +0000 @@ -23,8 +23,8 @@ #include #include "namespaces.hh" #include "logr.hh" +#include "stat_t.hh" #include void doSecPoll(time_t*, Logr::log_t); -extern uint32_t g_security_status; -extern std::string g_security_message; +extern pdns::stat_t g_security_status; diff -Nru pdns-recursor-5.2.13/settings/Makefile.am pdns-recursor-5.4.9/settings/Makefile.am --- pdns-recursor-5.2.13/settings/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/Makefile.am 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -# It's a bit dirty that this Makefile also generates a file inside rust/src (lib.rs). - -EXTRA_DIST = \ - cxxsettings-generated.cc \ - cxxsettings-private.hh \ - cxxsettings.hh \ - docs-new-preamble-in.rst \ - docs-old-preamble-in.rst \ - generate.py \ - rust-bridge-in.rs \ - rust-preamble-in.rs \ - table.py \ - rust/src/bridge.hh \ - rust/src/lib.rs - -all: cxxsettings-generated.cc rust/src/lib.rs - -BUILT_SOURCES=cxxsettings-generated.cc rust/src/lib.rs - -# We need to clean in the Rust dir, as in some cases the Serde/CXX derive/generate code does not get -# re-run by cargo after rust/src/lib.rs changed because of a generate.py run. In that case we end up -# with an rust/src/lib.rs.h that does not contain e.g. field name or field type changes. -# -# Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make -cxxsettings-generated%cc rust/src/lib%rs: table.py generate.py rust-preamble-in.rs rust-bridge-in.rs docs-old-preamble-in.rst docs-new-preamble-in.rst - @if test "$(PYTHON)" = ":"; then echo "Settings table table.py has changed, python is needed to regenerate the related settings files but python was not found. Please install python and re-run configure"; exit 1; fi - @if ! $(PYTHON) --version | grep -q "Python 3"; then echo $(PYTHON) should be at least version 3. Please install python 3 and re-run configure; exit 1; fi - $(MAKE) -C rust clean - (cd ${srcdir} && $(PYTHON) generate.py) - -clean-local: - rm -f cxxsettings-generated.cc rust/src/lib.rs - diff -Nru pdns-recursor-5.2.13/settings/Makefile.in pdns-recursor-5.4.9/settings/Makefile.in --- pdns-recursor-5.2.13/settings/Makefile.in 2026-08-05 12:01:46.000000000 +0000 +++ pdns-recursor-5.4.9/settings/Makefile.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,604 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# It's a bit dirty that this Makefile also generates a file inside rust/src (lib.rs). -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = settings -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \ - $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ - $(top_srcdir)/m4/ax_check_sign.m4 \ - $(top_srcdir)/m4/ax_compare_version.m4 \ - $(top_srcdir)/m4/ax_compile_check_sizeof.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \ - $(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \ - $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/pdns_check_cargo.m4 \ - $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \ - $(top_srcdir)/m4/pdns_check_curl.m4 \ - $(top_srcdir)/m4/pdns_check_dnstap.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto_eddsa.m4 \ - $(top_srcdir)/m4/pdns_check_libcurl.m4 \ - $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ - $(top_srcdir)/m4/pdns_check_network_libs.m4 \ - $(top_srcdir)/m4/pdns_check_os.m4 \ - $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ - $(top_srcdir)/m4/pdns_check_python_venv.m4 \ - $(top_srcdir)/m4/pdns_check_ragel.m4 \ - $(top_srcdir)/m4/pdns_check_secure_memset.m4 \ - $(top_srcdir)/m4/pdns_check_time_t.m4 \ - $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ - $(top_srcdir)/m4/pdns_enable_coverage.m4 \ - $(top_srcdir)/m4/pdns_enable_lto.m4 \ - $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ - $(top_srcdir)/m4/pdns_enable_nod.m4 \ - $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ - $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ - $(top_srcdir)/m4/pdns_enable_tls.m4 \ - $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ - $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ - $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ - $(top_srcdir)/m4/pdns_init_auto_vars.m4 \ - $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ - $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ - $(top_srcdir)/m4/pdns_stack_protector.m4 \ - $(top_srcdir)/m4/pdns_with_libcap.m4 \ - $(top_srcdir)/m4/pdns_with_libsodium.m4 \ - $(top_srcdir)/m4/pdns_with_libssl.m4 \ - $(top_srcdir)/m4/pdns_with_lua.m4 \ - $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ - $(top_srcdir)/m4/pdns_with_service_user.m4 \ - $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -am__DIST_COMMON = $(srcdir)/Makefile.in README.md -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_CPPFLAGS = @AM_CPPFLAGS@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ -BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ -BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ -BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ -BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@ -BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@ -BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@ -BOOST_LDPATH = @BOOST_LDPATH@ -BOOST_ROOT = @BOOST_ROOT@ -BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ -BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ -BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ -BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ -BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ -BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ -BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ -BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ -BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ -CARGO = @CARGO@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ -CURL = @CURL@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -DYNLINKFLAGS = @DYNLINKFLAGS@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ETAGS = @ETAGS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FILECMD = @FILECMD@ -FSTRM_CFLAGS = @FSTRM_CFLAGS@ -FSTRM_LIBS = @FSTRM_LIBS@ -GREP = @GREP@ -HAVE_CXX17 = @HAVE_CXX17@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBCAP_CFLAGS = @LIBCAP_CFLAGS@ -LIBCAP_LIBS = @LIBCAP_LIBS@ -LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ -LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ -LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ -LIBCURL = @LIBCURL@ -LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ -LIBDL = @LIBDL@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ -LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ -LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ -LIBSSL_LIBS = @LIBSSL_LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -LUA_CFLAGS = @LUA_CFLAGS@ -LUA_LIBS = @LUA_LIBS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NET_SNMP_LIBS = @NET_SNMP_LIBS@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PIE_CFLAGS = @PIE_CFLAGS@ -PIE_LDFLAGS = @PIE_LDFLAGS@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ -PYTHON = @PYTHON@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_PLATFORM = @PYTHON_PLATFORM@ -PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_VERSION = @PYTHON_VERSION@ -RAGEL = @RAGEL@ -RANLIB = @RANLIB@ -RELRO_LDFLAGS = @RELRO_LDFLAGS@ -RT_LIBS = @RT_LIBS@ -SANITIZER_FLAGS = @SANITIZER_FLAGS@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -SYSTEMCTL = @SYSTEMCTL@ -SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ -SYSTEMD_DIR = @SYSTEMD_DIR@ -SYSTEMD_LIBS = @SYSTEMD_LIBS@ -SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ -THREADFLAGS = @THREADFLAGS@ -VERSION = @VERSION@ -WARN_CFLAGS = @WARN_CFLAGS@ -YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ -YAHTTP_LIBS = @YAHTTP_LIBS@ -_libcurl_config = @_libcurl_config@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -nodcachedir = @nodcachedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pdns_configure_args = @pdns_configure_args@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -service_group = @service_group@ -service_user = @service_user@ -sharedstatedir = @sharedstatedir@ -socketdir = @socketdir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -systemd = @systemd@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -EXTRA_DIST = \ - cxxsettings-generated.cc \ - cxxsettings-private.hh \ - cxxsettings.hh \ - docs-new-preamble-in.rst \ - docs-old-preamble-in.rst \ - generate.py \ - rust-bridge-in.rs \ - rust-preamble-in.rs \ - table.py \ - rust/src/bridge.hh \ - rust/src/lib.rs - -BUILT_SOURCES = cxxsettings-generated.cc rust/src/lib.rs -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign settings/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign settings/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am -all-am: Makefile -installdirs: -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am -install-exec: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -clean: clean-am - -clean-am: clean-generic clean-libtool clean-local mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: all check install install-am install-exec install-strip - -.PHONY: all all-am check check-am clean clean-generic clean-libtool \ - clean-local cscopelist-am ctags-am distclean distclean-generic \ - distclean-libtool distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - - -all: cxxsettings-generated.cc rust/src/lib.rs - -# We need to clean in the Rust dir, as in some cases the Serde/CXX derive/generate code does not get -# re-run by cargo after rust/src/lib.rs changed because of a generate.py run. In that case we end up -# with an rust/src/lib.rs.h that does not contain e.g. field name or field type changes. -# -# Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make -cxxsettings-generated%cc rust/src/lib%rs: table.py generate.py rust-preamble-in.rs rust-bridge-in.rs docs-old-preamble-in.rst docs-new-preamble-in.rst - @if test "$(PYTHON)" = ":"; then echo "Settings table table.py has changed, python is needed to regenerate the related settings files but python was not found. Please install python and re-run configure"; exit 1; fi - @if ! $(PYTHON) --version | grep -q "Python 3"; then echo $(PYTHON) should be at least version 3. Please install python 3 and re-run configure; exit 1; fi - $(MAKE) -C rust clean - (cd ${srcdir} && $(PYTHON) generate.py) - -clean-local: - rm -f cxxsettings-generated.cc rust/src/lib.rs - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff -Nru pdns-recursor-5.2.13/settings/README.md pdns-recursor-5.4.9/settings/README.md --- pdns-recursor-5.2.13/settings/README.md 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,227 +0,0 @@ -SETTINGS CODE -============= -This directory contains the code to generate both old-style as new style (YAML) settings code. - -Inside this directory, there is a `rust` subdirectory that contains the Rust code and build files. -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 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.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: - -* `rust`: This namespace contains the classes defined by CXX. -Note that it is sometimes needed to explicitly name it `::rust`, as the `pdns` namespace also has a subnamespace called `rust`. -* `pdns::rust::settings::rec`: The classes and functions generated by CXX, callable from C++. -* `pdns::settings::rec`: The classes and functions of the settings code implemented in C++. This is mainly the code handling the conversion of old-style definitions to new-style (and vice versa). - -Internally, the old-style settings are still used by the recursor code. -Rewriting the existing code to start using the new style settings directly would have made the PR introducing the new-style settings even bigger. -Therefore, we chose to keep the code *using* settings the same. -If a new-style settings YAML file is encountered, it will be parsed, validated and the resulting new-style settings will be used to set the old-style settings to the values found in the YAML file. -In the future, when old-style settings do not need to be supported any longer, the recursor itself can start to use the new style settings directly. - -A `rec_control show-yaml [file]` command has been added to show the conversion of old-style settings to the new-style YAML. - -This directory --------------- -* `cxxsettings-generated.cc`: generated code that implements the C++ part of the settings code. -* `cxxsettings-private.hh`: private interface used by C++ settings code internally. -* `cxxsettings.hh`: public interface of C++ code to be used by pdns_recursor and rec_control. -* `cxxsupport.cc`: hand written C++ code. -* `docs-new-preamble-in.rst`: non-generated part of new settings docs. -* `docs-old-preamble-in.rst`: non-generated part of old settings docs. -* `generate.py`: the Python script to produce C++, Rust and .rst files based on `table.py`. -* `rust`: the directory containing rust code. -* `rust-bridge-in.rs`: file included in the generated Rust code, placed inside the CXX bridge module. -* `rust-preamble-in.rs`: file included in the generated Rust code as a preamble. -* `table.py`: the definitions of all settings. - -`rust` subdirectory -------------------- -* `Cargo.toml`: The definition of the Rust `settings` crate, including its dependencies. -* `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 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. - -The YAML settings are stored in a struct called (on the C++ side) `pdns::rust::settings::rec::Recursorsettings`. -This struct has a substruct for each section defined. -Each section has multiple typed variables. -Below we will tour some parts of the (generated) code. -An example settings file in YAML format: - -```yaml -dnssec: - log_bogus: true -incoming: - listen: - - 0.0.0.0:5301 - - '[::]:5301' -logging: - common_errors: true - disable_syslog: true - loglevel: 6 -recursor: - daemon: false - extended_resolution_errors: true - socket_dir: /tmp/rec - threads: 4 -webservice: - address: 127.0.0.1 - allow_from: - - 0.0.0.0/0 - api_key: secret - port: 8083 - webserver: true -``` - -The generated code ------------------- -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`: - -```python - { - 'name' : 'log_bogus', - 'section' : 'dnssec', - 'oldname' : 'dnssec-log-bogus', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Log DNSSEC bogus validations', - 'doc' : ''' -Log every DNSSEC validation failure. -**Note**: This is not logged per-query but every time records are validated as Bogus. - ''', - }, -``` - -The old-style documentation generated for this can be found in `../docs/settings.rst`: - -``` -.. _setting-dnssec-log-bogus: - -``dnssec-log-bogus`` -~~~~~~~~~~~~~~~~~~~~ - -- Boolean -- Default: no - -- YAML setting: :ref:`setting-yaml-dnssec.log_bogus` - -Log every DNSSEC validation failure. -**Note**: This is not logged per-query but every time records are validated as Bogus. -``` - -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: - -``dnssec.log_bogus`` -^^^^^^^^^^^^^^^^^^^^ - -- Boolean -- Default: ``false`` - -- Old style setting: :ref:`setting-dnssec-log-bogus` - -Log every DNSSEC validation failure. -**Note**: This is not logged per-query but every time records are validated as Bogus. -``` - -The C++ code generated from this entry can be found in `cxxsettings-generated.cc`. -The code to define the old-style settings, which is called by the recursor very early after startup and is a replacement for the hand-written code that defines all settings in the old recursor code. -Using generated code and generated docs makes sure the docs and the actual implementation are consistent. -Something which was not true for the old code in all cases. - -```cpp -void pdns::settings::rec::defineOldStyleSettings() - ... - ::arg().setSwitch("dnssec-log-bogus", "Log DNSSEC bogus validations") = "no"; - ... -``` - -There is also code generated to assign the current value of old-style `log_bogus` value to the right field in a `Recursorsettings` struct. -This code is used to convert the currently active settings to a YAML file (`pdns_recursor --config=diff`): -```cpp -void pdns::settings::rec::oldStyleSettingsToBridgeStruct(Recursorsettings& settings) - ... - settings.dnssec.log_bogus = arg().mustDo("dnssec-log-bogus"); - ... -``` - -Plus code to set the old-style setting, given a new-style struct: - -```cpp -void pdns::settings::rec::bridgeStructToOldStyleSettings(const Recursorsettings& settings) - ... - ::arg().set("dnssec-log-bogus") = to_arg(settings.dnssec.log_bogus); - ... -``` - -Lastly, there is code to support converting a old-style settings to a new-style struct found in `pdns::settings::rec::oldKVToBridgeStruct()`. -This code is used to convert old style settings files to YAML (used by `rec_control show-yaml`) and to generate a yaml file with all the defaults values (used by `pdns_recursor --config=default`). -The functions implementing that are `pdns::settings::rec::oldStyleSettingsFileToYaml` and `std::string pdns::settings::rec::defaultsToYaml()`, found in `cxxsupport.cc`. - -The Rust code generated by `generate.py` can be found in `rust/src/lib.rs`. -It contains these snippets that define the `log_bogus` field in the section struct `Dnssec` and the `dnssec` field in the `Recursorsettings` struct: - -```rust -pub struct Dnssec { - ... - #[serde(default, skip_serializing_if = "crate::is_default")] - log_bogus: bool, - ... -} -pub struct Recursorsettings { - ... - #[serde(default, skip_serializing_if = "crate::is_default")] - dnssec: Dnssec, - ... -} -``` -The `rust/src/lib.rs` file also contains the generated code to handle Serde defaults. -More details on this can be found in `generate.py`. - -The C++ version of the `Recursorsettings` struct and its substructs can be found in the CXX generated `rust/lib.rs.h` file: - -```cpp -struct Recursorsettings final { - ... - ::pdns::rust::settings::rec::Dnssec dnssec; - ... - }; - ... -struct Dnssec final { - ... - bool log_bogus; - ... -}; -``` - -The Rust functions callable from C++ are listed in `rust-bridge-in.rs` which gets included into `rust/src/lib.rs` by `generate.py` -An example is the function - -```rust - fn parse_yaml_string(str: &String) -> Result; -``` - -Which parses YAML and produces a struct with all the settings. -Settings that are not mentioned in the YAML string will have their default value. - -`rust/lib.rs.h` contains the corresponding C++ prototype, defined in the `pdns::rust::settings::rec` namespace: - -```cpp -::pdns::rust::settings::rec::Recursorsettings parse_yaml_string(::rust::String const &str); -``` - -The C++ function `pdns::settings::rec::readYamlSettings()` defined in `cxxsupport.cc` and called in `../rec-main.cc` calls the Rust function `pdns::rust::settings::rec::parse_yaml_string()` to do the actual YAML parsing. \ No newline at end of file diff -Nru pdns-recursor-5.2.13/settings/cxxsettings-generated.cc pdns-recursor-5.4.9/settings/cxxsettings-generated.cc --- pdns-recursor-5.2.13/settings/cxxsettings-generated.cc 2026-08-05 12:02:35.000000000 +0000 +++ pdns-recursor-5.4.9/settings/cxxsettings-generated.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,2208 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir - -#include "arguments.hh" -#include "cxxsettings.hh" -#include "cxxsettings-private.hh" - -void pdns::settings::rec::defineOldStyleSettings() -{ - ::arg().set("aggressive-nsec-cache-size", "The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198") = "100000"; - ::arg().set("aggressive-cache-min-nsec3-hit-ratio", "The minimum expected hit ratio to store NSEC3 records into the aggressive cache") = "2000"; - ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse") = "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"; - ::arg().set("allow-from-file", "If set, load allowed netmasks from this file") = ""; - ::arg().set("allow-notify-for", "If set, NOTIFY requests for these zones will be allowed") = ""; - ::arg().set("allow-notify-for-file", "If set, load NOTIFY-allowed zones from this file") = ""; - ::arg().set("allow-notify-from", "If set, NOTIFY requests from these comma separated netmasks will be allowed") = ""; - ::arg().set("allow-notify-from-file", "If set, load NOTIFY-allowed netmasks from this file") = ""; - ::arg().setSwitch("allow-no-rd", "Allow 'no recursion desired (RD=0)' queries.") = "no"; - ::arg().setSwitch("any-to-tcp", "Answer ANY queries with tc=1, shunting to TCP") = "no"; - ::arg().setSwitch("allow-trust-anchor-query", "Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT") = "no"; - ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = ""; - ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = ""; - ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs") = ""; - ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates") = "30"; - ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string") = "pdns"; - ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats") = ""; - ::arg().set("carbon-instance", "If set overwrites the instance name default") = "recursor"; - ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address") = ""; - ::arg().set("chroot", "switch to chroot jail") = ""; - ::arg().set("client-tcp-timeout", "Timeout in seconds when talking to TCP clients") = "2"; - ::arg().setCmd("config", "Output blank configuration. You can use --config=check to test the config file and command line arguments."); - ::arg().set("config-dir", "Location of configuration directory (recursor.conf or recursor.yml)") = SYSCONFDIR; - ::arg().set("config-name", "Name of this virtual configuration - will rename the binary image") = ""; - ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs") = ""; - ::arg().setSwitch("daemon", "Operate as a daemon") = "no"; - ::arg().set("dont-throttle-names", "Do not throttle nameservers with this name or suffix") = ""; - ::arg().set("dont-throttle-netmasks", "Do not throttle nameservers with this IP netmask") = ""; - ::arg().setSwitch("devonly-regression-test-mode", "internal use only") = "no"; - ::arg().setSwitch("disable-packetcache", "Disable packetcache") = "no"; - ::arg().setSwitch("disable-syslog", "Disable logging to syslog, useful when running inside a supervisor that logs stderr") = "no"; - ::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads") = "0.0"; - ::arg().set("distribution-pipe-buffer-size", "Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread") = "0"; - ::arg().set("distributor-threads", "Launch this number of distributor threads, distributing queries to other threads") = "0"; - ::arg().set("dot-to-auth-names", "Use DoT to authoritative servers with these names or suffixes") = ""; - ::arg().setSwitch("dot-to-port-853", "Force DoT connection to target port 853 if DoT compiled in") = "yes"; - ::arg().set("dns64-prefix", "DNS64 prefix") = ""; - ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate") = "process"; - ::arg().set("dnssec-disabled-algorithms", "List of DNSSEC algorithm numbers that are considered unsupported") = ""; - ::arg().setSwitch("dnssec-log-bogus", "Log DNSSEC bogus validations") = "no"; - ::arg().set("dont-query", "If set, do not query these netmasks for DNS data") = "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, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32"; - ::arg().set("ecs-add-for", "List of client netmasks for which EDNS Client Subnet will be added") = "0.0.0.0/0, ::/0, !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"; - ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet") = "24"; - ::arg().set("ecs-ipv4-cache-bits", "Maximum number of bits of IPv4 mask to cache ECS response") = "24"; - ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet") = "56"; - ::arg().set("ecs-ipv6-cache-bits", "Maximum number of bits of IPv6 mask to cache ECS response") = "56"; - ::arg().setSwitch("ecs-ipv4-never-cache", "If we should never cache IPv4 ECS responses") = "no"; - ::arg().setSwitch("ecs-ipv6-never-cache", "If we should never cache IPv6 ECS responses") = "no"; - ::arg().set("ecs-minimum-ttl-override", "The minimum TTL for records in ECS-specific answers") = "1"; - ::arg().set("ecs-cache-limit-ttl", "Minimum TTL to cache ECS response") = "0"; - ::arg().set("ecs-scope-zero-address", "Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0") = ""; - ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size") = "1232"; - ::arg().set("edns-padding-from", "List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that 'edns-padding-mode' applies") = ""; - ::arg().set("edns-padding-mode", "Whether to add EDNS padding to all responses ('always') or only to responses for queries containing the EDNS padding option ('padded-queries-only', the default). In both modes, padding will only be added to responses for queries coming from 'setting-edns-padding-from' sources") = "padded-queries-only"; - ::arg().setSwitch("edns-padding-out", "Whether to add EDNS padding to outgoing DoT messages") = "yes"; - ::arg().set("edns-padding-tag", "Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.") = "7830"; - ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for (deprecated)") = ""; - ::arg().set("edns-subnet-allow-list", "List of netmasks and domains that we should enable EDNS subnet for") = ""; - ::arg().setSwitch("edns-subnet-harden", "Do more strict checking or EDNS Client Subnet information returned by authoritative servers") = "no"; - ::arg().setSwitch("enable-old-settings", "Enable (deprecated) parsing of old-style settings") = "no"; - ::arg().set("entropy-source", "If set, read entropy from this file") = "/dev/urandom"; - ::arg().set("etc-hosts-file", "Path to 'hosts' file") = "/etc/hosts"; - ::arg().set("event-trace-enabled", "If set, event traces are collected and send out via protobuf logging (1), logfile (2) or both(3)") = "0"; - ::arg().setSwitch("export-etc-hosts", "If we should serve up contents from /etc/hosts") = "no"; - ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix") = ""; - ::arg().setSwitch("extended-resolution-errors", "If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors") = "yes"; - ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs") = ""; - ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding") = ""; - ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs") = ""; - ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook") = "no"; - ::arg().setCmd("help", "Provide a helpful message"); - ::arg().set("hint-file", "If set, load root hints from this file") = ""; - ::arg().set("ignore-unknown-settings", "Configuration settings to ignore if they are unknown") = ""; - ::arg().set("include-dir", "Include settings files from this directory.") = ""; - ::arg().set("latency-statistic-size", "Number of latency values to calculate the qa-latency average") = "10000"; - ::arg().set("local-address", "IP addresses to listen on, separated by spaces or commas. Also accepts ports.") = "127.0.0.1"; - ::arg().set("local-port", "port to listen on") = "53"; - ::arg().setSwitch("log-timestamp", "Print timestamps in log lines, useful to disable when running with a tool that timestamps stderr already") = "yes"; - ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options") = "no"; - ::arg().set("loglevel", "Amount of logging. Higher is more. Do not set below 3") = "6"; - ::arg().setSwitch("log-common-errors", "If we should log rather common errors") = "no"; - ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level") = "no"; - ::arg().set("logging-facility", "Facility to log messages as. 0 corresponds to local0") = ""; - ::arg().setSwitch("lowercase-outgoing", "Force outgoing questions to lowercase") = "no"; - ::arg().set("lua-config-file", "More powerful configuration options") = ""; - ::arg().set("lua-global-include-dir", "More powerful configuration options") = ""; - ::arg().set("lua-dns-script", "Filename containing an optional Lua script that will be used to modify dns answers") = ""; - ::arg().set("lua-maintenance-interval", "Number of seconds between calls to the lua user defined maintenance() function") = "1"; - ::arg().set("max-busy-dot-probes", "Maximum number of concurrent DoT probes") = "0"; - ::arg().set("max-cache-bogus-ttl", "maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory") = "3600"; - ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache") = "1000000"; - ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory") = "86400"; - ::arg().set("max-recordcache-entry-size", "maximum storage size of a recordset stored in record cache") = "8192"; - ::arg().set("max-concurrent-requests-per-tcp-connection", "Maximum number of requests handled concurrently per TCP connection") = "10"; - ::arg().set("max-chain-length", "maximum number of queries that can be chained to an outgoing request, 0 is no limit") = "0"; - ::arg().set("max-include-depth", "Maximum nested $INCLUDE depth when loading a zone from a file") = "20"; - ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file") = "0"; - ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads") = "2048"; - ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache") = "500000"; - ::arg().set("max-packetcache-entry-size", "maximum size of a packet stored in the the packet cache") = "8192"; - ::arg().set("max-qperq", "Maximum outgoing queries per client query") = "50"; - ::arg().set("max-bytesperq", "Maximum number of received bytes per client query") = "100000"; - ::arg().set("max-cnames-followed", "Maximum number CNAME records followed") = "10"; - ::arg().setSwitch("limit-qtype-any", "Limit answers to ANY queries in size") = "yes"; - ::arg().set("max-rrset-size", "Maximum size of RRSet in cache") = "256"; - ::arg().set("max-ns-address-qperq", "Maximum outgoing NS address queries per query") = "10"; - ::arg().set("max-ns-per-resolve", "Maximum number of NS records to consider to resolve a name, 0 is no limit") = "13"; - ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory") = "3600"; - ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited") = "16"; - ::arg().set("max-tcp-clients", "Maximum number of simultaneous TCP clients") = "1024"; - ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)") = "0"; - ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection") = "0"; - ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited") = "7000"; - ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing") = "10000"; - ::arg().set("minimum-ttl-override", "The minimum TTL") = "1"; - ::arg().setSwitch("new-domain-tracking", "Track newly observed domains (i.e. never seen before).") = "no"; - ::arg().setSwitch("new-domain-log", "Log newly observed domains.") = "yes"; - ::arg().set("new-domain-lookup", "Perform a DNS lookup newly observed domains as a subdomain of the configured domain") = ""; - ::arg().set("new-domain-db-size", "Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864") = "67108864"; - ::arg().set("new-domain-history-dir", "Persist new domain tracking data here to persist between restarts") = NODCACHEDIRNOD; - ::arg().set("new-domain-db-snapshot-interval", "Interval (in seconds) to write the NOD and UDR DB snapshots") = "600"; - ::arg().set("new-domain-whitelist", "List of domains (and implicitly all subdomains) which will never be considered a new domain (deprecated)") = ""; - ::arg().set("new-domain-ignore-list", "List of domains (and implicitly all subdomains) which will never be considered a new domain") = ""; - ::arg().set("new-domain-ignore-list-file", "File with a list of domains (and implicitly all subdomains) which will never be considered a new domain") = ""; - ::arg().set("new-domain-pb-tag", "If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to 'pdns-nod'") = "pdns-nod"; - ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o") = "1500"; - ::arg().setSwitch("no-shuffle", "Don't change") = "no"; - ::arg().set("non-resolving-ns-max-fails", "Number of failed address resolves of a nameserver to start throttling it, 0 is disabled") = "5"; - ::arg().set("non-resolving-ns-throttle-time", "Number of seconds to throttle a nameserver with a name failing to resolve") = "60"; - ::arg().set("nothing-below-nxdomain", "When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)") = "dnssec"; - ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record") = "50"; - ::arg().set("max-rrsigs-per-record", "Maximum number of RRSIGs to consider when validating a given record") = "2"; - ::arg().set("max-nsec3s-per-record", "Maximum number of NSEC3s to consider when validating a given denial of existence") = "10"; - ::arg().set("max-signature-validations-per-query", "Maximum number of RRSIG signatures we are willing to validate per incoming query") = "30"; - ::arg().set("max-nsec3-hash-computations-per-query", "Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query") = "600"; - ::arg().set("aggressive-cache-max-nsec3-hash-cost", "Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache") = "150"; - ::arg().set("max-ds-per-zone", "Maximum number of DS records to consider per zone") = "8"; - ::arg().set("max-dnskeys", "Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record") = "2"; - ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache") = "86400"; - ::arg().set("packetcache-negative-ttl", "maximum number of seconds to keep a cached NxDomain or NoData entry in packetcache") = "60"; - ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache") = "60"; - ::arg().set("packetcache-shards", "Number of shards in the packet cache") = "1024"; - ::arg().setSwitch("pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads") = "no"; - ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)") = "1"; - ::arg().setSwitch("protobuf-use-kernel-timestamp", "Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)") = "no"; - ::arg().set("proxy-protocol-from", "A Proxy Protocol header is required from these subnets") = ""; - ::arg().set("proxy-protocol-exceptions", "A Proxy Protocol header should not be used for these listen addresses.") = ""; - ::arg().set("proxy-protocol-maximum-size", "The maximum size of a proxy protocol payload, including the TLV values") = "512"; - ::arg().set("public-suffix-list-file", "Path to the Public Suffix List file, if any") = ""; - ::arg().setSwitch("qname-minimization", "Use Query Name Minimization") = "yes"; - ::arg().set("qname-max-minimize-count", "RFC9156 max minimize count") = "10"; - ::arg().set("qname-minimize-one-label", "RFC9156 minimize one label parameter") = "4"; - ::arg().set("query-local-address", "Source IP address for sending queries") = "0.0.0.0"; - ::arg().setSwitch("quiet", "Suppress logging of questions and answers") = "yes"; - ::arg().set("record-cache-locked-ttl-perc", "Replace records in record cache only after this % of original TTL has passed") = "0"; - ::arg().set("record-cache-shards", "Number of shards in the record cache") = "1024"; - ::arg().set("refresh-on-ttl-perc", "If a record is requested from the cache and only this % of original TTL remains, refetch") = "0"; - ::arg().setSwitch("reuseport", "Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address") = "yes"; - ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.") = "auto"; - ::arg().setSwitch("root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist") = "yes"; - ::arg().setSwitch("save-parent-ns-set", "Save parent NS set to be used if child NS set fails") = "yes"; - ::arg().set("security-poll-suffix", "Domain name from which to query security update notifications") = "secpoll.powerdns.com."; - ::arg().setSwitch("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space") = "yes"; - ::arg().setSwitch("serve-rfc6303", "If we should be authoritative for RFC 6303 private IP space") = "yes"; - ::arg().set("serve-stale-extensions", "Number of times a record's ttl is extended by 30s to be served stale") = "0"; - ::arg().set("server-down-max-fails", "Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )") = "64"; - ::arg().set("server-down-throttle-time", "Number of seconds to throttle all queries to a server after being marked as down") = "60"; - ::arg().set("bypass-server-throttling-probability", "Determines the probability of a server marked down to be used anyway") = "25"; - ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname, set custom or 'disabled'") = "*runtime determined*"; - ::arg().set("setgid", "If set, change group id to this gid for more security") = ""; - ::arg().set("setuid", "If set, change user id to this uid for more security") = ""; - ::arg().set("signature-inception-skew", "Allow the signature inception to be off by this number of seconds") = "60"; - ::arg().setSwitch("single-socket", "If set, only use a single socket for outgoing queries") = "no"; - ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent") = "no"; - ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP daemon (deprecated)") = ""; - ::arg().set("snmp-daemon-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP daemon") = ""; - ::arg().set("soa-minimum-ttl", "Don't change") = "0"; - ::arg().set("socket-dir", "Where the controlsocket will live, /var/run/pdns-recursor when unset and not chrooted") = ""; - ::arg().set("socket-group", "Group of socket") = ""; - ::arg().set("socket-mode", "Permissions for socket") = ""; - ::arg().set("socket-owner", "Owner of socket") = ""; - ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses") = "1"; - ::arg().set("stack-cache-size", "Size of the stack cache, per mthread") = "100"; - ::arg().set("stack-size", "stack size per mthread") = "200000"; - ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable") = "1800"; - ::arg().set("stats-api-blacklist", "List of statistics that are disabled when retrieving the complete list of statistics via the API (deprecated)") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128"; - ::arg().set("stats-api-disabled-list", "List of statistics that are disabled when retrieving the complete list of statistics via the API") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128"; - ::arg().set("stats-carbon-blacklist", "List of statistics that are prevented from being exported via Carbon (deprecated)") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().set("stats-carbon-disabled-list", "List of statistics that are prevented from being exported via Carbon") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().set("stats-rec-control-blacklist", "List of statistics that are prevented from being exported via rec_control get-all (deprecated)") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().set("stats-rec-control-disabled-list", "List of statistics that are prevented from being exported via rec_control get-all") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for") = "10000"; - ::arg().set("stats-snmp-blacklist", "List of statistics that are prevented from being exported via SNMP (deprecated)") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().set("stats-snmp-disabled-list", "List of statistics that are prevented from being exported via SNMP") = "cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count"; - ::arg().setSwitch("structured-logging", "Prefer structured logging") = "yes"; - ::arg().set("structured-logging-backend", "Structured logging backend") = "default"; - ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size") = "0"; - ::arg().setSwitch("tcp-fast-open-connect", "Enable TCP Fast Open support on outgoing sockets") = "no"; - ::arg().set("tcp-out-max-idle-ms", "Time TCP/DoT connections are left idle in milliseconds or 0 if no limit") = "10000"; - ::arg().set("tcp-out-max-idle-per-auth", "Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open") = "10"; - ::arg().set("tcp-out-max-queries", "Maximum total number of queries per TCP/DoT connection, 0 means no limit") = "0"; - ::arg().set("tcp-out-max-idle-per-thread", "Maximum number of idle TCP/DoT connections per thread") = "100"; - ::arg().set("threads", "Launch this number of threads") = "2"; - ::arg().set("tcp-threads", "Launch this number of threads listening for and processing TCP queries") = "1"; - ::arg().set("trace", "if we should output heaps of logging. set to 'fail' to only log failing domains") = "no"; - ::arg().set("udp-source-port-min", "Minimum UDP port to bind on") = "1024"; - ::arg().set("udp-source-port-max", "Maximum UDP port to bind on") = "65535"; - ::arg().set("udp-source-port-avoid", "List of comma separated UDP port numbers to avoid") = "4791,11211"; - ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate") = "1232"; - ::arg().setSwitch("unique-response-tracking", "Track unique responses (tuple of query name, type and RR).") = "no"; - ::arg().setSwitch("unique-response-log", "Log unique responses") = "yes"; - ::arg().set("unique-response-db-size", "Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864") = "67108864"; - ::arg().set("unique-response-history-dir", "Persist unique response tracking data here to persist between restarts") = NODCACHEDIRUDR; - ::arg().set("unique-response-pb-tag", "If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to 'pdns-udr'") = "pdns-udr"; - ::arg().set("unique-response-ignore-list", "List of domains (and implicitly all subdomains) which will never be considered for UDR") = ""; - ::arg().set("unique-response-ignore-list-file", "File with list of domains (and implicitly all subdomains) which will never be considered for UDR") = ""; - ::arg().setSwitch("use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information") = "no"; - ::arg().setCmd("version", "Print version string"); - ::arg().set("version-string", "string reported on version.pdns or version.bind") = "*runtime determined*"; - ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no"; - ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1"; - ::arg().set("webserver-allow-from", "Webserver access is only allowed from these subnets") = "127.0.0.1, ::1"; - ::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().set("webserver-loglevel", "Amount of logging in the webserver (none, normal, detailed)") = "normal"; - ::arg().set("webserver-password", "Password required for accessing the webserver") = ""; - ::arg().set("webserver-port", "Port of webserver to listen on") = "8082"; - ::arg().setSwitch("write-pid", "Write a PID file") = "yes"; - ::arg().set("x-dnssec-names", "Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters") = ""; - ::arg().set("system-resolver-ttl", "Set TTL of system resolver feature, 0 (default) is disabled") = "0"; - ::arg().set("system-resolver-interval", "Set interval (in seconds) of the re-resolve checks of system resolver subsystem.") = "0"; - ::arg().setSwitch("system-resolver-self-resolve-check", "Check for potential self-resolve, default enabled.") = "yes"; - ::arg().set("trustanchors", "Sequence of trust anchors") = "[{name: ., dsrecords: ['20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d', '38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16']}]"; - ::arg().set("negative-trustanchors", "A sequence of negative trust anchors") = ""; - ::arg().set("trustanchorfile", "A path to a zone file containing trust anchors") = ""; - ::arg().set("trustanchorfile-interval", "Interval (in hours) to read the trust anchors file") = "24"; - ::arg().set("protobuf-servers", "Sequence of protobuf servers") = ""; - ::arg().set("outgoing-protobuf-servers", "List of outgoing protobuf servers") = ""; - ::arg().set("protobuf-mask-v4", "Network mask to apply for client IPv4 addresses in protobuf messages") = "32"; - ::arg().set("protobuf-mask-v6", "Network mask to apply for client IPv6 addresses in protobuf messages") = "128"; - ::arg().set("dnstap-framestream-servers", "Sequence of dnstap servers") = ""; - ::arg().set("dnstap-nod-framestream-servers", "Sequence of NOD dnstap servers") = ""; - ::arg().set("sortlists", "Sequence of sort lists") = ""; - ::arg().set("rpzs", "Sequence of RPZ entries") = ""; - ::arg().set("zonetocaches", "Sequence of ZoneToCache entries ") = ""; - ::arg().set("allowed-additional-qtypes", "Sequence of AllowedAdditionalQType") = ""; - ::arg().set("proxymappings", "Sequence of ProxyMapping") = ""; - ::arg().set("lua-start-stop-script", "Lua script containing functions to run on startup and shutdown") = ""; - ::arg().set("forwarding-catalog-zones", "Sequence of ForwardingCatalogZone") = ""; -} - -void pdns::settings::rec::oldStyleSettingsToBridgeStruct(Recursorsettings& settings) -{ - settings.dnssec.aggressive_nsec_cache_size = static_cast(arg().asNum("aggressive-nsec-cache-size")); - settings.dnssec.aggressive_cache_min_nsec3_hit_ratio = static_cast(arg().asNum("aggressive-cache-min-nsec3-hit-ratio")); - settings.incoming.allow_from = getStrings("allow-from"); - settings.incoming.allow_from_file = arg()["allow-from-file"]; - settings.incoming.allow_notify_for = getStrings("allow-notify-for"); - settings.incoming.allow_notify_for_file = arg()["allow-notify-for-file"]; - settings.incoming.allow_notify_from = getStrings("allow-notify-from"); - settings.incoming.allow_notify_from_file = arg()["allow-notify-from-file"]; - settings.incoming.allow_no_rd = arg().mustDo("allow-no-rd"); - settings.recursor.any_to_tcp = arg().mustDo("any-to-tcp"); - settings.recursor.allow_trust_anchor_query = arg().mustDo("allow-trust-anchor-query"); - settings.webservice.api_dir = arg()["api-config-dir"]; - settings.webservice.api_key = arg()["api-key"]; - settings.recursor.auth_zones = getAuthZones("auth-zones"); - settings.carbon.interval = static_cast(arg().asNum("carbon-interval")); - settings.carbon.ns = arg()["carbon-namespace"]; - settings.carbon.ourname = arg()["carbon-ourname"]; - settings.carbon.instance = arg()["carbon-instance"]; - settings.carbon.server = getStrings("carbon-server"); - settings.recursor.chroot = arg()["chroot"]; - settings.incoming.tcp_timeout = static_cast(arg().asNum("client-tcp-timeout")); - settings.recursor.config_dir = arg()["config-dir"]; - settings.recursor.config_name = arg()["config-name"]; - settings.recursor.cpu_map = arg()["cpu-map"]; - settings.recursor.daemon = arg().mustDo("daemon"); - settings.outgoing.dont_throttle_names = getStrings("dont-throttle-names"); - settings.outgoing.dont_throttle_netmasks = getStrings("dont-throttle-netmasks"); - settings.recursor.devonly_regression_test_mode = arg().mustDo("devonly-regression-test-mode"); - settings.packetcache.disable = arg().mustDo("disable-packetcache"); - settings.logging.disable_syslog = arg().mustDo("disable-syslog"); - settings.incoming.distribution_load_factor = arg().asDouble("distribution-load-factor"); - settings.incoming.distribution_pipe_buffer_size = static_cast(arg().asNum("distribution-pipe-buffer-size")); - settings.incoming.distributor_threads = static_cast(arg().asNum("distributor-threads")); - settings.outgoing.dot_to_auth_names = getStrings("dot-to-auth-names"); - settings.outgoing.dot_to_port_853 = arg().mustDo("dot-to-port-853"); - settings.recursor.dns64_prefix = arg()["dns64-prefix"]; - settings.dnssec.validation = arg()["dnssec"]; - settings.dnssec.disabled_algorithms = getStrings("dnssec-disabled-algorithms"); - settings.dnssec.log_bogus = arg().mustDo("dnssec-log-bogus"); - settings.outgoing.dont_query = getStrings("dont-query"); - settings.ecs.add_for = getStrings("ecs-add-for"); - settings.ecs.ipv4_bits = static_cast(arg().asNum("ecs-ipv4-bits")); - settings.ecs.ipv4_cache_bits = static_cast(arg().asNum("ecs-ipv4-cache-bits")); - settings.ecs.ipv6_bits = static_cast(arg().asNum("ecs-ipv6-bits")); - settings.ecs.ipv6_cache_bits = static_cast(arg().asNum("ecs-ipv6-cache-bits")); - settings.ecs.ipv4_never_cache = arg().mustDo("ecs-ipv4-never-cache"); - settings.ecs.ipv6_never_cache = arg().mustDo("ecs-ipv6-never-cache"); - settings.ecs.minimum_ttl_override = static_cast(arg().asNum("ecs-minimum-ttl-override")); - settings.ecs.cache_limit_ttl = static_cast(arg().asNum("ecs-cache-limit-ttl")); - settings.ecs.scope_zero_address = arg()["ecs-scope-zero-address"]; - settings.outgoing.edns_bufsize = static_cast(arg().asNum("edns-outgoing-bufsize")); - settings.incoming.edns_padding_from = getStrings("edns-padding-from"); - settings.incoming.edns_padding_mode = arg()["edns-padding-mode"]; - settings.outgoing.edns_padding = arg().mustDo("edns-padding-out"); - settings.incoming.edns_padding_tag = static_cast(arg().asNum("edns-padding-tag")); - settings.outgoing.edns_subnet_allow_list = getStrings("edns-subnet-allow-list"); - settings.outgoing.edns_subnet_harden = arg().mustDo("edns-subnet-harden"); - settings.recursor.etc_hosts_file = arg()["etc-hosts-file"]; - settings.recursor.event_trace_enabled = static_cast(arg().asNum("event-trace-enabled")); - settings.recursor.export_etc_hosts = arg().mustDo("export-etc-hosts"); - settings.recursor.export_etc_hosts_search_suffix = arg()["export-etc-hosts-search-suffix"]; - settings.recursor.extended_resolution_errors = arg().mustDo("extended-resolution-errors"); - settings.recursor.forward_zones = getForwardZones("forward-zones"); - settings.recursor.forward_zones_file = arg()["forward-zones-file"]; - settings.recursor.forward_zones_recurse = getForwardZones("forward-zones-recurse"); - settings.incoming.gettag_needs_edns_options = arg().mustDo("gettag-needs-edns-options"); - settings.recursor.hint_file = arg()["hint-file"]; - settings.recursor.ignore_unknown_settings = getStrings("ignore-unknown-settings"); - settings.recursor.include_dir = arg()["include-dir"]; - settings.recursor.latency_statistic_size = static_cast(arg().asNum("latency-statistic-size")); - settings.incoming.listen = getStrings("local-address"); - settings.incoming.port = static_cast(arg().asNum("local-port")); - settings.logging.timestamp = arg().mustDo("log-timestamp"); - settings.incoming.non_local_bind = arg().mustDo("non-local-bind"); - settings.logging.loglevel = static_cast(arg().asNum("loglevel")); - settings.logging.common_errors = arg().mustDo("log-common-errors"); - settings.logging.rpz_changes = arg().mustDo("log-rpz-changes"); - settings.logging.facility = arg()["logging-facility"]; - settings.outgoing.lowercase = arg().mustDo("lowercase-outgoing"); - settings.recursor.lua_config_file = arg()["lua-config-file"]; - settings.recursor.lua_global_include_dir = arg()["lua-global-include-dir"]; - settings.recursor.lua_dns_script = arg()["lua-dns-script"]; - settings.recursor.lua_maintenance_interval = static_cast(arg().asNum("lua-maintenance-interval")); - settings.outgoing.max_busy_dot_probes = static_cast(arg().asNum("max-busy-dot-probes")); - settings.recordcache.max_cache_bogus_ttl = static_cast(arg().asNum("max-cache-bogus-ttl")); - settings.recordcache.max_entries = static_cast(arg().asNum("max-cache-entries")); - settings.recordcache.max_ttl = static_cast(arg().asNum("max-cache-ttl")); - settings.recordcache.max_entry_size = static_cast(arg().asNum("max-recordcache-entry-size")); - settings.incoming.max_concurrent_requests_per_tcp_connection = static_cast(arg().asNum("max-concurrent-requests-per-tcp-connection")); - settings.recursor.max_chain_length = static_cast(arg().asNum("max-chain-length")); - settings.recursor.max_include_depth = static_cast(arg().asNum("max-include-depth")); - settings.recursor.max_generate_steps = static_cast(arg().asNum("max-generate-steps")); - settings.recursor.max_mthreads = static_cast(arg().asNum("max-mthreads")); - settings.packetcache.max_entries = static_cast(arg().asNum("max-packetcache-entries")); - settings.packetcache.max_entry_size = static_cast(arg().asNum("max-packetcache-entry-size")); - settings.outgoing.max_qperq = static_cast(arg().asNum("max-qperq")); - settings.outgoing.max_bytesperq = static_cast(arg().asNum("max-bytesperq")); - settings.recursor.max_cnames_followed = static_cast(arg().asNum("max-cnames-followed")); - settings.recordcache.limit_qtype_any = arg().mustDo("limit-qtype-any"); - settings.recordcache.max_rrset_size = static_cast(arg().asNum("max-rrset-size")); - settings.outgoing.max_ns_address_qperq = static_cast(arg().asNum("max-ns-address-qperq")); - settings.outgoing.max_ns_per_resolve = static_cast(arg().asNum("max-ns-per-resolve")); - settings.recordcache.max_negative_ttl = static_cast(arg().asNum("max-negative-ttl")); - settings.recursor.max_recursion_depth = static_cast(arg().asNum("max-recursion-depth")); - settings.incoming.max_tcp_clients = static_cast(arg().asNum("max-tcp-clients")); - settings.incoming.max_tcp_per_client = static_cast(arg().asNum("max-tcp-per-client")); - settings.incoming.max_tcp_queries_per_connection = static_cast(arg().asNum("max-tcp-queries-per-connection")); - settings.recursor.max_total_msec = static_cast(arg().asNum("max-total-msec")); - settings.incoming.max_udp_queries_per_round = static_cast(arg().asNum("max-udp-queries-per-round")); - settings.recursor.minimum_ttl_override = static_cast(arg().asNum("minimum-ttl-override")); - settings.nod.tracking = arg().mustDo("new-domain-tracking"); - settings.nod.log = arg().mustDo("new-domain-log"); - settings.nod.lookup = arg()["new-domain-lookup"]; - settings.nod.db_size = static_cast(arg().asNum("new-domain-db-size")); - settings.nod.history_dir = arg()["new-domain-history-dir"]; - settings.nod.db_snapshot_interval = static_cast(arg().asNum("new-domain-db-snapshot-interval")); - settings.nod.ignore_list = getStrings("new-domain-ignore-list"); - settings.nod.ignore_list_file = arg()["new-domain-ignore-list-file"]; - settings.nod.pb_tag = arg()["new-domain-pb-tag"]; - settings.outgoing.network_timeout = static_cast(arg().asNum("network-timeout")); - settings.outgoing.non_resolving_ns_max_fails = static_cast(arg().asNum("non-resolving-ns-max-fails")); - settings.outgoing.non_resolving_ns_throttle_time = static_cast(arg().asNum("non-resolving-ns-throttle-time")); - settings.recursor.nothing_below_nxdomain = arg()["nothing-below-nxdomain"]; - settings.dnssec.nsec3_max_iterations = static_cast(arg().asNum("nsec3-max-iterations")); - settings.dnssec.max_rrsigs_per_record = static_cast(arg().asNum("max-rrsigs-per-record")); - settings.dnssec.max_nsec3s_per_record = static_cast(arg().asNum("max-nsec3s-per-record")); - settings.dnssec.max_signature_validations_per_query = static_cast(arg().asNum("max-signature-validations-per-query")); - settings.dnssec.max_nsec3_hash_computations_per_query = static_cast(arg().asNum("max-nsec3-hash-computations-per-query")); - settings.dnssec.aggressive_cache_max_nsec3_hash_cost = static_cast(arg().asNum("aggressive-cache-max-nsec3-hash-cost")); - settings.dnssec.max_ds_per_zone = static_cast(arg().asNum("max-ds-per-zone")); - settings.dnssec.max_dnskeys = static_cast(arg().asNum("max-dnskeys")); - settings.packetcache.ttl = static_cast(arg().asNum("packetcache-ttl")); - settings.packetcache.negative_ttl = static_cast(arg().asNum("packetcache-negative-ttl")); - settings.packetcache.servfail_ttl = static_cast(arg().asNum("packetcache-servfail-ttl")); - settings.packetcache.shards = static_cast(arg().asNum("packetcache-shards")); - settings.incoming.pdns_distributes_queries = arg().mustDo("pdns-distributes-queries"); - settings.logging.protobuf_use_kernel_timestamp = arg().mustDo("protobuf-use-kernel-timestamp"); - settings.incoming.proxy_protocol_from = getStrings("proxy-protocol-from"); - settings.incoming.proxy_protocol_exceptions = getStrings("proxy-protocol-exceptions"); - settings.incoming.proxy_protocol_maximum_size = static_cast(arg().asNum("proxy-protocol-maximum-size")); - settings.recursor.public_suffix_list_file = arg()["public-suffix-list-file"]; - settings.recursor.qname_minimization = arg().mustDo("qname-minimization"); - settings.recursor.qname_max_minimize_count = static_cast(arg().asNum("qname-max-minimize-count")); - settings.recursor.qname_minimize_one_label = static_cast(arg().asNum("qname-minimize-one-label")); - settings.outgoing.source_address = getStrings("query-local-address"); - settings.logging.quiet = arg().mustDo("quiet"); - settings.recordcache.locked_ttl_perc = static_cast(arg().asNum("record-cache-locked-ttl-perc")); - settings.recordcache.shards = static_cast(arg().asNum("record-cache-shards")); - settings.recordcache.refresh_on_ttl_perc = static_cast(arg().asNum("refresh-on-ttl-perc")); - settings.incoming.reuseport = arg().mustDo("reuseport"); - settings.recursor.root_nx_trust = arg().mustDo("root-nx-trust"); - settings.recursor.save_parent_ns_set = arg().mustDo("save-parent-ns-set"); - settings.recursor.security_poll_suffix = arg()["security-poll-suffix"]; - settings.recursor.serve_rfc1918 = arg().mustDo("serve-rfc1918"); - settings.recursor.serve_rfc6303 = arg().mustDo("serve-rfc6303"); - settings.recordcache.serve_stale_extensions = static_cast(arg().asNum("serve-stale-extensions")); - settings.outgoing.server_down_max_fails = static_cast(arg().asNum("server-down-max-fails")); - settings.outgoing.server_down_throttle_time = static_cast(arg().asNum("server-down-throttle-time")); - settings.outgoing.bypass_server_throttling_probability = static_cast(arg().asNum("bypass-server-throttling-probability")); - settings.recursor.server_id = arg()["server-id"]; - settings.recursor.setgid = arg()["setgid"]; - settings.recursor.setuid = arg()["setuid"]; - settings.dnssec.signature_inception_skew = static_cast(arg().asNum("signature-inception-skew")); - settings.outgoing.single_socket = arg().mustDo("single-socket"); - settings.snmp.agent = arg().mustDo("snmp-agent"); - settings.snmp.daemon_socket = arg()["snmp-daemon-socket"]; - settings.recursor.socket_dir = arg()["socket-dir"]; - settings.recursor.socket_group = arg()["socket-group"]; - settings.recursor.socket_mode = arg()["socket-mode"]; - settings.recursor.socket_owner = arg()["socket-owner"]; - settings.recursor.spoof_nearmiss_max = static_cast(arg().asNum("spoof-nearmiss-max")); - settings.recursor.stack_cache_size = static_cast(arg().asNum("stack-cache-size")); - settings.recursor.stack_size = static_cast(arg().asNum("stack-size")); - settings.logging.statistics_interval = static_cast(arg().asNum("statistics-interval")); - settings.recursor.stats_api_disabled_list = getStrings("stats-api-disabled-list"); - settings.recursor.stats_carbon_disabled_list = getStrings("stats-carbon-disabled-list"); - settings.recursor.stats_rec_control_disabled_list = getStrings("stats-rec-control-disabled-list"); - settings.recursor.stats_ringbuffer_entries = static_cast(arg().asNum("stats-ringbuffer-entries")); - settings.recursor.stats_snmp_disabled_list = getStrings("stats-snmp-disabled-list"); - settings.logging.structured_logging = arg().mustDo("structured-logging"); - settings.logging.structured_logging_backend = arg()["structured-logging-backend"]; - settings.incoming.tcp_fast_open = static_cast(arg().asNum("tcp-fast-open")); - settings.outgoing.tcp_fast_open_connect = arg().mustDo("tcp-fast-open-connect"); - settings.outgoing.tcp_max_idle_ms = static_cast(arg().asNum("tcp-out-max-idle-ms")); - settings.outgoing.tcp_max_idle_per_auth = static_cast(arg().asNum("tcp-out-max-idle-per-auth")); - settings.outgoing.tcp_max_queries = static_cast(arg().asNum("tcp-out-max-queries")); - settings.outgoing.tcp_max_idle_per_thread = static_cast(arg().asNum("tcp-out-max-idle-per-thread")); - settings.recursor.threads = static_cast(arg().asNum("threads")); - settings.recursor.tcp_threads = static_cast(arg().asNum("tcp-threads")); - settings.logging.trace = arg()["trace"]; - settings.outgoing.udp_source_port_min = static_cast(arg().asNum("udp-source-port-min")); - settings.outgoing.udp_source_port_max = static_cast(arg().asNum("udp-source-port-max")); - settings.outgoing.udp_source_port_avoid = getStrings("udp-source-port-avoid"); - settings.incoming.udp_truncation_threshold = static_cast(arg().asNum("udp-truncation-threshold")); - settings.nod.unique_response_tracking = arg().mustDo("unique-response-tracking"); - settings.nod.unique_response_log = arg().mustDo("unique-response-log"); - settings.nod.unique_response_db_size = static_cast(arg().asNum("unique-response-db-size")); - settings.nod.unique_response_history_dir = arg()["unique-response-history-dir"]; - settings.nod.unique_response_pb_tag = arg()["unique-response-pb-tag"]; - settings.nod.unique_response_ignore_list = getStrings("unique-response-ignore-list"); - settings.nod.unique_response_ignore_list_file = arg()["unique-response-ignore-list-file"]; - settings.incoming.use_incoming_edns_subnet = arg().mustDo("use-incoming-edns-subnet"); - settings.recursor.version_string = arg()["version-string"]; - settings.webservice.webserver = arg().mustDo("webserver"); - settings.webservice.address = arg()["webserver-address"]; - settings.webservice.allow_from = getStrings("webserver-allow-from"); - settings.webservice.hash_plaintext_credentials = arg().mustDo("webserver-hash-plaintext-credentials"); - settings.webservice.loglevel = arg()["webserver-loglevel"]; - settings.webservice.password = arg()["webserver-password"]; - settings.webservice.port = static_cast(arg().asNum("webserver-port")); - settings.recursor.write_pid = arg().mustDo("write-pid"); - settings.dnssec.x_dnssec_names = getStrings("x-dnssec-names"); - settings.recursor.system_resolver_ttl = static_cast(arg().asNum("system-resolver-ttl")); - settings.recursor.system_resolver_interval = static_cast(arg().asNum("system-resolver-interval")); - settings.recursor.system_resolver_self_resolve_check = arg().mustDo("system-resolver-self-resolve-check"); -} - -// Inefficient, but only meant to be used for one-time conversion purposes -bool pdns::settings::rec::oldKVToBridgeStruct(std::string& key, const std::string& value, ::rust::String& section, ::rust::String& fieldname, ::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue){ // NOLINT(readability-function-cognitive-complexity) - if (const auto newname = arg().isDeprecated(key); !newname.empty()) { - key = newname; - } - if (key == "aggressive-nsec-cache-size") { - section = "dnssec"; - fieldname = "aggressive_nsec_cache_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "aggressive-cache-min-nsec3-hit-ratio") { - section = "dnssec"; - fieldname = "aggressive_cache_min_nsec3_hit_ratio"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "allow-from") { - section = "incoming"; - fieldname = "allow_from"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "allow-from-file") { - section = "incoming"; - fieldname = "allow_from_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "allow-notify-for") { - section = "incoming"; - fieldname = "allow_notify_for"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "allow-notify-for-file") { - section = "incoming"; - fieldname = "allow_notify_for_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "allow-notify-from") { - section = "incoming"; - fieldname = "allow_notify_from"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "allow-notify-from-file") { - section = "incoming"; - fieldname = "allow_notify_from_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "allow-no-rd") { - section = "incoming"; - fieldname = "allow_no_rd"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "any-to-tcp") { - section = "recursor"; - fieldname = "any_to_tcp"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "allow-trust-anchor-query") { - section = "recursor"; - fieldname = "allow_trust_anchor_query"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "api-config-dir") { - section = "webservice"; - fieldname = "api_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "api-key") { - section = "webservice"; - fieldname = "api_key"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "auth-zones") { - section = "recursor"; - fieldname = "auth_zones"; - type_name = "Vec"; - to_yaml(rustvalue.vec_authzone_val, value); - return true; - } - if (key == "carbon-interval") { - section = "carbon"; - fieldname = "interval"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "carbon-namespace") { - section = "carbon"; - fieldname = "ns"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "carbon-ourname") { - section = "carbon"; - fieldname = "ourname"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "carbon-instance") { - section = "carbon"; - fieldname = "instance"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "carbon-server") { - section = "carbon"; - fieldname = "server"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "chroot") { - section = "recursor"; - fieldname = "chroot"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "client-tcp-timeout") { - section = "incoming"; - fieldname = "tcp_timeout"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "config-dir") { - section = "recursor"; - fieldname = "config_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "config-name") { - section = "recursor"; - fieldname = "config_name"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "cpu-map") { - section = "recursor"; - fieldname = "cpu_map"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "daemon") { - section = "recursor"; - fieldname = "daemon"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "dont-throttle-names") { - section = "outgoing"; - fieldname = "dont_throttle_names"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "dont-throttle-netmasks") { - section = "outgoing"; - fieldname = "dont_throttle_netmasks"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "devonly-regression-test-mode") { - section = "recursor"; - fieldname = "devonly_regression_test_mode"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "disable-packetcache") { - section = "packetcache"; - fieldname = "disable"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "disable-syslog") { - section = "logging"; - fieldname = "disable_syslog"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "distribution-load-factor") { - section = "incoming"; - fieldname = "distribution_load_factor"; - type_name = "f64"; - to_yaml(rustvalue.f64_val, value); - return true; - } - if (key == "distribution-pipe-buffer-size") { - section = "incoming"; - fieldname = "distribution_pipe_buffer_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "distributor-threads") { - section = "incoming"; - fieldname = "distributor_threads"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "dot-to-auth-names") { - section = "outgoing"; - fieldname = "dot_to_auth_names"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "dot-to-port-853") { - section = "outgoing"; - fieldname = "dot_to_port_853"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "dns64-prefix") { - section = "recursor"; - fieldname = "dns64_prefix"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "dnssec") { - section = "dnssec"; - fieldname = "validation"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "dnssec-disabled-algorithms") { - section = "dnssec"; - fieldname = "disabled_algorithms"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "dnssec-log-bogus") { - section = "dnssec"; - fieldname = "log_bogus"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "dont-query") { - section = "outgoing"; - fieldname = "dont_query"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "ecs-add-for") { - section = "ecs"; - fieldname = "add_for"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "ecs-ipv4-bits") { - section = "ecs"; - fieldname = "ipv4_bits"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-ipv4-cache-bits") { - section = "ecs"; - fieldname = "ipv4_cache_bits"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-ipv6-bits") { - section = "ecs"; - fieldname = "ipv6_bits"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-ipv6-cache-bits") { - section = "ecs"; - fieldname = "ipv6_cache_bits"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-ipv4-never-cache") { - section = "ecs"; - fieldname = "ipv4_never_cache"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "ecs-ipv6-never-cache") { - section = "ecs"; - fieldname = "ipv6_never_cache"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "ecs-minimum-ttl-override") { - section = "ecs"; - fieldname = "minimum_ttl_override"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-cache-limit-ttl") { - section = "ecs"; - fieldname = "cache_limit_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "ecs-scope-zero-address") { - section = "ecs"; - fieldname = "scope_zero_address"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "edns-outgoing-bufsize") { - section = "outgoing"; - fieldname = "edns_bufsize"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "edns-padding-from") { - section = "incoming"; - fieldname = "edns_padding_from"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "edns-padding-mode") { - section = "incoming"; - fieldname = "edns_padding_mode"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "edns-padding-out") { - section = "outgoing"; - fieldname = "edns_padding"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "edns-padding-tag") { - section = "incoming"; - fieldname = "edns_padding_tag"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "edns-subnet-allow-list") { - section = "outgoing"; - fieldname = "edns_subnet_allow_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "edns-subnet-harden") { - section = "outgoing"; - fieldname = "edns_subnet_harden"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "etc-hosts-file") { - section = "recursor"; - fieldname = "etc_hosts_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "event-trace-enabled") { - section = "recursor"; - fieldname = "event_trace_enabled"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "export-etc-hosts") { - section = "recursor"; - fieldname = "export_etc_hosts"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "export-etc-hosts-search-suffix") { - section = "recursor"; - fieldname = "export_etc_hosts_search_suffix"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "extended-resolution-errors") { - section = "recursor"; - fieldname = "extended_resolution_errors"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "forward-zones") { - section = "recursor"; - fieldname = "forward_zones"; - type_name = "Vec"; - to_yaml(rustvalue.vec_forwardzone_val, value); - return true; - } - if (key == "forward-zones-file") { - section = "recursor"; - fieldname = "forward_zones_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "forward-zones-recurse") { - section = "recursor"; - fieldname = "forward_zones_recurse"; - type_name = "Vec"; - to_yaml(rustvalue.vec_forwardzone_val, value, true); - return true; - } - if (key == "gettag-needs-edns-options") { - section = "incoming"; - fieldname = "gettag_needs_edns_options"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "hint-file") { - section = "recursor"; - fieldname = "hint_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "ignore-unknown-settings") { - section = "recursor"; - fieldname = "ignore_unknown_settings"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "include-dir") { - section = "recursor"; - fieldname = "include_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "latency-statistic-size") { - section = "recursor"; - fieldname = "latency_statistic_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "local-address") { - section = "incoming"; - fieldname = "listen"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "local-port") { - section = "incoming"; - fieldname = "port"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "log-timestamp") { - section = "logging"; - fieldname = "timestamp"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "non-local-bind") { - section = "incoming"; - fieldname = "non_local_bind"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "loglevel") { - section = "logging"; - fieldname = "loglevel"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "log-common-errors") { - section = "logging"; - fieldname = "common_errors"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "log-rpz-changes") { - section = "logging"; - fieldname = "rpz_changes"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "logging-facility") { - section = "logging"; - fieldname = "facility"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "lowercase-outgoing") { - section = "outgoing"; - fieldname = "lowercase"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "lua-config-file") { - section = "recursor"; - fieldname = "lua_config_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "lua-global-include-dir") { - section = "recursor"; - fieldname = "lua_global_include_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "lua-dns-script") { - section = "recursor"; - fieldname = "lua_dns_script"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "lua-maintenance-interval") { - section = "recursor"; - fieldname = "lua_maintenance_interval"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-busy-dot-probes") { - section = "outgoing"; - fieldname = "max_busy_dot_probes"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-cache-bogus-ttl") { - section = "recordcache"; - fieldname = "max_cache_bogus_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-cache-entries") { - section = "recordcache"; - fieldname = "max_entries"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-cache-ttl") { - section = "recordcache"; - fieldname = "max_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-recordcache-entry-size") { - section = "recordcache"; - fieldname = "max_entry_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-concurrent-requests-per-tcp-connection") { - section = "incoming"; - fieldname = "max_concurrent_requests_per_tcp_connection"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-chain-length") { - section = "recursor"; - fieldname = "max_chain_length"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-include-depth") { - section = "recursor"; - fieldname = "max_include_depth"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-generate-steps") { - section = "recursor"; - fieldname = "max_generate_steps"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-mthreads") { - section = "recursor"; - fieldname = "max_mthreads"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-packetcache-entries") { - section = "packetcache"; - fieldname = "max_entries"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-packetcache-entry-size") { - section = "packetcache"; - fieldname = "max_entry_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-qperq") { - section = "outgoing"; - fieldname = "max_qperq"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-bytesperq") { - section = "outgoing"; - fieldname = "max_bytesperq"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-cnames-followed") { - section = "recursor"; - fieldname = "max_cnames_followed"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "limit-qtype-any") { - section = "recordcache"; - fieldname = "limit_qtype_any"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "max-rrset-size") { - section = "recordcache"; - fieldname = "max_rrset_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-ns-address-qperq") { - section = "outgoing"; - fieldname = "max_ns_address_qperq"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-ns-per-resolve") { - section = "outgoing"; - fieldname = "max_ns_per_resolve"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-negative-ttl") { - section = "recordcache"; - fieldname = "max_negative_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-recursion-depth") { - section = "recursor"; - fieldname = "max_recursion_depth"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-tcp-clients") { - section = "incoming"; - fieldname = "max_tcp_clients"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-tcp-per-client") { - section = "incoming"; - fieldname = "max_tcp_per_client"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-tcp-queries-per-connection") { - section = "incoming"; - fieldname = "max_tcp_queries_per_connection"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-total-msec") { - section = "recursor"; - fieldname = "max_total_msec"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-udp-queries-per-round") { - section = "incoming"; - fieldname = "max_udp_queries_per_round"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "minimum-ttl-override") { - section = "recursor"; - fieldname = "minimum_ttl_override"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "new-domain-tracking") { - section = "nod"; - fieldname = "tracking"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "new-domain-log") { - section = "nod"; - fieldname = "log"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "new-domain-lookup") { - section = "nod"; - fieldname = "lookup"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "new-domain-db-size") { - section = "nod"; - fieldname = "db_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "new-domain-history-dir") { - section = "nod"; - fieldname = "history_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "new-domain-db-snapshot-interval") { - section = "nod"; - fieldname = "db_snapshot_interval"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "new-domain-ignore-list") { - section = "nod"; - fieldname = "ignore_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "new-domain-ignore-list-file") { - section = "nod"; - fieldname = "ignore_list_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "new-domain-pb-tag") { - section = "nod"; - fieldname = "pb_tag"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "network-timeout") { - section = "outgoing"; - fieldname = "network_timeout"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "non-resolving-ns-max-fails") { - section = "outgoing"; - fieldname = "non_resolving_ns_max_fails"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "non-resolving-ns-throttle-time") { - section = "outgoing"; - fieldname = "non_resolving_ns_throttle_time"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "nothing-below-nxdomain") { - section = "recursor"; - fieldname = "nothing_below_nxdomain"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "nsec3-max-iterations") { - section = "dnssec"; - fieldname = "nsec3_max_iterations"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-rrsigs-per-record") { - section = "dnssec"; - fieldname = "max_rrsigs_per_record"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-nsec3s-per-record") { - section = "dnssec"; - fieldname = "max_nsec3s_per_record"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-signature-validations-per-query") { - section = "dnssec"; - fieldname = "max_signature_validations_per_query"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-nsec3-hash-computations-per-query") { - section = "dnssec"; - fieldname = "max_nsec3_hash_computations_per_query"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "aggressive-cache-max-nsec3-hash-cost") { - section = "dnssec"; - fieldname = "aggressive_cache_max_nsec3_hash_cost"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-ds-per-zone") { - section = "dnssec"; - fieldname = "max_ds_per_zone"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "max-dnskeys") { - section = "dnssec"; - fieldname = "max_dnskeys"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "packetcache-ttl") { - section = "packetcache"; - fieldname = "ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "packetcache-negative-ttl") { - section = "packetcache"; - fieldname = "negative_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "packetcache-servfail-ttl") { - section = "packetcache"; - fieldname = "servfail_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "packetcache-shards") { - section = "packetcache"; - fieldname = "shards"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "pdns-distributes-queries") { - section = "incoming"; - fieldname = "pdns_distributes_queries"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "protobuf-use-kernel-timestamp") { - section = "logging"; - fieldname = "protobuf_use_kernel_timestamp"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "proxy-protocol-from") { - section = "incoming"; - fieldname = "proxy_protocol_from"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "proxy-protocol-exceptions") { - section = "incoming"; - fieldname = "proxy_protocol_exceptions"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "proxy-protocol-maximum-size") { - section = "incoming"; - fieldname = "proxy_protocol_maximum_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "public-suffix-list-file") { - section = "recursor"; - fieldname = "public_suffix_list_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "qname-minimization") { - section = "recursor"; - fieldname = "qname_minimization"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "qname-max-minimize-count") { - section = "recursor"; - fieldname = "qname_max_minimize_count"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "qname-minimize-one-label") { - section = "recursor"; - fieldname = "qname_minimize_one_label"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "query-local-address") { - section = "outgoing"; - fieldname = "source_address"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "quiet") { - section = "logging"; - fieldname = "quiet"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "record-cache-locked-ttl-perc") { - section = "recordcache"; - fieldname = "locked_ttl_perc"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "record-cache-shards") { - section = "recordcache"; - fieldname = "shards"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "refresh-on-ttl-perc") { - section = "recordcache"; - fieldname = "refresh_on_ttl_perc"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "reuseport") { - section = "incoming"; - fieldname = "reuseport"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "root-nx-trust") { - section = "recursor"; - fieldname = "root_nx_trust"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "save-parent-ns-set") { - section = "recursor"; - fieldname = "save_parent_ns_set"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "security-poll-suffix") { - section = "recursor"; - fieldname = "security_poll_suffix"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "serve-rfc1918") { - section = "recursor"; - fieldname = "serve_rfc1918"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "serve-rfc6303") { - section = "recursor"; - fieldname = "serve_rfc6303"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "serve-stale-extensions") { - section = "recordcache"; - fieldname = "serve_stale_extensions"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "server-down-max-fails") { - section = "outgoing"; - fieldname = "server_down_max_fails"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "server-down-throttle-time") { - section = "outgoing"; - fieldname = "server_down_throttle_time"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "bypass-server-throttling-probability") { - section = "outgoing"; - fieldname = "bypass_server_throttling_probability"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "server-id") { - section = "recursor"; - fieldname = "server_id"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "setgid") { - section = "recursor"; - fieldname = "setgid"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "setuid") { - section = "recursor"; - fieldname = "setuid"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "signature-inception-skew") { - section = "dnssec"; - fieldname = "signature_inception_skew"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "single-socket") { - section = "outgoing"; - fieldname = "single_socket"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "snmp-agent") { - section = "snmp"; - fieldname = "agent"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "snmp-daemon-socket") { - section = "snmp"; - fieldname = "daemon_socket"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "socket-dir") { - section = "recursor"; - fieldname = "socket_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "socket-group") { - section = "recursor"; - fieldname = "socket_group"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "socket-mode") { - section = "recursor"; - fieldname = "socket_mode"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "socket-owner") { - section = "recursor"; - fieldname = "socket_owner"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "spoof-nearmiss-max") { - section = "recursor"; - fieldname = "spoof_nearmiss_max"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "stack-cache-size") { - section = "recursor"; - fieldname = "stack_cache_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "stack-size") { - section = "recursor"; - fieldname = "stack_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "statistics-interval") { - section = "logging"; - fieldname = "statistics_interval"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "stats-api-disabled-list") { - section = "recursor"; - fieldname = "stats_api_disabled_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "stats-carbon-disabled-list") { - section = "recursor"; - fieldname = "stats_carbon_disabled_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "stats-rec-control-disabled-list") { - section = "recursor"; - fieldname = "stats_rec_control_disabled_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "stats-ringbuffer-entries") { - section = "recursor"; - fieldname = "stats_ringbuffer_entries"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "stats-snmp-disabled-list") { - section = "recursor"; - fieldname = "stats_snmp_disabled_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "structured-logging") { - section = "logging"; - fieldname = "structured_logging"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "structured-logging-backend") { - section = "logging"; - fieldname = "structured_logging_backend"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "tcp-fast-open") { - section = "incoming"; - fieldname = "tcp_fast_open"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "tcp-fast-open-connect") { - section = "outgoing"; - fieldname = "tcp_fast_open_connect"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "tcp-out-max-idle-ms") { - section = "outgoing"; - fieldname = "tcp_max_idle_ms"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "tcp-out-max-idle-per-auth") { - section = "outgoing"; - fieldname = "tcp_max_idle_per_auth"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "tcp-out-max-queries") { - section = "outgoing"; - fieldname = "tcp_max_queries"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "tcp-out-max-idle-per-thread") { - section = "outgoing"; - fieldname = "tcp_max_idle_per_thread"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "threads") { - section = "recursor"; - fieldname = "threads"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "tcp-threads") { - section = "recursor"; - fieldname = "tcp_threads"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "trace") { - section = "logging"; - fieldname = "trace"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "udp-source-port-min") { - section = "outgoing"; - fieldname = "udp_source_port_min"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "udp-source-port-max") { - section = "outgoing"; - fieldname = "udp_source_port_max"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "udp-source-port-avoid") { - section = "outgoing"; - fieldname = "udp_source_port_avoid"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "udp-truncation-threshold") { - section = "incoming"; - fieldname = "udp_truncation_threshold"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "unique-response-tracking") { - section = "nod"; - fieldname = "unique_response_tracking"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "unique-response-log") { - section = "nod"; - fieldname = "unique_response_log"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "unique-response-db-size") { - section = "nod"; - fieldname = "unique_response_db_size"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "unique-response-history-dir") { - section = "nod"; - fieldname = "unique_response_history_dir"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "unique-response-pb-tag") { - section = "nod"; - fieldname = "unique_response_pb_tag"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "unique-response-ignore-list") { - section = "nod"; - fieldname = "unique_response_ignore_list"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "unique-response-ignore-list-file") { - section = "nod"; - fieldname = "unique_response_ignore_list_file"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "use-incoming-edns-subnet") { - section = "incoming"; - fieldname = "use_incoming_edns_subnet"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "version-string") { - section = "recursor"; - fieldname = "version_string"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "webserver") { - section = "webservice"; - fieldname = "webserver"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "webserver-address") { - section = "webservice"; - fieldname = "address"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "webserver-allow-from") { - section = "webservice"; - fieldname = "allow_from"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "webserver-hash-plaintext-credentials") { - section = "webservice"; - fieldname = "hash_plaintext_credentials"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "webserver-loglevel") { - section = "webservice"; - fieldname = "loglevel"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "webserver-password") { - section = "webservice"; - fieldname = "password"; - type_name = "String"; - to_yaml(rustvalue.string_val, value); - return true; - } - if (key == "webserver-port") { - section = "webservice"; - fieldname = "port"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "write-pid") { - section = "recursor"; - fieldname = "write_pid"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - if (key == "x-dnssec-names") { - section = "dnssec"; - fieldname = "x_dnssec_names"; - type_name = "Vec"; - to_yaml(rustvalue.vec_string_val, value); - return true; - } - if (key == "system-resolver-ttl") { - section = "recursor"; - fieldname = "system_resolver_ttl"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "system-resolver-interval") { - section = "recursor"; - fieldname = "system_resolver_interval"; - type_name = "u64"; - to_yaml(rustvalue.u64_val, value); - return true; - } - if (key == "system-resolver-self-resolve-check") { - section = "recursor"; - fieldname = "system_resolver_self_resolve_check"; - type_name = "bool"; - to_yaml(rustvalue.bool_val, value); - return true; - } - return false; -} - -void pdns::settings::rec::bridgeStructToOldStyleSettings(const Recursorsettings& settings) -{ - ::arg().set("aggressive-nsec-cache-size") = to_arg(settings.dnssec.aggressive_nsec_cache_size); - ::arg().set("aggressive-cache-min-nsec3-hit-ratio") = to_arg(settings.dnssec.aggressive_cache_min_nsec3_hit_ratio); - ::arg().set("allow-from") = to_arg(settings.incoming.allow_from); - ::arg().set("allow-from-file") = to_arg(settings.incoming.allow_from_file); - ::arg().set("allow-notify-for") = to_arg(settings.incoming.allow_notify_for); - ::arg().set("allow-notify-for-file") = to_arg(settings.incoming.allow_notify_for_file); - ::arg().set("allow-notify-from") = to_arg(settings.incoming.allow_notify_from); - ::arg().set("allow-notify-from-file") = to_arg(settings.incoming.allow_notify_from_file); - ::arg().set("allow-no-rd") = to_arg(settings.incoming.allow_no_rd); - ::arg().set("any-to-tcp") = to_arg(settings.recursor.any_to_tcp); - ::arg().set("allow-trust-anchor-query") = to_arg(settings.recursor.allow_trust_anchor_query); - ::arg().set("api-config-dir") = to_arg(settings.webservice.api_dir); - ::arg().set("api-key") = to_arg(settings.webservice.api_key); - ::arg().set("auth-zones") = to_arg(settings.recursor.auth_zones); - ::arg().set("carbon-interval") = to_arg(settings.carbon.interval); - ::arg().set("carbon-namespace") = to_arg(settings.carbon.ns); - ::arg().set("carbon-ourname") = to_arg(settings.carbon.ourname); - ::arg().set("carbon-instance") = to_arg(settings.carbon.instance); - ::arg().set("carbon-server") = to_arg(settings.carbon.server); - ::arg().set("chroot") = to_arg(settings.recursor.chroot); - ::arg().set("client-tcp-timeout") = to_arg(settings.incoming.tcp_timeout); - ::arg().set("config-dir") = to_arg(settings.recursor.config_dir); - ::arg().set("config-name") = to_arg(settings.recursor.config_name); - ::arg().set("cpu-map") = to_arg(settings.recursor.cpu_map); - ::arg().set("daemon") = to_arg(settings.recursor.daemon); - ::arg().set("dont-throttle-names") = to_arg(settings.outgoing.dont_throttle_names); - ::arg().set("dont-throttle-netmasks") = to_arg(settings.outgoing.dont_throttle_netmasks); - ::arg().set("devonly-regression-test-mode") = to_arg(settings.recursor.devonly_regression_test_mode); - ::arg().set("disable-packetcache") = to_arg(settings.packetcache.disable); - ::arg().set("disable-syslog") = to_arg(settings.logging.disable_syslog); - ::arg().set("distribution-load-factor") = to_arg(settings.incoming.distribution_load_factor); - ::arg().set("distribution-pipe-buffer-size") = to_arg(settings.incoming.distribution_pipe_buffer_size); - ::arg().set("distributor-threads") = to_arg(settings.incoming.distributor_threads); - ::arg().set("dot-to-auth-names") = to_arg(settings.outgoing.dot_to_auth_names); - ::arg().set("dot-to-port-853") = to_arg(settings.outgoing.dot_to_port_853); - ::arg().set("dns64-prefix") = to_arg(settings.recursor.dns64_prefix); - ::arg().set("dnssec") = to_arg(settings.dnssec.validation); - ::arg().set("dnssec-disabled-algorithms") = to_arg(settings.dnssec.disabled_algorithms); - ::arg().set("dnssec-log-bogus") = to_arg(settings.dnssec.log_bogus); - ::arg().set("dont-query") = to_arg(settings.outgoing.dont_query); - ::arg().set("ecs-add-for") = to_arg(settings.ecs.add_for); - ::arg().set("ecs-ipv4-bits") = to_arg(settings.ecs.ipv4_bits); - ::arg().set("ecs-ipv4-cache-bits") = to_arg(settings.ecs.ipv4_cache_bits); - ::arg().set("ecs-ipv6-bits") = to_arg(settings.ecs.ipv6_bits); - ::arg().set("ecs-ipv6-cache-bits") = to_arg(settings.ecs.ipv6_cache_bits); - ::arg().set("ecs-ipv4-never-cache") = to_arg(settings.ecs.ipv4_never_cache); - ::arg().set("ecs-ipv6-never-cache") = to_arg(settings.ecs.ipv6_never_cache); - ::arg().set("ecs-minimum-ttl-override") = to_arg(settings.ecs.minimum_ttl_override); - ::arg().set("ecs-cache-limit-ttl") = to_arg(settings.ecs.cache_limit_ttl); - ::arg().set("ecs-scope-zero-address") = to_arg(settings.ecs.scope_zero_address); - ::arg().set("edns-outgoing-bufsize") = to_arg(settings.outgoing.edns_bufsize); - ::arg().set("edns-padding-from") = to_arg(settings.incoming.edns_padding_from); - ::arg().set("edns-padding-mode") = to_arg(settings.incoming.edns_padding_mode); - ::arg().set("edns-padding-out") = to_arg(settings.outgoing.edns_padding); - ::arg().set("edns-padding-tag") = to_arg(settings.incoming.edns_padding_tag); - ::arg().set("edns-subnet-allow-list") = to_arg(settings.outgoing.edns_subnet_allow_list); - ::arg().set("edns-subnet-harden") = to_arg(settings.outgoing.edns_subnet_harden); - ::arg().set("etc-hosts-file") = to_arg(settings.recursor.etc_hosts_file); - ::arg().set("event-trace-enabled") = to_arg(settings.recursor.event_trace_enabled); - ::arg().set("export-etc-hosts") = to_arg(settings.recursor.export_etc_hosts); - ::arg().set("export-etc-hosts-search-suffix") = to_arg(settings.recursor.export_etc_hosts_search_suffix); - ::arg().set("extended-resolution-errors") = to_arg(settings.recursor.extended_resolution_errors); - ::arg().set("forward-zones") = to_arg(settings.recursor.forward_zones); - ::arg().set("forward-zones-file") = to_arg(settings.recursor.forward_zones_file); - ::arg().set("forward-zones-recurse") = to_arg(settings.recursor.forward_zones_recurse); - ::arg().set("gettag-needs-edns-options") = to_arg(settings.incoming.gettag_needs_edns_options); - ::arg().set("hint-file") = to_arg(settings.recursor.hint_file); - ::arg().set("ignore-unknown-settings") = to_arg(settings.recursor.ignore_unknown_settings); - ::arg().set("include-dir") = to_arg(settings.recursor.include_dir); - ::arg().set("latency-statistic-size") = to_arg(settings.recursor.latency_statistic_size); - ::arg().set("local-address") = to_arg(settings.incoming.listen); - ::arg().set("local-port") = to_arg(settings.incoming.port); - ::arg().set("log-timestamp") = to_arg(settings.logging.timestamp); - ::arg().set("non-local-bind") = to_arg(settings.incoming.non_local_bind); - ::arg().set("loglevel") = to_arg(settings.logging.loglevel); - ::arg().set("log-common-errors") = to_arg(settings.logging.common_errors); - ::arg().set("log-rpz-changes") = to_arg(settings.logging.rpz_changes); - ::arg().set("logging-facility") = to_arg(settings.logging.facility); - ::arg().set("lowercase-outgoing") = to_arg(settings.outgoing.lowercase); - ::arg().set("lua-config-file") = to_arg(settings.recursor.lua_config_file); - ::arg().set("lua-global-include-dir") = to_arg(settings.recursor.lua_global_include_dir); - ::arg().set("lua-dns-script") = to_arg(settings.recursor.lua_dns_script); - ::arg().set("lua-maintenance-interval") = to_arg(settings.recursor.lua_maintenance_interval); - ::arg().set("max-busy-dot-probes") = to_arg(settings.outgoing.max_busy_dot_probes); - ::arg().set("max-cache-bogus-ttl") = to_arg(settings.recordcache.max_cache_bogus_ttl); - ::arg().set("max-cache-entries") = to_arg(settings.recordcache.max_entries); - ::arg().set("max-cache-ttl") = to_arg(settings.recordcache.max_ttl); - ::arg().set("max-recordcache-entry-size") = to_arg(settings.recordcache.max_entry_size); - ::arg().set("max-concurrent-requests-per-tcp-connection") = to_arg(settings.incoming.max_concurrent_requests_per_tcp_connection); - ::arg().set("max-chain-length") = to_arg(settings.recursor.max_chain_length); - ::arg().set("max-include-depth") = to_arg(settings.recursor.max_include_depth); - ::arg().set("max-generate-steps") = to_arg(settings.recursor.max_generate_steps); - ::arg().set("max-mthreads") = to_arg(settings.recursor.max_mthreads); - ::arg().set("max-packetcache-entries") = to_arg(settings.packetcache.max_entries); - ::arg().set("max-packetcache-entry-size") = to_arg(settings.packetcache.max_entry_size); - ::arg().set("max-qperq") = to_arg(settings.outgoing.max_qperq); - ::arg().set("max-bytesperq") = to_arg(settings.outgoing.max_bytesperq); - ::arg().set("max-cnames-followed") = to_arg(settings.recursor.max_cnames_followed); - ::arg().set("limit-qtype-any") = to_arg(settings.recordcache.limit_qtype_any); - ::arg().set("max-rrset-size") = to_arg(settings.recordcache.max_rrset_size); - ::arg().set("max-ns-address-qperq") = to_arg(settings.outgoing.max_ns_address_qperq); - ::arg().set("max-ns-per-resolve") = to_arg(settings.outgoing.max_ns_per_resolve); - ::arg().set("max-negative-ttl") = to_arg(settings.recordcache.max_negative_ttl); - ::arg().set("max-recursion-depth") = to_arg(settings.recursor.max_recursion_depth); - ::arg().set("max-tcp-clients") = to_arg(settings.incoming.max_tcp_clients); - ::arg().set("max-tcp-per-client") = to_arg(settings.incoming.max_tcp_per_client); - ::arg().set("max-tcp-queries-per-connection") = to_arg(settings.incoming.max_tcp_queries_per_connection); - ::arg().set("max-total-msec") = to_arg(settings.recursor.max_total_msec); - ::arg().set("max-udp-queries-per-round") = to_arg(settings.incoming.max_udp_queries_per_round); - ::arg().set("minimum-ttl-override") = to_arg(settings.recursor.minimum_ttl_override); - ::arg().set("new-domain-tracking") = to_arg(settings.nod.tracking); - ::arg().set("new-domain-log") = to_arg(settings.nod.log); - ::arg().set("new-domain-lookup") = to_arg(settings.nod.lookup); - ::arg().set("new-domain-db-size") = to_arg(settings.nod.db_size); - ::arg().set("new-domain-history-dir") = to_arg(settings.nod.history_dir); - ::arg().set("new-domain-db-snapshot-interval") = to_arg(settings.nod.db_snapshot_interval); - ::arg().set("new-domain-ignore-list") = to_arg(settings.nod.ignore_list); - ::arg().set("new-domain-ignore-list-file") = to_arg(settings.nod.ignore_list_file); - ::arg().set("new-domain-pb-tag") = to_arg(settings.nod.pb_tag); - ::arg().set("network-timeout") = to_arg(settings.outgoing.network_timeout); - ::arg().set("non-resolving-ns-max-fails") = to_arg(settings.outgoing.non_resolving_ns_max_fails); - ::arg().set("non-resolving-ns-throttle-time") = to_arg(settings.outgoing.non_resolving_ns_throttle_time); - ::arg().set("nothing-below-nxdomain") = to_arg(settings.recursor.nothing_below_nxdomain); - ::arg().set("nsec3-max-iterations") = to_arg(settings.dnssec.nsec3_max_iterations); - ::arg().set("max-rrsigs-per-record") = to_arg(settings.dnssec.max_rrsigs_per_record); - ::arg().set("max-nsec3s-per-record") = to_arg(settings.dnssec.max_nsec3s_per_record); - ::arg().set("max-signature-validations-per-query") = to_arg(settings.dnssec.max_signature_validations_per_query); - ::arg().set("max-nsec3-hash-computations-per-query") = to_arg(settings.dnssec.max_nsec3_hash_computations_per_query); - ::arg().set("aggressive-cache-max-nsec3-hash-cost") = to_arg(settings.dnssec.aggressive_cache_max_nsec3_hash_cost); - ::arg().set("max-ds-per-zone") = to_arg(settings.dnssec.max_ds_per_zone); - ::arg().set("max-dnskeys") = to_arg(settings.dnssec.max_dnskeys); - ::arg().set("packetcache-ttl") = to_arg(settings.packetcache.ttl); - ::arg().set("packetcache-negative-ttl") = to_arg(settings.packetcache.negative_ttl); - ::arg().set("packetcache-servfail-ttl") = to_arg(settings.packetcache.servfail_ttl); - ::arg().set("packetcache-shards") = to_arg(settings.packetcache.shards); - ::arg().set("pdns-distributes-queries") = to_arg(settings.incoming.pdns_distributes_queries); - ::arg().set("protobuf-use-kernel-timestamp") = to_arg(settings.logging.protobuf_use_kernel_timestamp); - ::arg().set("proxy-protocol-from") = to_arg(settings.incoming.proxy_protocol_from); - ::arg().set("proxy-protocol-exceptions") = to_arg(settings.incoming.proxy_protocol_exceptions); - ::arg().set("proxy-protocol-maximum-size") = to_arg(settings.incoming.proxy_protocol_maximum_size); - ::arg().set("public-suffix-list-file") = to_arg(settings.recursor.public_suffix_list_file); - ::arg().set("qname-minimization") = to_arg(settings.recursor.qname_minimization); - ::arg().set("qname-max-minimize-count") = to_arg(settings.recursor.qname_max_minimize_count); - ::arg().set("qname-minimize-one-label") = to_arg(settings.recursor.qname_minimize_one_label); - ::arg().set("query-local-address") = to_arg(settings.outgoing.source_address); - ::arg().set("quiet") = to_arg(settings.logging.quiet); - ::arg().set("record-cache-locked-ttl-perc") = to_arg(settings.recordcache.locked_ttl_perc); - ::arg().set("record-cache-shards") = to_arg(settings.recordcache.shards); - ::arg().set("refresh-on-ttl-perc") = to_arg(settings.recordcache.refresh_on_ttl_perc); - ::arg().set("reuseport") = to_arg(settings.incoming.reuseport); - ::arg().set("root-nx-trust") = to_arg(settings.recursor.root_nx_trust); - ::arg().set("save-parent-ns-set") = to_arg(settings.recursor.save_parent_ns_set); - ::arg().set("security-poll-suffix") = to_arg(settings.recursor.security_poll_suffix); - ::arg().set("serve-rfc1918") = to_arg(settings.recursor.serve_rfc1918); - ::arg().set("serve-rfc6303") = to_arg(settings.recursor.serve_rfc6303); - ::arg().set("serve-stale-extensions") = to_arg(settings.recordcache.serve_stale_extensions); - ::arg().set("server-down-max-fails") = to_arg(settings.outgoing.server_down_max_fails); - ::arg().set("server-down-throttle-time") = to_arg(settings.outgoing.server_down_throttle_time); - ::arg().set("bypass-server-throttling-probability") = to_arg(settings.outgoing.bypass_server_throttling_probability); - ::arg().set("server-id") = to_arg(settings.recursor.server_id); - ::arg().set("setgid") = to_arg(settings.recursor.setgid); - ::arg().set("setuid") = to_arg(settings.recursor.setuid); - ::arg().set("signature-inception-skew") = to_arg(settings.dnssec.signature_inception_skew); - ::arg().set("single-socket") = to_arg(settings.outgoing.single_socket); - ::arg().set("snmp-agent") = to_arg(settings.snmp.agent); - ::arg().set("snmp-daemon-socket") = to_arg(settings.snmp.daemon_socket); - ::arg().set("socket-dir") = to_arg(settings.recursor.socket_dir); - ::arg().set("socket-group") = to_arg(settings.recursor.socket_group); - ::arg().set("socket-mode") = to_arg(settings.recursor.socket_mode); - ::arg().set("socket-owner") = to_arg(settings.recursor.socket_owner); - ::arg().set("spoof-nearmiss-max") = to_arg(settings.recursor.spoof_nearmiss_max); - ::arg().set("stack-cache-size") = to_arg(settings.recursor.stack_cache_size); - ::arg().set("stack-size") = to_arg(settings.recursor.stack_size); - ::arg().set("statistics-interval") = to_arg(settings.logging.statistics_interval); - ::arg().set("stats-api-disabled-list") = to_arg(settings.recursor.stats_api_disabled_list); - ::arg().set("stats-carbon-disabled-list") = to_arg(settings.recursor.stats_carbon_disabled_list); - ::arg().set("stats-rec-control-disabled-list") = to_arg(settings.recursor.stats_rec_control_disabled_list); - ::arg().set("stats-ringbuffer-entries") = to_arg(settings.recursor.stats_ringbuffer_entries); - ::arg().set("stats-snmp-disabled-list") = to_arg(settings.recursor.stats_snmp_disabled_list); - ::arg().set("structured-logging") = to_arg(settings.logging.structured_logging); - ::arg().set("structured-logging-backend") = to_arg(settings.logging.structured_logging_backend); - ::arg().set("tcp-fast-open") = to_arg(settings.incoming.tcp_fast_open); - ::arg().set("tcp-fast-open-connect") = to_arg(settings.outgoing.tcp_fast_open_connect); - ::arg().set("tcp-out-max-idle-ms") = to_arg(settings.outgoing.tcp_max_idle_ms); - ::arg().set("tcp-out-max-idle-per-auth") = to_arg(settings.outgoing.tcp_max_idle_per_auth); - ::arg().set("tcp-out-max-queries") = to_arg(settings.outgoing.tcp_max_queries); - ::arg().set("tcp-out-max-idle-per-thread") = to_arg(settings.outgoing.tcp_max_idle_per_thread); - ::arg().set("threads") = to_arg(settings.recursor.threads); - ::arg().set("tcp-threads") = to_arg(settings.recursor.tcp_threads); - ::arg().set("trace") = to_arg(settings.logging.trace); - ::arg().set("udp-source-port-min") = to_arg(settings.outgoing.udp_source_port_min); - ::arg().set("udp-source-port-max") = to_arg(settings.outgoing.udp_source_port_max); - ::arg().set("udp-source-port-avoid") = to_arg(settings.outgoing.udp_source_port_avoid); - ::arg().set("udp-truncation-threshold") = to_arg(settings.incoming.udp_truncation_threshold); - ::arg().set("unique-response-tracking") = to_arg(settings.nod.unique_response_tracking); - ::arg().set("unique-response-log") = to_arg(settings.nod.unique_response_log); - ::arg().set("unique-response-db-size") = to_arg(settings.nod.unique_response_db_size); - ::arg().set("unique-response-history-dir") = to_arg(settings.nod.unique_response_history_dir); - ::arg().set("unique-response-pb-tag") = to_arg(settings.nod.unique_response_pb_tag); - ::arg().set("unique-response-ignore-list") = to_arg(settings.nod.unique_response_ignore_list); - ::arg().set("unique-response-ignore-list-file") = to_arg(settings.nod.unique_response_ignore_list_file); - ::arg().set("use-incoming-edns-subnet") = to_arg(settings.incoming.use_incoming_edns_subnet); - ::arg().set("version-string") = to_arg(settings.recursor.version_string); - ::arg().set("webserver") = to_arg(settings.webservice.webserver); - ::arg().set("webserver-address") = to_arg(settings.webservice.address); - ::arg().set("webserver-allow-from") = to_arg(settings.webservice.allow_from); - ::arg().set("webserver-hash-plaintext-credentials") = to_arg(settings.webservice.hash_plaintext_credentials); - ::arg().set("webserver-loglevel") = to_arg(settings.webservice.loglevel); - ::arg().set("webserver-password") = to_arg(settings.webservice.password); - ::arg().set("webserver-port") = to_arg(settings.webservice.port); - ::arg().set("write-pid") = to_arg(settings.recursor.write_pid); - ::arg().set("x-dnssec-names") = to_arg(settings.dnssec.x_dnssec_names); - ::arg().set("system-resolver-ttl") = to_arg(settings.recursor.system_resolver_ttl); - ::arg().set("system-resolver-interval") = to_arg(settings.recursor.system_resolver_interval); - ::arg().set("system-resolver-self-resolve-check") = to_arg(settings.recursor.system_resolver_self_resolve_check); -} diff -Nru pdns-recursor-5.2.13/settings/cxxsettings-private.hh pdns-recursor-5.4.9/settings/cxxsettings-private.hh --- pdns-recursor-5.2.13/settings/cxxsettings-private.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/cxxsettings-private.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +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 -#include -#include -#include - -#include "rust/lib.rs.h" -#include "misc.hh" - -using pdns::rust::settings::rec::AuthZone; -using pdns::rust::settings::rec::ForwardZone; -using pdns::rust::settings::rec::Recursorsettings; - -namespace pdns::settings::rec -{ -::rust::Vec<::rust::String> getStrings(const std::string& name); -::rust::Vec getForwardZones(const std::string& name); -::rust::Vec getAuthZones(const std::string& name); - -inline std::string to_arg(bool arg) -{ - return arg ? "yes" : "no"; -} - -inline std::string to_arg(uint64_t arg) -{ - return std::to_string(arg); -} - -inline std::string to_arg(double arg) -{ - return std::to_string(arg); -} - -inline std::string to_arg(const ::rust::String& str) -{ - return std::string(str); -} - -std::string to_arg(const AuthZone& authzone); -std::string to_arg(const ForwardZone& forwardzone); - -template -std::string to_arg(const ::rust::Vec& vec) -{ - std::ostringstream str; - for (auto iter = vec.begin(); iter != vec.end(); ++iter) { - if (iter != vec.begin()) { - str << ','; - } - str << to_arg(*iter); - } - return str.str(); -} - -inline void to_yaml(bool& field, const std::string& val) -{ - field = val != "no" && val != "off"; -} - -inline void to_yaml(::rust::String& field, const std::string& val) -{ - field = val; -} - -inline void to_yaml(::rust::Vec<::rust::String>& field, const std::string& val) -{ - stringtok(field, val, ", ;"); -} - -void to_yaml(uint64_t& field, const std::string& val); -void to_yaml(double& field, const std::string& val); -void to_yaml(::rust::Vec& field, const std::string& val); -void to_yaml(::rust::Vec& field, const std::string& val, bool recurse = false); -} diff -Nru pdns-recursor-5.2.13/settings/cxxsettings.hh pdns-recursor-5.4.9/settings/cxxsettings.hh --- pdns-recursor-5.2.13/settings/cxxsettings.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/cxxsettings.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +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 -#include "rust/cxx.h" -#include "rust/lib.rs.h" -#include "sholder.hh" -#include "logging.hh" -#include "rec-lua-conf.hh" - -namespace pdns::settings::rec -{ -enum YamlSettingsStatus : uint8_t -{ - OK, - CannotOpen, - PresentButFailed, -}; - -void defineOldStyleSettings(); -void oldStyleSettingsToBridgeStruct(pdns::rust::settings::rec::Recursorsettings& settings); -void oldStyleForwardsFileToBridgeStruct(const std::string& filename, ::rust::Vec& vec); -void oldStyleAllowFileToBridgeStruct(const std::string& filename, ::rust::Vec<::rust::String>& vec); -bool oldKVToBridgeStruct(string& key, const string& value, ::rust::String& section, ::rust::String& fieldname, ::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue); -std::string oldStyleSettingsFileToYaml(const string& fname, bool mainFile); -std::string defaultsToYaml(); -YamlSettingsStatus readYamlSettings(const std::string& configname, const std::string& includeDirOnCommandLine, rust::settings::rec::Recursorsettings& settings, std::string& msg, Logr::log_t log); -void processAPIDir(const string& includeDirOnCommandLine, pdns::rust::settings::rec::Recursorsettings& settings, Logr::log_t log); -void bridgeStructToOldStyleSettings(const pdns::rust::settings::rec::Recursorsettings& settings); -void readYamlForwardZonesFile(const std::string& filename, ::rust::Vec& vec, Logr::log_t log); -void readYamlAllowFromFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log); -void readYamlAllowNotifyForFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log); -void setArgsForZoneRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings); -void setArgsForACLRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings); -void fromLuaConfigToBridgeStruct(LuaConfigItems& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings); -void fromBridgeStructToLuaConfig(const pdns::rust::settings::rec::Recursorsettings& settings, LuaConfigItems& luaConfig, ProxyMapping& proxyMapping); -bool luaItemSet(const pdns::rust::settings::rec::Recursorsettings& settings); -YamlSettingsStatus tryReadYAML(const string& yamlconfigname, bool setGlobals, bool& yamlSettings, bool& luaSettingsInYAML, rust::settings::rec::Recursorsettings& settings, Logr::log_t startupLog); -} diff -Nru pdns-recursor-5.2.13/settings/cxxsupport.cc pdns-recursor-5.4.9/settings/cxxsupport.cc --- pdns-recursor-5.2.13/settings/cxxsupport.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/cxxsupport.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1455 +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 -#include -#include -#include -#include - -#include "namespaces.hh" -#include "arguments.hh" -#include "misc.hh" -#include "cxxsettings.hh" -#include "cxxsettings-private.hh" -#include "logger.hh" -#include "logging.hh" -#include "rec-lua-conf.hh" -#include "root-dnssec.hh" -#include "dnsrecords.hh" -#include "base64.hh" -#include "validate-recursor.hh" - -::rust::Vec<::rust::String> pdns::settings::rec::getStrings(const std::string& name) -{ - ::rust::Vec<::rust::String> vec; - to_yaml(vec, arg()[name]); - return vec; -} - -::rust::Vec pdns::settings::rec::getForwardZones(const string& name) -{ - ::rust::Vec vec; - const auto recurse = name == "forward-zones-recurse"; - to_yaml(vec, arg()[name], recurse); - return vec; -} - -::rust::Vec pdns::settings::rec::getAuthZones(const string& name) -{ - ::rust::Vec vec; - to_yaml(vec, arg()[name]); - return vec; -} - -void pdns::settings::rec::oldStyleForwardsFileToBridgeStruct(const std::string& file, ::rust::Vec& vec) -{ - auto filePtr = pdns::UniqueFilePtr(fopen(file.c_str(), "r")); - if (!filePtr) { - throw PDNSException("Error opening forward-zones-file '" + file + "': " + stringerror()); - } - - string line; - int linenum = 0; - while (linenum++, stringfgets(filePtr.get(), line)) { - boost::trim(line); - if (line.length() == 0 || line.at(0) == '#') { // Comment line, skip to the next line - continue; - } - auto [domain, instructions] = splitField(line, '='); - instructions = splitField(instructions, '#').first; // Remove EOL comments - boost::trim(domain); - boost::trim(instructions); - if (domain.empty() || instructions.empty()) { - throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + file); - } - bool allowNotify = false; - bool recurse = false; - for (; !domain.empty(); domain.erase(0, 1)) { - switch (domain[0]) { - case '+': - recurse = true; - continue; - case '^': - allowNotify = true; - continue; - } - break; - } - if (domain.empty()) { - throw PDNSException("Error parsing line " + std::to_string(linenum) + " of " + file); - } - ::rust::Vec<::rust::String> addresses; - stringtok(addresses, instructions, ",; "); - ForwardZone forwardzone{domain, std::move(addresses), recurse, allowNotify}; - vec.push_back(std::move(forwardzone)); - } -} - -void pdns::settings::rec::oldStyleAllowFileToBridgeStruct(const std::string& file, ::rust::Vec<::rust::String>& vec) -{ - string line; - ifstream ifs(file); - if (!ifs) { - int err = errno; - throw runtime_error("Could not open '" + file + "': " + stringerror(err)); - } - - while (getline(ifs, line)) { - auto pos = line.find('#'); - if (pos != string::npos) { - line.resize(pos); - } - boost::trim(line); - if (line.empty()) { - continue; - } - vec.emplace_back(line); - } -} - -static void mergeYamlSubFile(const std::string& configname, Recursorsettings& settings, bool allowabsent, Logr::log_t log) -{ - auto file = ifstream(configname); - if (!file.is_open()) { - if (allowabsent) { - return; - } - throw runtime_error("Cannot open " + configname); - } - SLOG(g_log << Logger::Notice << "Processing YAML settings from " << configname << endl, - log->info(Logr::Notice, "Processing YAML settings", "path", Logging::Loggable(configname))); - auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - pdns::rust::settings::rec::merge(settings, data); -} - -static void possiblyConvertACLFile(const string& includeDir, const string& apiDir, const std::string& filename, Logr::log_t log) -{ - auto path = includeDir; - path.append("/").append(filename).append(".conf"); - auto file = ifstream(path); - if (!file.is_open()) { - // Not an error, file just is not there - return; - } - rust::vec result; - std::string line; - while (getline(file, line)) { - auto pos = line.find('#'); - if (pos != string::npos) { - line.resize(pos); - } - boost::trim(line); - if (line.empty()) { - continue; - } - auto plusis = line.find("+="); - if (plusis != string::npos) { - auto val = line.substr(plusis + 2); - boost::trim(val); - vector acls; - stringtok(acls, val, " ,\t"); - for (const auto& acl : acls) { - result.emplace_back(acl); - } - } - } - - rust::string key = "allow_from"; - rust::string filekey = "allow_from_file"; - if (filename == "allow-notify-from") { - key = "allow_notify_from"; - filekey = "allow_notify_from_file"; - } - const auto yaml = pdns::rust::settings::rec::allow_from_to_yaml_string_incoming(key, filekey, result); - - string yamlfilename = apiDir; - yamlfilename.append("/").append(filename).append(".yml"); - string tmpfilename = yamlfilename + ".tmp"; - ofstream ofconf(tmpfilename); - if (!ofconf) { - int err = errno; - log->error(Logr::Error, err, "Cannot open for file for writing YAML", "to", Logging::Loggable(tmpfilename)); - throw runtime_error("YAML Conversion"); - } - ofconf << "# Generated by pdns-recursor REST API, DO NOT EDIT" << endl; - ofconf << yaml << endl; - ofconf.close(); - if (ofconf.bad()) { - log->error(Logr::Error, "Error writing YAML", "to", Logging::Loggable(tmpfilename)); - unlink(tmpfilename.c_str()); - throw runtime_error("YAML Conversion"); - } - if (rename(path.c_str(), (path + ".converted").c_str()) != 0) { - int err = errno; - log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path), "to", Logging::Loggable(path + ".converted")); - unlink(tmpfilename.c_str()); - throw runtime_error("YAML Conversion"); - } - - if (rename(tmpfilename.c_str(), yamlfilename.c_str()) != 0) { - int err = errno; - log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(tmpfilename), "to", Logging::Loggable(yamlfilename)); - if (rename((path + ".converted").c_str(), path.c_str()) != 0) { - err = errno; - log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(path + ".converted"), "to", Logging::Loggable(path)); - } - throw runtime_error("YAML Conversion"); - } - log->info(Logr::Notice, "Converted to YAML", "file", Logging::Loggable(path), "to", Logging::Loggable(yamlfilename)); -} - -static void fileCopy(const string& src, const string& dst, Logr::log_t log) -{ - ifstream ifconf(src); - if (!ifconf) { - log->info(Logr::Error, "Cannot open for file for reading", "file", Logging::Loggable(src)); - throw runtime_error("YAML Conversion"); - } - ofstream ofconf(dst); - if (!ofconf) { - log->info(Logr::Error, "Cannot open for file for writing YAML", "to", Logging::Loggable(dst)); - throw runtime_error("YAML Conversion"); - } - for (;;) { - auto character = ifconf.get(); - if (ifconf.eof()) { - break; - } - if (ifconf.bad()) { - int err = errno; - log->error(Logr::Error, err, "Error reading", "to", Logging::Loggable(src)); - throw runtime_error("YAML Conversion"); - } - ofconf.put(static_cast(character)); - if (ofconf.bad()) { - int err = errno; - log->error(Logr::Error, err, "Error writing YAML", "to", Logging::Loggable(dst)); - throw runtime_error("YAML Conversion"); - } - } - ifconf.close(); - ofconf.close(); - if (ofconf.bad()) { - log->error(Logr::Error, "Error writing YAML", "to", Logging::Loggable(dst)); - throw runtime_error("YAML Conversion"); - } -} - -static void possiblyConvertForwardsandAuths(const std::string& includeDir, const std::string& apiDir, Logr::log_t log) -{ - std::vector forwAndAuthFiles{}; - ::arg().gatherIncludes(includeDir, "..conf", forwAndAuthFiles); - pdns::rust::settings::rec::Recursorsettings settings{}; - for (const auto& file : forwAndAuthFiles) { - auto yaml = pdns::settings::rec::oldStyleSettingsFileToYaml(file, false); - pdns::rust::settings::rec::merge(settings, yaml); - } - const string yamlAPiZonesFile = apiDir + "/apizones"; - - for (auto& zone : settings.recursor.auth_zones) { - const std::string origName(zone.file); - std::string newName(zone.file); - newName.replace(0, includeDir.length(), apiDir); - log->info(Logr::Notice, "Copying auth zone file", "file", Logging::Loggable(origName), "to", Logging::Loggable(newName)); - fileCopy(origName, newName, log); - zone.file = ::rust::String(newName); - api_add_auth_zone(yamlAPiZonesFile, zone); - } - api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones); - api_add_forward_zones(yamlAPiZonesFile, settings.recursor.forward_zones_recurse); - for (const auto& file : forwAndAuthFiles) { - if (rename(file.c_str(), (file + ".converted").c_str()) != 0) { - int err = errno; - log->error(Logr::Error, err, "Rename failed", "file", Logging::Loggable(file), "to", Logging::Loggable(file + ".converted")); - } - } -} - -void pdns::settings::rec::processAPIDir(const string& includeDirOnCommandLine, pdns::rust::settings::rec::Recursorsettings& settings, Logr::log_t log) -{ - auto apiDir = std::string(settings.webservice.api_dir); - if (apiDir.empty()) { - return; - } - auto includeDir = std::string(settings.recursor.include_dir); - if (!includeDirOnCommandLine.empty()) { - includeDir = includeDirOnCommandLine; - } - if (includeDir == apiDir) { - throw runtime_error("Active YAML settings do not allow include_dir to be equal to api_dir"); - } - const std::array aclFiles = { - "allow-from", - "allow-notify-from"}; - for (const auto& file : aclFiles) { - possiblyConvertACLFile(includeDir, apiDir, file, log); - auto path = apiDir; - path.append("/").append(file).append(".yml"); - mergeYamlSubFile(path, settings, true, log); - } - possiblyConvertForwardsandAuths(includeDir, apiDir, log); -} - -template -static void addToAllowNotifyFor(Recursorsettings& settings, const rust::Vec& vec) -{ - for (const auto& item : vec) { - if (item.notify_allowed) { - settings.incoming.allow_notify_for.emplace_back(item.zone); - } - } -} - -pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::readYamlSettings(const std::string& configname, const std::string& includeDirOnCommandLine, Recursorsettings& settings, std::string& msg, Logr::log_t log) -{ - auto file = ifstream(configname); - if (!file.is_open()) { - msg = stringerror(errno); - return YamlSettingsStatus::CannotOpen; - } - SLOG(g_log << Logger::Notice << "Processing main YAML settings from " << configname << endl, - log->info(Logr::Notice, "Processing main YAML settings", "path", Logging::Loggable(configname))); - try { - auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - auto yamlstruct = pdns::rust::settings::rec::parse_yaml_string(data); - std::vector yamlFiles; - ::arg().gatherIncludes(!includeDirOnCommandLine.empty() ? includeDirOnCommandLine : string(yamlstruct.recursor.include_dir), - ".yml", yamlFiles); - for (const auto& yamlfile : yamlFiles) { - mergeYamlSubFile(yamlfile, yamlstruct, false, log); - } - // Add the zones with notify_allowed to allow_notify_for. For a forward_zones_file that will be - // taken care of elsewhere. One drawback: the zones will be shown in allow_notify_for if you - // run --config, while they aren't actually there in any config file. - addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forward_zones); - addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forward_zones_recurse); - addToAllowNotifyFor(yamlstruct, yamlstruct.recursor.forwarding_catalog_zones); - yamlstruct.validate(); - settings = std::move(yamlstruct); - return YamlSettingsStatus::OK; - } - catch (const ::rust::Error& ex) { - msg = ex.what(); - return YamlSettingsStatus::PresentButFailed; - } - catch (const std::exception& ex) { - msg = ex.what(); - return YamlSettingsStatus::PresentButFailed; - } - catch (...) { - msg = "Unexpected exception processing YAML"; - return YamlSettingsStatus::PresentButFailed; - } -} - -void pdns::settings::rec::readYamlAllowFromFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log) -{ - SLOG(g_log << Logger::Notice << "Processing allow YAML settings from " << filename << endl, - log->info(Logr::Notice, "Processing allow YAML settings", "path", Logging::Loggable(filename))); - auto file = ifstream(filename); - if (!file.is_open()) { - throw runtime_error(stringerror(errno)); - } - auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_allow_from(data); - pdns::rust::settings::rec::validate_allow_from(filename, yamlvec); - vec = std::move(yamlvec); -} - -void pdns::settings::rec::readYamlForwardZonesFile(const std::string& filename, ::rust::Vec& vec, Logr::log_t log) -{ - SLOG(g_log << Logger::Notice << "Processing forwarding YAML settings from " << filename << endl, - log->info(Logr::Notice, "Processing forwarding YAML settings", "path", Logging::Loggable(filename))); - auto file = ifstream(filename); - if (!file.is_open()) { - throw runtime_error(stringerror(errno)); - } - auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_forward_zones(data); - pdns::rust::settings::rec::validate_forward_zones("forward_zones", yamlvec); - vec = std::move(yamlvec); -} - -void pdns::settings::rec::readYamlAllowNotifyForFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log) -{ - SLOG(g_log << Logger::Notice << "Processing allow-notify-for YAML settings from " << filename << endl, - log->info(Logr::Notice, "Processing allow-notify-for YAML settings", "path", Logging::Loggable(filename))); - auto file = ifstream(filename); - if (!file.is_open()) { - throw runtime_error(stringerror(errno)); - } - auto data = string(std::istreambuf_iterator(file), std::istreambuf_iterator()); - auto yamlvec = pdns::rust::settings::rec::parse_yaml_string_to_allow_notify_for(data); - pdns::rust::settings::rec::validate_allow_notify_for("allow-notify-for", yamlvec); - vec = std::move(yamlvec); -} - -std::string pdns::settings::rec::to_arg(const AuthZone& authzone) -{ - std::ostringstream str; - str << to_arg(authzone.zone) << '=' << to_arg(authzone.file); - return str.str(); -} - -std::string pdns::settings::rec::to_arg(const ForwardZone& forwardzone) -{ - std::ostringstream str; - str << to_arg(forwardzone.zone) << '='; - const auto& vec = forwardzone.forwarders; - for (auto iter = vec.begin(); iter != vec.end(); ++iter) { - if (iter != vec.begin()) { - str << ';'; - } - str << to_arg(*iter); - } - return str.str(); -} - -void pdns::settings::rec::setArgsForZoneRelatedSettings(Recursorsettings& settings) -{ - ::arg().set("forward-zones") = to_arg(settings.recursor.forward_zones); - ::arg().set("forward-zones-file") = to_arg(settings.recursor.forward_zones_file); - ::arg().set("forward-zones-recurse") = to_arg(settings.recursor.forward_zones_recurse); - ::arg().set("auth-zones") = to_arg(settings.recursor.auth_zones); - ::arg().set("allow-notify-for") = to_arg(settings.incoming.allow_notify_for); - ::arg().set("allow-notify-for-file") = to_arg(settings.incoming.allow_notify_for_file); - ::arg().set("export-etc-hosts") = to_arg(settings.recursor.export_etc_hosts); - ::arg().set("serve-rfc1918") = to_arg(settings.recursor.serve_rfc1918); -} - -void pdns::settings::rec::setArgsForACLRelatedSettings(Recursorsettings& settings) -{ - ::arg().set("allow-from") = to_arg(settings.incoming.allow_from); - ::arg().set("allow-from-file") = to_arg(settings.incoming.allow_from_file); - ::arg().set("allow-notify-from") = to_arg(settings.incoming.allow_notify_from); - ::arg().set("allow-notify-from-file") = to_arg(settings.incoming.allow_notify_from_file); -} - -void pdns::settings::rec::to_yaml(uint64_t& field, const std::string& val) -{ - if (val.empty()) { - field = 0; - return; - } - - checked_stoi_into(field, val, nullptr, 0); -} - -void pdns::settings::rec::to_yaml(double& field, const std::string& val) -{ - if (val.empty()) { - field = 0.0; - return; - } - - const auto* cptr_orig = val.c_str(); - char* cptr_ret = nullptr; - auto retval = strtod(cptr_orig, &cptr_ret); - - field = retval; -} - -void pdns::settings::rec::to_yaml(::rust::Vec& field, const std::string& val) -{ - vector zones; - stringtok(zones, val, " ,\t\n\r"); - for (const auto& zone : zones) { - auto headers = splitField(zone, '='); - boost::trim(headers.first); - boost::trim(headers.second); - AuthZone authzone{headers.first, headers.second}; - field.push_back(std::move(authzone)); - } -} - -void pdns::settings::rec::to_yaml(::rust::Vec& field, const std::string& val, bool recurse) -{ - vector zones; - stringtok(zones, val, " ,\t\n\r"); - for (const auto& zone : zones) { - auto headers = splitField(zone, '='); - boost::trim(headers.first); - boost::trim(headers.second); - ::rust::Vec<::rust::String> addresses; - stringtok(addresses, headers.second, " ;"); - ForwardZone forwardzone{headers.first, std::move(addresses), recurse, false}; - field.push_back(std::move(forwardzone)); - } -} - -using FieldMap = std::map, pdns::rust::settings::rec::OldStyle>; - -static bool simpleRustType(const ::rust::String& rname) -{ - return rname == "bool" || rname == "u64" || rname == "f64" || rname == "String"; -} - -static void processLine(const std::string& arg, FieldMap& map, bool mainFile) -{ - string var; - string val; - string::size_type pos = 0; - bool incremental = false; - - if (arg.find("--") == 0 && (pos = arg.find("+=")) != string::npos) // this is a --port+=25 case - { - var = arg.substr(2, pos - 2); - val = arg.substr(pos + 2); - incremental = true; - } - else if (arg.find("--") == 0 && (pos = arg.find('=')) != string::npos) // this is a --port=25 case - { - var = arg.substr(2, pos - 2); - val = arg.substr(pos + 1); - } - else if (arg.find("--") == 0 && (arg.find('=') == string::npos)) // this is a --daemon case - { - var = arg.substr(2); - val = ""; - } - else if (arg[0] == '-' && arg.length() > 1) { - var = arg.substr(1); - val = ""; - } - boost::trim(var); - if (var.empty()) { - return; - } - pos = val.find_first_not_of(" \t"); // strip leading whitespace - if (pos != 0 && pos != string::npos) { - val = val.substr(pos); - } - - ::rust::String section; - ::rust::String fieldname; - ::rust::String type_name; - pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}}; - if (pdns::settings::rec::oldKVToBridgeStruct(var, val, section, fieldname, type_name, rustvalue)) { - auto overriding = !mainFile && !incremental && !simpleRustType(type_name); - auto [existing, inserted] = map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, var, std::move(type_name), rustvalue, overriding}}); - if (!inserted) { - // Simple values overwrite always - existing->second.value.bool_val = rustvalue.bool_val; - existing->second.value.u64_val = rustvalue.u64_val; - existing->second.value.f64_val = rustvalue.f64_val; - existing->second.value.string_val = rustvalue.string_val; - // List values only if = was used - if (!incremental) { - existing->second.value.vec_string_val.clear(); - existing->second.value.vec_forwardzone_val.clear(); - existing->second.value.vec_authzone_val.clear(); - } - for (const auto& add : rustvalue.vec_string_val) { - existing->second.value.vec_string_val.emplace_back(add); - } - for (const auto& add : rustvalue.vec_forwardzone_val) { - existing->second.value.vec_forwardzone_val.emplace_back(add); - } - for (const auto& add : rustvalue.vec_authzone_val) { - existing->second.value.vec_authzone_val.emplace_back(add); - } - } - } -} - -std::string pdns::settings::rec::oldStyleSettingsFileToYaml(const string& fname, bool mainFile) -{ - string line; - string pline; - - std::ifstream configFileStream(fname); - if (!configFileStream) { - int err = errno; - throw runtime_error("Cannot read " + fname + ": " + stringerror(err)); - } - - // Read the old-style config file and produce a map with the data, taking into account the - // difference between = and += - FieldMap map; - while (getline(configFileStream, pline)) { - boost::trim_right(pline); - - if (!pline.empty() && pline[pline.size() - 1] == '\\') { - line += pline.substr(0, pline.length() - 1); - continue; - } - - line += pline; - - // strip everything after a # - string::size_type pos = line.find('#'); - if (pos != string::npos) { - // make sure it's either first char or has whitespace before - // fixes issue #354 - if (pos == 0 || (std::isspace(line[pos - 1]) != 0)) { - line = line.substr(0, pos); - } - } - - // strip trailing spaces - boost::trim_right(line); - - // strip leading spaces - pos = line.find_first_not_of(" \t\r\n"); - if (pos != string::npos) { - line = line.substr(pos); - } - - processLine("--" + line, map, mainFile); - line = ""; - } - - // Convert the map to a vector, as CXX does not have any dictionary like support. - ::rust::Vec vec; - vec.reserve(map.size()); - for (const auto& entry : map) { - vec.emplace_back(entry.second); - } - return std::string(pdns::rust::settings::rec::map_to_yaml_string(vec)); -} - -std::string pdns::settings::rec::defaultsToYaml() -{ - // In this function we make use of the fact that we know a little about the formatting of YAML by - // serde_yaml. ATM there's no way around that, as serde_yaml itself does not have any support for - // comments (other than stripping them while parsing). So produced YAML cannot have any comments. - - // First we construct a map of (section, name) to info about the field (oldname, type, value etc) - FieldMap map; - for (const auto& var : arg().list()) { - if (const auto newname = ArgvMap::isDeprecated(var); !newname.empty()) { - continue; - } - ::rust::String section; - ::rust::String fieldname; - ::rust::String type_name; - pdns::rust::settings::rec::Value rustvalue{}; - string name = var; - string val = arg().getDefault(var); - if (pdns::settings::rec::oldKVToBridgeStruct(name, val, section, fieldname, type_name, rustvalue)) { - map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, name, std::move(type_name), std::move(rustvalue), false}}); - } - } - - // Should be generated - auto def = [&](const string& section, const string& name, const string& type) { - pdns::rust::settings::rec::Value rustvalue{}; - // Dirty hack: trustanchorfile_interval is the only u64 value, set the right default for it. - // 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, std::move(rustvalue), false}}); - }; - def("dnssec", "trustanchors", "Vec"); - def("dnssec", "negative_trustanchors", "Vec"); - def("dnssec", "trustanchorfile", "String"); - def("dnssec", "trustanchorfile_interval", "u64"); - def("logging", "protobuf_servers", "Vec"); - def("logging", "outgoing_protobuf_servers", "Vec"); - def("logging", "dnstap_framestream_servers", "Vec"); - def("logging", "dnstap_nod_framestream_servers", "Vec"); - def("recursor", "rpzs", "Vec"); - def("recursor", "sortlists", "Vec"); - def("recordcache", "zonetocaches", "Vec"); - def("recursor", "allowed_additional_qtypes", "Vec"); - def("incoming", "proxymappings", "Vec"); - def("recursor", "forwarding_catalog_zones", "Vec"); - // End of should be generated XXX - - // Convert the map to a vector, as CXX does not have any dictionary like support. - ::rust::Vec vec; - vec.reserve(map.size()); - for (const auto& entry : map) { - vec.emplace_back(entry.second); - } - const auto defs = std::string(pdns::rust::settings::rec::map_to_yaml_string(vec)); - - // We now have a YAML string, with all sections and all default values. Do a litle bit of parsing - // to insert the help text lines. - std::vector lines; - stringtok(lines, defs, "\n"); - std::string res; - - // These two RE's know about the formatting generated by serde_yaml - std::regex sectionRE("^(\\w+):"); - std::regex fieldRE("^ (\\w+):"); - std::string section; - std::string field; - - for (const auto& line : lines) { - bool withHelp = false; - bool sectionChange = false; - std::smatch matches; - std::regex_search(line, matches, sectionRE); - if (!matches.empty()) { - section = matches[1]; - sectionChange = true; - } - std::regex_search(line, matches, fieldRE); - if (!matches.empty()) { - field = matches[1]; - withHelp = true; - } - if (withHelp) { - std::string oldname; - if (auto iter = map.find(make_pair(section, field)); iter != map.end()) { - oldname = std::string(iter->second.old_name); - } - res += "##### "; - auto help = arg().getHelp(oldname); - if (help.empty()) { - replace(oldname.begin(), oldname.end(), '_', '-'); - help = arg().getHelp(oldname); - } - res += help; - res += '\n'; - } - if (sectionChange) { - res += "\n######### SECTION "; - res += section; - res += " #########\n"; - res += line; - } - else { - res += "# "; - res += line; - } - res += '\n'; - } - return res; -} - -namespace -{ -void fromLuaToRust(const LuaConfigItems& luaConfig, pdns::rust::settings::rec::Dnssec& dnssec) -{ - dnssec.trustanchorfile = luaConfig.trustAnchorFileInfo.fname; - dnssec.trustanchorfile_interval = luaConfig.trustAnchorFileInfo.interval; - dnssec.trustanchors.clear(); - for (const auto& anchors : luaConfig.dsAnchors) { - ::rust::Vec<::rust::String> dsRecords; - for (const auto& dsRecord : anchors.second) { - const auto dsString = dsRecord.getZoneRepresentation(); - if (anchors.first != g_rootdnsname || std::find(rootDSs.begin(), rootDSs.end(), dsString) == rootDSs.end()) { - dsRecords.emplace_back(dsRecord.getZoneRepresentation()); - } - } - if (!dsRecords.empty()) { - pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), std::move(dsRecords)}; - dnssec.trustanchors.emplace_back(trustAnchor); - } - } - for (const auto& anchors : luaConfig.negAnchors) { - pdns::rust::settings::rec::NegativeTrustAnchor negtrustAnchor{anchors.first.toString(), anchors.second}; - dnssec.negative_trustanchors.emplace_back(negtrustAnchor); - } -} - -void fromLuaToRust(const ProtobufExportConfig& pbConfig, pdns::rust::settings::rec::ProtobufServer& pbServer) -{ - for (const auto& server : pbConfig.servers) { - pbServer.servers.emplace_back(server.toStringWithPort()); - } - pbServer.timeout = pbConfig.timeout; - pbServer.maxQueuedEntries = pbConfig.maxQueuedEntries; - pbServer.reconnectWaitTime = pbConfig.reconnectWaitTime; - pbServer.taggedOnly = pbConfig.taggedOnly; - pbServer.asyncConnect = pbConfig.asyncConnect; - pbServer.logQueries = pbConfig.logQueries; - pbServer.logResponses = pbConfig.logResponses; - for (const auto num : pbConfig.exportTypes) { - pbServer.exportTypes.emplace_back(QType(num).toString()); - } - pbServer.logMappedFrom = pbConfig.logMappedFrom; -} - -void fromLuaToRust(const FrameStreamExportConfig& fsc, pdns::rust::settings::rec::DNSTapFrameStreamServer& dnstap) -{ - for (const auto& server : fsc.servers) { - dnstap.servers.emplace_back(server); - } - dnstap.logQueries = fsc.logQueries; - dnstap.logResponses = fsc.logResponses; - dnstap.bufferHint = fsc.bufferHint; - dnstap.flushTimeout = fsc.flushTimeout; - dnstap.inputQueueSize = fsc.inputQueueSize; - dnstap.outputQueueSize = fsc.outputQueueSize; - dnstap.queueNotifyThreshold = fsc.queueNotifyThreshold; - dnstap.reopenInterval = fsc.reopenInterval; -} - -void fromLuaToRust(const FrameStreamExportConfig& fsc, pdns::rust::settings::rec::DNSTapNODFrameStreamServer& dnstap) -{ - for (const auto& server : fsc.servers) { - dnstap.servers.emplace_back(server); - } - dnstap.logNODs = fsc.logNODs; - dnstap.logUDRs = fsc.logUDRs; - dnstap.bufferHint = fsc.bufferHint; - dnstap.flushTimeout = fsc.flushTimeout; - dnstap.inputQueueSize = fsc.inputQueueSize; - dnstap.outputQueueSize = fsc.outputQueueSize; - dnstap.queueNotifyThreshold = fsc.queueNotifyThreshold; - dnstap.reopenInterval = fsc.reopenInterval; -} - -void assign(pdns::rust::settings::rec::TSIGTriplet& var, const TSIGTriplet& tsig) -{ - var.name = tsig.name.empty() ? "" : tsig.name.toStringNoDot(); - var.algo = tsig.algo.empty() ? "" : tsig.algo.toStringNoDot(); - var.secret = Base64Encode(tsig.secret); -} - -void assign(TSIGTriplet& var, const pdns::rust::settings::rec::TSIGTriplet& tsig) -{ - if (!tsig.name.empty()) { - var.name = DNSName(std::string(tsig.name)); - } - if (!tsig.algo.empty()) { - var.algo = DNSName(std::string(tsig.algo)); - } - B64Decode(std::string(tsig.secret), var.secret); -} - -std::string cvt(DNSFilterEngine::PolicyKind kind) -{ - switch (kind) { - case DNSFilterEngine::PolicyKind::NoAction: - return "NoAction"; - case DNSFilterEngine::PolicyKind::Drop: - return "Drop"; - case DNSFilterEngine::PolicyKind::NXDOMAIN: - return "NXDOMAIN"; - case DNSFilterEngine::PolicyKind::NODATA: - return "NODATA"; - case DNSFilterEngine::PolicyKind::Truncate: - return "Truncate"; - case DNSFilterEngine::PolicyKind::Custom: - return "Custom"; - } - return "UnknownPolicyKind"; -} - -void fromLuaToRust(const vector& rpzs, pdns::rust::settings::rec::Recursor& rec) -{ - for (const auto& rpz : rpzs) { - pdns::rust::settings::rec::RPZ rustrpz{ - .name = "", - .addresses = {}, - .defcontent = "", - .defpol = "", - .defpolOverrideLocalData = true, - .defttl = std::numeric_limits::max(), - .extendedErrorCode = std::numeric_limits::max(), - .extendedErrorExtra = "", - .includeSOA = false, - .ignoreDuplicates = false, - .maxTTL = std::numeric_limits::max(), - .policyName = "", - .tags = {}, - .overridesGettag = true, - .zoneSizeHint = 0, - .tsig = {}, - .refresh = 0, - .maxReceivedMBytes = 0, - .localAddress = "", - .axfrTimeout = 20, - .dumpFile = "", - .seedFile = "", - }; - - for (const auto& address : rpz.zoneXFRParams.primaries) { - rustrpz.addresses.emplace_back(address); - } - rustrpz.name = rpz.zoneXFRParams.name; - rustrpz.defcontent = rpz.defcontent; - if (rpz.defpol) { - rustrpz.defpol = cvt(rpz.defpol->d_kind); - rustrpz.defttl = rpz.defpol->d_ttl; - } - rustrpz.defpolOverrideLocalData = rpz.defpolOverrideLocal; - rustrpz.extendedErrorCode = rpz.extendedErrorCode; - rustrpz.extendedErrorExtra = rpz.extendedErrorExtra; - rustrpz.includeSOA = rpz.includeSOA; - rustrpz.ignoreDuplicates = rpz.ignoreDuplicates; - rustrpz.maxTTL = rpz.maxTTL; - rustrpz.policyName = rpz.polName; - for (const auto& tag : rpz.tags) { - rustrpz.tags.emplace_back(tag); - } - rustrpz.overridesGettag = rpz.defpolOverrideLocal; - rustrpz.zoneSizeHint = rpz.zoneXFRParams.zoneSizeHint; - assign(rustrpz.tsig, rpz.zoneXFRParams.tsigtriplet); - rustrpz.refresh = rpz.zoneXFRParams.refreshFromConf; - rustrpz.maxReceivedMBytes = rpz.zoneXFRParams.maxReceivedMBytes; - if (rpz.zoneXFRParams.localAddress != ComboAddress()) { - rustrpz.localAddress = rpz.zoneXFRParams.localAddress.toString(); - } - rustrpz.axfrTimeout = rpz.zoneXFRParams.xfrTimeout; - rustrpz.dumpFile = rpz.dumpZoneFileName; - rustrpz.seedFile = rpz.seedFileName; - - rec.rpzs.emplace_back(rustrpz); - } -} - -string cvt(pdns::ZoneMD::Config cfg) -{ - switch (cfg) { - case pdns::ZoneMD::Config::Ignore: - return "ignore"; - case pdns::ZoneMD::Config::Validate: - return "validate"; - case pdns::ZoneMD::Config::Require: - return "require"; - } - return "UnknownZoneMDConfig"; -} - -void fromLuaToRust(const map& ztcConfigs, pdns::rust::settings::rec::Recordcache& recordcache) -{ - for (const auto& [_, iter] : ztcConfigs) { - pdns::rust::settings::rec::ZoneToCache ztc; - ztc.zone = iter.d_zone; - ztc.method = iter.d_method; - for (const auto& src : iter.d_sources) { - ztc.sources.emplace_back(src); - } - ztc.timeout = iter.d_timeout; - if (!iter.d_tt.name.empty()) { - ztc.tsig.name = iter.d_tt.name.toString(); - ztc.tsig.algo = iter.d_tt.algo.toString(); - ztc.tsig.secret = Base64Encode(iter.d_tt.secret); - } - ztc.refreshPeriod = iter.d_refreshPeriod; - ztc.retryOnErrorPeriod = iter.d_retryOnError; - ztc.maxReceivedMBytes = iter.d_maxReceivedBytes; - if (iter.d_local != ComboAddress()) { - ztc.localAddress = iter.d_local.toString(); - } - ztc.zonemd = cvt(iter.d_zonemd); - ztc.dnssec = cvt(iter.d_dnssec); - recordcache.zonetocaches.emplace_back(ztc); - } -} - -std::string cvt(AdditionalMode mode) -{ - switch (mode) { - case AdditionalMode::Ignore: - return "Ignore"; - case AdditionalMode::CacheOnly: - return "CacheOnly"; - case AdditionalMode::CacheOnlyRequireAuth: - return "CacheOnlyRequireAuth"; - case AdditionalMode::ResolveImmediately: - return "ResolveImmediately"; - case AdditionalMode::ResolveDeferred: - return "ResolveDeferred"; - } - return "UnknownAdditionalMode"; -} - -AdditionalMode cvtAdditional(const std::string& mode) -{ - static const std::map map = { - {"Ignore", AdditionalMode::Ignore}, - {"CacheOnly", AdditionalMode::CacheOnly}, - {"CacheOnlyRequireAuth", AdditionalMode::CacheOnlyRequireAuth}, - {"ResolveImmediately", AdditionalMode::ResolveImmediately}, - {"ResolveDeferred", AdditionalMode::ResolveDeferred}}; - if (auto iter = map.find(mode); iter != map.end()) { - return iter->second; - } - throw runtime_error("AdditionalMode '" + mode + "' unknown"); -} - -pdns::ZoneMD::Config cvtZoneMDConfig(const std::string& mode) -{ - static const std::map map = { - {"ignore", pdns::ZoneMD::Config::Ignore}, - {"validate", pdns::ZoneMD::Config::Validate}, - {"require", pdns::ZoneMD::Config::Require}, - }; - if (auto iter = map.find(mode); iter != map.end()) { - return iter->second; - } - throw runtime_error("ZoneMD config '" + mode + "' unknown"); -} - -void fromLuaToRust(const std::map, AdditionalMode>>& allowAdditionalQTypes, pdns::rust::settings::rec::Recursor& rec) -{ - for (const auto& [qtype, data] : allowAdditionalQTypes) { - const auto& [qtypeset, mode] = data; - pdns::rust::settings::rec::AllowedAdditionalQType add; - add.qtype = qtype.toString(); - for (const auto& extra : qtypeset) { - add.targets.emplace_back(extra.toString()); - } - add.mode = cvt(mode); - rec.allowed_additional_qtypes.emplace_back(add); - } -} - -void fromLuaToRust(const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Incoming& incoming) -{ - for (const auto& mapping : proxyMapping) { - pdns::rust::settings::rec::ProxyMapping pmap; - pmap.subnet = mapping.first.toString(); - pmap.address = mapping.second.address.toString(); - if (mapping.second.suffixMatchNode) { - for (const auto& domain : mapping.second.suffixMatchNode->d_tree.getNodes()) { - pmap.domains.emplace_back(domain.toString()); - } - } - incoming.proxymappings.emplace_back(pmap); - } -} - -void fromLuaToRust(const SortList& arg, pdns::rust::settings::rec::Recursor& rec) -{ - const auto& sortlist = arg.getTree(); - for (const auto& iter : sortlist) { - pdns::rust::settings::rec::SortList rsl; - rsl.key = iter.first.toString(); - const auto& sub = iter.second; - // Some extra work to present them ordered in the YAML - std::set indexes; - std::multimap ordered; - for (auto& order : sub.d_orders) { - indexes.emplace(order.second); - ordered.emplace(order.second, order.first); - } - for (const auto& index : indexes) { - const auto& range = ordered.equal_range(index); - for (auto subnet = range.first; subnet != range.second; ++subnet) { - pdns::rust::settings::rec::SubnetOrder snorder; - snorder.order = index; - snorder.subnet = subnet->second.toString(); - rsl.subnets.emplace_back(snorder); - } - } - rec.sortlists.emplace_back(rsl); - } -} -} // namespace - -void pdns::settings::rec::fromLuaConfigToBridgeStruct(LuaConfigItems& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings) -{ - - fromLuaToRust(luaConfig, settings.dnssec); - settings.logging.protobuf_mask_v4 = luaConfig.protobufMaskV4; - settings.logging.protobuf_mask_v6 = luaConfig.protobufMaskV6; - if (luaConfig.protobufExportConfig.enabled) { - pdns::rust::settings::rec::ProtobufServer pbServer; - fromLuaToRust(luaConfig.protobufExportConfig, pbServer); - settings.logging.protobuf_servers.emplace_back(pbServer); - } - if (luaConfig.outgoingProtobufExportConfig.enabled) { - pdns::rust::settings::rec::ProtobufServer pbServer; - fromLuaToRust(luaConfig.outgoingProtobufExportConfig, pbServer); - settings.logging.outgoing_protobuf_servers.emplace_back(pbServer); - } - if (luaConfig.frameStreamExportConfig.enabled) { - pdns::rust::settings::rec::DNSTapFrameStreamServer dnstap; - fromLuaToRust(luaConfig.frameStreamExportConfig, dnstap); - settings.logging.dnstap_framestream_servers.emplace_back(dnstap); - } - if (luaConfig.nodFrameStreamExportConfig.enabled) { - pdns::rust::settings::rec::DNSTapNODFrameStreamServer dnstap; - fromLuaToRust(luaConfig.nodFrameStreamExportConfig, dnstap); - settings.logging.dnstap_nod_framestream_servers.emplace_back(dnstap); - } - fromLuaToRust(luaConfig.rpzs, settings.recursor); - fromLuaToRust(luaConfig.sortlist, settings.recursor); - fromLuaToRust(luaConfig.ztcConfigs, settings.recordcache); - fromLuaToRust(luaConfig.allowAdditionalQTypes, settings.recursor); - fromLuaToRust(proxyMapping, settings.incoming); -} - -namespace -{ -void fromRustToLuaConfig(const pdns::rust::settings::rec::Dnssec& dnssec, LuaConfigItems& luaConfig) -{ - // This function fills a luaConfig equivalent to the given YAML config, assuming luaConfig has - // its default content. The docs say: "If the sequence contains an entry for the root zone, the - // default root zone trust anchor is not included." By default, a newly created luaConfig has the - // TAs for the root in it. If the YAML config has an entry for these, clear them from - // luaConfig. Otherwise the default TA's would remain even if the YAML config is trying to set - // them. This code actually clears all of the TAs in luaConfig mentioned in the YAML config, but - // as the luaConfig only contains the root TAs, this is equivalent (but not *very* efficient). - for (const auto& trustAnchor : dnssec.trustanchors) { - auto name = DNSName(std::string(trustAnchor.name)); - luaConfig.dsAnchors.erase(name); - } - for (const auto& trustAnchor : dnssec.trustanchors) { - auto name = DNSName(std::string(trustAnchor.name)); - for (const auto& dsRecord : trustAnchor.dsrecords) { - auto dsRecContent = std::dynamic_pointer_cast(DSRecordContent::make(std::string(dsRecord))); - luaConfig.dsAnchors[name].emplace(*dsRecContent); - } - } - for (const auto& nta : dnssec.negative_trustanchors) { - luaConfig.negAnchors[DNSName(std::string(nta.name))] = std::string(nta.reason); - } - luaConfig.trustAnchorFileInfo.fname = std::string(dnssec.trustanchorfile); - luaConfig.trustAnchorFileInfo.interval = dnssec.trustanchorfile_interval; -} - -void fromRustToLuaConfig(const pdns::rust::settings::rec::ProtobufServer& pbServer, ProtobufExportConfig& exp) -{ - exp.enabled = true; - exp.exportTypes.clear(); - for (const auto& type : pbServer.exportTypes) { - exp.exportTypes.emplace(QType::chartocode(std::string(type).c_str())); - } - for (const auto& server : pbServer.servers) { - exp.servers.emplace_back(std::string(server)); - } - exp.maxQueuedEntries = pbServer.maxQueuedEntries; - exp.timeout = pbServer.timeout; - exp.reconnectWaitTime = pbServer.reconnectWaitTime; - exp.asyncConnect = pbServer.asyncConnect; - exp.logQueries = pbServer.logQueries; - exp.logResponses = pbServer.logResponses; - exp.taggedOnly = pbServer.taggedOnly; - exp.logMappedFrom = pbServer.logMappedFrom; -} - -void fromRustToLuaConfig(const pdns::rust::settings::rec::DNSTapFrameStreamServer& dnstap, FrameStreamExportConfig& exp) -{ - exp.enabled = true; - for (const auto& server : dnstap.servers) { - exp.servers.emplace_back(std::string(server)); - } - exp.logQueries = dnstap.logQueries; - exp.logResponses = dnstap.logResponses; - exp.bufferHint = dnstap.bufferHint; - exp.flushTimeout = dnstap.flushTimeout; - exp.inputQueueSize = dnstap.inputQueueSize; - exp.outputQueueSize = dnstap.outputQueueSize; - exp.queueNotifyThreshold = dnstap.queueNotifyThreshold; - exp.reopenInterval = dnstap.reopenInterval; -} - -void fromRustToLuaConfig(const pdns::rust::settings::rec::DNSTapNODFrameStreamServer& dnstap, FrameStreamExportConfig& exp) -{ - exp.enabled = true; - for (const auto& server : dnstap.servers) { - exp.servers.emplace_back(std::string(server)); - } - exp.logNODs = dnstap.logNODs; - exp.logUDRs = dnstap.logUDRs; - exp.bufferHint = dnstap.bufferHint; - exp.flushTimeout = dnstap.flushTimeout; - exp.inputQueueSize = dnstap.inputQueueSize; - exp.outputQueueSize = dnstap.outputQueueSize; - exp.queueNotifyThreshold = dnstap.queueNotifyThreshold; - exp.reopenInterval = dnstap.reopenInterval; -} - -DNSFilterEngine::PolicyKind cvtKind(const std::string& kind) -{ - static const std::map map = { - {"Custom", DNSFilterEngine::PolicyKind::Custom}, - {"Drop", DNSFilterEngine::PolicyKind::Drop}, - {"NoAction", DNSFilterEngine::PolicyKind::NoAction}, - {"NODATA", DNSFilterEngine::PolicyKind::NODATA}, - {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN}, - {"Truncate", DNSFilterEngine::PolicyKind::Truncate}}; - if (auto iter = map.find(kind); iter != map.end()) { - return iter->second; - } - throw runtime_error("PolicyKind '" + kind + "' unknown"); -} - -void fromRustToLuaConfig(const rust::Vec& rpzs, LuaConfigItems& luaConfig) -{ - for (const auto& rpz : rpzs) { - RPZTrackerParams params; - for (const auto& address : rpz.addresses) { - params.zoneXFRParams.primaries.emplace_back(address); - } - params.zoneXFRParams.name = std::string(rpz.name); - params.polName = std::string(rpz.policyName); - - if (!rpz.defpol.empty()) { - params.defpol = DNSFilterEngine::Policy(); - params.defcontent = std::string(rpz.defcontent); - params.defpol->d_kind = cvtKind(std::string(rpz.defpol)); - params.defpol->setName(params.polName); - if (params.defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) { - if (!params.defpol->d_custom) { - params.defpol->d_custom = make_unique(); - } - params.defpol->d_custom->push_back(DNSRecordContent::make(QType::CNAME, QClass::IN, - std::string(params.defcontent))); - - if (rpz.defttl != std::numeric_limits::max()) { - params.defpol->d_ttl = static_cast(rpz.defttl); - } - else { - params.defpol->d_ttl = -1; // get it from the zone - } - } - } - params.defpolOverrideLocal = rpz.defpolOverrideLocalData; - params.extendedErrorCode = rpz.extendedErrorCode; - params.extendedErrorExtra = std::string(rpz.extendedErrorExtra); - params.includeSOA = rpz.includeSOA; - params.ignoreDuplicates = rpz.ignoreDuplicates; - params.maxTTL = rpz.maxTTL; - - for (const auto& tag : rpz.tags) { - params.tags.emplace(std::string(tag)); - } - params.defpolOverrideLocal = rpz.overridesGettag; - params.zoneXFRParams.zoneSizeHint = rpz.zoneSizeHint; - assign(params.zoneXFRParams.tsigtriplet, rpz.tsig); - params.zoneXFRParams.refreshFromConf = rpz.refresh; - params.zoneXFRParams.maxReceivedMBytes = rpz.maxReceivedMBytes; - if (!rpz.localAddress.empty()) { - params.zoneXFRParams.localAddress = ComboAddress(std::string(rpz.localAddress)); - } - params.zoneXFRParams.xfrTimeout = rpz.axfrTimeout; - params.dumpZoneFileName = std::string(rpz.dumpFile); - params.seedFileName = std::string(rpz.seedFile); - luaConfig.rpzs.emplace_back(params); - } -} - -void fromRustToLuaConfig(const rust::Vec& ztcs, map& lua) -{ - for (const auto& ztc : ztcs) { - DNSName zone = DNSName(std::string(ztc.zone)); - RecZoneToCache::Config lztc; - for (const auto& source : ztc.sources) { - lztc.d_sources.emplace_back(std::string(source)); - } - lztc.d_zone = std::string(ztc.zone); - lztc.d_method = std::string(ztc.method); - if (!ztc.localAddress.empty()) { - lztc.d_local = ComboAddress(std::string(ztc.localAddress)); - } - if (!ztc.tsig.name.empty()) { - lztc.d_tt.name = DNSName(std::string(ztc.tsig.name)); - lztc.d_tt.algo = DNSName(std::string(ztc.tsig.algo)); - B64Decode(std::string(ztc.tsig.secret), lztc.d_tt.secret); - } - lztc.d_maxReceivedBytes = ztc.maxReceivedMBytes; - lztc.d_retryOnError = static_cast(ztc.retryOnErrorPeriod); - lztc.d_refreshPeriod = static_cast(ztc.refreshPeriod); - lztc.d_timeout = ztc.timeout; - lztc.d_zonemd = cvtZoneMDConfig(std::string(ztc.zonemd)); - lztc.d_dnssec = cvtZoneMDConfig(std::string(ztc.dnssec)); - lua.emplace(zone, lztc); - } -} - -void fromRustToLuaConfig(const rust::Vec& sortlists, SortList& lua) -{ - for (const auto& sortlist : sortlists) { - for (const auto& entry : sortlist.subnets) { - lua.addEntry(Netmask(std::string(sortlist.key)), Netmask(std::string(entry.subnet)), static_cast(entry.order)); - } - } -} - -void fromRustToLuaConfig(const rust::Vec& alloweds, std::map, AdditionalMode>>& lua) -{ - for (const auto& allowed : alloweds) { - QType qtype(QType::chartocode(std::string(allowed.qtype).c_str())); - std::set set; - for (const auto& target : allowed.targets) { - set.emplace(QType::chartocode(std::string(target).c_str())); - } - AdditionalMode mode = AdditionalMode::CacheOnlyRequireAuth; - mode = cvtAdditional(std::string(allowed.mode)); - lua.emplace(qtype, std::pair{set, mode}); - } -} - -void fromRustToLuaConfig(const rust::Vec& pmaps, ProxyMapping& proxyMapping) -{ - for (const auto& pmap : pmaps) { - Netmask subnet = Netmask(std::string(pmap.subnet)); - ComboAddress address(std::string(pmap.address)); - boost::optional smn; - if (!pmap.domains.empty()) { - smn = boost::make_optional(SuffixMatchNode{}); - for (const auto& dom : pmap.domains) { - smn->add(DNSName(std::string(dom))); - } - } - proxyMapping.insert_or_assign(subnet, {address, smn}); - } -} - -void fromRustToLuaConfig(const rust::Vec& catzones, std::vector& lua) -{ - for (const auto& catz : catzones) { - FWCatalogZone fwcatz; - for (const auto& def : catz.groups) { - fwcatz.d_defaults.emplace(def.name, def); - } - fwcatz.d_catz = std::make_shared(); - - for (const auto& address : catz.xfr.addresses) { - fwcatz.d_params.primaries.emplace_back(address); - } - fwcatz.d_params.name = std::string(catz.zone); - fwcatz.d_params.zoneSizeHint = catz.xfr.zoneSizeHint; - assign(fwcatz.d_params.tsigtriplet, catz.xfr.tsig); - fwcatz.d_params.refreshFromConf = catz.xfr.refresh; - fwcatz.d_params.maxReceivedMBytes = catz.xfr.maxReceivedMBytes; - if (!catz.xfr.localAddress.empty()) { - fwcatz.d_params.localAddress = ComboAddress(std::string(catz.xfr.localAddress)); - } - fwcatz.d_params.xfrTimeout = catz.xfr.axfrTimeout; - lua.emplace_back(std::move(fwcatz)); - } -} -} - -void pdns::settings::rec::fromBridgeStructToLuaConfig(const pdns::rust::settings::rec::Recursorsettings& settings, LuaConfigItems& luaConfig, ProxyMapping& proxyMapping) -{ - fromRustToLuaConfig(settings.dnssec, luaConfig); - luaConfig.protobufMaskV4 = settings.logging.protobuf_mask_v4; - luaConfig.protobufMaskV6 = settings.logging.protobuf_mask_v6; - if (!settings.logging.protobuf_servers.empty()) { - fromRustToLuaConfig(settings.logging.protobuf_servers.at(0), luaConfig.protobufExportConfig); - } - if (!settings.logging.outgoing_protobuf_servers.empty()) { - fromRustToLuaConfig(settings.logging.outgoing_protobuf_servers.at(0), luaConfig.outgoingProtobufExportConfig); - } - if (!settings.logging.dnstap_framestream_servers.empty()) { - fromRustToLuaConfig(settings.logging.dnstap_framestream_servers.at(0), luaConfig.frameStreamExportConfig); - } - if (!settings.logging.dnstap_nod_framestream_servers.empty()) { - fromRustToLuaConfig(settings.logging.dnstap_nod_framestream_servers.at(0), luaConfig.nodFrameStreamExportConfig); - } - fromRustToLuaConfig(settings.recursor.rpzs, luaConfig); - fromRustToLuaConfig(settings.recursor.sortlists, luaConfig.sortlist); - fromRustToLuaConfig(settings.recordcache.zonetocaches, luaConfig.ztcConfigs); - fromRustToLuaConfig(settings.recursor.allowed_additional_qtypes, luaConfig.allowAdditionalQTypes); - fromRustToLuaConfig(settings.recursor.forwarding_catalog_zones, luaConfig.catalogzones); - fromRustToLuaConfig(settings.incoming.proxymappings, proxyMapping); -} - -// Return true if an item that's (also) a Lua config item is set -bool pdns::settings::rec::luaItemSet(const pdns::rust::settings::rec::Recursorsettings& settings) -{ - bool alldefault = true; - for (const auto& trustanchor : settings.dnssec.trustanchors) { - if (trustanchor.name == ".") { - if (trustanchor.dsrecords.size() != rootDSs.size()) { - alldefault = false; - break; - } - for (const auto& dsRecord : trustanchor.dsrecords) { - if (std::find(rootDSs.begin(), rootDSs.end(), std::string(dsRecord)) == rootDSs.end()) { - alldefault = false; - break; - } - } - } - else { - alldefault = false; - break; - } - } - alldefault = alldefault && settings.dnssec.negative_trustanchors.empty(); - alldefault = alldefault && settings.dnssec.trustanchorfile.empty(); - alldefault = alldefault && settings.dnssec.trustanchorfile_interval == 24; - alldefault = alldefault && settings.logging.protobuf_mask_v4 == 32; - alldefault = alldefault && settings.logging.protobuf_mask_v6 == 128; - alldefault = alldefault && settings.logging.protobuf_servers.empty(); - alldefault = alldefault && settings.logging.outgoing_protobuf_servers.empty(); - alldefault = alldefault && settings.logging.dnstap_framestream_servers.empty(); - alldefault = alldefault && settings.logging.dnstap_nod_framestream_servers.empty(); - alldefault = alldefault && settings.recursor.sortlists.empty(); - alldefault = alldefault && settings.recursor.rpzs.empty(); - alldefault = alldefault && settings.recursor.forwarding_catalog_zones.empty(); - alldefault = alldefault && settings.recordcache.zonetocaches.empty(); - alldefault = alldefault && settings.recursor.allowed_additional_qtypes.empty(); - alldefault = alldefault && settings.incoming.proxymappings.empty(); - return !alldefault; -} - -pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::tryReadYAML(const string& yamlconfigname, bool setGlobals, bool& yamlSettings, bool& luaSettingsInYAML, rust::settings::rec::Recursorsettings& settings, Logr::log_t startupLog) -{ - string msg; - // TODO: handle include-dir on command line - auto yamlstatus = pdns::settings::rec::readYamlSettings(yamlconfigname, ::arg()["include-dir"], settings, msg, startupLog); - - switch (yamlstatus) { - case pdns::settings::rec::YamlSettingsStatus::CannotOpen: - SLOG(g_log << Logger::Debug << "No YAML config found for configname '" << yamlconfigname << "': " << msg << endl, - startupLog->error(Logr::Debug, msg, "No YAML config found", "configname", Logging::Loggable(yamlconfigname))); - break; - - 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 processing it", "configname", Logging::Loggable(yamlconfigname))); - break; - - case pdns::settings::rec::YamlSettingsStatus::OK: - yamlSettings = true; - SLOG(g_log << Logger::Notice << "YAML config found and processed for configname '" << yamlconfigname << "'" << endl, - startupLog->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname))); - pdns::settings::rec::processAPIDir(arg()["include-dir"], settings, startupLog); - luaSettingsInYAML = pdns::settings::rec::luaItemSet(settings); - if (luaSettingsInYAML && !settings.recursor.lua_config_file.empty()) { - const std::string err = "YAML settings include values originally in Lua but also sets `recursor.lua_config_file`. This is unsupported"; - SLOG(g_log << Logger::Error << err << endl, - startupLog->info(Logr::Error, err, "configname", Logging::Loggable(yamlconfigname))); - yamlstatus = pdns::settings::rec::PresentButFailed; - } - else if (!settings.recursor.forwarding_catalog_zones.empty() && settings.webservice.api_dir.empty()) { - startupLog->info(Logr::Error, "Catalog zones defined, but webservice.api_dir is not set", "configname", Logging::Loggable(yamlconfigname)); - yamlstatus = pdns::settings::rec::PresentButFailed; - } - else if (setGlobals) { - pdns::settings::rec::bridgeStructToOldStyleSettings(settings); - } - break; - } - return yamlstatus; -} - -uint16_t pdns::rust::settings::rec::qTypeStringToCode(::rust::Str str) -{ - std::string tmp(str.data(), str.length()); - return QType::chartocode(tmp.c_str()); -} - -bool pdns::rust::settings::rec::isValidHostname(::rust::Str str) -{ - try { - auto name = DNSName(string(str)); - return name.isHostname(); - } - catch (...) { - return false; - } -} diff -Nru pdns-recursor-5.2.13/settings/docs-new-preamble-in.rst pdns-recursor-5.4.9/settings/docs-new-preamble-in.rst --- pdns-recursor-5.2.13/settings/docs-new-preamble-in.rst 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/docs-new-preamble-in.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,543 +0,0 @@ -PowerDNS Recursor New Style (YAML) Settings -=========================================== - -Each setting can appear on the command line, prefixed by ``--`` and using the old style name, or in configuration files. -Settings on the command line are processed after the file-based settings are processed. - -.. note:: - Starting with version 5.0.0, :program:`Recursor` supports a new YAML syntax for configuration files - as described here. - 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`` file. - - 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 YAML configuration file and reading of old-style ``recursor.conf`` files will have to be enabled specifically by providing a command line option ``--enable-old-settings``. - - In a future release support for the "old-style" ``recursor.conf`` settings file will be dropped. - -.. note:: - Starting with version 5.1.0, the settings originally specified in a Lua config file can also be put in YAML form. - The conversion printed by ``rec_control show-yaml`` will print these settings if a Lua config file is specified in the config file being converted. - You have to choose however: either set Lua settings the old way in the Lua config file, or convert all to YAML. - If you are using YAML settings of items originally specified in the Lua config file, do not set :ref:`setting-yaml-recursor.lua_config_file` anymore. The :program:`Recursor` will check that you do not mix both configuration methods. - - When using YAML style for settings originally found in the Lua config file, ``rec_control reload-lua-config`` will reload parts of the YAML settings. Refer to the specific setting to learn if it is subject to reloading. Starting with version 5.2.0, the command ``rec_control reload-yaml`` can be used, which is an alias for ``rec_control reload-lua-config``. - -YAML settings file ------------------- -Please refer to e.g. ``_ -for a description of YAML syntax. - -A :program:`Recursor` configuration file has several sections. For example, ``incoming`` for -settings related to receiving queries and ``dnssec`` for settings related to DNSSEC processing. - -An example :program:`Recursor` YAML configuration file looks like: - -.. code-block:: yaml - - dnssec: - log_bogus: true - incoming: - listen: - - 0.0.0.0:5301 - - '[::]:5301' - recursor: - extended_resolution_errors: true - forward_zones: - - zone: example.com - forwarders: - - 127.0.0.1:5301 - outgoing: - source_address: - - 0.0.0.0 - - '::' - logging: - loglevel: 6 - -Take care when listing IPv6 addresses, as characters used for these are special to YAML. -If in doubt, quote any string containing ``:``, ``!``, ``[`` or ``]`` and use (online) tools to check your YAML syntax. -Specify an empty sequence using ``[]``. - -The main setting file is called ``recursor.yml`` and will be processed first. -This settings file might refer to other files via the `recursor.include_dir`_ setting. -The next section will describe how settings specified in multiple files are merged. - -Merging multiple setting files ------------------------------- -If `recursor.include_dir`_ is set, all ``.yml`` files in it will be processed in alphabetical order, modifying the settings processed so far. - -For simple values like an boolean or number setting, a value in the processed file will overwrite an existing setting. - -For values of type sequence, the new value will *replace* the existing value if the existing value is equal to the ``default`` or if the new value is marked with the ``!override`` tag. -Otherwise, the existing value will be *extended* with the new value by appending the new sequence to the existing. - -For example, with the above example ``recursor.yml`` and an include directory containing a file ``extra.yml``: - -.. code-block:: yaml - - dnssec: - log_bogus: false - recursor: - forward_zones: - - zone: example.net - forwarders: - - '::1' - outgoing: - source_address: !override - - 0.0.0.0 - dont_query: [] - -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`` 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:: - The merging process does not process values deeper than the second level. - For example if the main ``recursor.yml`` specified a forward zone - - .. code-block:: yaml - - forward_zones: - - zone: example.net - forwarders: - - '::1' - - and another settings file contains - - .. code-block:: yaml - - forward_zones: - - zone: example.net - forwarders: - - '::2' - - 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 a string containing either an IP address or and IP address:port combination -For example: - -.. code-block:: yaml - - some_key: 127.0.0.1 - another_key: '[::1]:8080' - -Subnet -^^^^^^ -A subnet is a single IP address or an IP address followed by a slash and a prefix length. -If no prefix length is specified, ``/32`` or ``/128`` is assumed, indicating a single IP address. -Subnets can also be prefixed with a ``!``, specifying negation. -This can be used to deny addresses from a previously allowed range. - -For example, ``allow-from`` takes a sequence of subnets: - -.. code-block:: yaml - - allow_from: - - '2001:DB8::/32' - - 128.66.0.0/16 - - '!128.66.1.2' - -In this case the address ``128.66.1.2`` is excluded from the addresses allowed access. - -Forward Zone -^^^^^^^^^^^^ -A forward zone is defined as: - -.. code-block:: yaml - - 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: - -.. code-block:: yaml - - - zone: example1.com - forwarders: - - 127.0.0.1 - - 127.0.0.1:5353 - - '[::1]:53' - - zone: example2.com - forwarders: - - '::1' - recurse: true - notify_allowed: true - -Starting with version 5.1.0, names can be used if -:ref:`setting-yaml-recursor.system_resolver_ttl` is set. -The names will be resolved using the system resolver and an automatic refresh of the forwarding zones will happen if a name starts resolving to a new address. -The refresh is done by performing the equivalent of ``rec_control reload-zones``. - - -Auth Zone -^^^^^^^^^ -An auth zone is defined as: - -.. code-block:: yaml - - zone: string - file: string - -An example of a ``auth_zones`` entry, consisting of a sequence of `Auth Zone`_: - -.. code-block:: yaml - - auth_zones: - - zone: example.com - file: zones/example.com.zone - - zone: example.net - file: zones/example.net.zone - - -Description of YAML syntax corresponding to Lua config items ------------------------------------------------------------- - -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 -^^^^^^^^^^^ -As of version 5.1.0, a trust anchor is defined as - -.. code-block:: yaml - - name: string - dsrecords: sequence of DS record strings in presentation format - -An example of a ``trustanchors`` entry, which is a sequence of `TrustAnchor`_: - -.. code-block:: yaml - - trustanchors: - - name: example.com - dsrecords: - - 10000 8 2 a06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d - -NegativeTrustAnchor -^^^^^^^^^^^^^^^^^^^ -As of version 5.1.0, a negative trust anchor is defined as - -.. code-block:: yaml - - name: string - reason: string - -An example of a ``negative_trustanchors`` entry, which is a sequence of `NegativeTrustAnchor`_: - -.. code-block:: yaml - - negative_trustanchors: - - name: example.com - reason: an example - -ProtobufServer -^^^^^^^^^^^^^^ -As of version 5.1.0, a protobuf server is defined as - -.. code-block:: yaml - - servers: [] Sequence of strings representing SocketAddress - timeout: 2 - maxQueuedEntries: 100 - reconnectWaitTime: 1 - taggedOnly: false - asyncConnect: false - logQueries: true - logResponses: true - exportTypes: [A, AAAA, CNAME] Sequence of QType names - logMappedFrom: false - -An example of a ``protobuf_servers`` entry, which is a sequence of `ProtobufServer`_: - -.. code-block:: yaml - - protobuf_servers: - - servers: [127.0.0.1:4578] - exportTypes: [A, AAAA] - - servers: ['[2001:DB8::1]':7891] - logQueries: false - logResponses: true - exportTypes: [A] - -DNSTapFrameStreamServers -^^^^^^^^^^^^^^^^^^^^^^^^ -As of version 5.1.0, a dnstap framestream server is defined as - -.. code-block:: yaml - - servers: [] Sequence of strings representing SocketAddress or a socket path - logQueries: true - logResponses: true - bufferHint: 0 - flushTimeout: 0 - inputQueueSize: 0 - outputQueueSize: 0 - 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 -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -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 socket path - logNODs: true - logUDRs: false - bufferHint: 0 - flushTimeout: 0 - inputQueueSize: 0 - outputQueueSize: 0 - 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 - -.. code-block:: yaml - - - key: Subnet - subnets: - - 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 - -.. code-block:: yaml - - name: name or pathname - addresses: [] Sequence of SocketAddress - defcontent: string - defpol: Custom, Drop, NXDOMAIN, NODATA Truncate or NoAction - defpolOverrideLocalData: true - defttl: number - extendedErrorCode: number - extendedErrorExtra: string - includeSOA: false - ignoreDuplicates: false - maxTTL: number - policyName: string - tags: Sequence of string - overridesGettag: true - zoneSizeHint: number - tsig: - name: string - algo: string - secret: base64string - refresh: number - maxReceivedMBytes: number - localAddress: IP address - axfrTimeout: number - 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. -Starting with version 5.2.0, names instead of IP addresess can be used for ``addresses`` if -:ref:`setting-yaml-recursor.system_resolver_ttl` is set. - - -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 -^^^^^^^^^^^ -As of version 5.1.0, a ZoneToCache entry is defined as - -.. code-block:: yaml - - zone: zonename - method: One of axfr, url, file - sources: [] Sequence of string, representing IP address, URL or path - timeout: 20 - tsig: - name: name of key - algo: algorithm - secret: Base64 encoded secret - refreshPeriod: 86400 - retryOnErrorPeriod: 60 - maxReceivedMBytes: 0 Zero mean no restrcition - localAddress: local IP address to bind to. - zonemd: One of ignore, validate, require - dnssec: One of ignore, validate, require - -An example of an ``zonetocaches`` entry, which is a sequence of `ZoneToCache`_: - -.. code-block:: yaml - - zonetocaches: - - 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 additional qtype entry is defined as: - -.. code-block:: yaml - - qtype: string representing a QType - targets: [] Sequence of string representing QType - mode: One of Ignore, CacheOnly, CacheOnlyRequireAuth, ResolveImmediately, ResolveDeferred, default CacheOnlyRequireAuth - -An example of an ``allowed_additional_qtypes`` entry, which is a sequence of `AllowedAdditionalQType`_: - -.. code-block:: yaml - - allowed_additional_qtypes: - - qtype: MX - targets: [A, AAAA] - - qtype: NAPTR - targets: [A, AAAA, SRV] - mode: ResolveDeferred - -ProxyMapping -^^^^^^^^^^^^ -As of version 5.1.0, a proxy mapping entry is defined as: - -.. code-block:: yaml - - subnet: Subnet - address: IPAddress - domains: [] Sequence of string - -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.179.0/24 - address: 128.66.1.3 - domains: - - example.com - - example.net - -ForwardingCatalogZone -^^^^^^^^^^^^^^^^^^^^^ -As of version 5.2.0, a forwarding catalog zone entry is defined as: - -.. code-block:: yaml - - zone: Name of catalog zone - notify_allowed: bool, default false - xfr: - addresses: [] Sequence of SocketAddress - zoneSizeHint: number, default not set - tsig: - name: string - algo: string - secret: base64string - refresh: number, default not set - maxReceivedMBytes: number, default not set - localAddress: IP address, default not set - axfrTimeout: number, default 20 - groups: - - name: optional group name - forwarders: [] Sequence of SocketAddress - recurse: bool, default false - notify: bool, default false - -Names instead of IP addresess can be used for ``addresses`` if :ref:`setting-yaml-recursor.system_resolver_ttl` is set. -An example of a :ref:`setting-yaml-recursor.forwarding_catalog_zones` entry, which is a sequence of `ForwardingCatalogZone`_: - -.. code-block:: yaml - - forwarding_catalog_zones: - - zone: 'forward.example' - xfr: - addresses: [128.66.1.2] - groups: - - forwarders: [192.168.178.1] # default forwarder - - name: mygroup - forwarders: [192.168.179.2] # forwarder for catalog zone members in mygroup - recurse: true - notify_allowed: true - - zone: 'forward2.example' - xfr: - addresses: [128.66.1.3] - groups: - - forwarders: [192.168.178.3] # only default forwarder for 2nd catalog zone - -:program:`Recursor` will transfer the catalog zone from the authoritative server using IXFR (falling back to AXFR if needed) and add forwarding clauses for all members of the catalog zone. -The forwarding parameters will be taken from the default group entry (the one without a name) defined in the YAML settings. -For catalog zone members in a group, the forwarding parameters will be taken from the group entry with the corresponding name. - -The forwarding definitions will be written into a file ``$api_dir/catzone.$zonename``. :ref:`setting-yaml-webservice.api_dir` must be defined, the directory must exist and be writable by the :program:`Recursor` process. - -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 - ... - diff -Nru pdns-recursor-5.2.13/settings/docs-old-preamble-in.rst pdns-recursor-5.4.9/settings/docs-old-preamble-in.rst --- pdns-recursor-5.2.13/settings/docs-old-preamble-in.rst 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/docs-old-preamble-in.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -PowerDNS Recursor Settings -========================== -Each setting can appear on the command line, prefixed by ``--``, or in the configuration file. -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`. - Starting with version 5.2.0, parsing of old-style settings must be explicitly enabled using a command line argument ``--enable-old-settings``. - In a future release support for the old-style settings described here will be dropped. - See :doc:`yamlsettings` for details. - -.. note:: - Settings marked as ``Boolean`` can either be set to an empty value, which means **on**, or to ``no`` or ``off`` which means **off**. - Anything else means **on**. - - For example: - - - ``serve-rfc1918`` on its own means: do serve those zones. - - ``serve-rfc1918 = off`` or ``serve-rfc1918 = no`` means: do not serve those zones. - - Anything else means: do serve those zones. - -You can use ``+=`` syntax to set some variables incrementally, but this -requires you to have at least one non-incremental setting for the -variable to act as base setting. This is mostly useful for -:ref:`setting-include-dir` directive. An example:: - - forward-zones = foo.example.com=192.168.100.1; - forward-zones += bar.example.com=[1234::abcde]:5353; - -When a list of **Netmasks** is mentioned, a list of subnets can be specified. -A subnet that is not followed by ``/`` will be interpreted as a ``/32`` or ``/128`` subnet (a single address), depending on address family. -For most settings, it is possible to exclude ranges by prefixing an item with the negation character ``!``. -For example:: - - allow-from = 2001:DB8::/32, 128.66.0.0/16, !128.66.1.2 - -In this case the address ``128.66.1.2`` is excluded from the addresses allowed access. - -The Settings ------------- diff -Nru pdns-recursor-5.2.13/settings/generate.py pdns-recursor-5.4.9/settings/generate.py --- pdns-recursor-5.2.13/settings/generate.py 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/generate.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,842 +0,0 @@ -"""The Python script that takes table.py and generates C++, Rust ahd .rst code.""" -# -# For C++ it generates cxxsettings-generated.cc containing support for old style -# settings plus conversion from old style to new style. -# -# 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 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. -# -# Two documentation files are generated: ../docs/settings.rst and -# ../docs/yamlsettings.rst. Each of these files have a preamble as -# well, describing the syntax and giving some examples. -# -# An example table.py entry: -# -# { -# 'name' : "allow_from", -# 'section' : "incoming", -# 'oldname' : "allow-from", -# 'type' : LType.ListSubnets, -# 'default' : "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", -# 'help' : "If set, only allow these comma separated netmasks to recurse", -# 'doc' : """ -# """ -# } -# -# The fields are: -# -# name: short name within section, also yaml key, must be unique within section and not a C++ or -# Rust keyword -# section: yaml section -# oldname: name in old style settings, must be unique globally -# type : logical type (leave the space before the : as pylint is buggy parsing lines with type -# immediately followed by colon)x -# default: default value, use 'true' and 'false' for Booleans -# help: short help text -# doc: the docs text will be put here -# doc-rst: optional .rst annotations -# doc-new: optional docs text specific to YAML format, e.g. not talking about comma separated -# lists and giving YAML examples. (optional) -# skip-yaml: optional if this key is present, the field will be skipped in the new style settings. -# Use for deprecated settings, the generated code will use deprecated map from arg() -# to handle old names when converting .conf to .yml -# skip-old: optional if this key is present, the field will be skipped in the old style settings. -# versionadded: string or list of strings -# runtime: optional, mentions how the settings can be updated runtime (or via API) if applicable -# -# The above struct will generate in cxxsettings-generated.cc: -# -# ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse") = \ -# "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, ..."; -# -# For Rust, it will generate a field `allow_from' within struct Incoming. -# As CXX places restrictions on the Serde code (which means we cannot -# use Serde extensions) we have to handle the default value and "skip if -# default" functions ourselves. -# -# There are three cases: -# -# 1. Default is the same as the Rust default for the type -# In that case, the field becomes: -# -# #[serde(default, skip_serializing_if = "crate::is_default")] -# nameoffield: bool -# -# 2. Type is primitive and default value is different from the Rust default, e.g.: -# -# #[serde(default = "crate::U64::<2000>::value", -# skip_serializing_if = "crate::U64::<2000>::is_equal")] -# nameoffield: u64 -# -# U64 is implemented in rust/src/helpers.rs -# -# 3. Type is not primitive and has default value different from Rust default, e.g.: -# -# [serde(default = "crate::default_value_incoming_allow_from", -# skip_serializing_if = "crate::default_value_equal_incoming_allow_from")] -# allow_from: Vec -# -# The two functions default_value_incoming_allow_from() and -# default_value_equal_incoming_allow_from() are also generated. -# -from enum import Enum -from enum import auto -import os -import re -import sys - -class LType(Enum): - """The type we handle in table.py""" - Bool = auto() - Command = auto() - Double = auto() - ListAllowedAdditionalQTypes = auto() - ListAuthZones = auto() - ListDNSTapFrameStreamServers = auto() - ListDNSTapNODFrameStreamServers = auto() - ListForwardZones = auto() - ListNegativeTrustAnchors = auto() - ListProtobufServers = auto() - ListProxyMappings = auto() - ListRPZs = auto(); - ListSocketAddresses = auto() - ListSortLists = auto() - ListStrings = auto() - ListSubnets = auto() - ListTrustAnchors = auto() - ListZoneToCaches = auto() - ListForwardingCatalogZones = auto() - String = auto() - Uint64 = auto() - -listOfStringTypes = (LType.ListSocketAddresses, LType.ListStrings, LType.ListSubnets) -listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors, - LType.ListProtobufServers, LType.ListDNSTapFrameStreamServers, LType.ListDNSTapNODFrameStreamServers, - LType.ListSortLists, LType.ListRPZs, LType.ListZoneToCaches, LType.ListAllowedAdditionalQTypes, - LType.ListProxyMappings, LType.ListForwardingCatalogZones) - -def get_olddoc_typename(typ): - """Given a type from table.py, return the old-style type name""" - if typ == LType.Bool: - return 'Boolean' - if typ == LType.Uint64: - return 'Integer' - if typ == LType.Double: - return 'Double' - if typ == LType.String: - return 'String' - if typ == LType.ListSocketAddresses: - return 'Comma separated list or IPs of IP:port combinations' - if typ == LType.ListSubnets: - return 'Comma separated list of IP addresses or subnets, negation supported' - if typ == LType.ListStrings: - return 'Comma separated list of strings' - if typ == LType.ListForwardZones: - return 'Comma separated list of \'zonename=IP\' pairs' - if typ == LType.ListAuthZones: - return 'Comma separated list of \'zonename=filename\' pairs' - return 'Unknown' + str(typ) - -def get_newdoc_typename(typ): - """Given a type from table.py, return the new-style type name""" - if typ == LType.Bool: - return 'Boolean' - if typ == LType.Uint64: - return 'Integer' - if typ == LType.Double: - return 'Double' - if typ == LType.String: - return 'String' - if typ == LType.ListSocketAddresses: - return 'Sequence of `Socket Address`_ (IP or IP:port combinations)' - if typ == LType.ListSubnets: - return 'Sequence of `Subnet`_ (IP addresses or subnets, negation supported)' - if typ == LType.ListStrings: - return 'Sequence of strings' - if typ == LType.ListForwardZones: - return 'Sequence of `Forward Zone`_' - if typ == LType.ListAuthZones: - return 'Sequence of `Auth Zone`_' - if typ == LType.ListTrustAnchors: - return 'Sequence of `TrustAnchor`_' - if typ == LType.ListNegativeTrustAnchors: - return 'Sequence of `NegativeTrustAnchor`_' - if typ == LType.ListProtobufServers: - return 'Sequence of `ProtobufServer`_' - if typ == LType.ListDNSTapFrameStreamServers: - return 'Sequence of `DNSTapFrameStreamServers`_' - if typ == LType.ListDNSTapNODFrameStreamServers: - return 'Sequence of `DNSTapNODFrameStreamServers`_' - if typ == LType.ListSortLists: - return 'Sequence of `Sortlist`_' - if typ == LType.ListRPZs: - return 'Sequence of `RPZ`_' - if typ == LType.ListZoneToCaches: - return 'Sequence of `ZoneToCache`_' - if typ == LType.ListAllowedAdditionalQTypes: - return 'Sequence of `AllowedAdditionalQType`_' - if typ == LType.ListProxyMappings: - return 'Sequence of `ProxyMapping`_' - if typ == LType.ListForwardingCatalogZones: - return 'Sequence of `ForwardingCatalogZone`_' - return 'Unknown' + str(typ) - -def get_default_olddoc_value(typ, val): - """Given a type and a value from table.py return the old doc representation of the value""" - if typ == LType.Bool: - if val == 'false': - return 'no' - return 'yes' - if val == '': - return '(empty)' - return val - -def get_default_newdoc_value(typ, val): - """Given a type and a value from table.py return the new doc representation of the value""" - if typ in (LType.Bool, LType.Uint64, LType.Double): - return '``' + val + '``' - if typ == LType.String and val == '': - return '(empty)' - if typ == LType.String: - return '``' + val + '``' - parts = re.split('[ \t,]+', val) - if len(parts) > 0: - ret = '' - for part in parts: - if part == '': - continue - if ret != '': - ret += ', ' - if ':' in part or '!' in part: - ret += "'" + part + "'" - else: - ret += part - else: - ret = '' - return '``[' + ret + ']``' - -def list_to_base_type(typ): - typeName = typ.name - if typeName.startswith('List') and typeName.endswith('s'): - baseName = typeName[4:len(typeName) - 1] - return baseName - return 'Unknown: ' + typeName - -def get_rust_type(typ): - """Determine which Rust type is used for a logical type""" - if typ == LType.Bool: - return 'bool' - if typ == LType.Uint64: - return 'u64' - if typ == LType.Double: - return 'f64' - if typ == LType.String: - return 'String' - # These vectors map to Vec - if typ == LType.ListSocketAddresses: - return 'Vec' - if typ == LType.ListSubnets: - return 'Vec' - if typ == LType.ListStrings: - return 'Vec' - # These vectors map to Vec - return 'Vec<' + list_to_base_type(typ) + '>' - -def quote(arg): - """Return a quoted string""" - return '"' + arg + '"' - -def isEnvVar(name): - return name in ('SYSCONFDIR', 'NODCACHEDIRNOD', 'NODCACHEDIRUDR') - -def gen_cxx_defineoldsettings(file, entries): - """Generate C++ code to declare old-style settings""" - file.write('void pdns::settings::rec::defineOldStyleSettings()\n{\n') - for entry in entries: - helptxt = quote(entry['help']) - oldname = quote(entry['oldname']) - if entry['type'] == LType.Bool: - if entry['default'] == "true": - cxxdef = "yes" - else: - cxxdef = "no" - cxxdef = quote(cxxdef) - file.write(f" ::arg().setSwitch({oldname}, {helptxt}) = {cxxdef};\n") - elif entry['type'] == LType.Command: - file.write(f" ::arg().setCmd({oldname}, {helptxt});\n") - else: - cxxdef = entry['default'] if isEnvVar(entry['default']) else quote(entry['default']) - file.write(f" ::arg().set({oldname}, {helptxt}) = {cxxdef};\n") - file.write('}\n\n') - -def gen_cxx_oldstylesettingstobridgestruct(file, entries): - """Generate C++ code the convert old-style settings to new-style struct""" - file.write('void pdns::settings::rec::oldStyleSettingsToBridgeStruct') - file.write('(Recursorsettings& settings)\n{\n') - for entry in entries: - if entry['type'] == LType.Command: - continue - if 'skip-yaml' in entry: - continue - if 'skip-old' in entry: - continue - rust_type = get_rust_type(entry['type']) - name = entry['name'] - oldname = entry['oldname'] - section = entry['section'] - file.write(f' settings.{section}.{name} = ') - if rust_type == 'bool': - file.write(f'arg().mustDo("{oldname}")') - elif rust_type == 'u64': - file.write(f'static_cast(arg().asNum("{oldname}"))') - elif rust_type == 'f64': - file.write(f'arg().asDouble("{oldname}")') - elif rust_type == 'String': - file.write(f'arg()["{oldname}"]') - elif rust_type == 'Vec': - file.write(f'getStrings("{oldname}")') - elif rust_type == 'Vec': - file.write(f'getForwardZones("{oldname}")') - elif rust_type == 'Vec': - file.write(f'getAuthZones("{oldname}")') - else: - file.write(f'Unknown type {rust_type}\n') - file.write(';\n') - file.write('}\n\n') - -def gen_cxx_oldkvtobridgestruct(file, entries): - """Generate C++ code for oldKVToBridgeStruct""" - file.write('// Inefficient, but only meant to be used for one-time conversion purposes\n') - file.write('bool pdns::settings::rec::oldKVToBridgeStruct(std::string& key, ') - file.write('const std::string& value, ::rust::String& section, ::rust::String& fieldname, ') - file.write('::rust::String& type_name, pdns::rust::settings::rec::Value& rustvalue)') - file.write('{ // NOLINT(readability-function-cognitive-complexity)\n') - file.write(' if (const auto newname = arg().isDeprecated(key); !newname.empty()) {\n') - file.write(' key = newname;\n') - file.write(' }\n') - for entry in entries: - if entry['type'] == LType.Command: - continue - if 'skip-yaml' in entry: - continue - if 'skip-old' in entry: - continue - rust_type = get_rust_type(entry['type']) - extra = '' - if entry['oldname'] == 'forward-zones-recurse': - extra = ', true' - name = entry['name'] - section = entry['section'] - oldname = entry['oldname'] - file.write(f' if (key == "{oldname}") {{\n') - file.write(f' section = "{section}";\n') - file.write(f' fieldname = "{name}";\n') - file.write(f' type_name = "{rust_type}";\n') - if rust_type == 'bool': - file.write(f' to_yaml(rustvalue.bool_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'u64': - file.write(f' to_yaml(rustvalue.u64_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'f64': - file.write(f' to_yaml(rustvalue.f64_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'String': - file.write(f' to_yaml(rustvalue.string_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'Vec': - file.write(f' to_yaml(rustvalue.vec_string_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'Vec': - file.write(f' to_yaml(rustvalue.vec_forwardzone_val, value{extra});\n') - file.write(' return true;\n }\n') - elif rust_type == 'Vec': - file.write(f' to_yaml(rustvalue.vec_authzone_val, value{extra});\n') - file.write(' return true;\n }\n') - else: - file.write(f'Unknown type {rust_type}\n') - file.write(' return false;\n') - file.write('}\n\n') - -def gen_cxx_brigestructtoldstylesettings(file, entries): - """Generate C++ Code for bridgeStructToOldStyleSettings""" - file.write('void pdns::settings::rec::bridgeStructToOldStyleSettings') - file.write('(const Recursorsettings& settings)\n{\n') - for entry in entries: - if entry['type'] == LType.Command: - continue - if 'skip-yaml' in entry: - continue - if 'skip-old' in entry: - continue - section = entry['section'].lower() - name = entry['name'] - oldname = entry['oldname'] - file.write(f' ::arg().set("{oldname}") = ') - file.write(f'to_arg(settings.{section}.{name});\n') - file.write('}\n') - -def gen_cxx(gendir, entries): - """Generate the C++ code from the defs in table.py""" - 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') - file.write('#include "cxxsettings-private.hh"\n\n') - gen_cxx_defineoldsettings(file, entries) - gen_cxx_oldstylesettingstobridgestruct(file, entries) - gen_cxx_oldkvtobridgestruct(file, entries) - gen_cxx_brigestructtoldstylesettings(file, entries) - -def is_value_rust_default(typ, value): - """Is a value (represented as string) the same as its corresponding Rust default?""" - if typ == 'bool': - return value == 'false' - if typ == 'u64': - return value in ('0', '') - if typ == 'f64': - return value == '0.0' - if typ == 'String': - return value == '' - return False - -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 {{\n' - ret += f' let msg = "default value defined for `{name}\' should be valid YAML";' - ret += f' let deserialized: Vec = serde_yaml::from_str({quote(defvalue)}).expect(msg);\n' - ret += f' deserialized\n' - ret += '}\n' - ret += f'fn default_value_equal_{name}(value: &Vec)' - ret += '-> bool {\n' - ret += f' let def = default_value_{name}();\n' - ret += ' &def == value\n' - ret += '}\n\n' - return ret - -# Example snippet generated -# fn default_value_general_query_local_address() -> Vec { -# vec![String::from("0.0.0.0"), ] -#} -#fn default_value_equal_general_query_local_address(value: &Vec) -> bool { -# let def = default_value_general_query_local_address(); -# &def == value -#} -def gen_rust_stringvec_default_functions(entry, name): - """Generate Rust code for the default handling of a vector for Strings""" - ret = f'// DEFAULT HANDLING for {name}\n' - ret += f'fn default_value_{name}() -> Vec {{\n' - parts = re.split('[ \t,]+', entry['default']) - if len(parts) > 0: - ret += ' vec![\n' - for part in parts: - if part == '': - continue - ret += f' String::from({quote(part)}),\n' - ret += ' ]\n' - else: - ret += ' vec![]\n' - ret += '}\n' - ret += f'fn default_value_equal_{name}(value: &Vec) -> bool {{\n' - ret += f' let def = default_value_{name}();\n' - ret += ' &def == value\n' - ret += '}\n\n' - return ret - -def gen_rust_default_functions(entry, name, rust_type): - """Generate Rust code for the default handling""" - defvalue = entry['default'] - if entry['type'] in listOfStringTypes: - return gen_rust_stringvec_default_functions(entry, name) - if entry['type'] in listOfStructuredTypes: - baseName = list_to_base_type(entry['type']) - return gen_rust_vec_default_functions(name, baseName, defvalue) - ret = f'// DEFAULT HANDLING for {name}\n' - ret += f'fn default_value_{name}() -> {rust_type} {{\n' - rustdef = f'env!("{defvalue}")' if isEnvVar(defvalue) else quote(defvalue) - ret += f" String::from({rustdef})\n" - ret += '}\n' - if rust_type == 'String': - rust_type = 'str' - ret += f'fn default_value_equal_{name}(value: &{rust_type})' - ret += '-> bool {\n' - ret += f' value == default_value_{name}()\n' - ret += '}\n\n' - return ret - -def write_rust_field(file, entry, default_funcs): - """Generate Rust code for a field with Serde annotations""" - rust_type = get_rust_type(entry['type']) - the_default = entry['default'] - is_rust_default = is_value_rust_default(rust_type, the_default) - if is_rust_default: - file.write(' #[serde(default, skip_serializing_if = "crate::is_default")]\n') - else: - if entry['type'] == LType.Bool: - file.write(' #[serde(default = "crate::Bool::::value", ') - file.write('skip_serializing_if = "crate::if_true")]\n') - elif entry['type'] == LType.Uint64: - file.write(f' #[serde(default = "crate::U64::<{the_default}>::value", ') - file.write(f'skip_serializing_if = "crate::U64::<{the_default}>::is_equal")]\n') - else: - basename = entry['section'] + '_' + entry['name'] - file.write(f' #[serde(default = "crate::default_value_{basename}", ') - file.write(f'skip_serializing_if = "crate::default_value_equal_{basename}")]\n') - default_funcs.append(gen_rust_default_functions(entry, basename, rust_type)) - file.write(f" {entry['name']}: {rust_type},\n\n") - -def write_rust_section(file, section, entries, default_funcs): - """Generate Rust code for a Section with Serde annotations""" - file.write(f' // SECTION {section.capitalize()}\n') - file.write(' #[derive(Deserialize, Serialize, Debug, PartialEq)]\n') - file.write(' #[serde(deny_unknown_fields)]\n') - file.write(f' pub struct {section.capitalize()} {{\n') - for entry in entries: - if entry['section'] != section: - continue - if entry['type'] == LType.Command: - continue - if 'skip-yaml' in entry: - continue - write_rust_field(file, entry, default_funcs) - file.write(f' }}\n // END SECTION {section.capitalize()}\n\n') - -# -# Each section als has a Default implementation, so that a section with all entries having a default -# value does not get generated into a yaml section. Such a trait looks like: -# -#impl Default for recsettings::ForwardZone { -# fn default() -> Self { -# let deserialized: recsettings::ForwardZone = serde_yaml::from_str("").unwrap(); -# deserialized -# } -#} - -def write_rust_default_trait_impl(file, section): - """Generate Rust code for the default Trait for a section""" - file.write(f'impl Default for recsettings::{section.capitalize()} {{\n') - file.write(' fn default() -> Self {\n') - file.write(' let deserialized: recsettings::') - file.write(f'{section.capitalize()} = serde_yaml::from_str("").unwrap();\n') - file.write(' deserialized\n') - file.write(' }\n') - file.write('}\n\n') - -def write_validator(file, section, entries): - """Generate Rust code for the Validator Trait for a section""" - file.write(f'impl Validate for recsettings::{section.capitalize()} {{\n') - file.write(' fn validate(&self) -> Result<(), ValidationError> {\n') - for entry in entries: - if entry['section'] != section: - continue - name = entry['name'].lower() - typ = entry['type'] - if typ == LType.ListSubnets: - validator = 'validate_subnet' - elif typ == LType.ListSocketAddresses: - validator = 'validate_socket_address' - elif typ in listOfStructuredTypes: - validator = '|field, element| element.validate(field)' - else: - continue - file.write(f' let fieldname = "{section.lower()}.{name}".to_string();\n') - file.write(f' validate_vec(&fieldname, &self.{name}, {validator})?;\n') - file.write(f' validate_{section.lower()}(self)\n') - file.write(' }\n') - file.write('}\n\n') - -def write_rust_merge_trait_impl(file, section, entries): - """Generate Rust code for the Merge Trait for a section""" - file.write(f'impl Merge for recsettings::{section.capitalize()} {{\n') - file.write(' fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n') - file.write(' if let Some(m) = map {\n') - for entry in entries: - if entry['section'] != section: - continue - if 'skip-yaml' in entry: - continue - rtype = get_rust_type(entry['type']) - name = entry['name'] - file.write(f' if m.contains_key("{name}") {{\n') - if rtype in ('bool', 'u64', 'f64', 'String'): - 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') - file.write(f' self.{name}.clear();\n') - file.write(' }\n') - file.write(f' merge_vec(&mut self.{name}, &mut rhs.{name});\n') - file.write(' }\n') - file.write(' }\n') - file.write(' }\n') - file.write('}\n\n') - -def gen_rust(srcdir, entries): - """Generate Rust code all entries""" - def_functions = [] - sections = {} - 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(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(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) - - file.write(' // END INCLUDE rust-bridge-in.rs\n\n') - for entry in entries: - if entry['section'] == 'commands': - continue - sections[entry['section']] = entry['section'] - - for section in sections: - write_rust_section(file, section, entries, def_functions) - - file.write(' #[derive(Serialize, Deserialize, Debug)]\n') - file.write(' #[serde(deny_unknown_fields)]\n') - file.write(' pub struct Recursorsettings {\n') - for section in sections: - file.write(' #[serde(default, skip_serializing_if = "crate::is_default")]\n') - file.write(f' {section.lower()}: {section.capitalize()},\n') - file.write('} // End of generated structs\n') - file.write('}\n') - - for section in sections: - write_rust_default_trait_impl(file, section) - write_rust_default_trait_impl(file, 'Recursorsettings') - - for section in sections: - write_validator(file, section, entries) - - file.write('impl crate::recsettings::Recursorsettings {\n') - file.write(' fn validate(&self) -> Result<(), ValidationError> {\n') - for section in sections: - file.write(f' self.{section.lower()}.validate()?;\n') - file.write(' Ok(())\n') - file.write(' }\n') - file.write('}\n\n') - - for section in sections: - write_rust_merge_trait_impl(file, section, entries) - - file.write('impl Merge for crate::recsettings::Recursorsettings {\n') - file.write(' fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) {\n') - file.write(' if let Some(m) = map {\n') - for section in sections: - file.write(f' if let Some(s) = m.get("{section}") {{\n') - file.write(' if s.is_mapping() {\n') - file.write((f' self.{section}.merge(&mut rhs.{section},' - ' s.as_mapping());\n')) - file.write(' }\n') - file.write(' }\n') - file.write(' }\n') - file.write(' }\n') - file.write('}\n\n') - - for entry in def_functions: - file.write(entry) - file.close() - -def gen_docs_meta(file, entry, name, is_tuple): - """Write .. versionadded:: and related entries""" - if name in entry: - val = entry[name] - if not isinstance(val, list): - val = [val] - for vers in val: - if is_tuple: - file.write(f'.. {name}:: {vers[0]}\n\n') - file.write(f' {vers[1].strip()}\n') - else: - file.write(f'.. {name}:: {vers}\n') - -def gen_oldstyle_docs(srcdir, entries): - """Write old style docs""" - 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(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') - - for entry in entries: - if entry['type'] == LType.Command: - continue - if entry['doc'].strip() == 'SKIP': - continue - if 'skip-old' in entry: - continue - oldname = entry['oldname'] - section = entry['section'] - file.write(f'.. _setting-{oldname}:\n\n') - file.write(f'``{oldname}``\n') - dots = '~' * (len(entry['oldname']) + 4) - file.write(f'{dots}\n') - gen_docs_meta(file, entry, 'versionadded', False) - gen_docs_meta(file, entry, 'versionchanged', True) - gen_docs_meta(file, entry, 'deprecated', True) - if 'doc-rst' in entry: - file.write(entry['doc-rst'].strip()) - file.write('\n') - file.write('\n') - typ = get_olddoc_typename(entry['type']) - file.write(f'- {typ}\n') - if 'docdefault' in entry: - file.write(f"- Default: {entry['docdefault']}\n\n") - else: - file.write((f"- Default: " - f"{get_default_olddoc_value(entry['type'], entry['default'])}\n\n")) - if 'skip-yaml' in entry: - file.write('- YAML setting does not exist\n\n') - else: - file.write(f"- YAML setting: :ref:`setting-yaml-{section}.{entry['name']}`\n\n") - if 'runtime' in entry: - runtime = entry['runtime'] - if not isinstance(runtime, list): - runtime = [runtime] - li = [] - for v in runtime: - if v == 'reload-yaml': - continue - li.append('``' + v + '``') - file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n") - file.write(entry['doc'].strip()) - file.write('\n\n') - -def fixxrefs(entries, arg): - """Docs in table refer to old style names, we modify them to ref to new style""" - matches = re.findall(':ref:`setting-(.*?)`', arg) - # We want to replace longest match first, to avoid a short match modifying a long one - matches = sorted(matches, key = lambda x: -len(x)) - for match in matches: - for entry in entries: - if entry['oldname'] == match: - key = ':ref:`setting-' + match - repl = ':ref:`setting-yaml-' + entry['section'] + '.' + entry['name'] - arg = arg.replace(key, repl) - return arg - -def gen_newstyle_docs(srcdir, argentries): - """Write new style docs""" - entries = sorted(argentries, key = lambda entry: [entry['section'], entry['name']]) - 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(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') - - for entry in entries: - if entry['type'] == LType.Command: - continue - if entry['doc'].strip() == 'SKIP': - continue - if 'skip-yaml' in entry: - continue - section = entry['section'] - name = entry['name'] - fullname = section + '.' + name - file.write(f'.. _setting-yaml-{fullname}:\n\n') - file.write(f'``{fullname}``\n') - dots = '^' * (len(fullname) + 4) - file.write(f'{dots}\n') - gen_docs_meta(file, entry, 'versionadded', False) - gen_docs_meta(file, entry, 'versionchanged', True) - gen_docs_meta(file, entry, 'deprecated', True) - if 'doc-rst' in entry: - file.write(fixxrefs(entries, entry['doc-rst'].strip())) - file.write('\n') - file.write('\n') - file.write(f"- {get_newdoc_typename(entry['type'])}\n") - if 'docdefault' in entry: - file.write(f"- Default: {entry['docdefault']}\n\n") - else: - file.write((f"- Default: " - f"{get_default_newdoc_value(entry['type'], entry['default'])}\n\n")) - if 'skip-old' in entry: - file.write(f"- {entry['skip-old']}\n\n") - else: - file.write(f"- Old style setting: :ref:`setting-{entry['oldname']}`\n\n") - if 'runtime' in entry: - runtime = entry['runtime'] - if not isinstance(runtime, list): - runtime = [runtime] - li = [] - for v in runtime: - vv = '``' + v + '``' - if v == 'reload-yaml': - vv = 'since 5.2.0: ' + vv - li.append(vv) - file.write(f"- Runtime modifiable using ``rec_control`` {', '.join(f'{w}' for w in li)}\n\n") - if 'doc-new' in entry: - file.write(fixxrefs(entries, entry['doc-new'].strip())) - else: - file.write(fixxrefs(entries, entry['doc'].strip())) - file.write('\n\n') - -RUNTIME = '*runtime determined*' - -def generate(): - """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(srcdir + '/table.py', mode='r', encoding="utf-8") as file: - entries = eval(file.read()) - - for entry in entries: - the_oldname = entry['name'].replace('_', '-') - if 'oldname' in entry: - if entry['oldname'] == the_oldname: - sys.stderr.write(f"Redundant old name {entry['oldname']}\n") - else: - entry['oldname'] = the_oldname - - dupcheck1 = {} - dupcheck2 = {} - for entry in entries: - if entry['oldname'] in dupcheck1: - sys.stderr.write(f"duplicate entries with oldname = {entry['oldname']}\n") - sys.exit(1) - if entry['section'] + '.' + entry['name'] in dupcheck2: - sys.stderr.write((f"duplicate entries with section.name = " - f"{entry['section']}.{ entry['name']}\n")) - sys.exit(1) - dupcheck1[entry['oldname']] = True - dupcheck2[entry['section'] + '.' + entry['name']] = True - # And generate C++, Rust and docs code based on table - # 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(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 -Nru pdns-recursor-5.2.13/settings/rust/Cargo.lock pdns-recursor-5.4.9/settings/rust/Cargo.lock --- pdns-recursor-5.2.13/settings/rust/Cargo.lock 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/Cargo.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,323 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "cc" -version = "1.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" -dependencies = [ - "shlex", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "cxx" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ccead7d199d584d139148b04b4a368d1ec7556a1d9ea2548febb1b9d49f9a4" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77953e99f01508f89f55c494bfa867171ef3a6c8cea03d26975368f2121a5c1" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65777e06cc48f0cb0152024c77d6cf9e4bdb4408e7b48bea993d42fa0f5b02b6" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98532a60dedaebc4848cb2cba5023337cc9ea3af16a5b062633fabfd9f18fb60" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "indexmap" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "ipnet" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "link-cplusplus" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" -dependencies = [ - "cc", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "scratch" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" - -[[package]] -name = "serde" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "settings" -version = "5.2.0" -dependencies = [ - "base64", - "cxx", - "cxx-build", - "ipnet", - "once_cell", - "serde", - "serde_yaml", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "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 = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff -Nru pdns-recursor-5.2.13/settings/rust/Cargo.toml pdns-recursor-5.4.9/settings/rust/Cargo.toml --- pdns-recursor-5.2.13/settings/rust/Cargo.toml 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -[package] -name = "settings" -# Convention: major/minor is equal to rec's major/minor -version = "5.2.0" -edition = "2021" - -[lib] -name = "settings" -crate-type = ["staticlib"] - -[dependencies] -cxx = "1.0" -serde = { version = "1.0", features = ["derive"] } -serde_yaml = { version = "0.9.34" } -ipnet = "2.8" -once_cell = "1.18.0" -base64 = "0.22" - -[build-dependencies] -cxx-build = "1.0" - diff -Nru pdns-recursor-5.2.13/settings/rust/Makefile.am pdns-recursor-5.4.9/settings/rust/Makefile.am --- pdns-recursor-5.2.13/settings/rust/Makefile.am 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/Makefile.am 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -CARGO ?= cargo - -all install: libsettings.a - -EXTRA_DIST = \ - Cargo.toml \ - Cargo.lock \ - build.rs \ - src/bridge.rs \ - src/helpers.rs - -# should actually end up in a target specific dir... -libsettings.a lib.rs.h: src/bridge.rs src/lib.rs src/helpers.rs Cargo.toml Cargo.lock build.rs - SYSCONFDIR=$(sysconfdir) NODCACHEDIRNOD=$(localstatedir)/nod NODCACHEDIRUDR=$(localstatedir)/udr $(CARGO) build --release $(RUST_TARGET) --target-dir=$(builddir)/target --manifest-path ${srcdir}/Cargo.toml - cp target/$(RUSTC_TARGET_ARCH)/release/libsettings.a libsettings.a - cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/settings/src/lib.rs.h lib.rs.h - cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/rust/cxx.h cxx.h - -clean-local: - rm -rf libsettings.a src/lib.rs lib.rs.h cxx.h target diff -Nru pdns-recursor-5.2.13/settings/rust/Makefile.in pdns-recursor-5.4.9/settings/rust/Makefile.in --- pdns-recursor-5.2.13/settings/rust/Makefile.in 2026-08-05 12:01:46.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/Makefile.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,587 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = settings/rust -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \ - $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \ - $(top_srcdir)/m4/ax_check_sign.m4 \ - $(top_srcdir)/m4/ax_compare_version.m4 \ - $(top_srcdir)/m4/ax_compile_check_sizeof.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \ - $(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \ - $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/pdns_check_cargo.m4 \ - $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \ - $(top_srcdir)/m4/pdns_check_curl.m4 \ - $(top_srcdir)/m4/pdns_check_dnstap.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \ - $(top_srcdir)/m4/pdns_check_libcrypto_eddsa.m4 \ - $(top_srcdir)/m4/pdns_check_libcurl.m4 \ - $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \ - $(top_srcdir)/m4/pdns_check_network_libs.m4 \ - $(top_srcdir)/m4/pdns_check_os.m4 \ - $(top_srcdir)/m4/pdns_check_pthread_np.m4 \ - $(top_srcdir)/m4/pdns_check_python_venv.m4 \ - $(top_srcdir)/m4/pdns_check_ragel.m4 \ - $(top_srcdir)/m4/pdns_check_secure_memset.m4 \ - $(top_srcdir)/m4/pdns_check_time_t.m4 \ - $(top_srcdir)/m4/pdns_d_fortify_source.m4 \ - $(top_srcdir)/m4/pdns_enable_coverage.m4 \ - $(top_srcdir)/m4/pdns_enable_lto.m4 \ - $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \ - $(top_srcdir)/m4/pdns_enable_nod.m4 \ - $(top_srcdir)/m4/pdns_enable_reproducible.m4 \ - $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \ - $(top_srcdir)/m4/pdns_enable_tls.m4 \ - $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \ - $(top_srcdir)/m4/pdns_enable_valgrind.m4 \ - $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \ - $(top_srcdir)/m4/pdns_init_auto_vars.m4 \ - $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \ - $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \ - $(top_srcdir)/m4/pdns_stack_protector.m4 \ - $(top_srcdir)/m4/pdns_with_libcap.m4 \ - $(top_srcdir)/m4/pdns_with_libsodium.m4 \ - $(top_srcdir)/m4/pdns_with_libssl.m4 \ - $(top_srcdir)/m4/pdns_with_lua.m4 \ - $(top_srcdir)/m4/pdns_with_net_snmp.m4 \ - $(top_srcdir)/m4/pdns_with_service_user.m4 \ - $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_CPPFLAGS = @AM_CPPFLAGS@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BOOST_CONTEXT_LDFLAGS = @BOOST_CONTEXT_LDFLAGS@ -BOOST_CONTEXT_LDPATH = @BOOST_CONTEXT_LDPATH@ -BOOST_CONTEXT_LIBS = @BOOST_CONTEXT_LIBS@ -BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ -BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@ -BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@ -BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@ -BOOST_LDPATH = @BOOST_LDPATH@ -BOOST_ROOT = @BOOST_ROOT@ -BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@ -BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@ -BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@ -BOOST_THREAD_LDFLAGS = @BOOST_THREAD_LDFLAGS@ -BOOST_THREAD_LDPATH = @BOOST_THREAD_LDPATH@ -BOOST_THREAD_LIBS = @BOOST_THREAD_LIBS@ -BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@ -BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@ -BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@ -CARGO = @CARGO@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ -CURL = @CURL@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -DYNLINKFLAGS = @DYNLINKFLAGS@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ETAGS = @ETAGS@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FILECMD = @FILECMD@ -FSTRM_CFLAGS = @FSTRM_CFLAGS@ -FSTRM_LIBS = @FSTRM_LIBS@ -GREP = @GREP@ -HAVE_CXX17 = @HAVE_CXX17@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBCAP_CFLAGS = @LIBCAP_CFLAGS@ -LIBCAP_LIBS = @LIBCAP_LIBS@ -LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@ -LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@ -LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ -LIBCURL = @LIBCURL@ -LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ -LIBDL = @LIBDL@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ -LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ -LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ -LIBSSL_LIBS = @LIBSSL_LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -LUA_CFLAGS = @LUA_CFLAGS@ -LUA_LIBS = @LUA_LIBS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NET_SNMP_LIBS = @NET_SNMP_LIBS@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PIE_CFLAGS = @PIE_CFLAGS@ -PIE_LDFLAGS = @PIE_LDFLAGS@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@ -PYTHON = @PYTHON@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_PLATFORM = @PYTHON_PLATFORM@ -PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_VERSION = @PYTHON_VERSION@ -RAGEL = @RAGEL@ -RANLIB = @RANLIB@ -RELRO_LDFLAGS = @RELRO_LDFLAGS@ -RT_LIBS = @RT_LIBS@ -SANITIZER_FLAGS = @SANITIZER_FLAGS@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -SYSTEMCTL = @SYSTEMCTL@ -SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ -SYSTEMD_DIR = @SYSTEMD_DIR@ -SYSTEMD_LIBS = @SYSTEMD_LIBS@ -SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@ -THREADFLAGS = @THREADFLAGS@ -VERSION = @VERSION@ -WARN_CFLAGS = @WARN_CFLAGS@ -YAHTTP_CFLAGS = @YAHTTP_CFLAGS@ -YAHTTP_LIBS = @YAHTTP_LIBS@ -_libcurl_config = @_libcurl_config@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -nodcachedir = @nodcachedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pdns_configure_args = @pdns_configure_args@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -service_group = @service_group@ -service_user = @service_user@ -sharedstatedir = @sharedstatedir@ -socketdir = @socketdir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -systemd = @systemd@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -EXTRA_DIST = \ - Cargo.toml \ - Cargo.lock \ - build.rs \ - src/bridge.rs \ - src/helpers.rs - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign settings/rust/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign settings/rust/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-local mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: install-am install-strip - -.PHONY: all all-am check check-am clean clean-generic clean-libtool \ - clean-local cscopelist-am ctags-am distclean distclean-generic \ - distclean-libtool distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - -CARGO ?= cargo - -all install: libsettings.a - -# should actually end up in a target specific dir... -libsettings.a lib.rs.h: src/bridge.rs src/lib.rs src/helpers.rs Cargo.toml Cargo.lock build.rs - SYSCONFDIR=$(sysconfdir) NODCACHEDIRNOD=$(localstatedir)/nod NODCACHEDIRUDR=$(localstatedir)/udr $(CARGO) build --release $(RUST_TARGET) --target-dir=$(builddir)/target --manifest-path ${srcdir}/Cargo.toml - cp target/$(RUSTC_TARGET_ARCH)/release/libsettings.a libsettings.a - cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/settings/src/lib.rs.h lib.rs.h - cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/rust/cxx.h cxx.h - -clean-local: - rm -rf libsettings.a src/lib.rs lib.rs.h cxx.h target - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff -Nru pdns-recursor-5.2.13/settings/rust/build.rs pdns-recursor-5.4.9/settings/rust/build.rs --- pdns-recursor-5.2.13/settings/rust/build.rs 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/build.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -fn main() { - cxx_build::bridge("src/lib.rs") - // .file("src/source.cc") Code callable from Rust is in ../cxxsupport.cc - .flag_if_supported("-std=c++17") - .flag("-Isrc") - .compile("settings"); -} diff -Nru pdns-recursor-5.2.13/settings/rust/src/bridge.hh pdns-recursor-5.4.9/settings/rust/src/bridge.hh --- pdns-recursor-5.2.13/settings/rust/src/bridge.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/src/bridge.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +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 "rust/cxx.h" - -namespace pdns::rust::settings::rec -{ -uint16_t qTypeStringToCode(::rust::Str str); -bool isValidHostname(::rust::Str str); -} diff -Nru pdns-recursor-5.2.13/settings/rust/src/bridge.rs pdns-recursor-5.4.9/settings/rust/src/bridge.rs --- pdns-recursor-5.2.13/settings/rust/src/bridge.rs 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/src/bridge.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1203 +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. - */ - -use base64::prelude::*; -use once_cell::sync::Lazy; -use std::fs::File; -use std::io::{BufReader, BufWriter, ErrorKind, Write}; -use std::net::{IpAddr, SocketAddr}; -use std::str::FromStr; -use std::sync::Mutex; - -use crate::helpers::OVERRIDE_TAG; -use crate::recsettings::{self, *}; -use crate::{Merge, ValidationError}; - -impl Default for ForwardZone { - fn default() -> Self { - let deserialized: ForwardZone = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for AuthZone { - fn default() -> Self { - let deserialized: AuthZone = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for TrustAnchor { - fn default() -> Self { - let deserialized: TrustAnchor = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for NegativeTrustAnchor { - fn default() -> Self { - let deserialized: NegativeTrustAnchor = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for ApiZones { - fn default() -> Self { - let deserialized: ApiZones = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for XFR { - fn default() -> Self { - let deserialized: XFR = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for FCZDefault { - fn default() -> Self { - let deserialized: FCZDefault = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for ForwardingCatalogZone { - fn default() -> Self { - let deserialized: ForwardingCatalogZone = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -pub fn validate_socket_address(field: &str, val: &String) -> Result<(), ValidationError> { - let sa = SocketAddr::from_str(val); - if sa.is_err() { - let ip = IpAddr::from_str(val); - if ip.is_err() { - let msg = format!( - "{}: value `{}' is not an IP or IP:port combination", - field, val - ); - return Err(ValidationError { msg }); - } - } - Ok(()) -} - -fn is_port_number(str: &str) -> bool { - str.parse::().is_ok() -} - -pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), ValidationError> { - let sa = validate_socket_address(field, val); - 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(()) -} - -fn validate_qtype(field: &str, val: &String) -> Result<(), ValidationError> { - let code = qTypeStringToCode(val); - if code == 0 { - let msg = format!("{}: value `{}' is not a qtype", field, val); - return Err(ValidationError { msg }); - } - Ok(()) -} - -fn validate_name(field: &str, val: &String) -> Result<(), ValidationError> { - if val.is_empty() { - let msg = format!("{}: value may not be empty", field); - return Err(ValidationError { msg }); - } - if val == "." { - return Ok(()); - } - // Strip potential dot at end - let mut testval = val.as_str(); - if testval.ends_with('.') { - testval = &testval[0..testval.len() - 1]; - } - for label in testval.split('.') { - if label.is_empty() { - let msg = format!("{}: `{}' has empty label", field, val); - return Err(ValidationError { msg }); - } - // XXX Too liberal, should check for alnum, - and proper \ddd - if !label.is_ascii() { - let msg = format!("{}: `{}' contains non-ascii character", field, val); - return Err(ValidationError { msg }); - } - } - Ok(()) -} - -pub fn validate_subnet(field: &str, val: &String) -> Result<(), ValidationError> { - if val.is_empty() { - let msg = format!("{}: value `{}' is not a subnet or IP", field, val); - return Err(ValidationError { msg }); - } - let mut ip = val.as_str(); - if val.starts_with('!') { - ip = &ip[1..]; - } - let subnet = ipnet::IpNet::from_str(ip); - if subnet.is_err() { - let ip = IpAddr::from_str(ip); - if ip.is_err() { - let msg = format!("{}: value `{}' is not a subnet or IP", field, val); - return Err(ValidationError { msg }); - } - } - Ok(()) -} - -fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], local_address: &String) -> Result<(), ValidationError> { - if vec.is_empty() { - let msg = format!("{}: cannot be empty", addrfield); - return Err(ValidationError { msg }); - } - validate_vec(addrfield, vec, validate_socket_address_or_name)?; - if local_address.is_empty() { - return Ok(()); - } - let local = IpAddr::from_str(local_address); - if local.is_err() { - let msg = format!("{}: value `{}' is not an IP", localfield, local_address); - return Err(ValidationError { msg }); - } - let local = local.unwrap(); - for addr_str in vec { - let mut wrong = false; - let sa = SocketAddr::from_str(addr_str); - if sa.is_err() { - let ip = IpAddr::from_str(addr_str); - if ip.is_err() { // It is likely a name - continue; - } - let ip = ip.unwrap(); - if local.is_ipv4() != ip.is_ipv4() || local.is_ipv6() != ip.is_ipv6() { - wrong = true; - } - } - else { - let sa = sa.unwrap(); - if local.is_ipv4() != sa.is_ipv4() || local.is_ipv6() != sa.is_ipv6() { - wrong = true; - } - } - if wrong { - let msg = format!("{}: value `{}' and `{}' differ in address family", localfield, local_address, addr_str); - return Err(ValidationError { msg }); - } - } - Ok(()) -} - -pub fn validate_vec(field: &str, vec: &[T], func: F) -> Result<(), ValidationError> -where - F: Fn(&str, &T) -> Result<(), ValidationError>, -{ - vec.iter().try_for_each(|element| func(field, element)) -} - -pub fn parse_yaml_string(str: &str) -> Result { - serde_yaml::from_str(str) -} - -pub fn parse_yaml_string_to_allow_from(str: &str) -> Result, serde_yaml::Error> { - serde_yaml::from_str(str) -} - -pub fn parse_yaml_string_to_forward_zones( - str: &str, -) -> Result, serde_yaml::Error> { - serde_yaml::from_str(str) -} - -pub fn parse_yaml_string_to_api_zones(str: &str) -> Result { - serde_yaml::from_str(str) -} - -pub fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result, serde_yaml::Error> { - serde_yaml::from_str(str) -} - -pub fn forward_zones_to_yaml_string(vec: &Vec) -> Result { - serde_yaml::to_string(vec) -} - -fn insertb(map: &mut serde_yaml::Mapping, name: &str, val: bool) { - map.insert( - serde_yaml::Value::String(name.to_owned()), - serde_yaml::Value::Bool(val), - ); -} - -fn insertu(map: &mut serde_yaml::Mapping, name: &str, val: u64) { - map.insert( - serde_yaml::Value::String(name.to_owned()), - serde_yaml::Value::Number(serde_yaml::Number::from(val)), - ); -} - -fn insertu32(map: &mut serde_yaml::Mapping, name: &str, val: u32) { - map.insert( - serde_yaml::Value::String(name.to_owned()), - serde_yaml::Value::Number(serde_yaml::Number::from(val)), - ); -} - -fn inserts(map: &mut serde_yaml::Mapping, name: &str, val: &str) { - map.insert( - serde_yaml::Value::String(name.to_owned()), - serde_yaml::Value::String(val.to_owned()), - ); -} - -fn insertseq(map: &mut serde_yaml::Mapping, name: &str, val: &serde_yaml::Sequence) { - map.insert( - serde_yaml::Value::String(name.to_owned()), - serde_yaml::Value::Sequence(val.to_owned()), - ); -} - -impl ForwardZone { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - validate_name(&(field.to_owned() + ".zone"), &self.zone)?; - if self.forwarders.is_empty() { - let msg = format!("{}.forwarders cannot be empty", field); - return Err(ValidationError { msg }); - } - validate_vec( - &(field.to_owned() + ".forwarders"), - &self.forwarders, - validate_socket_address_or_name, - ) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.forwarders { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "zone", &self.zone); - insertb(&mut map, "recurse", self.recurse); - map.insert( - serde_yaml::Value::String("forwarders".to_owned()), - serde_yaml::Value::Sequence(seq), - ); - serde_yaml::Value::Mapping(map) - } -} - -impl AuthZone { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - validate_name(&(field.to_owned() + ".zone"), &self.zone)?; - if self.file.is_empty() { - let msg = format!("{}.file cannot be empty", field); - return Err(ValidationError { msg }); - } - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "zone", &self.zone); - inserts(&mut map, "file", &self.file); - serde_yaml::Value::Mapping(map) - } -} - -impl TrustAnchor { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.dsrecords { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "name", &self.name); - insertseq(&mut map, "dsrecords", &seq); - serde_yaml::Value::Mapping(map) - } -} - -impl NegativeTrustAnchor { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "name", &self.name); - inserts(&mut map, "reason", &self.reason); - serde_yaml::Value::Mapping(map) - } -} - -impl ProtobufServer { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - validate_vec( - &(field.to_owned() + ".servers"), - &self.servers, - validate_socket_address, - )?; - validate_vec( - &(field.to_owned() + ".exportTypes"), - &self.exportTypes, - validate_qtype, - )?; - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.servers { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - let mut map = serde_yaml::Mapping::new(); - insertseq(&mut map, "servers", &seq); - insertu(&mut map, "timeout", self.timeout); - insertu(&mut map, "maxQueuedEntries", self.maxQueuedEntries); - insertu(&mut map, "reconnectWaitTime", self.reconnectWaitTime); - insertb(&mut map, "taggedOnly", self.taggedOnly); - insertb(&mut map, "asyncConnect", self.asyncConnect); - insertb(&mut map, "logQueries", self.logQueries); - insertb(&mut map, "logResponses", self.logResponses); - let mut seq2 = serde_yaml::Sequence::new(); - for entry in &self.exportTypes { - seq2.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "exportTypes", &seq2); - insertb(&mut map, "logMappedFrom", self.logMappedFrom); - serde_yaml::Value::Mapping(map) - } -} - -impl DNSTapFrameStreamServer { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.servers { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - let mut map = serde_yaml::Mapping::new(); - insertseq(&mut map, "servers", &seq); - insertb(&mut map, "logQueries", self.logQueries); - insertb(&mut map, "logResponses", self.logResponses); - insertu(&mut map, "bufferHint", self.bufferHint); - insertu(&mut map, "flushTimeout", self.flushTimeout); - insertu(&mut map, "inputQueueSize", self.inputQueueSize); - insertu(&mut map, "outputQueueSize", self.outputQueueSize); - insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold); - insertu(&mut map, "reopenInterval", self.reopenInterval); - serde_yaml::Value::Mapping(map) - } -} - -impl DNSTapNODFrameStreamServer { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.servers { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - let mut map = serde_yaml::Mapping::new(); - insertseq(&mut map, "servers", &seq); - insertb(&mut map, "logNODs", self.logNODs); - insertb(&mut map, "logUDRs", self.logUDRs); - insertu(&mut map, "bufferHint", self.bufferHint); - insertu(&mut map, "flushTimeout", self.flushTimeout); - insertu(&mut map, "inputQueueSize", self.inputQueueSize); - insertu(&mut map, "outputQueueSize", self.outputQueueSize); - insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold); - insertu(&mut map, "reopenInterval", self.reopenInterval); - serde_yaml::Value::Mapping(map) - } -} - -impl SortList { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "key", &self.key); - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.subnets { - let mut submap = serde_yaml::Mapping::new(); - inserts(&mut submap, "subnet", &entry.subnet); - insertu32(&mut submap, "order", entry.order); - seq.push(serde_yaml::Value::Mapping(submap)); - } - insertseq(&mut map, "subnets", &seq); - serde_yaml::Value::Mapping(map) - } -} - -impl RPZ { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - if self.extendedErrorCode > u16::MAX as u32 && self.extendedErrorCode != u32::MAX { - let msg = format!( - "{}: value `{}' is no a valid extendedErrorCode", - field, self.extendedErrorCode - ); - return Err(ValidationError { msg }); - } - self.tsig.validate(&(field.to_owned() + ".tsig"))?; - if !self.addresses.is_empty() { - validate_address_family(&(field.to_owned() + ".addresses"), &(field.to_owned() + ".localAddress"), &self.addresses, &self.localAddress)?; - } - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - let mut seq1 = serde_yaml::Sequence::new(); - for entry in &self.addresses { - seq1.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "addresses", &seq1); - inserts(&mut map, "name", &self.name); - inserts(&mut map, "defcontent", &self.defcontent); - inserts(&mut map, "defpol", &self.defpol); - insertb( - &mut map, - "defpolOverrideLocalData", - self.defpolOverrideLocalData, - ); - insertu32(&mut map, "defttl", self.defttl); - insertu32(&mut map, "extendedErrorCode", self.extendedErrorCode); - insertb(&mut map, "includeSOA", self.includeSOA); - insertb(&mut map, "ignoreDuplicates", self.ignoreDuplicates); - insertu32(&mut map, "maxTTL", self.maxTTL); - inserts(&mut map, "policyName", &self.policyName); - let mut seq2 = serde_yaml::Sequence::new(); - for entry in &self.tags { - seq2.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "tags", &seq2); - insertb(&mut map, "overridesGettag", self.overridesGettag); - insertu32(&mut map, "zoneSizeHint", self.zoneSizeHint); - - let mut tsigmap = serde_yaml::Mapping::new(); - inserts(&mut tsigmap, "name", &self.tsig.name); - inserts(&mut tsigmap, "algo", &self.tsig.algo); - inserts(&mut tsigmap, "secret", &self.tsig.secret); - map.insert( - serde_yaml::Value::String("tsig".to_owned()), - serde_yaml::Value::Mapping(tsigmap), - ); - - insertu32(&mut map, "refresh", self.refresh); - insertu32(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes); - inserts(&mut map, "localAddress", &self.localAddress); - insertu32(&mut map, "axfrTimeout", self.axfrTimeout); - inserts(&mut map, "dumpFile", &self.dumpFile); - inserts(&mut map, "seedFile", &self.seedFile); - serde_yaml::Value::Mapping(map) - } -} - -impl ZoneToCache { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - match self.method.as_str() { - "axfr" | "url" | "file" => {} - _ => { - let msg = format!( - "{}: must be one of axfr, url, file", - &(field.to_string() + ".method") - ); - return Err(ValidationError { msg }); - } - } - if self.sources.is_empty() { - let msg = format!( - "{}: at least one source required", - &(field.to_string() + ".sources") - ); - return Err(ValidationError { msg }); - } - if self.method == "axfr" { - validate_vec( - &(field.to_string() + ".sources"), - &self.sources, - validate_socket_address, - )?; - validate_address_family(&(field.to_string() + ".sources"), &(field.to_string() + ".localAddress"), &self.sources, &self.localAddress)?; - } - self.tsig.validate(&(field.to_owned() + ".tsig"))?; - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "zone", &self.zone); - inserts(&mut map, "method", &self.method); - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.sources { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "sources", &seq); - insertu(&mut map, "timeout", self.timeout); - - let mut tsigmap = serde_yaml::Mapping::new(); - inserts(&mut tsigmap, "name", &self.tsig.name); - inserts(&mut tsigmap, "algo", &self.tsig.algo); - inserts(&mut tsigmap, "secret", &self.tsig.secret); - map.insert( - serde_yaml::Value::String("tsig".to_owned()), - serde_yaml::Value::Mapping(tsigmap), - ); - - insertu(&mut map, "refreshPeriod", self.refreshPeriod); - insertu(&mut map, "retryOnErrorPeriod", self.retryOnErrorPeriod); - insertu(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes); - inserts(&mut map, "localAddress", &self.localAddress); - inserts(&mut map, "zonemd", &self.zonemd); - inserts(&mut map, "dnssec", &self.dnssec); - - serde_yaml::Value::Mapping(map) - } -} - -impl AllowedAdditionalQType { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "qtype", &self.qtype); - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.targets { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "targets", &seq); - inserts(&mut map, "mode", &self.mode); - serde_yaml::Value::Mapping(map) - } -} - -impl ProxyMapping { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "subnet", &self.subnet); - inserts(&mut map, "address", &self.address); - let mut seq = serde_yaml::Sequence::new(); - for entry in &self.domains { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - insertseq(&mut map, "domains", &seq); - serde_yaml::Value::Mapping(map) - } -} - -impl TSIGTriplet { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - let namelen = self.name.len(); - let algolen = self.algo.len(); - let secretlen = self.secret.len(); - if namelen == 0 && algolen == 0 && secretlen == 0 { - return Ok(()); - } - if namelen == 0 || algolen == 0 || secretlen == 0 { - let msg = format!("{}: a field value is missing", field); - return Err(ValidationError { msg }); - } - if BASE64_STANDARD.decode(&self.secret).is_err() { - let msg = format!("{}.secret: `{}' is not a Base64 string", field, self.secret); - return Err(ValidationError { msg }); - } - Ok(()) - } -} - -impl ForwardingCatalogZone { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - self.xfr.tsig.validate(&(field.to_owned() + ".xfr.tsig"))?; - if !self.xfr.addresses.is_empty() { - validate_address_family(&(field.to_owned() + ".xfr.addresses"), &(field.to_owned() + ".xfr.localAddress"), &self.xfr.addresses, &self.xfr.localAddress)?; - } - else { - let msg = format!("{}.xfr.addresses: at least one address required", field); - return Err(ValidationError { msg }); - } - Ok(()) - } - - fn to_yaml_map(&self) -> serde_yaml::Value { - let mut map = serde_yaml::Mapping::new(); - inserts(&mut map, "zone", &self.zone); - insertb(&mut map, "notify_allowed", self.notify_allowed); - - let mut xfrmap = serde_yaml::Mapping::new(); - let mut addrs = serde_yaml::Sequence::new(); - for address in &self.xfr.addresses { - addrs.push(serde_yaml::Value::String(address.to_owned())); - } - insertseq(&mut xfrmap, "addresses", &addrs); - insertu32(&mut xfrmap, "zoneSizeHint", self.xfr.zoneSizeHint); - let mut tsigmap = serde_yaml::Mapping::new(); - inserts(&mut tsigmap, "name", &self.xfr.tsig.name); - inserts(&mut tsigmap, "algo", &self.xfr.tsig.algo); - inserts(&mut tsigmap, "secret", &self.xfr.tsig.secret); - xfrmap.insert( - serde_yaml::Value::String("tsig".to_owned()), - serde_yaml::Value::Mapping(tsigmap), - ); - insertu32(&mut xfrmap, "refresh", self.xfr.refresh); - insertu32(&mut xfrmap, "maxReceivedMBytes", self.xfr.maxReceivedMBytes); - inserts(&mut xfrmap, "localAddress", &self.xfr.localAddress); - insertu32(&mut xfrmap, "axfrTimeout", self.xfr.axfrTimeout); - map.insert( - serde_yaml::Value::String("xfr".to_owned()), - serde_yaml::Value::Mapping(xfrmap), - ); - - let mut groupseq = serde_yaml::Sequence::new(); - for entry in &self.groups { - let mut submap = serde_yaml::Mapping::new(); - inserts(&mut submap, "name", &entry.name); - let mut fwseq = serde_yaml::Sequence::new(); - for forwarder in &entry.forwarders { - fwseq.push(serde_yaml::Value::String(forwarder.to_owned())); - } - insertseq(&mut submap, "forwarders", &fwseq); - insertb(&mut submap, "recurse", entry.recurse); - insertb(&mut submap, "notify_allowed", entry.notify_allowed); - groupseq.push(serde_yaml::Value::Mapping(submap)); - } - insertseq(&mut map, "groups", &groupseq); - serde_yaml::Value::Mapping(map) - } -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_auth_zones(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, |field, element| element.validate(field)) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_forward_zones(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, |field, element| element.validate(field)) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_trustanchors(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, |field, element| element.validate(field)) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_negativetrustanchors( - field: &str, - vec: &Vec, -) -> Result<(), ValidationError> { - validate_vec(field, vec, |field, element| element.validate(field)) -} - -pub fn allow_from_to_yaml_string(vec: &Vec) -> Result { - let mut seq = serde_yaml::Sequence::new(); - for entry in vec { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - let val = serde_yaml::Value::Sequence(seq); - - serde_yaml::to_string(&val) -} - -pub fn allow_from_to_yaml_string_incoming( - key: &String, - filekey: &String, - vec: &Vec, -) -> Result { - // Produce - // incoming: - // allow-from-file: '' - // allow-from: !override - // - ... - let mut seq = serde_yaml::Sequence::new(); - for entry in vec { - seq.push(serde_yaml::Value::String(entry.to_owned())); - } - - let mut innermap = serde_yaml::Mapping::new(); - innermap.insert( - serde_yaml::Value::String(filekey.to_owned()), - serde_yaml::Value::String("".to_owned()), - ); - let af = Box::new(serde_yaml::value::TaggedValue { - tag: serde_yaml::value::Tag::new(OVERRIDE_TAG), - value: serde_yaml::Value::Sequence(seq), - }); - innermap.insert( - serde_yaml::Value::String(key.to_owned()), - serde_yaml::Value::Tagged(af), - ); - - let mut outermap = serde_yaml::Mapping::new(); - outermap.insert( - serde_yaml::Value::String("incoming".to_owned()), - serde_yaml::Value::Mapping(innermap), - ); - let outerval = serde_yaml::Value::Mapping(outermap); - - serde_yaml::to_string(&outerval) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_allow_from(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, validate_subnet) -} - -pub fn allow_for_to_yaml_string(vec: &Vec) -> Result { - // For purpose of generating yaml allow-for is no different than allow-from as we're handling a - // vector of Strings - allow_from_to_yaml_string(vec) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_allow_for(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, validate_name) -} - -#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. -pub fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<(), ValidationError> { - validate_vec(field, vec, validate_name) -} - -impl Recursorsettings { - pub fn to_yaml_string(&self) -> Result { - serde_yaml::to_string(self) - } - - // validate() is implemented in the (generated) lib.rs -} - -pub static DEFAULT_CONFIG: Lazy = Lazy::new(Recursorsettings::default); - -pub fn merge_vec(lhs: &mut Vec, rhs: &mut Vec) { - lhs.append(rhs); -} - -// This is used for conversion, where we want to have !override tags in some cases, so we craft a YAML Mapping by hand -pub fn map_to_yaml_string(vec: &Vec) -> Result { - let mut map = serde_yaml::Mapping::new(); - for entry in vec { - let section = entry.section.as_str(); - if !map.contains_key(section) { - let newmap = serde_yaml::Mapping::new(); - map.insert( - serde_yaml::Value::String(section.to_string()), - serde_yaml::Value::Mapping(newmap), - ); - } - if let Some(mapentry) = map.get_mut(section) { - if let Some(mapping) = mapentry.as_mapping_mut() { - let val = match entry.type_name.as_str() { - "bool" => serde_yaml::Value::Bool(entry.value.bool_val), - "u64" => { - serde_yaml::Value::Number(serde_yaml::Number::from(entry.value.u64_val)) - } - "f64" => { - serde_yaml::Value::Number(serde_yaml::Number::from(entry.value.f64_val)) - } - "String" => serde_yaml::Value::String(entry.value.string_val.to_owned()), - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_string_val { - seq.push(serde_yaml::Value::String(element.to_owned())) - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_forwardzone_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_authzone_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_trustanchor_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_negativetrustanchor_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_protobufserver_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_dnstap_framestream_server_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_dnstap_nod_framestream_server_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_rpz_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_sortlist_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_zonetocache_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_allowedadditionalqtype_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_proxymapping_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - "Vec" => { - let mut seq = serde_yaml::Sequence::new(); - for element in &entry.value.vec_forwardingcatalogzone_val { - seq.push(element.to_yaml_map()); - } - serde_yaml::Value::Sequence(seq) - } - other => serde_yaml::Value::String( - "map_to_yaml_string: Unknown type: ".to_owned() + other, - ), - }; - if entry.overriding { - let tagged_value = Box::new(serde_yaml::value::TaggedValue { - tag: serde_yaml::value::Tag::new(OVERRIDE_TAG), - value: val, - }); - mapping.insert( - serde_yaml::Value::String(entry.name.to_owned()), - serde_yaml::Value::Tagged(tagged_value), - ); - } else { - mapping.insert(serde_yaml::Value::String(entry.name.to_owned()), val); - } - } - } - } - serde_yaml::to_string(&map) -} - -pub fn merge(lhs: &mut Recursorsettings, yaml_str: &str) -> Result<(), serde_yaml::Error> { - // Parse the yaml for the values - let mut rhs: Recursorsettings = serde_yaml::from_str(yaml_str)?; - // Parse again for the map containing the keys present, which is used to only override specific values, - // taking into account !override tags - let map: serde_yaml::Value = serde_yaml::from_str(yaml_str)?; - if map.is_mapping() { - lhs.merge(&mut rhs, map.as_mapping()); - } - - Ok(()) -} - -// API zones maintenance. In contrast to the old settings code, which creates a settings file per -// zone, we maintain a single yaml file with all settings. File locking is no issue, as we are the -// single process managing this dir. So we only use process specific locking. - -impl ApiZones { - pub fn validate(&self, field: &str) -> Result<(), ValidationError> { - validate_auth_zones(&(field.to_owned() + ".auth_zones"), &self.auth_zones)?; - validate_forward_zones(&(field.to_owned() + ".forward_zones"), &self.forward_zones)?; - Ok(()) - } -} - -static LOCK: Mutex = Mutex::new(false); - -// Assume we hold the lock -fn api_read_zones_locked( - path: &str, - create: bool, -) -> Result, std::io::Error> { - let zones = match File::open(path) { - Ok(file) => { - let data: Result = - serde_yaml::from_reader(BufReader::new(file)); - match data { - Err(error) => return Err(std::io::Error::new(ErrorKind::Other, error.to_string())), - Ok(yaml) => yaml, - } - } - Err(error) => match error.kind() { - // If the file does not exist we return an empty struct - ErrorKind::NotFound => { - if create { - ApiZones::default() - } else { - return Err(error); - } - } - // Any other error is fatal - _ => return Err(error), - }, - }; - Ok(cxx::UniquePtr::new(zones)) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_read_zones(path: &str) -> Result, std::io::Error> { - let _lock = LOCK.lock().unwrap(); - api_read_zones_locked(path, false) -} - -// Assume we hold the lock -fn api_write_zones(path: &str, zones: &ApiZones) -> Result<(), std::io::Error> { - let mut tmpfile = path.to_owned(); - tmpfile.push_str(".tmp"); - - let file = File::create(tmpfile.as_str())?; - let mut buffered_writer = BufWriter::new(&file); - if let Err(error) = serde_yaml::to_writer(&mut buffered_writer, &zones) { - return Err(std::io::Error::new(ErrorKind::Other, error.to_string())); - } - buffered_writer.flush()?; - file.sync_all()?; - drop(buffered_writer); - std::fs::rename(tmpfile.as_str(), path) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_add_auth_zone(path: &str, authzone: AuthZone) -> Result<(), std::io::Error> { - let _lock = LOCK.lock().unwrap(); - let mut zones = api_read_zones_locked(path, true)?; - zones.auth_zones.push(authzone); - api_write_zones(path, &zones) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_add_forward_zone(path: &str, forwardzone: ForwardZone) -> Result<(), std::io::Error> { - let _lock = LOCK.lock().unwrap(); - let mut zones = api_read_zones_locked(path, true)?; - zones.forward_zones.push(forwardzone); - api_write_zones(path, &zones) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_add_forward_zones( - path: &str, - forwardzones: &mut Vec, -) -> Result<(), std::io::Error> { - let _lock = LOCK.lock().unwrap(); - let mut zones = api_read_zones_locked(path, true)?; - zones.forward_zones.append(forwardzones); - api_write_zones(path, &zones) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_delete_zone(path: &str, zone: &str) -> Result<(), std::io::Error> { - let _lock = LOCK.lock().unwrap(); - let mut zones = api_read_zones_locked(path, true)?; - zones.auth_zones.retain(|x| x.zone != zone); - // Zone data file is unlinked in the C++ caller ws-recursor.cc:doDeleteZone() - zones.forward_zones.retain(|x| x.zone != zone); - api_write_zones(path, &zones) -} - -// This function is called from C++, it needs to acquire the lock -pub fn api_delete_zones(path: &str) -> Result<(), std::io::Error> { - let _lock = LOCK.lock().unwrap(); - let mut zones = api_read_zones_locked(path, true)?; - zones.forward_zones.clear(); - api_write_zones(path, &zones) -} - -pub fn def_pb_export_qtypes() -> Vec { - vec![ - String::from("A"), - String::from("CNAME"), - String::from("AAAA"), - ] -} - -pub fn default_value_equal_pb_export_qtypes(value: &Vec) -> bool { - &def_pb_export_qtypes() == value -} - -pub fn def_ztc_validate() -> String { - String::from("validate") -} - -pub fn def_value_equals_ztc_validate(value: &String) -> bool { - &def_ztc_validate() == value -} - -pub fn def_additional_mode() -> String { - String::from("CacheOnlyRequireAuth") -} - -pub fn default_value_equals_additional_mode(value: &String) -> bool { - &def_additional_mode() == value -} - -pub fn validate_dnssec(dnssec: &recsettings::Dnssec) -> Result<(), ValidationError> { - let val = dnssec.validation.as_str(); - match val { - "off" | "process-no-validate" | "process" | "log-fail" | "validate" => {} - _ => { - let msg = format!("dnssec.validation: value `{}' is unknown", val); - return Err(ValidationError { msg }); - } - }; - Ok(()) -} - -pub fn validate_incoming(_incoming: &recsettings::Incoming) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_recursor(_recursor: &recsettings::Recursor) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_webservice(_webservice: &recsettings::Webservice) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_carbon(_carbon: &recsettings::Carbon) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_outgoing(_outgoing: &recsettings::Outgoing) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_packetcache( - _packetcache: &recsettings::Packetcache, -) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_logging(logging: &recsettings::Logging) -> Result<(), ValidationError> { - if logging.protobuf_servers.len() > 1 { - return Err(ValidationError { - msg: String::from("number of protobuf_servers must be <= 1"), - }); - } - if logging.outgoing_protobuf_servers.len() > 1 { - return Err(ValidationError { - msg: String::from("number of outgoing_protobuf_servers must be <= 1"), - }); - } - if logging.dnstap_framestream_servers.len() > 1 { - return Err(ValidationError { - msg: String::from("number of dnstap_framestream_servers must be <= 1"), - }); - } - if logging.dnstap_nod_framestream_servers.len() > 1 { - return Err(ValidationError { - msg: String::from("number of dnstap_nod_framestream_servers must be <= 1"), - }); - } - Ok(()) -} - -pub fn validate_ecs(_ecs: &recsettings::Ecs) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_nod(_nod: &recsettings::Nod) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_recordcache( - _recordcache: &recsettings::Recordcache, -) -> Result<(), ValidationError> { - Ok(()) -} - -pub fn validate_snmp(_snmp: &recsettings::Snmp) -> Result<(), ValidationError> { - Ok(()) -} - diff -Nru pdns-recursor-5.2.13/settings/rust/src/helpers.rs pdns-recursor-5.4.9/settings/rust/src/helpers.rs --- pdns-recursor-5.2.13/settings/rust/src/helpers.rs 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/src/helpers.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +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. - */ - -use crate::ValidationError; -use std::{error::Error, fmt}; - -/* Helper code for validation */ -impl Error for ValidationError {} -impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.msg) - } -} - -// Generic helpers - -// A helper to define a function returning a constant value and an equal function as a Rust path */ -pub struct U64; -impl U64 { - pub const fn value() -> u64 { - U - } - pub fn is_equal(v: &u64) -> bool { - v == &U - } -} - -pub struct U32; -impl U32 { - pub const fn value() -> u32 { - U - } - pub fn is_equal(v: &u32) -> bool { - v == &U - } -} - -// A helper to define constant value as a Rust path */ -pub struct Bool; -impl Bool { - pub const fn value() -> bool { - U - } -} - -// A helper used to decide if a bool value should be skipped -pub fn if_true(v: &bool) -> bool { - *v -} - -/* Helper to decide if a value has a default value, as defined by Default trait */ -pub fn is_default(t: &T) -> bool { - t == &T::default() -} - -pub const OVERRIDE_TAG: &str = "!override"; - -pub fn is_overriding(m: &serde_yaml::Mapping, key: &str) -> bool { - if let Some(serde_yaml::Value::Tagged(vvv)) = m.get(key) { - return vvv.tag == OVERRIDE_TAG; - } - false -} diff -Nru pdns-recursor-5.2.13/settings/rust/src/lib.rs pdns-recursor-5.4.9/settings/rust/src/lib.rs --- pdns-recursor-5.2.13/settings/rust/src/lib.rs 2026-08-05 12:02:35.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust/src/lib.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,3735 +0,0 @@ -// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE: see settings dir -// START INCLUDE rust-preable-in.rs -/* - * 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. - */ - -// This file (rust-preamble-in.rs) is included at the start of lib.rs - -use serde::{Deserialize, Serialize}; - -mod helpers; -use helpers::*; - -mod bridge; -use bridge::*; - -// Suppresses "Deserialize unused" warning -#[derive(Deserialize, Serialize)] -struct UnusedStruct {} - -trait Validate { - fn validate(&self) -> Result<(), ValidationError>; -} - -#[derive(Debug)] -pub struct ValidationError { - msg: String, -} - -trait Merge { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>); -} -// END INCLUDE rust-preamble-in.rs - -#[cxx::bridge(namespace = "pdns::rust::settings::rec")] -mod recsettings { - // START INCLUDE rust-bridge-in.rs - // This file (rust-bridge-in.rs) is included into lib.rs inside the bridge module - /* - * Implement non-generated structs that need to be handled by Serde and CXX - */ - - // A single forward zone - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ForwardZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - forwarders: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - recurse: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, - } - - // A single auth zone - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct AuthZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - file: String, - } - - // A single trust anchor - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct TrustAnchor { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - dsrecords: Vec, - } - - // A single negative trust anchor - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct NegativeTrustAnchor { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - reason: String, - } - - // A protobuf logging server - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ProtobufServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - timeout: u64, - #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] - maxQueuedEntries: u64, - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - reconnectWaitTime: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - taggedOnly: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - asyncConnect: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logQueries: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logResponses: bool, - #[serde(default = "crate::def_pb_export_qtypes", skip_serializing_if = "crate::default_value_equal_pb_export_qtypes")] - exportTypes: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - logMappedFrom: bool, - } - - // A dnstap logging server - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct DNSTapFrameStreamServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logQueries: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logResponses: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - bufferHint: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - flushTimeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - inputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - outputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - queueNotifyThreshold: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - reopenInterval: u64, - } - - // A dnstap logging NOD server - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct DNSTapNODFrameStreamServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logNODs: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - logUDRs: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - bufferHint: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - flushTimeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - inputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - outputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - queueNotifyThreshold: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - reopenInterval: u64, - } - - #[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct TSIGTriplet { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - algo: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - secret: String, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct RPZ { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - addresses: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - defcontent: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - defpol: String, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - defpolOverrideLocalData: bool, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - defttl: u32, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - extendedErrorCode: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - extendedErrorExtra: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - includeSOA: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - ignoreDuplicates: bool, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - maxTTL: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - policyName: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - tags: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - overridesGettag: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - zoneSizeHint: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default, skip_serializing_if = "crate::is_default")] - refresh: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal")] - axfrTimeout: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - dumpFile: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - seedFile: String, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ZoneToCache { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - method: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - sources: Vec, - #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] - timeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] - refreshPeriod: u64, - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - retryOnErrorPeriod: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] - zonemd: String, - #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] - dnssec: String, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct SubnetOrder { - #[serde(default, skip_serializing_if = "crate::is_default")] - subnet: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - order: u32, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct SortList { - #[serde(default, skip_serializing_if = "crate::is_default")] - key: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - subnets: Vec, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct AllowedAdditionalQType { - #[serde(default, skip_serializing_if = "crate::is_default")] - qtype: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - targets: Vec, - #[serde(default = "crate::def_additional_mode", skip_serializing_if = "crate::default_value_equals_additional_mode")] - mode: String, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ProxyMapping { - #[serde(default, skip_serializing_if = "crate::is_default")] - subnet: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - address: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - domains: Vec, - } - - // A struct holding both a vector of forward zones and a vector of auth zones, used by REST API code - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ApiZones { - #[serde(default, skip_serializing_if = "crate::is_default")] - auth_zones: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - forward_zones: Vec, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct XFR { - #[serde(default, skip_serializing_if = "crate::is_default")] - addresses: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - zoneSizeHint: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default, skip_serializing_if = "crate::is_default")] - refresh: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal")] - axfrTimeout: u32, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct FCZDefault { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - forwarders: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - recurse: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, - } - - #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct ForwardingCatalogZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - xfr: XFR, - #[serde(default, skip_serializing_if = "crate::is_default")] - groups: Vec, - } - - // Two structs used to generated YAML based on a vector of name to value mappings - // Cannot use Enum as CXX has only very basic Enum support - struct Value { - bool_val: bool, - u64_val: u64, - f64_val: f64, - string_val: String, - vec_string_val: Vec, - vec_forwardzone_val: Vec, - vec_authzone_val: Vec, - vec_trustanchor_val: Vec, - vec_negativetrustanchor_val: Vec, - vec_protobufserver_val: Vec, - vec_dnstap_framestream_server_val: Vec, - vec_dnstap_nod_framestream_server_val: Vec, - vec_rpz_val: Vec, - vec_sortlist_val: Vec, - vec_zonetocache_val: Vec, - vec_allowedadditionalqtype_val: Vec, - vec_proxymapping_val: Vec, - vec_forwardingcatalogzone_val: Vec, - } - - struct OldStyle { - section: String, - name: String, - old_name: String, - type_name: String, - value: Value, - overriding: bool, - } - - /* - * Functions callable from C++ - */ - extern "Rust" { - // Parse a string representing YAML text and produce the corresponding data structure known to Serde - // The settings that can be stored in individual files get their own parse function - // Main recursor settings - fn parse_yaml_string(str: &str) -> Result; - // Allow from sequence - fn parse_yaml_string_to_allow_from(str: &str) -> Result>; - // Forward zones sequence - fn parse_yaml_string_to_forward_zones(str: &str) -> Result>; - // Allow notify for sequence - fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result>; - // REST API zones - fn parse_yaml_string_to_api_zones(str: &str) -> Result; - - // Prdoduce a YAML formatted string given a data structure known to Serde - fn to_yaml_string(self: &Recursorsettings) -> Result; - // When doing a conversion of old-style to YAML style we use a vector of OldStyle structs - fn map_to_yaml_string(map: &Vec) -> Result; - fn forward_zones_to_yaml_string(vec: &Vec) -> Result; - fn allow_from_to_yaml_string(vec: &Vec) -> Result; - fn allow_from_to_yaml_string_incoming(key: &String, filekey: &String, vec: &Vec) -> Result; - fn allow_for_to_yaml_string(vec: &Vec) -> Result; - - // Merge a string representing YAML settings into a existing setttings struct - fn merge(lhs: &mut Recursorsettings, rhs: &str) -> Result<()>; - - // Validate the sections inside the main settings struct, sections themselves will validate their fields - fn validate(self: &Recursorsettings) -> Result<()>; - // The validate function below are "hand-crafted" as their structs are not generated - fn validate(self: &AuthZone, field: &str) -> Result<()>; - fn validate(self: &ForwardZone, field: &str) -> Result<()>; - fn validate(self: &TrustAnchor, field: &str) -> Result<()>; - fn validate(self: &NegativeTrustAnchor, field: &str) -> Result<()>; - fn validate(self: &ApiZones, field: &str) -> Result<()>; - - // Helper functions to call the proper validate function on vectors of various kinds - fn validate_auth_zones(field: &str, vec: &Vec) -> Result<()>; - fn validate_forward_zones(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_for(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_from(field: &str, vec: &Vec) -> Result<()>; - - // The functions to maintain REST API managed zones - fn api_read_zones(path: &str) -> Result>; - fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>; - fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>; - fn api_add_forward_zones(file: &str, forwardzones: &mut Vec) -> Result<()>; - fn validate_trustanchors(field: &str, vec: &Vec) -> Result<()>; - fn validate_negativetrustanchors(field: &str, vec: &Vec) -> Result<()>; - fn api_delete_zone(file: &str, zone: &str) -> Result<()>; - fn api_delete_zones(file: &str) -> Result<()>; - } - - unsafe extern "C++" { - include!("bridge.hh"); - fn qTypeStringToCode(name: &str) -> u16; - fn isValidHostname(name: &str) -> bool; - } - // END INCLUDE rust-bridge-in.rs - - // SECTION Dnssec - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Dnssec { - #[serde(default = "crate::U64::<100000>::value", skip_serializing_if = "crate::U64::<100000>::is_equal")] - aggressive_nsec_cache_size: u64, - - #[serde(default = "crate::U64::<2000>::value", skip_serializing_if = "crate::U64::<2000>::is_equal")] - aggressive_cache_min_nsec3_hit_ratio: u64, - - #[serde(default = "crate::default_value_dnssec_validation", skip_serializing_if = "crate::default_value_equal_dnssec_validation")] - validation: String, - - #[serde(default = "crate::default_value_dnssec_disabled_algorithms", skip_serializing_if = "crate::default_value_equal_dnssec_disabled_algorithms")] - disabled_algorithms: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - log_bogus: bool, - - #[serde(default = "crate::U64::<50>::value", skip_serializing_if = "crate::U64::<50>::is_equal")] - nsec3_max_iterations: u64, - - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - max_rrsigs_per_record: u64, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - max_nsec3s_per_record: u64, - - #[serde(default = "crate::U64::<30>::value", skip_serializing_if = "crate::U64::<30>::is_equal")] - max_signature_validations_per_query: u64, - - #[serde(default = "crate::U64::<600>::value", skip_serializing_if = "crate::U64::<600>::is_equal")] - max_nsec3_hash_computations_per_query: u64, - - #[serde(default = "crate::U64::<150>::value", skip_serializing_if = "crate::U64::<150>::is_equal")] - aggressive_cache_max_nsec3_hash_cost: u64, - - #[serde(default = "crate::U64::<8>::value", skip_serializing_if = "crate::U64::<8>::is_equal")] - max_ds_per_zone: u64, - - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - max_dnskeys: u64, - - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - signature_inception_skew: u64, - - #[serde(default = "crate::default_value_dnssec_x_dnssec_names", skip_serializing_if = "crate::default_value_equal_dnssec_x_dnssec_names")] - x_dnssec_names: Vec, - - #[serde(default = "crate::default_value_dnssec_trustanchors", skip_serializing_if = "crate::default_value_equal_dnssec_trustanchors")] - trustanchors: Vec, - - #[serde(default = "crate::default_value_dnssec_negative_trustanchors", skip_serializing_if = "crate::default_value_equal_dnssec_negative_trustanchors")] - negative_trustanchors: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - trustanchorfile: String, - - #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] - trustanchorfile_interval: u64, - - } - // END SECTION Dnssec - - // SECTION Incoming - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Incoming { - #[serde(default = "crate::default_value_incoming_allow_from", skip_serializing_if = "crate::default_value_equal_incoming_allow_from")] - allow_from: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - allow_from_file: String, - - #[serde(default = "crate::default_value_incoming_allow_notify_for", skip_serializing_if = "crate::default_value_equal_incoming_allow_notify_for")] - allow_notify_for: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - allow_notify_for_file: String, - - #[serde(default = "crate::default_value_incoming_allow_notify_from", skip_serializing_if = "crate::default_value_equal_incoming_allow_notify_from")] - allow_notify_from: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - allow_notify_from_file: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - allow_no_rd: bool, - - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - tcp_timeout: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - distribution_load_factor: f64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - distribution_pipe_buffer_size: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - distributor_threads: u64, - - #[serde(default = "crate::default_value_incoming_edns_padding_from", skip_serializing_if = "crate::default_value_equal_incoming_edns_padding_from")] - edns_padding_from: Vec, - - #[serde(default = "crate::default_value_incoming_edns_padding_mode", skip_serializing_if = "crate::default_value_equal_incoming_edns_padding_mode")] - edns_padding_mode: String, - - #[serde(default = "crate::U64::<7830>::value", skip_serializing_if = "crate::U64::<7830>::is_equal")] - edns_padding_tag: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - gettag_needs_edns_options: bool, - - #[serde(default = "crate::default_value_incoming_listen", skip_serializing_if = "crate::default_value_equal_incoming_listen")] - listen: Vec, - - #[serde(default = "crate::U64::<53>::value", skip_serializing_if = "crate::U64::<53>::is_equal")] - port: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - non_local_bind: bool, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - max_concurrent_requests_per_tcp_connection: u64, - - #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] - max_tcp_clients: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - max_tcp_per_client: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - max_tcp_queries_per_connection: u64, - - #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] - max_udp_queries_per_round: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - pdns_distributes_queries: bool, - - #[serde(default = "crate::default_value_incoming_proxy_protocol_from", skip_serializing_if = "crate::default_value_equal_incoming_proxy_protocol_from")] - proxy_protocol_from: Vec, - - #[serde(default = "crate::default_value_incoming_proxy_protocol_exceptions", skip_serializing_if = "crate::default_value_equal_incoming_proxy_protocol_exceptions")] - proxy_protocol_exceptions: Vec, - - #[serde(default = "crate::U64::<512>::value", skip_serializing_if = "crate::U64::<512>::is_equal")] - proxy_protocol_maximum_size: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - reuseport: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - tcp_fast_open: u64, - - #[serde(default = "crate::U64::<1232>::value", skip_serializing_if = "crate::U64::<1232>::is_equal")] - udp_truncation_threshold: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - use_incoming_edns_subnet: bool, - - #[serde(default = "crate::default_value_incoming_proxymappings", skip_serializing_if = "crate::default_value_equal_incoming_proxymappings")] - proxymappings: Vec, - - } - // END SECTION Incoming - - // SECTION Recursor - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Recursor { - #[serde(default, skip_serializing_if = "crate::is_default")] - any_to_tcp: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - allow_trust_anchor_query: bool, - - #[serde(default = "crate::default_value_recursor_auth_zones", skip_serializing_if = "crate::default_value_equal_recursor_auth_zones")] - auth_zones: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - chroot: String, - - #[serde(default = "crate::default_value_recursor_config_dir", skip_serializing_if = "crate::default_value_equal_recursor_config_dir")] - config_dir: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - config_name: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - cpu_map: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - daemon: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - devonly_regression_test_mode: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - dns64_prefix: String, - - #[serde(default = "crate::default_value_recursor_etc_hosts_file", skip_serializing_if = "crate::default_value_equal_recursor_etc_hosts_file")] - etc_hosts_file: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - event_trace_enabled: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - export_etc_hosts: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - export_etc_hosts_search_suffix: String, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - extended_resolution_errors: bool, - - #[serde(default = "crate::default_value_recursor_forward_zones", skip_serializing_if = "crate::default_value_equal_recursor_forward_zones")] - forward_zones: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - forward_zones_file: String, - - #[serde(default = "crate::default_value_recursor_forward_zones_recurse", skip_serializing_if = "crate::default_value_equal_recursor_forward_zones_recurse")] - forward_zones_recurse: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - hint_file: String, - - #[serde(default = "crate::default_value_recursor_ignore_unknown_settings", skip_serializing_if = "crate::default_value_equal_recursor_ignore_unknown_settings")] - ignore_unknown_settings: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - include_dir: String, - - #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] - latency_statistic_size: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lua_config_file: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lua_global_include_dir: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lua_dns_script: String, - - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - lua_maintenance_interval: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - max_chain_length: u64, - - #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] - max_include_depth: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - max_generate_steps: u64, - - #[serde(default = "crate::U64::<2048>::value", skip_serializing_if = "crate::U64::<2048>::is_equal")] - max_mthreads: u64, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - max_cnames_followed: u64, - - #[serde(default = "crate::U64::<16>::value", skip_serializing_if = "crate::U64::<16>::is_equal")] - max_recursion_depth: u64, - - #[serde(default = "crate::U64::<7000>::value", skip_serializing_if = "crate::U64::<7000>::is_equal")] - max_total_msec: u64, - - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - minimum_ttl_override: u64, - - #[serde(default = "crate::default_value_recursor_nothing_below_nxdomain", skip_serializing_if = "crate::default_value_equal_recursor_nothing_below_nxdomain")] - nothing_below_nxdomain: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - public_suffix_list_file: String, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - qname_minimization: bool, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - qname_max_minimize_count: u64, - - #[serde(default = "crate::U64::<4>::value", skip_serializing_if = "crate::U64::<4>::is_equal")] - qname_minimize_one_label: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - root_nx_trust: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - save_parent_ns_set: bool, - - #[serde(default = "crate::default_value_recursor_security_poll_suffix", skip_serializing_if = "crate::default_value_equal_recursor_security_poll_suffix")] - security_poll_suffix: String, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - serve_rfc1918: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - serve_rfc6303: bool, - - #[serde(default = "crate::default_value_recursor_server_id", skip_serializing_if = "crate::default_value_equal_recursor_server_id")] - server_id: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - setgid: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - setuid: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - socket_dir: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - socket_group: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - socket_mode: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - socket_owner: String, - - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - spoof_nearmiss_max: u64, - - #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] - stack_cache_size: u64, - - #[serde(default = "crate::U64::<200000>::value", skip_serializing_if = "crate::U64::<200000>::is_equal")] - stack_size: u64, - - #[serde(default = "crate::default_value_recursor_stats_api_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_api_disabled_list")] - stats_api_disabled_list: Vec, - - #[serde(default = "crate::default_value_recursor_stats_carbon_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_carbon_disabled_list")] - stats_carbon_disabled_list: Vec, - - #[serde(default = "crate::default_value_recursor_stats_rec_control_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_rec_control_disabled_list")] - stats_rec_control_disabled_list: Vec, - - #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] - stats_ringbuffer_entries: u64, - - #[serde(default = "crate::default_value_recursor_stats_snmp_disabled_list", skip_serializing_if = "crate::default_value_equal_recursor_stats_snmp_disabled_list")] - stats_snmp_disabled_list: Vec, - - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - threads: u64, - - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - tcp_threads: u64, - - #[serde(default = "crate::default_value_recursor_version_string", skip_serializing_if = "crate::default_value_equal_recursor_version_string")] - version_string: String, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - write_pid: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - system_resolver_ttl: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - system_resolver_interval: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - system_resolver_self_resolve_check: bool, - - #[serde(default = "crate::default_value_recursor_sortlists", skip_serializing_if = "crate::default_value_equal_recursor_sortlists")] - sortlists: Vec, - - #[serde(default = "crate::default_value_recursor_rpzs", skip_serializing_if = "crate::default_value_equal_recursor_rpzs")] - rpzs: Vec, - - #[serde(default = "crate::default_value_recursor_allowed_additional_qtypes", skip_serializing_if = "crate::default_value_equal_recursor_allowed_additional_qtypes")] - allowed_additional_qtypes: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lua_start_stop_script: String, - - #[serde(default = "crate::default_value_recursor_forwarding_catalog_zones", skip_serializing_if = "crate::default_value_equal_recursor_forwarding_catalog_zones")] - forwarding_catalog_zones: Vec, - - } - // END SECTION Recursor - - // SECTION Webservice - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Webservice { - #[serde(default, skip_serializing_if = "crate::is_default")] - api_dir: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - api_key: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - webserver: bool, - - #[serde(default = "crate::default_value_webservice_address", skip_serializing_if = "crate::default_value_equal_webservice_address")] - address: String, - - #[serde(default = "crate::default_value_webservice_allow_from", skip_serializing_if = "crate::default_value_equal_webservice_allow_from")] - allow_from: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - hash_plaintext_credentials: bool, - - #[serde(default = "crate::default_value_webservice_loglevel", skip_serializing_if = "crate::default_value_equal_webservice_loglevel")] - loglevel: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - password: String, - - #[serde(default = "crate::U64::<8082>::value", skip_serializing_if = "crate::U64::<8082>::is_equal")] - port: u64, - - } - // END SECTION Webservice - - // SECTION Carbon - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Carbon { - #[serde(default = "crate::U64::<30>::value", skip_serializing_if = "crate::U64::<30>::is_equal")] - interval: u64, - - #[serde(default = "crate::default_value_carbon_ns", skip_serializing_if = "crate::default_value_equal_carbon_ns")] - ns: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - ourname: String, - - #[serde(default = "crate::default_value_carbon_instance", skip_serializing_if = "crate::default_value_equal_carbon_instance")] - instance: String, - - #[serde(default = "crate::default_value_carbon_server", skip_serializing_if = "crate::default_value_equal_carbon_server")] - server: Vec, - - } - // END SECTION Carbon - - // SECTION Outgoing - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Outgoing { - #[serde(default = "crate::default_value_outgoing_dont_throttle_names", skip_serializing_if = "crate::default_value_equal_outgoing_dont_throttle_names")] - dont_throttle_names: Vec, - - #[serde(default = "crate::default_value_outgoing_dont_throttle_netmasks", skip_serializing_if = "crate::default_value_equal_outgoing_dont_throttle_netmasks")] - dont_throttle_netmasks: Vec, - - #[serde(default = "crate::default_value_outgoing_dot_to_auth_names", skip_serializing_if = "crate::default_value_equal_outgoing_dot_to_auth_names")] - dot_to_auth_names: Vec, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - dot_to_port_853: bool, - - #[serde(default = "crate::default_value_outgoing_dont_query", skip_serializing_if = "crate::default_value_equal_outgoing_dont_query")] - dont_query: Vec, - - #[serde(default = "crate::U64::<1232>::value", skip_serializing_if = "crate::U64::<1232>::is_equal")] - edns_bufsize: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - edns_padding: bool, - - #[serde(default = "crate::default_value_outgoing_edns_subnet_allow_list", skip_serializing_if = "crate::default_value_equal_outgoing_edns_subnet_allow_list")] - edns_subnet_allow_list: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - edns_subnet_harden: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lowercase: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - max_busy_dot_probes: u64, - - #[serde(default = "crate::U64::<50>::value", skip_serializing_if = "crate::U64::<50>::is_equal")] - max_qperq: u64, - - #[serde(default = "crate::U64::<100000>::value", skip_serializing_if = "crate::U64::<100000>::is_equal")] - max_bytesperq: u64, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - max_ns_address_qperq: u64, - - #[serde(default = "crate::U64::<13>::value", skip_serializing_if = "crate::U64::<13>::is_equal")] - max_ns_per_resolve: u64, - - #[serde(default = "crate::U64::<1500>::value", skip_serializing_if = "crate::U64::<1500>::is_equal")] - network_timeout: u64, - - #[serde(default = "crate::U64::<5>::value", skip_serializing_if = "crate::U64::<5>::is_equal")] - non_resolving_ns_max_fails: u64, - - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - non_resolving_ns_throttle_time: u64, - - #[serde(default = "crate::default_value_outgoing_source_address", skip_serializing_if = "crate::default_value_equal_outgoing_source_address")] - source_address: Vec, - - #[serde(default = "crate::U64::<64>::value", skip_serializing_if = "crate::U64::<64>::is_equal")] - server_down_max_fails: u64, - - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - server_down_throttle_time: u64, - - #[serde(default = "crate::U64::<25>::value", skip_serializing_if = "crate::U64::<25>::is_equal")] - bypass_server_throttling_probability: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - single_socket: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - tcp_fast_open_connect: bool, - - #[serde(default = "crate::U64::<10000>::value", skip_serializing_if = "crate::U64::<10000>::is_equal")] - tcp_max_idle_ms: u64, - - #[serde(default = "crate::U64::<10>::value", skip_serializing_if = "crate::U64::<10>::is_equal")] - tcp_max_idle_per_auth: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - tcp_max_queries: u64, - - #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] - tcp_max_idle_per_thread: u64, - - #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] - udp_source_port_min: u64, - - #[serde(default = "crate::U64::<65535>::value", skip_serializing_if = "crate::U64::<65535>::is_equal")] - udp_source_port_max: u64, - - #[serde(default = "crate::default_value_outgoing_udp_source_port_avoid", skip_serializing_if = "crate::default_value_equal_outgoing_udp_source_port_avoid")] - udp_source_port_avoid: Vec, - - } - // END SECTION Outgoing - - // SECTION Packetcache - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Packetcache { - #[serde(default, skip_serializing_if = "crate::is_default")] - disable: bool, - - #[serde(default = "crate::U64::<500000>::value", skip_serializing_if = "crate::U64::<500000>::is_equal")] - max_entries: u64, - - #[serde(default = "crate::U64::<8192>::value", skip_serializing_if = "crate::U64::<8192>::is_equal")] - max_entry_size: u64, - - #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] - ttl: u64, - - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - negative_ttl: u64, - - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - servfail_ttl: u64, - - #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] - shards: u64, - - } - // END SECTION Packetcache - - // SECTION Logging - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Logging { - #[serde(default, skip_serializing_if = "crate::is_default")] - disable_syslog: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - timestamp: bool, - - #[serde(default = "crate::U64::<6>::value", skip_serializing_if = "crate::U64::<6>::is_equal")] - loglevel: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - common_errors: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - rpz_changes: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - facility: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - protobuf_use_kernel_timestamp: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - quiet: bool, - - #[serde(default = "crate::U64::<1800>::value", skip_serializing_if = "crate::U64::<1800>::is_equal")] - statistics_interval: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - structured_logging: bool, - - #[serde(default = "crate::default_value_logging_structured_logging_backend", skip_serializing_if = "crate::default_value_equal_logging_structured_logging_backend")] - structured_logging_backend: String, - - #[serde(default = "crate::default_value_logging_trace", skip_serializing_if = "crate::default_value_equal_logging_trace")] - trace: String, - - #[serde(default = "crate::default_value_logging_protobuf_servers", skip_serializing_if = "crate::default_value_equal_logging_protobuf_servers")] - protobuf_servers: Vec, - - #[serde(default = "crate::default_value_logging_outgoing_protobuf_servers", skip_serializing_if = "crate::default_value_equal_logging_outgoing_protobuf_servers")] - outgoing_protobuf_servers: Vec, - - #[serde(default = "crate::U64::<32>::value", skip_serializing_if = "crate::U64::<32>::is_equal")] - protobuf_mask_v4: u64, - - #[serde(default = "crate::U64::<128>::value", skip_serializing_if = "crate::U64::<128>::is_equal")] - protobuf_mask_v6: u64, - - #[serde(default = "crate::default_value_logging_dnstap_framestream_servers", skip_serializing_if = "crate::default_value_equal_logging_dnstap_framestream_servers")] - dnstap_framestream_servers: Vec, - - #[serde(default = "crate::default_value_logging_dnstap_nod_framestream_servers", skip_serializing_if = "crate::default_value_equal_logging_dnstap_nod_framestream_servers")] - dnstap_nod_framestream_servers: Vec, - - } - // END SECTION Logging - - // SECTION Ecs - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Ecs { - #[serde(default = "crate::default_value_ecs_add_for", skip_serializing_if = "crate::default_value_equal_ecs_add_for")] - add_for: Vec, - - #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] - ipv4_bits: u64, - - #[serde(default = "crate::U64::<24>::value", skip_serializing_if = "crate::U64::<24>::is_equal")] - ipv4_cache_bits: u64, - - #[serde(default = "crate::U64::<56>::value", skip_serializing_if = "crate::U64::<56>::is_equal")] - ipv6_bits: u64, - - #[serde(default = "crate::U64::<56>::value", skip_serializing_if = "crate::U64::<56>::is_equal")] - ipv6_cache_bits: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - ipv4_never_cache: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - ipv6_never_cache: bool, - - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - minimum_ttl_override: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - cache_limit_ttl: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - scope_zero_address: String, - - } - // END SECTION Ecs - - // SECTION Recordcache - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Recordcache { - #[serde(default = "crate::U64::<3600>::value", skip_serializing_if = "crate::U64::<3600>::is_equal")] - max_cache_bogus_ttl: u64, - - #[serde(default = "crate::U64::<1000000>::value", skip_serializing_if = "crate::U64::<1000000>::is_equal")] - max_entries: u64, - - #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] - max_ttl: u64, - - #[serde(default = "crate::U64::<8192>::value", skip_serializing_if = "crate::U64::<8192>::is_equal")] - max_entry_size: u64, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - limit_qtype_any: bool, - - #[serde(default = "crate::U64::<256>::value", skip_serializing_if = "crate::U64::<256>::is_equal")] - max_rrset_size: u64, - - #[serde(default = "crate::U64::<3600>::value", skip_serializing_if = "crate::U64::<3600>::is_equal")] - max_negative_ttl: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - locked_ttl_perc: u64, - - #[serde(default = "crate::U64::<1024>::value", skip_serializing_if = "crate::U64::<1024>::is_equal")] - shards: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - refresh_on_ttl_perc: u64, - - #[serde(default, skip_serializing_if = "crate::is_default")] - serve_stale_extensions: u64, - - #[serde(default = "crate::default_value_recordcache_zonetocaches", skip_serializing_if = "crate::default_value_equal_recordcache_zonetocaches")] - zonetocaches: Vec, - - } - // END SECTION Recordcache - - // SECTION Nod - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Nod { - #[serde(default, skip_serializing_if = "crate::is_default")] - tracking: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - log: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - lookup: String, - - #[serde(default = "crate::U64::<67108864>::value", skip_serializing_if = "crate::U64::<67108864>::is_equal")] - db_size: u64, - - #[serde(default = "crate::default_value_nod_history_dir", skip_serializing_if = "crate::default_value_equal_nod_history_dir")] - history_dir: String, - - #[serde(default = "crate::U64::<600>::value", skip_serializing_if = "crate::U64::<600>::is_equal")] - db_snapshot_interval: u64, - - #[serde(default = "crate::default_value_nod_ignore_list", skip_serializing_if = "crate::default_value_equal_nod_ignore_list")] - ignore_list: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - ignore_list_file: String, - - #[serde(default = "crate::default_value_nod_pb_tag", skip_serializing_if = "crate::default_value_equal_nod_pb_tag")] - pb_tag: String, - - #[serde(default, skip_serializing_if = "crate::is_default")] - unique_response_tracking: bool, - - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - unique_response_log: bool, - - #[serde(default = "crate::U64::<67108864>::value", skip_serializing_if = "crate::U64::<67108864>::is_equal")] - unique_response_db_size: u64, - - #[serde(default = "crate::default_value_nod_unique_response_history_dir", skip_serializing_if = "crate::default_value_equal_nod_unique_response_history_dir")] - unique_response_history_dir: String, - - #[serde(default = "crate::default_value_nod_unique_response_pb_tag", skip_serializing_if = "crate::default_value_equal_nod_unique_response_pb_tag")] - unique_response_pb_tag: String, - - #[serde(default = "crate::default_value_nod_unique_response_ignore_list", skip_serializing_if = "crate::default_value_equal_nod_unique_response_ignore_list")] - unique_response_ignore_list: Vec, - - #[serde(default, skip_serializing_if = "crate::is_default")] - unique_response_ignore_list_file: String, - - } - // END SECTION Nod - - // SECTION Snmp - #[derive(Deserialize, Serialize, Debug, PartialEq)] - #[serde(deny_unknown_fields)] - pub struct Snmp { - #[serde(default, skip_serializing_if = "crate::is_default")] - agent: bool, - - #[serde(default, skip_serializing_if = "crate::is_default")] - daemon_socket: String, - - } - // END SECTION Snmp - - #[derive(Serialize, Deserialize, Debug)] - #[serde(deny_unknown_fields)] - pub struct Recursorsettings { - #[serde(default, skip_serializing_if = "crate::is_default")] - dnssec: Dnssec, - #[serde(default, skip_serializing_if = "crate::is_default")] - incoming: Incoming, - #[serde(default, skip_serializing_if = "crate::is_default")] - recursor: Recursor, - #[serde(default, skip_serializing_if = "crate::is_default")] - webservice: Webservice, - #[serde(default, skip_serializing_if = "crate::is_default")] - carbon: Carbon, - #[serde(default, skip_serializing_if = "crate::is_default")] - outgoing: Outgoing, - #[serde(default, skip_serializing_if = "crate::is_default")] - packetcache: Packetcache, - #[serde(default, skip_serializing_if = "crate::is_default")] - logging: Logging, - #[serde(default, skip_serializing_if = "crate::is_default")] - ecs: Ecs, - #[serde(default, skip_serializing_if = "crate::is_default")] - recordcache: Recordcache, - #[serde(default, skip_serializing_if = "crate::is_default")] - nod: Nod, - #[serde(default, skip_serializing_if = "crate::is_default")] - snmp: Snmp, -} // End of generated structs -} -impl Default for recsettings::Dnssec { - fn default() -> Self { - let deserialized: recsettings::Dnssec = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Incoming { - fn default() -> Self { - let deserialized: recsettings::Incoming = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Recursor { - fn default() -> Self { - let deserialized: recsettings::Recursor = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Webservice { - fn default() -> Self { - let deserialized: recsettings::Webservice = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Carbon { - fn default() -> Self { - let deserialized: recsettings::Carbon = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Outgoing { - fn default() -> Self { - let deserialized: recsettings::Outgoing = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Packetcache { - fn default() -> Self { - let deserialized: recsettings::Packetcache = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Logging { - fn default() -> Self { - let deserialized: recsettings::Logging = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Ecs { - fn default() -> Self { - let deserialized: recsettings::Ecs = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Recordcache { - fn default() -> Self { - let deserialized: recsettings::Recordcache = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Nod { - fn default() -> Self { - let deserialized: recsettings::Nod = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Snmp { - fn default() -> Self { - let deserialized: recsettings::Snmp = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Default for recsettings::Recursorsettings { - fn default() -> Self { - let deserialized: recsettings::Recursorsettings = serde_yaml::from_str("").unwrap(); - deserialized - } -} - -impl Validate for recsettings::Dnssec { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "dnssec.trustanchors".to_string(); - validate_vec(&fieldname, &self.trustanchors, |field, element| element.validate(field))?; - let fieldname = "dnssec.negative_trustanchors".to_string(); - validate_vec(&fieldname, &self.negative_trustanchors, |field, element| element.validate(field))?; - validate_dnssec(self) - } -} - -impl Validate for recsettings::Incoming { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "incoming.allow_from".to_string(); - validate_vec(&fieldname, &self.allow_from, validate_subnet)?; - let fieldname = "incoming.allow_notify_from".to_string(); - validate_vec(&fieldname, &self.allow_notify_from, validate_subnet)?; - let fieldname = "incoming.edns_padding_from".to_string(); - validate_vec(&fieldname, &self.edns_padding_from, validate_subnet)?; - let fieldname = "incoming.listen".to_string(); - validate_vec(&fieldname, &self.listen, validate_socket_address)?; - let fieldname = "incoming.proxy_protocol_from".to_string(); - validate_vec(&fieldname, &self.proxy_protocol_from, validate_subnet)?; - let fieldname = "incoming.proxy_protocol_exceptions".to_string(); - validate_vec(&fieldname, &self.proxy_protocol_exceptions, validate_socket_address)?; - let fieldname = "incoming.proxymappings".to_string(); - validate_vec(&fieldname, &self.proxymappings, |field, element| element.validate(field))?; - validate_incoming(self) - } -} - -impl Validate for recsettings::Recursor { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "recursor.auth_zones".to_string(); - validate_vec(&fieldname, &self.auth_zones, |field, element| element.validate(field))?; - let fieldname = "recursor.forward_zones".to_string(); - validate_vec(&fieldname, &self.forward_zones, |field, element| element.validate(field))?; - let fieldname = "recursor.forward_zones_recurse".to_string(); - validate_vec(&fieldname, &self.forward_zones_recurse, |field, element| element.validate(field))?; - let fieldname = "recursor.sortlists".to_string(); - validate_vec(&fieldname, &self.sortlists, |field, element| element.validate(field))?; - let fieldname = "recursor.rpzs".to_string(); - validate_vec(&fieldname, &self.rpzs, |field, element| element.validate(field))?; - let fieldname = "recursor.allowed_additional_qtypes".to_string(); - validate_vec(&fieldname, &self.allowed_additional_qtypes, |field, element| element.validate(field))?; - let fieldname = "recursor.forwarding_catalog_zones".to_string(); - validate_vec(&fieldname, &self.forwarding_catalog_zones, |field, element| element.validate(field))?; - validate_recursor(self) - } -} - -impl Validate for recsettings::Webservice { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "webservice.allow_from".to_string(); - validate_vec(&fieldname, &self.allow_from, validate_subnet)?; - validate_webservice(self) - } -} - -impl Validate for recsettings::Carbon { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "carbon.server".to_string(); - validate_vec(&fieldname, &self.server, validate_socket_address)?; - validate_carbon(self) - } -} - -impl Validate for recsettings::Outgoing { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "outgoing.dont_throttle_netmasks".to_string(); - validate_vec(&fieldname, &self.dont_throttle_netmasks, validate_subnet)?; - let fieldname = "outgoing.dont_query".to_string(); - validate_vec(&fieldname, &self.dont_query, validate_subnet)?; - let fieldname = "outgoing.source_address".to_string(); - validate_vec(&fieldname, &self.source_address, validate_subnet)?; - validate_outgoing(self) - } -} - -impl Validate for recsettings::Packetcache { - fn validate(&self) -> Result<(), ValidationError> { - validate_packetcache(self) - } -} - -impl Validate for recsettings::Logging { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "logging.protobuf_servers".to_string(); - validate_vec(&fieldname, &self.protobuf_servers, |field, element| element.validate(field))?; - let fieldname = "logging.outgoing_protobuf_servers".to_string(); - validate_vec(&fieldname, &self.outgoing_protobuf_servers, |field, element| element.validate(field))?; - let fieldname = "logging.dnstap_framestream_servers".to_string(); - validate_vec(&fieldname, &self.dnstap_framestream_servers, |field, element| element.validate(field))?; - let fieldname = "logging.dnstap_nod_framestream_servers".to_string(); - validate_vec(&fieldname, &self.dnstap_nod_framestream_servers, |field, element| element.validate(field))?; - validate_logging(self) - } -} - -impl Validate for recsettings::Ecs { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "ecs.add_for".to_string(); - validate_vec(&fieldname, &self.add_for, validate_subnet)?; - validate_ecs(self) - } -} - -impl Validate for recsettings::Recordcache { - fn validate(&self) -> Result<(), ValidationError> { - let fieldname = "recordcache.zonetocaches".to_string(); - validate_vec(&fieldname, &self.zonetocaches, |field, element| element.validate(field))?; - validate_recordcache(self) - } -} - -impl Validate for recsettings::Nod { - fn validate(&self) -> Result<(), ValidationError> { - validate_nod(self) - } -} - -impl Validate for recsettings::Snmp { - fn validate(&self) -> Result<(), ValidationError> { - validate_snmp(self) - } -} - -impl crate::recsettings::Recursorsettings { - fn validate(&self) -> Result<(), ValidationError> { - self.dnssec.validate()?; - self.incoming.validate()?; - self.recursor.validate()?; - self.webservice.validate()?; - self.carbon.validate()?; - self.outgoing.validate()?; - self.packetcache.validate()?; - self.logging.validate()?; - self.ecs.validate()?; - self.recordcache.validate()?; - self.nod.validate()?; - self.snmp.validate()?; - Ok(()) - } -} - -impl Merge for recsettings::Dnssec { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("aggressive_nsec_cache_size") { - rhs.aggressive_nsec_cache_size.clone_into(&mut self.aggressive_nsec_cache_size); - } - if m.contains_key("aggressive_cache_min_nsec3_hit_ratio") { - rhs.aggressive_cache_min_nsec3_hit_ratio.clone_into(&mut self.aggressive_cache_min_nsec3_hit_ratio); - } - if m.contains_key("validation") { - rhs.validation.clone_into(&mut self.validation); - } - if m.contains_key("disabled_algorithms") { - if is_overriding(m, "disabled_algorithms") || self.disabled_algorithms == DEFAULT_CONFIG.dnssec.disabled_algorithms { - self.disabled_algorithms.clear(); - } - merge_vec(&mut self.disabled_algorithms, &mut rhs.disabled_algorithms); - } - if m.contains_key("log_bogus") { - rhs.log_bogus.clone_into(&mut self.log_bogus); - } - if m.contains_key("nsec3_max_iterations") { - rhs.nsec3_max_iterations.clone_into(&mut self.nsec3_max_iterations); - } - if m.contains_key("max_rrsigs_per_record") { - rhs.max_rrsigs_per_record.clone_into(&mut self.max_rrsigs_per_record); - } - if m.contains_key("max_nsec3s_per_record") { - rhs.max_nsec3s_per_record.clone_into(&mut self.max_nsec3s_per_record); - } - if m.contains_key("max_signature_validations_per_query") { - rhs.max_signature_validations_per_query.clone_into(&mut self.max_signature_validations_per_query); - } - if m.contains_key("max_nsec3_hash_computations_per_query") { - rhs.max_nsec3_hash_computations_per_query.clone_into(&mut self.max_nsec3_hash_computations_per_query); - } - if m.contains_key("aggressive_cache_max_nsec3_hash_cost") { - rhs.aggressive_cache_max_nsec3_hash_cost.clone_into(&mut self.aggressive_cache_max_nsec3_hash_cost); - } - if m.contains_key("max_ds_per_zone") { - rhs.max_ds_per_zone.clone_into(&mut self.max_ds_per_zone); - } - if m.contains_key("max_dnskeys") { - rhs.max_dnskeys.clone_into(&mut self.max_dnskeys); - } - if m.contains_key("signature_inception_skew") { - rhs.signature_inception_skew.clone_into(&mut self.signature_inception_skew); - } - if m.contains_key("x_dnssec_names") { - if is_overriding(m, "x_dnssec_names") || self.x_dnssec_names == DEFAULT_CONFIG.dnssec.x_dnssec_names { - self.x_dnssec_names.clear(); - } - merge_vec(&mut self.x_dnssec_names, &mut rhs.x_dnssec_names); - } - if m.contains_key("trustanchors") { - if is_overriding(m, "trustanchors") || self.trustanchors == DEFAULT_CONFIG.dnssec.trustanchors { - self.trustanchors.clear(); - } - merge_vec(&mut self.trustanchors, &mut rhs.trustanchors); - } - if m.contains_key("negative_trustanchors") { - if is_overriding(m, "negative_trustanchors") || self.negative_trustanchors == DEFAULT_CONFIG.dnssec.negative_trustanchors { - self.negative_trustanchors.clear(); - } - merge_vec(&mut self.negative_trustanchors, &mut rhs.negative_trustanchors); - } - if m.contains_key("trustanchorfile") { - rhs.trustanchorfile.clone_into(&mut self.trustanchorfile); - } - if m.contains_key("trustanchorfile_interval") { - rhs.trustanchorfile_interval.clone_into(&mut self.trustanchorfile_interval); - } - } - } -} - -impl Merge for recsettings::Incoming { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("allow_from") { - if is_overriding(m, "allow_from") || self.allow_from == DEFAULT_CONFIG.incoming.allow_from { - self.allow_from.clear(); - } - merge_vec(&mut self.allow_from, &mut rhs.allow_from); - } - if m.contains_key("allow_from_file") { - rhs.allow_from_file.clone_into(&mut self.allow_from_file); - } - if m.contains_key("allow_notify_for") { - if is_overriding(m, "allow_notify_for") || self.allow_notify_for == DEFAULT_CONFIG.incoming.allow_notify_for { - self.allow_notify_for.clear(); - } - merge_vec(&mut self.allow_notify_for, &mut rhs.allow_notify_for); - } - if m.contains_key("allow_notify_for_file") { - rhs.allow_notify_for_file.clone_into(&mut self.allow_notify_for_file); - } - if m.contains_key("allow_notify_from") { - if is_overriding(m, "allow_notify_from") || self.allow_notify_from == DEFAULT_CONFIG.incoming.allow_notify_from { - self.allow_notify_from.clear(); - } - merge_vec(&mut self.allow_notify_from, &mut rhs.allow_notify_from); - } - if m.contains_key("allow_notify_from_file") { - rhs.allow_notify_from_file.clone_into(&mut self.allow_notify_from_file); - } - if m.contains_key("allow_no_rd") { - rhs.allow_no_rd.clone_into(&mut self.allow_no_rd); - } - if m.contains_key("tcp_timeout") { - rhs.tcp_timeout.clone_into(&mut self.tcp_timeout); - } - if m.contains_key("distribution_load_factor") { - rhs.distribution_load_factor.clone_into(&mut self.distribution_load_factor); - } - if m.contains_key("distribution_pipe_buffer_size") { - rhs.distribution_pipe_buffer_size.clone_into(&mut self.distribution_pipe_buffer_size); - } - if m.contains_key("distributor_threads") { - rhs.distributor_threads.clone_into(&mut self.distributor_threads); - } - if m.contains_key("edns_padding_from") { - if is_overriding(m, "edns_padding_from") || self.edns_padding_from == DEFAULT_CONFIG.incoming.edns_padding_from { - self.edns_padding_from.clear(); - } - merge_vec(&mut self.edns_padding_from, &mut rhs.edns_padding_from); - } - if m.contains_key("edns_padding_mode") { - rhs.edns_padding_mode.clone_into(&mut self.edns_padding_mode); - } - if m.contains_key("edns_padding_tag") { - rhs.edns_padding_tag.clone_into(&mut self.edns_padding_tag); - } - if m.contains_key("gettag_needs_edns_options") { - rhs.gettag_needs_edns_options.clone_into(&mut self.gettag_needs_edns_options); - } - if m.contains_key("listen") { - if is_overriding(m, "listen") || self.listen == DEFAULT_CONFIG.incoming.listen { - self.listen.clear(); - } - merge_vec(&mut self.listen, &mut rhs.listen); - } - if m.contains_key("port") { - rhs.port.clone_into(&mut self.port); - } - if m.contains_key("non_local_bind") { - rhs.non_local_bind.clone_into(&mut self.non_local_bind); - } - if m.contains_key("max_concurrent_requests_per_tcp_connection") { - rhs.max_concurrent_requests_per_tcp_connection.clone_into(&mut self.max_concurrent_requests_per_tcp_connection); - } - if m.contains_key("max_tcp_clients") { - rhs.max_tcp_clients.clone_into(&mut self.max_tcp_clients); - } - if m.contains_key("max_tcp_per_client") { - rhs.max_tcp_per_client.clone_into(&mut self.max_tcp_per_client); - } - if m.contains_key("max_tcp_queries_per_connection") { - rhs.max_tcp_queries_per_connection.clone_into(&mut self.max_tcp_queries_per_connection); - } - if m.contains_key("max_udp_queries_per_round") { - rhs.max_udp_queries_per_round.clone_into(&mut self.max_udp_queries_per_round); - } - if m.contains_key("pdns_distributes_queries") { - rhs.pdns_distributes_queries.clone_into(&mut self.pdns_distributes_queries); - } - if m.contains_key("proxy_protocol_from") { - if is_overriding(m, "proxy_protocol_from") || self.proxy_protocol_from == DEFAULT_CONFIG.incoming.proxy_protocol_from { - self.proxy_protocol_from.clear(); - } - merge_vec(&mut self.proxy_protocol_from, &mut rhs.proxy_protocol_from); - } - if m.contains_key("proxy_protocol_exceptions") { - if is_overriding(m, "proxy_protocol_exceptions") || self.proxy_protocol_exceptions == DEFAULT_CONFIG.incoming.proxy_protocol_exceptions { - self.proxy_protocol_exceptions.clear(); - } - merge_vec(&mut self.proxy_protocol_exceptions, &mut rhs.proxy_protocol_exceptions); - } - if m.contains_key("proxy_protocol_maximum_size") { - rhs.proxy_protocol_maximum_size.clone_into(&mut self.proxy_protocol_maximum_size); - } - if m.contains_key("reuseport") { - rhs.reuseport.clone_into(&mut self.reuseport); - } - if m.contains_key("tcp_fast_open") { - rhs.tcp_fast_open.clone_into(&mut self.tcp_fast_open); - } - if m.contains_key("udp_truncation_threshold") { - rhs.udp_truncation_threshold.clone_into(&mut self.udp_truncation_threshold); - } - if m.contains_key("use_incoming_edns_subnet") { - rhs.use_incoming_edns_subnet.clone_into(&mut self.use_incoming_edns_subnet); - } - if m.contains_key("proxymappings") { - if is_overriding(m, "proxymappings") || self.proxymappings == DEFAULT_CONFIG.incoming.proxymappings { - self.proxymappings.clear(); - } - merge_vec(&mut self.proxymappings, &mut rhs.proxymappings); - } - } - } -} - -impl Merge for recsettings::Recursor { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("any_to_tcp") { - rhs.any_to_tcp.clone_into(&mut self.any_to_tcp); - } - if m.contains_key("allow_trust_anchor_query") { - rhs.allow_trust_anchor_query.clone_into(&mut self.allow_trust_anchor_query); - } - if m.contains_key("auth_zones") { - if is_overriding(m, "auth_zones") || self.auth_zones == DEFAULT_CONFIG.recursor.auth_zones { - self.auth_zones.clear(); - } - merge_vec(&mut self.auth_zones, &mut rhs.auth_zones); - } - if m.contains_key("chroot") { - rhs.chroot.clone_into(&mut self.chroot); - } - if m.contains_key("config_dir") { - rhs.config_dir.clone_into(&mut self.config_dir); - } - if m.contains_key("config_name") { - rhs.config_name.clone_into(&mut self.config_name); - } - if m.contains_key("cpu_map") { - rhs.cpu_map.clone_into(&mut self.cpu_map); - } - if m.contains_key("daemon") { - rhs.daemon.clone_into(&mut self.daemon); - } - if m.contains_key("devonly_regression_test_mode") { - rhs.devonly_regression_test_mode.clone_into(&mut self.devonly_regression_test_mode); - } - if m.contains_key("dns64_prefix") { - rhs.dns64_prefix.clone_into(&mut self.dns64_prefix); - } - if m.contains_key("etc_hosts_file") { - rhs.etc_hosts_file.clone_into(&mut self.etc_hosts_file); - } - if m.contains_key("event_trace_enabled") { - rhs.event_trace_enabled.clone_into(&mut self.event_trace_enabled); - } - if m.contains_key("export_etc_hosts") { - rhs.export_etc_hosts.clone_into(&mut self.export_etc_hosts); - } - if m.contains_key("export_etc_hosts_search_suffix") { - rhs.export_etc_hosts_search_suffix.clone_into(&mut self.export_etc_hosts_search_suffix); - } - if m.contains_key("extended_resolution_errors") { - rhs.extended_resolution_errors.clone_into(&mut self.extended_resolution_errors); - } - if m.contains_key("forward_zones") { - if is_overriding(m, "forward_zones") || self.forward_zones == DEFAULT_CONFIG.recursor.forward_zones { - self.forward_zones.clear(); - } - merge_vec(&mut self.forward_zones, &mut rhs.forward_zones); - } - if m.contains_key("forward_zones_file") { - rhs.forward_zones_file.clone_into(&mut self.forward_zones_file); - } - if m.contains_key("forward_zones_recurse") { - if is_overriding(m, "forward_zones_recurse") || self.forward_zones_recurse == DEFAULT_CONFIG.recursor.forward_zones_recurse { - self.forward_zones_recurse.clear(); - } - merge_vec(&mut self.forward_zones_recurse, &mut rhs.forward_zones_recurse); - } - if m.contains_key("hint_file") { - rhs.hint_file.clone_into(&mut self.hint_file); - } - if m.contains_key("ignore_unknown_settings") { - if is_overriding(m, "ignore_unknown_settings") || self.ignore_unknown_settings == DEFAULT_CONFIG.recursor.ignore_unknown_settings { - self.ignore_unknown_settings.clear(); - } - merge_vec(&mut self.ignore_unknown_settings, &mut rhs.ignore_unknown_settings); - } - if m.contains_key("include_dir") { - rhs.include_dir.clone_into(&mut self.include_dir); - } - if m.contains_key("latency_statistic_size") { - rhs.latency_statistic_size.clone_into(&mut self.latency_statistic_size); - } - if m.contains_key("lua_config_file") { - rhs.lua_config_file.clone_into(&mut self.lua_config_file); - } - if m.contains_key("lua_global_include_dir") { - rhs.lua_global_include_dir.clone_into(&mut self.lua_global_include_dir); - } - if m.contains_key("lua_dns_script") { - rhs.lua_dns_script.clone_into(&mut self.lua_dns_script); - } - if m.contains_key("lua_maintenance_interval") { - rhs.lua_maintenance_interval.clone_into(&mut self.lua_maintenance_interval); - } - if m.contains_key("max_chain_length") { - rhs.max_chain_length.clone_into(&mut self.max_chain_length); - } - if m.contains_key("max_include_depth") { - rhs.max_include_depth.clone_into(&mut self.max_include_depth); - } - if m.contains_key("max_generate_steps") { - rhs.max_generate_steps.clone_into(&mut self.max_generate_steps); - } - if m.contains_key("max_mthreads") { - rhs.max_mthreads.clone_into(&mut self.max_mthreads); - } - if m.contains_key("max_cnames_followed") { - rhs.max_cnames_followed.clone_into(&mut self.max_cnames_followed); - } - if m.contains_key("max_recursion_depth") { - rhs.max_recursion_depth.clone_into(&mut self.max_recursion_depth); - } - if m.contains_key("max_total_msec") { - rhs.max_total_msec.clone_into(&mut self.max_total_msec); - } - if m.contains_key("minimum_ttl_override") { - rhs.minimum_ttl_override.clone_into(&mut self.minimum_ttl_override); - } - if m.contains_key("nothing_below_nxdomain") { - rhs.nothing_below_nxdomain.clone_into(&mut self.nothing_below_nxdomain); - } - if m.contains_key("public_suffix_list_file") { - rhs.public_suffix_list_file.clone_into(&mut self.public_suffix_list_file); - } - if m.contains_key("qname_minimization") { - rhs.qname_minimization.clone_into(&mut self.qname_minimization); - } - if m.contains_key("qname_max_minimize_count") { - rhs.qname_max_minimize_count.clone_into(&mut self.qname_max_minimize_count); - } - if m.contains_key("qname_minimize_one_label") { - rhs.qname_minimize_one_label.clone_into(&mut self.qname_minimize_one_label); - } - if m.contains_key("root_nx_trust") { - rhs.root_nx_trust.clone_into(&mut self.root_nx_trust); - } - if m.contains_key("save_parent_ns_set") { - rhs.save_parent_ns_set.clone_into(&mut self.save_parent_ns_set); - } - if m.contains_key("security_poll_suffix") { - rhs.security_poll_suffix.clone_into(&mut self.security_poll_suffix); - } - if m.contains_key("serve_rfc1918") { - rhs.serve_rfc1918.clone_into(&mut self.serve_rfc1918); - } - if m.contains_key("serve_rfc6303") { - rhs.serve_rfc6303.clone_into(&mut self.serve_rfc6303); - } - if m.contains_key("server_id") { - rhs.server_id.clone_into(&mut self.server_id); - } - if m.contains_key("setgid") { - rhs.setgid.clone_into(&mut self.setgid); - } - if m.contains_key("setuid") { - rhs.setuid.clone_into(&mut self.setuid); - } - if m.contains_key("socket_dir") { - rhs.socket_dir.clone_into(&mut self.socket_dir); - } - if m.contains_key("socket_group") { - rhs.socket_group.clone_into(&mut self.socket_group); - } - if m.contains_key("socket_mode") { - rhs.socket_mode.clone_into(&mut self.socket_mode); - } - if m.contains_key("socket_owner") { - rhs.socket_owner.clone_into(&mut self.socket_owner); - } - if m.contains_key("spoof_nearmiss_max") { - rhs.spoof_nearmiss_max.clone_into(&mut self.spoof_nearmiss_max); - } - if m.contains_key("stack_cache_size") { - rhs.stack_cache_size.clone_into(&mut self.stack_cache_size); - } - if m.contains_key("stack_size") { - rhs.stack_size.clone_into(&mut self.stack_size); - } - if m.contains_key("stats_api_disabled_list") { - if is_overriding(m, "stats_api_disabled_list") || self.stats_api_disabled_list == DEFAULT_CONFIG.recursor.stats_api_disabled_list { - self.stats_api_disabled_list.clear(); - } - merge_vec(&mut self.stats_api_disabled_list, &mut rhs.stats_api_disabled_list); - } - if m.contains_key("stats_carbon_disabled_list") { - if is_overriding(m, "stats_carbon_disabled_list") || self.stats_carbon_disabled_list == DEFAULT_CONFIG.recursor.stats_carbon_disabled_list { - self.stats_carbon_disabled_list.clear(); - } - merge_vec(&mut self.stats_carbon_disabled_list, &mut rhs.stats_carbon_disabled_list); - } - if m.contains_key("stats_rec_control_disabled_list") { - if is_overriding(m, "stats_rec_control_disabled_list") || self.stats_rec_control_disabled_list == DEFAULT_CONFIG.recursor.stats_rec_control_disabled_list { - self.stats_rec_control_disabled_list.clear(); - } - merge_vec(&mut self.stats_rec_control_disabled_list, &mut rhs.stats_rec_control_disabled_list); - } - if m.contains_key("stats_ringbuffer_entries") { - rhs.stats_ringbuffer_entries.clone_into(&mut self.stats_ringbuffer_entries); - } - if m.contains_key("stats_snmp_disabled_list") { - if is_overriding(m, "stats_snmp_disabled_list") || self.stats_snmp_disabled_list == DEFAULT_CONFIG.recursor.stats_snmp_disabled_list { - self.stats_snmp_disabled_list.clear(); - } - merge_vec(&mut self.stats_snmp_disabled_list, &mut rhs.stats_snmp_disabled_list); - } - if m.contains_key("threads") { - rhs.threads.clone_into(&mut self.threads); - } - if m.contains_key("tcp_threads") { - rhs.tcp_threads.clone_into(&mut self.tcp_threads); - } - if m.contains_key("version_string") { - rhs.version_string.clone_into(&mut self.version_string); - } - if m.contains_key("write_pid") { - rhs.write_pid.clone_into(&mut self.write_pid); - } - if m.contains_key("system_resolver_ttl") { - rhs.system_resolver_ttl.clone_into(&mut self.system_resolver_ttl); - } - if m.contains_key("system_resolver_interval") { - rhs.system_resolver_interval.clone_into(&mut self.system_resolver_interval); - } - if m.contains_key("system_resolver_self_resolve_check") { - rhs.system_resolver_self_resolve_check.clone_into(&mut self.system_resolver_self_resolve_check); - } - if m.contains_key("sortlists") { - if is_overriding(m, "sortlists") || self.sortlists == DEFAULT_CONFIG.recursor.sortlists { - self.sortlists.clear(); - } - merge_vec(&mut self.sortlists, &mut rhs.sortlists); - } - if m.contains_key("rpzs") { - if is_overriding(m, "rpzs") || self.rpzs == DEFAULT_CONFIG.recursor.rpzs { - self.rpzs.clear(); - } - merge_vec(&mut self.rpzs, &mut rhs.rpzs); - } - if m.contains_key("allowed_additional_qtypes") { - if is_overriding(m, "allowed_additional_qtypes") || self.allowed_additional_qtypes == DEFAULT_CONFIG.recursor.allowed_additional_qtypes { - self.allowed_additional_qtypes.clear(); - } - merge_vec(&mut self.allowed_additional_qtypes, &mut rhs.allowed_additional_qtypes); - } - if m.contains_key("lua_start_stop_script") { - rhs.lua_start_stop_script.clone_into(&mut self.lua_start_stop_script); - } - if m.contains_key("forwarding_catalog_zones") { - if is_overriding(m, "forwarding_catalog_zones") || self.forwarding_catalog_zones == DEFAULT_CONFIG.recursor.forwarding_catalog_zones { - self.forwarding_catalog_zones.clear(); - } - merge_vec(&mut self.forwarding_catalog_zones, &mut rhs.forwarding_catalog_zones); - } - } - } -} - -impl Merge for recsettings::Webservice { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("api_dir") { - rhs.api_dir.clone_into(&mut self.api_dir); - } - if m.contains_key("api_key") { - rhs.api_key.clone_into(&mut self.api_key); - } - if m.contains_key("webserver") { - rhs.webserver.clone_into(&mut self.webserver); - } - if m.contains_key("address") { - rhs.address.clone_into(&mut self.address); - } - if m.contains_key("allow_from") { - if is_overriding(m, "allow_from") || self.allow_from == DEFAULT_CONFIG.webservice.allow_from { - self.allow_from.clear(); - } - merge_vec(&mut self.allow_from, &mut rhs.allow_from); - } - if m.contains_key("hash_plaintext_credentials") { - rhs.hash_plaintext_credentials.clone_into(&mut self.hash_plaintext_credentials); - } - if m.contains_key("loglevel") { - rhs.loglevel.clone_into(&mut self.loglevel); - } - if m.contains_key("password") { - rhs.password.clone_into(&mut self.password); - } - if m.contains_key("port") { - rhs.port.clone_into(&mut self.port); - } - } - } -} - -impl Merge for recsettings::Carbon { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("interval") { - rhs.interval.clone_into(&mut self.interval); - } - if m.contains_key("ns") { - rhs.ns.clone_into(&mut self.ns); - } - if m.contains_key("ourname") { - rhs.ourname.clone_into(&mut self.ourname); - } - if m.contains_key("instance") { - rhs.instance.clone_into(&mut self.instance); - } - if m.contains_key("server") { - if is_overriding(m, "server") || self.server == DEFAULT_CONFIG.carbon.server { - self.server.clear(); - } - merge_vec(&mut self.server, &mut rhs.server); - } - } - } -} - -impl Merge for recsettings::Outgoing { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("dont_throttle_names") { - if is_overriding(m, "dont_throttle_names") || self.dont_throttle_names == DEFAULT_CONFIG.outgoing.dont_throttle_names { - self.dont_throttle_names.clear(); - } - merge_vec(&mut self.dont_throttle_names, &mut rhs.dont_throttle_names); - } - if m.contains_key("dont_throttle_netmasks") { - if is_overriding(m, "dont_throttle_netmasks") || self.dont_throttle_netmasks == DEFAULT_CONFIG.outgoing.dont_throttle_netmasks { - self.dont_throttle_netmasks.clear(); - } - merge_vec(&mut self.dont_throttle_netmasks, &mut rhs.dont_throttle_netmasks); - } - if m.contains_key("dot_to_auth_names") { - if is_overriding(m, "dot_to_auth_names") || self.dot_to_auth_names == DEFAULT_CONFIG.outgoing.dot_to_auth_names { - self.dot_to_auth_names.clear(); - } - merge_vec(&mut self.dot_to_auth_names, &mut rhs.dot_to_auth_names); - } - if m.contains_key("dot_to_port_853") { - rhs.dot_to_port_853.clone_into(&mut self.dot_to_port_853); - } - if m.contains_key("dont_query") { - if is_overriding(m, "dont_query") || self.dont_query == DEFAULT_CONFIG.outgoing.dont_query { - self.dont_query.clear(); - } - merge_vec(&mut self.dont_query, &mut rhs.dont_query); - } - if m.contains_key("edns_bufsize") { - rhs.edns_bufsize.clone_into(&mut self.edns_bufsize); - } - if m.contains_key("edns_padding") { - rhs.edns_padding.clone_into(&mut self.edns_padding); - } - if m.contains_key("edns_subnet_allow_list") { - if is_overriding(m, "edns_subnet_allow_list") || self.edns_subnet_allow_list == DEFAULT_CONFIG.outgoing.edns_subnet_allow_list { - self.edns_subnet_allow_list.clear(); - } - merge_vec(&mut self.edns_subnet_allow_list, &mut rhs.edns_subnet_allow_list); - } - if m.contains_key("edns_subnet_harden") { - rhs.edns_subnet_harden.clone_into(&mut self.edns_subnet_harden); - } - if m.contains_key("lowercase") { - rhs.lowercase.clone_into(&mut self.lowercase); - } - if m.contains_key("max_busy_dot_probes") { - rhs.max_busy_dot_probes.clone_into(&mut self.max_busy_dot_probes); - } - if m.contains_key("max_qperq") { - rhs.max_qperq.clone_into(&mut self.max_qperq); - } - if m.contains_key("max_bytesperq") { - rhs.max_bytesperq.clone_into(&mut self.max_bytesperq); - } - if m.contains_key("max_ns_address_qperq") { - rhs.max_ns_address_qperq.clone_into(&mut self.max_ns_address_qperq); - } - if m.contains_key("max_ns_per_resolve") { - rhs.max_ns_per_resolve.clone_into(&mut self.max_ns_per_resolve); - } - if m.contains_key("network_timeout") { - rhs.network_timeout.clone_into(&mut self.network_timeout); - } - if m.contains_key("non_resolving_ns_max_fails") { - rhs.non_resolving_ns_max_fails.clone_into(&mut self.non_resolving_ns_max_fails); - } - if m.contains_key("non_resolving_ns_throttle_time") { - rhs.non_resolving_ns_throttle_time.clone_into(&mut self.non_resolving_ns_throttle_time); - } - if m.contains_key("source_address") { - if is_overriding(m, "source_address") || self.source_address == DEFAULT_CONFIG.outgoing.source_address { - self.source_address.clear(); - } - merge_vec(&mut self.source_address, &mut rhs.source_address); - } - if m.contains_key("server_down_max_fails") { - rhs.server_down_max_fails.clone_into(&mut self.server_down_max_fails); - } - if m.contains_key("server_down_throttle_time") { - rhs.server_down_throttle_time.clone_into(&mut self.server_down_throttle_time); - } - if m.contains_key("bypass_server_throttling_probability") { - rhs.bypass_server_throttling_probability.clone_into(&mut self.bypass_server_throttling_probability); - } - if m.contains_key("single_socket") { - rhs.single_socket.clone_into(&mut self.single_socket); - } - if m.contains_key("tcp_fast_open_connect") { - rhs.tcp_fast_open_connect.clone_into(&mut self.tcp_fast_open_connect); - } - if m.contains_key("tcp_max_idle_ms") { - rhs.tcp_max_idle_ms.clone_into(&mut self.tcp_max_idle_ms); - } - if m.contains_key("tcp_max_idle_per_auth") { - rhs.tcp_max_idle_per_auth.clone_into(&mut self.tcp_max_idle_per_auth); - } - if m.contains_key("tcp_max_queries") { - rhs.tcp_max_queries.clone_into(&mut self.tcp_max_queries); - } - if m.contains_key("tcp_max_idle_per_thread") { - rhs.tcp_max_idle_per_thread.clone_into(&mut self.tcp_max_idle_per_thread); - } - if m.contains_key("udp_source_port_min") { - rhs.udp_source_port_min.clone_into(&mut self.udp_source_port_min); - } - if m.contains_key("udp_source_port_max") { - rhs.udp_source_port_max.clone_into(&mut self.udp_source_port_max); - } - if m.contains_key("udp_source_port_avoid") { - if is_overriding(m, "udp_source_port_avoid") || self.udp_source_port_avoid == DEFAULT_CONFIG.outgoing.udp_source_port_avoid { - self.udp_source_port_avoid.clear(); - } - merge_vec(&mut self.udp_source_port_avoid, &mut rhs.udp_source_port_avoid); - } - } - } -} - -impl Merge for recsettings::Packetcache { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("disable") { - rhs.disable.clone_into(&mut self.disable); - } - if m.contains_key("max_entries") { - rhs.max_entries.clone_into(&mut self.max_entries); - } - if m.contains_key("max_entry_size") { - rhs.max_entry_size.clone_into(&mut self.max_entry_size); - } - if m.contains_key("ttl") { - rhs.ttl.clone_into(&mut self.ttl); - } - if m.contains_key("negative_ttl") { - rhs.negative_ttl.clone_into(&mut self.negative_ttl); - } - if m.contains_key("servfail_ttl") { - rhs.servfail_ttl.clone_into(&mut self.servfail_ttl); - } - if m.contains_key("shards") { - rhs.shards.clone_into(&mut self.shards); - } - } - } -} - -impl Merge for recsettings::Logging { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("disable_syslog") { - rhs.disable_syslog.clone_into(&mut self.disable_syslog); - } - if m.contains_key("timestamp") { - rhs.timestamp.clone_into(&mut self.timestamp); - } - if m.contains_key("loglevel") { - rhs.loglevel.clone_into(&mut self.loglevel); - } - if m.contains_key("common_errors") { - rhs.common_errors.clone_into(&mut self.common_errors); - } - if m.contains_key("rpz_changes") { - rhs.rpz_changes.clone_into(&mut self.rpz_changes); - } - if m.contains_key("facility") { - rhs.facility.clone_into(&mut self.facility); - } - if m.contains_key("protobuf_use_kernel_timestamp") { - rhs.protobuf_use_kernel_timestamp.clone_into(&mut self.protobuf_use_kernel_timestamp); - } - if m.contains_key("quiet") { - rhs.quiet.clone_into(&mut self.quiet); - } - if m.contains_key("statistics_interval") { - rhs.statistics_interval.clone_into(&mut self.statistics_interval); - } - if m.contains_key("structured_logging") { - rhs.structured_logging.clone_into(&mut self.structured_logging); - } - if m.contains_key("structured_logging_backend") { - rhs.structured_logging_backend.clone_into(&mut self.structured_logging_backend); - } - if m.contains_key("trace") { - rhs.trace.clone_into(&mut self.trace); - } - if m.contains_key("protobuf_servers") { - if is_overriding(m, "protobuf_servers") || self.protobuf_servers == DEFAULT_CONFIG.logging.protobuf_servers { - self.protobuf_servers.clear(); - } - merge_vec(&mut self.protobuf_servers, &mut rhs.protobuf_servers); - } - if m.contains_key("outgoing_protobuf_servers") { - if is_overriding(m, "outgoing_protobuf_servers") || self.outgoing_protobuf_servers == DEFAULT_CONFIG.logging.outgoing_protobuf_servers { - self.outgoing_protobuf_servers.clear(); - } - merge_vec(&mut self.outgoing_protobuf_servers, &mut rhs.outgoing_protobuf_servers); - } - if m.contains_key("protobuf_mask_v4") { - rhs.protobuf_mask_v4.clone_into(&mut self.protobuf_mask_v4); - } - if m.contains_key("protobuf_mask_v6") { - rhs.protobuf_mask_v6.clone_into(&mut self.protobuf_mask_v6); - } - if m.contains_key("dnstap_framestream_servers") { - if is_overriding(m, "dnstap_framestream_servers") || self.dnstap_framestream_servers == DEFAULT_CONFIG.logging.dnstap_framestream_servers { - self.dnstap_framestream_servers.clear(); - } - merge_vec(&mut self.dnstap_framestream_servers, &mut rhs.dnstap_framestream_servers); - } - if m.contains_key("dnstap_nod_framestream_servers") { - if is_overriding(m, "dnstap_nod_framestream_servers") || self.dnstap_nod_framestream_servers == DEFAULT_CONFIG.logging.dnstap_nod_framestream_servers { - self.dnstap_nod_framestream_servers.clear(); - } - merge_vec(&mut self.dnstap_nod_framestream_servers, &mut rhs.dnstap_nod_framestream_servers); - } - } - } -} - -impl Merge for recsettings::Ecs { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("add_for") { - if is_overriding(m, "add_for") || self.add_for == DEFAULT_CONFIG.ecs.add_for { - self.add_for.clear(); - } - merge_vec(&mut self.add_for, &mut rhs.add_for); - } - if m.contains_key("ipv4_bits") { - rhs.ipv4_bits.clone_into(&mut self.ipv4_bits); - } - if m.contains_key("ipv4_cache_bits") { - rhs.ipv4_cache_bits.clone_into(&mut self.ipv4_cache_bits); - } - if m.contains_key("ipv6_bits") { - rhs.ipv6_bits.clone_into(&mut self.ipv6_bits); - } - if m.contains_key("ipv6_cache_bits") { - rhs.ipv6_cache_bits.clone_into(&mut self.ipv6_cache_bits); - } - if m.contains_key("ipv4_never_cache") { - rhs.ipv4_never_cache.clone_into(&mut self.ipv4_never_cache); - } - if m.contains_key("ipv6_never_cache") { - rhs.ipv6_never_cache.clone_into(&mut self.ipv6_never_cache); - } - if m.contains_key("minimum_ttl_override") { - rhs.minimum_ttl_override.clone_into(&mut self.minimum_ttl_override); - } - if m.contains_key("cache_limit_ttl") { - rhs.cache_limit_ttl.clone_into(&mut self.cache_limit_ttl); - } - if m.contains_key("scope_zero_address") { - rhs.scope_zero_address.clone_into(&mut self.scope_zero_address); - } - } - } -} - -impl Merge for recsettings::Recordcache { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("max_cache_bogus_ttl") { - rhs.max_cache_bogus_ttl.clone_into(&mut self.max_cache_bogus_ttl); - } - if m.contains_key("max_entries") { - rhs.max_entries.clone_into(&mut self.max_entries); - } - if m.contains_key("max_ttl") { - rhs.max_ttl.clone_into(&mut self.max_ttl); - } - if m.contains_key("max_entry_size") { - rhs.max_entry_size.clone_into(&mut self.max_entry_size); - } - if m.contains_key("limit_qtype_any") { - rhs.limit_qtype_any.clone_into(&mut self.limit_qtype_any); - } - if m.contains_key("max_rrset_size") { - rhs.max_rrset_size.clone_into(&mut self.max_rrset_size); - } - if m.contains_key("max_negative_ttl") { - rhs.max_negative_ttl.clone_into(&mut self.max_negative_ttl); - } - if m.contains_key("locked_ttl_perc") { - rhs.locked_ttl_perc.clone_into(&mut self.locked_ttl_perc); - } - if m.contains_key("shards") { - rhs.shards.clone_into(&mut self.shards); - } - if m.contains_key("refresh_on_ttl_perc") { - rhs.refresh_on_ttl_perc.clone_into(&mut self.refresh_on_ttl_perc); - } - if m.contains_key("serve_stale_extensions") { - rhs.serve_stale_extensions.clone_into(&mut self.serve_stale_extensions); - } - if m.contains_key("zonetocaches") { - if is_overriding(m, "zonetocaches") || self.zonetocaches == DEFAULT_CONFIG.recordcache.zonetocaches { - self.zonetocaches.clear(); - } - merge_vec(&mut self.zonetocaches, &mut rhs.zonetocaches); - } - } - } -} - -impl Merge for recsettings::Nod { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("tracking") { - rhs.tracking.clone_into(&mut self.tracking); - } - if m.contains_key("log") { - rhs.log.clone_into(&mut self.log); - } - if m.contains_key("lookup") { - rhs.lookup.clone_into(&mut self.lookup); - } - if m.contains_key("db_size") { - rhs.db_size.clone_into(&mut self.db_size); - } - if m.contains_key("history_dir") { - rhs.history_dir.clone_into(&mut self.history_dir); - } - if m.contains_key("db_snapshot_interval") { - rhs.db_snapshot_interval.clone_into(&mut self.db_snapshot_interval); - } - if m.contains_key("ignore_list") { - if is_overriding(m, "ignore_list") || self.ignore_list == DEFAULT_CONFIG.nod.ignore_list { - self.ignore_list.clear(); - } - merge_vec(&mut self.ignore_list, &mut rhs.ignore_list); - } - if m.contains_key("ignore_list_file") { - rhs.ignore_list_file.clone_into(&mut self.ignore_list_file); - } - if m.contains_key("pb_tag") { - rhs.pb_tag.clone_into(&mut self.pb_tag); - } - if m.contains_key("unique_response_tracking") { - rhs.unique_response_tracking.clone_into(&mut self.unique_response_tracking); - } - if m.contains_key("unique_response_log") { - rhs.unique_response_log.clone_into(&mut self.unique_response_log); - } - if m.contains_key("unique_response_db_size") { - rhs.unique_response_db_size.clone_into(&mut self.unique_response_db_size); - } - if m.contains_key("unique_response_history_dir") { - rhs.unique_response_history_dir.clone_into(&mut self.unique_response_history_dir); - } - if m.contains_key("unique_response_pb_tag") { - rhs.unique_response_pb_tag.clone_into(&mut self.unique_response_pb_tag); - } - if m.contains_key("unique_response_ignore_list") { - if is_overriding(m, "unique_response_ignore_list") || self.unique_response_ignore_list == DEFAULT_CONFIG.nod.unique_response_ignore_list { - self.unique_response_ignore_list.clear(); - } - merge_vec(&mut self.unique_response_ignore_list, &mut rhs.unique_response_ignore_list); - } - if m.contains_key("unique_response_ignore_list_file") { - rhs.unique_response_ignore_list_file.clone_into(&mut self.unique_response_ignore_list_file); - } - } - } -} - -impl Merge for recsettings::Snmp { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if m.contains_key("agent") { - rhs.agent.clone_into(&mut self.agent); - } - if m.contains_key("daemon_socket") { - rhs.daemon_socket.clone_into(&mut self.daemon_socket); - } - } - } -} - -impl Merge for crate::recsettings::Recursorsettings { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>) { - if let Some(m) = map { - if let Some(s) = m.get("dnssec") { - if s.is_mapping() { - self.dnssec.merge(&mut rhs.dnssec, s.as_mapping()); - } - } - if let Some(s) = m.get("incoming") { - if s.is_mapping() { - self.incoming.merge(&mut rhs.incoming, s.as_mapping()); - } - } - if let Some(s) = m.get("recursor") { - if s.is_mapping() { - self.recursor.merge(&mut rhs.recursor, s.as_mapping()); - } - } - if let Some(s) = m.get("webservice") { - if s.is_mapping() { - self.webservice.merge(&mut rhs.webservice, s.as_mapping()); - } - } - if let Some(s) = m.get("carbon") { - if s.is_mapping() { - self.carbon.merge(&mut rhs.carbon, s.as_mapping()); - } - } - if let Some(s) = m.get("outgoing") { - if s.is_mapping() { - self.outgoing.merge(&mut rhs.outgoing, s.as_mapping()); - } - } - if let Some(s) = m.get("packetcache") { - if s.is_mapping() { - self.packetcache.merge(&mut rhs.packetcache, s.as_mapping()); - } - } - if let Some(s) = m.get("logging") { - if s.is_mapping() { - self.logging.merge(&mut rhs.logging, s.as_mapping()); - } - } - if let Some(s) = m.get("ecs") { - if s.is_mapping() { - self.ecs.merge(&mut rhs.ecs, s.as_mapping()); - } - } - if let Some(s) = m.get("recordcache") { - if s.is_mapping() { - self.recordcache.merge(&mut rhs.recordcache, s.as_mapping()); - } - } - if let Some(s) = m.get("nod") { - if s.is_mapping() { - self.nod.merge(&mut rhs.nod, s.as_mapping()); - } - } - if let Some(s) = m.get("snmp") { - if s.is_mapping() { - self.snmp.merge(&mut rhs.snmp, s.as_mapping()); - } - } - } - } -} - -// DEFAULT HANDLING for dnssec_validation -fn default_value_dnssec_validation() -> String { - String::from("process") -} -fn default_value_equal_dnssec_validation(value: &str)-> bool { - value == default_value_dnssec_validation() -} - -// DEFAULT HANDLING for dnssec_disabled_algorithms -fn default_value_dnssec_disabled_algorithms() -> Vec { - vec![ - ] -} -fn default_value_equal_dnssec_disabled_algorithms(value: &Vec) -> bool { - let def = default_value_dnssec_disabled_algorithms(); - &def == value -} - -// DEFAULT HANDLING for dnssec_x_dnssec_names -fn default_value_dnssec_x_dnssec_names() -> Vec { - vec![ - ] -} -fn default_value_equal_dnssec_x_dnssec_names(value: &Vec) -> bool { - let def = default_value_dnssec_x_dnssec_names(); - &def == value -} - -// DEFAULT HANDLING for dnssec_trustanchors -fn default_value_dnssec_trustanchors() -> Vec { - let msg = "default value defined for `dnssec_trustanchors' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("[{name: ., dsrecords: ['20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d', '38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16']}]").expect(msg); - deserialized -} -fn default_value_equal_dnssec_trustanchors(value: &Vec)-> bool { - let def = default_value_dnssec_trustanchors(); - &def == value -} - -// DEFAULT HANDLING for dnssec_negative_trustanchors -fn default_value_dnssec_negative_trustanchors() -> Vec { - let msg = "default value defined for `dnssec_negative_trustanchors' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_dnssec_negative_trustanchors(value: &Vec)-> bool { - let def = default_value_dnssec_negative_trustanchors(); - &def == value -} - -// DEFAULT HANDLING for incoming_allow_from -fn default_value_incoming_allow_from() -> Vec { - vec![ - String::from("127.0.0.0/8"), - String::from("10.0.0.0/8"), - String::from("100.64.0.0/10"), - String::from("169.254.0.0/16"), - String::from("192.168.0.0/16"), - String::from("172.16.0.0/12"), - String::from("::1/128"), - String::from("fc00::/7"), - String::from("fe80::/10"), - ] -} -fn default_value_equal_incoming_allow_from(value: &Vec) -> bool { - let def = default_value_incoming_allow_from(); - &def == value -} - -// DEFAULT HANDLING for incoming_allow_notify_for -fn default_value_incoming_allow_notify_for() -> Vec { - vec![ - ] -} -fn default_value_equal_incoming_allow_notify_for(value: &Vec) -> bool { - let def = default_value_incoming_allow_notify_for(); - &def == value -} - -// DEFAULT HANDLING for incoming_allow_notify_from -fn default_value_incoming_allow_notify_from() -> Vec { - vec![ - ] -} -fn default_value_equal_incoming_allow_notify_from(value: &Vec) -> bool { - let def = default_value_incoming_allow_notify_from(); - &def == value -} - -// DEFAULT HANDLING for incoming_edns_padding_from -fn default_value_incoming_edns_padding_from() -> Vec { - vec![ - ] -} -fn default_value_equal_incoming_edns_padding_from(value: &Vec) -> bool { - let def = default_value_incoming_edns_padding_from(); - &def == value -} - -// DEFAULT HANDLING for incoming_edns_padding_mode -fn default_value_incoming_edns_padding_mode() -> String { - String::from("padded-queries-only") -} -fn default_value_equal_incoming_edns_padding_mode(value: &str)-> bool { - value == default_value_incoming_edns_padding_mode() -} - -// DEFAULT HANDLING for incoming_listen -fn default_value_incoming_listen() -> Vec { - vec![ - String::from("127.0.0.1"), - ] -} -fn default_value_equal_incoming_listen(value: &Vec) -> bool { - let def = default_value_incoming_listen(); - &def == value -} - -// DEFAULT HANDLING for incoming_proxy_protocol_from -fn default_value_incoming_proxy_protocol_from() -> Vec { - vec![ - ] -} -fn default_value_equal_incoming_proxy_protocol_from(value: &Vec) -> bool { - let def = default_value_incoming_proxy_protocol_from(); - &def == value -} - -// DEFAULT HANDLING for incoming_proxy_protocol_exceptions -fn default_value_incoming_proxy_protocol_exceptions() -> Vec { - vec![ - ] -} -fn default_value_equal_incoming_proxy_protocol_exceptions(value: &Vec) -> bool { - let def = default_value_incoming_proxy_protocol_exceptions(); - &def == value -} - -// DEFAULT HANDLING for incoming_proxymappings -fn default_value_incoming_proxymappings() -> Vec { - let msg = "default value defined for `incoming_proxymappings' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_incoming_proxymappings(value: &Vec)-> bool { - let def = default_value_incoming_proxymappings(); - &def == value -} - -// DEFAULT HANDLING for recursor_auth_zones -fn default_value_recursor_auth_zones() -> Vec { - let msg = "default value defined for `recursor_auth_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_auth_zones(value: &Vec)-> bool { - let def = default_value_recursor_auth_zones(); - &def == value -} - -// DEFAULT HANDLING for recursor_config_dir -fn default_value_recursor_config_dir() -> String { - String::from(env!("SYSCONFDIR")) -} -fn default_value_equal_recursor_config_dir(value: &str)-> bool { - value == default_value_recursor_config_dir() -} - -// DEFAULT HANDLING for recursor_etc_hosts_file -fn default_value_recursor_etc_hosts_file() -> String { - String::from("/etc/hosts") -} -fn default_value_equal_recursor_etc_hosts_file(value: &str)-> bool { - value == default_value_recursor_etc_hosts_file() -} - -// DEFAULT HANDLING for recursor_forward_zones -fn default_value_recursor_forward_zones() -> Vec { - let msg = "default value defined for `recursor_forward_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_forward_zones(value: &Vec)-> bool { - let def = default_value_recursor_forward_zones(); - &def == value -} - -// DEFAULT HANDLING for recursor_forward_zones_recurse -fn default_value_recursor_forward_zones_recurse() -> Vec { - let msg = "default value defined for `recursor_forward_zones_recurse' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_forward_zones_recurse(value: &Vec)-> bool { - let def = default_value_recursor_forward_zones_recurse(); - &def == value -} - -// DEFAULT HANDLING for recursor_ignore_unknown_settings -fn default_value_recursor_ignore_unknown_settings() -> Vec { - vec![ - ] -} -fn default_value_equal_recursor_ignore_unknown_settings(value: &Vec) -> bool { - let def = default_value_recursor_ignore_unknown_settings(); - &def == value -} - -// DEFAULT HANDLING for recursor_nothing_below_nxdomain -fn default_value_recursor_nothing_below_nxdomain() -> String { - String::from("dnssec") -} -fn default_value_equal_recursor_nothing_below_nxdomain(value: &str)-> bool { - value == default_value_recursor_nothing_below_nxdomain() -} - -// DEFAULT HANDLING for recursor_security_poll_suffix -fn default_value_recursor_security_poll_suffix() -> String { - String::from("secpoll.powerdns.com.") -} -fn default_value_equal_recursor_security_poll_suffix(value: &str)-> bool { - value == default_value_recursor_security_poll_suffix() -} - -// DEFAULT HANDLING for recursor_server_id -fn default_value_recursor_server_id() -> String { - String::from("*runtime determined*") -} -fn default_value_equal_recursor_server_id(value: &str)-> bool { - value == default_value_recursor_server_id() -} - -// DEFAULT HANDLING for recursor_stats_api_disabled_list -fn default_value_recursor_stats_api_disabled_list() -> Vec { - vec![ - String::from("cache-bytes"), - String::from("packetcache-bytes"), - String::from("special-memory-usage"), - String::from("ecs-v4-response-bits-1"), - String::from("ecs-v4-response-bits-2"), - String::from("ecs-v4-response-bits-3"), - String::from("ecs-v4-response-bits-4"), - String::from("ecs-v4-response-bits-5"), - String::from("ecs-v4-response-bits-6"), - String::from("ecs-v4-response-bits-7"), - String::from("ecs-v4-response-bits-8"), - String::from("ecs-v4-response-bits-9"), - String::from("ecs-v4-response-bits-10"), - String::from("ecs-v4-response-bits-11"), - String::from("ecs-v4-response-bits-12"), - String::from("ecs-v4-response-bits-13"), - String::from("ecs-v4-response-bits-14"), - String::from("ecs-v4-response-bits-15"), - String::from("ecs-v4-response-bits-16"), - String::from("ecs-v4-response-bits-17"), - String::from("ecs-v4-response-bits-18"), - String::from("ecs-v4-response-bits-19"), - String::from("ecs-v4-response-bits-20"), - String::from("ecs-v4-response-bits-21"), - String::from("ecs-v4-response-bits-22"), - String::from("ecs-v4-response-bits-23"), - String::from("ecs-v4-response-bits-24"), - String::from("ecs-v4-response-bits-25"), - String::from("ecs-v4-response-bits-26"), - String::from("ecs-v4-response-bits-27"), - String::from("ecs-v4-response-bits-28"), - String::from("ecs-v4-response-bits-29"), - String::from("ecs-v4-response-bits-30"), - String::from("ecs-v4-response-bits-31"), - String::from("ecs-v4-response-bits-32"), - String::from("ecs-v6-response-bits-1"), - String::from("ecs-v6-response-bits-2"), - String::from("ecs-v6-response-bits-3"), - String::from("ecs-v6-response-bits-4"), - String::from("ecs-v6-response-bits-5"), - String::from("ecs-v6-response-bits-6"), - String::from("ecs-v6-response-bits-7"), - String::from("ecs-v6-response-bits-8"), - String::from("ecs-v6-response-bits-9"), - String::from("ecs-v6-response-bits-10"), - String::from("ecs-v6-response-bits-11"), - String::from("ecs-v6-response-bits-12"), - String::from("ecs-v6-response-bits-13"), - String::from("ecs-v6-response-bits-14"), - String::from("ecs-v6-response-bits-15"), - String::from("ecs-v6-response-bits-16"), - String::from("ecs-v6-response-bits-17"), - String::from("ecs-v6-response-bits-18"), - String::from("ecs-v6-response-bits-19"), - String::from("ecs-v6-response-bits-20"), - String::from("ecs-v6-response-bits-21"), - String::from("ecs-v6-response-bits-22"), - String::from("ecs-v6-response-bits-23"), - String::from("ecs-v6-response-bits-24"), - String::from("ecs-v6-response-bits-25"), - String::from("ecs-v6-response-bits-26"), - String::from("ecs-v6-response-bits-27"), - String::from("ecs-v6-response-bits-28"), - String::from("ecs-v6-response-bits-29"), - String::from("ecs-v6-response-bits-30"), - String::from("ecs-v6-response-bits-31"), - String::from("ecs-v6-response-bits-32"), - String::from("ecs-v6-response-bits-33"), - String::from("ecs-v6-response-bits-34"), - String::from("ecs-v6-response-bits-35"), - String::from("ecs-v6-response-bits-36"), - String::from("ecs-v6-response-bits-37"), - String::from("ecs-v6-response-bits-38"), - String::from("ecs-v6-response-bits-39"), - String::from("ecs-v6-response-bits-40"), - String::from("ecs-v6-response-bits-41"), - String::from("ecs-v6-response-bits-42"), - String::from("ecs-v6-response-bits-43"), - String::from("ecs-v6-response-bits-44"), - String::from("ecs-v6-response-bits-45"), - String::from("ecs-v6-response-bits-46"), - String::from("ecs-v6-response-bits-47"), - String::from("ecs-v6-response-bits-48"), - String::from("ecs-v6-response-bits-49"), - String::from("ecs-v6-response-bits-50"), - String::from("ecs-v6-response-bits-51"), - String::from("ecs-v6-response-bits-52"), - String::from("ecs-v6-response-bits-53"), - String::from("ecs-v6-response-bits-54"), - String::from("ecs-v6-response-bits-55"), - String::from("ecs-v6-response-bits-56"), - String::from("ecs-v6-response-bits-57"), - String::from("ecs-v6-response-bits-58"), - String::from("ecs-v6-response-bits-59"), - String::from("ecs-v6-response-bits-60"), - String::from("ecs-v6-response-bits-61"), - String::from("ecs-v6-response-bits-62"), - String::from("ecs-v6-response-bits-63"), - String::from("ecs-v6-response-bits-64"), - String::from("ecs-v6-response-bits-65"), - String::from("ecs-v6-response-bits-66"), - String::from("ecs-v6-response-bits-67"), - String::from("ecs-v6-response-bits-68"), - String::from("ecs-v6-response-bits-69"), - String::from("ecs-v6-response-bits-70"), - String::from("ecs-v6-response-bits-71"), - String::from("ecs-v6-response-bits-72"), - String::from("ecs-v6-response-bits-73"), - String::from("ecs-v6-response-bits-74"), - String::from("ecs-v6-response-bits-75"), - String::from("ecs-v6-response-bits-76"), - String::from("ecs-v6-response-bits-77"), - String::from("ecs-v6-response-bits-78"), - String::from("ecs-v6-response-bits-79"), - String::from("ecs-v6-response-bits-80"), - String::from("ecs-v6-response-bits-81"), - String::from("ecs-v6-response-bits-82"), - String::from("ecs-v6-response-bits-83"), - String::from("ecs-v6-response-bits-84"), - String::from("ecs-v6-response-bits-85"), - String::from("ecs-v6-response-bits-86"), - String::from("ecs-v6-response-bits-87"), - String::from("ecs-v6-response-bits-88"), - String::from("ecs-v6-response-bits-89"), - String::from("ecs-v6-response-bits-90"), - String::from("ecs-v6-response-bits-91"), - String::from("ecs-v6-response-bits-92"), - String::from("ecs-v6-response-bits-93"), - String::from("ecs-v6-response-bits-94"), - String::from("ecs-v6-response-bits-95"), - String::from("ecs-v6-response-bits-96"), - String::from("ecs-v6-response-bits-97"), - String::from("ecs-v6-response-bits-98"), - String::from("ecs-v6-response-bits-99"), - String::from("ecs-v6-response-bits-100"), - String::from("ecs-v6-response-bits-101"), - String::from("ecs-v6-response-bits-102"), - String::from("ecs-v6-response-bits-103"), - String::from("ecs-v6-response-bits-104"), - String::from("ecs-v6-response-bits-105"), - String::from("ecs-v6-response-bits-106"), - String::from("ecs-v6-response-bits-107"), - String::from("ecs-v6-response-bits-108"), - String::from("ecs-v6-response-bits-109"), - String::from("ecs-v6-response-bits-110"), - String::from("ecs-v6-response-bits-111"), - String::from("ecs-v6-response-bits-112"), - String::from("ecs-v6-response-bits-113"), - String::from("ecs-v6-response-bits-114"), - String::from("ecs-v6-response-bits-115"), - String::from("ecs-v6-response-bits-116"), - String::from("ecs-v6-response-bits-117"), - String::from("ecs-v6-response-bits-118"), - String::from("ecs-v6-response-bits-119"), - String::from("ecs-v6-response-bits-120"), - String::from("ecs-v6-response-bits-121"), - String::from("ecs-v6-response-bits-122"), - String::from("ecs-v6-response-bits-123"), - String::from("ecs-v6-response-bits-124"), - String::from("ecs-v6-response-bits-125"), - String::from("ecs-v6-response-bits-126"), - String::from("ecs-v6-response-bits-127"), - String::from("ecs-v6-response-bits-128"), - ] -} -fn default_value_equal_recursor_stats_api_disabled_list(value: &Vec) -> bool { - let def = default_value_recursor_stats_api_disabled_list(); - &def == value -} - -// DEFAULT HANDLING for recursor_stats_carbon_disabled_list -fn default_value_recursor_stats_carbon_disabled_list() -> Vec { - vec![ - String::from("cache-bytes"), - String::from("packetcache-bytes"), - String::from("special-memory-usage"), - String::from("ecs-v4-response-bits-1"), - String::from("ecs-v4-response-bits-2"), - String::from("ecs-v4-response-bits-3"), - String::from("ecs-v4-response-bits-4"), - String::from("ecs-v4-response-bits-5"), - String::from("ecs-v4-response-bits-6"), - String::from("ecs-v4-response-bits-7"), - String::from("ecs-v4-response-bits-8"), - String::from("ecs-v4-response-bits-9"), - String::from("ecs-v4-response-bits-10"), - String::from("ecs-v4-response-bits-11"), - String::from("ecs-v4-response-bits-12"), - String::from("ecs-v4-response-bits-13"), - String::from("ecs-v4-response-bits-14"), - String::from("ecs-v4-response-bits-15"), - String::from("ecs-v4-response-bits-16"), - String::from("ecs-v4-response-bits-17"), - String::from("ecs-v4-response-bits-18"), - String::from("ecs-v4-response-bits-19"), - String::from("ecs-v4-response-bits-20"), - String::from("ecs-v4-response-bits-21"), - String::from("ecs-v4-response-bits-22"), - String::from("ecs-v4-response-bits-23"), - String::from("ecs-v4-response-bits-24"), - String::from("ecs-v4-response-bits-25"), - String::from("ecs-v4-response-bits-26"), - String::from("ecs-v4-response-bits-27"), - String::from("ecs-v4-response-bits-28"), - String::from("ecs-v4-response-bits-29"), - String::from("ecs-v4-response-bits-30"), - String::from("ecs-v4-response-bits-31"), - String::from("ecs-v4-response-bits-32"), - String::from("ecs-v6-response-bits-1"), - String::from("ecs-v6-response-bits-2"), - String::from("ecs-v6-response-bits-3"), - String::from("ecs-v6-response-bits-4"), - String::from("ecs-v6-response-bits-5"), - String::from("ecs-v6-response-bits-6"), - String::from("ecs-v6-response-bits-7"), - String::from("ecs-v6-response-bits-8"), - String::from("ecs-v6-response-bits-9"), - String::from("ecs-v6-response-bits-10"), - String::from("ecs-v6-response-bits-11"), - String::from("ecs-v6-response-bits-12"), - String::from("ecs-v6-response-bits-13"), - String::from("ecs-v6-response-bits-14"), - String::from("ecs-v6-response-bits-15"), - String::from("ecs-v6-response-bits-16"), - String::from("ecs-v6-response-bits-17"), - String::from("ecs-v6-response-bits-18"), - String::from("ecs-v6-response-bits-19"), - String::from("ecs-v6-response-bits-20"), - String::from("ecs-v6-response-bits-21"), - String::from("ecs-v6-response-bits-22"), - String::from("ecs-v6-response-bits-23"), - String::from("ecs-v6-response-bits-24"), - String::from("ecs-v6-response-bits-25"), - String::from("ecs-v6-response-bits-26"), - String::from("ecs-v6-response-bits-27"), - String::from("ecs-v6-response-bits-28"), - String::from("ecs-v6-response-bits-29"), - String::from("ecs-v6-response-bits-30"), - String::from("ecs-v6-response-bits-31"), - String::from("ecs-v6-response-bits-32"), - String::from("ecs-v6-response-bits-33"), - String::from("ecs-v6-response-bits-34"), - String::from("ecs-v6-response-bits-35"), - String::from("ecs-v6-response-bits-36"), - String::from("ecs-v6-response-bits-37"), - String::from("ecs-v6-response-bits-38"), - String::from("ecs-v6-response-bits-39"), - String::from("ecs-v6-response-bits-40"), - String::from("ecs-v6-response-bits-41"), - String::from("ecs-v6-response-bits-42"), - String::from("ecs-v6-response-bits-43"), - String::from("ecs-v6-response-bits-44"), - String::from("ecs-v6-response-bits-45"), - String::from("ecs-v6-response-bits-46"), - String::from("ecs-v6-response-bits-47"), - String::from("ecs-v6-response-bits-48"), - String::from("ecs-v6-response-bits-49"), - String::from("ecs-v6-response-bits-50"), - String::from("ecs-v6-response-bits-51"), - String::from("ecs-v6-response-bits-52"), - String::from("ecs-v6-response-bits-53"), - String::from("ecs-v6-response-bits-54"), - String::from("ecs-v6-response-bits-55"), - String::from("ecs-v6-response-bits-56"), - String::from("ecs-v6-response-bits-57"), - String::from("ecs-v6-response-bits-58"), - String::from("ecs-v6-response-bits-59"), - String::from("ecs-v6-response-bits-60"), - String::from("ecs-v6-response-bits-61"), - String::from("ecs-v6-response-bits-62"), - String::from("ecs-v6-response-bits-63"), - String::from("ecs-v6-response-bits-64"), - String::from("ecs-v6-response-bits-65"), - String::from("ecs-v6-response-bits-66"), - String::from("ecs-v6-response-bits-67"), - String::from("ecs-v6-response-bits-68"), - String::from("ecs-v6-response-bits-69"), - String::from("ecs-v6-response-bits-70"), - String::from("ecs-v6-response-bits-71"), - String::from("ecs-v6-response-bits-72"), - String::from("ecs-v6-response-bits-73"), - String::from("ecs-v6-response-bits-74"), - String::from("ecs-v6-response-bits-75"), - String::from("ecs-v6-response-bits-76"), - String::from("ecs-v6-response-bits-77"), - String::from("ecs-v6-response-bits-78"), - String::from("ecs-v6-response-bits-79"), - String::from("ecs-v6-response-bits-80"), - String::from("ecs-v6-response-bits-81"), - String::from("ecs-v6-response-bits-82"), - String::from("ecs-v6-response-bits-83"), - String::from("ecs-v6-response-bits-84"), - String::from("ecs-v6-response-bits-85"), - String::from("ecs-v6-response-bits-86"), - String::from("ecs-v6-response-bits-87"), - String::from("ecs-v6-response-bits-88"), - String::from("ecs-v6-response-bits-89"), - String::from("ecs-v6-response-bits-90"), - String::from("ecs-v6-response-bits-91"), - String::from("ecs-v6-response-bits-92"), - String::from("ecs-v6-response-bits-93"), - String::from("ecs-v6-response-bits-94"), - String::from("ecs-v6-response-bits-95"), - String::from("ecs-v6-response-bits-96"), - String::from("ecs-v6-response-bits-97"), - String::from("ecs-v6-response-bits-98"), - String::from("ecs-v6-response-bits-99"), - String::from("ecs-v6-response-bits-100"), - String::from("ecs-v6-response-bits-101"), - String::from("ecs-v6-response-bits-102"), - String::from("ecs-v6-response-bits-103"), - String::from("ecs-v6-response-bits-104"), - String::from("ecs-v6-response-bits-105"), - String::from("ecs-v6-response-bits-106"), - String::from("ecs-v6-response-bits-107"), - String::from("ecs-v6-response-bits-108"), - String::from("ecs-v6-response-bits-109"), - String::from("ecs-v6-response-bits-110"), - String::from("ecs-v6-response-bits-111"), - String::from("ecs-v6-response-bits-112"), - String::from("ecs-v6-response-bits-113"), - String::from("ecs-v6-response-bits-114"), - String::from("ecs-v6-response-bits-115"), - String::from("ecs-v6-response-bits-116"), - String::from("ecs-v6-response-bits-117"), - String::from("ecs-v6-response-bits-118"), - String::from("ecs-v6-response-bits-119"), - String::from("ecs-v6-response-bits-120"), - String::from("ecs-v6-response-bits-121"), - String::from("ecs-v6-response-bits-122"), - String::from("ecs-v6-response-bits-123"), - String::from("ecs-v6-response-bits-124"), - String::from("ecs-v6-response-bits-125"), - String::from("ecs-v6-response-bits-126"), - String::from("ecs-v6-response-bits-127"), - String::from("ecs-v6-response-bits-128"), - String::from("cumul-clientanswers"), - String::from("cumul-authanswers"), - String::from("policy-hits"), - String::from("proxy-mapping-total"), - String::from("remote-logger-count"), - ] -} -fn default_value_equal_recursor_stats_carbon_disabled_list(value: &Vec) -> bool { - let def = default_value_recursor_stats_carbon_disabled_list(); - &def == value -} - -// DEFAULT HANDLING for recursor_stats_rec_control_disabled_list -fn default_value_recursor_stats_rec_control_disabled_list() -> Vec { - vec![ - String::from("cache-bytes"), - String::from("packetcache-bytes"), - String::from("special-memory-usage"), - String::from("ecs-v4-response-bits-1"), - String::from("ecs-v4-response-bits-2"), - String::from("ecs-v4-response-bits-3"), - String::from("ecs-v4-response-bits-4"), - String::from("ecs-v4-response-bits-5"), - String::from("ecs-v4-response-bits-6"), - String::from("ecs-v4-response-bits-7"), - String::from("ecs-v4-response-bits-8"), - String::from("ecs-v4-response-bits-9"), - String::from("ecs-v4-response-bits-10"), - String::from("ecs-v4-response-bits-11"), - String::from("ecs-v4-response-bits-12"), - String::from("ecs-v4-response-bits-13"), - String::from("ecs-v4-response-bits-14"), - String::from("ecs-v4-response-bits-15"), - String::from("ecs-v4-response-bits-16"), - String::from("ecs-v4-response-bits-17"), - String::from("ecs-v4-response-bits-18"), - String::from("ecs-v4-response-bits-19"), - String::from("ecs-v4-response-bits-20"), - String::from("ecs-v4-response-bits-21"), - String::from("ecs-v4-response-bits-22"), - String::from("ecs-v4-response-bits-23"), - String::from("ecs-v4-response-bits-24"), - String::from("ecs-v4-response-bits-25"), - String::from("ecs-v4-response-bits-26"), - String::from("ecs-v4-response-bits-27"), - String::from("ecs-v4-response-bits-28"), - String::from("ecs-v4-response-bits-29"), - String::from("ecs-v4-response-bits-30"), - String::from("ecs-v4-response-bits-31"), - String::from("ecs-v4-response-bits-32"), - String::from("ecs-v6-response-bits-1"), - String::from("ecs-v6-response-bits-2"), - String::from("ecs-v6-response-bits-3"), - String::from("ecs-v6-response-bits-4"), - String::from("ecs-v6-response-bits-5"), - String::from("ecs-v6-response-bits-6"), - String::from("ecs-v6-response-bits-7"), - String::from("ecs-v6-response-bits-8"), - String::from("ecs-v6-response-bits-9"), - String::from("ecs-v6-response-bits-10"), - String::from("ecs-v6-response-bits-11"), - String::from("ecs-v6-response-bits-12"), - String::from("ecs-v6-response-bits-13"), - String::from("ecs-v6-response-bits-14"), - String::from("ecs-v6-response-bits-15"), - String::from("ecs-v6-response-bits-16"), - String::from("ecs-v6-response-bits-17"), - String::from("ecs-v6-response-bits-18"), - String::from("ecs-v6-response-bits-19"), - String::from("ecs-v6-response-bits-20"), - String::from("ecs-v6-response-bits-21"), - String::from("ecs-v6-response-bits-22"), - String::from("ecs-v6-response-bits-23"), - String::from("ecs-v6-response-bits-24"), - String::from("ecs-v6-response-bits-25"), - String::from("ecs-v6-response-bits-26"), - String::from("ecs-v6-response-bits-27"), - String::from("ecs-v6-response-bits-28"), - String::from("ecs-v6-response-bits-29"), - String::from("ecs-v6-response-bits-30"), - String::from("ecs-v6-response-bits-31"), - String::from("ecs-v6-response-bits-32"), - String::from("ecs-v6-response-bits-33"), - String::from("ecs-v6-response-bits-34"), - String::from("ecs-v6-response-bits-35"), - String::from("ecs-v6-response-bits-36"), - String::from("ecs-v6-response-bits-37"), - String::from("ecs-v6-response-bits-38"), - String::from("ecs-v6-response-bits-39"), - String::from("ecs-v6-response-bits-40"), - String::from("ecs-v6-response-bits-41"), - String::from("ecs-v6-response-bits-42"), - String::from("ecs-v6-response-bits-43"), - String::from("ecs-v6-response-bits-44"), - String::from("ecs-v6-response-bits-45"), - String::from("ecs-v6-response-bits-46"), - String::from("ecs-v6-response-bits-47"), - String::from("ecs-v6-response-bits-48"), - String::from("ecs-v6-response-bits-49"), - String::from("ecs-v6-response-bits-50"), - String::from("ecs-v6-response-bits-51"), - String::from("ecs-v6-response-bits-52"), - String::from("ecs-v6-response-bits-53"), - String::from("ecs-v6-response-bits-54"), - String::from("ecs-v6-response-bits-55"), - String::from("ecs-v6-response-bits-56"), - String::from("ecs-v6-response-bits-57"), - String::from("ecs-v6-response-bits-58"), - String::from("ecs-v6-response-bits-59"), - String::from("ecs-v6-response-bits-60"), - String::from("ecs-v6-response-bits-61"), - String::from("ecs-v6-response-bits-62"), - String::from("ecs-v6-response-bits-63"), - String::from("ecs-v6-response-bits-64"), - String::from("ecs-v6-response-bits-65"), - String::from("ecs-v6-response-bits-66"), - String::from("ecs-v6-response-bits-67"), - String::from("ecs-v6-response-bits-68"), - String::from("ecs-v6-response-bits-69"), - String::from("ecs-v6-response-bits-70"), - String::from("ecs-v6-response-bits-71"), - String::from("ecs-v6-response-bits-72"), - String::from("ecs-v6-response-bits-73"), - String::from("ecs-v6-response-bits-74"), - String::from("ecs-v6-response-bits-75"), - String::from("ecs-v6-response-bits-76"), - String::from("ecs-v6-response-bits-77"), - String::from("ecs-v6-response-bits-78"), - String::from("ecs-v6-response-bits-79"), - String::from("ecs-v6-response-bits-80"), - String::from("ecs-v6-response-bits-81"), - String::from("ecs-v6-response-bits-82"), - String::from("ecs-v6-response-bits-83"), - String::from("ecs-v6-response-bits-84"), - String::from("ecs-v6-response-bits-85"), - String::from("ecs-v6-response-bits-86"), - String::from("ecs-v6-response-bits-87"), - String::from("ecs-v6-response-bits-88"), - String::from("ecs-v6-response-bits-89"), - String::from("ecs-v6-response-bits-90"), - String::from("ecs-v6-response-bits-91"), - String::from("ecs-v6-response-bits-92"), - String::from("ecs-v6-response-bits-93"), - String::from("ecs-v6-response-bits-94"), - String::from("ecs-v6-response-bits-95"), - String::from("ecs-v6-response-bits-96"), - String::from("ecs-v6-response-bits-97"), - String::from("ecs-v6-response-bits-98"), - String::from("ecs-v6-response-bits-99"), - String::from("ecs-v6-response-bits-100"), - String::from("ecs-v6-response-bits-101"), - String::from("ecs-v6-response-bits-102"), - String::from("ecs-v6-response-bits-103"), - String::from("ecs-v6-response-bits-104"), - String::from("ecs-v6-response-bits-105"), - String::from("ecs-v6-response-bits-106"), - String::from("ecs-v6-response-bits-107"), - String::from("ecs-v6-response-bits-108"), - String::from("ecs-v6-response-bits-109"), - String::from("ecs-v6-response-bits-110"), - String::from("ecs-v6-response-bits-111"), - String::from("ecs-v6-response-bits-112"), - String::from("ecs-v6-response-bits-113"), - String::from("ecs-v6-response-bits-114"), - String::from("ecs-v6-response-bits-115"), - String::from("ecs-v6-response-bits-116"), - String::from("ecs-v6-response-bits-117"), - String::from("ecs-v6-response-bits-118"), - String::from("ecs-v6-response-bits-119"), - String::from("ecs-v6-response-bits-120"), - String::from("ecs-v6-response-bits-121"), - String::from("ecs-v6-response-bits-122"), - String::from("ecs-v6-response-bits-123"), - String::from("ecs-v6-response-bits-124"), - String::from("ecs-v6-response-bits-125"), - String::from("ecs-v6-response-bits-126"), - String::from("ecs-v6-response-bits-127"), - String::from("ecs-v6-response-bits-128"), - String::from("cumul-clientanswers"), - String::from("cumul-authanswers"), - String::from("policy-hits"), - String::from("proxy-mapping-total"), - String::from("remote-logger-count"), - ] -} -fn default_value_equal_recursor_stats_rec_control_disabled_list(value: &Vec) -> bool { - let def = default_value_recursor_stats_rec_control_disabled_list(); - &def == value -} - -// DEFAULT HANDLING for recursor_stats_snmp_disabled_list -fn default_value_recursor_stats_snmp_disabled_list() -> Vec { - vec![ - String::from("cache-bytes"), - String::from("packetcache-bytes"), - String::from("special-memory-usage"), - String::from("ecs-v4-response-bits-1"), - String::from("ecs-v4-response-bits-2"), - String::from("ecs-v4-response-bits-3"), - String::from("ecs-v4-response-bits-4"), - String::from("ecs-v4-response-bits-5"), - String::from("ecs-v4-response-bits-6"), - String::from("ecs-v4-response-bits-7"), - String::from("ecs-v4-response-bits-8"), - String::from("ecs-v4-response-bits-9"), - String::from("ecs-v4-response-bits-10"), - String::from("ecs-v4-response-bits-11"), - String::from("ecs-v4-response-bits-12"), - String::from("ecs-v4-response-bits-13"), - String::from("ecs-v4-response-bits-14"), - String::from("ecs-v4-response-bits-15"), - String::from("ecs-v4-response-bits-16"), - String::from("ecs-v4-response-bits-17"), - String::from("ecs-v4-response-bits-18"), - String::from("ecs-v4-response-bits-19"), - String::from("ecs-v4-response-bits-20"), - String::from("ecs-v4-response-bits-21"), - String::from("ecs-v4-response-bits-22"), - String::from("ecs-v4-response-bits-23"), - String::from("ecs-v4-response-bits-24"), - String::from("ecs-v4-response-bits-25"), - String::from("ecs-v4-response-bits-26"), - String::from("ecs-v4-response-bits-27"), - String::from("ecs-v4-response-bits-28"), - String::from("ecs-v4-response-bits-29"), - String::from("ecs-v4-response-bits-30"), - String::from("ecs-v4-response-bits-31"), - String::from("ecs-v4-response-bits-32"), - String::from("ecs-v6-response-bits-1"), - String::from("ecs-v6-response-bits-2"), - String::from("ecs-v6-response-bits-3"), - String::from("ecs-v6-response-bits-4"), - String::from("ecs-v6-response-bits-5"), - String::from("ecs-v6-response-bits-6"), - String::from("ecs-v6-response-bits-7"), - String::from("ecs-v6-response-bits-8"), - String::from("ecs-v6-response-bits-9"), - String::from("ecs-v6-response-bits-10"), - String::from("ecs-v6-response-bits-11"), - String::from("ecs-v6-response-bits-12"), - String::from("ecs-v6-response-bits-13"), - String::from("ecs-v6-response-bits-14"), - String::from("ecs-v6-response-bits-15"), - String::from("ecs-v6-response-bits-16"), - String::from("ecs-v6-response-bits-17"), - String::from("ecs-v6-response-bits-18"), - String::from("ecs-v6-response-bits-19"), - String::from("ecs-v6-response-bits-20"), - String::from("ecs-v6-response-bits-21"), - String::from("ecs-v6-response-bits-22"), - String::from("ecs-v6-response-bits-23"), - String::from("ecs-v6-response-bits-24"), - String::from("ecs-v6-response-bits-25"), - String::from("ecs-v6-response-bits-26"), - String::from("ecs-v6-response-bits-27"), - String::from("ecs-v6-response-bits-28"), - String::from("ecs-v6-response-bits-29"), - String::from("ecs-v6-response-bits-30"), - String::from("ecs-v6-response-bits-31"), - String::from("ecs-v6-response-bits-32"), - String::from("ecs-v6-response-bits-33"), - String::from("ecs-v6-response-bits-34"), - String::from("ecs-v6-response-bits-35"), - String::from("ecs-v6-response-bits-36"), - String::from("ecs-v6-response-bits-37"), - String::from("ecs-v6-response-bits-38"), - String::from("ecs-v6-response-bits-39"), - String::from("ecs-v6-response-bits-40"), - String::from("ecs-v6-response-bits-41"), - String::from("ecs-v6-response-bits-42"), - String::from("ecs-v6-response-bits-43"), - String::from("ecs-v6-response-bits-44"), - String::from("ecs-v6-response-bits-45"), - String::from("ecs-v6-response-bits-46"), - String::from("ecs-v6-response-bits-47"), - String::from("ecs-v6-response-bits-48"), - String::from("ecs-v6-response-bits-49"), - String::from("ecs-v6-response-bits-50"), - String::from("ecs-v6-response-bits-51"), - String::from("ecs-v6-response-bits-52"), - String::from("ecs-v6-response-bits-53"), - String::from("ecs-v6-response-bits-54"), - String::from("ecs-v6-response-bits-55"), - String::from("ecs-v6-response-bits-56"), - String::from("ecs-v6-response-bits-57"), - String::from("ecs-v6-response-bits-58"), - String::from("ecs-v6-response-bits-59"), - String::from("ecs-v6-response-bits-60"), - String::from("ecs-v6-response-bits-61"), - String::from("ecs-v6-response-bits-62"), - String::from("ecs-v6-response-bits-63"), - String::from("ecs-v6-response-bits-64"), - String::from("ecs-v6-response-bits-65"), - String::from("ecs-v6-response-bits-66"), - String::from("ecs-v6-response-bits-67"), - String::from("ecs-v6-response-bits-68"), - String::from("ecs-v6-response-bits-69"), - String::from("ecs-v6-response-bits-70"), - String::from("ecs-v6-response-bits-71"), - String::from("ecs-v6-response-bits-72"), - String::from("ecs-v6-response-bits-73"), - String::from("ecs-v6-response-bits-74"), - String::from("ecs-v6-response-bits-75"), - String::from("ecs-v6-response-bits-76"), - String::from("ecs-v6-response-bits-77"), - String::from("ecs-v6-response-bits-78"), - String::from("ecs-v6-response-bits-79"), - String::from("ecs-v6-response-bits-80"), - String::from("ecs-v6-response-bits-81"), - String::from("ecs-v6-response-bits-82"), - String::from("ecs-v6-response-bits-83"), - String::from("ecs-v6-response-bits-84"), - String::from("ecs-v6-response-bits-85"), - String::from("ecs-v6-response-bits-86"), - String::from("ecs-v6-response-bits-87"), - String::from("ecs-v6-response-bits-88"), - String::from("ecs-v6-response-bits-89"), - String::from("ecs-v6-response-bits-90"), - String::from("ecs-v6-response-bits-91"), - String::from("ecs-v6-response-bits-92"), - String::from("ecs-v6-response-bits-93"), - String::from("ecs-v6-response-bits-94"), - String::from("ecs-v6-response-bits-95"), - String::from("ecs-v6-response-bits-96"), - String::from("ecs-v6-response-bits-97"), - String::from("ecs-v6-response-bits-98"), - String::from("ecs-v6-response-bits-99"), - String::from("ecs-v6-response-bits-100"), - String::from("ecs-v6-response-bits-101"), - String::from("ecs-v6-response-bits-102"), - String::from("ecs-v6-response-bits-103"), - String::from("ecs-v6-response-bits-104"), - String::from("ecs-v6-response-bits-105"), - String::from("ecs-v6-response-bits-106"), - String::from("ecs-v6-response-bits-107"), - String::from("ecs-v6-response-bits-108"), - String::from("ecs-v6-response-bits-109"), - String::from("ecs-v6-response-bits-110"), - String::from("ecs-v6-response-bits-111"), - String::from("ecs-v6-response-bits-112"), - String::from("ecs-v6-response-bits-113"), - String::from("ecs-v6-response-bits-114"), - String::from("ecs-v6-response-bits-115"), - String::from("ecs-v6-response-bits-116"), - String::from("ecs-v6-response-bits-117"), - String::from("ecs-v6-response-bits-118"), - String::from("ecs-v6-response-bits-119"), - String::from("ecs-v6-response-bits-120"), - String::from("ecs-v6-response-bits-121"), - String::from("ecs-v6-response-bits-122"), - String::from("ecs-v6-response-bits-123"), - String::from("ecs-v6-response-bits-124"), - String::from("ecs-v6-response-bits-125"), - String::from("ecs-v6-response-bits-126"), - String::from("ecs-v6-response-bits-127"), - String::from("ecs-v6-response-bits-128"), - String::from("cumul-clientanswers"), - String::from("cumul-authanswers"), - String::from("policy-hits"), - String::from("proxy-mapping-total"), - String::from("remote-logger-count"), - ] -} -fn default_value_equal_recursor_stats_snmp_disabled_list(value: &Vec) -> bool { - let def = default_value_recursor_stats_snmp_disabled_list(); - &def == value -} - -// DEFAULT HANDLING for recursor_version_string -fn default_value_recursor_version_string() -> String { - String::from("*runtime determined*") -} -fn default_value_equal_recursor_version_string(value: &str)-> bool { - value == default_value_recursor_version_string() -} - -// DEFAULT HANDLING for recursor_sortlists -fn default_value_recursor_sortlists() -> Vec { - let msg = "default value defined for `recursor_sortlists' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_sortlists(value: &Vec)-> bool { - let def = default_value_recursor_sortlists(); - &def == value -} - -// DEFAULT HANDLING for recursor_rpzs -fn default_value_recursor_rpzs() -> Vec { - let msg = "default value defined for `recursor_rpzs' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_rpzs(value: &Vec)-> bool { - let def = default_value_recursor_rpzs(); - &def == value -} - -// DEFAULT HANDLING for recursor_allowed_additional_qtypes -fn default_value_recursor_allowed_additional_qtypes() -> Vec { - let msg = "default value defined for `recursor_allowed_additional_qtypes' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_allowed_additional_qtypes(value: &Vec)-> bool { - let def = default_value_recursor_allowed_additional_qtypes(); - &def == value -} - -// DEFAULT HANDLING for recursor_forwarding_catalog_zones -fn default_value_recursor_forwarding_catalog_zones() -> Vec { - let msg = "default value defined for `recursor_forwarding_catalog_zones' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recursor_forwarding_catalog_zones(value: &Vec)-> bool { - let def = default_value_recursor_forwarding_catalog_zones(); - &def == value -} - -// DEFAULT HANDLING for webservice_address -fn default_value_webservice_address() -> String { - String::from("127.0.0.1") -} -fn default_value_equal_webservice_address(value: &str)-> bool { - value == default_value_webservice_address() -} - -// DEFAULT HANDLING for webservice_allow_from -fn default_value_webservice_allow_from() -> Vec { - vec![ - String::from("127.0.0.1"), - String::from("::1"), - ] -} -fn default_value_equal_webservice_allow_from(value: &Vec) -> bool { - let def = default_value_webservice_allow_from(); - &def == value -} - -// DEFAULT HANDLING for webservice_loglevel -fn default_value_webservice_loglevel() -> String { - String::from("normal") -} -fn default_value_equal_webservice_loglevel(value: &str)-> bool { - value == default_value_webservice_loglevel() -} - -// DEFAULT HANDLING for carbon_ns -fn default_value_carbon_ns() -> String { - String::from("pdns") -} -fn default_value_equal_carbon_ns(value: &str)-> bool { - value == default_value_carbon_ns() -} - -// DEFAULT HANDLING for carbon_instance -fn default_value_carbon_instance() -> String { - String::from("recursor") -} -fn default_value_equal_carbon_instance(value: &str)-> bool { - value == default_value_carbon_instance() -} - -// DEFAULT HANDLING for carbon_server -fn default_value_carbon_server() -> Vec { - vec![ - ] -} -fn default_value_equal_carbon_server(value: &Vec) -> bool { - let def = default_value_carbon_server(); - &def == value -} - -// DEFAULT HANDLING for outgoing_dont_throttle_names -fn default_value_outgoing_dont_throttle_names() -> Vec { - vec![ - ] -} -fn default_value_equal_outgoing_dont_throttle_names(value: &Vec) -> bool { - let def = default_value_outgoing_dont_throttle_names(); - &def == value -} - -// DEFAULT HANDLING for outgoing_dont_throttle_netmasks -fn default_value_outgoing_dont_throttle_netmasks() -> Vec { - vec![ - ] -} -fn default_value_equal_outgoing_dont_throttle_netmasks(value: &Vec) -> bool { - let def = default_value_outgoing_dont_throttle_netmasks(); - &def == value -} - -// DEFAULT HANDLING for outgoing_dot_to_auth_names -fn default_value_outgoing_dot_to_auth_names() -> Vec { - vec![ - ] -} -fn default_value_equal_outgoing_dot_to_auth_names(value: &Vec) -> bool { - let def = default_value_outgoing_dot_to_auth_names(); - &def == value -} - -// DEFAULT HANDLING for outgoing_dont_query -fn default_value_outgoing_dont_query() -> Vec { - vec![ - String::from("127.0.0.0/8"), - String::from("10.0.0.0/8"), - String::from("100.64.0.0/10"), - String::from("169.254.0.0/16"), - String::from("192.168.0.0/16"), - String::from("172.16.0.0/12"), - String::from("::1/128"), - String::from("fc00::/7"), - String::from("fe80::/10"), - String::from("0.0.0.0/8"), - String::from("192.0.0.0/24"), - String::from("192.0.2.0/24"), - String::from("198.51.100.0/24"), - String::from("203.0.113.0/24"), - String::from("240.0.0.0/4"), - String::from("::/96"), - String::from("::ffff:0:0/96"), - String::from("100::/64"), - String::from("2001:db8::/32"), - ] -} -fn default_value_equal_outgoing_dont_query(value: &Vec) -> bool { - let def = default_value_outgoing_dont_query(); - &def == value -} - -// DEFAULT HANDLING for outgoing_edns_subnet_allow_list -fn default_value_outgoing_edns_subnet_allow_list() -> Vec { - vec![ - ] -} -fn default_value_equal_outgoing_edns_subnet_allow_list(value: &Vec) -> bool { - let def = default_value_outgoing_edns_subnet_allow_list(); - &def == value -} - -// DEFAULT HANDLING for outgoing_source_address -fn default_value_outgoing_source_address() -> Vec { - vec![ - String::from("0.0.0.0"), - ] -} -fn default_value_equal_outgoing_source_address(value: &Vec) -> bool { - let def = default_value_outgoing_source_address(); - &def == value -} - -// DEFAULT HANDLING for outgoing_udp_source_port_avoid -fn default_value_outgoing_udp_source_port_avoid() -> Vec { - vec![ - String::from("4791"), - String::from("11211"), - ] -} -fn default_value_equal_outgoing_udp_source_port_avoid(value: &Vec) -> bool { - let def = default_value_outgoing_udp_source_port_avoid(); - &def == value -} - -// DEFAULT HANDLING for logging_structured_logging_backend -fn default_value_logging_structured_logging_backend() -> String { - String::from("default") -} -fn default_value_equal_logging_structured_logging_backend(value: &str)-> bool { - value == default_value_logging_structured_logging_backend() -} - -// DEFAULT HANDLING for logging_trace -fn default_value_logging_trace() -> String { - String::from("no") -} -fn default_value_equal_logging_trace(value: &str)-> bool { - value == default_value_logging_trace() -} - -// DEFAULT HANDLING for logging_protobuf_servers -fn default_value_logging_protobuf_servers() -> Vec { - let msg = "default value defined for `logging_protobuf_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_logging_protobuf_servers(value: &Vec)-> bool { - let def = default_value_logging_protobuf_servers(); - &def == value -} - -// DEFAULT HANDLING for logging_outgoing_protobuf_servers -fn default_value_logging_outgoing_protobuf_servers() -> Vec { - let msg = "default value defined for `logging_outgoing_protobuf_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_logging_outgoing_protobuf_servers(value: &Vec)-> bool { - let def = default_value_logging_outgoing_protobuf_servers(); - &def == value -} - -// DEFAULT HANDLING for logging_dnstap_framestream_servers -fn default_value_logging_dnstap_framestream_servers() -> Vec { - let msg = "default value defined for `logging_dnstap_framestream_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_logging_dnstap_framestream_servers(value: &Vec)-> bool { - let def = default_value_logging_dnstap_framestream_servers(); - &def == value -} - -// DEFAULT HANDLING for logging_dnstap_nod_framestream_servers -fn default_value_logging_dnstap_nod_framestream_servers() -> Vec { - let msg = "default value defined for `logging_dnstap_nod_framestream_servers' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_logging_dnstap_nod_framestream_servers(value: &Vec)-> bool { - let def = default_value_logging_dnstap_nod_framestream_servers(); - &def == value -} - -// DEFAULT HANDLING for ecs_add_for -fn default_value_ecs_add_for() -> Vec { - vec![ - String::from("0.0.0.0/0"), - String::from("::/0"), - String::from("!127.0.0.0/8"), - String::from("!10.0.0.0/8"), - String::from("!100.64.0.0/10"), - String::from("!169.254.0.0/16"), - String::from("!192.168.0.0/16"), - String::from("!172.16.0.0/12"), - String::from("!::1/128"), - String::from("!fc00::/7"), - String::from("!fe80::/10"), - ] -} -fn default_value_equal_ecs_add_for(value: &Vec) -> bool { - let def = default_value_ecs_add_for(); - &def == value -} - -// DEFAULT HANDLING for recordcache_zonetocaches -fn default_value_recordcache_zonetocaches() -> Vec { - let msg = "default value defined for `recordcache_zonetocaches' should be valid YAML"; let deserialized: Vec = serde_yaml::from_str("").expect(msg); - deserialized -} -fn default_value_equal_recordcache_zonetocaches(value: &Vec)-> bool { - let def = default_value_recordcache_zonetocaches(); - &def == value -} - -// DEFAULT HANDLING for nod_history_dir -fn default_value_nod_history_dir() -> String { - String::from(env!("NODCACHEDIRNOD")) -} -fn default_value_equal_nod_history_dir(value: &str)-> bool { - value == default_value_nod_history_dir() -} - -// DEFAULT HANDLING for nod_ignore_list -fn default_value_nod_ignore_list() -> Vec { - vec![ - ] -} -fn default_value_equal_nod_ignore_list(value: &Vec) -> bool { - let def = default_value_nod_ignore_list(); - &def == value -} - -// DEFAULT HANDLING for nod_pb_tag -fn default_value_nod_pb_tag() -> String { - String::from("pdns-nod") -} -fn default_value_equal_nod_pb_tag(value: &str)-> bool { - value == default_value_nod_pb_tag() -} - -// DEFAULT HANDLING for nod_unique_response_history_dir -fn default_value_nod_unique_response_history_dir() -> String { - String::from(env!("NODCACHEDIRUDR")) -} -fn default_value_equal_nod_unique_response_history_dir(value: &str)-> bool { - value == default_value_nod_unique_response_history_dir() -} - -// DEFAULT HANDLING for nod_unique_response_pb_tag -fn default_value_nod_unique_response_pb_tag() -> String { - String::from("pdns-udr") -} -fn default_value_equal_nod_unique_response_pb_tag(value: &str)-> bool { - value == default_value_nod_unique_response_pb_tag() -} - -// DEFAULT HANDLING for nod_unique_response_ignore_list -fn default_value_nod_unique_response_ignore_list() -> Vec { - vec![ - ] -} -fn default_value_equal_nod_unique_response_ignore_list(value: &Vec) -> bool { - let def = default_value_nod_unique_response_ignore_list(); - &def == value -} - diff -Nru pdns-recursor-5.2.13/settings/rust-bridge-in.rs pdns-recursor-5.4.9/settings/rust-bridge-in.rs --- pdns-recursor-5.2.13/settings/rust-bridge-in.rs 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust-bridge-in.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,398 +0,0 @@ -// This file (rust-bridge-in.rs) is included into lib.rs inside the bridge module -/* - * Implement non-generated structs that need to be handled by Serde and CXX - */ - -// A single forward zone -#[derive(Deserialize, Serialize, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ForwardZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - forwarders: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - recurse: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, -} - -// A single auth zone -#[derive(Deserialize, Serialize, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct AuthZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - file: String, -} - -// A single trust anchor -#[derive(Deserialize, Serialize, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct TrustAnchor { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - dsrecords: Vec, -} - -// A single negative trust anchor -#[derive(Deserialize, Serialize, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct NegativeTrustAnchor { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - reason: String, -} - -// A protobuf logging server -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ProtobufServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")] - timeout: u64, - #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")] - maxQueuedEntries: u64, - #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")] - reconnectWaitTime: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - taggedOnly: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - asyncConnect: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logQueries: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logResponses: bool, - #[serde(default = "crate::def_pb_export_qtypes", skip_serializing_if = "crate::default_value_equal_pb_export_qtypes")] - exportTypes: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - logMappedFrom: bool, -} - -// A dnstap logging server -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct DNSTapFrameStreamServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logQueries: bool, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logResponses: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - bufferHint: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - flushTimeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - inputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - outputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - queueNotifyThreshold: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - reopenInterval: u64, -} - -// A dnstap logging NOD server -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct DNSTapNODFrameStreamServer { - #[serde(default, skip_serializing_if = "crate::is_default")] - servers: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - logNODs: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - logUDRs: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - bufferHint: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - flushTimeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - inputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - outputQueueSize: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - queueNotifyThreshold: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - reopenInterval: u64, -} - -#[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct TSIGTriplet { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - algo: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - secret: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct RPZ { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - addresses: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - defcontent: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - defpol: String, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - defpolOverrideLocalData: bool, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - defttl: u32, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - extendedErrorCode: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - extendedErrorExtra: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - includeSOA: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - ignoreDuplicates: bool, - #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")] - maxTTL: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - policyName: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - tags: Vec, - #[serde(default = "crate::Bool::::value", skip_serializing_if = "crate::if_true")] - overridesGettag: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - zoneSizeHint: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default, skip_serializing_if = "crate::is_default")] - refresh: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal")] - axfrTimeout: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - dumpFile: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - seedFile: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ZoneToCache { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - method: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - sources: Vec, - #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")] - timeout: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")] - refreshPeriod: u64, - #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")] - retryOnErrorPeriod: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u64, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] - zonemd: String, - #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")] - dnssec: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct SubnetOrder { - #[serde(default, skip_serializing_if = "crate::is_default")] - subnet: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - order: u32, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct SortList { - #[serde(default, skip_serializing_if = "crate::is_default")] - key: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - subnets: Vec, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct AllowedAdditionalQType { - #[serde(default, skip_serializing_if = "crate::is_default")] - qtype: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - targets: Vec, - #[serde(default = "crate::def_additional_mode", skip_serializing_if = "crate::default_value_equals_additional_mode")] - mode: String, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ProxyMapping { - #[serde(default, skip_serializing_if = "crate::is_default")] - subnet: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - address: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - domains: Vec, -} - -// A struct holding both a vector of forward zones and a vector of auth zones, used by REST API code -#[derive(Deserialize, Serialize, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ApiZones { - #[serde(default, skip_serializing_if = "crate::is_default")] - auth_zones: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - forward_zones: Vec, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct XFR { - #[serde(default, skip_serializing_if = "crate::is_default")] - addresses: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - zoneSizeHint: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - tsig: TSIGTriplet, - #[serde(default, skip_serializing_if = "crate::is_default")] - refresh: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - maxReceivedMBytes: u32, - #[serde(default, skip_serializing_if = "crate::is_default")] - localAddress: String, - #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal")] - axfrTimeout: u32, -} - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct FCZDefault { - #[serde(default, skip_serializing_if = "crate::is_default")] - name: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - forwarders: Vec, - #[serde(default, skip_serializing_if = "crate::is_default")] - recurse: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, - } - -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct ForwardingCatalogZone { - #[serde(default, skip_serializing_if = "crate::is_default")] - zone: String, - #[serde(default, skip_serializing_if = "crate::is_default")] - notify_allowed: bool, - #[serde(default, skip_serializing_if = "crate::is_default")] - xfr: XFR, - #[serde(default, skip_serializing_if = "crate::is_default")] - groups: Vec, -} - -// Two structs used to generated YAML based on a vector of name to value mappings -// Cannot use Enum as CXX has only very basic Enum support -struct Value { - bool_val: bool, - u64_val: u64, - f64_val: f64, - string_val: String, - vec_string_val: Vec, - vec_forwardzone_val: Vec, - vec_authzone_val: Vec, - vec_trustanchor_val: Vec, - vec_negativetrustanchor_val: Vec, - vec_protobufserver_val: Vec, - vec_dnstap_framestream_server_val: Vec, - vec_dnstap_nod_framestream_server_val: Vec, - vec_rpz_val: Vec, - vec_sortlist_val: Vec, - vec_zonetocache_val: Vec, - vec_allowedadditionalqtype_val: Vec, - vec_proxymapping_val: Vec, - vec_forwardingcatalogzone_val: Vec, -} - -struct OldStyle { - section: String, - name: String, - old_name: String, - type_name: String, - value: Value, - overriding: bool, -} - -/* - * Functions callable from C++ - */ -extern "Rust" { - // Parse a string representing YAML text and produce the corresponding data structure known to Serde - // The settings that can be stored in individual files get their own parse function - // Main recursor settings - fn parse_yaml_string(str: &str) -> Result; - // Allow from sequence - fn parse_yaml_string_to_allow_from(str: &str) -> Result>; - // Forward zones sequence - fn parse_yaml_string_to_forward_zones(str: &str) -> Result>; - // Allow notify for sequence - fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result>; - // REST API zones - fn parse_yaml_string_to_api_zones(str: &str) -> Result; - - // Prdoduce a YAML formatted string given a data structure known to Serde - fn to_yaml_string(self: &Recursorsettings) -> Result; - // When doing a conversion of old-style to YAML style we use a vector of OldStyle structs - fn map_to_yaml_string(map: &Vec) -> Result; - fn forward_zones_to_yaml_string(vec: &Vec) -> Result; - fn allow_from_to_yaml_string(vec: &Vec) -> Result; - fn allow_from_to_yaml_string_incoming(key: &String, filekey: &String, vec: &Vec) -> Result; - fn allow_for_to_yaml_string(vec: &Vec) -> Result; - - // Merge a string representing YAML settings into a existing setttings struct - fn merge(lhs: &mut Recursorsettings, rhs: &str) -> Result<()>; - - // Validate the sections inside the main settings struct, sections themselves will validate their fields - fn validate(self: &Recursorsettings) -> Result<()>; - // The validate function below are "hand-crafted" as their structs are not generated - fn validate(self: &AuthZone, field: &str) -> Result<()>; - fn validate(self: &ForwardZone, field: &str) -> Result<()>; - fn validate(self: &TrustAnchor, field: &str) -> Result<()>; - fn validate(self: &NegativeTrustAnchor, field: &str) -> Result<()>; - fn validate(self: &ApiZones, field: &str) -> Result<()>; - - // Helper functions to call the proper validate function on vectors of various kinds - fn validate_auth_zones(field: &str, vec: &Vec) -> Result<()>; - fn validate_forward_zones(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_for(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_notify_for(field: &str, vec: &Vec) -> Result<()>; - fn validate_allow_from(field: &str, vec: &Vec) -> Result<()>; - - // The functions to maintain REST API managed zones - fn api_read_zones(path: &str) -> Result>; - fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>; - fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>; - fn api_add_forward_zones(file: &str, forwardzones: &mut Vec) -> Result<()>; - fn validate_trustanchors(field: &str, vec: &Vec) -> Result<()>; - fn validate_negativetrustanchors(field: &str, vec: &Vec) -> Result<()>; - fn api_delete_zone(file: &str, zone: &str) -> Result<()>; - fn api_delete_zones(file: &str) -> Result<()>; -} - -unsafe extern "C++" { - include!("bridge.hh"); - fn qTypeStringToCode(name: &str) -> u16; - fn isValidHostname(name: &str) -> bool; -} diff -Nru pdns-recursor-5.2.13/settings/rust-preamble-in.rs pdns-recursor-5.4.9/settings/rust-preamble-in.rs --- pdns-recursor-5.2.13/settings/rust-preamble-in.rs 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/rust-preamble-in.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +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. - */ - -// This file (rust-preamble-in.rs) is included at the start of lib.rs - -use serde::{Deserialize, Serialize}; - -mod helpers; -use helpers::*; - -mod bridge; -use bridge::*; - -// Suppresses "Deserialize unused" warning -#[derive(Deserialize, Serialize)] -struct UnusedStruct {} - -trait Validate { - fn validate(&self) -> Result<(), ValidationError>; -} - -#[derive(Debug)] -pub struct ValidationError { - msg: String, -} - -trait Merge { - fn merge(&mut self, rhs: &mut Self, map: Option<&serde_yaml::Mapping>); -} diff -Nru pdns-recursor-5.2.13/settings/table.py pdns-recursor-5.4.9/settings/table.py --- pdns-recursor-5.2.13/settings/table.py 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/settings/table.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,3636 +0,0 @@ -# This file contains the table used to generate old and new-style settings code -# -# Example: -# { -# 'name' : 'allow_from', -# 'section' : 'incoming', -# 'oldname' : 'allow-from' -# 'type' : LType.ListSubnets, -# 'default' : '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', -# 'help' : 'If set, only allow these comma separated netmasks to recurse', -# 'doc' : ''' -# ''' -# } -# -# See generate.py for a description of the fields. -# -# Sections -# - incoming -# - outgoing -# - packetcache -# - recursor -# - recordcache -# - dnssec -# - webservice -# - carbon -# - ecs -# - logging -# - nod -# - snmp - -[ - { - 'name' : 'aggressive_nsec_cache_size', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '100000', - 'help' : 'The number of records to cache in the aggressive cache. If set to a value greater than 0, and DNSSEC processing or validation is enabled, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in rfc8198', - 'doc' : ''' -The number of records to cache in the aggressive cache. If set to a value greater than 0, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in :rfc:`8198`. -To use this, DNSSEC processing or validation must be enabled by setting :ref:`setting-dnssec` to ``process``, ``log-fail`` or ``validate``. - ''', - 'versionadded': '4.5.0', - 'runtime': 'set-max-aggr-nsec-cache-size', - }, - { - 'name' : 'aggressive_cache_min_nsec3_hit_ratio', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '2000', - 'help' : 'The minimum expected hit ratio to store NSEC3 records into the aggressive cache', - 'doc' : ''' -The limit for which to put NSEC3 records into the aggressive cache. -A value of ``n`` means that an NSEC3 record is only put into the aggressive cache if the estimated probability of a random name hitting the NSEC3 record is higher than ``1/n``. -A higher ``n`` will cause more records to be put into the aggressive cache, e.g. a value of 4000 will cause records to be put in the aggressive cache even if the estimated probability of hitting them is twice as low as would be the case for ``n=2000``. -A value of 0 means no NSEC3 records will be put into the aggressive cache. - -For large zones the effectiveness of the NSEC3 cache is reduced since each NSEC3 record only covers a randomly distributed subset of all possible names. -This setting avoids doing unnecessary work for such large zones. - ''', - 'versionadded' : '4.9.0', - }, - { - 'name' : 'allow_from', - 'section' : 'incoming', - 'type' : LType.ListSubnets, - 'default' : '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', - 'help' : 'If set, only allow these comma separated netmasks to recurse', - 'doc' : ''' -Netmasks (both IPv4 and IPv6) that are allowed to use the server. -The default allows access only from :rfc:`1918` private IP addresses. -An empty value means no checking is done, all clients are allowed. -Due to the aggressive nature of the internet these days, it is highly recommended to not open up the recursor for the entire internet. -Questions from IP addresses not listed here are ignored and do not get an answer. - -When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the recursor will check the address of the client IP advertised in the Proxy Protocol header instead of the one of the proxy. - -Note that specifying an IP address without a netmask uses an implicit netmask of /32 or /128. - ''', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_from_file', - 'section' : 'incoming', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, load allowed netmasks from this file', - 'doc' : ''' -Like :ref:`setting-allow-from`, except reading from file. -Overrides the :ref:`setting-allow-from` setting. To use this feature, supply one netmask per line, with optional comments preceded by a '#'. - ''', - 'doc-new' : ''' -Like :ref:`setting-allow-from`, except reading a sequence of `Subnet`_ from file. -Overrides the :ref:`setting-allow-from` setting. Example content of th specified file: - -.. code-block:: yaml - - - 127.0.01 - - ::1 - - ''', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_notify_for', - 'section' : 'incoming', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'If set, NOTIFY requests for these zones will be allowed', - 'doc' : ''' -Domain names specified in this list are used to permit incoming -NOTIFY operations to wipe any cache entries that match the domain -name. If this list is empty, all NOTIFY operations will be ignored. - ''', - 'versionadded': '4.6.0', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_notify_for_file', - 'section' : 'incoming', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, load NOTIFY-allowed zones from this file', - 'doc' : ''' -Like :ref:`setting-allow-notify-for`, except reading from file. To use this -feature, supply one domain name per line, with optional comments -preceded by a '#'. - -NOTIFY-allowed zones can also be specified using :ref:`setting-forward-zones-file`. - ''', - 'doc-new' : ''' -Like :ref:`setting-allow-notify-for`, except reading a sequence of names from file. Example contents of specified file: - -.. code-block:: yaml - - - example.com - - example.org - - ''', - 'versionadded': '4.6.0', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_notify_from', - 'section' : 'incoming', - 'type' : LType.ListSubnets, - 'default' : '', - 'help' : 'If set, NOTIFY requests from these comma separated netmasks will be allowed', - 'doc' : ''' -Netmasks (both IPv4 and IPv6) that are allowed to issue NOTIFY operations -to the server. NOTIFY operations from IP addresses not listed here are -ignored and do not get an answer. - -When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the -recursor will check the address of the client IP advertised in the -Proxy Protocol header instead of the one of the proxy. - -Note that specifying an IP address without a netmask uses an implicit -netmask of /32 or /128. - -NOTIFY operations received from a client listed in one of these netmasks -will be accepted and used to wipe any cache entries whose zones match -the zone specified in the NOTIFY operation, but only if that zone (or -one of its parents) is included in :ref:`setting-allow-notify-for`, -:ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a '^' prefix. - ''', - 'doc-new' : ''' -Subnets (both IPv4 and IPv6) that are allowed to issue NOTIFY operations -to the server. NOTIFY operations from IP addresses not listed here are -ignored and do not get an answer. - -When the Proxy Protocol is enabled (see :ref:`setting-proxy-protocol-from`), the -recursor will check the address of the client IP advertised in the -Proxy Protocol header instead of the one of the proxy. - -Note that specifying an IP address without a netmask uses an implicit -netmask of /32 or /128. - -NOTIFY operations received from a client listed in one of these netmasks -will be accepted and used to initiate a freshness check for an RPZ zone or wipe any cache entries whose zones match -the zone specified in the NOTIFY operation, but only if that zone (or -one of its parents) is included in :ref:`setting-allow-notify-for`, -:ref:`setting-allow-notify-for-file`, or :ref:`setting-forward-zones-file` with a ``allow_notify`` set to ``true``. - ''', - 'versionadded': '4.6.0', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_notify_from_file', - 'section' : 'incoming', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, load NOTIFY-allowed netmasks from this file', - 'doc' : ''' -Like :ref:`setting-allow-notify-from`, except reading from file. To use this -feature, supply one netmask per line, with optional comments preceded -by a '#'. - ''', - 'doc-new' : ''' -Like :ref:`setting-allow-notify-from`, except reading a sequence of `Subnet`_ from file. - ''', - 'versionadded': '4.6.0', - 'runtime': ['reload-acls'], - }, - { - 'name' : 'allow_no_rd', - 'section' : 'incoming', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Allow \'no recursion desired (RD=0)\' queries.', - 'doc' : ''' -Allow ``no recursion desired (RD=0) queries`` to query cache contents. -If not set (the default), these queries are answered with rcode ``Refused``. - ''', - 'versionadded': '5.0.0' - }, - { - 'name' : 'any_to_tcp', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Answer ANY queries with tc=1, shunting to TCP', - 'doc' : ''' -Answer questions for the ANY type on UDP with a truncated packet that refers the remote server to TCP. -Useful for mitigating ANY reflection attacks. - ''', - }, - { - 'name' : 'allow_trust_anchor_query', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Allow queries for trustanchor.server CH TXT and negativetrustanchor.server CH TXT', - 'doc' : ''' -Allow ``trustanchor.server CH TXT`` and ``negativetrustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC ` (negative) trust anchors. - ''', - 'versionadded': '4.3.0' - }, - { - 'name' : 'api_dir', - 'section' : 'webservice', - 'oldname' : 'api-config-dir', - 'type' : LType.String, - 'default' : '', - 'help' : 'Directory where REST API stores config and zones', - 'doc' : ''' -Directory where the REST API stores its configuration and zones. -For configuration updates to work, :ref:`setting-include-dir` should have the same value when using old-style settings. -When using YAML settings :ref:`setting-yaml-recursor.include_dir` and :ref:`setting-yaml-webservice.api_dir` must have a different value. - ''', - 'versionadded': '4.0.0' - }, - { - 'name' : 'api_key', - 'section' : 'webservice', - 'type' : LType.String, - 'default' : '', - 'help' : 'Static pre-shared authentication key for access to the REST API', - 'doc' : ''' -Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password`` instead of being stored in the configuration in plaintext, but the plaintext version is still supported. - ''', - 'versionadded': '4.0.0', - 'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.') - }, - { - 'name' : 'auth_zones', - 'section' : 'recursor', - 'type' : LType.ListAuthZones, - 'default' : '', - 'help' : 'Zones for which we have authoritative data, comma separated domain=file pairs', - 'doc' : ''' -Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses). -DNSSEC is not supported. Example: - -.. code-block:: none - - auth-zones=example.org=/var/zones/example.org, powerdns.com=/var/zones/powerdns.com - ''', - 'doc-new' : ''' -Zones read from these files (in BIND format) are served authoritatively (but without the AA bit set in responses). -DNSSEC is not supported. Example: - -.. code-block:: yaml - - recursor: - auth-zones: - - zone: example.org - file: /var/zones/example.org - - zone: powerdns.com - file: /var/zones/powerdns.com - ''', - 'runtime': ['reload-zones'], - }, - { - 'name' : 'interval', - 'section' : 'carbon', - 'oldname' : 'carbon-interval', - 'type' : LType.Uint64, - 'default' : '30', - 'help' : 'Number of seconds between carbon (graphite) updates', - 'doc' : ''' -If sending carbon updates, this is the interval between them in seconds. -See :doc:`metrics`. - ''', - }, - { - 'name' : 'ns', - 'section' : 'carbon', - 'oldname' : 'carbon-namespace', - 'type' : LType.String, - 'default' : 'pdns', - 'help' : 'If set overwrites the first part of the carbon string', - 'doc' : ''' -Change the namespace or first string of the metric key. The default is pdns. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'ourname', - 'section' : 'carbon', - 'oldname' : 'carbon-ourname', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, overrides our reported hostname for carbon stats', - 'doc' : ''' -If sending carbon updates, if set, this will override our hostname. -Be careful not to include any dots in this setting, unless you know what you are doing. -See :ref:`metricscarbon`. - ''', - }, - { - 'name' : 'instance', - 'section' : 'carbon', - 'oldname' : 'carbon-instance', - 'type' : LType.String, - 'default' : 'recursor', - 'help' : 'If set overwrites the instance name default', - 'doc' : ''' -Change the instance or third string of the metric key. The default is recursor. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'server', - 'section' : 'carbon', - 'oldname' : 'carbon-server', - 'type' : LType.ListSocketAddresses, - 'default' : '', - 'help' : 'If set, send metrics in carbon (graphite) format to this server IP address', - 'doc' : ''' -If set to an IP or IPv6 address, will send all available metrics to this server via the carbon protocol, which is used by graphite and metronome. Moreover you can specify more than one server using a comma delimited list, ex: carbon-server=10.10.10.10,10.10.10.20. -You may specify an alternate port by appending :port, for example: ``127.0.0.1:2004``. -See :doc:`metrics`. - ''', - 'doc-new' : ''' -Will send all available metrics to these servers via the carbon protocol, which is used by graphite and metronome. -See :doc:`metrics`. - ''', - 'runtime': 'set-carbon-server', - }, - { - 'name' : 'chroot', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'switch to chroot jail', - 'doc' : ''' -If set, chroot to this directory for more security. -This is not recommended; instead, we recommend containing PowerDNS using operating system features. -We ship systemd unit files with our packages to make this easy. - -Make sure that ``/dev/log`` is available from within the chroot. -Logging will silently fail over time otherwise (on logrotate). - -When using ``chroot``, all other paths (except for :ref:`setting-config-dir`) set in the configuration are relative to the new root. - -When running on a system where systemd manages services, ``chroot`` does not work out of the box, as PowerDNS cannot use the ``NOTIFY_SOCKET``. -Either do not ``chroot`` on these systems or set the 'Type' of this service to 'simple' instead of 'notify' (refer to the systemd documentation on how to modify unit-files). - ''', - }, - { - 'name' : 'tcp_timeout', - 'section' : 'incoming', - 'oldname' : 'client-tcp-timeout', - 'type' : LType.Uint64, - 'default' : '2', - 'help' : 'Timeout in seconds when talking to TCP clients', - 'doc' : ''' -Time to wait for data from TCP clients. - ''', - }, - { - 'name' : 'config', - 'section' : 'commands', - 'type' : LType.Command, - 'default' : 'no', - 'help' : 'Output blank configuration. You can use --config=check to test the config file and command line arguments.', - 'doc' : ''' -EMPTY? ''' - }, - { - 'name' : 'config_dir', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : 'SYSCONFDIR', - 'docdefault': 'Determined by distribution', - 'help' : 'Location of configuration directory (recursor.conf or recursor.yml)', - 'doc' : ''' -Location of configuration directory (where ``recursor.conf`` or ``recursor.yml`` is stored). -Usually ``/etc/powerdns``, but this depends on ``SYSCONFDIR`` during compile-time. -Use default or set on command line. - ''', - }, - { - 'name' : 'config_name', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Name of this virtual configuration - will rename the binary image', - 'doc' : ''' -When running multiple recursors on the same server, read settings from :file:`recursor-{name}.conf`, this will also rename the binary image. - ''', - }, - { - 'name' : 'cpu_map', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs', - 'doc' : ''' -Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs. -This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N. -For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2:: - - cpu-map=0=0 1=1,2 - -The thread handling the control channel, the webserver and other internal stuff has been assigned id 0, the distributor -threads if any are assigned id 1 and counting, and the worker threads follow behind. -The number of distributor threads is determined by :ref:`setting-distributor-threads`, the number of worker threads is determined by the :ref:`setting-threads` setting. - -This parameter is only available if the OS provides the ``pthread_setaffinity_np()`` function. - -Note that depending on the configuration the Recursor can start more threads. -Typically these threads will sleep most of the time. -These threads cannot be specified in this setting as their thread-ids are left unspecified. - ''', - 'doc' : ''' -Set CPU affinity for threads, asking the scheduler to run those threads on a single CPU, or a set of CPUs. -This parameter accepts a space separated list of thread-id=cpu-id, or thread-id=cpu-id-1,cpu-id-2,...,cpu-id-N. -For example, to make the worker thread 0 run on CPU id 0 and the worker thread 1 on CPUs 1 and 2: - -.. code-block:: yaml - - recursor: - cpu_map: 0=0 1=1,2 - -The thread handling the control channel, the webserver and other internal stuff has been assigned id 0, the distributor -threads if any are assigned id 1 and counting, and the worker threads follow behind. -The number of distributor threads is determined by :ref:`setting-distributor-threads`, the number of worker threads is determined by the :ref:`setting-threads` setting. - -This parameter is only available if the OS provides the ``pthread_setaffinity_np()`` function. - -Note that depending on the configuration the Recursor can start more threads. -Typically these threads will sleep most of the time. -These threads cannot be specified in this setting as their thread-ids are left unspecified. - ''', - }, - { - 'name' : 'daemon', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Operate as a daemon', - 'doc' : ''' -Operate in the background. - ''', - 'versionchanged': ('4.0.0', 'Default is now ``no``, was ``yes`` before.') - }, - { - 'name' : 'dont_throttle_names', - 'section' : 'outgoing', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'Do not throttle nameservers with this name or suffix', - 'doc' : ''' -When an authoritative server does not answer a query or sends a reply the recursor does not like, it is throttled. -Any servers' name suffix-matching the supplied names will never be throttled. - -.. warning:: - Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-names`` could make this load on the upstream server even higher, resulting in further service degradation. - ''', - 'versionadded': '4.2.0', - 'runtime': ['add-dont-throttle-names', 'clear-dont-throttle-names'], - }, - { - 'name' : 'dont_throttle_netmasks', - 'section' : 'outgoing', - 'type' : LType.ListSubnets, - 'default' : '', - 'help' : 'Do not throttle nameservers with this IP netmask', - 'doc' : ''' -When an authoritative server does not answer a query or sends a reply the recursor does not like, it is throttled. -Any servers matching the supplied netmasks will never be throttled. - -This can come in handy on lossy networks when forwarding, where the same server is configured multiple times (e.g. with ``forward-zones-recurse=example.com=192.0.2.1;192.0.2.1``). -By default, the PowerDNS Recursor would throttle the 'first' server on a timeout and hence not retry the 'second' one. -In this case, ``dont-throttle-netmasks`` could be set to ``192.0.2.1``. - -.. warning:: - Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation. - ''', - 'doc-new' : ''' -When an authoritative server does not answer a query or sends a reply the recursor does not like, it is throttled. -Any servers matching the supplied netmasks will never be throttled. - -This can come in handy on lossy networks when forwarding, where the same server is configured multiple times (e.g. with ``forward_zones_recurse: [ {zone: example.com, forwarders: [ 192.0.2.1, 192.0.2.1 ] } ]``. -By default, the PowerDNS Recursor would throttle the 'first' server on a timeout and hence not retry the 'second' one. -In this case, :ref:`setting-dont-throttle-netmasks` could be set to include ``192.0.2.1``. - -.. warning:: - Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation. - ''', - 'versionadded': '4.2.0', - 'runtime': ['rec_control add-dont-throttle-netmasks', 'rec_control clear-dont-throttle-netmask'], - }, - { - 'name' : 'devonly_regression_test_mode', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'internal use only', - 'doc' : 'SKIP', - }, - { - 'name' : 'disable', - 'section' : 'packetcache', - 'oldname' : 'disable-packetcache', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Disable packetcache', - 'doc' : ''' -Turn off the packet cache. Useful when running with Lua scripts that modify answers in such a way they cannot be cached, though individual answer caching can be controlled from Lua as well. - ''', - }, - { - 'name' : 'disable_syslog', - 'section' : 'logging', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Disable logging to syslog, useful when running inside a supervisor that logs stderr', - 'doc' : ''' -Do not log to syslog, only to stderr. -Use this setting when running inside a supervisor that handles logging (like systemd). -**Note**: do not use this setting in combination with :ref:`setting-daemon` as all logging will disappear. - ''', - }, - { - 'name' : 'distribution_load_factor', - 'section' : 'incoming', - 'type' : LType.Double, - 'default' : '0.0', - 'help' : 'The load factor used when PowerDNS is distributing queries to worker threads', - 'doc' : ''' -If :ref:`setting-pdns-distributes-queries` is set and this setting is set to another value -than 0, the distributor thread will use a bounded load-balancing algorithm while -distributing queries to worker threads, making sure that no thread is assigned -more queries than distribution-load-factor times the average number of queries -currently processed by all the workers. -For example, with a value of 1.25, no server should get more than 125 % of the -average load. This helps making sure that all the workers have roughly the same -share of queries, even if the incoming traffic is very skewed, with a larger -number of requests asking for the same qname. - ''', - 'versionadded': '4.1.12' - }, - { - 'name' : 'distribution_pipe_buffer_size', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread', - 'doc' : ''' -Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread. -Requires support for `F_SETPIPE_SZ` which is present in Linux since 2.6.35. The actual size might be rounded up to -a multiple of a page size. 0 means that the OS default size is used. -A large buffer might allow the recursor to deal with very short-lived load spikes during which a worker thread gets -overloaded, but it will be at the cost of an increased latency. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'distributor_threads', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '0', - 'docdefault' : '1 if :ref:`setting-pdns-distributes-queries` is set, 0 otherwise', - 'help' : 'Launch this number of distributor threads, distributing queries to other threads', - 'doc' : ''' -If :ref:`setting-pdns-distributes-queries` is set, spawn this number of distributor threads on startup. Distributor threads -handle incoming queries and distribute them to other threads based on a hash of the query. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'dot_to_auth_names', - 'section' : 'outgoing', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'Use DoT to authoritative servers with these names or suffixes', - 'doc' : ''' -Force DoT to the listed authoritative nameservers. For this to work, DoT support has to be compiled in. -Currently, the certificate is not checked for validity in any way. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'dot_to_port_853', - 'section' : 'outgoing', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Force DoT connection to target port 853 if DoT compiled in', - 'doc' : ''' -Enable DoT to forwarders that specify port 853. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'dns64_prefix', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'DNS64 prefix', - 'doc' : ''' -Enable DNS64 (:rfc:`6147`) support using the supplied /96 IPv6 prefix. This will generate 'fake' ``AAAA`` records for names -with only ``A`` records, as well as 'fake' ``PTR`` records to make sure that reverse lookup of DNS64-generated IPv6 addresses -generate the right name. -See :doc:`dns64` for more flexible but slower alternatives using Lua. - ''', - 'versionadded': '4.4.0' - }, - { - 'name' : 'validation', - 'section' : 'dnssec', - 'oldname' : 'dnssec', - 'type' : LType.String, - 'default' : 'process', - 'help' : 'DNSSEC mode: off/process-no-validate/process (default)/log-fail/validate', - 'doc' : ''' -One of ``off``, ``process-no-validate``, ``process``, ``log-fail``, ``validate`` - -Set the mode for DNSSEC processing, as detailed in :doc:`dnssec`. - -``off`` - No DNSSEC processing whatsoever. - Ignore DO-bits in queries, don't request any DNSSEC information from authoritative servers. - This behaviour is similar to PowerDNS Recursor pre-4.0. -``process-no-validate`` - Respond with DNSSEC records to clients that ask for it, set the DO bit on all outgoing queries. - Don't do any validation. -``process`` - Respond with DNSSEC records to clients that ask for it, set the DO bit on all outgoing queries. - Do validation for clients that request it (by means of the AD- bit or DO-bit in the query). -``log-fail`` - Similar behaviour to ``process``, but validate RRSIGs on responses and log bogus responses. -``validate`` - Full blown DNSSEC validation. Send SERVFAIL to clients on bogus responses. - ''', - 'versionadded': '4.0.0', - 'versionchanged': ('4.5.0', - 'The default changed from ``process-no-validate`` to ``process``') - }, - { - 'name' : 'disabled_algorithms', - 'section' : 'dnssec', - 'oldname' : 'dnssec-disabled-algorithms', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'List of DNSSEC algorithm numbers that are considered unsupported', - 'doc' : ''' -A list of DNSSEC algorithm numbers that should be considered disabled. -These algorithms will not be used to validate DNSSEC signatures. -Zones (only) signed with these algorithms will be considered ``Insecure``. - -If this setting is empty (the default), :program:`Recursor` will determine which algorithms to disable automatically. -This is done for specific algorithms only, currently algorithms 5 (``RSASHA1``) and 7 (``RSASHA1NSEC3SHA1``). - -This is important on systems that have a default strict crypto policy, like RHEL9 derived systems. -On such systems not disabling some algorithms (or changing the security policy) will make affected zones to be considered ``Bogus`` as using these algorithms fails. - ''', - 'versionadded': '4.9.0' - }, - { - 'name' : 'log_bogus', - 'section' : 'dnssec', - 'oldname' : 'dnssec-log-bogus', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Log DNSSEC bogus validations', - 'doc' : ''' -Log every DNSSEC validation failure. -**Note**: This is not logged per-query but every time records are validated as Bogus. - ''', - 'runtime': 'set-dnssec-log-bogus', - }, - { - 'name' : 'dont_query', - 'section' : 'outgoing', - 'type' : LType.ListSubnets, - 'default' : '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, 0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32', - 'help' : 'If set, do not query these netmasks for DNS data', - 'doc' : ''' -The DNS is a public database, but sometimes contains delegations to private IP addresses, like for example 127.0.0.1. -This can have odd effects, depending on your network, and may even be a security risk. -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. 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. - ''', - }, - { - 'name' : 'add_for', - 'section' : 'ecs', - 'oldname' : 'ecs-add-for', - 'type' : LType.ListSubnets, - 'default' : '0.0.0.0/0, ::/0, !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', - 'help' : 'List of client netmasks for which EDNS Client Subnet will be added', - 'doc' : ''' -List of requestor netmasks for which the requestor IP Address should be used as the :rfc:`EDNS Client Subnet <7871>` for outgoing queries. Outgoing queries for requestors that do not match this list will use the :ref:`setting-ecs-scope-zero-address` instead. -Valid incoming ECS values from :ref:`setting-use-incoming-edns-subnet` are not replaced. - -Regardless of the value of this setting, ECS values are only sent for outgoing queries matching the conditions in the :ref:`setting-edns-subnet-allow-list` setting. This setting only controls the actual value being sent. - -This defaults to not using the requestor address inside RFC1918 and similar 'private' IP address spaces. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'ipv4_bits', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv4-bits', - 'type' : LType.Uint64, - 'default' : '24', - 'help' : 'Number of bits of IPv4 address to pass for EDNS Client Subnet', - 'doc' : ''' -Number of bits of client IPv4 address to pass when sending EDNS Client Subnet address information. - ''', - 'versionadded': '4.1.0', - }, - { - 'name' : 'ipv4_cache_bits', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv4-cache-bits', - 'type' : LType.Uint64, - 'default' : '24', - 'help' : 'Maximum number of bits of IPv4 mask to cache ECS response', - 'doc' : ''' -Maximum number of bits of client IPv4 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``. -That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. - ''', - 'versionadded': '4.1.12' - }, - { - 'name' : 'ipv6_bits', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv6-bits', - 'type' : LType.Uint64, - 'default' : '56', - 'help' : 'Number of bits of IPv6 address to pass for EDNS Client Subnet', - 'doc' : ''' -Number of bits of client IPv6 address to pass when sending EDNS Client Subnet address information. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'ipv6_cache_bits', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv6-cache-bits', - 'type' : LType.Uint64, - 'default' : '56', - 'help' : 'Maximum number of bits of IPv6 mask to cache ECS response', - 'doc' : ''' -Maximum number of bits of client IPv6 address used by the authoritative server (as indicated by the EDNS Client Subnet scope in the answer) for an answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-cache-limit-ttl``. -That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. - ''', - 'versionadded': '4.1.12' - }, - { - 'name' : 'ipv4_never_cache', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv4-never-cache', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If we should never cache IPv4 ECS responses', - 'doc' : ''' -When set, never cache replies carrying EDNS IPv4 Client Subnet scope in the record cache. -In this case the decision made by ``ecs-ipv4-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'ipv6_never_cache', - 'section' : 'ecs', - 'oldname' : 'ecs-ipv6-never-cache', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If we should never cache IPv6 ECS responses', - 'doc' : ''' -When set, never cache replies carrying EDNS IPv6 Client Subnet scope in the record cache. -In this case the decision made by ``ecs-ipv6-cache-bits`` and ``ecs-cache-limit-ttl`` is no longer relevant. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'minimum_ttl_override', - 'section' : 'ecs', - 'oldname' : 'ecs-minimum-ttl-override', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'The minimum TTL for records in ECS-specific answers', - 'doc' : ''' -This setting artificially raises the TTLs of records in the ANSWER section of ECS-specific answers to be at least this long. -Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot. -Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact -authoritative servers every time a client requests them. - ''', - 'versionchanged': ('4.5.0', 'Old versions used default 0.'), - 'runtime': 'set-ecs-minimum-ttl', - }, - { - 'name' : 'cache_limit_ttl', - 'section' : 'ecs', - 'oldname' : 'ecs-cache-limit-ttl', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Minimum TTL to cache ECS response', - 'doc' : ''' -The minimum TTL for an ECS-specific answer to be inserted into the record cache. This condition applies in conjunction with ``ecs-ipv4-cache-bits`` or ``ecs-ipv6-cache-bits``. -That is, only if both the limits apply, the record will not be cached. This decision can be overridden by ``ecs-ipv4-never-cache`` and ``ecs-ipv6-never-cache``. - ''', - 'versionadded': '4.1.12' - }, - { - 'name' : 'scope_zero_address', - 'section' : 'ecs', - 'oldname' : 'ecs-scope-zero-address', - 'type' : LType.String, - 'default' : '', - 'help' : 'Address to send to allow-listed authoritative servers for incoming queries with ECS prefix-length source of 0', - 'doc' : ''' -The IP address sent via EDNS Client Subnet to authoritative servers listed in -:ref:`setting-edns-subnet-allow-list` when :ref:`setting-use-incoming-edns-subnet` is set and the query has -an ECS source prefix-length set to 0. -The default is to look for the first usable (not an ``any`` one) address in -:ref:`setting-query-local-address` (starting with IPv4). If no suitable address is -found, the recursor fallbacks to sending 127.0.0.1. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'edns_bufsize', - 'section' : 'outgoing', - 'oldname' : 'edns-outgoing-bufsize', - 'type' : LType.Uint64, - 'default' : '1232', - 'help' : 'Outgoing EDNS buffer size', - 'doc' : ''' -.. note:: Why 1232? - - 1232 is the largest number of payload bytes that can fit in the smallest IPv6 packet. - IPv6 has a minimum MTU of 1280 bytes (:rfc:`RFC 8200, section 5 <8200#section-5>`), minus 40 bytes for the IPv6 header, minus 8 bytes for the UDP header gives 1232, the maximum payload size for the DNS response. - -This is the value set for the EDNS0 buffer size in outgoing packets. -Lower this if you experience timeouts. - ''', - 'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680') - }, - { - 'name' : 'edns_padding_from', - 'section' : 'incoming', - 'type' : LType.ListSubnets, - 'default' : '', - 'help' : 'List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that \'edns-padding-mode\' applies', - 'doc' : ''' -List of netmasks (proxy IP in case of proxy-protocol presence, client IP otherwise) for which EDNS padding will be enabled in responses, provided that :ref:`setting-edns-padding-mode` applies. - ''', - 'versionadded' : '4.5.0', - 'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence') - }, - { - 'name' : 'edns_padding_mode', - 'section' : 'incoming', - 'type' : LType.String, - 'default' : 'padded-queries-only', - 'help' : 'Whether to add EDNS padding to all responses (\'always\') or only to responses for queries containing the EDNS padding option (\'padded-queries-only\', the default). In both modes, padding will only be added to responses for queries coming from \'setting-edns-padding-from\' sources', - 'doc' : ''' -One of ``always``, ``padded-queries-only``. -Whether to add EDNS padding to all responses (``always``) or only to responses for queries containing the EDNS padding option (``padded-queries-only``, the default). -In both modes, padding will only be added to responses for queries coming from :ref:`setting-edns-padding-from` sources. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'edns_padding', - 'section' : 'outgoing', - 'oldname' : 'edns-padding-out', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Whether to add EDNS padding to outgoing DoT messages', - 'doc' : ''' -Whether to add EDNS padding to outgoing DoT queries. - ''', - 'versionadded': '4.8.0' - }, - { - 'name' : 'edns_padding_tag', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '7830', - 'help' : 'Packetcache tag associated to responses sent with EDNS padding, to prevent sending these to clients for which padding is not enabled.', - 'doc' : ''' -The packetcache tag to use for padded responses, to prevent a client not allowed by the :ref::`setting-edns-padding-from` list to be served a cached answer generated for an allowed one. This -effectively divides the packet cache in two when :ref:`setting-edns-padding-from` is used. Note that this will not override a tag set from one of the ``Lua`` hooks. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'edns_subnet_whitelist', - 'section' : 'outgoing', - 'type' : LType.String, - 'default' : '', - 'help' : 'List of netmasks and domains that we should enable EDNS subnet for (deprecated)', - 'doc' : '', - 'deprecated': ('4.5.0', 'Use :ref:`setting-edns-subnet-allow-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'edns_subnet_allow_list', - 'section' : 'outgoing', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'List of netmasks and domains that we should enable EDNS subnet for', - 'doc' : ''' -List of netmasks and domains that :rfc:`EDNS Client Subnet <7871>` should be enabled for in outgoing queries. - -For example, an EDNS Client Subnet option containing the address of the initial requestor (but see :ref:`setting-ecs-add-for`) will be added to an outgoing query sent to server 192.0.2.1 for domain X if 192.0.2.1 matches one of the supplied netmasks, or if X matches one of the supplied domains. -The initial requestor address will be truncated to 24 bits for IPv4 (see :ref:`setting-ecs-ipv4-bits`) and to 56 bits for IPv6 (see :ref:`setting-ecs-ipv6-bits`), as recommended in the privacy section of RFC 7871. - - -Note that this setting describes the destination of outgoing queries, not the sources of incoming queries, nor the subnets described in the EDNS Client Subnet option. - -By default, this option is empty, meaning no EDNS Client Subnet information is sent. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'edns_subnet_harden', - 'section' : 'outgoing', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Do more strict checking or EDNS Client Subnet information returned by authoritative servers', - 'doc' : ''' -Do more strict checking or EDNS Client Subnet information returned by authoritative servers. -Answers missing ECS information will be ignored and followed up by an ECS-less query. - ''', - 'versionadded': ['5.2.x', '5.1.x', '5.0.x'] - }, - { - 'name' : 'enable_old_settings', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Enable (deprecated) parsing of old-style settings', - 'doc' : ''' -Enable the deprecated parsing of old-style settings. -Only makes sense to set on the command line. - ''', - 'skip-yaml': True, - 'versionadded': '5.2.0', - }, - { - 'name' : 'entropy_source', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '/dev/urandom', - 'help' : 'If set, read entropy from this file', - 'doc' : ''' -PowerDNS can read entropy from a (hardware) source. -This is used for generating random numbers which are very hard to predict. -Generally on UNIX platforms, this source will be ``/dev/urandom``, which will always supply random numbers, even if entropy is lacking. -Change to ``/dev/random`` if PowerDNS should block waiting for enough entropy to arrive. - ''', - 'skip-yaml': True, - 'versionchanged': ('4.9.0', 'This setting is no longer used.'), - }, - { - 'name' : 'etc_hosts_file', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '/etc/hosts', - 'help' : 'Path to \'hosts\' file', - 'doc' : ''' -The path to the /etc/hosts file, or equivalent. -This file can be used to serve data authoritatively using :ref:`setting-export-etc-hosts`. - ''', - }, - { - 'name' : 'event_trace_enabled', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'If set, event traces are collected and send out via protobuf logging (1), logfile (2) or both(3)', - 'doc' : ''' -Enable the recording and logging of ref:`event traces`. This is an experimental feature and subject to change. -Possible values are 0: (disabled), 1 (add information to protobuf logging messages) and 2 (write to log) and 3 (both). - ''', - 'versionadded': '4.6.0', - 'runtime': 'set-event-trace-enabled', - }, - { - 'name' : 'export_etc_hosts', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If we should serve up contents from /etc/hosts', - 'doc' : ''' -If set, this flag will export the host names and IP addresses mentioned in ``/etc/hosts``. - ''', - }, - { - 'name' : 'export_etc_hosts_search_suffix', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Also serve up the contents of /etc/hosts with this suffix', - 'doc' : ''' -If set, all hostnames in the :ref:`setting-export-etc-hosts` file are loaded in canonical form, based on this suffix, unless the name contains a '.', in which case the name is unchanged. -So an entry called 'pc' with ``export-etc-hosts-search-suffix='home.com'`` will lead to the generation of 'pc.home.com' within the recursor. -An entry called 'server1.home' will be stored as 'server1.home', regardless of this setting. - ''', - }, - { - 'name' : 'extended_resolution_errors', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'If set, send an EDNS Extended Error extension on resolution failures, like DNSSEC validation errors', - 'doc' : ''' -If set, the recursor will add an EDNS Extended Error (:rfc:`8914`) to responses when resolution failed, like DNSSEC validation errors, explaining the reason it failed. This setting is not needed to allow setting custom error codes from Lua or from a RPZ hit. - ''', - 'versionadded': '4.5.0', - 'versionchanged': ('5.0.0', 'Default changed to enabled, previously it was disabled.'), - }, - { - 'name' : 'forward_zones', - 'section' : 'recursor', - 'type' : LType.ListForwardZones, - 'default' : '', - 'help' : 'Zones for which we forward queries, comma separated domain=ip pairs', - 'doc' : ''' -Queries for zones listed here will be forwarded to the IP address listed. i.e. - -.. code-block:: none - - forward-zones=example.org=203.0.113.210, powerdns.com=2001:DB8::BEEF:5 - -Multiple IP addresses can be specified and port numbers other than 53 can be configured: - -.. code-block:: none - - forward-zones=example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;198.51.100.10:530;[2001:DB8::1:3]:5300 - -Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning that this setting is intended to forward queries to authoritative servers. -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`. -See the :doc:`dnssec` information. - ''', - 'doc-new' : ''' -Queries for zones listed here will be forwarded to the IP address listed. i.e. - -.. code-block:: yaml - - recursor: - forward-zones: - - zone: example.org - forwarders: - - 203.0.113.210 - - zone: powerdns.com - forwarders: - - 2001:DB8::BEEF:5 - -Multiple IP addresses can be specified and port numbers other than 53 can be configured: - -.. code-block:: yaml - - recursor: - forward-zones: - - zone: example.org - forwarders: - - 203.0.113.210:5300 - - 127.0.0.1 - - zone: powerdns.com - forwarders: - - 127.0.0.1 - - 198.51.100.10:530 - - '[2001:DB8::1:3]:5300' - -Forwarded queries have the ``recursion desired (RD)`` bit set to ``0``, meaning that this setting is intended to forward queries to authoritative servers. -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`. -See the :doc:`dnssec` information. - ''', - 'versionchanged' : ('5.2.0', 'Zones having ``notify_allowed`` set will be added to :ref:`setting-yaml-incoming.allow_notify_for`.'), - 'runtime': ['reload-zones'], - }, - { - 'name' : 'forward_zones_file', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'File with (+)domain=ip pairs for forwarding', - 'doc' : ''' -Same as :ref:`setting-forward-zones`, parsed from a file. Only 1 zone is allowed per line, specified as follows: - -.. code-block:: none - - example.org=203.0.113.210, 192.0.2.4:5300 - -Zones prefixed with a ``+`` are treated as with -:ref:`setting-forward-zones-recurse`. Default behaviour without ``+`` is as with -:ref:`setting-forward-zones`. - -The DNSSEC notes from :ref:`setting-forward-zones` apply here as well. - ''', - 'doc-new' : ''' - Same as :ref:`setting-forward-zones`, parsed from a file as a sequence of `ZoneForward`. - -.. code-block:: yaml - - - zone: example1.com - forwarders: - - 127.0.0.1 - - 127.0.0.1:5353 - - '[::1]:53' - - zone: example2.com - forwarders: - - ::1 - recurse: true - notify_allowed: true - -The DNSSEC notes from :ref:`setting-forward-zones` apply here as well. - ''', - 'versionchanged': [('4.0.0', '(Old style settings only) Comments are allowed, everything behind ``#`` is ignored.'), - ('4.6.0', '(Old style settings only) Zones prefixed with a ``^`` are added to the :ref:`setting-allow-notify-for` list. Both prefix characters can be used if desired, in any order.')], - 'runtime': ['reload-zones'], - }, - { - 'name' : 'forward_zones_recurse', - 'section' : 'recursor', - 'type' : LType.ListForwardZones, - 'default' : '', - 'help' : 'Zones for which we forward queries with recursion bit, comma separated domain=ip pairs', - 'doc' : ''' -Like regular :ref:`setting-forward-zones`, but forwarded queries have the ``recursion desired (RD)`` bit set to ``1``, meaning that this setting is intended to forward queries to other recursive servers. -In contrast to regular forwarding, the rule that delegations of the forwarded subzones are respected is not active. -This is because we rely on the forwarder to resolve the query fully. - -See :ref:`setting-forward-zones` for additional options (such as supplying multiple recursive servers) and an important note about DNSSEC. - ''', - 'runtime': ['reload-zones'], - }, - { - 'name' : 'gettag_needs_edns_options', - 'section' : 'incoming', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If EDNS Options should be extracted before calling the gettag() hook', - 'doc' : ''' -If set, EDNS options in incoming queries are extracted and passed to the :func:`gettag` hook in the ``ednsoptions`` table. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'help', - 'section' : 'commands', - 'type' : LType.Command, - 'default' : 'no', - 'help' : 'Provide a helpful message', - 'doc' : ''' -EMPTY? ''' - }, - { - 'name' : 'hint_file', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, load root hints from this file', - 'doc' : ''' -If set, the root-hints are read from this file. If empty, the default built-in root hints are used. - -In some special cases, processing the root hints is not needed, for example when forwarding all queries to another recursor. -For these special cases, it is possible to disable the processing of root hints by setting the value to ``no`` or ``no-refresh``. -See :ref:`handling-of-root-hints` for more information on root hints handling. - ''', - 'versionchanged': [('4.6.2', 'Introduced the value ``no`` to disable root-hints processing.'), - ('4.9.0', 'Introduced the value ``no-refresh`` to disable both root-hints processing and periodic refresh of the cached root `NS` records.')] - }, - { - 'name' : 'ignore_unknown_settings', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'Configuration settings to ignore if they are unknown', - 'doc' : ''' -Names of settings to be ignored while parsing configuration files, if the setting -name is unknown to PowerDNS. - -Useful during upgrade testing. - ''', - }, - { - 'name' : 'include_dir', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - '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. - ''', - 'doc-new' : ''' -Directory to scan for additional config files. All files that end with ``.yml`` are loaded in order using ``POSIX`` as locale. - ''', - }, - { - 'name' : 'latency_statistic_size', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '10000', - 'help' : 'Number of latency values to calculate the qa-latency average', - 'doc' : ''' -Indication of how many queries will be averaged to get the average latency reported by the 'qa-latency' metric. - ''', - }, - { - 'name' : 'listen', - 'section' : 'incoming', - 'oldname' : 'local-address', - 'type' : LType.ListSocketAddresses, - 'default' : '127.0.0.1', - 'help' : 'IP addresses to listen on, separated by spaces or commas. Also accepts ports.', - 'doc' : ''' -Local IP addresses to which we bind. Each address specified can -include a port number; if no port is included then the -:ref:`setting-local-port` port will be used for that address. If a -port number is specified, it must be separated from the address with a -':'; for an IPv6 address the address must be enclosed in square -brackets. - -Examples:: - - local-address=127.0.0.1 ::1 - local-address=0.0.0.0:5353 - local-address=[::]:8053 - local-address=127.0.0.1:53, [::1]:5353 - ''', - 'doc-new' : ''' -Local IP addresses to which we bind. Each address specified can -include a port number; if no port is included then the -:ref:`setting-local-port` port will be used for that address. If a -port number is specified, it must be separated from the address with a -':'; for an IPv6 address the address must be enclosed in square -brackets. - -Example: - -.. code-block:: yaml - - incoming: - listen: - - 127.0.0.1 - - listen: '[::1]:5353' - - listen: '::' - ''', - }, - { - 'name' : 'port', - 'section' : 'incoming', - 'oldname' : 'local-port', - 'type' : LType.Uint64, - 'default' : '53', - 'help' : 'port to listen on', - 'doc' : ''' -Local port to bind to. -If an address in :ref:`setting-local-address` does not have an explicit port, this port is used. - ''', - }, - { - 'name' : 'timestamp', - 'section' : 'logging', - 'oldname' : 'log-timestamp', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Print timestamps in log lines, useful to disable when running with a tool that timestamps stderr already', - 'doc' : ''' - - ''', - }, - { - 'name' : 'non_local_bind', - 'section' : 'incoming', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Enable binding to non-local addresses by using FREEBIND / BINDANY socket options', - 'doc' : ''' -Bind to addresses even if one or more of the :ref:`setting-local-address`'s do not exist on this server. -Setting this option will enable the needed socket options to allow binding to non-local addresses. -This feature is intended to facilitate ip-failover setups, but it may also mask configuration issues and for this reason it is disabled by default. - ''', - }, - { - 'name' : 'loglevel', - 'section' : 'logging', - 'type' : LType.Uint64, - 'default' : '6', - 'help' : 'Amount of logging. Higher is more. Do not set below 3', - 'doc' : ''' -Amount of logging. The higher the number, the more lines logged. -Corresponds to ``syslog`` level values (e.g. 0 = ``emergency``, 1 = ``alert``, 2 = ``critical``, 3 = ``error``, 4 = ``warning``, 5 = ``notice``, 6 = ``info``, 7 = ``debug``). -Each level includes itself plus the lower levels before it. -Not recommended to set this below 3. -If :ref:`setting-quiet` is ``no/false``, :ref:`setting-loglevel` will be minimally set to ``6 (info)``. - ''', - 'versionchanged': ('5.0.0', 'Previous version would not allow setting a level below ``3 (error)``.') - }, - { - 'name' : 'common_errors', - 'section' : 'logging', - 'oldname' : 'log-common-errors', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If we should log rather common errors', - 'doc' : ''' -Some DNS errors occur rather frequently and are no cause for alarm. - ''', - }, - { - 'name' : 'rpz_changes', - 'section' : 'logging', - 'oldname' : 'log-rpz-changes', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Log additions and removals to RPZ zones at Info level', - 'doc' : ''' -Log additions and removals to RPZ zones at Info (6) level instead of Debug (7). - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'facility', - 'section' : 'logging', - 'oldname' : 'logging-facility', - 'type' : LType.String, - 'default' : '', - 'help' : 'Facility to log messages as. 0 corresponds to local0', - 'doc' : ''' -If set to a digit, logging is performed under this LOCAL facility. -See :ref:`logging`. -Do not pass names like 'local0'! - ''', - }, - { - 'name' : 'lowercase', - 'section' : 'outgoing', - 'oldname' : 'lowercase-outgoing', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Force outgoing questions to lowercase', - 'doc' : ''' -Set to true to lowercase the outgoing queries. -When set to 'no' (the default) a query from a client using mixed case in the DNS labels (such as a user entering mixed-case names or `draft-vixie-dnsext-dns0x20-00 `_), PowerDNS preserves the case of the query. -Broken authoritative servers might give a wrong or broken answer on this encoding. -Setting ``lowercase-outgoing`` to 'yes' makes the PowerDNS Recursor lowercase all the labels in the query to the authoritative servers, but still return the proper case to the client requesting. - ''', - }, - { - 'name' : 'lua_config_file', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'More powerful configuration options', - '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. - ''', - }, - { - 'name' : 'lua_dns_script', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Filename containing an optional Lua script that will be used to modify dns answers', - 'doc' : ''' -Path to a lua file to manipulate the Recursor's answers. See :doc:`lua-scripting/index` for more information. - ''', - }, - { - 'name' : 'lua_maintenance_interval', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'Number of seconds between calls to the lua user defined maintenance() function', - 'doc' : ''' -The interval between calls to the Lua user defined `maintenance()` function in seconds. -See :ref:`hooks-maintenance-callback` - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'max_busy_dot_probes', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Maximum number of concurrent DoT probes', - 'doc' : ''' -Limit the maximum number of simultaneous DoT probes the Recursor will schedule. -The default value 0 means no DoT probes are scheduled. - -DoT probes are used to check if an authoritative server's IP address supports DoT. -If the probe determines an IP address supports DoT, the Recursor will use DoT to contact it for subsequent queries until a failure occurs. -After a failure, the Recursor will stop using DoT for that specific IP address for a while. -The results of probes are remembered and can be viewed by the ``rec_control dump-dot-probe-map`` command. -If the maximum number of pending probes is reached, no probes will be scheduled, even if no DoT status is known for an address. -If the result of a probe is not yet available, the Recursor will contact the authoritative server in the regular way, unless an authoritative server is configured to be contacted over DoT always using :ref:`setting-dot-to-auth-names`. -In that case no probe will be scheduled. - -.. note:: - DoT probing is an experimental feature. - Please test thoroughly to determine if it is suitable in your specific production environment before enabling. - ''', - 'versionadded': '4.7.0' - }, - { - 'name' : 'max_cache_bogus_ttl', - 'section' : 'recordcache', - 'type' : LType.Uint64, - 'default' : '3600', - 'help' : 'maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory', - 'doc' : ''' -Maximum number of seconds to cache an item in the DNS cache (negative or positive) if its DNSSEC validation failed, no matter what the original TTL specified, to reduce the impact of a broken domain. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'max_entries', - 'section' : 'recordcache', - 'oldname' : 'max-cache-entries', - 'type' : LType.Uint64, - 'default' : '1000000', - 'help' : 'If set, maximum number of entries in the main cache', - 'doc' : ''' -Maximum number of DNS record cache entries, shared by all threads since 4.4.0. -Each entry associates a name and type with a record set. -The size of the negative cache is 10% of this number. - ''', - 'runtime': 'set-max-cache-entries', - }, - { - 'name' : 'max_ttl', - 'section' : 'recordcache', - 'oldname' : 'max-cache-ttl', - 'type' : LType.Uint64, - 'default' : '86400', - 'help' : 'maximum number of seconds to keep a cached entry in memory', - 'doc' : ''' -Maximum number of seconds to cache an item in the DNS cache, no matter what the original TTL specified. -This value also controls the refresh period of cached root data. -See :ref:`handling-of-root-hints` for more information on this. - ''', - 'versionchanged': ('4.1.0', 'The minimum value of this setting is 15. i.e. setting this to lower than 15 will make this value 15.') - }, - { - 'name' : 'max_entry_size', - 'section' : 'recordcache', - 'oldname': 'max-recordcache-entry-size', - 'type' : LType.Uint64, - 'default' : '8192', - 'help' : 'maximum storage size of a recordset stored in record cache', - 'doc' : ''' -Maximum size of storage used by a single record cache entry. Entries larger than this number will not be stored. -Zero means no limit. -''', - 'versionadded': ['5.1.10', '5.2.8', '5.3.5', '5.4.0'], - }, - { - 'name' : 'max_concurrent_requests_per_tcp_connection', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '10', - 'help' : 'Maximum number of requests handled concurrently per TCP connection', - 'doc' : ''' -Maximum number of incoming requests handled concurrently per tcp -connection. This number must be larger than 0 and smaller than 65536 -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', - 'type' : LType.Uint64, - 'default' : '20', - 'help' : 'Maximum nested $INCLUDE depth when loading a zone from a file', - 'doc' : ''' -Maximum number of nested ``$INCLUDE`` directives while processing a zone file. -Zero mean no ``$INCLUDE`` directives will be accepted. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'max_generate_steps', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Maximum number of $GENERATE steps when loading a zone from a file', - 'doc' : ''' -Maximum number of steps for a '$GENERATE' directive when parsing a -zone file. This is a protection measure to prevent consuming a lot of -CPU and memory when untrusted zones are loaded. Default to 0 which -means unlimited. - ''', - 'versionadded': '4.3.0' - }, - { - 'name' : 'max_mthreads', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '2048', - 'help' : 'Maximum number of simultaneous Mtasker threads', - 'doc' : ''' -Maximum number of simultaneous MTasker threads, per worker thread. - ''', - }, - { - 'name' : 'max_entries', - 'section' : 'packetcache', - 'oldname' : 'max-packetcache-entries', - 'type' : LType.Uint64, - 'default' : '500000', - 'help' : 'maximum number of entries to keep in the packetcache', - 'doc' : ''' -Maximum number of Packet Cache entries. Sharded and shared by all threads since 4.9.0. -''', - 'runtime': 'set-max-packetcache-entries', - }, - { - 'name' : 'max_entry_size', - 'section' : 'packetcache', - 'oldname' : 'max-packetcache-entry-size', - 'type' : LType.Uint64, - 'default' : '8192', - 'help' : 'maximum size of a packet stored in the the packet cache', - 'doc' : ''' -Maximum size of packets stored in the packet cache. Packets larger than this number will not be stored. -Zero means no limit. -''', - 'versionadded': ['5.1.10', '5.2.8', '5.3.5', '5.4.0'], - }, - { - 'name' : 'max_qperq', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '50', - 'help' : 'Maximum outgoing queries per client query', - 'doc' : ''' -The maximum number of outgoing queries that will be sent out during the resolution of a single client query. -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_bytesperq', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '100000', - 'help' : 'Maximum number of received bytes per client query', - 'doc' : ''' -The maximum number of cumulative bytes that will be accepted during the resolution of a single client query. -This is useful to limit amplification attacks. - ''', - 'versionadded': '5.4.0', - }, - { - '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' : 'limit_qtype_any', - 'section' : 'recordcache', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Limit answers to ANY queries in size', - 'doc' : ''' -Limit answers to ANY queries constructed from the record cache in size. -Trying to retrieve more than :ref:`setting-max-rrset-size` records will result in a ``ServFail``', - ''', - 'versionadded': ['4.9.9', '5.0.9', '5.1.2'] - }, - { - 'name' : 'max_rrset_size', - 'section' : 'recordcache', - 'type' : LType.Uint64, - 'default' : '256', - 'help' : 'Maximum size of RRSet in cache', - 'doc' : ''' -Maximum size of RRSets in cache. -Trying to retrieve larger RRSets will result in a ``ServFail``.', - ''', - 'versionadded': ['4.9.9', '5.0.9', '5.1.2'] - }, - { - 'name' : 'max_ns_address_qperq', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '10', - 'help' : 'Maximum outgoing NS address queries per query', - 'doc' : ''' -The maximum number of outgoing queries with empty replies for -resolving nameserver names to addresses we allow during the resolution -of a single client query. If IPv6 is enabled, an A and a AAAA query -for a name counts as 1. If a zone publishes more than this number of -NS records, the limit is further reduced for that zone by lowering -it by the number of NS records found above the -:ref:`setting-max-ns-address-qperq` value. The limit will not be reduced to a -number lower than 5. - ''', - 'versionadded' : ['4.1.16', '4.2.2', '4.3.1'] - }, - { - 'name' : 'max_ns_per_resolve', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '13', - 'help' : 'Maximum number of NS records to consider to resolve a name, 0 is no limit', - 'doc' : ''' -The maximum number of NS records that will be considered to select a nameserver to contact to resolve a name. -If a zone has more than :ref:`setting-max-ns-per-resolve` NS records, a random sample of this size will be used. -If :ref:`setting-max-ns-per-resolve` is zero, no limit applies. - ''', - 'versionadded': ['4.8.0', '4.7.3', '4.6.4', '4.5.11'] - }, - { - 'name' : 'max_negative_ttl', - 'section' : 'recordcache', - 'type' : LType.Uint64, - 'default' : '3600', - 'help' : 'maximum number of seconds to keep a negative cached entry in memory', - 'doc' : ''' -A query for which there is authoritatively no answer is cached to quickly deny a record's existence later on, without putting a heavy load on the remote server. -In practice, caches can become saturated with hundreds of thousands of hosts which are tried only once. -This setting, which defaults to 3600 seconds, puts a maximum on the amount of time negative entries are cached. - ''', - }, - { - 'name' : 'max_recursion_depth', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '16', - 'help' : 'Maximum number of internal recursion calls per query, 0 for unlimited', - 'doc' : ''' -Total maximum number of internal recursion calls the server may use to answer a single query. -0 means unlimited. -The value of :ref:`setting-stack-size` should be increased together with this one to prevent the stack from overflowing. -If :ref:`setting-qname-minimization` is enabled, the fallback code in case of a failing resolve is allowed an additional `max-recursion-depth/2`. - ''', - 'versionchanged': [('4.1.0', 'Before 4.1.0, this settings was unlimited.'), - ('4.9.0', "Before 4.9.0 this setting's default was 40 and the limit on ``CNAME`` chains (fixed at 16) acted as a bound on he recursion depth.")] - }, - { - 'name' : 'max_tcp_clients', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '1024', - 'help' : 'Maximum number of simultaneous TCP clients', - 'doc' : ''' -Maximum number of simultaneous incoming TCP connections allowed. - ''', - 'versionchanged': ('5.2.0', 'Before 5.2.0 the default was 128.'), - }, - { - 'name' : 'max_tcp_per_client', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'If set, maximum number of TCP sessions per client (IP address)', - 'doc' : ''' -Maximum number of simultaneous incoming TCP connections allowed per client (remote IP address). -0 means unlimited. - ''', - }, - { - 'name' : 'max_tcp_queries_per_connection', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'If set, maximum number of TCP queries in a TCP connection', - 'doc' : ''' -Maximum number of DNS queries in a TCP connection. -0 means unlimited. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'max_total_msec', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '7000', - 'help' : 'Maximum total wall-clock time per query in milliseconds, 0 for unlimited', - 'doc' : ''' -Total maximum number of milliseconds of wallclock time the server may use to answer a single query. -0 means unlimited. - ''', - }, - { - 'name' : 'max_udp_queries_per_round', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '10000', - 'help' : 'Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing', - 'doc' : ''' -Under heavy load the recursor might be busy processing incoming UDP queries for a long while before there is no more of these, and might therefore -neglect scheduling new ``mthreads``, handling responses from authoritative servers or responding to :doc:`rec_control ` -requests. -This setting caps the maximum number of incoming UDP DNS queries processed in a single round of looping on ``recvmsg()`` after being woken up by the multiplexer, before -returning back to normal processing and handling other events. - ''', - 'versionadded': '4.1.4' - }, - { - 'name' : 'minimum_ttl_override', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'The minimum TTL', - 'doc' : ''' -This setting artificially raises all TTLs to be at least this long. -Setting this to a value greater than 1 technically is an RFC violation, but might improve performance a lot. -Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact -authoritative servers each time a client requests them. - ''', - 'versionchanged': ('4.5.0', 'Old versions used default 0.'), - 'runtime': 'set-minimum-ttl', - }, - { - 'name' : 'tracking', - 'section' : 'nod', - 'oldname' : 'new-domain-tracking', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Track newly observed domains (i.e. never seen before).', - 'doc' : ''' -Whether to track newly observed domains, i.e. never seen before. This -is a probabilistic algorithm, using a stable bloom filter to store -records of previously seen domains. When enabled for the first time, -all domains will appear to be newly observed, so the feature is best -left enabled for e.g. a week or longer before using the results. Note -that this feature is optional and must be enabled at compile-time, -thus it may not be available in all pre-built packages. -If protobuf is enabled and configured, then the newly observed domain -status will appear as a flag in Response messages. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'log', - 'section' : 'nod', - 'oldname' : 'new-domain-log', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Log newly observed domains.', - 'doc' : ''' -If a newly observed domain is detected, log that domain in the -recursor log file. The log line looks something like:: - - Jul 18 11:31:25 Newly observed domain nod=sdfoijdfio.com - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'lookup', - 'section' : 'nod', - 'oldname' : 'new-domain-lookup', - 'type' : LType.String, - 'default' : '', - 'help' : 'Perform a DNS lookup newly observed domains as a subdomain of the configured domain', - 'doc' : ''' -If a domain is specified, then each time a newly observed domain is -detected, the recursor will perform an A record lookup of '.'. For example if 'new-domain-lookup' -is configured as 'nod.powerdns.com', and a new domain 'example.com' is -detected, then an A record lookup will be made for -'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. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'db_size', - 'section' : 'nod', - 'oldname' : 'new-domain-db-size', - 'type' : LType.Uint64, - 'default' : '67108864', - 'help' : 'Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864', - 'doc' : ''' -The default size of the stable bloom filter used to store previously -observed domains is 67108864. To change the number of cells, use this -setting. For each cell, the SBF uses 1 bit of memory, and one byte of -disk for the persistent file. -If there are already persistent files saved to disk, this setting will -have no effect unless you remove the existing files. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'history_dir', - 'section' : 'nod', - 'oldname' : 'new-domain-history-dir', - 'type' : LType.String, - 'default' : 'NODCACHEDIRNOD', - 'docdefault': 'Determined by distribution', - 'help' : 'Persist new domain tracking data here to persist between restarts', - 'doc' : ''' -This setting controls which directory is used to store the on-disk -cache of previously observed domains. - -The default depends on ``LOCALSTATEDIR`` when building the software. -Usually this comes down to ``/var/lib/pdns-recursor/nod`` or ``/usr/local/var/lib/pdns-recursor/nod``). - -The newly observed domain feature uses a stable bloom filter to store -a history of previously observed domains. The data structure is -synchronized to disk every 10 minutes, and is also initialized from -disk on startup. This ensures that previously observed domains are -preserved across recursor restarts. -If you change the new-domain-db-size setting, you must remove any files -from this directory. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'db_snapshot_interval', - 'section' : 'nod', - 'oldname' : 'new-domain-db-snapshot-interval', - 'type' : LType.Uint64, - 'default' : '600', - 'help' : 'Interval (in seconds) to write the NOD and UDR DB snapshots', - 'doc' : ''' -Interval (in seconds) to write the NOD and UDR DB snapshots. -Set to zero to disable snapshot writing.', - ''', - 'versionadded': '5.1.0' - }, - { - 'name' : 'whitelist', - 'section' : 'nod', - 'oldname' : 'new-domain-whitelist', - 'type' : LType.String, - 'default' : '', - 'help' : 'List of domains (and implicitly all subdomains) which will never be considered a new domain (deprecated)', - 'doc' : '', - 'versionadded': '4.2.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-new-domain-ignore-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'ignore_list', - 'section' : 'nod', - 'oldname' : 'new-domain-ignore-list', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'List of domains (and implicitly all subdomains) which will never be considered a new domain', - '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 -'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', - 'oldname' : 'new-domain-pb-tag', - 'type' : LType.String, - 'default' : 'pdns-nod', - 'help' : 'If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to \'pdns-nod\'', - 'doc' : ''' -If protobuf is configured, then this tag will be added to all protobuf response messages when -a new domain is observed. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'network_timeout', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '1500', - '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. - ''', - }, - { - 'name' : 'no_shuffle', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Don\'t change', - 'doc' : 'SKIP', - 'skip-yaml': True, - }, - { - 'name' : 'non_resolving_ns_max_fails', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '5', - 'help' : 'Number of failed address resolves of a nameserver to start throttling it, 0 is disabled', - 'doc' : ''' -Number of failed address resolves of a nameserver name to start throttling it, 0 is disabled. -Nameservers matching :ref:`setting-dont-throttle-names` will not be throttled. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'non_resolving_ns_throttle_time', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '60', - 'help' : 'Number of seconds to throttle a nameserver with a name failing to resolve', - 'doc' : ''' -Number of seconds to throttle a nameserver with a name failing to resolve. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'nothing_below_nxdomain', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : 'dnssec', - 'help' : 'When an NXDOMAIN exists in cache for a name with fewer labels than the qname, send NXDOMAIN without doing a lookup (see RFC 8020)', - 'doc' : ''' -- One of ``no``, ``dnssec``, ``yes``. - -The type of :rfc:`8020` handling using cached NXDOMAIN responses. -This RFC specifies that NXDOMAIN means that the DNS tree under the denied name MUST be empty. -When an NXDOMAIN exists in the cache for a shorter name than the qname, no lookup is done and an NXDOMAIN is sent to the client. - -For instance, when ``foo.example.net`` is negatively cached, any query -matching ``*.foo.example.net`` will be answered with NXDOMAIN directly -without consulting authoritative servers. - -``no`` - No :rfc:`8020` processing is done. - -``dnssec`` - :rfc:`8020` processing is only done using cached NXDOMAIN records that are - DNSSEC validated. - -``yes`` - :rfc:`8020` processing is done using any non-Bogus NXDOMAIN record - available in the cache. - ''', - 'versionadded': '4.3.0' - }, - { - 'name' : 'nsec3_max_iterations', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '50', - 'help' : 'Maximum number of iterations allowed for an NSEC3 record', - 'doc' : ''' -Maximum number of iterations allowed for an NSEC3 record. -If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as ``Insecure``. - ''', - 'versionadded': '4.1.0', - 'versionchanged': [('4.5.2', 'Default is now 150, was 2500 before.'), - ('5.0.0', 'Default is now 50, was 150 before.')] - }, - { - 'name' : 'max_rrsigs_per_record', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '2', - 'help' : 'Maximum number of RRSIGs to consider when validating a given record', - 'doc' : ''' -Maximum number of RRSIGs we are willing to cryptographically check when validating a given record. Expired or not yet incepted RRSIGs do not count toward to this limit. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'max_nsec3s_per_record', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '10', - 'help' : 'Maximum number of NSEC3s to consider when validating a given denial of existence', - 'doc' : ''' -Maximum number of NSEC3s to consider when validating a given denial of existence. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'max_signature_validations_per_query', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '30', - 'help' : 'Maximum number of RRSIG signatures we are willing to validate per incoming query', - 'doc' : ''' -Maximum number of RRSIG signatures we are willing to validate per incoming query. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'max_nsec3_hash_computations_per_query', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '600', - 'help' : 'Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query', - 'doc' : ''' -Maximum number of NSEC3 hashes that we are willing to compute during DNSSEC validation, per incoming query. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'aggressive_cache_max_nsec3_hash_cost', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '150', - 'help' : 'Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache', - 'doc' : ''' -Maximum estimated NSEC3 cost for a given query to consider aggressive use of the NSEC3 cache. The cost is estimated based on a heuristic taking the zone's NSEC3 salt and iterations parameters into account, as well at the number of labels of the requested name. For example a query for a name like a.b.c.d.e.f.example.com. in an example.com zone. secured with NSEC3 and 10 iterations (NSEC3 iterations count of 9) and an empty salt will have an estimated worst-case cost of 10 (iterations) * 6 (number of labels) = 60. The aggressive NSEC cache is an optimization to reduce the number of queries to authoritative servers, which is especially useful when a zone is under pseudo-random subdomain attack, and we want to skip it the zone parameters make it expensive. -''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'max_ds_per_zone', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '8', - 'help' : 'Maximum number of DS records to consider per zone', - 'doc' : ''' -Maximum number of DS records to consider when validating records inside a zone. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'max_dnskeys', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '2', - 'help' : 'Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record', - 'doc' : ''' -Maximum number of DNSKEYs with the same algorithm and tag to consider when validating a given record. Setting this value to 1 effectively denies DNSKEY tag collisions in a zone. - ''', - 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], - }, - { - 'name' : 'ttl', - 'section' : 'packetcache', - 'oldname' : 'packetcache-ttl', - 'type' : LType.Uint64, - 'default' : '86400', - 'help' : 'maximum number of seconds to keep a cached entry in packetcache', - 'doc' : ''' -Maximum number of seconds to cache an item in the packet cache, no matter what the original TTL specified. - ''', - 'versionchanged': ('4.9.0', 'The default was changed from 3600 (1 hour) to 86400 (24 hours).') - }, - { - 'name' : 'negative_ttl', - 'section' : 'packetcache', - 'oldname' : 'packetcache-negative-ttl', - 'type' : LType.Uint64, - 'default' : '60', - 'help' : 'maximum number of seconds to keep a cached NxDomain or NoData entry in packetcache', - 'doc' : ''' -Maximum number of seconds to cache an ``NxDomain`` or ``NoData`` answer in the packetcache. -This setting's maximum is capped to :ref:`setting-packetcache-ttl`. -i.e. setting ``packetcache-ttl=15`` and keeping ``packetcache-negative-ttl`` at the default will lower ``packetcache-negative-ttl`` to ``15``. - ''', - 'versionadded': '4.9.0' - }, - { - 'name' : 'servfail_ttl', - 'section' : 'packetcache', - 'oldname' : 'packetcache-servfail-ttl', - 'type' : LType.Uint64, - 'default' : '60', - 'help' : 'maximum number of seconds to keep a cached servfail entry in packetcache', - 'doc' : ''' -Maximum number of seconds to cache an answer indicating a failure to resolve in the packet cache. -Before version 4.6.0 only ``ServFail`` answers were considered as such. Starting with 4.6.0, all responses with a code other than ``NoError`` and ``NXDomain``, or without records in the answer and authority sections, are considered as a failure to resolve. -Since 4.9.0, negative answers are handled separately from resolving failures. - ''', - 'doc-rst' : ''' - 'versionchanged': ('4.0.0', "This setting's maximum is capped to :ref:`setting-packetcache-ttl`. - i.e. setting ``packetcache-ttl=15`` and keeping ``packetcache-servfail-ttl`` at the default will lower ``packetcache-servfail-ttl`` to ``15``.") - ''' - }, - { - 'name' : 'shards', - 'section' : 'packetcache', - 'oldname' : 'packetcache-shards', - 'type' : LType.Uint64, - 'default' : '1024', - 'help' : 'Number of shards in the packet cache', - 'doc' : ''' -Sets the number of shards in the packet cache. If you have high contention as reported by ``packetcache-contented/packetcache-acquired``, -you can try to enlarge this value or run with fewer threads. - ''', - 'versionadded': '4.9.0' - }, - { - 'name' : 'pdns_distributes_queries', - 'section' : 'incoming', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If PowerDNS itself should distribute queries over threads', - 'doc' : ''' -If set, PowerDNS will use distinct threads to listen to client sockets and distribute that work to worker-threads using a hash of the query. -This feature should maximize the cache hit ratio on versions before 4.9.0. -To use more than one thread set :ref:`setting-distributor-threads` in version 4.2.0 or newer. -Enabling should improve performance on systems where :ref:`setting-reuseport` does not have the effect of -balancing the queries evenly over multiple worker threads. - ''', - 'versionchanged': ('4.9.0', 'Default changed to ``no``, previously it was ``yes``.') - }, - { - 'name' : 'processes', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)', - 'doc' : '''SKIP''', - 'skip-yaml': True, - }, - { - 'name' : 'protobuf_use_kernel_timestamp', - 'section' : 'logging', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)', - 'doc' : ''' -Whether to compute the latency of responses in protobuf messages using the timestamp set by the kernel when the query packet was received (when available), instead of computing it based on the moment we start processing the query. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'proxy_protocol_from', - 'section' : 'incoming', - 'type' : LType.ListSubnets, - 'default' : '', - 'help' : 'A Proxy Protocol header is required from these subnets', - 'doc' : ''' -Ranges that are required to send a Proxy Protocol version 2 header in front of UDP and TCP queries, to pass the original source and destination addresses and ports to the recursor, as well as custom values. -Queries that are not prefixed with such a header will not be accepted from clients in these ranges. Queries prefixed by headers from clients that are not listed in these ranges will be dropped. - -Note that once a Proxy Protocol header has been received, the source address from the proxy header instead of the address of the proxy will be checked against the :ref:`setting-allow-from` ACL. - -The dnsdist docs have `more information about the PROXY protocol `_. - ''', - 'versionadded' : '4.4.0', - 'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence') - }, - { - 'name' : 'proxy_protocol_exceptions', - 'section' : 'incoming', - 'type' : LType.ListSocketAddresses, - 'default' : '', - 'help' : 'A Proxy Protocol header should not be used for these listen addresses.', - 'doc' : ''' -If set, clients sending from an address in :ref:`setting-proxy-protocol-from` to a address:port listed here are excluded from using the Proxy Protocol. -If no port is specified, port 53 is assumed. -This is typically used to provide an easy to use address and port to send debug queries to. - ''', - 'versionadded' : '5.1.0', - }, - { - 'name' : 'proxy_protocol_maximum_size', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '512', - 'help' : 'The maximum size of a proxy protocol payload, including the TLV values', - 'doc' : ''' -The maximum size, in bytes, of a Proxy Protocol payload (header, addresses and ports, and TLV values). Queries with a larger payload will be dropped. - ''', - 'versionadded': '4.4.0' - }, - { - 'name' : 'public_suffix_list_file', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Path to the Public Suffix List file, if any', - 'doc' : ''' -Path to the Public Suffix List file, if any. If set, PowerDNS will try to load the Public Suffix List from this file instead of using the built-in list. The PSL is used to group the queries by relevant domain names when displaying the top queries. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'qname_minimization', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Use Query Name Minimization', - 'doc' : ''' -Enable Query Name Minimization. This implements a relaxed form of Query Name Mimimization as -described in :rfc:`9156`. - ''', - 'versionadded': '4.3.0' - }, - { - 'name' : 'qname_max_minimize_count', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '10', - 'help' : 'RFC9156 max minimize count', - 'doc' : ''' -``Max minimize count`` parameter, described in :rfc:`9156`. This is the maximum number of iterations -of the Query Name Minimization Algorithm. - ''', - 'versionadded': '5.0.0' - }, - { - 'name' : 'qname_minimize_one_label', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '4', - 'help' : 'RFC9156 minimize one label parameter', - 'doc' : ''' -``Minimize one label`` parameter, described in :rfc:`9156`. -The value for the number of iterations of the Query Name Minimization Algorithm that should only have one label appended. -This value has precedence over :ref:`setting-qname-max-minimize-count`. - ''', - 'versionadded': '5.0.0' - }, - { - 'name' : 'source_address', - 'section' : 'outgoing', - 'oldname' : 'query-local-address', - 'type' : LType.ListSubnets, - 'default' : '0.0.0.0', - 'help' : 'Source IP address for sending queries', - 'doc' : ''' -.. note:: - While subnets and their negations are syntactically accepted, the handling of subnets has not been implemented yet. - Only individual IP addresses can be listed. - -Send out local queries from this address, or addresses. By adding multiple -addresses, increased spoofing resilience is achieved. When no address of a certain -address family is configured, there are *no* queries sent with that address family. -In the default configuration this means that IPv6 is not used for outgoing queries. - ''', - 'versionchanged': ('4.4.0', 'IPv6 addresses can be set with this option as well.') - }, - { - 'name' : 'quiet', - 'section' : 'logging', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Suppress logging of questions and answers', - 'doc' : ''' -Don't log queries. - ''', - }, - { - 'name' : 'locked_ttl_perc', - 'section' : 'recordcache', - 'oldname' : 'record-cache-locked-ttl-perc', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Replace records in record cache only after this % of original TTL has passed', - 'doc' : ''' -Replace record sets in the record cache only after this percentage of the original TTL has passed. -The PowerDNS Recursor already has several mechanisms to protect against spoofing attempts. -This adds an extra layer of protection---as it limits the window of time cache updates are accepted---at the cost of a less efficient record cache. - -The default value of 0 means no extra locking occurs. -When non-zero, record sets received (e.g. in the Additional Section) will not replace existing record sets in the record cache until the given percentage of the original TTL has expired. -A value of 100 means only expired record sets will be replaced. - -There are a few cases where records will be replaced anyway: - -- Record sets that are expired will always be replaced. -- Authoritative record sets will replace unauthoritative record sets unless DNSSEC validation of the new record set failed. -- If the new record set belongs to a DNSSEC-secure zone and successfully passed validation it will replace an existing entry. -- Record sets produced by :ref:`setting-refresh-on-ttl-perc` tasks will also replace existing record sets. - ''', - 'versionadded': '4.8.0' - }, - { - 'name' : 'shards', - 'section' : 'recordcache', - 'oldname' : 'record-cache-shards', - 'type' : LType.Uint64, - 'default' : '1024', - 'help' : 'Number of shards in the record cache', - 'doc' : ''' -Sets the number of shards in the record cache. If you have high -contention as reported by -``record-cache-contented/record-cache-acquired``, you can try to -enlarge this value or run with fewer threads. - ''', - 'versionadded': '4.4.0' - }, - { - 'name' : 'refresh_on_ttl_perc', - 'section' : 'recordcache', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'If a record is requested from the cache and only this % of original TTL remains, refetch', - 'doc' : ''' -Sets the 'refresh almost expired' percentage of the record cache. Whenever a record is fetched from the packet or record cache -and only ``refresh-on-ttl-perc`` percent or less of its original TTL is left, a task is queued to refetch the name/type combination to -update the record cache. In most cases this causes future queries to always see a non-expired record cache entry. -A typical value is 10. If the value is zero, this functionality is disabled. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'reuseport', - 'section' : 'incoming', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address', - 'doc' : ''' -If ``SO_REUSEPORT`` support is available, allows multiple threads and processes to open listening sockets for the same port. - -Since 4.1.0, when :ref:`setting-pdns-distributes-queries` is disabled and :ref:`setting-reuseport` is enabled, every worker-thread will open a separate listening socket to let the kernel distribute the incoming queries instead of running a distributor thread (which could otherwise be a bottleneck) and avoiding thundering herd issues, thus leading to much higher performance on multi-core boxes. - ''', - 'versionchanged': ('4.9.0', 'The default is changed to ``yes``, previously it was ``no``. If ``SO_REUSEPORT`` support is not available, the setting defaults to ``no``.') - }, - { - 'name' : 'rng', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : 'auto', - 'help' : 'Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.', - 'doc' : ''' -- String -- Default: auto - -Specify which random number generator to use. Permissible choices are - - auto - choose automatically - - sodium - Use libsodium ``randombytes_uniform`` - - openssl - Use libcrypto ``RAND_bytes`` - - getrandom - Use libc getrandom, falls back to urandom if it does not really work - - arc4random - Use BSD ``arc4random_uniform`` - - urandom - Use ``/dev/urandom`` - - kiss - Use simple settable deterministic RNG. **FOR TESTING PURPOSES ONLY!** - ''', - 'skip-yaml': True, - 'versionchanged': ('4.9.0', 'This setting is no longer used.') - }, - { - 'name' : 'root_nx_trust', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'If set, believe that an NXDOMAIN from the root means the TLD does not exist', - 'doc' : ''' -If set, an NXDOMAIN from the root-servers will serve as a blanket NXDOMAIN for the entire TLD the query belonged to. -The effect of this is far fewer queries to the root-servers. - ''', - 'versionchanged': ('4.0.0', "Default is ``yes`` now, was ``no`` before 4.0.0") - }, - { - 'name' : 'save_parent_ns_set', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Save parent NS set to be used if child NS set fails', - 'doc' : ''' -If set, a parent (non-authoritative) ``NS`` set is saved if it contains more entries than a newly encountered child (authoritative) ``NS`` set for the same domain. -The saved parent ``NS`` set is tried if resolution using the child ``NS`` set fails. - ''', - 'versionadded': '4.7.0' - }, - { - 'name' : 'security_poll_suffix', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : 'secpoll.powerdns.com.', - 'help' : 'Domain name from which to query security update notifications', - 'doc' : ''' -Domain name from which to query security update notifications. -Setting this to an empty string disables secpoll. - ''', - }, - { - 'name' : 'serve_rfc1918', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'If we should be authoritative for RFC 1918 private IP space', - 'doc' : ''' -This makes the server authoritatively aware of: ``10.in-addr.arpa``, ``168.192.in-addr.arpa``, ``16-31.172.in-addr.arpa``, which saves load on the AS112 servers. -Individual parts of these zones can still be loaded or forwarded. - ''', - 'runtime': ['reload-zones'], - }, - { - 'name' : 'serve_rfc6303', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'If we should be authoritative for RFC 6303 private IP space', - 'doc' : ''' -This makes the server authoritatively aware of the zones in RFC 6303 not covered by RFC 1918. -Individual parts of these zones can still be loaded or forwarded. -:ref:`setting-serve-rfc1918` must be enabled for this option to take effect. -''', - 'versionadded': ['5.1.3', '5.2.0'], - 'runtime': ['reload-zones'], - }, - { - 'name' : 'serve_stale_extensions', - 'section' : 'recordcache', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Number of times a record\'s ttl is extended by 30s to be served stale', - 'doc' : ''' -Maximum number of times an expired record's TTL is extended by 30s when serving stale. -Extension only occurs if a record cannot be refreshed. -A value of 0 means the ``Serve Stale`` mechanism is not used. -To allow records becoming stale to be served for an hour, use a value of 120. -See :ref:`serve-stale` for a description of the Serve Stale mechanism. - ''', - 'versionadded': '4.8.0' - }, - { - 'name' : 'server_down_max_fails', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '64', - 'help' : 'Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )', - 'doc' : ''' -If a server has not responded in any way this many times in a row, no longer send it any queries for :ref:`setting-server-down-throttle-time` seconds. -Afterwards, we will try a new packet, and if that also gets no response at all, we again throttle for :ref:`setting-server-down-throttle-time` seconds. -Even a single response packet will drop the block. - ''', - }, - { - 'name' : 'server_down_throttle_time', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '60', - 'help' : 'Number of seconds to throttle all queries to a server after being marked as down', - 'doc' : ''' -Throttle a server that has failed to respond :ref:`setting-server-down-max-fails` times for this many seconds. - ''', - }, - { - 'name' : 'bypass_server_throttling_probability', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '25', - 'help' : 'Determines the probability of a server marked down to be used anyway', - 'doc' : ''' -This setting determines the probability of a server marked down to be used anyway. -A value of ``n`` means that the chance of a server marked down still being used after it wins speed selection is is ``1/n``. -If this setting is zero throttled servers will never be selected to be used anyway. - ''', - 'versionadded': '5.0.0' - }, - { - 'name' : 'server_id', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : RUNTIME, - 'help' : 'Returned when queried for \'id.server\' TXT or NSID, defaults to hostname, set custom or \'disabled\'', - 'doc' : ''' -The reply given by The PowerDNS recursor to a query for 'id.server' with its hostname, useful for in clusters. -When a query contains the :rfc:`NSID EDNS0 Option <5001>`, this value is returned in the response as the NSID value. - -This setting can be used to override the answer given to these queries. -Set to 'disabled' to disable NSID and 'id.server' answers. - -Query example (where 192.0.2.14 is your server): - -.. code-block:: sh - - dig @192.0.2.14 CHAOS TXT id.server. - dig @192.0.2.14 example.com IN A +nsid - ''', - }, - { - 'name' : 'setgid', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, change group id to this gid for more security', - 'doc' : ''' -PowerDNS can change its user and group id after binding to its socket. -Can be used for better :doc:`security `. - ''' - }, - { - 'name' : 'setuid', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set, change user id to this uid for more security', - 'doc' : ''' -PowerDNS can change its user and group id after binding to its socket. -Can be used for better :doc:`security `. - ''' - }, - { - 'name' : 'signature_inception_skew', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '60', - 'help' : 'Allow the signature inception to be off by this number of seconds', - 'doc' : ''' -Allow the signature inception to be off by this number of seconds. Negative values are not allowed. - ''', - 'versionadded': '4.1.5', - 'versionchanged': ('4.2.0', 'Default is now 60, was 0 before.') - }, - { - 'name' : 'single_socket', - 'section' : 'outgoing', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If set, only use a single socket for outgoing queries', - 'doc' : ''' -Use only a single socket for outgoing queries. - ''', - }, - { - 'name' : 'agent', - 'section' : 'snmp', - 'oldname' : 'snmp-agent', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'If set, register as an SNMP agent', - 'doc' : ''' -If set to true and PowerDNS has been compiled with SNMP support, it will register as an SNMP agent to provide statistics and be able to send traps. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'master_socket', - 'section' : 'snmp', - 'oldname' : 'snmp-master-socket', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set and snmp-agent is set, the socket to use to register to the SNMP daemon (deprecated)', - 'doc' : ''' - ''', - 'versionadded': '4.1.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-snmp-daemon-socket`.'), - 'skip-yaml': True, - }, - { - 'name' : 'daemon_socket', - 'section' : 'snmp', - 'oldname' : 'snmp-daemon-socket', - 'type' : LType.String, - 'default' : '', - 'help' : 'If set and snmp-agent is set, the socket to use to register to the SNMP daemon', - 'doc' : ''' -If not empty and ``snmp-agent`` is set to true, indicates how PowerDNS should contact the SNMP daemon to register as an SNMP agent. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'soa_minimum_ttl', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Don\'t change', - 'doc' : '''SKIP''', - 'skip-yaml': True, - }, - { - 'name' : 'socket_dir', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Where the controlsocket will live, /var/run/pdns-recursor when unset and not chrooted', - 'doc' : ''' -Where to store the control socket and pidfile. -The default depends on ``LOCALSTATEDIR`` or the ``--with-socketdir`` setting when building (usually ``/var/run`` or ``/run``). - -When using :ref:`setting-chroot` the default becomes ``/``. -The default value is overruled by the ``RUNTIME_DIRECTORY`` environment variable when that variable has a value (e.g. under systemd). - ''', - }, - { - 'name' : 'socket_group', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Group of socket', - 'doc' : ''' -Group and mode of the controlsocket. -Owner and group can be specified by name, mode is in octal. -''' - }, - { - 'name' : 'socket_mode', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Permissions for socket', - 'doc' : ''' -Mode of the controlsocket. -Owner and group can be specified by name, mode is in octal. - ''' - }, - { - 'name' : 'socket_owner', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Owner of socket', - 'doc' : ''' -Owner of the controlsocket. -Owner and group can be specified by name, mode is in octal. - ''' - }, - { - 'name' : 'spoof_nearmiss_max', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'If non-zero, assume spoofing after this many near misses', - 'doc' : ''' -If set to non-zero, PowerDNS will assume it is being spoofed after seeing this many answers with the wrong id. - ''', - 'versionchanged': ('4.5.0', 'Older versions used 20 as the default value.') - }, - { - 'name' : 'stack_cache_size', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '100', - 'help' : 'Size of the stack cache, per mthread', - 'doc' : ''' -Maximum number of mthread stacks that can be cached for later reuse, per thread. Caching these stacks reduces the CPU load at the cost of a slightly higher memory usage, each cached stack consuming `stack-size` bytes of memory. -It makes no sense to cache more stacks than the value of `max-mthreads`, since there will never be more stacks than that in use at a given time. - ''', - 'versionadded': '4.9.0' - }, - { - 'name' : 'stack_size', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '200000', - 'help' : 'stack size per mthread', - 'doc' : ''' -Size in bytes of the stack of each mthread. - ''', - }, - { - 'name' : 'statistics_interval', - 'section' : 'logging', - 'type' : LType.Uint64, - 'default' : '1800', - 'help' : 'Number of seconds between printing of recursor statistics, 0 to disable', - 'doc' : ''' -Interval between logging statistical summary on recursor performance. -Use 0 to disable. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'stats_api_blacklist', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128', - 'help' : 'List of statistics that are disabled when retrieving the complete list of statistics via the API (deprecated)', - 'docdefault': '', - 'doc' : '', - 'versionadded': '4.2.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-stats-api-disabled-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'stats_api_disabled_list', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128', - 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*', - 'help' : 'List of statistics that are disabled when retrieving the complete list of statistics via the API', - 'doc' : ''' -A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons. -These statistics can still be retrieved individually by specifically asking for it. - ''', - 'doc-new' : ''' -A sequence of statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons. -These statistics can still be retrieved individually by specifically asking for it. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'stats_carbon_blacklist', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': '', - 'help' : 'List of statistics that are prevented from being exported via Carbon (deprecated)', - 'doc' : '', - 'versionadded': '4.2.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-stats-carbon-disabled-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'stats_carbon_disabled_list', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*', - 'help' : 'List of statistics that are prevented from being exported via Carbon', - 'doc' : ''' -A list of comma-separated statistic names, that are prevented from being exported via carbon for performance reasons. - ''', - 'doc-new' : ''' -A sequence of statistic names, that are prevented from being exported via carbon for performance reasons. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'stats_rec_control_blacklist', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': '', - 'help' : 'List of statistics that are prevented from being exported via rec_control get-all (deprecated)', - 'doc' : '', - 'versionadded': '4.2.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-stats-rec-control-disabled-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'stats_rec_control_disabled_list', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*', - 'help' : 'List of statistics that are prevented from being exported via rec_control get-all', - 'doc' : ''' -A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons. -These statistics can still be retrieved individually. - ''', - 'doc-new' : ''' -A sequence of statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons. -These statistics can still be retrieved individually. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'stats_ringbuffer_entries', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '10000', - 'help' : 'maximum number of packets to store statistics for', - 'doc' : ''' -Number of entries in the remotes ringbuffer, which keeps statistics on who is querying your server. -Can be read out using ``rec_control top-remotes``. - ''', - }, - { - 'name' : 'stats_snmp_blacklist', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': '', - 'help' : 'List of statistics that are prevented from being exported via SNMP (deprecated)', - 'doc' : '', - 'versionadded': '4.2.0', - 'deprecated': ('4.5.0', 'Use :ref:`setting-stats-snmp-disabled-list`.'), - 'skip-yaml': True, - }, - { - 'name' : 'stats_snmp_disabled_list', - 'section' : 'recursor', - 'type' : LType.ListStrings, - 'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count', - 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*', - 'help' : 'List of statistics that are prevented from being exported via SNMP', - 'doc' : ''' -A list of comma-separated statistic names, that are prevented from being exported via SNMP, for performance reasons. - ''', - 'doc-new' : ''' -A sequence of statistic names, that are prevented from being exported via SNMP, for performance reasons. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'structured_logging', - 'section' : 'logging', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Prefer structured logging', - 'doc' : ''' -Prefer structured logging when both an old style and a structured log messages is available. - ''', - 'versionadded': '4.6.0', - 'versionchanged': ('5.0.0', 'Disabling structured logging is deprecated'), - 'versionchanged': ('5.1.0', 'Disabling structured logging is not supported'), - }, - { - 'name' : 'structured_logging_backend', - 'section' : 'logging', - 'type' : LType.String, - 'default' : 'default', - 'help' : 'Structured logging backend', - 'doc' : ''' -The backend used for structured logging output. -This setting must be set on the command line (``--structured-logging-backend=...``) to be effective. -Available backends are: - -- ``default``: use the traditional logging system to output structured logging information. -- ``systemd-journal``: use systemd-journal. - When using this backend, provide ``-o verbose`` or simular output option to ``journalctl`` to view the full information. -- ``json``: JSON objects are written to the standard error stream. - -See :doc:`appendices/structuredlogging` for more details. - ''', - 'versionadded': '4.8.0', - 'versionchanged': ('5.1.0', 'The JSON backend was added') - }, - { - 'name' : 'tcp_fast_open', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size', - 'doc' : ''' -Enable TCP Fast Open support, if available, on the listening sockets. -The numerical value supplied is used as the queue size, 0 meaning disabled. See :ref:`tcp-fast-open-support`. - ''', - 'versionadded': '4.1.0' - }, - { - 'name' : 'tcp_fast_open_connect', - 'section' : 'outgoing', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Enable TCP Fast Open support on outgoing sockets', - 'doc' : ''' -Enable TCP Fast Open Connect support, if available, on the outgoing connections to authoritative servers. See :ref:`tcp-fast-open-support`. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'tcp_max_idle_ms', - 'section' : 'outgoing', - 'oldname' : 'tcp-out-max-idle-ms', - 'type' : LType.Uint64, - 'default' : '10000', - 'help' : 'Time TCP/DoT connections are left idle in milliseconds or 0 if no limit', - 'doc' : ''' -Time outgoing TCP/DoT connections are left idle in milliseconds or 0 if no limit. After having been idle for this time, the connection is eligible for closing. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'tcp_max_idle_per_auth', - 'section' : 'outgoing', - 'oldname' : 'tcp-out-max-idle-per-auth', - 'type' : LType.Uint64, - 'default' : '10', - 'help' : 'Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open', - 'doc' : ''' -Maximum number of idle outgoing TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'tcp_max_queries', - 'section' : 'outgoing', - 'oldname' : 'tcp-out-max-queries', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Maximum total number of queries per TCP/DoT connection, 0 means no limit', - 'doc' : ''' -Maximum total number of queries per outgoing TCP/DoT connection, 0 means no limit. After this number of queries, the connection is -closed and a new one will be created if needed. - ''', - }, - { - 'name' : 'tcp_max_idle_per_thread', - 'section' : 'outgoing', - 'oldname' : 'tcp-out-max-idle-per-thread', - 'type' : LType.Uint64, - 'default' : '100', - 'help' : 'Maximum number of idle TCP/DoT connections per thread', - 'doc' : ''' -Maximum number of idle outgoing TCP/DoT connections per thread, 0 means do not keep idle connections open. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'threads', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '2', - 'help' : 'Launch this number of threads', - 'doc' : ''' -Spawn this number of threads on startup. - ''', - }, - { - 'name' : 'tcp_threads', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '1', - 'help' : 'Launch this number of threads listening for and processing TCP queries', - 'doc' : ''' -Spawn this number of TCP processing threads on startup. - ''', - 'versionadded': '5.0.0' - }, - { - 'name' : 'trace', - 'section' : 'logging', - 'type' : LType.String, - 'default' : 'no', - 'help' : 'if we should output heaps of logging. set to \'fail\' to only log failing domains', - 'doc' : ''' -One of ``no``, ``yes`` or ``fail``. -If turned on, output impressive heaps of logging. -May destroy performance under load. -To log only queries resulting in a ``ServFail`` answer from the resolving process, this value can be set to ``fail``, but note that the performance impact is still large. -Also note that queries that do produce a result but with a failing DNSSEC validation are not written to the log - ''', - }, - { - 'name' : 'udp_source_port_min', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '1024', - 'help' : 'Minimum UDP port to bind on', - 'doc' : ''' -This option sets the low limit of UDP port number to bind on. - -In combination with :ref:`setting-udp-source-port-max` it configures the UDP -port range to use. Port numbers are randomized within this range on -initialization, and exceptions can be configured with :ref:`setting-udp-source-port-avoid` - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'udp_source_port_max', - 'section' : 'outgoing', - 'type' : LType.Uint64, - 'default' : '65535', - 'help' : 'Maximum UDP port to bind on', - 'doc' : ''' -This option sets the maximum limit of UDP port number to bind on. - -See :ref:`setting-udp-source-port-min`. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'udp_source_port_avoid', - 'section' : 'outgoing', - 'type' : LType.ListStrings, - 'default' : '4791,11211', - 'help' : 'List of comma separated UDP port numbers to avoid', - 'doc' : ''' -A list of comma-separated UDP port numbers to avoid when binding. -Ex: `4791,5300,11211` - -See :ref:`setting-udp-source-port-min`. - ''', - 'doc-new' : ''' -A sequence of UDP port numbers to avoid when binding. For example: - -.. code-block:: yaml - - outgoing: - udp_source_port_avoid: - - 4791 - - 5300 - - 11211 - -See :ref:`setting-udp-source-port-min`. - ''', - 'versionadded': '4.2.0', - 'versionchanged': ('5.2.0', 'port 4791 was added to the default list'), - }, - { - 'name' : 'udp_truncation_threshold', - 'section' : 'incoming', - 'type' : LType.Uint64, - 'default' : '1232', - 'help' : 'Maximum UDP response size before we truncate', - 'doc' : ''' -EDNS0 allows for large UDP response datagrams, which can potentially raise performance. -Large responses however also have downsides in terms of reflection attacks. -This setting limits the accepted size. -Maximum value is 65535, but values above 4096 should probably not be attempted. - -To know why 1232, see the note at :ref:`setting-edns-outgoing-bufsize`. - ''', - 'versionchanged': ('4.2.0', 'Before 4.2.0, the default was 1680.') - }, - { - 'name' : 'unique_response_tracking', - 'section' : 'nod', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Track unique responses (tuple of query name, type and RR).', - 'doc' : ''' -Whether to track unique DNS responses, i.e. never seen before combinations -of the triplet (query name, query type, RR[rrname, rrtype, rrdata]). -This can be useful for tracking potentially suspicious domains and -behaviour, e.g. DNS fast-flux. -If protobuf is enabled and configured, then the Protobuf Response message -will contain a flag with udr set to true for each RR that is considered -unique, i.e. never seen before. -This feature uses a probabilistic data structure (stable bloom filter) to -track unique responses, which can have false positives as well as false -negatives, thus it is a best-effort feature. Increasing the number of cells -in the SBF using the unique-response-db-size setting can reduce FPs and FNs. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'unique_response_log', - 'section' : 'nod', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Log unique responses', - 'doc' : ''' -Whether to log when a unique response is detected. The log line -looks something like: - -Oct 24 12:11:27 Unique response observed: qname=foo.com qtype=A rrtype=AAAA rrname=foo.com rrcontent=1.2.3.4 - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'unique_response_db_size', - 'section' : 'nod', - 'type' : LType.Uint64, - 'default' : '67108864', - 'help' : 'Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864', - 'doc' : ''' -The default size of the stable bloom filter used to store previously -observed responses is 67108864. To change the number of cells, use this -setting. For each cell, the SBF uses 1 bit of memory, and one byte of -disk for the persistent file. -If there are already persistent files saved to disk, this setting will -have no effect unless you remove the existing files. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'unique_response_history_dir', - 'section' : 'nod', - 'type' : LType.String, - 'default' : 'NODCACHEDIRUDR', - 'docdefault': 'Determined by distribution', - 'help' : 'Persist unique response tracking data here to persist between restarts', - 'doc' : ''' -This setting controls which directory is used to store the on-disk -cache of previously observed responses. - -The default depends on ``LOCALSTATEDIR`` when building the software. -Usually this comes down to ``/var/lib/pdns-recursor/udr`` or ``/usr/local/var/lib/pdns-recursor/udr``). - -The newly observed domain feature uses a stable bloom filter to store -a history of previously observed responses. The data structure is -synchronized to disk every 10 minutes, and is also initialized from -disk on startup. This ensures that previously observed responses are -preserved across recursor restarts. If you change the -unique-response-db-size, you must remove any files from this directory. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'unique_response_pb_tag', - 'section' : 'nod', - 'type' : LType.String, - 'default' : 'pdns-udr', - 'help' : 'If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to \'pdns-udr\'', - 'doc' : ''' -If protobuf is configured, then this tag will be added to all protobuf response messages when -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', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Pass along received EDNS Client Subnet information', - 'doc' : ''' -Whether to process and pass along a received EDNS Client Subnet to authoritative servers. -The ECS information will only be sent for netmasks and domains listed in :ref:`setting-edns-subnet-allow-list` and will be truncated if the received scope exceeds :ref:`setting-ecs-ipv4-bits` for IPv4 or :ref:`setting-ecs-ipv6-bits` for IPv6. - ''', - }, - { - 'name' : 'version', - 'section' : 'commands', - 'type' : LType.Command, - 'default' : 'no', - 'help' : 'Print version string', - 'doc' : ''' -Print version of this binary. Useful for checking which version of the PowerDNS recursor is installed on a system. - ''', - }, - { - 'name' : 'version_string', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : RUNTIME, - 'help' : 'string reported on version.pdns or version.bind', - 'doc' : ''' -By default, PowerDNS replies to the 'version.bind' query with its version number. -Security conscious users may wish to override the reply PowerDNS issues. - ''', - }, - { - 'name' : 'webserver', - 'section' : 'webservice', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Start a webserver (for REST API)', - 'doc' : ''' -Start the webserver (for REST API). - ''', - }, - { - 'name' : 'address', - 'section' : 'webservice', - 'oldname' : 'webserver-address', - 'type' : LType.String, - 'default' : '127.0.0.1', - 'help' : 'IP Address of webserver to listen on', - 'doc' : ''' -IP address for the webserver to listen on. - ''', - }, - { - 'name' : 'allow_from', - 'section' : 'webservice', - 'oldname' : 'webserver-allow-from', - 'type' : LType.ListSubnets, - 'default' : '127.0.0.1, ::1', - 'help' : 'Webserver access is only allowed from these subnets', - 'doc' : ''' -These IPs and subnets are allowed to access the webserver. Note that -specifying an IP address without a netmask uses an implicit netmask -of /32 or /128. - ''', - 'versionchanged': ('4.1.0', 'Default is now 127.0.0.1,::1, was 0.0.0.0/0,::/0 before.') - }, - { - 'name' : 'hash_plaintext_credentials', - 'section' : 'webservice', - 'oldname': 'webserver-hash-plaintext-credentials', - 'type' : LType.Bool, - 'default' : 'false', - 'help' : 'Whether to hash passwords and api keys supplied in plaintext, to prevent keeping the plaintext version in memory at runtime', - 'doc' : ''' -Whether passwords and API keys supplied in the configuration as plaintext should be hashed during startup, to prevent the plaintext versions from staying in memory. Doing so increases significantly the cost of verifying credentials and is thus disabled by default. -Note that this option only applies to credentials stored in the configuration as plaintext, but hashed credentials are supported without enabling this option. - ''', - 'versionadded': '4.6.0' - }, - { - 'name' : 'loglevel', - 'section' : 'webservice', - 'oldname' : 'webserver-loglevel', - 'type' : LType.String, - 'default' : 'normal', - 'help' : 'Amount of logging in the webserver (none, normal, detailed)', - 'doc' : ''' -One of ``none``, ``normal``, ``detailed``. -The amount of logging the webserver must do. 'none' means no useful webserver information will be logged. -When set to 'normal', the webserver will log a line per request that should be familiar:: - - [webserver] e235780e-a5cf-415e-9326-9d33383e739e 127.0.0.1:55376 'GET /api/v1/servers/localhost/bla HTTP/1.1' 404 196 - -When set to 'detailed', all information about the request and response are logged:: - - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Request Details: - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Headers: - [webserver] e235780e-a5cf-415e-9326-9d33383e739e accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e accept-encoding: gzip, deflate - [webserver] e235780e-a5cf-415e-9326-9d33383e739e accept-language: en-US,en;q=0.5 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e connection: keep-alive - [webserver] e235780e-a5cf-415e-9326-9d33383e739e dnt: 1 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e host: 127.0.0.1:8081 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e upgrade-insecure-requests: 1 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e user-agent: Mozilla/5.0 (X11; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e No body - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Response details: - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Headers: - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Connection: close - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Content-Length: 49 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Content-Type: text/html; charset=utf-8 - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Server: PowerDNS/0.0.15896.0.gaba8bab3ab - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Full body: - [webserver] e235780e-a5cf-415e-9326-9d33383e739e Not Found

Not Found

- [webserver] e235780e-a5cf-415e-9326-9d33383e739e 127.0.0.1:55376 'GET /api/v1/servers/localhost/bla HTTP/1.1' 404 196 - -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. - ''', - 'versionadded': '4.2.0' - }, - { - 'name' : 'password', - 'section' : 'webservice', - 'oldname' : 'webserver-password', - 'type' : LType.String, - 'default' : '', - 'help' : 'Password required for accessing the webserver', - 'doc' : ''' -Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``rec_control hash-password`` instead of being present in the configuration in plaintext, but the plaintext version is still supported. - ''', - 'versionchanged': ('4.6.0', 'This setting now accepts a hashed and salted version.') - }, - { - 'name' : 'port', - 'section' : 'webservice', - 'type' : LType.Uint64, - 'oldname': 'webserver-port', - 'default' : '8082', - 'help' : 'Port of webserver to listen on', - 'doc' : ''' -TCP port where the webserver should listen on. - ''', - }, - { - 'name' : 'write_pid', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Write a PID file', - 'doc' : ''' -If a PID file should be written to :ref:`setting-socket-dir` - ''', - }, - { - 'name' : 'x_dnssec_names', - 'section' : 'dnssec', - 'type' : LType.ListStrings, - 'default' : '', - 'help' : 'Collect DNSSEC statistics for names or suffixes in this list in separate x-dnssec counters', - 'doc' : ''' -List of names whose DNSSEC validation metrics will be counted in a separate set of metrics that start -with ``x-dnssec-result-``. -The names are suffix-matched. -This can be used to not count known failing (test) name validations in the ordinary DNSSEC metrics. - ''', - 'versionadded': '4.5.0' - }, - { - 'name' : 'system_resolver_ttl', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Set TTL of system resolver feature, 0 (default) is disabled', - 'doc' : ''' -Sets TTL in seconds of the system resolver feature. -If not equal to zero names can be used for forwarding targets. -The names will be resolved by the system resolver configured in the OS. - -The TTL is used as a time to live to see if the names used in forwarding resolve to a different address than before. -If the TTL is expired, a re-resolve will be done by the next iteration of the check function; -if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``. - -Make sure the recursor itself is not used by the system resolver! Default is 0 (not enabled). -A suggested value is 60. -''', - 'versionadded': '5.1.0' - }, - { - 'name' : 'system_resolver_interval', - 'section' : 'recursor', - 'type' : LType.Uint64, - 'default' : '0', - 'help' : 'Set interval (in seconds) of the re-resolve checks of system resolver subsystem.', - 'doc' : ''' -Sets the check interval (in seconds) of the system resolver feature. -All names known by the system resolver subsystem are periodically checked for changing values. - -If the TTL of a name has expired, it is checked by re-resolving it. -if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``. - -This settings sets the interval between the checks. -If set to zero (the default), the value :ref:`setting-system-resolver-ttl` is used. -''', - 'versionadded': '5.1.0' - }, - { - 'name' : 'system_resolver_self_resolve_check', - 'section' : 'recursor', - 'type' : LType.Bool, - 'default' : 'true', - 'help' : 'Check for potential self-resolve, default enabled.', - 'doc' : ''' -Warn on potential self-resolve. -If this check draws the wrong conclusion, you can disable it. -''', - 'versionadded': '5.1.0' - }, - { - 'name' : 'trustanchors', - 'section' : 'dnssec', - 'type' : LType.ListTrustAnchors, - 'default' : '[{name: ., dsrecords: [\'20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d\', \'38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16\']}]', - 'docdefault' : ''' - -.. code-block:: yaml - - - name: . - dsrecords: - - 20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d - - 38696 8 2 683d2d0acb8c9b712a1948b27f741219298d0a450d612c483af444a4c0fb2b16 - -''', - 'help' : 'Sequence of trust anchors', - 'doc' : ''' -Sequence of trust anchors. If the sequence contains an entry for the root zone, the default root zone trust anchor is not included. -If a zone appears multiple times, the entries in ``dsrecords`` are merged. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', - 'versionadded': '5.1.0', - 'runtime': ['add-ta', 'clear-ta', 'reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'negative_trustanchors', - 'section' : 'dnssec', - 'type' : LType.ListNegativeTrustAnchors, - 'default' : '', - 'help' : 'A sequence of negative trust anchors', - 'doc' : ''' -Sequence of negative trust anchors. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', - 'versionadded': '5.1.0', - 'runtime': ['add-nta', 'clear-nta', 'reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'trustanchorfile', - 'section' : 'dnssec', - 'type' : LType.String, - 'default' : '', - 'help' : 'A path to a zone file containing trust anchors', - 'doc' : ''' -A path to a zone file to read trust anchors from. -This can be used to read distribution provided trust anchors, as for instance ``/usr/share/dns/root.key`` from Debian's ``dns-root-data`` package. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'trustanchorfile_interval', - 'section' : 'dnssec', - 'type' : LType.Uint64, - 'default' : '24', - 'help' : 'Interval (in hours) to read the trust anchors file', - 'doc' : ''' -Interval (in hours) to re-read the ``trustanchorfile``. Zero disables periodic re-reads. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/dnssec`', - 'versionadded': '5.1.0', - }, - { - 'name' : 'protobuf_servers', - 'section' : 'logging', - 'type' : LType.ListProtobufServers, - 'default' : '', - 'help' : 'Sequence of protobuf servers', - 'doc' : ''' -Sequence of outgoing protobuf servers. Currently the maximum size of this list is one. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'outgoing_protobuf_servers', - 'section' : 'logging', - 'type' : LType.ListProtobufServers, - 'default' : '', - 'help' : 'List of outgoing protobuf servers', - 'doc' : ''' -Sequence of outgoing protobuf servers. Currently the maximum size of this list is one. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'protobuf_mask_v4', - 'section' : 'logging', - 'type' : LType.Uint64, - 'default' : '32', - 'help' : 'Network mask to apply for client IPv4 addresses in protobuf messages', - 'doc' : ''' -Network mask to apply to the client IPv4 addresses, for anonymization purposes. The default of 32 means no anonymization. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - }, - { - 'name' : 'protobuf_mask_v6', - 'section' : 'logging', - 'type' : LType.Uint64, - 'default' : '128', - 'help' : 'Network mask to apply for client IPv6 addresses in protobuf messages', - 'doc' : ''' -Network mask to apply to the client IPv6 addresses, for anonymization purposes. The default of 128 means no anonymization. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - }, - { - 'name' : 'dnstap_framestream_servers', - 'section' : 'logging', - 'type' : LType.ListDNSTapFrameStreamServers, - 'default' : '', - 'help' : 'Sequence of dnstap servers', - 'doc' : ''' -Sequence of dnstap servers. Currently the maximum size of this list is one. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'dnstap_nod_framestream_servers', - 'section' : 'logging', - 'type' : LType.ListDNSTapNODFrameStreamServers, - 'default' : '', - 'help' : 'Sequence of NOD dnstap servers', - 'doc' : ''' -Sequence of NOD dnstap servers. Currently the maximum size of this list is one. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/protobuf`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'sortlists', - 'section' : 'recursor', - 'type' : LType.ListSortLists, - 'default' : '', - 'help' : 'Sequence of sort lists', - 'doc' : ''' -Sequence of sort lists. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/sortlist`', - 'versionadded': '5.1.0', - }, - { - 'name' : 'rpzs', - 'section' : 'recursor', - 'type' : LType.ListRPZs, - 'default' : '', - 'help' : 'Sequence of RPZ entries', - 'doc' : ''' -Sequence of RPZ entries. - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/rpz`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'zonetocaches', - 'section' : 'recordcache', - 'type' : LType.ListZoneToCaches, - 'default' : '', - 'help' : 'Sequence of ZoneToCache entries ', - 'doc' : ''' -Sequence of ZoneToCache entries - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/ztc`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'allowed_additional_qtypes', - 'section' : 'recursor', - 'type' : LType.ListAllowedAdditionalQTypes, - 'default' : '', - 'help' : 'Sequence of AllowedAdditionalQType', - 'doc' : ''' -Sequence of AllowedAdditionalQType - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/additionals`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'proxymappings', - 'section' : 'incoming', - 'type' : LType.ListProxyMappings, - 'default' : '', - 'help' : 'Sequence of ProxyMapping', - 'doc' : ''' -Sequence of ProxyMapping - ''', - 'skip-old' : 'Equivalent Lua config in :doc:`lua-config/proxymapping`', - 'versionadded': '5.1.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, - { - 'name' : 'lua_start_stop_script', - 'section' : 'recursor', - 'type' : LType.String, - 'default' : '', - 'help' : 'Lua script containing functions to run on startup and shutdown', - 'doc' : ''' -Load this Lua script on startup and shutdown and run the Lua function ``on_recursor_start`` on startup and the Lua function ``on_recursor_stop`` on a ``nice`` shutdown (using ``rec_control quit-nicely`` of the :program:`Recursor` process. - ''', - 'skip-old' : 'No equivalent old-style setting', - 'versionadded': '5.2.0', - }, - { - 'name' : 'forwarding_catalog_zones', - 'section' : 'recursor', - 'type' : LType.ListForwardingCatalogZones, - 'default' : '', - 'help' : 'Sequence of ForwardingCatalogZone', - 'doc' : ''' -Sequence of ForwardingCatalogZone - ''', - 'skip-old' : 'No equivalent old style setting', - 'versionadded': '5.2.0', - 'runtime': ['reload-lua-config', 'reload-yaml'], - }, -] diff -Nru pdns-recursor-5.2.13/sholder.hh pdns-recursor-5.4.9/sholder.hh --- pdns-recursor-5.2.13/sholder.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/sholder.hh 2026-10-26 09:46:36.000000000 +0000 @@ -74,6 +74,17 @@ return *operator->(); } + // fast const-only access, see "read-only" above. + // if allowedOutdated is true, the current local version is returned + // without checking if there has been an update. + const T& get(bool allowedOutdated = false) + { + if (!allowedOutdated || !d_state) { + return *operator->(); + } + return *d_state; + } + void reset() { d_generation = 0; diff -Nru pdns-recursor-5.2.13/shuffle.cc pdns-recursor-5.4.9/shuffle.cc --- pdns-recursor-5.2.13/shuffle.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/shuffle.cc 2026-10-26 09:46:36.000000000 +0000 @@ -35,7 +35,7 @@ std::vector::iterator first; std::vector::iterator second; - // We assume the CNAMES are listed first in the ANSWER section and the the other records + // We assume the CNAMES are listed first in the ANSWER section and the other records // and we want to shuffle the other records only // First we scan for the first non-CNAME ANSWER record @@ -140,3 +140,49 @@ }); shuffle(rrs, includingAdditionals); } + +unsigned int pdns::dedupRecords(vector& rrs) +{ + // This function tries to avoid unnecessary work + // First a vector with zero or one element does not need dedupping + if (rrs.size() <= 1) { + return 0; + } + + // If we have a larger vector, first check if we actually have duplicates. + // We assume the most common case is: no + std::unordered_set seen; + std::vector dups(rrs.size(), false); + + unsigned int counter = 0; + unsigned int numDups = 0; + + seen.reserve(rrs.size()); + for (const auto& rec : rrs) { + auto key = rec.getContent()->serialize(rec.d_name, true, true, true); + // This ignores class, ttl and place by using constants for those + if (!seen.emplace(std::move(key)).second) { + dups[counter] = true; + numDups++; + } + ++counter; + } + + if (numDups == 0) { + // Original is fine as-is. + return 0; + } + + // We avoid calling erase, as it calls a lot of move constructors. This can hurt, especially if + // you call it on a large vector multiple times. + // So we just take the elements that are unique + std::vector ret; + ret.reserve(rrs.size() - numDups); + for (counter = 0; counter < rrs.size(); ++counter) { + if (!dups[counter]) { + ret.emplace_back(std::move(rrs[counter])); + } + } + rrs = std::move(ret); + return numDups; +} diff -Nru pdns-recursor-5.2.13/shuffle.hh pdns-recursor-5.4.9/shuffle.hh --- pdns-recursor-5.2.13/shuffle.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/shuffle.hh 2026-10-26 09:46:36.000000000 +0000 @@ -29,4 +29,5 @@ { void shuffle(std::vector& rrs); void orderAndShuffle(std::vector& rrs, bool includingAdditionals); +unsigned int dedupRecords(std::vector& rrs); } diff -Nru pdns-recursor-5.2.13/sillyrecords.cc pdns-recursor-5.4.9/sillyrecords.cc --- pdns-recursor-5.2.13/sillyrecords.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/sillyrecords.cc 2026-10-26 09:46:36.000000000 +0000 @@ -2,6 +2,7 @@ #include "config.h" #endif +#include #include #include "utility.hh" @@ -46,8 +47,7 @@ break; mantissa = cmval / poweroften[exponent]; - if (mantissa > 9) - mantissa = 9; + mantissa = std::min(mantissa, 9); retval = (mantissa << 4) | exponent; @@ -301,8 +301,6 @@ // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to: // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m - double latitude= ((int32_t)((uint32_t)d_latitude - ((uint32_t)1<<31)))/3600000.0; - double longitude=((int32_t)((uint32_t)d_longitude - ((uint32_t)1<<31)))/3600000.0; double altitude= ((int32_t)d_altitude )/100.0 - 100000; double size=0.01*((d_size>>4)&0xf); @@ -320,15 +318,43 @@ while(count--) vertpre*=10; - double remlat=60.0*(latitude-(int)latitude); - double remlong=60.0*(longitude-(int)longitude); - static const boost::format fmt("%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm"); + char hemLat = 'N'; + uint32_t lat = d_latitude; + if (lat >= 1U << 31) { + lat -= 1U << 31; + } + else { + hemLat = 'S'; + lat = (1U << 31) - lat; + } + auto fracLat = lat % 1000; + lat /= 1000; + auto secLat = lat % 60; + lat /= 60; + auto minutesLat = lat % 60; + auto degreesLat = lat / 60; + + char hemLon= 'E'; + uint32_t lon = d_longitude; + if (lon >= 1U << 31) { + lon -= 1U << 31; + } + else { + hemLon = 'W'; + lon = (1U << 31) - lon; + } + auto fracLon = lon % 1000; + lon /= 1000; + auto secLon = lon % 60; + lon /= 60; + auto minutesLon = lon % 60; + auto degreesLon = lon / 60; + + static const boost::format fmt("%d %d %d.%03d %c %d %d %d.%03d %c %.2fm %.2fm %.2fm %.2fm"); std::string ret = boost::str( boost::format(fmt) - % abs((int)latitude) % abs((int) ((latitude-(int)latitude)*60)) - % fabs((double)((remlat-(int)remlat)*60.0)) % (latitude>0 ? 'N' : 'S') - % abs((int)longitude) % abs((int) ((longitude-(int)longitude)*60)) - % fabs((double)((remlong-(int)remlong)*60.0)) % (longitude>0 ? 'E' : 'W') + % degreesLat % minutesLat % secLat % fracLat % hemLat + % degreesLon % minutesLon % secLon % fracLon % hemLon % altitude % size % horizpre % vertpre ); diff -Nru pdns-recursor-5.2.13/sodiumsigners.cc pdns-recursor-5.4.9/sodiumsigners.cc --- pdns-recursor-5.2.13/sodiumsigners.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/sodiumsigners.cc 2026-10-26 09:46:36.000000000 +0000 @@ -8,7 +8,7 @@ #include } #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" class SodiumED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine { @@ -210,7 +210,7 @@ { LoaderSodiumStruct() { - DNSCryptoKeyEngine::report(DNSSECKeeper::ED25519, &SodiumED25519DNSCryptoKeyEngine::maker); + DNSCryptoKeyEngine::report(DNSSEC::ED25519, &SodiumED25519DNSCryptoKeyEngine::maker); } } loadersodium; } diff -Nru pdns-recursor-5.2.13/sstuff.hh pdns-recursor-5.4.9/sstuff.hh --- pdns-recursor-5.2.13/sstuff.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/sstuff.hh 2026-10-26 09:46:36.000000000 +0000 @@ -121,7 +121,13 @@ { ComboAddress remote; if (getRemote(remote)) { - return netmaskGroup.match(remote); + if (netmaskGroup.match(remote)) { + return true; + } + + if (remote.isMappedIPv4()) { + return netmaskGroup.match(remote.mapToIPv4()); + } } return false; @@ -162,7 +168,8 @@ } //! Bind the socket to a specified endpoint - void bind(const ComboAddress& local, bool reuseaddr = true) const + template + void bind(const T& local, bool reuseaddr = true) const { int tmp = 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) @@ -178,7 +185,7 @@ //! Connect the socket to a specified endpoint void connect(const ComboAddress& address, int timeout = 0) const { - SConnectWithTimeout(d_socket, address, timeval{timeout, 0}); + SConnectWithTimeout(d_socket, false, address, timeval{timeout, 0}); } //! For datagram sockets, receive a datagram and learn where it came from @@ -327,33 +334,6 @@ } } - //! reads one character from the socket - [[nodiscard]] int getChar() const - { - char character{}; - - ssize_t res = ::recv(d_socket, &character, 1, 0); - if (res == 0) { - return character; - } - return -1; - } - - void getline(string& data) const - { - 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) { diff -Nru pdns-recursor-5.2.13/svc-records.cc pdns-recursor-5.4.9/svc-records.cc --- pdns-recursor-5.2.13/svc-records.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/svc-records.cc 2026-10-26 09:46:36.000000000 +0000 @@ -30,15 +30,20 @@ {"port", SvcParam::SvcParamKey::port}, {"ipv4hint", SvcParam::SvcParamKey::ipv4hint}, {"ech", SvcParam::SvcParamKey::ech}, - {"ipv6hint", SvcParam::SvcParamKey::ipv6hint} + {"ipv6hint", SvcParam::SvcParamKey::ipv6hint}, + {"dohpath", SvcParam::SvcParamKey::dohpath}, + {"ohttp", SvcParam::SvcParamKey::ohttp}, + {"tls-supported-groups", SvcParam::SvcParamKey::tls_supported_groups}, }; -SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k) { +SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k) +{ bool ignored; return SvcParam::keyFromString(k, ignored); } -SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k, bool &generic) { +SvcParam::SvcParamKey SvcParam::keyFromString(const std::string& k, bool& generic) +{ auto it = SvcParams.find(k); if (it != SvcParams.end()) { generic = false; @@ -55,7 +60,8 @@ throw std::invalid_argument("SvcParam '" + k + "' is not recognized or in keyNNNN format"); } -std::string SvcParam::keyToString(const SvcParam::SvcParamKey& k) { +std::string SvcParam::keyToString(const SvcParam::SvcParamKey& k) +{ auto ret = std::find_if(SvcParams.begin(), SvcParams.end(), [&](const std::pair& e) { return e.second == k; }); if (ret != SvcParams.end()) { return ret->first; @@ -63,16 +69,18 @@ return "key" + std::to_string(k); } -SvcParam::SvcParam(const SvcParamKey &key) { +SvcParam::SvcParam(const SvcParamKey& key) +{ d_key = key; - if (d_key != SvcParamKey::no_default_alpn) { + if (d_key != SvcParamKey::no_default_alpn && d_key != SvcParamKey::ohttp) { throw std::invalid_argument("can not create non-empty SvcParam for key '" + keyToString(key) + "'"); } } -SvcParam::SvcParam(const SvcParamKey &key, const std::string &value) { +SvcParam::SvcParam(const SvcParamKey& key, const std::string& value) +{ d_key = key; - if (d_key != SvcParamKey::ech && d_key < 7) { + if (d_key != SvcParamKey::ech && d_key != SvcParamKey::dohpath && d_key < 10) { throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string value"); } if (d_key == SvcParamKey::ech) { @@ -84,7 +92,8 @@ d_value = value; } -SvcParam::SvcParam(const SvcParamKey &key, std::vector &&value) { +SvcParam::SvcParam(const SvcParamKey& key, std::vector&& value) +{ d_key = key; if (d_key != SvcParamKey::alpn) { throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); @@ -94,19 +103,21 @@ } } -SvcParam::SvcParam(const SvcParamKey &key, std::set &&value) { +SvcParam::SvcParam(const SvcParamKey& key, std::set&& value) +{ d_key = key; if (d_key != SvcParamKey::mandatory) { throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a string-set value"); } if (d_key == SvcParamKey::mandatory) { - for (auto const &v: value) { + for (auto const& v : value) { d_mandatory.insert(keyFromString(v)); } } } -SvcParam::SvcParam(const SvcParamKey &key, std::set &&value) { +SvcParam::SvcParam(const SvcParamKey& key, std::set&& value) +{ d_key = key; if (d_key != SvcParamKey::mandatory) { throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a SvcParamKey-set value"); @@ -114,12 +125,13 @@ d_mandatory = std::move(value); } -SvcParam::SvcParam(const SvcParamKey &key, std::vector &&value) { +SvcParam::SvcParam(const SvcParamKey& key, std::vector&& value) +{ d_key = key; if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an IP address value"); } - for (auto const &addr : value) { + for (auto const& addr : value) { if (d_key == SvcParam::ipv6hint && !addr.isIPv6()) { throw std::invalid_argument("non-IPv6 address ('" + addr.toString() + "') passed for " + keyToString(key)); } @@ -130,57 +142,116 @@ d_ipHints = std::move(value); } -SvcParam::SvcParam(const SvcParamKey &key, const uint16_t value) { +SvcParam::SvcParam(const SvcParamKey& key, std::vector&& value) : + d_key(key) +{ + if (d_key != SvcParamKey::tls_supported_groups) { + throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a uint16 value-vector"); + } + d_tls_supported_groups = std::move(value); +} + +SvcParam::SvcParam(const SvcParamKey& key, const uint16_t value) +{ d_key = key; if (d_key != SvcParamKey::port) { - throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with an port value"); + throw std::invalid_argument("can not create SvcParam for " + keyToString(key) + " with a port value"); } d_port = value; } //! This ensures an std::set will be sorted by key (section 2.2 mandates this for wire format) -bool SvcParam::operator<(const SvcParam& other) const { +bool SvcParam::operator<(const SvcParam& other) const +{ return this->d_key < other.getKey(); } -const std::vector& SvcParam::getIPHints() const { +bool SvcParam::operator==(const SvcParam& other) const +{ + if (this->getKey() != other.getKey()) { + return false; + } + switch (this->d_key) { + case SvcParamKey::mandatory: + return this->getMandatory() == other.getMandatory(); + case SvcParamKey::alpn: + return this->getALPN() == other.getALPN(); + case SvcParamKey::no_default_alpn: /* fallthrough */ + case SvcParamKey::ohttp: + return true; + case SvcParamKey::port: + return this->getPort() == other.getPort(); + case SvcParamKey::ipv4hint: /* fallthrough */ + case SvcParamKey::ipv6hint: + return (this->getIPHints() == other.getIPHints() && this->getAutoHint() == other.getAutoHint()); + case SvcParamKey::ech: + return this->getECH() == other.getECH(); + case SvcParamKey::dohpath: + return this->getValue() == other.getValue(); + case SvcParamKey::tls_supported_groups: + return this->getTLSSupportedGroups() == other.getTLSSupportedGroups(); + default: + return this->getValue() == other.getValue(); + } +} + +bool SvcParam::operator!=(const SvcParam& other) const +{ + return !(*this == other); +} + +const std::vector& SvcParam::getIPHints() const +{ if (d_key != SvcParamKey::ipv6hint && d_key != SvcParamKey::ipv4hint) { throw std::invalid_argument("getIPHints called for non-IP address key '" + keyToString(d_key) + "'"); } return d_ipHints; } -uint16_t SvcParam::getPort() const { +uint16_t SvcParam::getPort() const +{ if (d_key != SvcParam::port) { throw std::invalid_argument("getPort called for non-port key '" + keyToString(d_key) + "'"); } return d_port; } -const std::vector& SvcParam::getALPN() const { +const std::vector& SvcParam::getALPN() const +{ if (d_key != SvcParam::alpn) { throw std::invalid_argument("getALPN called for non-alpn key '" + keyToString(d_key) + "'"); } return d_alpn; } -const std::set& SvcParam::getMandatory() const { +const std::set& SvcParam::getMandatory() const +{ if (d_key != SvcParam::mandatory) { throw std::invalid_argument("getMandatory called for non-mandatory key '" + keyToString(d_key) + "'"); } return d_mandatory; } -const std::string& SvcParam::getECH() const { +const std::string& SvcParam::getECH() const +{ if (d_key != SvcParam::ech) { throw std::invalid_argument("getECH called for non-ech key '" + keyToString(d_key) + "'"); } return d_ech; } -const std::string& SvcParam::getValue() const { - if (d_key < 7) { +const std::string& SvcParam::getValue() const +{ + if (d_key != SvcParamKey::dohpath && d_key < 10) { throw std::invalid_argument("getValue called for non-single value key '" + keyToString(d_key) + "'"); } return d_value; } + +const std::vector& SvcParam::getTLSSupportedGroups() const +{ + if (d_key != SvcParam::tls_supported_groups) { + throw std::invalid_argument("getTLSSupportedGroups called for non-tls-supported-groups key '" + keyToString(d_key) + "'"); + } + return d_tls_supported_groups; +} diff -Nru pdns-recursor-5.2.13/svc-records.hh pdns-recursor-5.4.9/svc-records.hh --- pdns-recursor-5.2.13/svc-records.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/svc-records.hh 2026-10-26 09:46:36.000000000 +0000 @@ -25,58 +25,76 @@ #include #include "iputils.hh" -class SvcParam { - public: - enum SvcParamKey: uint16_t { - // TODO link to IANA registry - /* When adding new values, you *must* update SvcParam::SvcParam(const std::string &key, const std::string &value) - * in svc-record.cc with the new numbers - */ - mandatory = 0, - alpn = 1, - no_default_alpn = 2, - port = 3, - ipv4hint = 4, - ech = 5, - ipv6hint = 6 - }; +class SvcParam +{ +public: + enum SvcParamKey : uint16_t + { + // https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml#dns-svcparamkeys + /* When adding new values, you *must* update SvcParam::SvcParam(const std::string &key, const std::string &value) + * in svc-record.cc with the new numbers + */ + mandatory = 0, + alpn = 1, + no_default_alpn = 2, + port = 3, + ipv4hint = 4, + ech = 5, + ipv6hint = 6, + dohpath = 7, + ohttp = 8, + tls_supported_groups = 9, /* https://datatracker.ietf.org/doc/draft-ietf-tls-key-share-prediction/ */ + }; //! empty Param, unusable SvcParam() = delete; //! To create a value-less SvcParam (like no-default-alpn) - SvcParam(const SvcParamKey &key); + SvcParam(const SvcParamKey& key); //! To create a "generic" SvcParam (for keyNNNNN and ech) - SvcParam(const SvcParamKey &key, const std::string &value); + SvcParam(const SvcParamKey& key, const std::string& value); //! To create a multi-value SvcParam (like mandatory) - SvcParam(const SvcParamKey &key, std::set &&value); + SvcParam(const SvcParamKey& key, std::set&& value); //! To create a multi-value SvcParam (like alpn) - SvcParam(const SvcParamKey &key, std::vector &&value); + SvcParam(const SvcParamKey& key, std::vector&& value); //! To create a multi-value SvcParam with key values (like mandatory) - SvcParam(const SvcParamKey &key, std::set &&value); + SvcParam(const SvcParamKey& key, std::set&& value); - //! To create and ipv{4,6}hists SvcParam - SvcParam(const SvcParamKey &key, std::vector &&value); + //! To create an ipv{4,6}hints SvcParam + SvcParam(const SvcParamKey& key, std::vector&& value); + + //! To create a tls-supported-groups SvcParam + SvcParam(const SvcParamKey& key, std::vector&& value); //! To create a port SvcParam - SvcParam(const SvcParamKey &key, const uint16_t value); + SvcParam(const SvcParamKey& key, const uint16_t value); //! Returns the SvcParamKey based on the input - static SvcParamKey keyFromString(const std::string &k); + static SvcParamKey keyFromString(const std::string& k); //! Returns the SvcParamKey based on the input, generic is true when the format was 'keyNNNN' - static SvcParamKey keyFromString(const std::string &k, bool &generic); + static SvcParamKey keyFromString(const std::string& k, bool& generic); //! Returns the string value of the SvcParamKey - static std::string keyToString(const SvcParamKey &k); + static std::string keyToString(const SvcParamKey& k); + + bool operator<(const SvcParam& other) const; + + bool operator==(const SvcParam& other) const; - bool operator< (const SvcParam &other) const; + bool operator!=(const SvcParam& other) const; + + bool operator==(const SvcParamKey& key) const + { + return key == d_key; + } - SvcParamKey getKey() const { + SvcParamKey getKey() const + { return d_key; } @@ -86,23 +104,25 @@ const std::set& getMandatory() const; const std::string& getECH() const; const std::string& getValue() const; + const std::vector& getTLSSupportedGroups() const; bool getAutoHint() const { return d_autohint; }; void setAutoHint(const bool value) { d_autohint = value; }; - private: - SvcParamKey d_key; - std::string d_value; // For keyNNNNN vals - - std::vector d_alpn; // For ALPN - std::set d_mandatory; // For mandatory - std::vector d_ipHints; // For ipv{6,4}hints - std::string d_ech; // For Encrypted Client Hello - uint16_t d_port{0}; // For port - - // Set to true if we encountered an "auto" field in hints - // Can only be true when we read SVCParams from text - bool d_autohint{false}; +private: + SvcParamKey d_key; + std::string d_value; // For keyNNNNN vals + + std::vector d_alpn; // For ALPN + std::set d_mandatory; // For mandatory + std::vector d_ipHints; // For ipv{6,4}hints + std::string d_ech; // For Encrypted Client Hello + std::vector d_tls_supported_groups; // For tls-supported-groups + uint16_t d_port{0}; // For port + + // Set to true if we encountered an "auto" field in hints + // Can only be true when we read SVCParams from text + bool d_autohint{false}; - static const std::map SvcParams; + static const std::map SvcParams; }; diff -Nru pdns-recursor-5.2.13/syncres.cc pdns-recursor-5.4.9/syncres.cc --- pdns-recursor-5.2.13/syncres.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/syncres.cc 2026-10-26 08:26:51.000000000 +0000 @@ -19,6 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #ifdef HAVE_CONFIG_H #include @@ -36,9 +37,11 @@ #include "lua-recursor4.hh" #include "rec-lua-conf.hh" #include "syncres.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include "validate-recursor.hh" #include "rec-taskqueue.hh" +#include "shuffle.hh" +#include "rec-nsspeeds.hh" rec::GlobalCounters g_Counters; thread_local rec::TCounters t_Counters(g_Counters); @@ -115,135 +118,19 @@ cont_t d_cont; }; -/** Class that implements a decaying EWMA. - This class keeps an exponentially weighted moving average which, additionally, decays over time. - The decaying is only done on get. -*/ +static LockGuarded s_nsSpeeds; -//! This represents a number of decaying Ewmas, used to store performance per nameserver-name. -/** Modelled to work mostly like the underlying DecayingEwma */ -class DecayingEwmaCollection +size_t SyncRes::getNSSpeedTable(size_t maxSize, std::string& ret) { -private: - struct DecayingEwma - { - public: - void submit(int arg, const struct timeval& last, const struct timeval& now) - { - d_last = arg; - auto val = static_cast(arg); - if (d_val == 0) { - d_val = val; - } - else { - auto diff = makeFloat(last - now); - auto factor = expf(diff) / 2.0F; // might be '0.5', or 0.0001 - d_val = (1.0F - factor) * val + factor * d_val; - } - } - - float get(float factor) - { - return d_val *= factor; - } - - [[nodiscard]] float peek() const - { - return d_val; - } - - [[nodiscard]] int last() const - { - return d_last; - } - - float d_val{0}; - int d_last{0}; - }; - -public: - DecayingEwmaCollection(DNSName name, const struct timeval val = {0, 0}) : - d_name(std::move(name)), d_lastget(val) - { - } - - void submit(const ComboAddress& remote, int usecs, const struct timeval& now) const - { - d_collection[remote].submit(usecs, d_lastget, now); - } - - float getFactor(const struct timeval& now) const - { - float diff = makeFloat(d_lastget - now); - return expf(diff / 60.0F); // is 1.0 or less - } - - bool stale(time_t limit) const - { - return limit > d_lastget.tv_sec; - } - - void purge(const std::map& keep) const - { - for (auto iter = d_collection.begin(); iter != d_collection.end();) { - if (keep.find(iter->first) != keep.end()) { - ++iter; - } - else { - iter = d_collection.erase(iter); - } - } - } - - // d_collection is the modifyable part of the record, we index on DNSName and timeval, and DNSName never changes - mutable std::map d_collection; - DNSName d_name; - struct timeval d_lastget; -}; + const auto copy = *s_nsSpeeds.lock(); + return copy.getPB(s_serverID, maxSize, ret); +} -class nsspeeds_t : public multi_index_container, member>, - ordered_non_unique, member>>> +size_t SyncRes::putIntoNSSpeedTable(const std::string& ret) { -public: - const auto& find_or_enter(const DNSName& name, const struct timeval& now) - { - const auto iter = insert(DecayingEwmaCollection{name, now}).first; - return *iter; - } - - const auto& find_or_enter(const DNSName& name) - { - const auto iter = insert(DecayingEwmaCollection{name}).first; - return *iter; - } - - float fastest(const DNSName& name, const struct timeval& now) - { - auto& ind = get(); - auto iter = insert(DecayingEwmaCollection{name, now}).first; - if (iter->d_collection.empty()) { - return 0; - } - // This could happen if find(DNSName) entered an entry; it's used only by test code - if (iter->d_lastget.tv_sec == 0 && iter->d_lastget.tv_usec == 0) { - ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; }); - } - - float ret = std::numeric_limits::max(); - const float factor = iter->getFactor(now); - for (auto& entry : iter->d_collection) { - if (float tmp = entry.second.get(factor); tmp < ret) { - ret = tmp; - } - } - ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; }); - return ret; - } -}; - -static LockGuarded s_nsSpeeds; + auto lock = s_nsSpeeds.lock(); + return lock->putPB(time(nullptr) - 300, ret); +} class Throttle { @@ -499,6 +386,7 @@ bool SyncRes::s_rootNXTrust; bool SyncRes::s_noEDNS; bool SyncRes::s_qnameminimization; +bool SyncRes::s_outAnyToTcp; SyncRes::HardenNXD SyncRes::s_hardenNXD; unsigned int SyncRes::s_refresh_ttlperc; unsigned int SyncRes::s_locked_ttlperc; @@ -764,7 +652,10 @@ /** everything begins here - this is the entry point just after receiving a packet */ int SyncRes::beginResolve(const DNSName& qname, const QType qtype, QClass qclass, vector& ret, unsigned int depth) { - d_eventTrace.add(RecEventTrace::SyncRes); + auto newParent = d_eventTrace.add(RecEventTrace::SyncRes); + auto oldParent = d_eventTrace.setParent(newParent); + RecEventTrace::EventScope traceScope(oldParent, d_eventTrace); + d_wasVariable = false; d_wasOutOfBand = false; d_cutStates.clear(); @@ -819,7 +710,7 @@ d_wasVariable = true; } } - d_eventTrace.add(RecEventTrace::SyncRes, res, false); + traceScope.close(res); return res; } @@ -896,6 +787,7 @@ ans << "\""; answers.emplace_back(QType::TXT, ans.str()); } + d_wasVariable = true; } } @@ -908,11 +800,12 @@ ans << "\""; ans << negAnchor.first.toString(); // Explicit toString to have a trailing dot if (negAnchor.second.length() != 0) { - ans << " " << negAnchor.second; + ans << " " << txtEscape(negAnchor.second); } ans << "\""; answers.emplace_back(QType::TXT, ans.str()); } + d_wasVariable = true; } } @@ -942,7 +835,7 @@ if (ziter != d_records.end()) { DNSRecord dnsRecord = *ziter; dnsRecord.d_place = DNSResourceRecord::AUTHORITY; - records.push_back(dnsRecord); + records.push_back(std::move(dnsRecord)); } } @@ -1000,7 +893,7 @@ // we hit a delegation point! DNSRecord dnsRecord = *ziter; dnsRecord.d_place = DNSResourceRecord::AUTHORITY; - records.push_back(dnsRecord); + records.push_back(std::move(dnsRecord)); } } @@ -1028,7 +921,7 @@ if (dnsRecord.d_type == qtype || qtype == QType::ANY || dnsRecord.d_type == QType::CNAME) { dnsRecord.d_name = qname; dnsRecord.d_place = DNSResourceRecord::ANSWER; - records.push_back(dnsRecord); + records.push_back(std::move(dnsRecord)); } } @@ -1049,7 +942,7 @@ for (ziter = range.first; ziter != range.second; ++ziter) { DNSRecord dnsRecord = *ziter; dnsRecord.d_place = DNSResourceRecord::AUTHORITY; - records.push_back(dnsRecord); + records.push_back(std::move(dnsRecord)); } } @@ -1107,9 +1000,7 @@ const char* isoDateTimeMillis(const struct timeval& tval, timebuf_t& buf) { const std::string s_timestampFormat = "%Y-%m-%dT%T"; - struct tm tmval - { - }; + struct tm tmval{}; size_t len = strftime(buf.data(), buf.size(), s_timestampFormat.c_str(), localtime_r(&tval.tv_sec, &tmval)); if (len == 0) { int ret = snprintf(buf.data(), buf.size(), "%lld", static_cast(tval.tv_sec)); @@ -1126,22 +1017,6 @@ return buf.data(); } -static const char* timestamp(time_t arg, timebuf_t& buf) -{ - const std::string s_timestampFormat = "%Y-%m-%dT%T"; - struct tm tmval - { - }; - size_t len = strftime(buf.data(), buf.size(), s_timestampFormat.c_str(), localtime_r(&arg, &tmval)); - if (len == 0) { - int ret = snprintf(buf.data(), buf.size(), "%lld", static_cast(arg)); - if (ret < 0 || static_cast(ret) >= buf.size()) { - buf[0] = '\0'; - } - } - return buf.data(); -} - struct ednsstatus_t : public multi_index_container, member>, @@ -1467,7 +1342,7 @@ close(newfd); return 0; } - fprintf(filePtr.get(), "; dump of saved parent nameserver sets succesfully used follows\n"); + fprintf(filePtr.get(), "; dump of saved parent nameserver sets successfully used follows\n"); fprintf(filePtr.get(), "; total entries: %zu\n", s_savedParentNSSet.lock()->size()); fprintf(filePtr.get(), "; domain\tsuccess\tttd\n"); uint64_t count = 0; @@ -1551,7 +1426,7 @@ For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish. */ -LWResult::Result SyncRes::asyncresolveWrapper(const ComboAddress& address, bool ednsMANDATORY, const DNSName& domain, [[maybe_unused]] const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional& srcmask, LWResult* res, bool* chained, const DNSName& nsName) const +LWResult::Result SyncRes::asyncresolveWrapper(const OptLog& log, const ComboAddress& address, bool ednsMANDATORY, const DNSName& domain, [[maybe_unused]] const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, std::optional& srcmask, LWResult* res, bool* chained, const DNSName& nsName) const { /* what is your QUEST? the goal is to get as many remotes as possible on the best level of EDNS support @@ -1587,10 +1462,7 @@ int EDNSLevel = 0; auto luaconfsLocal = g_luaconfs.getLocal(); - ResolveContext ctx(d_initialRequestId, nsName); -#ifdef HAVE_FSTRM - ctx.d_auth = auth; -#endif + ResolveContext ctx(d_initialRequestId, nsName, auth); LWResult::Result ret{}; @@ -1616,7 +1488,7 @@ ret = d_asyncResolve(address, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, res, chained); } else { - ret = asyncresolve(address, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, d_frameStreamServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained); + ret = asyncresolve(log, address, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, d_frameStreamServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained); } if (ret == LWResult::Result::PermanentError || LWResult::isLimitError(ret) || ret == LWResult::Result::Spoofed) { @@ -1634,12 +1506,24 @@ auto lock = s_ednsstatus.lock(); // all three branches below need a lock // Determine new mode + if (ret == LWResult::Result::BindError) { + // BindError is only generated when cookies are active and we failed to bind to a local + // address associated with a cookie, see RFC9018 section 3 last paragraph. We assume the + // called code has already erased the cookie info. + // This is the first path that re-iterates the loop + continue; + } + if (res->d_validpacket && res->d_haveEDNS && ret == LWResult::Result::BadCookie) { + // We assume the received cookie was stored and will be used in the second iteration + // This is the second path that re-iterates the loop + continue; + } if (res->d_validpacket && !res->d_haveEDNS && res->d_rcode == RCode::FormErr) { mode = EDNSStatus::NOEDNS; auto ednsstatus = lock->insert(address).first; auto& ind = lock->get(); lock->setMode(ind, ednsstatus, mode, d_now.tv_sec); - // This is the only path that re-iterates the loop + // This is the third path that re-iterates the loop continue; } if (!res->d_haveEDNS) { @@ -1741,7 +1625,7 @@ try { // The cache lookup below can have three types of result: // Case 1: successful. In that case the records will be added to the end result below and we're done. - // Case 2: unsuccessful. In that case the records in retq wil be discarded. E.g. there + // Case 2: unsuccessful. In that case the records in retq will be discarded. E.g. there // might be records as the lookup found a CNAME chain, but the target is missing from the cache. // Case 3: an exception is thrown, in that case we're still interested in the (partial) results in retq. // This can e.g. happen on a too-long CNAME chain. @@ -1783,7 +1667,7 @@ for (int tries = 0; tries < 2 && bestns.empty(); ++tries) { bool flawedNSSet = false; set beenthereIgnored; - getBestNSFromCache(nsdomain, qtype, bestns, &flawedNSSet, depth, prefix, beenthereIgnored, boost::make_optional(forwarded, fwdomain)); + getBestNSFromCache(nsdomain, qtype, bestns, &flawedNSSet, depth, prefix, beenthereIgnored, forwarded ? std::make_optional(fwdomain) : std::nullopt); if (forwarded) { break; } @@ -1908,6 +1792,32 @@ return bound; } +static bool haveFinalAnswer(const DNSName& qname, QType qtype, int res, const vector& ret) +{ + if (res != RCode::NoError) { + return false; + } + + // This loop assumes the CNAME's records are in-order + DNSName target(qname); + for (const auto& record : ret) { + if (record.d_place == DNSResourceRecord::ANSWER && record.d_name == target) { + if (record.d_type == qtype) { + return true; + } + if (record.d_type == QType::CNAME) { + if (auto ptr = getRR(record)) { + target = ptr->getTarget(); + } + else { + return false; + } + } + } + } + return false; +} + /*! This function will check the cache and go out to the internet if the answer is not in cache * * \param qname The name we need an answer for @@ -2015,6 +1925,11 @@ } } } + // This handles the case mentioned above: if the full CNAME chain leading to the answer was + // constructed from the cache, indicate that. + if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) { + *fromCache = true; + } return res; } @@ -2064,7 +1979,9 @@ } } } - + if (fromCache != nullptr && !*fromCache && haveFinalAnswer(qname, qtype, res, ret)) { + *fromCache = true; + } return res; } } @@ -2227,6 +2144,7 @@ bool oldRequireAuthData = d_requireAuthData; bool oldValidationRequested = d_DNSSECValidationRequested; bool oldFollowCNAME = d_followCNAME; + bool oldWasOutOfBand = wasOutOfBand(); bool seenV6 = false; const unsigned int startqueries = d_outqueries; d_requireAuthData = false; @@ -2296,6 +2214,7 @@ d_DNSSECValidationRequested = oldValidationRequested; setCacheOnly(oldCacheOnly); d_followCNAME = oldFollowCNAME; + setOutOfBand(oldWasOutOfBand); if (s_max_busy_dot_probes > 0 && s_dot_to_port_853) { for (auto& add : ret) { @@ -2318,7 +2237,7 @@ return true; } -void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const boost::optional& cutOffDomain) // NOLINT(readability-function-cognitive-complexity) +void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const std::optional& cutOffDomain) // NOLINT(readability-function-cognitive-complexity) { DNSName subdomain(qname); bestns.clear(); @@ -2546,7 +2465,7 @@ g_recCache->updateValidationStatus(d_now.tv_sec, qname, qtype, d_cacheRemote, d_routingTag, aaFlag, newState, s_maxbogusttl + d_now.tv_sec); } else { - g_recCache->updateValidationStatus(d_now.tv_sec, qname, qtype, d_cacheRemote, d_routingTag, aaFlag, newState, boost::none); + g_recCache->updateValidationStatus(d_now.tv_sec, qname, qtype, d_cacheRemote, d_routingTag, aaFlag, newState, std::nullopt); } } @@ -2567,8 +2486,8 @@ bool SyncRes::doCNAMECacheCheck(const DNSName& qname, const QType qtype, vector& ret, unsigned int depth, const string& prefix, int& res, Context& context, bool wasAuthZone, bool wasForwardRecurse, bool checkForDups) // NOLINT(readability-function-cognitive-complexity) { vector cset; - vector> signatures; - vector> authorityRecs; + MemRecursorCache::SigRecs signatures = MemRecursorCache::s_emptySigRecs; + MemRecursorCache::AuthRecs authorityRecs = MemRecursorCache::s_emptyAuthRecs; bool wasAuth = false; uint32_t capTTL = std::numeric_limits::max(); DNSName foundName; @@ -2586,9 +2505,11 @@ if (d_serveStale) { flags |= MemRecursorCache::ServeStale; } - if (g_recCache->get(d_now.tv_sec, qname, QType::CNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &d_fromAuthIP) > 0) { + MemRecursorCache::Extra extra; + if (g_recCache->get(d_now.tv_sec, qname, QType::CNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &extra) > 0) { foundName = qname; foundQT = QType::CNAME; + d_fromAuthIP = extra.d_address; } if (foundName.empty() && qname != g_rootdnsname) { @@ -2602,9 +2523,10 @@ if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match break; } - if (g_recCache->get(d_now.tv_sec, dnameName, QType::DNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &d_fromAuthIP) > 0) { - foundName = dnameName; + if (g_recCache->get(d_now.tv_sec, dnameName, QType::DNAME, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &context.state, &wasAuth, &authZone, &extra) > 0) { + foundName = std::move(dnameName); foundQT = QType::DNAME; + d_fromAuthIP = extra.d_address; break; } } while (!labels.empty()); @@ -2631,10 +2553,10 @@ if (!wasAuthZone && shouldValidate() && (wasAuth || wasForwardRecurse) && context.state == vState::Indeterminate && d_requireAuthData) { /* This means we couldn't figure out the state when this entry was cached */ - vState recordState = getValidationStatus(foundName, !signatures.empty(), qtype == QType::DS, depth, prefix); + vState recordState = getValidationStatus(foundName, !signatures->empty(), qtype == QType::DS, depth, prefix); if (recordState == vState::Secure) { LOG(prefix << qname << ": Got vState::Indeterminate state from the " << foundQT.toString() << " cache, validating.." << endl); - context.state = SyncRes::validateRecordsWithSigs(depth, prefix, qname, qtype, foundName, foundQT, cset, signatures); + context.state = SyncRes::validateRecordsWithSigs(depth, prefix, qname, qtype, foundName, foundQT, cset, *signatures); if (context.state != vState::Indeterminate) { LOG(prefix << qname << ": Got vState::Indeterminate state from the " << foundQT.toString() << " cache, new validation result is " << context.state << endl); if (vStateIsBogus(context.state)) { @@ -2664,10 +2586,10 @@ dnsRecord.d_ttl = std::min(dnsRecord.d_ttl, capTTL); const uint32_t ttl = dnsRecord.d_ttl; if (!alreadyPresent) { - ret.reserve(ret.size() + 2 + signatures.size() + authorityRecs.size()); + ret.reserve(ret.size() + 2 + signatures->size() + authorityRecs->size()); ret.push_back(dnsRecord); - for (const auto& signature : signatures) { + for (const auto& signature : *signatures) { DNSRecord sigdr; sigdr.d_type = QType::RRSIG; sigdr.d_name = foundName; @@ -2675,13 +2597,13 @@ sigdr.setContent(signature); sigdr.d_place = DNSResourceRecord::ANSWER; sigdr.d_class = QClass::IN; - ret.push_back(sigdr); + ret.push_back(std::move(sigdr)); } - for (const auto& rec : authorityRecs) { - DNSRecord authDR(*rec); + for (const auto& rec : *authorityRecs) { + DNSRecord authDR(rec); authDR.d_ttl = ttl; - ret.push_back(authDR); + ret.push_back(std::move(authDR)); } } @@ -2771,6 +2693,7 @@ // so you can't trust that a real lookup will have been made. res = doResolve(newTarget, qtype, ret, depth + 1, beenthere, cnameContext); LOG(prefix << qname << ": Updating validation state for response to " << qname << " from " << context.state << " with the state from the DNAME/CNAME quest: " << cnameContext.state << endl); + pdns::dedupRecords(ret); // multiple NSECS could have been added, #14120 updateValidationState(qname, context.state, cnameContext.state, prefix); return true; @@ -2784,7 +2707,7 @@ struct CacheEntry { vector records; - vector> signatures; + MemRecursorCache::SigRecsVec signatures; // for wildcard records, we need the real owner name for the aggressive cache DNSName realOwner; time_t d_ttl_time{0}; @@ -2834,9 +2757,9 @@ } } -static void reapSignaturesForValidation(std::map& entries, const vector>& signatures) +static void reapSignaturesForValidation(std::map& entries, const MemRecursorCache::SigRecs& signatures) { - for (const auto& sig : signatures) { + for (const auto& sig : *signatures) { entries[sig->d_type].signatures.push_back(sig); } } @@ -2897,7 +2820,7 @@ } if (state != vState::Indeterminate) { /* validation succeeded, let's update the cache entry so we don't have to validate again */ - boost::optional capTTD = boost::none; + std::optional capTTD = std::nullopt; if (vStateIsBogus(state)) { capTTD = d_now.tv_sec + s_maxbogusttl; } @@ -3016,8 +2939,8 @@ vector cset; bool found = false; bool expired = false; - vector> signatures; - vector> authorityRecs; + MemRecursorCache::SigRecs signatures = MemRecursorCache::s_emptySigRecs; + MemRecursorCache::AuthRecs authorityRecs = MemRecursorCache::s_emptyAuthRecs; uint32_t ttl = 0; uint32_t capTTL = std::numeric_limits::max(); bool wasCachedAuth{}; @@ -3031,19 +2954,22 @@ if (d_refresh) { flags |= MemRecursorCache::Refresh; } - if (g_recCache->get(d_now.tv_sec, sqname, sqt, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth, nullptr, &d_fromAuthIP) > 0) { + + MemRecursorCache::Extra extra; + if (g_recCache->get(d_now.tv_sec, sqname, sqt, flags, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth, nullptr, &extra) > 0) { + d_fromAuthIP = extra.d_address; LOG(prefix << sqname << ": Found cache hit for " << sqt.toString() << ": "); if (!wasAuthZone && shouldValidate() && (wasCachedAuth || wasForwardRecurse) && cachedState == vState::Indeterminate && d_requireAuthData) { /* This means we couldn't figure out the state when this entry was cached */ - vState recordState = getValidationStatus(qname, !signatures.empty(), qtype == QType::DS, depth, prefix); + vState recordState = getValidationStatus(qname, !signatures->empty(), qtype == QType::DS, depth, prefix); if (recordState == vState::Secure) { LOG(prefix << sqname << ": Got vState::Indeterminate state from the cache, validating.." << endl); - if (sqt == QType::DNSKEY && sqname == getSigner(signatures)) { - cachedState = validateDNSKeys(sqname, cset, signatures, depth, prefix); + if (sqt == QType::DNSKEY && sqname == getSigner(*signatures)) { + cachedState = validateDNSKeys(sqname, cset, *signatures, depth, prefix); } else { if (sqt == QType::ANY) { @@ -3063,7 +2989,7 @@ } } else { - cachedState = SyncRes::validateRecordsWithSigs(depth, prefix, qname, qtype, sqname, sqt, cset, signatures); + cachedState = SyncRes::validateRecordsWithSigs(depth, prefix, qname, qtype, sqname, sqt, cset, *signatures); } } } @@ -3105,9 +3031,9 @@ } } - ret.reserve(ret.size() + signatures.size() + authorityRecs.size()); + ret.reserve(ret.size() + signatures->size() + authorityRecs->size()); - for (const auto& signature : signatures) { + for (const auto& signature : *signatures) { DNSRecord dnsRecord; dnsRecord.d_type = QType::RRSIG; dnsRecord.d_name = sqname; @@ -3115,13 +3041,13 @@ dnsRecord.setContent(signature); dnsRecord.d_place = DNSResourceRecord::ANSWER; dnsRecord.d_class = QClass::IN; - ret.push_back(dnsRecord); + ret.push_back(std::move(dnsRecord)); } - for (const auto& rec : authorityRecs) { - DNSRecord dnsRecord(*rec); + for (const auto& rec : *authorityRecs) { + DNSRecord dnsRecord(rec); dnsRecord.d_ttl = ttl; - ret.push_back(dnsRecord); + ret.push_back(std::move(dnsRecord)); } LOG(endl); @@ -3249,7 +3175,7 @@ for (const auto& rec : records) { if (rec.d_place != DNSResourceRecord::AUTHORITY) { // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in - // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for + // the AUTHORITY section. Section 3.1.1 indicates that RRSIGs for // records MUST be in the same section as the records they cover. // Hence, we ignore all records outside of the AUTHORITY section. continue; @@ -3627,7 +3553,7 @@ return g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate; } -uint32_t SyncRes::computeLowestTTD(const std::vector& records, const std::vector>& signatures, uint32_t signaturesTTL, const std::vector>& authorityRecs) const +uint32_t SyncRes::computeLowestTTD(const std::vector& records, const MemRecursorCache::SigRecsVec& signatures, uint32_t signaturesTTL, const MemRecursorCache::AuthRecsVec& authorityRecs) const { uint32_t lowestTTD = std::numeric_limits::max(); for (const auto& record : records) { @@ -3651,10 +3577,10 @@ for (const auto& entry : authorityRecs) { /* be careful, this is still a TTL here */ - lowestTTD = min(lowestTTD, static_cast(entry->d_ttl + d_now.tv_sec)); + lowestTTD = min(lowestTTD, static_cast(entry.d_ttl + d_now.tv_sec)); - if (entry->d_type == QType::RRSIG && validationEnabled()) { - auto rrsig = getRR(*entry); + if (entry.d_type == QType::RRSIG && validationEnabled()) { + auto rrsig = getRR(entry); if (rrsig) { if (isRRSIGNotExpired(d_now.tv_sec, *rrsig)) { // we don't decrement d_sigexpire by 'now' because we actually want a TTD, not a TTL */ @@ -3775,9 +3701,11 @@ const bool oldCacheOnly = setCacheOnly(false); const bool oldQM = setQNameMinimization(!getQMFallbackMode()); + const bool oldRPZ = setWantsRPZ(false); int rcode = doResolve(zone, QType::DS, dsrecords, depth + 1, beenthere, context); setCacheOnly(oldCacheOnly); setQNameMinimization(oldQM); + setWantsRPZ(oldRPZ); if (rcode == RCode::ServFail) { throw ImmediateServFailException("Server Failure while retrieving DS records for " + zone.toLogString()); @@ -3796,10 +3724,10 @@ const auto dscontent = getRR(record); if (dscontent && isSupportedDS(*dscontent, LogObject(prefix))) { // Make GOST a lower prio than SHA256 - if (dscontent->d_digesttype == DNSSECKeeper::DIGEST_GOST && bestDigestType == DNSSECKeeper::DIGEST_SHA256) { + if (dscontent->d_digesttype == DNSSEC::DIGEST_GOST && bestDigestType == DNSSEC::DIGEST_SHA256) { continue; } - if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::DIGEST_GOST && dscontent->d_digesttype == DNSSECKeeper::DIGEST_SHA256)) { + if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSEC::DIGEST_GOST && dscontent->d_digesttype == DNSSEC::DIGEST_SHA256)) { bestDigestType = dscontent->d_digesttype; } dsSet.insert(*dscontent); @@ -3815,7 +3743,7 @@ * We interpret that as: do not use SHA-1 if SHA-256 or SHA-384 is available */ for (auto dsrec = dsSet.begin(); dsrec != dsSet.end();) { - if (dsrec->d_digesttype == DNSSECKeeper::DIGEST_SHA1 && dsrec->d_digesttype != bestDigestType) { + if (dsrec->d_digesttype == DNSSEC::DIGEST_SHA1 && dsrec->d_digesttype != bestDigestType) { dsrec = dsSet.erase(dsrec); } else { @@ -3950,7 +3878,7 @@ return result; } -vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const std::vector>& signatures, unsigned int depth, const string& prefix) +vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const MemRecursorCache::SigRecsVec& signatures, unsigned int depth, const string& prefix) { dsset_t dsSet; if (signatures.empty()) { @@ -4030,8 +3958,10 @@ Context context; const bool oldCacheOnly = setCacheOnly(false); + const bool oldRPZ = setWantsRPZ(false); int rcode = doResolve(signer, QType::DNSKEY, records, depth + 1, beenthere, context); setCacheOnly(oldCacheOnly); + setWantsRPZ(oldRPZ); if (rcode == RCode::ServFail) { servFailOccurred = true; @@ -4044,7 +3974,7 @@ if (key.d_type == QType::DNSKEY) { auto content = getRR(key); if (content) { - keys.insert(content); + keys.insert(std::move(content)); } } } @@ -4061,7 +3991,7 @@ return vState::BogusUnableToGetDNSKEYs; } -vState SyncRes::validateRecordsWithSigs(unsigned int depth, const string& prefix, const DNSName& qname, const QType qtype, const DNSName& name, const QType type, const std::vector& records, const std::vector>& signatures) +vState SyncRes::validateRecordsWithSigs(unsigned int depth, const string& prefix, const DNSName& qname, const QType qtype, const DNSName& name, const QType type, const std::vector& records, const MemRecursorCache::SigRecsVec& signatures) { skeyset_t keys; if (signatures.empty()) { @@ -4265,7 +4195,7 @@ if (target.isRoot()) { target = rec.d_name; } - allowedAdditionals.insert(target); + allowedAdditionals.insert(std::move(target)); } else { // FIXME: Alias mode not implemented yet @@ -4525,6 +4455,12 @@ } lwr.d_records = std::move(vec); } +#ifdef notyet + // As dedupping is relatively expensive and having dup records not really hurts as far as we have seen, do not dedup. + if (auto count = pdns::dedupRecords(lwr.d_records); count > 0) { + LOG(prefix << qname << ": Removed " << count << " duplicate records from response received from " << auth << endl); + } +#endif } void SyncRes::rememberParentSetIfNeeded(const DNSName& domain, const vector& newRecords, unsigned int depth, const string& prefix) @@ -4575,7 +4511,7 @@ } } -RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, const DNSName& auth, bool wasForwarded, const boost::optional& ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery, const ComboAddress& remoteIP) // NOLINT(readability-function-cognitive-complexity) +RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, const DNSName& auth, bool wasForwarded, const std::optional& ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery, const ComboAddress& remoteIP, bool overTCP) // NOLINT(readability-function-cognitive-complexity) { bool wasForwardRecurse = wasForwarded && rdQuery; tcache_t tcache; @@ -4583,7 +4519,7 @@ fixupAnswer(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery); sanitizeRecords(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery); - std::vector> authorityRecs; + MemRecursorCache::AuthRecsVec authorityRecs; bool isCNAMEAnswer = false; bool isDNAMEAnswer = false; DNSName seenAuth; @@ -4680,12 +4616,12 @@ } if (nsecTypes.count(rec.d_type) != 0) { - authorityRecs.push_back(std::make_shared(rec)); + authorityRecs.emplace_back(rec); } else if (rec.d_type == QType::RRSIG) { auto rrsig = getRR(rec); if (rrsig && nsecTypes.count(rrsig->d_type) != 0) { - authorityRecs.push_back(std::make_shared(rec)); + authorityRecs.emplace_back(rec); } } } @@ -4749,7 +4685,7 @@ tcache[{rec.d_name, rec.d_type, rec.d_place}].d_ttl_time = d_now.tv_sec; dnsRecord.d_ttl += d_now.tv_sec; dnsRecord.d_place = DNSResourceRecord::ANSWER; - tcache[{rec.d_name, rec.d_type, rec.d_place}].records.push_back(dnsRecord); + tcache[{rec.d_name, rec.d_type, rec.d_place}].records.push_back(std::move(dnsRecord)); } } else @@ -4943,7 +4879,7 @@ if (tCacheEntry->first.type == QType::DS) { tCacheEntry->second.isAuth = true; } - g_recCache->replace(d_now.tv_sec, tCacheEntry->first.name, tCacheEntry->first.type, tCacheEntry->second.records, tCacheEntry->second.signatures, thisRRNeedsWildcardProof ? authorityRecs : std::vector>(), tCacheEntry->second.isAuth, auth, tCacheEntry->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState, remoteIP, d_refresh, tCacheEntry->second.d_ttl_time); + g_recCache->replace(d_now.tv_sec, tCacheEntry->first.name, tCacheEntry->first.type, tCacheEntry->second.records, tCacheEntry->second.signatures, thisRRNeedsWildcardProof ? authorityRecs : *MemRecursorCache::s_emptyAuthRecs, tCacheEntry->second.isAuth, auth, tCacheEntry->first.place == DNSResourceRecord::ANSWER ? ednsmask : std::nullopt, d_routingTag, recordState, MemRecursorCache::Extra{remoteIP, overTCP}, d_refresh, tCacheEntry->second.d_ttl_time); tCacheEntry->second.inserted = true; // Delete potential negcache entry. When a record recovers with serve-stale the negcache entry can cause the wrong entry to @@ -4952,7 +4888,7 @@ g_negCache->wipeTyped(tCacheEntry->first.name, tCacheEntry->first.type); } - if (g_aggressiveNSECCache && thisRRNeedsWildcardProof && recordState == vState::Secure && tCacheEntry->first.place == DNSResourceRecord::ANSWER && !tCacheEntry->second.signatures.empty() && !d_routingTag && !ednsmask) { + if (g_aggressiveNSECCache && thisRRNeedsWildcardProof && recordState == vState::Secure && tCacheEntry->first.place == DNSResourceRecord::ANSWER && !tCacheEntry->second.signatures.empty() && d_routingTag.empty() && !ednsmask) { /* we have an answer synthesized from a wildcard and aggressive NSEC is enabled, we need to store the wildcard in its non-expanded form in the cache to be able to synthesize wildcard answers later */ const auto& rrsig = tCacheEntry->second.signatures.at(0); @@ -4969,7 +4905,7 @@ content.push_back(std::move(nonExpandedRecord)); } - g_recCache->replace(d_now.tv_sec, tCacheEntry->second.realOwner, QType(tCacheEntry->first.type), content, tCacheEntry->second.signatures, /* no additional records in that case */ {}, tCacheEntry->second.isAuth, auth, boost::none, boost::none, recordState, remoteIP, d_refresh, tCacheEntry->second.d_ttl_time); + g_recCache->replace(d_now.tv_sec, tCacheEntry->second.realOwner, QType(tCacheEntry->first.type), content, tCacheEntry->second.signatures, /* no additional records in that case */ {}, tCacheEntry->second.isAuth, auth, std::nullopt, MemRecursorCache::NOTAG, recordState, MemRecursorCache::Extra{remoteIP, overTCP}, d_refresh, tCacheEntry->second.d_ttl_time); } } } @@ -5003,7 +4939,7 @@ g_recCache->updateValidationStatus(d_now.tv_sec, entry.first.name, entry.first.type, d_cacheRemote, d_routingTag, entry.second.isAuth, *seenBogusRRSet, s_maxbogusttl + d_now.tv_sec); if (!entry.second.realOwner.empty()) { - g_recCache->updateValidationStatus(d_now.tv_sec, entry.second.realOwner, entry.first.type, d_cacheRemote, boost::none, entry.second.isAuth, *seenBogusRRSet, s_maxbogusttl + d_now.tv_sec); + g_recCache->updateValidationStatus(d_now.tv_sec, entry.second.realOwner, entry.first.type, d_cacheRemote, MemRecursorCache::NOTAG, entry.second.isAuth, *seenBogusRRSet, s_maxbogusttl + d_now.tv_sec); } } } @@ -5085,7 +5021,7 @@ if (recordState == vState::Secure) { /* We have a positive answer synthesized from a wildcard, we need to check that we have - proof that the exact name doesn't exist so the wildcard can be used, + proof that the next closer doesn't exist so the wildcard can be used, as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129. */ cspmap_t csp = harvestCSPFromNE(negEntry); @@ -5499,12 +5435,12 @@ LWResult lwr; bool truncated{}; bool spoofed{}; - boost::optional netmask; + std::optional netmask; address.setPort(853); // We use the fact that qname equals auth bool isOK = false; try { - boost::optional extendedError; + std::optional extendedError; isOK = doResolveAtThisIP("", qname, qtype, lwr, netmask, qname, false, false, nsName, address, true, true, truncated, spoofed, extendedError, true); isOK = isOK && lwr.d_rcode == RCode::NoError && !lwr.d_records.empty(); } @@ -5527,7 +5463,7 @@ return isOK; } -void SyncRes::ednsStats(boost::optional& ednsmask, const DNSName& qname, const string& prefix) +void SyncRes::ednsStats(std::optional& ednsmask, const DNSName& qname, const string& prefix) { if (!ednsmask) { return; @@ -5584,7 +5520,7 @@ } } -void SyncRes::checkTotalTime(const DNSName& qname, QType qtype, boost::optional& extendedError) const +void SyncRes::checkTotalTime(const DNSName& qname, QType qtype, std::optional& extendedError) const { if (s_maxtotusec != 0 && d_totUsec > s_maxtotusec) { if (s_addExtendedResolutionDNSErrors) { @@ -5594,7 +5530,7 @@ } } -bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional& 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& extendedError, bool dontThrottle) +bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, std::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, std::optional& extendedError, bool dontThrottle) { checkTotalTime(qname, qtype, extendedError); @@ -5611,16 +5547,22 @@ LOG(prefix << qname << ": Adding EDNS Client Subnet Mask " << ednsmask->toString() << " to query" << endl); s_ecsqueries++; } + auto match = d_eventTrace.add(RecEventTrace::AuthRequest, qname.toLogString(), true, 0); + d_eventTrace.setValueName(match, "query.qname"); + d_eventTrace.addExtraValues(match, {{"query.qtype", qtype.toString()}, {"auth.address", remoteIP.toStringWithPortExcept(53)}, {"auth.nsname", nsName.toLogString()}}); updateQueryCounts(prefix, qname, remoteIP, doTCP, doDoT); - resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(), + resolveret = asyncresolveWrapper(LogObject(prefix), remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(), doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained, nsName); // <- we go out on the wire! + d_eventTrace.add(RecEventTrace::AuthRequest, static_cast(lwr.d_rcode), false, match); ednsStats(ednsmask, qname, prefix); if (resolveret == LWResult::Result::ECSMissing) { - ednsmask = boost::none; + ednsmask = std::nullopt; LOG(prefix << qname << ": Answer has no ECS, trying again without EDNS Client Subnet Mask" << endl); updateQueryCounts(prefix, qname, remoteIP, doTCP, doDoT); - resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(), - doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained, nsName); + match = d_eventTrace.add(RecEventTrace::AuthRequest, qname.toLogString() + '/' + qtype.toString(), true, 0); + resolveret = asyncresolveWrapper(LogObject(prefix), remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(), + doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained, nsName); // <- we go out on the wire! + d_eventTrace.add(RecEventTrace::AuthRequest, static_cast(lwr.d_rcode), false, match); } } @@ -5632,13 +5574,15 @@ d_bytesReceived += lwr.d_bytesReceived; d_totUsec += lwr.d_usec; - if (resolveret == LWResult::Result::Spoofed) { + if (resolveret == LWResult::Result::Spoofed || resolveret == LWResult::Result::BadCookie) { spoofed = true; return false; } accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family); - ++t_Counters.at(rec::RCode::auth).rcodeCounters.at(static_cast(lwr.d_rcode)); + if (lwr.d_rcode >= 0 && lwr.d_rcode < static_cast(t_Counters.at(rec::RCode::auth).rcodeCounters.size())) { + ++t_Counters.at(rec::RCode::auth).rcodeCounters.at(static_cast(lwr.d_rcode)); + } if (!dontThrottle) { dontThrottle = shouldNotThrottle(&nsName, &remoteIP); @@ -5646,26 +5590,28 @@ if (resolveret != LWResult::Result::Success) { /* Error while resolving */ - if (resolveret == LWResult::Result::Timeout) { + switch (resolveret) { + case LWResult::Result::Timeout: LOG(prefix << qname << ": Timeout resolving after " << lwr.d_usec / 1000.0 << " ms " << (doTCP ? "over TCP" : "") << endl); incTimeoutStats(remoteIP); - } - else if (resolveret == LWResult::Result::OSLimitError) { + break; + case 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) { + break; + case 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 { + break; + default: /* LWResult::Result::PermanentError */ t_Counters.at(rec::Counter::unreachables)++; d_unreachables++; // XXX questionable use of errno LOG(prefix << qname << ": Error resolving from " << remoteIP.toString() << (doTCP ? " over TCP" : "") << ", possible error: " << stringerror() << endl); + break; } // don't account for resource limits, they are our own fault @@ -5828,7 +5774,7 @@ updateValidationState(qname, state, cnameContext.state, prefix); } -bool SyncRes::processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, DNSName& auth, bool wasForwarded, const boost::optional& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP) +bool SyncRes::processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, const QType qtype, DNSName& auth, bool wasForwarded, const std::optional& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP, bool overTCP) { if (s_minimumTTL != 0) { for (auto& rec : lwr.d_records) { @@ -5849,7 +5795,7 @@ bool needWildcardProof = false; bool gatherWildcardProof = false; unsigned int wildcardLabelsCount = 0; - *rcode = updateCacheFromRecords(depth, prefix, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery, remoteIP); + *rcode = updateCacheFromRecords(depth, prefix, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery, remoteIP, overTCP); if (*rcode != RCode::NoError) { return true; } @@ -6049,7 +5995,7 @@ remoteIPs_t::iterator remoteIP; bool pierceDontQuery = false; bool sendRDQuery = false; - boost::optional ednsmask; + std::optional ednsmask; LWResult lwr; const bool wasForwarded = tns->first.empty() && (!nameservers[tns->first].first.empty()); int rcode = RCode::NoError; @@ -6066,7 +6012,7 @@ lwr.d_aabit = true; /* we have received an answer, are we done ? */ - bool done = processAnswer(depth, prefix, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, context.state, s_oobRemote); + bool done = processAnswer(depth, prefix, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, context.state, s_oobRemote, false); if (done) { return rcode; } @@ -6142,19 +6088,24 @@ if (SyncRes::s_dot_to_port_853 && remoteIP->getPort() == 853) { doDoT = true; } - bool forceTCP = doDoT; + bool forceTCP = doDoT || (qtype == QType::ANY && s_outAnyToTcp); if (!doDoT && s_max_busy_dot_probes > 0) { submitTryDotTask(*remoteIP, auth, tns->first, d_now.tv_sec); } + bool overTCP = false; if (!forceTCP) { gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, tns->first, *remoteIP, false, false, truncated, spoofed, context.extendedError); } + if (spoofed) { + LOG(prefix << qname << ": potentially spoofed, retrying over TCP" << endl); + } if (forceTCP || (spoofed || (gotAnswer && truncated))) { /* retry, over TCP this time */ gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, tns->first, *remoteIP, true, doDoT, truncated, spoofed, context.extendedError); + overTCP = true; } if (!gotAnswer) { @@ -6179,7 +6130,7 @@ s_nsSpeeds.lock()->find_or_enter(tns->first.empty() ? DNSName(remoteIP->toStringWithPort()) : tns->first, d_now).submit(*remoteIP, static_cast(lwr.d_usec), d_now); /* we have received an answer, are we done ? */ - bool done = processAnswer(depth, prefix, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, context.state, *remoteIP); + bool done = processAnswer(depth, prefix, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, context.state, *remoteIP, overTCP); if (done) { return rcode; } @@ -6215,7 +6166,7 @@ d_outgoingECSNetwork = netmask; } else { - d_outgoingECSNetwork = boost::none; + d_outgoingECSNetwork = std::nullopt; } } @@ -6223,12 +6174,12 @@ { d_requestor = requestor; - if (incomingECS && incomingECS->source.getBits() > 0) { - d_cacheRemote = incomingECS->source.getMaskedNetwork(); - uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit)); - ComboAddress trunc = incomingECS->source.getNetwork(); + if (incomingECS && incomingECS->getSourcePrefixLength() > 0) { + d_cacheRemote = incomingECS->getSource().getMaskedNetwork(); + uint8_t bits = std::min(incomingECS->getSourcePrefixLength(), (incomingECS->getSource().isIPv4() ? s_ecsipv4limit : s_ecsipv6limit)); + ComboAddress trunc = incomingECS->getSource().getNetwork(); trunc.truncate(bits); - d_outgoingECSNetwork = boost::optional(Netmask(trunc, bits)); + d_outgoingECSNetwork = std::optional(Netmask(trunc, bits)); } else { d_cacheRemote = d_requestor; @@ -6237,9 +6188,9 @@ uint8_t bits = d_requestor.isIPv4() ? 32 : 128; bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit)); trunc.truncate(bits); - d_outgoingECSNetwork = boost::optional(Netmask(trunc, bits)); + d_outgoingECSNetwork = std::optional(Netmask(trunc, bits)); } - else if (s_ecsScopeZero.source.getBits() > 0) { + else if (s_ecsScopeZero.getSourcePrefixLength() > 0) { /* RFC7871 says we MUST NOT send any ECS if the source scope is 0. But using an empty ECS in that case would mean inserting a non ECS-specific entry into the cache, preventing any further @@ -6254,22 +6205,22 @@ indicator of the applicable scope. Subsequent Stub Resolver queries for /0 can then be answered from this cached response. */ - d_outgoingECSNetwork = boost::optional(s_ecsScopeZero.source.getMaskedNetwork()); - d_cacheRemote = s_ecsScopeZero.source.getNetwork(); + d_outgoingECSNetwork = std::optional(s_ecsScopeZero.getSource().getMaskedNetwork()); + d_cacheRemote = s_ecsScopeZero.getSource().getNetwork(); } else { // ECS disabled because no scope-zero address could be derived. - d_outgoingECSNetwork = boost::none; + d_outgoingECSNetwork = std::nullopt; } } } -boost::optional SyncRes::getEDNSSubnetMask(const DNSName& name, const ComboAddress& rem) +std::optional SyncRes::getEDNSSubnetMask(const DNSName& name, const ComboAddress& rem) { if (d_outgoingECSNetwork && (s_ednsdomains.check(name) || s_ednsremotesubnets.match(rem))) { return d_outgoingECSNetwork; } - return boost::none; + return std::nullopt; } void SyncRes::parseEDNSSubnetAllowlist(const std::string& alist) @@ -6305,9 +6256,7 @@ { auto log = slog->withValues("qname", Logging::Loggable(qname), "qtype", Logging::Loggable(qtype)); - struct timeval now - { - }; + struct timeval now{}; gettimeofday(&now, nullptr); SyncRes resolver(now); @@ -6322,28 +6271,23 @@ res = resolver.beginResolve(qname, qtype, qclass, ret, 0); } catch (const PDNSException& e) { - SLOG(g_log << Logger::Warning << "Failed to resolve " << qname << ", got pdns exception: " << e.reason << endl, - log->error(Logr::Warning, e.reason, msg, "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Warning, e.reason, msg, "exception", Logging::Loggable("PDNSException")); ret.clear(); } catch (const ImmediateServFailException& e) { - SLOG(g_log << Logger::Warning << "Failed to resolve " << qname << ", got ImmediateServFailException: " << e.reason << endl, - log->error(Logr::Warning, e.reason, msg, "exception", Logging::Loggable("ImmediateServFailException"))); + log->error(Logr::Warning, e.reason, msg, "exception", Logging::Loggable("ImmediateServFailException")); ret.clear(); } catch (const PolicyHitException& e) { - SLOG(g_log << Logger::Warning << "Failed to resolve " << qname << ", got a policy hit" << endl, - log->info(Logr::Warning, msg, "exception", Logging::Loggable("PolicyHitException"))); + log->info(Logr::Warning, msg, "exception", Logging::Loggable("PolicyHitException")); ret.clear(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Warning << "Failed to resolve " << qname << ", got STL error: " << e.what() << endl, - log->error(Logr::Warning, e.what(), msg, "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Warning, e.what(), msg, "exception", Logging::Loggable("std::exception")); ret.clear(); } catch (...) { - SLOG(g_log << Logger::Warning << "Failed to resolve " << qname << ", got an exception" << endl, - log->info(Logr::Warning, msg)); + log->info(Logr::Warning, msg); ret.clear(); } @@ -6377,35 +6321,28 @@ } } catch (const PDNSException& e) { - SLOG(g_log << Logger::Error << "Failed to update . records, got an exception: " << e.reason << endl, - log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException"))); + log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("PDNSException")); } catch (const ImmediateServFailException& e) { - SLOG(g_log << Logger::Error << "Failed to update . records, got an exception: " << e.reason << endl, - log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("ImmediateServFailException"))); + log->error(Logr::Error, e.reason, msg, "exception", Logging::Loggable("ImmediateServFailException")); } catch (const PolicyHitException& policyHit) { - SLOG(g_log << Logger::Error << "Failed to update . records, got a policy hit" << endl, - log->info(Logr::Error, msg, "exception", Logging::Loggable("PolicyHitException"), - "policyName", Logging::Loggable(resolver.d_appliedPolicy.getName()))); + log->info(Logr::Error, msg, "exception", Logging::Loggable("PolicyHitException"), + "policyName", Logging::Loggable(resolver.d_appliedPolicy.getName())); ret.clear(); } catch (const std::exception& e) { - SLOG(g_log << Logger::Error << "Failed to update . records, got an exception: " << e.what() << endl, - log->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception"))); + log->error(Logr::Error, e.what(), msg, "exception", Logging::Loggable("std::exception")); } catch (...) { - SLOG(g_log << Logger::Error << "Failed to update . records, got an exception" << endl, - log->info(Logr::Error, msg)); + log->info(Logr::Error, msg); } if (res == 0) { - SLOG(g_log << Logger::Debug << "Refreshed . records" << endl, - log->info(Logr::Debug, "Refreshed . records")); + log->info(Logr::Debug, "Refreshed . records"); } else { - SLOG(g_log << Logger::Warning << "Failed to update root NS records, RCODE=" << res << endl, - log->info(Logr::Warning, msg, "rcode", Logging::Loggable(res))); + log->info(Logr::Warning, msg, "rcode", Logging::Loggable(res)); } return res; } diff -Nru pdns-recursor-5.2.13/syncres.hh pdns-recursor-5.4.9/syncres.hh --- pdns-recursor-5.2.13/syncres.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/syncres.hh 2026-10-26 08:26:51.000000000 +0000 @@ -54,6 +54,7 @@ #include "logr.hh" #include "rec-tcounters.hh" #include "ednsextendederror.hh" +#include "protozero-trace.hh" #ifdef HAVE_CONFIG_H #include "config.h" @@ -86,7 +87,7 @@ Log, Store }; - using asyncresolve_t = std::function&, const ResolveContext&, LWResult*, bool*)>; + using asyncresolve_t = std::function&, const ResolveContext&, LWResult*, bool*)>; enum class HardenNXD { @@ -97,7 +98,7 @@ struct Context { - boost::optional extendedError; + std::optional extendedError; vState state{vState::Indeterminate}; }; @@ -169,6 +170,9 @@ static uint64_t doDumpSavedParentNSSets(int fileDesc); static uint64_t doDumpDoTProbeMap(int fileDesc); + static size_t getNSSpeedTable(size_t maxSize, std::string& ret); + static size_t putIntoNSSpeedTable(const std::string& ret); + static int getRootNS(struct timeval now, asyncresolve_t asyncCallback, unsigned int depth, Logr::log_t); static void addDontQuery(const std::string& mask) { @@ -300,7 +304,7 @@ static void setECSScopeZeroAddress(const Netmask& scopeZeroMask) { - s_ecsScopeZero.source = scopeZeroMask; + s_ecsScopeZero.setSource(scopeZeroMask); } static void clearECSStats() @@ -404,9 +408,11 @@ return d_DNSSECValidationRequested && !d_wasOutOfBand; } - void setWantsRPZ(bool state = true) + bool setWantsRPZ(bool state = true) { + bool old = d_wantsRPZ; d_wantsRPZ = state; + return old; } bool getWantsRPZ() const @@ -439,6 +445,13 @@ return d_wasOutOfBand; } + bool setOutOfBand(bool flag) + { + bool old = d_wasOutOfBand; + d_wasOutOfBand = flag; + return old; + } + struct timeval getNow() const { return d_now; @@ -557,6 +570,7 @@ static bool s_noEDNS; static bool s_rootNXTrust; static bool s_qnameminimization; + static bool s_outAnyToTcp; static HardenNXD s_hardenNXD; static unsigned int s_refresh_ttlperc; static unsigned int s_locked_ttlperc; @@ -570,18 +584,28 @@ static const int event_trace_to_pb = 1; static const int event_trace_to_log = 2; + static const int event_trace_to_ot = 4; static int s_event_trace_enabled; static bool s_save_parent_ns_set; static bool s_addExtendedResolutionDNSErrors; + static bool eventTraceEnabled(int flag) + { + return (s_event_trace_enabled & flag) != 0; + } + static bool eventTraceEnabledOnly(int flag) + { + return s_event_trace_enabled == flag; + } std::unordered_map d_discardedPolicies; DNSFilterEngine::Policy d_appliedPolicy; std::unordered_set d_policyTags; - boost::optional d_routingTag; + std::string d_routingTag; ComboAddress d_fromAuthIP; RecEventTrace d_eventTrace; + pdns::trace::InitialSpanInfo d_otTrace; std::shared_ptr d_slog = g_slog->withName("syncres"); - boost::optional d_extendedError; + std::optional d_extendedError; unsigned int d_authzonequeries; unsigned int d_outqueries; @@ -635,11 +659,11 @@ int doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, const DNSName& qname, QType qtype, vector& ret, unsigned int depth, const string& prefix, set& beenthere, Context& context, StopAtDelegation* stopAtDelegation, std::map>* fallback); - void ednsStats(boost::optional& ednsmask, const DNSName& qname, const string& prefix); + void ednsStats(std::optional& ednsmask, const DNSName& qname, const string& prefix); void incTimeoutStats(const ComboAddress& remoteIP); - void checkTotalTime(const DNSName& qname, QType qtype, boost::optional& extendedError) const; - bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, QType qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool sendRDQuery, bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional& 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& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP); + void checkTotalTime(const DNSName& qname, QType qtype, std::optional& extendedError) const; + bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, QType qtype, LWResult& lwr, std::optional& ednsmask, const DNSName& auth, bool sendRDQuery, bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, std::optional& extendedError, bool dontThrottle = false); + bool processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, DNSName& auth, bool wasForwarded, const std::optional& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP, bool overTCP); int doResolve(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, Context& context); int doResolveNoQNameMinimization(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, Context& context, bool* fromCache = nullptr, StopAtDelegation* stopAtDelegation = nullptr); @@ -651,7 +675,7 @@ bool doCNAMECacheCheck(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, const string& prefix, int& res, Context& context, bool wasAuthZone, bool wasForwardRecurse, bool checkForDups); bool doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, const string& prefix, int& res, Context& context); bool canUseRecords(const std::string& prefix, const DNSName& qname, const DNSName& name, QType qtype, vState state); - void getBestNSFromCache(const DNSName& qname, QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const boost::optional& cutOffDomain = boost::none); + void getBestNSFromCache(const DNSName& qname, QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const std::optional& cutOffDomain = std::nullopt); DNSName getBestNSNamesFromCache(const DNSName& qname, QType qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere); vector> shuffleInSpeedOrder(const DNSName& qname, NsSet& nameservers, const string& prefix); @@ -668,25 +692,25 @@ vector retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector>::const_iterator& tns, unsigned int depth, set& beenthere, const vector>& 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, QType qtype, const DNSName& auth, std::unordered_set& allowedAnswerNames, std::unordered_set& allowedAdditionals, bool cnameSeen, bool delegationAccepted, std::vector& skipvec, unsigned int& skipCount); + void sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, std::unordered_set& allowedAnswerNames, std::unordered_set& allowedAdditionals, bool cnameSeen, bool acceptDelegation, std::vector& 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); void rememberParentSetIfNeeded(const DNSName& domain, const vector& newRecords, unsigned int depth, const string& prefix); - RCode::rcodes_ updateCacheFromRecords(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, const boost::optional&, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery, const ComboAddress& remoteIP); + RCode::rcodes_ updateCacheFromRecords(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, const std::optional&, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery, const ComboAddress& remoteIP, bool overTCP); bool processRecords(const std::string& prefix, const DNSName& qname, QType qtype, const DNSName& auth, LWResult& lwr, bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, bool needWildcardProof, bool gatherwildcardProof, unsigned int wildcardLabelsCount, int& rcode, bool& negIndicHasSignatures, unsigned int depth); bool doSpecialNamesResolve(const DNSName& qname, QType qtype, QClass qclass, vector& ret); - LWResult::Result asyncresolveWrapper(const ComboAddress& address, bool ednsMANDATORY, const DNSName& domain, const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional& srcmask, LWResult* res, bool* chained, const DNSName& nsName) const; + LWResult::Result asyncresolveWrapper(const OptLog& log, const ComboAddress& address, bool ednsMANDATORY, const DNSName& domain, const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, std::optional& srcmask, LWResult* res, bool* chained, const DNSName& nsName) const; - boost::optional getEDNSSubnetMask(const DNSName& name, const ComboAddress& rem); + std::optional getEDNSSubnetMask(const DNSName& name, const ComboAddress& rem); static bool validationEnabled(); - uint32_t computeLowestTTD(const std::vector& records, const std::vector>& signatures, uint32_t signaturesTTL, const std::vector>& authorityRecs) const; + uint32_t computeLowestTTD(const std::vector& records, const MemRecursorCache::SigRecsVec& signatures, uint32_t signaturesTTL, const MemRecursorCache::AuthRecsVec& authorityRecs) const; void updateValidationState(const DNSName& qname, vState& state, vState stateUpdate, const string& prefix); - vState validateRecordsWithSigs(unsigned int depth, const string& prefix, const DNSName& qname, QType qtype, const DNSName& name, QType type, const std::vector& records, const std::vector>& signatures); - vState validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const std::vector>& signatures, unsigned int depth, const string& prefix); + vState validateRecordsWithSigs(unsigned int depth, const string& prefix, const DNSName& qname, QType qtype, const DNSName& name, QType type, const std::vector& records, const MemRecursorCache::SigRecsVec& signatures); + vState validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const MemRecursorCache::SigRecsVec& signatures, unsigned int depth, const string& prefix); vState getDNSKeys(const DNSName& signer, skeyset_t& keys, bool& servFailOccurred, unsigned int depth, const string& prefix); dState getDenialValidationState(const NegCache::NegCacheEntry& negEntry, dState expectedState, bool referralToUnsigned, const string& prefix); void updateDenialValidationState(const DNSName& qname, vState& neValidationState, const DNSName& neName, vState& state, dState denialState, dState expectedState, bool isDS, unsigned int depth, const string& prefix); @@ -722,7 +746,7 @@ zonesStates_t d_cutStates; ostringstream d_trace; shared_ptr d_pdl; - boost::optional d_outgoingECSNetwork; + std::optional d_outgoingECSNetwork; std::shared_ptr>> d_outgoingProtobufServers; std::shared_ptr>> d_frameStreamServers; boost::optional d_initialRequestId; @@ -914,7 +938,7 @@ { public: ImmediateServFailException(string reason_) : - reason(std::move(reason_)){}; + reason(std::move(reason_)) {}; string reason; //! Print this to tell the user what went wrong }; diff -Nru pdns-recursor-5.2.13/taskqueue.cc pdns-recursor-5.4.9/taskqueue.cc --- pdns-recursor-5.2.13/taskqueue.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/taskqueue.cc 2026-10-26 08:26:51.000000000 +0000 @@ -52,9 +52,7 @@ log->error(Logr::Debug, "null task"); return false; } - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now); if (d_deadline >= now.tv_sec) { d_func(now, logErrors, *this); diff -Nru pdns-recursor-5.2.13/tcounters.hh pdns-recursor-5.4.9/tcounters.hh --- pdns-recursor-5.2.13/tcounters.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/tcounters.hh 2026-10-26 09:46:36.000000000 +0000 @@ -23,7 +23,6 @@ #pragma once #include -#include #include #include @@ -54,7 +53,7 @@ // time has passed since the last snap update. // To fetch aggregate values, call globals.sum(counter1) or -// globals.avg(counter2), or any aggreggation function. If multiple +// globals.avg(counter2), or any aggregation function. If multiple // counters need to be collected in a consistent way: // auto data = globals.aggregatedSnap(); // @@ -204,11 +203,11 @@ auto GlobalCounters::sum(Enum index) { auto lock = d_guarded.lock(); - auto sum = lock->d_history.at(index); + auto theSum = lock->d_history.at(index); for (const auto& instance : lock->d_instances) { - sum += instance->snapAt(index); + theSum += instance->snapAt(index); } - return sum; + return theSum; } // Average for a specific index @@ -220,14 +219,14 @@ { auto lock = d_guarded.lock(); auto wavg = lock->d_history.at(index); - auto sum = wavg.avg * wavg.weight; + auto theSum = wavg.avg * wavg.weight; auto count = wavg.weight; for (const auto& instance : lock->d_instances) { auto val = instance->snapAt(index); count += val.weight; - sum += val.avg * val.weight; + theSum += val.avg * val.weight; } - return count > 0 ? sum / count : 0; + return count > 0 ? theSum / count : 0; } // Max for a specific index @@ -238,11 +237,11 @@ auto GlobalCounters::max(Enum index) { auto lock = d_guarded.lock(); - uint64_t max = 0; // ignore history + uint64_t theMax = 0; // ignore history for (const auto& instance : lock->d_instances) { - max = std::max(instance->snapAt(index), max); + theMax = std::max(instance->snapAt(index), theMax); } - return max; + return theMax; } // Get a consistent snap of *all* aggregated values diff -Nru pdns-recursor-5.2.13/tcpiohandler.cc pdns-recursor-5.4.9/tcpiohandler.cc --- pdns-recursor-5.2.13/tcpiohandler.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/tcpiohandler.cc 2026-10-26 09:46:36.000000000 +0000 @@ -3,29 +3,18 @@ #include "dolog.hh" #include "iputils.hh" #include "lock.hh" +#include "logging.hh" #include "tcpiohandler.hh" 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 #endif /* HAVE_LIBSODIUM */ TLSCtx::tickets_key_added_hook TLSCtx::s_ticketsKeyAddedHook{nullptr}; +#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) static std::vector> getALPNVector(TLSFrontend::ALPN alpn, bool client) { if (alpn == TLSFrontend::ALPN::DoT) { @@ -46,9 +35,21 @@ return {}; } -#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) #ifdef HAVE_LIBSSL +namespace { +bool shouldDoVerboseLogging() +{ +#ifdef DNSDIST + return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose; +#elif defined(RECURSOR) + return false; +#else + return true; +#endif +} +} + #include #include #include @@ -57,6 +58,7 @@ #include "libssl.hh" +static int sni_server_name_callback(SSL* ssl, int* /* alert */, void* arg); class OpenSSLFrontendContext { @@ -65,11 +67,24 @@ { registerOpenSSLUser(); - auto [ctx, warnings] = libssl_init_server_context(tlsConfig, d_ocspResponses); + auto [ctx, warnings] = libssl_init_server_context(tlsConfig); for (const auto& warning : warnings) { +#if defined(DNSDIST) + SLOG(warnlog("%s", warning), + dnsdist::logging::getTopLogger("openssl-frontend")->info(Logr::Warning, warning)); +#else /* DNSDIST */ warnlog("%s", warning); +#endif /* DNSDIST */ + } + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer): it cannot be initialized before calling libssl_init_server_context() + d_ocspResponses = std::move(ctx.d_ocspResponses); + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer): it cannot be initialized before calling libssl_init_server_context() + d_tlsCtx = std::move(ctx.d_defaultContext); + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer): it cannot be initialized before calling libssl_init_server_context() + d_sniMap = std::move(ctx.d_sniMap); + for (auto& entry : d_sniMap) { + SSL_CTX_set_tlsext_servername_callback(entry.second.get(), &sni_server_name_callback); } - d_tlsCtx = std::move(ctx); if (!d_tlsCtx) { ERR_print_errors_fp(stderr); @@ -86,10 +101,39 @@ OpenSSLTLSTicketKeysRing d_ticketKeys; std::map d_ocspResponses; - std::unique_ptr d_tlsCtx{nullptr, SSL_CTX_free}; + pdns::libssl::ServerContext::SNIToContextMap d_sniMap; + std::shared_ptr d_tlsCtx{nullptr}; pdns::UniqueFilePtr d_keyLogFile{nullptr}; }; + +static int sni_server_name_callback(SSL* ssl, int* /* alert */, void* /* arg */) +{ + const auto* serverName = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if (serverName == nullptr) { + return SSL_TLSEXT_ERR_NOACK; + } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API + auto* frontendCtx = reinterpret_cast(libssl_get_ticket_key_callback_data(ssl)); + if (frontendCtx == nullptr) { + return SSL_TLSEXT_ERR_OK; + } + + auto serverNameView = std::string_view(serverName); + + auto mapIt = frontendCtx->d_sniMap.find(serverNameView); + if (mapIt == frontendCtx->d_sniMap.end()) { + /* keep the default certificate */ + return SSL_TLSEXT_ERR_OK; + } + + /* if it fails there is nothing we can do, + let's hope OpenSSL will fall back to the existing, + default certificate*/ + SSL_set_SSL_CTX(ssl, mapIt->second.get()); + return SSL_TLSEXT_ERR_OK; +} + class OpenSSLSession : public TLSSession { public: @@ -117,7 +161,8 @@ d_socket = socket; if (!d_conn) { - vinfolog("Error creating TLS object"); + VERBOSESLOG(infolog("Error creating TLS object"), + dnsdist::logging::getTopLogger("openssl-server-side")->info(Logr::Info, "Error creating server-side TLS object")); if (shouldDoVerboseLogging()) { ERR_print_errors_fp(stderr); } @@ -137,7 +182,8 @@ d_socket = socket; if (!d_conn) { - vinfolog("Error creating TLS object"); + VERBOSESLOG(infolog("Error creating TLS object"), + dnsdist::logging::getTopLogger("openssl-client-side")->info(Logr::Info, "Error creating client-side TLS object")); if (shouldDoVerboseLogging()) { ERR_print_errors_fp(stderr); } @@ -248,7 +294,7 @@ { auto state = convertIORequestToIOState(res); if (state == IOState::NeedRead) { - res = waitForData(d_socket, timeout.tv_sec, timeout.tv_usec); + res = waitForData(d_socket, timeout); if (res == 0) { throw std::runtime_error("Timeout while reading from TLS connection"); } @@ -257,7 +303,7 @@ } } else if (state == IOState::NeedWrite) { - res = waitForRWData(d_socket, false, timeout.tv_sec, timeout.tv_usec); + res = waitForRWData(d_socket, false, timeout); if (res == 0) { throw std::runtime_error("Timeout while writing to TLS connection"); } @@ -525,6 +571,27 @@ return result; } + [[nodiscard]] std::pair getVerifyResult() const override + { + if (d_conn) { + auto errorCode = SSL_get_verify_result(d_conn.get()); + auto certPresented = errorCode != X509_V_OK; + if (!certPresented) { + auto* cert = SSL_get_peer_certificate(d_conn.get()); + if (cert != nullptr) { + certPresented = true; + X509_free(cert); + } + } + if (!certPresented) { + return {-1, "No certificate presented by peer"}; + } + const auto* errorMsg = X509_verify_cert_error_string(errorCode); + return {errorCode, errorMsg != nullptr ? errorMsg : "No details available"}; + } + return {0, ""}; + } + LibsslTLSVersion getTLSVersion() const override { auto proto = SSL_version(d_conn.get()); @@ -649,33 +716,36 @@ d_ticketsKeyRotationDelay = frontend.d_tlsConfig.d_ticketsKeyRotationDelay; - if (frontend.d_tlsConfig.d_enableTickets && frontend.d_tlsConfig.d_numberOfTicketsKeys > 0) { - /* use our own ticket keys handler so we can rotate them */ + for (auto& entry : d_feContext->d_sniMap) { + auto* ctx = entry.second.get(); + 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); + SSL_CTX_set_tlsext_ticket_key_evp_cb(ctx, &OpenSSLTLSIOCtx::ticketKeyCb); #else - SSL_CTX_set_tlsext_ticket_key_cb(d_feContext->d_tlsCtx.get(), &OpenSSLTLSIOCtx::ticketKeyCb); + SSL_CTX_set_tlsext_ticket_key_cb(ctx, &OpenSSLTLSIOCtx::ticketKeyCb); #endif - libssl_set_ticket_key_callback_data(d_feContext->d_tlsCtx.get(), d_feContext.get()); - } + libssl_set_ticket_key_callback_data(ctx, d_feContext.get()); + } #ifndef DISABLE_OCSP_STAPLING - if (!d_feContext->d_ocspResponses.empty()) { - SSL_CTX_set_tlsext_status_cb(d_feContext->d_tlsCtx.get(), &OpenSSLTLSIOCtx::ocspStaplingCb); - SSL_CTX_set_tlsext_status_arg(d_feContext->d_tlsCtx.get(), &d_feContext->d_ocspResponses); - } + if (!d_feContext->d_ocspResponses.empty()) { + SSL_CTX_set_tlsext_status_cb(ctx, &OpenSSLTLSIOCtx::ocspStaplingCb); + SSL_CTX_set_tlsext_status_arg(ctx, &d_feContext->d_ocspResponses); + } #endif /* DISABLE_OCSP_STAPLING */ - if (frontend.d_tlsConfig.d_readAhead) { - SSL_CTX_set_read_ahead(d_feContext->d_tlsCtx.get(), 1); - } + if (frontend.d_tlsConfig.d_readAhead) { + SSL_CTX_set_read_ahead(ctx, 1); + } - libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &frontend.d_tlsCounters); + libssl_set_error_counters_callback(*ctx, &frontend.d_tlsCounters); - libssl_set_alpn_select_callback(d_feContext->d_tlsCtx.get(), alpnServerSelectCallback, this); + libssl_set_alpn_select_callback(ctx, alpnServerSelectCallback, this); - if (!frontend.d_tlsConfig.d_keyLogFile.empty()) { - d_feContext->d_keyLogFile = libssl_set_key_log_file(d_feContext->d_tlsCtx.get(), frontend.d_tlsConfig.d_keyLogFile); + if (!frontend.d_tlsConfig.d_keyLogFile.empty()) { + d_feContext->d_keyLogFile = libssl_set_key_log_file(ctx, frontend.d_tlsConfig.d_keyLogFile); + } } try { @@ -767,8 +837,13 @@ SSL_CTX_set_verify(d_tlsCtx.get(), SSL_VERIFY_PEER, nullptr); #if (OPENSSL_VERSION_NUMBER < 0x10002000L) +#if defined(DNSDIST) + SLOG(warnlog("TLS hostname validation requested but not supported for OpenSSL < 1.0.2"), + dnsdist::logging::getTopLogger("openssl-client-side")->info(Logr::Warning, "TLS hostname validation requested but not supported for OpenSSL < 1.0.2")); +#else /* DNSDIST */ warnlog("TLS hostname validation requested but not supported for OpenSSL < 1.0.2"); -#endif +#endif /* DNSDIST */ +#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */ } /* we need to set SSL_SESS_CACHE_CLIENT for the "new ticket" callback (below) to be called, @@ -964,7 +1039,7 @@ #include #include -static void safe_memory_lock(void* data, size_t size) +static void safe_memory_lock([[maybe_unused]] void* data, [[maybe_unused]] size_t size) { #ifdef HAVE_LIBSODIUM sodium_mlock(data, size); @@ -1267,13 +1342,13 @@ return; } else if (state == IOState::NeedRead) { - int result = waitForData(d_socket, remainingTime.tv_sec, remainingTime.tv_usec); + int result = waitForData(d_socket, remainingTime); if (result <= 0) { throw std::runtime_error("Error reading from TLS connection: " + std::to_string(result)); } } else if (state == IOState::NeedWrite) { - int result = waitForRWData(d_socket, false, remainingTime.tv_sec, remainingTime.tv_usec); + int result = waitForRWData(d_socket, false, remainingTime); if (result <= 0) { throw std::runtime_error("Error reading from TLS connection: " + std::to_string(result)); } @@ -1380,7 +1455,8 @@ else if (res == GNUTLS_E_AGAIN) { return IOState::NeedWrite; } - vinfolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)); + VERBOSESLOG(infolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)), + dnsdist::logging::getTopLogger("gnutls")->error(Logr::Info, gnutls_strerror(res), "Non-fatal error while writing to TLS connection", "tls.provider", Logging::Loggable("GnuTLS"))); } } while (pos < toWrite); @@ -1416,7 +1492,8 @@ else if (res == GNUTLS_E_AGAIN) { return IOState::NeedRead; } - vinfolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)); + VERBOSESLOG(infolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)), + dnsdist::logging::getTopLogger("gnutls")->error(Logr::Info, gnutls_strerror(res), "Non-fatal error while writing to TLS connection", "tls.provider", Logging::Loggable("GnuTLS"))); } } while (pos < toRead); @@ -1448,13 +1525,14 @@ throw std::runtime_error("Fatal error reading from TLS connection: " + std::string(gnutls_strerror(res))); } else if (res == GNUTLS_E_AGAIN) { - int result = waitForData(d_socket, readTimeout.tv_sec, readTimeout.tv_usec); + int result = waitForData(d_socket, readTimeout); if (result <= 0) { throw std::runtime_error("Error while waiting to read from TLS connection: " + std::to_string(result)); } } else { - vinfolog("Non-fatal error while reading from TLS connection: %s", gnutls_strerror(res)); + VERBOSESLOG(infolog("Non-fatal error while reading from TLS connection: %s", gnutls_strerror(res)), + dnsdist::logging::getTopLogger("gnutls")->error(Logr::Info, gnutls_strerror(res), "Non-fatal error while reading from TLS connection", "tls.provider", Logging::Loggable("GnuTLS"))); } } @@ -1491,13 +1569,14 @@ throw std::runtime_error("Fatal error writing to TLS connection: " + std::string(gnutls_strerror(res))); } else if (res == GNUTLS_E_AGAIN) { - int result = waitForRWData(d_socket, false, writeTimeout.tv_sec, writeTimeout.tv_usec); + int result = waitForRWData(d_socket, false, writeTimeout); if (result <= 0) { throw std::runtime_error("Error waiting to write to TLS connection: " + std::to_string(result)); } } else { - vinfolog("Non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)); + VERBOSESLOG(infolog("Non-fatal error while writing to TLS connection: %s", gnutls_strerror(res)), + dnsdist::logging::getTopLogger("gnutls")->error(Logr::Info, gnutls_strerror(res), "Non-fatal error while writing to TLS connection", "tls.provider", Logging::Loggable("GnuTLS"))); } } } @@ -1566,6 +1645,21 @@ } } + [[nodiscard]] std::pair getVerifyResult() const override + { + if (d_conn) { + auto status = gnutls_session_get_verify_cert_status(d_conn.get()); + gnutls_datum_t out{}; + if (gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509, &out, 0) == 0) { + auto errString = std::string(reinterpret_cast(out.data), out.size); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) It's the API + gnutls_free(out.data); + return {status, errString}; + } + return {status, ""}; + } + return {0, ""}; + } + bool hasSessionBeenResumed() const override { if (d_conn) { @@ -1665,7 +1759,12 @@ 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) { +#if defined(DNSDIST) + SLOG(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)), + dnsdist::logging::getTopLogger("gnutls")->error(Logr::Warning, gnutls_strerror(rc), "Error loading OCSP response for TLS context", "tls.provider", Logging::Loggable("GnuTLS"), "frontend.address", Logging::Loggable(frontend.d_addr), "tls.ocsp_file", Logging::Loggable(file), "tls.certificate_file", Logging::Loggable(frontend.d_tlsConfig.d_certKeyPairs.at(count).d_cert), "tls.key_file", Logging::Loggable(frontend.d_tlsConfig.d_certKeyPairs.at(count).d_key.value()))); +#else /* DNSDIST */ 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)); +#endif /* DNSDIST */ } ++count; } @@ -1883,6 +1982,14 @@ { #if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) std::shared_ptr newCtx{nullptr}; + if (d_parentFrontend) { + newCtx = d_parentFrontend->getContext(); + if (newCtx) { + std::atomic_store_explicit(&d_ctx, std::move(newCtx), std::memory_order_release); + return true; + } + } + /* get the "best" available provider */ #if defined(HAVE_GNUTLS) if (d_provider == "gnutls") { diff -Nru pdns-recursor-5.2.13/tcpiohandler.hh pdns-recursor-5.4.9/tcpiohandler.hh --- pdns-recursor-5.2.13/tcpiohandler.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/tcpiohandler.hh 2026-10-26 09:46:36.000000000 +0000 @@ -39,6 +39,7 @@ virtual bool isUsable() const = 0; virtual std::vector getAsyncFDs() = 0; virtual void close() = 0; + [[nodiscard]] virtual std::pair getVerifyResult() const = 0; void setUnknownTicketKey() { @@ -155,30 +156,35 @@ void rotateTicketsKey(time_t now) { - if (d_ctx != nullptr) { + if (d_ctx != nullptr && d_parentFrontend == nullptr) { d_ctx->rotateTicketsKey(now); } } void loadTicketsKeys(const std::string& file) { - if (d_ctx != nullptr) { + if (d_ctx != nullptr && d_parentFrontend == nullptr) { d_ctx->loadTicketsKeys(file); } } void loadTicketsKey(const std::string& key) { - if (d_ctx != nullptr) { + if (d_ctx != nullptr && d_parentFrontend == nullptr) { d_ctx->loadTicketsKey(key); } } - std::shared_ptr getContext() + std::shared_ptr getContext() const { return std::atomic_load_explicit(&d_ctx, std::memory_order_acquire); } + void setParent(std::shared_ptr parent) + { + std::atomic_store_explicit(&d_parentFrontend, std::move(parent), std::memory_order_release); + } + void cleanup() { d_ctx.reset(); @@ -242,6 +248,7 @@ bool d_proxyProtocolOutsideTLS{false}; protected: std::shared_ptr d_ctx{nullptr}; + std::shared_ptr d_parentFrontend{nullptr}; }; class TCPIOHandler @@ -307,12 +314,12 @@ } else { if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); + SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); } } #else if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); + SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); } #endif /* MSG_FASTOPEN */ @@ -343,12 +350,12 @@ } else { if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, timeout); + SConnectWithTimeout(d_socket, fastOpen, remote, timeout); } } #else if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, timeout); + SConnectWithTimeout(d_socket, fastOpen, remote, timeout); } #endif /* MSG_FASTOPEN */ @@ -375,7 +382,7 @@ } /* Tries to read exactly toRead - pos bytes into the buffer, starting at position pos. - Updates pos everytime a successful read occurs, + Updates pos every time a successful read occurs, throws an std::runtime_error in case of IO error, return Done when toRead bytes have been read, needRead or needWrite if the IO operation would block. @@ -415,7 +422,7 @@ } /* Tries to write exactly toWrite - pos bytes from the buffer, starting at position pos. - Updates pos everytime a successful write occurs, + Updates pos every time a successful write occurs, throws an std::runtime_error in case of IO error, return Done when toWrite bytes have been written, needRead or needWrite if the IO operation would block. @@ -518,6 +525,14 @@ return d_conn != nullptr; } + [[nodiscard]] std::pair getVerifyResult() const + { + if (d_conn) { + return d_conn->getVerifyResult(); + } + return {0, ""}; + } + bool hasTLSSessionBeenResumed() const { return d_conn && d_conn->hasSessionBeenResumed(); diff -Nru pdns-recursor-5.2.13/test-aggressive_nsec_cc.cc pdns-recursor-5.4.9/test-aggressive_nsec_cc.cc --- pdns-recursor-5.2.13/test-aggressive_nsec_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-aggressive_nsec_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -9,7 +9,7 @@ BOOST_AUTO_TEST_SUITE(aggressive_nsec_cc) -BOOST_AUTO_TEST_CASE(test_small_coverering_nsec3) +BOOST_AUTO_TEST_CASE(test_small_covering_nsec3) { AggressiveNSECCache::s_maxNSEC3CommonPrefix = 1; @@ -50,14 +50,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target1, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + // NOLINTNEXTLINE(bugprone-exception-escape) When this test throws an exception, that's ok + sr->setAsyncCallback([target1, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -146,14 +147,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -232,14 +233,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -251,7 +252,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* the name does not exist, a wildcard applies but does not have this type */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("z.powerdns.com."), {QType::TXT, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } else if (domain == DNSName("com.")) { @@ -283,7 +284,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* the name does not exist, a wildcard applies but does not have this type */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("z.powerdns.com."), {QType::TXT, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } } @@ -325,14 +326,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -439,14 +440,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -458,7 +459,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* the name does not exist, a wildcard applies and have the requested type but no DS */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("z.powerdns.com."), {QType::A, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } else if (domain == DNSName("com.")) { @@ -486,10 +487,10 @@ if (type == QType::A) { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.1"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* the name does not exist, a wildcard applies and has the requested type */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("z.powerdns.com."), {QType::A, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } else if (type == QType::TXT) { @@ -498,7 +499,7 @@ addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "powerdns.com. powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY); addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("z.powerdns.com."), {QType::A, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } } @@ -556,14 +557,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target1, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target1, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -659,20 +660,20 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { if (domain != DNSName("powerdns.com.") && domain.isPartOf(DNSName("powerdns.com."))) { /* no cut, NSEC3 */ - return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false, boost::none, true); + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false, std::nullopt, true); } else if (domain == DNSName("com.")) { /* no cut */ @@ -746,14 +747,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -771,7 +772,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* a wildcard applies but does not have this type */ addNSEC3UnhashedRecordToLW(DNSName("*.powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::TXT, QType::RRSIG}, 600, res->d_records, 10); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } else if (domain == DNSName("com.")) { @@ -809,7 +810,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* a wildcard applies but does not have this type */ addNSEC3NoDataNarrowRecordToLW(DNSName("*.powerdns.com."), DNSName("powerdns.com."), {QType::TXT, QType::RRSIG}, 600, res->d_records, 10); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } } @@ -851,14 +852,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -971,14 +972,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -996,7 +997,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* a wildcard applies but does not have this type */ addNSEC3UnhashedRecordToLW(DNSName("*.powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::RRSIG}, 600, res->d_records, 10); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } else if (domain == DNSName("com.")) { @@ -1024,7 +1025,7 @@ if (type == QType::A) { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.1"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* no need for the closest encloser since we have a positive answer expanded from a wildcard */ /* the next closer */ addNSEC3UnhashedRecordToLW(DNSName("+.powerdns.com."), DNSName("powerdns.com."), "v", {QType::RRSIG}, 600, res->d_records, 10); @@ -1087,9 +1088,7 @@ const size_t testSize = 10000; auto cache = make_unique(testSize); - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now, nullptr); vector names; @@ -1235,7 +1234,7 @@ BOOST_CHECK_EQUAL(cache->getEntriesCount(), 3U); - /* we have set a upper bound to 2 entries, so we are above, + /* we have set an upper bound to 2 entries, so we are above, and one entry is actually expired, so we will prune one entry to get below the limit */ cache->prune(now.tv_sec + 15); @@ -1261,9 +1260,7 @@ expected.emplace_back("www.powerdns.org. 10 IN NSEC3 1 0 50 ab HASG==== A RRSIG NSEC3 by ./TYPE0\n"); expected.emplace_back("- RRSIG NSEC3 5 3 10 20370101000000 20370101000000 24567 dummy. data\n"); - struct timeval now - { - }; + struct timeval now{}; Utility::gettimeofday(&now, nullptr); DNSRecord rec; @@ -1348,7 +1345,7 @@ std::vector results; pdns::validation::ValidationContext validationContext; validationContext.d_nsec3IterationsRemainingQuota = std::numeric_limits::max(); - bool found = cache->getDenial(now, name, qtype, results, res, ComboAddress("192.0.2.1"), boost::none, true, validationContext); + bool found = cache->getDenial(now, name, qtype, results, res, ComboAddress("192.0.2.1"), MemRecursorCache::NOTAG, true, validationContext); if (expectedResult) { BOOST_CHECK_EQUAL(res, *expectedResult); } @@ -1381,7 +1378,7 @@ drSOA.d_place = DNSResourceRecord::ANSWER; records.push_back(drSOA); - g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, boost::none, boost::none, vState::Secure); + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); BOOST_CHECK_EQUAL(g_recCache->size(), 1U); std::string oldSalt = "ab"; @@ -1498,7 +1495,7 @@ drSOA.d_place = DNSResourceRecord::ANSWER; records.push_back(drSOA); - g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, boost::none, boost::none, vState::Secure); + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); BOOST_CHECK_EQUAL(g_recCache->size(), 1U); { @@ -1656,7 +1653,7 @@ drSOA.d_place = DNSResourceRecord::ANSWER; records.push_back(drSOA); - g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, boost::none, boost::none, vState::Secure); + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); BOOST_CHECK_EQUAL(g_recCache->size(), 1U); const std::string salt("ab"); @@ -1976,7 +1973,7 @@ drSOA.d_place = DNSResourceRecord::ANSWER; records.push_back(drSOA); - g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, boost::none, boost::none, vState::Secure); + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); BOOST_CHECK_EQUAL(g_recCache->size(), 1U); auto insertNSEC3s = [zone, now](std::unique_ptr& cache, const std::string& salt, unsigned int iterationsCount) -> void { @@ -2114,4 +2111,167 @@ } } +BOOST_AUTO_TEST_CASE(test_aggressive_nsec_dname) +{ + auto cache = make_unique(10000); + g_recCache = std::make_unique(); + + const DNSName zone("powerdns.com"); + time_t now = time(nullptr); + + /* first we need a SOA */ + std::vector records; + time_t ttd = now + 30; + DNSRecord drSOA; + drSOA.d_name = zone; + drSOA.d_type = QType::SOA; + drSOA.d_class = QClass::IN; + drSOA.setContent(std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600")); + drSOA.d_ttl = static_cast(ttd); // XXX truncation + drSOA.d_place = DNSResourceRecord::ANSWER; + records.push_back(drSOA); + + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); + BOOST_CHECK_EQUAL(g_recCache->size(), 1U); + + { + cache = make_unique(10000); + DNSName name("powerdns.com"); + DNSRecord rec; + rec.d_name = name; + rec.d_type = QType::NSEC; + rec.d_ttl = now + 10; + + NSECRecordContent nrc; + nrc.d_next = DNSName("z.powerdns.com"); + for (const auto& type : {QType::DNAME}) { + nrc.set(type); + } + + rec.setContent(std::make_shared(nrc)); + auto rrsig = std::make_shared("NSEC 5 3 10 20370101000000 20370101000000 24567 sub.powerdns.com. data"); + cache->insertNSEC(zone, rec.d_name, rec, {rrsig}, false); + + BOOST_CHECK_EQUAL(cache->getEntriesCount(), 1U); + + /* the cache should NOT be able to deny anything below powerdns.com */ + BOOST_CHECK_EQUAL(getDenialWrapper(cache, now, DNSName("www.powerdns.com"), QType::A), false); + } +} + +BOOST_AUTO_TEST_CASE(test_aggressive_nsec3_dname) +{ + auto cache = make_unique(10000); + g_recCache = std::make_unique(); + AggressiveNSECCache::s_maxNSEC3CommonPrefix = 200; + + const DNSName zone("powerdns.com"); + time_t now = time(nullptr); + + /* first we need a SOA */ + std::vector records; + time_t ttd = now + 30; + DNSRecord drSOA; + drSOA.d_name = zone; + drSOA.d_type = QType::SOA; + drSOA.d_class = QClass::IN; + drSOA.setContent(std::make_shared("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600")); + drSOA.d_ttl = static_cast(ttd); // XXX truncation + drSOA.d_place = DNSResourceRecord::ANSWER; + records.push_back(drSOA); + + g_recCache->replace(now, zone, QType(QType::SOA), records, {}, {}, true, zone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); + BOOST_CHECK_EQUAL(g_recCache->size(), 1U); + + const std::string salt("ab"); + const unsigned int iterationsCount = 1; + { + cache = make_unique(10000); + DNSName closestEncloser("powerdns.com."); + DNSName nextCloser("www.powerdns.com."); + DNSName wildcard("*.powerdns.com."); + + { + /* closest encloser */ + std::string hashed = hashQNameWithSalt(salt, iterationsCount, closestEncloser); + DNSRecord rec; + rec.d_name = DNSName(toBase32Hex(hashed)) + zone; + rec.d_type = QType::NSEC3; + rec.d_ttl = now + 10; + + NSEC3RecordContent nrc; + nrc.d_algorithm = 1; + nrc.d_flags = 0; + nrc.d_iterations = iterationsCount; + nrc.d_salt = salt; + nrc.d_nexthash = hashed; + incrementHash(nrc.d_nexthash); + for (const auto& type : {QType::DNAME}) { + nrc.set(type); + } + + rec.setContent(std::make_shared(nrc)); + auto rrsig = std::make_shared("NSEC3 5 3 10 20370101000000 20370101000000 24567 powerdns.com. data"); + cache->insertNSEC(zone, rec.d_name, rec, {rrsig}, true); + } + + { + /* next closer */ + std::string hashed = hashQNameWithSalt(salt, iterationsCount, nextCloser); + auto before = hashed; + decrementHash(before); + DNSRecord rec; + rec.d_name = DNSName(toBase32Hex(before)) + zone; + rec.d_type = QType::NSEC3; + rec.d_ttl = now + 10; + + NSEC3RecordContent nrc; + nrc.d_algorithm = 1; + nrc.d_flags = 0; + nrc.d_iterations = iterationsCount; + nrc.d_salt = salt; + nrc.d_nexthash = hashed; + incrementHash(nrc.d_nexthash); + for (const auto& type : {QType::A}) { + nrc.set(type); + } + + rec.setContent(std::make_shared(nrc)); + auto rrsig = std::make_shared("NSEC3 5 3 10 20370101000000 20370101000000 24567 powerdns.com. data"); + cache->insertNSEC(zone, rec.d_name, rec, {rrsig}, true); + } + + { + /* wildcard */ + std::string hashed = hashQNameWithSalt(salt, iterationsCount, wildcard); + auto before = hashed; + decrementHash(before); + DNSRecord rec; + rec.d_name = DNSName(toBase32Hex(before)) + zone; + rec.d_type = QType::NSEC3; + rec.d_ttl = now + 10; + + NSEC3RecordContent nrc; + nrc.d_algorithm = 1; + nrc.d_flags = 0; + nrc.d_iterations = iterationsCount; + nrc.d_salt = salt; + nrc.d_nexthash = hashed; + incrementHash(nrc.d_nexthash); + for (const auto& type : {QType::A}) { + nrc.set(type); + } + + rec.setContent(std::make_shared(nrc)); + auto rrsig = std::make_shared("NSEC3 5 3 10 20370101000000 20370101000000 24567 powerdns.com. data"); + cache->insertNSEC(zone, rec.d_name, rec, {rrsig}, true); + } + + BOOST_CHECK_EQUAL(cache->getEntriesCount(), 3U); + + /* the cache should NOT be able to deny anything below powerdns.com */ + BOOST_CHECK_EQUAL(getDenialWrapper(cache, now, DNSName("www.powerdns.com."), QType::A), false); + } +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-base64_cc.cc pdns-recursor-5.4.9/test-base64_cc.cc --- pdns-recursor-5.2.13/test-base64_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-base64_cc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -3,34 +3,35 @@ #endif #define BOOST_TEST_NO_MAIN -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif + #include #include #include "base64.hh" +#include "openssl/conf.h" using namespace boost; BOOST_AUTO_TEST_SUITE(test_base64_cc) BOOST_AUTO_TEST_CASE(test_Base64_Roundtrip) { - std::string before("Some Random String"), after; - std::string encoded = Base64Encode(before); + const std::string before("Some Random String"); + const auto encoded = Base64Encode(before); + + std::string after; B64Decode(encoded, after); BOOST_CHECK_EQUAL(before, after); } -/* for a in $(seq 1 32); - do - plain=$(pwgen -1 -s $a) - echo \(\"$plain\",\"$(echo -n $plain | openssl enc -base64)\"\) ; +/* for a in $(seq 1 32); + do + plain=$(pwgen -1 -s $a) + echo \(\"$plain\",\"$(echo -n $plain | openssl enc -base64)\"\) ; done */ BOOST_AUTO_TEST_CASE(test_Base64_Encode) { - typedef std::map cases_t; + using cases_t = std::map; cases_t cases; assign::insert(cases) ("", "") @@ -67,14 +68,28 @@ ("eSHBt7Xx5F7A4HFtabXEzDLD01bnSiG","ZVNIQnQ3WHg1RjdBNEhGdGFiWEV6RExEMDFiblNpRw==") ("dq4KydZjmcoQQ45VYBP2EDR8FqKaMul0","ZHE0S3lkWmptY29RUTQ1VllCUDJFRFI4RnFLYU11bDA="); - for(const cases_t::value_type& val : cases) { - std::string encoded = Base64Encode(val.first), decoded; + for (const auto& val : cases) { + const auto encoded = Base64Encode(val.first); BOOST_CHECK_EQUAL(encoded, val.second); - decoded.clear(); + std::string decoded; B64Decode(val.second, decoded); BOOST_CHECK_EQUAL(decoded, val.first); } } +BOOST_AUTO_TEST_CASE(test_Base64_Decode_Garbage) +{ + const std::string paddingOnly("===="); + std::string decoded; + auto ret = B64Decode(paddingOnly, decoded); + // DNSdist uses a custom base64 implementation, + // and older versions of OpenSSL were less strict +#if defined(DNSDIST) || OPENSSL_VERSION_NUMBER >= 0x30500000 + BOOST_CHECK_EQUAL(ret, -1); +#else + // does not test anything meaningful, but avoids a "ret unused" warning + BOOST_CHECK(ret == 0 || ret == -1); +#endif +} BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-dns_random_hh.cc pdns-recursor-5.4.9/test-dns_random_hh.cc --- pdns-recursor-5.2.13/test-dns_random_hh.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-dns_random_hh.cc 2026-10-26 09:46:36.000000000 +0000 @@ -28,37 +28,8 @@ BOOST_AUTO_TEST_SUITE(test_dns_random_hh) -const std::vector rndSources = { - "auto", - "urandom", -#if defined(HAVE_GETRANDOM) - "getrandom", -#endif -#if defined(HAVE_ARC4RANDOM) - "arc4random", -#endif -#if defined(HAVE_RANDOMBYTES_STIR) - "sodium", -#endif -#if defined(HAVE_RAND_BYTES) - "openssl", -#endif -#if defined(HAVE_KISS_RNG) - "kiss", -#endif -}; - -BOOST_AUTO_TEST_CASE(test_dns_random_garbage) -{ - ::arg().set("rng") = "garbage"; - ::arg().set("entropy-source") = "/dev/urandom"; -} - BOOST_AUTO_TEST_CASE(test_dns_random_upper_bound) { - ::arg().set("rng") = "auto"; - ::arg().set("entropy-source") = "/dev/urandom"; - map seen; for (unsigned int iteration = 0; iteration < 100000; ++iteration) { seen[dns_random(10)] = true; @@ -77,11 +48,8 @@ BOOST_CHECK_EQUAL(seen[10], false); } -static void test_dns_random_avg(const string& source) +BOOST_AUTO_TEST_CASE(test_dns_random_average) { - ::arg().set("rng") = source; - ::arg().set("entropy-source") = "/dev/urandom"; - acc_t acc; for (unsigned int iteration = 0; iteration < 100000; ++iteration) { @@ -93,11 +61,8 @@ // please add covariance tests, chi-square, Kolmogorov-Smirnov } -static void test_dns_random_uint32_avg(const string& source) +BOOST_AUTO_TEST_CASE(test_dns_random_uint32_average) { - ::arg().set("rng") = source; - ::arg().set("entropy-source") = "/dev/urandom"; - acc_t acc; for (unsigned int iteration = 0; iteration < 100000; ++iteration) { @@ -109,18 +74,4 @@ // please add covariance tests, chi-square, Kolmogorov-Smirnov } -BOOST_AUTO_TEST_CASE(test_dns_random_average) -{ - for (const auto& source : rndSources) { - test_dns_random_avg(source); - } -} - -BOOST_AUTO_TEST_CASE(test_dns_random_uint32_average) -{ - for (const auto& source : rndSources) { - test_dns_random_uint32_avg(source); - } -} - BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-dnsname_cc.cc pdns-recursor-5.4.9/test-dnsname_cc.cc --- pdns-recursor-5.2.13/test-dnsname_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-dnsname_cc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -24,8 +24,8 @@ DNSName aroot("a.root-servers.net"), broot("b.root-servers.net"); BOOST_CHECK(aroot < broot); BOOST_CHECK(!(broot < aroot)); - BOOST_CHECK(aroot.canonCompare(broot)); - BOOST_CHECK(!broot.canonCompare(aroot)); + BOOST_CHECK(aroot.canonCompare_three_way(broot) < 0); + BOOST_CHECK(broot.canonCompare_three_way(aroot) > 0); string before("www.ds9a.nl."); @@ -684,7 +684,7 @@ BOOST_AUTO_TEST_CASE(test_compare_empty) { DNSName a, b; BOOST_CHECK(!(a> 7) & 0xff) | 0xc0); name.append( 1, ((i << 1) & 0xff) | 0x01); } + size_t budget = 99; + BOOST_CHECK_NO_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true, nullptr, nullptr, nullptr, 0, &budget)); + + ++i; + name.append( 1, ((i >> 7) & 0xff) | 0xc0); + name.append( 1, ((i << 1) & 0xff) | 0x01); + + BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true), std::range_error); + DNSName::s_maxPointersToPointers = 4; + DNSName::s_maxPointersPerName = 10; +} + +BOOST_AUTO_TEST_CASE(test_compression_loop3) { // Compression loop (direct pointer to pointer) + + int i; + string name("\x00\xc0\x00", 3); + for (i=0; i<2; ++i) { + name.append( 1, ((i >> 7) & 0xff) | 0xc0); + name.append( 1, ((i << 1) & 0xff) | 0x01); + } BOOST_CHECK_NO_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true)); ++i; @@ -1043,4 +1073,63 @@ BOOST_CHECK_EQUAL(name5.getCommonLabels(name1), DNSName()); } +BOOST_AUTO_TEST_CASE(test_raw_data_comparison) { + const DNSName aroot("a.root-servers.net"); + PacketBuffer query; + GenericDNSPacketWriter packetWriter(query, aroot, QType::A, QClass::IN, 0); + + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic) + const std::string_view raw(reinterpret_cast(query.data()) + sizeof(dnsheader), query.size() - sizeof(dnsheader)); + BOOST_CHECK(aroot.matchesUncompressedName(raw)); + + const DNSName differentCase("A.RooT-Servers.NET"); + BOOST_CHECK(differentCase.matchesUncompressedName(raw)); + + const DNSName broot("b.root-servers.net"); + BOOST_CHECK(!(broot.matchesUncompressedName(raw))); + + /* last character differs */ + const DNSName notaroot("a.root-servers.nes"); + BOOST_CHECK(!(notaroot.matchesUncompressedName(raw))); + } + + { + /* too short */ + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic) + const std::string_view raw(reinterpret_cast(query.data() + sizeof(dnsheader)), aroot.wirelength() - 1); + BOOST_CHECK(!(aroot.matchesUncompressedName(raw))); + } +} + +#if defined(PDNS_AUTH) +BOOST_AUTO_TEST_CASE(test_variantnames) { + ZoneName zone1("..variant"); + ZoneName zone2("bug.less..variant"); + ZoneName zone3(R"(actually\..not.a.variant)"); + ZoneName zone4(R"(still\\\..not.a.variant)"); + ZoneName zone5(R"(anti-\\..variant)"); + ZoneName zone6(R"(sl\\\\\..a\\\..sh\...overflow)"); + + BOOST_CHECK(zone1.hasVariant()); + BOOST_CHECK(zone1.operator const DNSName&().isRoot()); + + BOOST_CHECK(zone2.hasVariant()); + BOOST_CHECK_EQUAL(zone2.operator const DNSName&().toString(), "bug.less."); + BOOST_CHECK_EQUAL(zone2.getVariant(), "variant"); + + BOOST_CHECK(!zone3.hasVariant()); + BOOST_CHECK(!zone4.hasVariant()); + + BOOST_CHECK(zone5.hasVariant()); + BOOST_CHECK_EQUAL(zone5.operator const DNSName&().toString(), R"(anti-\\.)"); + BOOST_CHECK_EQUAL(zone5.getVariant(), "variant"); + + BOOST_CHECK(zone6.hasVariant()); + BOOST_CHECK_EQUAL(zone6.getVariant(), "overflow"); + + BOOST_CHECK_THROW(ZoneName zone("variants.r.us..dot..dot...dot....dot.....dots"),std::out_of_range); +} +#endif + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-dnsrecordcontent.cc pdns-recursor-5.4.9/test-dnsrecordcontent.cc --- pdns-recursor-5.2.13/test-dnsrecordcontent.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-dnsrecordcontent.cc 2026-10-26 09:46:36.000000000 +0000 @@ -17,10 +17,10 @@ ARecordContent a1(ip), a2(ip), a3(ip2); AAAARecordContent aaaa(ip6), aaaa1(ip6); - BOOST_CHECK(a1==a2); - BOOST_CHECK(!(a1==a3)); + BOOST_CHECK(a1.operator==(a2)); + BOOST_CHECK(!(a1.operator==(a3))); - BOOST_CHECK(aaaa == aaaa1); + BOOST_CHECK(aaaa.operator==(aaaa1)); auto rec1 = DNSRecordContent::make(QType::A, 1, "192.168.0.1"); auto rec2 = DNSRecordContent::make(QType::A, 1, "192.168.222.222"); @@ -40,8 +40,8 @@ BOOST_CHECK(!(*rec1==*rec3)); NSRecordContent ns1(DNSName("ns1.powerdns.com")), ns2(DNSName("NS1.powerdns.COM")), ns3(DNSName("powerdns.net")); - BOOST_CHECK(ns1==ns2); - BOOST_CHECK(!(ns1==ns3)); + BOOST_CHECK(ns1.operator==(ns2)); + BOOST_CHECK(!(ns1.operator==(ns3))); } BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-dnsrecords_cc.cc pdns-recursor-5.4.9/test-dnsrecords_cc.cc --- pdns-recursor-5.2.13/test-dnsrecords_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-dnsrecords_cc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -84,9 +84,9 @@ // non-local name (CASE_S(QType::PTR, "ptr.example.com.", "\x03ptr\x07""example\x03""com\x00")) (CASE_S(QType::HINFO, "\"i686\" \"Linux\"", "\x04i686\x05Linux")) - (BROKEN_CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) + (CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) (CASE_L(QType::HINFO, "\"i686\" Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) - (BROKEN_CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) + (CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux")) // local name (CASE_S(QType::MX, "10 mx.rec.test.", "\x00\x0a\x02mx\xc0\x11")) // non-local name @@ -100,7 +100,6 @@ (CASE_S(QType::TXT, "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS")) (CASE_S(QType::TXT, "\"text with DEL in there: \\127\"", "\x19text with DEL in there: \x7f")) (CASE_L(QType::TXT, "\"\xc3\x85LAND ISLANDS\"", "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS")) - (CASE_S(QType::TXT, "\"nonbreakingtxt\"", "\x0enonbreakingtxt")) // local name (CASE_S(QType::RP, "admin.rec.test. admin-info.rec.test.", "\x05""admin\x03rec\x04test\x00\x0a""admin-info\x03rec\x04test\x00")) // non-local name @@ -117,7 +116,13 @@ (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E 10m", "32 7 19.000 S 116 2 25.000 E 10.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x9a\x68")) (CASE_L(QType::LOC, "42 21 54 N 71 06 18 W -24m 30m", "42 21 54.000 N 71 6 18.000 W -24.00m 30.00m 10000.00m 10.00m", "\x00\x33\x16\x13\x89\x17\x2d\xd0\x70\xbe\x15\xf0\x00\x98\x8d\x20")) (CASE_L(QType::LOC, "42 21 43.952 N 71 5 6.344 W -24m 1m 200m", "42 21 43.952 N 71 5 6.344 W -24.00m 1.00m 200.00m 10.00m", "\x00\x12\x24\x13\x89\x17\x06\x90\x70\xbf\x2d\xd8\x00\x98\x8d\x20")) + (CASE_L(QType::LOC, "57 9 0.000 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "57 9 0.000 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8c\x43\x57\xe0\x7f\x8b\x93\x52\x00\x98\x96\x80")) + (CASE_L(QType::LOC, "57 8 59.999 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "57 8 59.999 N 2 7 9.998 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8c\x43\x57\xdf\x7f\x8b\x93\x52\x00\x98\x96\x80")) // local name + (CASE_L(QType::LOC, "51 11 60.000 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "51 12 0.000 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8a\xfc\x80\x00\x7f\x87\x12\xa8\x00\x98\x96\x80")) + (CASE_L(QType::LOC, "51 11 59.999 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "51 11 59.999 N 2 12 5.080 W 0.00m 0.00m 0.00m 0.00m", "\x00\x00\x00\x00\x8a\xfc\x7f\xff\x7f\x87\x12\xa8\x00\x98\x96\x80")) + (CASE_L(QType::LOC, "49 18 0.000 N 10 35 0.000 E 409.00m 1.00m 10000.00m 10.00m", "49 18 0.000 N 10 35 0.000 E 409.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x8a\x94\x21\x40\x82\x45\x5c\x20\x00\x99\x36\x44")) + (CASE_L(QType::LOC, "49 18 0.000 S 10 35 0.000 W 409.00m 1.00m 10000.00m 10.00m", "49 18 0.000 S 10 35 0.000 W 409.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x75\x6b\xde\xc0\x7d\xba\xa3\xe0\x00\x99\x36\x44")) (CASE_S(QType::SRV, "10 10 5060 sip.rec.test.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x03rec\x04test\x00")) // non-local name (CASE_S(QType::SRV, "10 10 5060 sip.example.com.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x07""example\x03""com\x00")) @@ -254,6 +259,17 @@ (CASE_L(QType::SVCB, R"XXX(16 foo.example.org. alpn=f\\\092oo\092,bar,h2)XXX", R"XXX(16 foo.example.org. alpn=f\\\\oo\\,bar,h2)XXX", "\x00\x10\3foo\7example\3org\x00\x00\x01\x00\x0c\x08\x66\\oo,bar\x02h2")) // END SVCB draft test vectors + (CASE_S(QType::SVCB, "1 foo.powerdns.org. dohpath=\"path\"", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x07\0\x04path")) + (CASE_L(QType::SVCB, "1 foo.powerdns.org. dohpath=/q{?dns}", "1 foo.powerdns.org. dohpath=\"/q{?dns}\"", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x07\0\x08/q{?dns}")) + (CASE_S(QType::SVCB, "1 foo.powerdns.org. ohttp", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x08\x00\x00")) + (CASE_S(QType::SVCB, "1 foo.powerdns.org. tls-supported-groups=29,23", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x09\x00\x04\x00\x1d\x00\x17")) + (CASE_S(QType::SVCB, "1 foo.powerdns.org. port=8004 tls-supported-groups=29,23", "\0\x01\3foo\x08powerdns\x03org\x00\x00\x03\x00\x02\x1f\x44\0\x09\x00\x04\x00\x1d\x00\x17")) + + (CASE_S(QType::HHIT, "1234abcd", "\xd7\x6d\xf8\x69\xb7\x1d")) + (CASE_L(QType::HHIT, "1234 abcd", "1234abcd", "\xd7\x6d\xf8\x69\xb7\x1d")) + (CASE_S(QType::BRID, "1234abcd", "\xd7\x6d\xf8\x69\xb7\x1d")) + (CASE_L(QType::BRID, "1234 abcd", "1234abcd", "\xd7\x6d\xf8\x69\xb7\x1d")) + (CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all")) (CASE_S(QType::NID, "15 0123:4567:89AB:CDEF", "\x00\x0F\x01\x23\x45\x67\x89\xab\xcd\xef")) @@ -276,6 +292,7 @@ (CASE_S(QType::CAA, "0 issue \"aa\"", "\x00\x05\x69\x73\x73\x75\x65\x61\x61")) (CASE_S(QType::CAA, "0 issue \"aaaaaaa\"", "\x00\x05\x69\x73\x73\x75\x65\x61\x61\x61\x61\x61\x61\x61")) (CASE_S(QType::CAA, "0 issue \"aaaaaaa.aaa\"", "\x00\x05\x69\x73\x73\x75\x65\x61\x61\x61\x61\x61\x61\x61\x2e\x61\x61\x61")) + (CASE_S(QType::RESINFO, "\"qnamemin exterr=15-17\"", "\x15qnamemin exterr=15-17")) (CASE_S(QType::DLV, "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e")) (CASE_S((QType::typeenum)65226,"\\# 3 414243","\x41\x42\x43")) @@ -378,6 +395,8 @@ // non-local overly large name (256), must be broken (ZONE_CASE(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012.")) (ZONE_CASE(QType::SOA, "ns.rec.test hostmaster.test.rec 20130512010 3600 3600 604800 120")) // too long serial + (ZONE_CASE(QType::TXT, "\\02unlimited")) // incorrect escape + (ZONE_CASE(QType::TXT, "\\384excessive")) // incorrect escape ; int n=0; @@ -716,4 +735,27 @@ } } +BOOST_AUTO_TEST_CASE(test_size_estimate) +{ + auto anA = DNSRecordContent::make(QType::A, QClass::IN, "1.2.3.4"); + auto anAAAA = DNSRecordContent::make(QType::AAAA, QClass::IN, "1234:4578:89ab::"); + auto aTXT = DNSRecordContent::make(QType::TXT, QClass::IN, "\"a somewhat long text\""); + BOOST_CHECK(anAAAA->sizeEstimate() < aTXT->sizeEstimate()); + + auto rrsigA = DNSRecordContent::make(QType::RRSIG, QClass::IN, "SOA 8 3 300 20130523000000 20130509000000 54216 rec.test. ecWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4Y="); + auto rrsigB = DNSRecordContent::make(QType::RRSIG, QClass::IN, "SOA 8 3 300 20130523000000 20130509000000 54216 rec.test. fcWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4YAAAA="); + BOOST_CHECK(rrsigA->sizeEstimate() < rrsigB->sizeEstimate()); + BOOST_CHECK(rrsigA->sizeEstimate() > aTXT->sizeEstimate()); + + auto nsecA = DNSRecordContent::make(QType::NSEC, QClass::IN, "host.example.com. A MX RRSIG NSEC TYPE1234"); + auto nsecB = DNSRecordContent::make(QType::NSEC, QClass::IN, "host1.example.com. A MX RRSIG NSEC TYPE1234"); + BOOST_CHECK(nsecA->sizeEstimate() < nsecB->sizeEstimate()); + BOOST_CHECK(nsecA->sizeEstimate() > aTXT->sizeEstimate()); + + auto nsec3A = DNSRecordContent::make(QType::NSEC3, QClass::IN, "1 1 12 aabbccdd 2vptu5timamqttgl4luu9kg21e0aor3s a mx rrsig nsec3 type1234 type65535"); + auto nsec3B = DNSRecordContent::make(QType::NSEC3, QClass::IN, "1 1 0 - 2vptu5timamqttgl4luu9kg21e0aor3s"); + BOOST_CHECK(nsec3A->sizeEstimate() > nsec3B->sizeEstimate()); + BOOST_CHECK(nsec3B->sizeEstimate() > aTXT->sizeEstimate()); +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-ednscookie_cc.cc pdns-recursor-5.4.9/test-ednscookie_cc.cc --- pdns-recursor-5.2.13/test-ednscookie_cc.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/test-ednscookie_cc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,116 @@ +/* + * 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. + */ +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_NO_MAIN + +#include "config.h" + +#include +#include + +#include "ednscookies.hh" +#include "iputils.hh" + +BOOST_AUTO_TEST_SUITE(test_ednscookie) +BOOST_AUTO_TEST_CASE(test_getEDNSCookiesOptFromString) +{ + std::string cookie; + EDNSCookiesOpt eco(cookie); + // Length 0 + BOOST_CHECK(!eco.isWellFormed()); + + // Too short + cookie = "\x12\x34\x56\x78\x90\xab\xcd"; + BOOST_CHECK(!eco.makeFromString(cookie)); + + // Correct length client cookie + cookie = "\x12\x34\x56\x78\x90\xab\xcd\xef"; + BOOST_CHECK(eco.makeFromString(cookie)); + + // Too short server cookie + cookie = "\x12\x34\x56\x78\x90\xab\xcd\xef\x01"; + BOOST_CHECK(!eco.makeFromString(cookie)); + + cookie = "\x12\x34\x56\x78\x90\xab\xcd\xef\x12\x34\x56\x78\x90\xab\xcd"; + BOOST_CHECK(!eco.makeFromString(cookie)); + + // Have server cookie of correct length + cookie = "\x12\x34\x56\x78\x90\xab\xcd\xef"; + cookie += cookie; // size 16 + BOOST_CHECK(eco.makeFromString(cookie)); + + cookie += cookie; // size 32 + BOOST_CHECK(eco.makeFromString(cookie)); + + cookie += "\x12\x34\x56\x78\x90\xab\xcd\xef"; // size 40 (the max) + BOOST_CHECK(eco.makeFromString(cookie)); + + // Cookie total size too long + cookie += "\x01"; + BOOST_CHECK(!eco.makeFromString(cookie)); +} + +BOOST_AUTO_TEST_CASE(test_ctor) +{ + std::string cookie; + auto eco = EDNSCookiesOpt(cookie); + BOOST_CHECK(!eco.isWellFormed()); + + eco = EDNSCookiesOpt("\x12\x34\x56\x78\x90\xab\xcd\xef"); + BOOST_CHECK(eco.isWellFormed()); + BOOST_CHECK_EQUAL(8U, eco.makeOptString().length()); +} + +#ifdef HAVE_CRYPTO_SHORTHASH +BOOST_AUTO_TEST_CASE(test_createEDNSServerCookie) +{ + auto eco = EDNSCookiesOpt("\x12\x34\x56\x78\x90\xab\xcd\xef"); + ComboAddress remote("192.0.2.2"); + + BOOST_CHECK(eco.isWellFormed()); + + // wrong keysize (not 128 bits) + std::string secret = "blablablabla"; + BOOST_CHECK(!eco.makeServerCookie(secret, remote)); + BOOST_CHECK(eco.isWellFormed()); + BOOST_CHECK(!eco.isValid(secret, remote)); + + secret = "blablablablablab"; + BOOST_CHECK(eco.makeServerCookie(secret, remote)); + BOOST_CHECK(eco.isWellFormed()); + BOOST_CHECK(eco.isValid(secret, remote)); + + EDNSCookiesOpt eco2(eco.makeOptString()); + BOOST_CHECK(!eco2.isValid(secret, ComboAddress("192.0.2.1"))); + BOOST_CHECK(!eco2.isValid("blablablablabla1", remote)); + BOOST_CHECK(eco2.isValid(secret, remote)); + + /* very old cookie (epoch) */ + const auto veryOldCookie = EDNSCookiesOpt(std::string("\x12\x34\x56\x78\x90\xab\xcd\xef\x01\x00\x00\x00\x00\x00\x00\x00\xcb\xc9\x38\x5f\xb5\x75\x75\x2a", (8U + 16U))); + BOOST_CHECK(!veryOldCookie.isValid(secret, remote)); +} +#endif + +BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-ednsoptions_cc.cc pdns-recursor-5.4.9/test-ednsoptions_cc.cc --- pdns-recursor-5.2.13/test-ednsoptions_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-ednsoptions_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -28,8 +28,8 @@ EDNSCookiesOpt cookiesOpt(clientCookie + serverCookie); string cookiesOptionStr = cookiesOpt.makeOptString(); EDNSSubnetOpts ecsOpts; - ecsOpts.source = ecs; - string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); + ecsOpts.setSource(ecs); + string origECSOptionStr = ecsOpts.makeOptString(); DNSPacketWriter::optvect_t opts; opts.emplace_back(EDNSOptionCode::COOKIE, cookiesOptionStr); opts.emplace_back(EDNSOptionCode::ECS, origECSOptionStr); @@ -65,9 +65,9 @@ BOOST_CHECK_EQUAL(res, 0); EDNSSubnetOpts eso; - BOOST_REQUIRE(getEDNSSubnetOptsFromString(reinterpret_cast(&query.at(pos + 9 + ecsStartPosition + 4)), ecsLen - 4, &eso)); + BOOST_REQUIRE(EDNSSubnetOpts::getFromString(reinterpret_cast(&query.at(pos + 9 + ecsStartPosition + 4)), ecsLen - 4, &eso)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - BOOST_CHECK(eso.source == ecs); + BOOST_CHECK(eso.getSource() == ecs); } BOOST_AUTO_TEST_CASE(test_getEDNSOptions) @@ -105,8 +105,8 @@ BOOST_REQUIRE_GT(it->second.values.at(0).size, 0U); EDNSSubnetOpts eso; - BOOST_REQUIRE(getEDNSSubnetOptsFromString(it->second.values.at(0).content, it->second.values.at(0).size, &eso)); - BOOST_CHECK(eso.source == ecs); + BOOST_REQUIRE(EDNSSubnetOpts::getFromString(it->second.values.at(0).content, it->second.values.at(0).size, &eso)); + BOOST_CHECK(eso.getSource() == ecs); it = options.find(EDNSOptionCode::COOKIE); BOOST_REQUIRE(it != options.end()); @@ -121,9 +121,9 @@ { ComboAddress source(sourceStr); EDNSSubnetOpts ecsOpts; - ecsOpts.source = Netmask(source, sourceMask); + ecsOpts.setSource(Netmask(source, sourceMask)); - string ecsOptionStr = makeEDNSSubnetOptsString(ecsOpts); + string ecsOptionStr = ecsOpts.makeOptString(); /* 2 bytes for family, one for source mask and one for scope mask */ const size_t ecsHeaderSize = 4; @@ -157,9 +157,9 @@ } EDNSSubnetOpts parsed; - BOOST_REQUIRE(getEDNSSubnetOptsFromString(ecsOptionStr, &parsed)); - BOOST_REQUIRE(parsed.source == Netmask(truncated, sourceMask)); - BOOST_REQUIRE_EQUAL(ecsOpts.scope.getBits(), parsed.scope.getBits()); + BOOST_REQUIRE(EDNSSubnetOpts::getFromString(ecsOptionStr, &parsed)); + BOOST_REQUIRE(parsed.getSource() == Netmask(truncated, sourceMask)); + BOOST_REQUIRE_EQUAL(ecsOpts.getScopePrefixLength(), parsed.getScopePrefixLength()); } BOOST_AUTO_TEST_CASE(test_makeEDNSSubnetOptsString) @@ -213,4 +213,79 @@ BOOST_CHECK(!getEDNSExtendedErrorOptFromString(empty, parsed)); } +BOOST_AUTO_TEST_CASE(test_slowParseEDNSOptions_root_opt) +{ + const DNSName qname("example.com."); + std::vector packet; + DNSPacketWriter pw(packet, qname, QType::A, QClass::IN, 0); + pw.commit(); + + /* make it look like a response: one answer record */ + pw.startRecord(qname, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER, true); + pw.xfr32BitInt(0x01020304U); + pw.commit(); + + EDNSSubnetOpts ecsOpts; + ecsOpts.setSource(Netmask("192.0.2.0/24")); + const std::string ecsOption = ecsOpts.makeOptString(); + + uint32_t ttl{0}; + EDNS0Record stuff{}; + stuff.version = 0; + stuff.extFlags = htons(0); + stuff.extRCode = 0; + memcpy(&ttl, &stuff, sizeof(stuff)); + ttl = ntohl(ttl); + /* OPT RR with a non-root owner name */ + pw.startRecord(DNSName("."), QType::OPT, ttl, 512U, DNSResourceRecord::ADDITIONAL, false); + pw.xfr16BitInt(EDNSOptionCode::ECS); + pw.xfr16BitInt(ecsOption.length()); + pw.xfrBlob(ecsOption); + pw.commit(); + + PacketBuffer pbuf(packet.begin(), packet.end()); + EDNSOptionViewMap options; + const bool parsed = slowParseEDNSOptions(pbuf, options); + BOOST_CHECK_EQUAL(parsed, true); + BOOST_REQUIRE(options.find(EDNSOptionCode::ECS) != options.end()); + BOOST_CHECK_EQUAL(options.at(EDNSOptionCode::ECS).values.size(), 1U); +} + +BOOST_AUTO_TEST_CASE(test_slowParseEDNSOptions_non_root_opt) +{ + const DNSName qname("example.com."); + std::vector packet; + DNSPacketWriter pw(packet, qname, QType::A, QClass::IN, 0); + pw.commit(); + + /* make it look like a response: one answer record */ + pw.startRecord(qname, QType::A, 60, QClass::IN, DNSResourceRecord::ANSWER, true); + pw.xfr32BitInt(0x01020304U); + pw.commit(); + + EDNSSubnetOpts ecsOpts; + ecsOpts.setSource(Netmask("192.0.2.0/24")); + const std::string ecsOption = ecsOpts.makeOptString(); + + uint32_t ttl{0}; + EDNS0Record stuff{}; + stuff.version = 0; + stuff.extFlags = htons(0); + stuff.extRCode = 0; + memcpy(&ttl, &stuff, sizeof(stuff)); + ttl = ntohl(ttl); + /* OPT RR with a non-root owner name */ + pw.startRecord(DNSName("evil.example."), QType::OPT, ttl, 512U, DNSResourceRecord::ADDITIONAL, false); + pw.xfr16BitInt(EDNSOptionCode::ECS); + pw.xfr16BitInt(ecsOption.length()); + pw.xfrBlob(ecsOption); + pw.commit(); + + PacketBuffer pbuf(packet.begin(), packet.end()); + EDNSOptionViewMap options; + const bool parsed = slowParseEDNSOptions(pbuf, options); + BOOST_CHECK_EQUAL(parsed, false); + BOOST_REQUIRE(options.find(EDNSOptionCode::ECS) == options.end()); +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-filterpo_cc.cc pdns-recursor-5.4.9/test-filterpo_cc.cc --- pdns-recursor-5.2.13/test-filterpo_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-filterpo_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -832,6 +832,24 @@ BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::None); BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::NoAction); } + + { + /* blocked A in the response, except 1 is disabled, so 2 should match */ + DNSRecord dr; + dr.d_type = QType::A; + dr.setContent(DNSRecordContent::make(QType::A, QClass::IN, responseIP.toString())); + const auto matchingPolicy = dfe.getPostPolicy({dr}, {{zone1->getName(), true}}, DNSFilterEngine::maximumPriority); + BOOST_CHECK(matchingPolicy.d_type == DNSFilterEngine::PolicyType::ResponseIP); + BOOST_CHECK(matchingPolicy.d_kind == DNSFilterEngine::PolicyKind::Custom); + auto records = matchingPolicy.getCustomRecords(bad, QType::A); + BOOST_CHECK_EQUAL(records.size(), 1U); + const auto& record = records.at(0); + BOOST_CHECK(record.d_type == QType::CNAME); + BOOST_CHECK(record.d_class == QClass::IN); + auto content = getRR(record); + BOOST_CHECK(content != nullptr); + BOOST_CHECK_EQUAL(content->getTarget().toString(), "response2a.example.net."); + } } BOOST_AUTO_TEST_CASE(test_mask_to_rpz) diff -Nru pdns-recursor-5.2.13/test-iputils_hh.cc pdns-recursor-5.4.9/test-iputils_hh.cc --- pdns-recursor-5.2.13/test-iputils_hh.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-iputils_hh.cc 2026-10-26 09:46:36.000000000 +0000 @@ -71,6 +71,45 @@ BOOST_CHECK_THROW(ComboAddress("[::1]:-6"), PDNSException); // Port no. too low } +BOOST_AUTO_TEST_CASE(test_SockaddrWrapper) { + SockaddrWrapper local("127.0.0.1", 53); + BOOST_CHECK_EQUAL(local.sin4.sin_family, AF_INET); + BOOST_CHECK_EQUAL(local.sin4.sin_port, htons(53)); + BOOST_CHECK_EQUAL(local.sin4.sin_addr.s_addr, htonl(0x7f000001UL)); + + SockaddrWrapper localun("/run/pdns/http.sock", 0); + BOOST_CHECK_EQUAL(localun.sinun.sun_family, AF_UNIX); + + SockaddrWrapper withport("213.244.168.210:53"); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53)); + + SockaddrWrapper withportO("213.244.168.210:53", 5300); + BOOST_CHECK_EQUAL(withportO.sin4.sin_port, htons(53)); + + withport = SockaddrWrapper("[::]:53"); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53)); + + withport = SockaddrWrapper("[::]:5300", 53); + BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(5300)); + + SockaddrWrapper defaultport("213.244.168.210"); + BOOST_CHECK_EQUAL(defaultport.sin4.sin_port, htons(0)); + + defaultport = SockaddrWrapper("[::1]"); + BOOST_CHECK_EQUAL(defaultport.sin4.sin_port, htons(0)); + + defaultport = SockaddrWrapper("::1"); + BOOST_CHECK_EQUAL(defaultport.sin4.sin_port, htons(0)); + + BOOST_CHECK_THROW(SockaddrWrapper("127.0.0.1:70000"), PDNSException); // Port no. too high + BOOST_CHECK_THROW(SockaddrWrapper("127.0.0.1:-6"), PDNSException); // Port no. too low + BOOST_CHECK_THROW(SockaddrWrapper("[::1]:70000"), PDNSException); // Port no. too high + BOOST_CHECK_THROW(SockaddrWrapper("[::1]:-6"), PDNSException); // Port no. too low + + BOOST_CHECK_THROW(SockaddrWrapper("\"\""), PDNSException); + BOOST_CHECK_THROW(SockaddrWrapper("''"), PDNSException); +} + BOOST_AUTO_TEST_CASE(test_ComboAddressCompare) { ComboAddress a, b; a.reset(); @@ -283,8 +322,18 @@ BOOST_CHECK(nm1921 < nm1922); BOOST_CHECK(nm1922 > nm1921); + Netmask outer("20.25.0.0/16"); + Netmask inner("20.25.4.0/24"); + Netmask disjoint("20.24.0.0/16"); + BOOST_CHECK(outer.match(inner.getNetwork())); + BOOST_CHECK(!inner.match(outer.getNetwork())); + BOOST_CHECK(!outer.match(disjoint.getNetwork())); + BOOST_CHECK(!inner.match(disjoint.getNetwork())); + BOOST_CHECK(!disjoint.match(inner.getNetwork())); + BOOST_CHECK(!disjoint.match(outer.getNetwork())); + /* An empty Netmask should be larger than - every others. */ + every other. */ Netmask empty = Netmask(); Netmask full("255.255.255.255/32"); BOOST_CHECK(empty > all); @@ -918,4 +967,28 @@ } } +BOOST_AUTO_TEST_CASE(test_unspecified) +{ + struct TestParams + { + std::string str; + bool unspecified; + }; + const std::array tests{{ + {"0.0.0.0:0", true}, + {"[::]:0", true}, + {"0.0.0.0:853", true}, + {"[::]:853", true}, + {"192.0.2.1:0", false}, + {"192.0.2.1:853", false}, + {"[2001:db8::1]:0", false}, + {"[2001:db8::1]:853", false} + }}; + + for (const auto& test : tests) { + const ComboAddress address(test.str); + BOOST_CHECK_EQUAL(address.isUnspecified(), test.unspecified); + } +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-luawrapper.cc pdns-recursor-5.4.9/test-luawrapper.cc --- pdns-recursor-5.2.13/test-luawrapper.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-luawrapper.cc 2026-10-26 09:46:36.000000000 +0000 @@ -35,3 +35,99 @@ } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(test_luawrapper) + +BOOST_AUTO_TEST_CASE(test_boost_optional) +{ + LuaContext context; + context.writeFunction("testOptional", [](boost::optional incoming) -> boost::optional { + return incoming; + }); + + BOOST_REQUIRE(!context.executeCode>("return testOptional(nil)")); + + { + auto result = context.executeCode>("return testOptional(1)"); + BOOST_REQUIRE(result); + BOOST_CHECK_EQUAL(*result, 1); + } +} + +BOOST_AUTO_TEST_CASE(test_std_optional) +{ + LuaContext context; + context.writeFunction("testOptional", [](std::optional incoming) -> std::optional { + return incoming; + }); + + BOOST_REQUIRE(!context.executeCode>("return testOptional(nil)")); + + { + auto result = context.executeCode>("return testOptional(1)"); + BOOST_REQUIRE(result); + BOOST_CHECK_EQUAL(*result, 1); + } +} + +BOOST_AUTO_TEST_CASE(test_boost_variant) +{ + using MyVariantType = boost::variant; + + LuaContext context; + context.writeFunction("testVariant", [](MyVariantType incoming) -> MyVariantType { + return incoming; + }); + + { + auto result = context.executeCode("return testVariant(1)"); + const auto* content = boost::get(&result); + BOOST_REQUIRE(content); + BOOST_CHECK_EQUAL(*content, 1); + } + + { + auto result = context.executeCode("return testVariant('foo')"); + const auto* content = boost::get(&result); + BOOST_REQUIRE(content); + BOOST_CHECK_EQUAL(*content, "foo"); + } + + { + auto func = [&]() { + context.executeCode("return testVariant(nil)"); + }; + BOOST_CHECK_THROW(func(), LuaContext::ExecutionErrorException); + } +} + +BOOST_AUTO_TEST_CASE(test_std_variant) +{ + using MyVariantType = std::variant; + + LuaContext context; + context.writeFunction("testVariant", [](MyVariantType incoming) -> MyVariantType { + return incoming; + }); + + { + const auto result = context.executeCode("return testVariant(1)"); + BOOST_REQUIRE(std::holds_alternative(result)); + BOOST_CHECK_EQUAL(std::get(result), 1); + } + + { + const auto result = context.executeCode("return testVariant('foo')"); + BOOST_REQUIRE(std::holds_alternative(result)); + BOOST_CHECK_EQUAL(std::get(result), "foo"); + } + + { + auto func = [&]() { + context.executeCode("return testVariant(nil)"); + }; + BOOST_CHECK_THROW(func(), LuaContext::ExecutionErrorException); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-misc_hh.cc pdns-recursor-5.4.9/test-misc_hh.cc --- pdns-recursor-5.2.13/test-misc_hh.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-misc_hh.cc 2026-10-26 09:46:36.000000000 +0000 @@ -213,7 +213,7 @@ BOOST_CHECK_EQUAL(gethostname(buffer, sizeof buffer), 0); std::string my_hostname(buffer); - boost::replace_all(my_hostname, ".", "_"); + std::replace(my_hostname.begin(), my_hostname.end(), '.', '_'); std::string hostname = getCarbonHostName(); // ensure it matches what we get diff -Nru pdns-recursor-5.2.13/test-mtasker.cc pdns-recursor-5.4.9/test-mtasker.cc --- pdns-recursor-5.2.13/test-mtasker.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-mtasker.cc 2026-10-26 08:26:51.000000000 +0000 @@ -178,9 +178,7 @@ for (;;) { mt.schedule(now); - } - }, - std::exception); + } }, std::exception); } BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-packetcache_hh.cc pdns-recursor-5.4.9/test-packetcache_hh.cc --- pdns-recursor-5.2.13/test-packetcache_hh.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-packetcache_hh.cc 2026-10-26 09:46:36.000000000 +0000 @@ -56,9 +56,9 @@ pw1.getHeader()->rd = true; pw1.getHeader()->qr = false; pw1.getHeader()->id = 0x42; - opt.source = Netmask("10.0.59.220/32"); + opt.setSource(Netmask("10.0.59.220/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); pw1.addOpt(512, 0, 0, ednsOptions); pw1.commit(); @@ -70,9 +70,9 @@ pw2.getHeader()->rd = true; pw2.getHeader()->qr = false; pw2.getHeader()->id = 0x84; - opt.source = Netmask("10.0.167.48/32"); + opt.setSource(Netmask("10.0.167.48/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); pw2.addOpt(512, 0, 0, ednsOptions); pw2.commit(); @@ -128,9 +128,9 @@ pw1.getHeader()->rd = true; pw1.getHeader()->qr = false; pw1.getHeader()->id = 0x42; - opt.source = Netmask("10.0.41.6/32"); + opt.setSource(Netmask("10.0.41.6/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions); pw1.commit(); @@ -142,9 +142,9 @@ pw2.getHeader()->rd = true; pw2.getHeader()->qr = false; pw2.getHeader()->id = 0x84; - opt.source = Netmask("10.0.119.79/32"); + opt.setSource(Netmask("10.0.119.79/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); /* no EDNSOpts::DNSSECOK !! */ pw2.addOpt(512, 0, 0, ednsOptions); pw2.commit(); @@ -164,9 +164,9 @@ pw1.getHeader()->rd = true; pw1.getHeader()->qr = false; pw1.getHeader()->id = 0x42; - opt.source = Netmask("192.0.2.1/32"); + opt.setSource(Netmask("192.0.2.1/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); EDNSCookiesOpt cookiesOpt(string("deadbeefdeadbeef")); ednsOptions.emplace_back(EDNSOptionCode::COOKIE, cookiesOpt.makeOptString()); pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions); @@ -180,9 +180,9 @@ pw2.getHeader()->rd = true; pw2.getHeader()->qr = false; pw2.getHeader()->id = 0x84; - opt.source = Netmask("192.0.2.1/32"); + opt.setSource(Netmask("192.0.2.1/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); cookiesOpt.makeFromString(string("deadbeefbadc0fee")); ednsOptions.emplace_back(EDNSOptionCode::COOKIE, cookiesOpt.makeOptString()); pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions); @@ -315,9 +315,9 @@ pw1.getHeader()->rd = true; pw1.getHeader()->qr = false; pw1.getHeader()->id = 0x42; - opt.source = Netmask("10.0.18.199/32"); + opt.setSource(Netmask("10.0.18.199/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); pw1.addOpt(512, 0, 0, ednsOptions); pw1.commit(); @@ -329,9 +329,9 @@ pw2.getHeader()->rd = true; pw2.getHeader()->qr = false; pw2.getHeader()->id = 0x84; - opt.source = Netmask("10.0.131.66/32"); + opt.setSource(Netmask("10.0.131.66/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); pw2.addOpt(512, 0, 0, ednsOptions); pw2.commit(); @@ -350,9 +350,9 @@ pw1.getHeader()->rd = true; pw1.getHeader()->qr = false; pw1.getHeader()->id = 0x42; - opt.source = Netmask("192.0.2.1/32"); + opt.setSource(Netmask("192.0.2.1/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); EDNSCookiesOpt cookiesOpt(string("deadbeefdead\x11\xee\x00\x00").c_str(), 16); ednsOptions.emplace_back(EDNSOptionCode::COOKIE, cookiesOpt.makeOptString()); pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions); @@ -366,9 +366,9 @@ pw2.getHeader()->rd = true; pw2.getHeader()->qr = false; pw2.getHeader()->id = 0x84; - opt.source = Netmask("192.0.2.1/32"); + opt.setSource(Netmask("192.0.2.1/32")); ednsOptions.clear(); - ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)); + ednsOptions.emplace_back(EDNSOptionCode::ECS, opt.makeOptString()); cookiesOpt.makeFromString(string("deadbeefdead\x67\x44\x00\x00").c_str(), 16); ednsOptions.emplace_back(EDNSOptionCode::COOKIE, cookiesOpt.makeOptString()); pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions); diff -Nru pdns-recursor-5.2.13/test-protozero-trace.cc pdns-recursor-5.4.9/test-protozero-trace.cc --- pdns-recursor-5.2.13/test-protozero-trace.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/test-protozero-trace.cc 2026-10-26 09:46:36.000000000 +0000 @@ -0,0 +1,288 @@ +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_NO_MAIN + +#include "config.h" +#include +#include + +#include "protozero-trace.hh" +#include "misc.hh" + +BOOST_AUTO_TEST_SUITE(test_protobuf_trace) + +BOOST_AUTO_TEST_CASE(resource0) +{ + pdns::trace::Resource resource{}; + std::string data; + protozero::pbf_writer writer{data}; + resource.encode(writer); +#if 0 + std::ofstream x("x"); + x << data; +#endif + BOOST_CHECK_EQUAL(makeHexDump(data, " "), ""); +} + +BOOST_AUTO_TEST_CASE(resource1) +{ + pdns::trace::Resource resource{ + { + {"foo0", {"bar"}}, + {"foo1", {99.99}}, + }, + 99, + {{{"schema0", "type0", {"id00", "id01"}, {"desc00", "desc01"}}, + {"schema1", "type1", {"id10", "id11"}, {"desc10", "desc11"}}}}}; + std::string data; + protozero::pbf_writer writer{data}; + resource.encode(writer); +#if 0 + std::ofstream x("x"); + x << data; +#endif + BOOST_CHECK_EQUAL(makeHexDump(data, " "), "0a 0d 0a 04 66 6f 6f 30 12 05 0a 03 62 61 72 0a 11 0a 04 66 6f 6f 31 12 09 21 8f c2 f5 28 5c ff 58 40 10 63 1a 2c 0a 07 73 63 68 65 6d 61 30 12 05 74 79 70 65 30 1a 04 69 64 30 30 1a 04 69 64 30 31 22 06 64 65 73 63 30 30 22 06 64 65 73 63 30 31 1a 2c 0a 07 73 63 68 65 6d 61 31 12 05 74 79 70 65 31 1a 04 69 64 31 30 1a 04 69 64 31 31 22 06 64 65 73 63 31 30 22 06 64 65 73 63 31 31 "); +} + +template +static void testAny(const T& testcase) +{ + std::string data; + protozero::pbf_writer writer{data}; + pdns::trace::AnyValue wrapper{testcase}; + wrapper.encode(writer); +#if 0 + std::ofstream x("x"); + x << data; +#endif + + protozero::pbf_reader reader{data}; + pdns::trace::AnyValue value = pdns::trace::AnyValue::decode(reader); + if (!std::holds_alternative(value)) { + BOOST_CHECK(testcase == std::get(value)); + } + else { + if (std::holds_alternative(wrapper)) { + BOOST_CHECK(std::get(wrapper).values.empty()); + } + else if (std::holds_alternative(wrapper)) { + BOOST_CHECK(std::get(wrapper).values.empty()); + } + } +} + +BOOST_AUTO_TEST_CASE(any) +{ + testAny(std::string{"foo"}); + testAny(false); + testAny(true); + testAny(static_cast(0)); + testAny(static_cast(1)); + testAny(static_cast(-1)); + testAny(std::numeric_limits::min()); + testAny(std::numeric_limits::max()); + testAny(0.0); + testAny(1.0); + testAny(-1.0); + testAny(std::numeric_limits::min()); + testAny(std::numeric_limits::max()); + + pdns::trace::ArrayValue avalue; + testAny(avalue); + avalue.values.emplace_back(pdns::trace::AnyValue{"foo"}); + avalue.values.emplace_back(pdns::trace::AnyValue{1.99}); + testAny(avalue); + + pdns::trace::KeyValueList kvlist; + testAny(kvlist); + kvlist.values.emplace_back(pdns::trace::KeyValue{"foo", {"bar"}}); + kvlist.values.emplace_back(pdns::trace::KeyValue{"baz", {1.99}}); + testAny(kvlist); + + std::vector bytes; + testAny(bytes); + bytes.push_back(0); + bytes.push_back(1); + bytes.push_back(2); + testAny(bytes); +} + +BOOST_AUTO_TEST_CASE(traces1) +{ + pdns::trace::Span span = { + .trace_id = {0x5B, 0x8E, 0xFF, 0xF7, 0x98, 0x03, 0x81, 0x03, 0xD2, 0x69, 0xB6, 0x33, 0x81, 0x3F, 0xC6, 0x0C}, + .span_id = {0xEE, 0xE1, 0x9B, 0x7E, 0xC3, 0xC1, 0xB1, 0x74}, + .trace_state = "", + .parent_span_id = {0xEE, 0xE1, 0x9B, 0x7E, 0xC3, 0xC1, 0xB1, 0x73}, + .name = "I'm a server span", + .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER, + .start_time_unix_nano = 1544712660000000000UL, + .end_time_unix_nano = 1544712661000000000UL, + .attributes = {{"my.span.attr", {"some value"}}}}; + pdns::trace::InstrumentationScope scope = {"my.library", "1.0.0", {{"my.scope.attribute", {"some scope attribute"}}}}; + pdns::trace::ScopeSpans scopespans = {.scope = scope, .spans = {span}}; + pdns::trace::Resource res = {.attributes = {{"service.name", {"my.service"}}}}; + pdns::trace::ResourceSpans resspans = {.resource = res, .scope_spans = {scopespans}}; + pdns::trace::TracesData traces = {.resource_spans = {resspans}}; + + std::string data; + protozero::pbf_writer writer{data}; + traces.encode(writer); +#if 0 + std::ofstream z("z"); + z << data; +#endif + const string expected = "" + "0a d3 01 0a 1e 0a 1c 0a 0c 73 65 72 76 69 63 65 " + "2e 6e 61 6d 65 12 0c 0a 0a 6d 79 2e 73 65 72 76 " + "69 63 65 12 b0 01 0a 41 0a 0a 6d 79 2e 6c 69 62 " + "72 61 72 79 12 05 31 2e 30 2e 30 1a 2c 0a 12 6d " + "79 2e 73 63 6f 70 65 2e 61 74 74 72 69 62 75 74 " + "65 12 16 0a 14 73 6f 6d 65 20 73 63 6f 70 65 20 " + "61 74 74 72 69 62 75 74 65 12 6b 0a 10 5b 8e ff " + "f7 98 03 81 03 d2 69 b6 33 81 3f c6 0c 12 08 ee " + "e1 9b 7e c3 c1 b1 74 22 08 ee e1 9b 7e c3 c1 b1 " + "73 2a 11 49 27 6d 20 61 20 73 65 72 76 65 72 20 " + "73 70 61 6e 30 02 39 00 48 59 e3 fa eb 6f 15 41 " + "00 12 f4 1e fb eb 6f 15 4a 1c 0a 0c 6d 79 2e 73 " + "70 61 6e 2e 61 74 74 72 12 0c 0a 0a 73 6f 6d 65 " + "20 76 61 6c 75 65 "; + BOOST_CHECK_EQUAL(makeHexDump(data, " "), expected); + + protozero::pbf_reader reader{data}; + auto copy = pdns::trace::TracesData::decode(reader); + data.clear(); + protozero::pbf_writer copyWriter{data}; + copy.encode(copyWriter); + BOOST_CHECK_EQUAL(makeHexDump(data, " "), expected); +} + +BOOST_AUTO_TEST_CASE(traces2) +{ + pdns::trace::Span span1{ + .trace_id = {0x5B, 0x8E, 0xFF, 0xF7, 0x98, 0x03, 0x81, 0x03, 0xD2, 0x69, 0xB6, 0x33, 0x81, 0x3F, 0xC6, 0x0C}, + .span_id = {0xEE, 0xE1, 0x9B, 0x7E, 0xC3, 0xC1, 0xB1, 0x74}, + .trace_state = "", + .parent_span_id = {0xEE, 0xE1, 0x9B, 0x7E, 0xC3, 0xC1, 0xB1, 0x73}, + .name = "I'm a server span", + .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER, + .start_time_unix_nano = 1544712660000000000UL, + .end_time_unix_nano = 1544712661000000000UL, + .attributes = {{"my.span.attr", {"some value"}}, {"attr2", {1.0}}}, + .dropped_attributes_count = 1, + .events = { + {.time_unix_nano = 100, + .name = "event1", + .attributes = {{"a", {"b"}}, {"c", {"d"}}}, + .dropped_attributes_count = 101}, + {.time_unix_nano = 200, + .name = "event2", + .attributes = {{"c", {"d"}}, {"e", {""}}}, + .dropped_attributes_count = 201}, + }, + .dropped_events_count = 2, + .links = { + {.trace_id = {0x1}, .span_id = {0x4}, .trace_state = "state1", .attributes = {{"foo", {"bar"}}, {"bar", {true}}}, .dropped_attributes_count = 1000, .flags = static_cast(pdns::trace::SpanFlags::SPAN_FLAGS_TRACE_FLAGS_MASK)}, + {.trace_id = {0x2}, .span_id = {0x3}, .trace_state = "state2", .attributes = {{"foo", {"bar"}}, {"bar", {true}}}, .dropped_attributes_count = 1001, .flags = static_cast(pdns::trace::SpanFlags::SPAN_FLAGS_TRACE_FLAGS_MASK)}, + }, + .dropped_links_count = 3, + .status = {"hi", pdns::trace::Status::StatusCode::STATUS_CODE_OK}, + .flags = 33, + }; + pdns::trace::Span span2{span1}; + pdns::trace::Span span3{span1}; + pdns::trace::Span span4{span1}; + pdns::trace::InstrumentationScope scope{"name", "version", {{"key1", {0.1}}, {"key2", {false}}}, 100}; + pdns::trace::ScopeSpans scopespans1{scope, {span1, span2}, "url"}; + pdns::trace::ScopeSpans scopespans2{scope, {span3, span4}, "url"}; + pdns::trace::Resource res{.attributes = {{"key1", {"foo"}}, {"key2", {"bar"}}}, + .dropped_attributes_count = 99, + .entity_refs = {{"url1", "type1", {"id_key1", "id_key2"}, {"desc_key1", "desc_key2"}}, + {"url2", "type2", {"id_key3", "id_key4"}, {"desc_key3", "desc_key4"}}}}; + pdns::trace::ResourceSpans resspans1{res, {scopespans1, scopespans2}, "url"}; + pdns::trace::ResourceSpans resspans2{res, {scopespans1, scopespans2}, "url"}; + pdns::trace::TracesData traces{{resspans1, resspans2}}; + + std::string data; + protozero::pbf_writer writer{data}; + traces.encode(writer); +#if 0 + std::ofstream x("x"); + x << data; +#endif + protozero::pbf_reader reader{data}; + auto copy = pdns::trace::TracesData::decode(reader); + string copyData; + protozero::pbf_writer copyWriter{copyData}; + copy.encode(copyWriter); + BOOST_CHECK_EQUAL(data, copyData); +} + +BOOST_AUTO_TEST_CASE(EDNSOTTraceRecordView) +{ + std::array data; + data[0] = 0; + data[1] = 1; + size_t i; + for (i = 2; i < data.size(); i++) { + data[i] = i; + } + + pdns::trace::EDNSOTTraceRecordView record(data.data(), data.size()); + + uint8_t version; + BOOST_CHECK(record.getVersion(version)); + BOOST_CHECK_EQUAL(version, 0); + + uint8_t reserved; + BOOST_CHECK(record.getReserved(reserved)); + BOOST_CHECK_EQUAL(reserved, 1); + + pdns::trace::TraceID traceid; + BOOST_CHECK(record.getTraceID(traceid)); + + const std::array expectedTID = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; + BOOST_CHECK_EQUAL_COLLECTIONS(traceid.begin(), traceid.end(), expectedTID.begin(), expectedTID.end()); + + pdns::trace::SpanID spanid; + BOOST_CHECK(record.getSpanID(spanid)); + + const std::array expectedSID = {18, 19, 20, 21, 22, 23, 24, 25}; + BOOST_CHECK_EQUAL_COLLECTIONS(spanid.begin(), spanid.end(), expectedSID.begin(), expectedSID.end()); + + uint8_t flags; + BOOST_CHECK(record.getFlags(flags)); + BOOST_CHECK_EQUAL(flags, 26); +} + +BOOST_AUTO_TEST_CASE(EDNSOTTraceRecord) +{ + std::array data; + pdns::trace::EDNSOTTraceRecord record(data.data()); + + pdns::trace::TraceID traceid; + pdns::trace::SpanID spanid; + traceid.makeRandom(); + spanid.makeRandom(); + record.setVersion(1); + record.setReserved(0); + record.setTraceID(traceid); + record.setSpanID(spanid); + record.setFlags(99); + + std::array expected; + expected[0] = 1; + expected[1] = 0; + + for (size_t i = 0; i < traceid.size(); i++) { + expected[i + 2] = traceid.data()[i]; + } + for (size_t i = 0; i < spanid.size(); i++) { + expected[i + 18] = spanid.data()[i]; + } + expected[pdns::trace::EDNSOTTraceRecord::flagsOffset] = 99; + BOOST_CHECK_EQUAL_COLLECTIONS(data.begin(), data.end(), expected.begin(), expected.end()); +} +BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-rcpgenerator_cc.cc pdns-recursor-5.4.9/test-rcpgenerator_cc.cc --- pdns-recursor-5.2.13/test-rcpgenerator_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-rcpgenerator_cc.cc 2026-10-26 09:46:36.000000000 +0000 @@ -92,6 +92,54 @@ source="key1=\\002h2\\002h3foobar"; // extra data RecordTextReader rtr5(source); BOOST_CHECK_THROW(rtr5.xfrSvcParamKeyVals(v), RecordTextException); + + source="key1"; // no data + RecordTextReader rtr6(source); + BOOST_CHECK_THROW(rtr6.xfrSvcParamKeyVals(v), RecordTextException); + + source="key1=\\000"; // no data + RecordTextReader rtr7(source); + BOOST_CHECK_THROW(rtr7.xfrSvcParamKeyVals(v), RecordTextException); +} + +BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_dohpath) { + string source("dohpath=\"foo/bar\""); + set vals; + RecordTextReader(source).xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::dohpath); + BOOST_CHECK_EQUAL(vals.begin()->getValue(), "foo/bar"); + + // Check the writer + string target; + RecordTextWriter rtw(target); + rtw.xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(target, source); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("dohpath=").xfrSvcParamKeyVals(vals), RecordTextException); + + // Generic + vals.clear(); + RecordTextReader ("key7=\"foo/bar\"").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::dohpath); + BOOST_CHECK_EQUAL(vals.begin()->getValue(), "foo/bar"); + + vals.clear(); + RecordTextReader ("key7=foo/bar").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::dohpath); + BOOST_CHECK_EQUAL(vals.begin()->getValue(), "foo/bar"); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key7").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key7=").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key7=\"\"").xfrSvcParamKeyVals(vals), RecordTextException); } BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_mandatory) { @@ -180,12 +228,37 @@ // Generic v.clear(); - source = "key2"; - RecordTextReader rtr3(source); + RecordTextReader rtr3("key2"); rtr3.xfrSvcParamKeyVals(v); BOOST_CHECK_EQUAL(v.size(), 1U); k = v.begin()->getKey(); BOOST_CHECK(k == SvcParam::no_default_alpn); + + v.clear(); + RecordTextReader rtr4("key2="); + BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr5("key2 ipv4hint=1.2.3.4"); + rtr5.xfrSvcParamKeyVals(v); + BOOST_CHECK_EQUAL(v.size(), 2U); + k = v.begin()->getKey(); + BOOST_CHECK(k == SvcParam::no_default_alpn); + + v.clear(); + RecordTextReader rtr6("ipv4hint=1.2.3.4 key2"); + rtr6.xfrSvcParamKeyVals(v); + BOOST_CHECK_EQUAL(v.size(), 2U); + k = v.begin()->getKey(); + BOOST_CHECK(k == SvcParam::no_default_alpn); + + v.clear(); + RecordTextReader rtr7("key2=port=123 ipv4hint=1.2.3.4"); + BOOST_CHECK_THROW(rtr7.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr8("key2=port=123"); + BOOST_CHECK_THROW(rtr8.xfrSvcParamKeyVals(v), RecordTextException); } BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv4hint) { @@ -263,6 +336,23 @@ source = "key4=\\192\\000\\222"; // Wrong number of octets RecordTextReader rtr7(source); BOOST_CHECK_THROW(rtr7.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr8("key4="); // must have a value + BOOST_CHECK_THROW(rtr8.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr9("ipv4hint="); // must have a value + BOOST_CHECK_THROW(rtr9.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr10("ipv4hint=auto"); // special value + rtr10.xfrSvcParamKeyVals(v); + BOOST_CHECK_EQUAL(v.size(), 1U); + k = v.begin()->getKey(); + BOOST_CHECK(k == SvcParam::ipv4hint); + BOOST_CHECK_EQUAL(v.begin()->getIPHints().size(), 0U); + BOOST_CHECK_EQUAL(v.begin()->getAutoHint(), true); } BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ipv6hint) { @@ -339,6 +429,96 @@ source = "key6=\\040\\001\\015\\270\\000\\123\\000\\000\\000\\000\\000\\000\\000\\000\\000"; // wrong number of octets RecordTextReader rtr7(source); BOOST_CHECK_THROW(rtr7.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr8("key6="); // must have a value + BOOST_CHECK_THROW(rtr8.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr9("ipv6hint="); // must have a value + BOOST_CHECK_THROW(rtr9.xfrSvcParamKeyVals(v), RecordTextException); +} + +BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_tls_supported_groups) { + string source("tls-supported-groups=29,23"); + std::vector expected_value{29, 23}; + set vals; + RecordTextReader (source).xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::tls_supported_groups); + BOOST_CHECK(vals.begin()->getTLSSupportedGroups() == expected_value); + + // Check the writer + string target; + RecordTextWriter(target).xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(target, source); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("tls-supported-groups=").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("tls-supported-groups=foo,bar").xfrSvcParamKeyVals(vals), RecordTextException); + + // Generic + vals.clear(); + RecordTextReader ("key9=29,23").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::tls_supported_groups); + BOOST_CHECK(vals.begin()->getTLSSupportedGroups() == expected_value); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key9").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key9=").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key9=\"\"").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key9=foo,bar").xfrSvcParamKeyVals(vals), RecordTextException); +} + +BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ohttp) { + string source("ohttp"); + set vals; + RecordTextReader(source).xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK(vals.begin()->getKey() == SvcParam::ohttp); + + // Check the writer + string target; + RecordTextWriter(target).xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(target, source); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("ohttp=").xfrSvcParamKeyVals(vals), RecordTextException); + + // Generic + vals.clear(); + RecordTextReader("key8").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 1U); + BOOST_CHECK_EQUAL(vals.begin()->getKey(), SvcParam::ohttp); + BOOST_CHECK(vals.begin()->getKey() == SvcParam::SvcParamKey::ohttp); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key8=").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + RecordTextReader("key8 ipv4hint=1.2.3.4").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 2U); + BOOST_CHECK_EQUAL(std::count_if(vals.begin(), vals.end(), [](const SvcParam& param) { return param.getKey() == SvcParam::ohttp; }), 1); + + vals.clear(); + RecordTextReader("ipv4hint=1.2.3.4 key8").xfrSvcParamKeyVals(vals); + BOOST_CHECK_EQUAL(vals.size(), 2U); + BOOST_CHECK_EQUAL(std::count_if(vals.begin(), vals.end(), [](const SvcParam& param) { return param.getKey() == SvcParam::ohttp; }), 1); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key8=port=123 ipv4hint=1.2.3.4").xfrSvcParamKeyVals(vals), RecordTextException); + + vals.clear(); + BOOST_CHECK_THROW(RecordTextReader("key8=port=123").xfrSvcParamKeyVals(vals), RecordTextException); } BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_port) { @@ -412,7 +592,10 @@ v.clear(); RecordTextReader rtr3("key666"); - BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException); + BOOST_CHECK_NO_THROW(rtr3.xfrSvcParamKeyVals(v)); + BOOST_CHECK_EQUAL(v.size(), 1U); + k = v.begin()->getKey(); + BOOST_CHECK(k == SvcParam::keyFromString("key666")); v.clear(); source = "key666=\"blablabla\""; @@ -490,6 +673,20 @@ RecordTextWriter rtw(target); rtw.xfrSvcParamKeyVals(v); BOOST_CHECK_EQUAL(target, "mandatory=alpn alpn=h2,h3 ipv4hint=192.0.2.1,192.0.2.2 ech=\"dG90YWxseSBib2d1cyBlY2hjb25maWcgdmFsdWU=\" ipv6hint=2001:db8::1 key666=\"foobar\""); + + v.clear(); + RecordTextReader rtr2("mandatory=alpn key666"); // generic key without value at the end of the string + BOOST_CHECK_NO_THROW(rtr2.xfrSvcParamKeyVals(v)); + BOOST_CHECK_EQUAL(v.size(), 2U); + + v.clear(); + RecordTextReader rtr3("key666 key677=\"foo\" mandatory=alpn"); // generic key without value -not- at the end of the string + BOOST_CHECK_NO_THROW(rtr3.xfrSvcParamKeyVals(v)); + BOOST_CHECK_EQUAL(v.size(), 3U); + + v.clear(); + RecordTextReader rtr4("mandatory= key666"); // non-generic key without value -not- at the end of the string + BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException); } BOOST_AUTO_TEST_CASE(test_xfrSvcParamKeyVals_ech) { @@ -519,6 +716,14 @@ BOOST_CHECK(k == SvcParam::ech); val = v.begin()->getECH(); BOOST_CHECK_EQUAL(val, "echconfig"); + + v.clear(); + RecordTextReader rtr3("key5"); + BOOST_CHECK_THROW(rtr3.xfrSvcParamKeyVals(v), RecordTextException); + + v.clear(); + RecordTextReader rtr4("ech=\"\""); + BOOST_CHECK_THROW(rtr4.xfrSvcParamKeyVals(v), RecordTextException); } BOOST_AUTO_TEST_CASE(test_xfrNodeOrLocatorID) { diff -Nru pdns-recursor-5.2.13/test-rec-tcounters_cc.cc pdns-recursor-5.4.9/test-rec-tcounters_cc.cc --- pdns-recursor-5.2.13/test-rec-tcounters_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-rec-tcounters_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -104,10 +104,8 @@ if (dns_random(10000) == 0) { tlocal.updateSnap(); } - struct timespec interval - { - 0, dns_random(20 * 1000 * 1000) - }; + struct timespec interval{ + 0, dns_random(20 * 1000 * 1000)}; nanosleep(&interval, nullptr); } done++; @@ -120,10 +118,8 @@ if (dns_random(10000) == 0) { tlocal.updateSnap(); } - struct timespec interval - { - 0, dns_random(40 * 1000 * 1000) - }; + struct timespec interval{ + 0, dns_random(40 * 1000 * 1000)}; nanosleep(&interval, nullptr); } done++; @@ -135,10 +131,8 @@ auto avg = counts.at(rec::DoubleWAvgCounter::avgLatencyUsec).avg; // std::cerr << avg << std::endl; BOOST_CHECK(avg == 0.0 || (avg >= 1.1 && avg <= 2.2)); - struct timespec interval - { - 0, dns_random(80 * 1000 * 1000) - }; + struct timespec interval{ + 0, dns_random(80 * 1000 * 1000)}; nanosleep(&interval, nullptr); } }); diff -Nru pdns-recursor-5.2.13/test-recpacketcache_cc.cc pdns-recursor-5.4.9/test-recpacketcache_cc.cc --- pdns-recursor-5.2.13/test-recpacketcache_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-recpacketcache_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -47,16 +47,16 @@ pw.commit(); string rpacket((const char*)&packet[0], packet.size()); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); rpc.doPruneTo(now, 0); BOOST_CHECK_EQUAL(rpc.size(), 0U); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); rpc.doWipePacketCache(qname); BOOST_CHECK_EQUAL(rpc.size(), 0U); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); uint32_t qhash2 = 0; bool found = rpc.getResponsePacket(tag, qpacket, now, &fpacket, &age, &qhash2); @@ -117,7 +117,7 @@ pw.commit(); string rpacket((const char*)&packet[0], packet.size()); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); uint32_t qhash2 = 0; bool found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, now, &fpacket, &age, &qhash2); @@ -177,17 +177,17 @@ pw.commit(); string rpacket((const char*)&packet[0], packet.size()); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); rpc.doPruneTo(time(nullptr), 0); BOOST_CHECK_EQUAL(rpc.size(), 0U); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); rpc.doWipePacketCache(qname); BOOST_CHECK_EQUAL(rpc.size(), 0U); - rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); uint32_t qhash2 = 0; bool found = rpc.getResponsePacket(tag, qpacket, future, &fpacket, &age, &qhash2); @@ -253,7 +253,7 @@ BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag1, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), false); BOOST_CHECK_EQUAL(qhash, temphash); - /* Different tag, should still get get the same hash, for both interfaces */ + /* Different tag, should still get the same hash, for both interfaces */ BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, time(nullptr), &fpacket, &age, &temphash), false); BOOST_CHECK_EQUAL(qhash, temphash); BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag2, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &temphash), false); @@ -276,11 +276,11 @@ BOOST_CHECK(r1packet != r2packet); /* inserting a response for tag1 */ - rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); /* inserting a different response for tag2, should not override the first one */ - rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* remove all responses from the cache */ @@ -288,10 +288,10 @@ BOOST_CHECK_EQUAL(rpc.size(), 0U); /* reinsert both */ - rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); - rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* remove the responses by qname, should remove both */ @@ -299,7 +299,7 @@ BOOST_CHECK_EQUAL(rpc.size(), 0U); /* insert the response for tag1 */ - rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag1, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); /* we can retrieve it */ @@ -318,7 +318,7 @@ BOOST_CHECK_EQUAL(temphash, qhash); /* adding a response for the second tag */ - rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(tag2, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* We still get the correct response for the first tag */ @@ -362,14 +362,16 @@ string qpacket(reinterpret_cast(&packet[0]), packet.size()); pw.startRecord(qname, QType::A, ttd); + std::pair ecsInfo; + /* Both interfaces (with and without the qname/qtype/qclass) should get the same hash */ BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, time(nullptr), &fpacket, &age, &qhash), false); - BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, nullptr, &temphash, nullptr, false), false); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, nullptr, &temphash, nullptr, false, ecsInfo), false); BOOST_CHECK_EQUAL(qhash, temphash); - /* Different tcp/udp, should still get get the same hash, for both interfaces */ + /* Different tcp/udp, should still get the same hash, for both interfaces */ BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, time(nullptr), &fpacket, &age, &qhash), false); - BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, nullptr, &temphash, nullptr, true), false); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, nullptr, &temphash, nullptr, true, ecsInfo), false); BOOST_CHECK_EQUAL(qhash, temphash); { @@ -389,11 +391,11 @@ BOOST_CHECK(r1packet != r2packet); /* inserting a response for udp */ - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); /* inserting a different response for tcp, should not override the first one */ - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, true); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, true); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* remove all responses from the cache */ @@ -401,10 +403,10 @@ BOOST_CHECK_EQUAL(rpc.size(), 0U); /* reinsert both */ - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 1U); - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, true); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, true); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* remove the responses by qname, should remove both */ @@ -412,12 +414,12 @@ BOOST_CHECK_EQUAL(rpc.size(), 0U); /* insert the response for tcp */ - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, boost::none, true); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r1packet), time(0), ttd, vState::Indeterminate, std::nullopt, true); BOOST_CHECK_EQUAL(rpc.size(), 1U); vState vState; /* we can retrieve it */ - BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, true), true); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, true, ecsInfo), true); BOOST_CHECK_EQUAL(qhash, temphash); BOOST_CHECK_EQUAL(fpacket, r1packet); @@ -427,12 +429,12 @@ BOOST_CHECK_EQUAL(fpacket, r1packet); /* and not with explicit udp */ - BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, false), false); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, false, ecsInfo), false); /* we should still get the same hash */ BOOST_CHECK_EQUAL(temphash, qhash); /* adding a response for udp */ - rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, boost::none, false); + rpc.insertResponsePacket(0, qhash, string(qpacket), qname, QType::A, QClass::IN, string(r2packet), time(0), ttd, vState::Indeterminate, std::nullopt, false); BOOST_CHECK_EQUAL(rpc.size(), 2U); /* We get the correct response for udp now */ @@ -445,7 +447,7 @@ BOOST_CHECK_EQUAL(fpacket, r2packet); /* and the correct response for tcp */ - BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, true), true); + BOOST_CHECK_EQUAL(rpc.getResponsePacket(0, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &vState, &temphash, nullptr, true, ecsInfo), true); BOOST_CHECK_EQUAL(qhash, temphash); BOOST_CHECK_EQUAL(fpacket, r1packet); } diff -Nru pdns-recursor-5.2.13/test-recursorcache_cc.cc pdns-recursor-5.4.9/test-recursorcache_cc.cc --- pdns-recursor-5.2.13/test-recursorcache_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-recursorcache_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -8,6 +8,7 @@ #include "config.h" #endif #include +#include #include "iputils.hh" #include "recursor_cache.hh" @@ -21,7 +22,7 @@ MemRecursorCache MRC; std::vector records; - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; const DNSName authZone("."); @@ -39,7 +40,7 @@ records.push_back(dr0); BOOST_CHECK_EQUAL(MRC.size(), 0U); - MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_GT(MRC.bytes(), 1U); BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U); @@ -52,10 +53,10 @@ DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); BOOST_CHECK_EQUAL(DNSName(a.toString()), a); - MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); if (!MRC.doWipeCache(a, false)) BOOST_FAIL("Could not remove entry we just added to the cache!"); - MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); } BOOST_CHECK_EQUAL(MRC.size(), counter); @@ -107,7 +108,7 @@ // insert a subnet specific entry records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional("192.0.2.1/25")); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, std::optional("192.0.2.1/25")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // subnet specific should be returned for a matching subnet @@ -126,7 +127,7 @@ // insert a NON-subnet specific entry records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); // NON-subnet specific should always be returned @@ -137,14 +138,14 @@ // insert a subnet specific entry for the same name but a different QType records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional("192.0.2.1/25")); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, std::optional("192.0.2.1/25")); // we should not have replaced the existing entry BOOST_CHECK_EQUAL(MRC.size(), 2U); // insert a TXT one, we will use that later records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, authZone, std::nullopt); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 3U); @@ -229,7 +230,7 @@ // insert auth record records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1")), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), 1U); @@ -251,14 +252,14 @@ records.push_back(dr3); // non-auth should not replace valid auth - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1")), (ttd - now)); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); // but non-auth _should_ replace expired auth - MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); + MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(ttd + 1, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1")), (dr3.d_ttl - (ttd + 1))); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); @@ -267,7 +268,7 @@ // non-auth should replace non-auth records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); // let's first check that non-auth is not returned when we need authoritative data BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::RequireAuth, &retrieved, ComboAddress("127.0.0.1")), -1); @@ -282,20 +283,20 @@ // insert Secure record records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Secure); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::Secure); BOOST_CHECK_EQUAL(MRC.size(), 1U); vState retrievedState = vState::Indeterminate; bool wasAuth = false; - BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), boost::none, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), (ttd - now)); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure)); BOOST_CHECK_EQUAL(wasAuth, true); // try to replace that with a Bogus record - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::BogusNoRRSIG); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::BogusNoRRSIG); BOOST_CHECK_EQUAL(MRC.size(), 1U); retrievedState = vState::Indeterminate; wasAuth = false; - BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), boost::none, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), (ttd - now)); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure)); BOOST_CHECK_EQUAL(wasAuth, true); @@ -310,7 +311,7 @@ // insert an entry for 192.0.0.1/8 records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.0.0.1/8")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::optional("192.0.0.1/8")); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* same as dr2 except for the actual IP */ @@ -326,14 +327,14 @@ // insert another entry but for 192.168.0.1/31 records.clear(); records.push_back(dr4); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.168.0.1/31")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::optional("192.168.0.1/31")); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 2U); // insert the same than the first one but for 192.168.0.2/32 records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.168.0.2/32")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::optional("192.168.0.2/32")); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 3U); @@ -350,7 +351,7 @@ // insert an entry for 192.0.0.1/8, non auth records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::optional("192.0.0.1/8")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, std::optional("192.0.0.1/8")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // we should not get it when we need authoritative data @@ -417,7 +418,7 @@ } // This one should fit - MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, boost::none); + MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::AAAA), MemRecursorCache::None, &retrieved, ComboAddress()), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), MemRecursorCache::s_maxRRSetSize); @@ -425,7 +426,7 @@ dr0.setContent(std::make_shared(dr0Content + std::to_string(MemRecursorCache::s_maxRRSetSize))); records.push_back(dr0); // This one is too large and should throw exception - MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, boost::none); + MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_THROW((void)MRC.get(now, power, QType(QType::AAAA), MemRecursorCache::None, &retrieved, ComboAddress()), @@ -433,7 +434,7 @@ records.resize(1); // This one should fit again - MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, boost::none); + MRC.replace(now, power, QType::AAAA, records, {}, {}, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::AAAA), MemRecursorCache::None, &retrieved, ComboAddress()), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), 1U); @@ -445,7 +446,7 @@ MemRecursorCache MRC; std::vector records; - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; time_t now = time(nullptr); @@ -463,7 +464,7 @@ ns1.d_ttl = static_cast(ttd); // XXX truncation ns1.d_place = DNSResourceRecord::ANSWER; records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* try to raise the TTL, simulating the delegated authoritative server @@ -471,7 +472,7 @@ records.clear(); ns1.d_ttl = static_cast(ttd + 3600); // XXX truncation records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("ghost.powerdns.com."), boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("ghost.powerdns.com."), std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* the TTL should not have been raised */ @@ -489,7 +490,7 @@ MemRecursorCache MRC; std::vector records; - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; time_t now = time(nullptr); @@ -507,7 +508,7 @@ ns1.d_ttl = static_cast(ttd); // XXX truncation ns1.d_place = DNSResourceRecord::ANSWER; records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); // Record will expire soon so we should hit the 5s margin, replace by non-auth data should succeed @@ -517,7 +518,7 @@ records.clear(); records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, false, DNSName("powerdns.com."), boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, false, DNSName("powerdns.com."), std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); // Let time pass, if we did not insert the non-auth record, it will be expired @@ -536,7 +537,7 @@ std::vector records; std::vector> signatures; - std::vector> authRecs; + MemRecursorCache::AuthRecsVec authRecs; const DNSName authZone("."); BOOST_CHECK_EQUAL(MRC.size(), 0U); time_t now = time(nullptr); @@ -568,10 +569,10 @@ /* insert both entries */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -584,11 +585,11 @@ /* the remaining entry should be power2, but to get it we need to go back in the past a bit */ - BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), 1); + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), 1); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); /* check that power1 is gone */ - BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); /* clear everything up */ MRC.doWipeCache(DNSName("."), true); @@ -597,15 +598,15 @@ /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); /* trigger a miss (expired) for power2 */ - BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); /* power2 should have been moved to the front of the expunge queue, and should this time be removed first */ @@ -617,11 +618,11 @@ /* the remaining entry should be power1, but to get it we need to go back in the past a bit */ - BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), 1); + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), 1); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); /* check that power2 is gone */ - BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); } BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) @@ -631,7 +632,7 @@ std::vector records; std::vector> signatures; - std::vector> authRecs; + MemRecursorCache::AuthRecsVec authRecs; const DNSName authZone("."); BOOST_CHECK_EQUAL(MRC.size(), 0U); time_t now = time(nullptr); @@ -663,10 +664,10 @@ /* insert both entries */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -677,11 +678,11 @@ BOOST_CHECK_EQUAL(MRC.size(), 1U); /* the remaining entry should be power2 */ - BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), ttd - now); + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), ttd - now); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); /* check that power1 is gone */ - BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); /* clear everything up */ MRC.doWipeCache(DNSName("."), true); @@ -690,16 +691,16 @@ /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); /* replace the entry for power1 */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -711,11 +712,11 @@ BOOST_CHECK_EQUAL(MRC.size(), 1U); /* the remaining entry should be power1 */ - BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), ttd - now); + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), ttd - now); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); /* check that power2 is gone */ - BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); /* clear everything up */ MRC.doWipeCache(DNSName("."), true); @@ -724,15 +725,15 @@ /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, std::nullopt); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); /* get a hit for power1 */ - BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), ttd - now); + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), ttd - now); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); @@ -743,11 +744,11 @@ BOOST_CHECK_EQUAL(MRC.size(), 1U); /* the remaining entry should be power1 */ - BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), ttd - now); + BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), ttd - now); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); /* check that power2 is gone */ - BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1); + BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, MemRecursorCache::NOTAG, nullptr), -1); MRC.doPrune(now, 0); BOOST_CHECK_EQUAL(MRC.size(), 0U); @@ -811,7 +812,7 @@ const DNSName power("powerdns.com."); const DNSName authZone("."); std::vector records; - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; time_t now = time(nullptr); std::vector retrieved; @@ -845,7 +846,7 @@ /* insert a non-specific entry */ records.push_back(dr1); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); @@ -936,7 +937,7 @@ /* insert a non-specific entry */ records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, std::nullopt); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); @@ -971,7 +972,7 @@ const DNSName power("powerdns.com."); const DNSName authZone("."); std::vector records; - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; time_t now = time(nullptr); std::vector retrieved; @@ -1060,7 +1061,7 @@ MemRecursorCache MRC; const DNSName authZone("."); - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; std::vector> signatures; time_t now = time(nullptr); time_t ttd = now + 30; @@ -1090,8 +1091,8 @@ BOOST_CHECK_EQUAL(MRC.size(), 0U); // An entry without edns subnet gets stored without tag as well - MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none); - MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytag")); + MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG); + MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, string("mytag")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U); BOOST_CHECK_EQUAL(MRC.size(), 0U); @@ -1106,8 +1107,8 @@ DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); BOOST_CHECK_EQUAL(DNSName(a.toString()), a); - MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagA")); - MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagB")); + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, string("mytagA")); + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, string("mytagB")); // After this, we have untagged entries, since no address was specified for both replace calls } @@ -1118,7 +1119,7 @@ int64_t expected = counter; for (counter = 0; counter < 110; counter++) { - if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, nobody, boost::none) > 0) { + if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, nobody, MemRecursorCache::NOTAG) > 0) { matches++; BOOST_CHECK_EQUAL(retrieved.size(), rset0.size()); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr0Content.toString()); @@ -1149,13 +1150,13 @@ // Now insert some tagged entries for (counter = 0; counter < 50; ++counter) { DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); - MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, authZone, boost::optional("128.0.0.0/8"), string("mytagA")); + MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, authZone, std::optional("128.0.0.0/8"), string("mytagA")); } BOOST_CHECK_EQUAL(MRC.size(), 150U); matches = 0; for (counter = 0; counter < 110; counter++) { - if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, nobody, boost::none) > 0) { + if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, nobody, MemRecursorCache::NOTAG) > 0) { matches++; BOOST_CHECK_EQUAL(retrieved.size(), rset0.size()); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr0Content.toString()); @@ -1226,7 +1227,7 @@ rset3.push_back(dr3); // insert a tagged entry - MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, authZone, boost::optional("192.0.2.0/24"), string("mytag")); + MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, authZone, std::optional("192.0.2.0/24"), string("mytag")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // tagged specific should be returned for a matching tag @@ -1239,7 +1240,7 @@ BOOST_CHECK_EQUAL(retrieved.size(), 0U); // insert a new entry without tag - MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, authZone, boost::optional("192.0.3.0/24"), boost::none); + MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, authZone, std::optional("192.0.3.0/24"), MemRecursorCache::NOTAG); BOOST_CHECK_EQUAL(MRC.size(), 2U); // tagged specific should be returned for a matching tag @@ -1248,28 +1249,28 @@ BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr1Content.toString()); // if no tag given nothing should be retrieved if address doesn't match - BOOST_CHECK_LT(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), boost::none), 0); + BOOST_CHECK_LT(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("127.0.0.1"), MemRecursorCache::NOTAG), 0); BOOST_REQUIRE_EQUAL(retrieved.size(), 0U); // if no tag given and no-non-tagged entries matches nothing should be returned - BOOST_CHECK_LT(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.2.2"), boost::none), 0); + BOOST_CHECK_LT(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.2.2"), MemRecursorCache::NOTAG), 0); BOOST_REQUIRE_EQUAL(retrieved.size(), 0U); // Insert untagged entry with no netmask - MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, authZone, boost::none, boost::none); + MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG); BOOST_CHECK_EQUAL(MRC.size(), 3U); // Retrieval with no address and no tag should get that one - BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress(), boost::none), (ttd - now)); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress(), MemRecursorCache::NOTAG), (ttd - now)); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr3Content.toString()); // If no tag given match non-tagged entry - BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.2.2"), boost::none), (ttd - now)); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.2.2"), MemRecursorCache::NOTAG), (ttd - now)); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr3Content.toString()); // If no tag given we should be able to retrieve the netmask specific record - BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.3.1"), boost::none), (ttd - now)); + BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), MemRecursorCache::None, &retrieved, ComboAddress("192.0.3.1"), MemRecursorCache::NOTAG), (ttd - now)); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); @@ -1294,14 +1295,14 @@ MemRecursorCache MRC; const DNSName authZone("."); - std::vector> authRecords; + MemRecursorCache::AuthRecsVec authRecords; DNSRecord dr; dr.d_place = DNSResourceRecord::ANSWER; dr.d_name = DNSName("hi"); dr.d_type = QType::AAAA; dr.d_ttl = 3600; dr.setContent(std::make_shared(ComboAddress("1::2:3:4"))); - authRecords.emplace_back(std::make_shared(dr)); + authRecords.emplace_back(dr); std::vector> signatures; signatures.emplace_back(std::dynamic_pointer_cast(RRSIGRecordContent::make("DNSKEY 8 0 172800 20241111000000 20241021000000 20326 . alCFgDZS+0l5zcpQ/7R+5OFeCrk9KGkNP2F9ynXIXG6QigPj/9qjm0xx ItRJUUim+SrJywAmLKe+48oTUeSRyDKVVg3LGDekLKcIVz0EBqTL2y44 usDlUlxqx5O0LQVHy4h/hm9+dCXFiSBWoV0LcAplV9OYWhxi+CxmxZU5 8vK6eVAde8E2JHdeDuy23WF5lxYEg1q7ehEt5EdRvZ7hZzfawEFR3Qv3 WMootO2eBAAneIe94daJP/i1iwQJ4p+bGVCZ4sJk+Pk9J7lwEQq6Ghkd SpLsRxArUhvoVgtnh0LkAV7TsajYk8K2JRt7wHNDbBV6+Vdq2bh7ZPGv LiGkIQ=="))); @@ -1323,15 +1324,16 @@ const ComboAddress nobody; const ComboAddress somebody("::1"); + const MemRecursorCache::Extra authAddress{ComboAddress{"::2"}, true}; const time_t ttl_time = 90; const size_t expected = 100; for (size_t counter = 0; counter < expected; ++counter) { - DNSName name = DNSName("hello ") + DNSName(std::to_string(counter)); - BOOST_CHECK_EQUAL(DNSName(name.toString()), name); + DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); + BOOST_CHECK_EQUAL(DNSName(a.toString()), a); - MRC.replace(now, name, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Insecure, somebody, false, ttl_time); + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, authAddress, false, ttl_time); } BOOST_CHECK_EQUAL(MRC.size(), expected); @@ -1341,26 +1343,27 @@ for (size_t counter = 0; counter < expected + 10; counter++) { std::vector retrieved; - std::vector> authRecs; - std::vector> sigs; + MemRecursorCache::AuthRecs authRecs; + MemRecursorCache::SigRecs sigs; bool variable = false; vState state = vState::Indeterminate; bool wasAuth = false; DNSName fromZone; - ComboAddress from; - if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, boost::none, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &from) > 0) { + MemRecursorCache::Extra extra; + if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, MemRecursorCache::NOTAG, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &extra) > 0) { matches++; BOOST_CHECK_EQUAL(retrieved.size(), rset0.size()); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr0Content.toString()); - BOOST_CHECK_EQUAL(sigs.size(), 1U); - BOOST_CHECK_EQUAL(sigs.at(0)->getZoneRepresentation(), signatures.at(0)->getZoneRepresentation()); - BOOST_CHECK_EQUAL(authRecs.size(), 1U); + BOOST_CHECK_EQUAL(sigs->size(), 1U); + BOOST_CHECK_EQUAL(sigs->at(0)->getZoneRepresentation(), signatures.at(0)->getZoneRepresentation()); + BOOST_CHECK_EQUAL(authRecs->size(), 1U); - BOOST_CHECK_EQUAL(authRecs.at(0)->toString(), authRecords.at(0)->toString()); + BOOST_CHECK_EQUAL(authRecs->at(0).toString(), authRecords.at(0).toString()); BOOST_CHECK_EQUAL(state, vState::Insecure); BOOST_CHECK_EQUAL(wasAuth, true); BOOST_CHECK_EQUAL(fromZone, authZone); - BOOST_CHECK_EQUAL(from.toString(), somebody.toString()); + BOOST_CHECK_EQUAL(extra.d_address.toString(), authAddress.d_address.toString()); + BOOST_CHECK(extra.d_tcp); } } BOOST_CHECK_EQUAL(matches, expected); @@ -1384,4 +1387,191 @@ } } +BOOST_AUTO_TEST_CASE(test_RecursorAuthRecords) +{ + MemRecursorCache::resetStaticsForTests(); + MemRecursorCache MRC; + + const DNSName authZone("."); + MemRecursorCache::AuthRecsVec authRecords; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("hi"); + dr.d_type = QType::AAAA; + dr.d_ttl = 3600; + dr.setContent(std::make_shared(ComboAddress("1::2:3:4"))); + authRecords.emplace_back(dr); + + std::vector> signatures; + signatures.emplace_back(std::dynamic_pointer_cast(RRSIGRecordContent::make("DNSKEY 8 0 172800 20241111000000 20241021000000 20326 . alCFgDZS+0l5zcpQ/7R+5OFeCrk9KGkNP2F9ynXIXG6QigPj/9qjm0xx ItRJUUim+SrJywAmLKe+48oTUeSRyDKVVg3LGDekLKcIVz0EBqTL2y44 usDlUlxqx5O0LQVHy4h/hm9+dCXFiSBWoV0LcAplV9OYWhxi+CxmxZU5 8vK6eVAde8E2JHdeDuy23WF5lxYEg1q7ehEt5EdRvZ7hZzfawEFR3Qv3 WMootO2eBAAneIe94daJP/i1iwQJ4p+bGVCZ4sJk+Pk9J7lwEQq6Ghkd SpLsRxArUhvoVgtnh0LkAV7TsajYk8K2JRt7wHNDbBV6+Vdq2bh7ZPGv LiGkIQ=="))); + + time_t now = time(nullptr); + time_t ttd = now + 30; + + DNSName power("powerdns.com."); + DNSRecord dr0; + ComboAddress dr0Content("192.0.2.40"); + dr0.d_name = power; + dr0.d_type = QType::A; + dr0.d_class = QClass::IN; + dr0.setContent(std::make_shared(dr0Content)); + dr0.d_ttl = static_cast(ttd); + dr0.d_place = DNSResourceRecord::ANSWER; + std::vector rset0; + rset0.push_back(dr0); + + const ComboAddress nobody; + const ComboAddress somebody("::1"); + const MemRecursorCache::Extra authAddress{ComboAddress{"::2"}, true}; + const time_t ttl_time = 90; + + DNSName aname = DNSName("hello "); + MRC.replace(now, aname, QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, authAddress, false, ttl_time); + MRC.replace(now, aname, QType(QType::AAAA), rset0, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, authAddress, false, ttl_time); + + std::vector retrieved; + MemRecursorCache::AuthRecs authRecs; + MemRecursorCache::SigRecs sigs; + bool variable = false; + vState state = vState::Indeterminate; + bool wasAuth = false; + DNSName fromZone; + MemRecursorCache::Extra extra; + if (MRC.get(now, aname, QType(QType::ANY), MemRecursorCache::None, &retrieved, somebody, MemRecursorCache::NOTAG, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &extra) > 0) { + BOOST_CHECK_EQUAL(retrieved.size(), 2U); + } +} + +#if 0 +volatile bool g_ret; // make sure the optimizer does not get too smart +uint64_t g_totalRuns; +volatile bool g_stop; + +static void alarmHandler(int /* unused */) +{ + g_stop = true; +} + +template +void doRun(const C& cmd, int mseconds = 100) +{ + itimerval timer{}; + timer.it_value.tv_sec = mseconds / 1000; + timer.it_value.tv_usec = 1000 * (mseconds % 1000); + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 0; + + signal(SIGPROF, alarmHandler); + setitimer(ITIMER_PROF, &timer, nullptr); + + unsigned int runs = 0; + g_stop = false; + CPUTime start{}; + start.start(); + while (runs++, !g_stop) { + cmd(); + } + double delta = static_cast(start.ndiff()) / 1000000000.0; + boost::format fmt("'%s' %.02f seconds: %.1f runs/s, %.02f us/run"); + + cerr << (fmt % cmd.getName() % delta % (runs / delta) % (delta * 1000000.0 / runs)) << endl; + g_totalRuns += runs; +} + +struct NOPTest +{ + [[nodiscard]] static string getName() + { + return "null test"; + } + + void operator()() const + { + } +}; + +struct RecordsSpeedTest +{ + [[nodiscard]] static string getName() + { + return "RecordsSpeedTest"; + } + + void operator()() const + { + MemRecursorCache::resetStaticsForTests(); + MemRecursorCache MRC; + + const DNSName authZone("."); + MemRecursorCache::AuthRecsVec authRecords; + DNSRecord dr; + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("hi"); + dr.d_type = QType::AAAA; + dr.d_ttl = 3600; + dr.setContent(std::make_shared(ComboAddress("1::2:3:4"))); + authRecords.emplace_back(dr); + time_t now = time(nullptr); + time_t ttd = now + 30; + + MemRecursorCache::SigRecsVec signatures; + signatures.emplace_back(std::dynamic_pointer_cast(RRSIGRecordContent::make("DNSKEY 8 0 172800 20241111000000 20241021000000 20326 . alCFgDZS+0l5zcpQ/7R+5OFeCrk9KGkNP2F9ynXIXG6QigPj/9qjm0xx ItRJUUim+SrJywAmLKe+48oTUeSRyDKVVg3LGDekLKcIVz0EBqTL2y44 usDlUlxqx5O0LQVHy4h/hm9+dCXFiSBWoV0LcAplV9OYWhxi+CxmxZU5 8vK6eVAde8E2JHdeDuy23WF5lxYEg1q7ehEt5EdRvZ7hZzfawEFR3Qv3 WMootO2eBAAneIe94daJP/i1iwQJ4p+bGVCZ4sJk+Pk9J7lwEQq6Ghkd SpLsRxArUhvoVgtnh0LkAV7TsajYk8K2JRt7wHNDbBV6+Vdq2bh7ZPGv LiGkIQ=="))); + + DNSName power("powerdns.com."); + DNSRecord dr0; + ComboAddress dr0Content("192.0.2.40"); + dr0.d_name = power; + dr0.d_type = QType::A; + dr0.d_class = QClass::IN; + dr0.setContent(std::make_shared(dr0Content)); + dr0.d_ttl = static_cast(ttd); + dr0.d_place = DNSResourceRecord::ANSWER; + std::vector rset0; + rset0.push_back(dr0); + + const ComboAddress nobody; + const ComboAddress somebody("::1"); + const time_t ttl_time = 90; + const size_t expected = 100; + + for (size_t counter = 0; counter < expected; ++counter) { + DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); + BOOST_CHECK_EQUAL(DNSName(a.toString()), a); + + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, std::nullopt, MemRecursorCache::NOTAG, vState::Insecure, MemRecursorCache::Extra{somebody, false}, false, ttl_time); + } + + BOOST_CHECK_EQUAL(MRC.size(), expected); + + size_t matches = 0; + + const size_t runs = 1000; + for (size_t run = 0; run < runs; run++) { + for (size_t counter = 0; counter < expected; ++counter) { + std::vector retrieved; + MemRecursorCache::AuthRecs authRecs; + MemRecursorCache::SigRecs sigs; + bool variable = false; + vState state = vState::Indeterminate; + bool wasAuth = false; + DNSName fromZone; + MemRecursorCache::Extra extra; + if (MRC.get(now, DNSName("hello ") + DNSName(std::to_string(counter)), QType(QType::A), MemRecursorCache::None, &retrieved, somebody, MemRecursorCache::NOTAG, &sigs, &authRecs, &variable, &state, &wasAuth, &fromZone, &extra) > 0) { + BOOST_CHECK_EQUAL(somebody.toString(), extra.d_address.toString()); + BOOST_CHECK(!extra.d_tcp); + matches++; + } + } + } + BOOST_CHECK_EQUAL(matches, runs * expected); + } +}; + +BOOST_AUTO_TEST_CASE(test_speed) +{ + doRun(NOPTest()); + doRun(RecordsSpeedTest()); +} +#endif + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-reczones-helpers.cc pdns-recursor-5.4.9/test-reczones-helpers.cc --- pdns-recursor-5.2.13/test-reczones-helpers.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-reczones-helpers.cc 2026-10-26 08:26:51.000000000 +0000 @@ -277,20 +277,21 @@ ::arg().set("max-generate-steps") = "0"; ::arg().set("max-include-depth") = "0"; - char temp[] = "/tmp/hintsXXXXXXXXXX"; - int fd = mkstemp(temp); - BOOST_REQUIRE(fd > 0); - FILE* fp = fdopen(fd, "w"); - BOOST_REQUIRE(fp != nullptr); - size_t written = fwrite(hints.data(), 1, hints.length(), fp); + string temp{"/tmp/hintsXXXXXXXXXX"}; + int fileDesc = mkstemp(temp.data()); + BOOST_REQUIRE(fileDesc > 0); + FILE* filePointer = fdopen(fileDesc, "w"); + BOOST_REQUIRE(filePointer != nullptr); + size_t written = fwrite(hints.data(), 1, hints.length(), filePointer); BOOST_REQUIRE(written == hints.length()); - BOOST_REQUIRE(fclose(fp) == 0); + BOOST_REQUIRE(fclose(filePointer) == 0); // NOLINT time_t now = time(nullptr); std::vector nsvec; - auto ok = readHintsIntoCache(now, std::string(temp), nsvec); - BOOST_CHECK(ok); + auto readOK = readHintsIntoCache(now, std::string(temp), nsvec); + unlink(temp.data()); + BOOST_CHECK(readOK); BOOST_CHECK_EQUAL(nsvec.size(), 2U); const MemRecursorCache::Flags flags = 0; diff -Nru pdns-recursor-5.2.13/test-rpzloader_cc.cc pdns-recursor-5.4.9/test-rpzloader_cc.cc --- pdns-recursor-5.2.13/test-rpzloader_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-rpzloader_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -12,9 +12,6 @@ #include -// Provide stubs for some symbols -bool g_logRPZChanges{false}; - BOOST_AUTO_TEST_SUITE(rpzloader_cc) BOOST_AUTO_TEST_CASE(test_rpz_loader) @@ -108,7 +105,7 @@ ::arg().set("max-generate-steps") = "1"; ::arg().set("max-include-depth") = "20"; auto zone = std::make_shared(); - auto soa = loadRPZFromFile(rpz, zone, boost::none, false, 3600); + auto soa = loadRPZFromFile(rpz, zone, std::nullopt, false, 3600); unlink(rpz.c_str()); BOOST_CHECK_EQUAL(soa->d_st.serial, 1U); @@ -137,7 +134,7 @@ ::arg().set("max-include-depth") = "20"; auto zone = std::make_shared(); - BOOST_CHECK_THROW(loadRPZFromFile(rpz, zone, boost::none, false, 3600), + BOOST_CHECK_THROW(loadRPZFromFile(rpz, zone, std::nullopt, false, 3600), std::runtime_error); unlink(rpz.c_str()); } @@ -163,7 +160,7 @@ ::arg().set("max-include-depth") = "20"; auto zone = std::make_shared(); zone->setIgnoreDuplicates(true); - auto soa = loadRPZFromFile(rpz, zone, boost::none, false, 3600); + auto soa = loadRPZFromFile(rpz, zone, std::nullopt, false, 3600); unlink(rpz.c_str()); BOOST_CHECK_EQUAL(soa->d_st.serial, 1000000000U); BOOST_CHECK_EQUAL(zone->getDomain(), DNSName(".")); diff -Nru pdns-recursor-5.2.13/test-settings.cc pdns-recursor-5.4.9/test-settings.cc --- pdns-recursor-5.2.13/test-settings.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-settings.cc 2026-10-26 08:26:51.000000000 +0000 @@ -9,7 +9,7 @@ #include #include -#include "settings/cxxsettings.hh" +#include "rec-rust-lib/cxxsettings.hh" BOOST_AUTO_TEST_SUITE(test_settings) @@ -100,9 +100,7 @@ BOOST_CHECK_THROW({ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); auto back = settings.to_yaml_string(); - settings.validate(); - }, - rust::Error); + settings.validate(); }, rust::Error); } BOOST_AUTO_TEST_CASE(test_rust_validation_with_error2) @@ -118,10 +116,7 @@ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); auto back = settings.to_yaml_string(); - BOOST_CHECK_THROW({ - settings.validate(); - }, - rust::Error); + BOOST_CHECK_THROW({ settings.validate(); }, rust::Error); } BOOST_AUTO_TEST_CASE(test_rust_validation_with_error3) @@ -137,9 +132,7 @@ BOOST_CHECK_THROW({ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); auto back = settings.to_yaml_string(); - settings.validate(); - }, - rust::Error); + settings.validate(); }, rust::Error); } BOOST_AUTO_TEST_CASE(test_rust_validation_with_error4) @@ -153,9 +146,7 @@ BOOST_CHECK_THROW({ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); auto back = settings.to_yaml_string(); - settings.validate(); - }, - rust::Error); + settings.validate(); }, rust::Error); } BOOST_AUTO_TEST_CASE(test_rust_validation_with_error5) @@ -194,9 +185,7 @@ BOOST_CHECK_THROW({ auto settings = pdns::rust::settings::rec::parse_yaml_string(yamltest.str()); auto back = settings.to_yaml_string(); - settings.validate(); - }, - rust::Error); + settings.validate(); }, rust::Error); } } @@ -477,7 +466,8 @@ settings.validate(); LuaConfigItems lua1; ProxyMapping proxyMapping; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua1, proxyMapping); + OpenTelemetryTraceConditions conditions; + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua1, proxyMapping, conditions); BOOST_CHECK_EQUAL(lua1.dsAnchors.size(), 2U); BOOST_CHECK_EQUAL(lua1.dsAnchors[DNSName(".")].size(), 1U); BOOST_CHECK_EQUAL(lua1.dsAnchors[DNSName(".")].begin()->getZoneRepresentation(), "19718 13 2 8acbb0cd28f41250a80a491389424d341522d946b0da0c0291f2d3d771d7805a"); @@ -495,7 +485,7 @@ settings = pdns::rust::settings::rec::parse_yaml_string(yaml2); settings.validate(); LuaConfigItems lua2; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua2, proxyMapping); + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua2, proxyMapping, conditions); BOOST_CHECK_EQUAL(lua2.dsAnchors.size(), 2U); BOOST_CHECK_EQUAL(lua2.dsAnchors[DNSName(".")].size(), 2U); BOOST_CHECK_EQUAL(lua2.dsAnchors[DNSName("a")].size(), 2U); @@ -1065,7 +1055,8 @@ // create a Lua config based on YAML LuaConfigItems luaConfig; ProxyMapping proxyMapping; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, luaConfig, proxyMapping); + OpenTelemetryTraceConditions conditions; + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, luaConfig, proxyMapping, conditions); // Create YAML, given a Lua config auto newsettings = pdns::rust::settings::rec::parse_yaml_string(""); diff -Nru pdns-recursor-5.2.13/test-shuffle_cc.cc pdns-recursor-5.4.9/test-shuffle_cc.cc --- pdns-recursor-5.2.13/test-shuffle_cc.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/test-shuffle_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef BOOST_TEST_DYN_LINK +#define BOOST_TEST_DYN_LINK +#endif + +#define BOOST_TEST_NO_MAIN + +#include "config.h" +#include + +#include "shuffle.hh" +#include "test-common.hh" + +BOOST_AUTO_TEST_SUITE(shuffle_cc) + +BOOST_AUTO_TEST_CASE(test_simple) +{ + std::vector list; + auto* address = &list; + addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4"); + addRecordToList(list, DNSName("foo2"), QType::A, "1.2.3.4"); + auto dups = pdns::dedupRecords(list); + BOOST_CHECK_EQUAL(dups, 0U); + BOOST_CHECK_EQUAL(list.size(), 2U); + addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4"); + dups = pdns::dedupRecords(list); + BOOST_CHECK_EQUAL(dups, 1U); + BOOST_CHECK_EQUAL(list.size(), 2U); + addRecordToList(list, DNSName("Foo"), QType::A, "1.2.3.4"); + addRecordToList(list, DNSName("FoO"), QType::A, "1.2.3.4", DNSResourceRecord::ADDITIONAL, 999); + dups = pdns::dedupRecords(list); + BOOST_CHECK_EQUAL(dups, 2U); + BOOST_CHECK_EQUAL(list.size(), 2U); + BOOST_CHECK_EQUAL(address, &list); +} + +BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-signers.cc pdns-recursor-5.4.9/test-signers.cc --- pdns-recursor-5.2.13/test-signers.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-signers.cc 2026-10-26 09:46:36.000000000 +0000 @@ -12,11 +12,12 @@ #include "base32.hh" #include "base64.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include "dnssecinfra.hh" #include "misc.hh" -#include +#include // OPENSSL_VERSION_MAJOR + #include // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables): Boost stuff. @@ -86,7 +87,7 @@ .flags = 256, .rfcFlags = 0, - .algorithm = DNSSECKeeper::RSASHA256, + .algorithm = DNSSEC::RSASHA256, .isDeterministic = true, #if OPENSSL_VERSION_MAJOR >= 3 @@ -156,7 +157,7 @@ .flags = 256, .rfcFlags = 0, - .algorithm = DNSSECKeeper::ECDSA256, + .algorithm = DNSSEC::ECDSA256, .isDeterministic = false, #if OPENSSL_VERSION_MAJOR >= 3 @@ -223,7 +224,7 @@ .flags = 256, .rfcFlags = 257, - .algorithm = DNSSECKeeper::ED25519, + .algorithm = DNSSEC::ED25519, .isDeterministic = true, .pem = "-----BEGIN PRIVATE KEY-----\n" @@ -285,7 +286,7 @@ .flags = 256, .rfcFlags = 257, - .algorithm = DNSSECKeeper::ED448, + .algorithm = DNSSEC::ED448, .isDeterministic = true, .pem = "-----BEGIN PRIVATE KEY-----\n" @@ -307,19 +308,19 @@ BOOST_TEST_MESSAGE("Setting up signer params:"); - addSignerParams(DNSSECKeeper::RSASHA256, "RSA SHA256", rsaSha256SignerParams); + addSignerParams(DNSSEC::RSASHA256, "RSA SHA256", rsaSha256SignerParams); #ifdef HAVE_LIBCRYPTO_ECDSA - addSignerParams(DNSSECKeeper::ECDSA256, "ECDSA SHA256", ecdsaSha256); + addSignerParams(DNSSEC::ECDSA256, "ECDSA SHA256", ecdsaSha256); #endif // We need to have HAVE_LIBCRYPTO_ED25519 for the PEM reader/writer. #if defined(HAVE_LIBCRYPTO_ED25519) - addSignerParams(DNSSECKeeper::ED25519, "ED25519", ed25519); + addSignerParams(DNSSEC::ED25519, "ED25519", ed25519); #endif #if defined(HAVE_LIBCRYPTO_ED448) - addSignerParams(DNSSECKeeper::ED448, "ED448", ed448); + addSignerParams(DNSSEC::ED448, "ED448", ed448); #endif } @@ -342,13 +343,13 @@ sortedRecords_t rrs; /* values taken from rfc8080 for ed25519 and ed448, rfc5933 for gost */ - DNSName qname(dpk.getAlgorithm() == DNSSECKeeper::ECCGOST ? "www.example.net." : "example.com."); + DNSName qname(dpk.getAlgorithm() == DNSSEC::ECCGOST ? "www.example.net." : "example.com."); RRSIGRecordContent rrc; uint32_t expire = 1440021600; uint32_t inception = 1438207200; - if (dpk.getAlgorithm() == DNSSECKeeper::ECCGOST) { + if (dpk.getAlgorithm() == DNSSEC::ECCGOST) { rrc.d_signer = DNSName("example.net."); inception = 946684800; expire = 1893456000; @@ -413,17 +414,17 @@ BOOST_CHECK_EQUAL(drc.getZoneRepresentation(), signer.zoneRepresentation); DNSName name(signer.name); - auto ds1 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA1); + auto ds1 = makeDSFromDNSKey(name, drc, DNSSEC::DIGEST_SHA1); if (!signer.dsSHA1.empty()) { BOOST_CHECK_EQUAL(ds1.getZoneRepresentation(), signer.dsSHA1); } - auto ds2 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA256); + auto ds2 = makeDSFromDNSKey(name, drc, DNSSEC::DIGEST_SHA256); if (!signer.dsSHA256.empty()) { BOOST_CHECK_EQUAL(ds2.getZoneRepresentation(), signer.dsSHA256); } - auto ds4 = makeDSFromDNSKey(name, drc, DNSSECKeeper::DIGEST_SHA384); + auto ds4 = makeDSFromDNSKey(name, drc, DNSSEC::DIGEST_SHA384); if (!signer.dsSHA384.empty()) { BOOST_CHECK_EQUAL(ds4.getZoneRepresentation(), signer.dsSHA384); } diff -Nru pdns-recursor-5.2.13/test-syncres_cc.cc pdns-recursor-5.4.9/test-syncres_cc.cc --- pdns-recursor-5.2.13/test-syncres_cc.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc.cc 2026-10-26 08:26:51.000000000 +0000 @@ -30,27 +30,25 @@ return theArg; } -BaseLua4::~BaseLua4() -{ -} +BaseLua4::~BaseLua4() = default; void BaseLua4::getFeatures(Features& /* features */) { } -bool RecursorLua4::preoutquery(const ComboAddress& /* ns */, const ComboAddress& /* requestor */, const DNSName& /* query */, const QType& /* qtype */, bool /* isTcp */, vector& /* res */, int& /* ret */, RecEventTrace& /* et */, const struct timeval& /* tv */) const +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +bool RecursorLua4::preoutquery(const ComboAddress& /* ns */, const ComboAddress& /* requestor */, const DNSName& /* query */, const QType& /* qtype */, bool& /* isTcp */, vector& /* res */, int& /* ret */, RecEventTrace& /* et */, const struct timeval& /* tv */) const { return false; } +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) bool RecursorLua4::policyHitEventFilter(const ComboAddress& /* remote */, const DNSName& /* qname */, const QType& /* qtype */, bool /* tcp */, DNSFilterEngine::Policy& /* policy */, std::unordered_set& /* tags */, std::unordered_map& /* discardedPolicies */) const { return false; } -RecursorLua4::~RecursorLua4() -{ -} +RecursorLua4::~RecursorLua4() = default; void RecursorLua4::postPrepareContext() { @@ -64,7 +62,7 @@ { } -LWResult::Result asyncresolve(const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, const std::shared_ptr>>& /* outgoingLoggers */, const std::shared_ptr>>& /* fstrmLoggers */, const std::set& /* exportTypes */, LWResult* /* res */, bool* /* chained */) +LWResult::Result asyncresolve(const OptLog& /* log */, const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, const std::shared_ptr>>& /* outgoingLoggers */, const std::shared_ptr>>& /* fstrmLoggers */, const std::set& /* exportTypes */, LWResult* /* res */, bool* /* chained */) { return LWResult::Result::Timeout; } @@ -80,40 +78,44 @@ bool primeHints(time_t now) { vector nsset; - if (!g_recCache) + if (!g_recCache) { g_recCache = std::make_unique(); - if (!g_negCache) + } + if (!g_negCache) { g_negCache = std::make_unique(); + } - DNSRecord arr, aaaarr, nsrr; + DNSRecord arr; + DNSRecord aaaarr; + DNSRecord nsrr; nsrr.d_name = g_rootdnsname; arr.d_type = QType::A; aaaarr.d_type = QType::AAAA; nsrr.d_type = QType::NS; arr.d_ttl = aaaarr.d_ttl = nsrr.d_ttl = now + 3600000; - for (char c = 'a'; c <= 'm'; ++c) { - char templ[40]; - strncpy(templ, "a.root-servers.net.", sizeof(templ) - 1); - templ[sizeof(templ) - 1] = '\0'; - *templ = c; - aaaarr.d_name = arr.d_name = DNSName(templ); - nsrr.setContent(std::make_shared(DNSName(templ))); - arr.setContent(std::make_shared(ComboAddress(rootIps4[c - 'a']))); + for (char character = 'a'; character <= 'm'; ++character) { + std::array templ{}; + strncpy(templ.data(), "a.root-servers.net.", sizeof(templ) - 1); + templ[templ.size() - 1] = '\0'; + templ.at(0) = character; + aaaarr.d_name = arr.d_name = DNSName(templ.data()); + nsrr.setContent(std::make_shared(DNSName(templ.data()))); + arr.setContent(std::make_shared(ComboAddress(rootIps4.at(character - 'a')))); vector aset; aset.push_back(arr); - g_recCache->replace(now, DNSName(templ), QType(QType::A), aset, vector>(), vector>(), false, g_rootdnsname); - if (!rootIps6[c - 'a'].empty()) { - aaaarr.setContent(std::make_shared(ComboAddress(rootIps6[c - 'a']))); + g_recCache->replace(now, DNSName(templ.data()), QType(QType::A), aset, vector>(), {}, false, g_rootdnsname); + if (!rootIps6.at(character - 'a').empty()) { + aaaarr.setContent(std::make_shared(ComboAddress(rootIps6.at(character - 'a')))); vector aaaaset; aaaaset.push_back(aaaarr); - g_recCache->replace(now, DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), false, g_rootdnsname); + g_recCache->replace(now, DNSName(templ.data()), QType(QType::AAAA), aaaaset, vector>(), {}, false, g_rootdnsname); } nsset.push_back(nsrr); } - g_recCache->replace(now, g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false, g_rootdnsname); // and stuff in the cache + g_recCache->replace(now, g_rootdnsname, QType(QType::NS), nsset, vector>(), {}, false, g_rootdnsname); // and stuff in the cache return true; } @@ -299,7 +301,7 @@ return false; } -void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, const sortedRecords_t& toSign, boost::optional algo, boost::optional inception, boost::optional now) +void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, const sortedRecords_t& toSign, std::optional algo, std::optional inception, std::optional now) { if (!now) { now = time(nullptr); @@ -323,7 +325,7 @@ typedef std::unordered_map> testkeysset_t; -bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, bool broken, boost::optional algo, boost::optional wildcard, boost::optional now) +bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, std::variant broken, std::optional algo, std::optional wildcard, std::optional now) { if (records.empty()) { return false; @@ -364,10 +366,13 @@ } RRSIGRecordContent rrc; - computeRRSIG(it->second.first, signer, wildcard ? *wildcard : name, type, ttl, sigValidity, rrc, recordcontents, algo, boost::none, now); - if (broken) { + computeRRSIG(it->second.first, signer, wildcard ? *wildcard : name, type, ttl, sigValidity, rrc, recordcontents, algo, std::nullopt, now); + if (auto* bval = std::get_if(&broken); bval != nullptr && *bval) { rrc.d_signature[0] ^= 42; } + else if (auto* ival = std::get_if(&broken)) { + rrc.d_signature[0] ^= *ival; // NOLINT(*-narrowing-conversions) + } DNSRecord rec; rec.d_type = QType::RRSIG; @@ -502,7 +507,7 @@ dsAnchors[name].insert(keys[name].second); } -LWResult::Result genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut, boost::optional now, bool nsec3, bool optOut) +LWResult::Result genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut, std::optional now, bool nsec3, bool optOut) { if (type == QType::DS) { auth.chopOff(); @@ -510,7 +515,7 @@ setLWResult(res, 0, true, false, true); if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) { - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, now); } else { addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); @@ -519,7 +524,7 @@ const auto it = keys.find(auth); if (it != keys.cend()) { /* sign the SOA */ - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, now); /* add a NSEC denying the DS */ std::set types = {QType::RRSIG}; if (proveCut) { @@ -535,7 +540,7 @@ addNSEC3UnhashedRecordToLW(domain, auth, next.toString(), types, 600, res->d_records, 10, optOut); } - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, now); } } @@ -545,7 +550,7 @@ if (type == QType::DNSKEY) { setLWResult(res, 0, true, false, true); addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, now); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, now); return LWResult::Result::Success; } @@ -584,3 +589,5 @@ } return LWResult::Result::Timeout; } + +#include "rec-web-stubs.hh" diff -Nru pdns-recursor-5.2.13/test-syncres_cc.hh pdns-recursor-5.4.9/test-syncres_cc.hh --- pdns-recursor-5.2.13/test-syncres_cc.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc.hh 2026-10-26 08:26:51.000000000 +0000 @@ -23,7 +23,7 @@ #include "arguments.hh" #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include "rec-lua-conf.hh" #include "syncres.hh" #include "test-common.hh" @@ -44,11 +44,11 @@ bool isRootServer(const ComboAddress& ip); -void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, const sortedRecords_t& toSign, boost::optional algo = boost::none, boost::optional inception = boost::none, boost::optional now = boost::none); +void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, const sortedRecords_t& toSign, std::optional algo = std::nullopt, std::optional inception = std::nullopt, std::optional now = std::nullopt); typedef std::unordered_map> testkeysset_t; -bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, bool broken = false, boost::optional algo = boost::none, boost::optional wildcard = boost::none, boost::optional now = boost::none); +bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, std::variant broken = false, std::optional algo = std::nullopt, std::optional wildcard = std::nullopt, std::optional now = std::nullopt); void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector& records); @@ -71,6 +71,6 @@ void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map& dsAnchors); -LWResult::Result genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut = true, boost::optional now = boost::none, bool nsec3 = false, bool optOut = false); +LWResult::Result genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut = true, std::optional now = std::nullopt, bool nsec3 = false, bool optOut = false); LWResult::Result basicRecordsForQnameMinimization(LWResult* res, const DNSName& domain, int type); diff -Nru pdns-recursor-5.2.13/test-syncres_cc1.cc pdns-recursor-5.4.9/test-syncres_cc1.cc --- pdns-recursor-5.2.13/test-syncres_cc1.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc1.cc 2026-10-26 08:26:51.000000000 +0000 @@ -50,7 +50,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -85,7 +85,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == g_rootdnsname && type == QType::NS) { @@ -121,7 +121,7 @@ then call getRootNS(), for which at least one of the root servers needs to answer. None will, so it should ServFail. */ - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { downServers.insert(address); return LWResult::Result::Timeout; }); @@ -145,7 +145,7 @@ primeHints(); const DNSName target("www.example.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (domain == g_rootdnsname && type == QType::NS) { setLWResult(res, 0, true, false, true); @@ -210,7 +210,7 @@ size_t queriesCount = 0; - auto asynccb = [&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + auto asynccb = [&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -265,7 +265,7 @@ size_t queriesWithEDNS = 0; size_t queriesWithoutEDNS = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (EDNS0Level != 0) { queriesWithEDNS++; noEDNSServer = address; @@ -323,7 +323,7 @@ size_t queriesWithoutEDNS = 0; std::set usedServers; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int type, bool /* doTCP */, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int type, bool /* doTCP */, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (EDNS0Level > 0) { queriesWithEDNS++; } @@ -373,7 +373,7 @@ size_t queriesWithoutEDNS = 0; std::set usedServers; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int type, bool /* doTCP */, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int type, bool /* doTCP */, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (EDNS0Level > 0) { queriesWithEDNS++; } @@ -412,7 +412,7 @@ for (const auto qtype : invalidTypes) { size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -432,7 +432,7 @@ std::unique_ptr sr; initSR(sr); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (!doTCP) { setLWResult(res, 0, false, true, false); return LWResult::Result::Success; @@ -461,7 +461,7 @@ size_t tcpQueriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (!doTCP) { setLWResult(res, 0, true, true, false); return LWResult::Result::Success; @@ -496,7 +496,7 @@ primeHints(); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -542,7 +542,7 @@ primeHints(); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -590,7 +590,7 @@ std::set downServers; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -634,7 +634,7 @@ std::set downServers; size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -678,7 +678,7 @@ std::set downServers; size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -730,7 +730,7 @@ ad.d_servers = forwardedNSs; (*SyncRes::t_sstorage.domainmap)[target] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -781,7 +781,7 @@ ad.d_servers = forwardedNSs; (*SyncRes::t_sstorage.domainmap)[DNSName("refused.")] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -834,7 +834,7 @@ ad.d_servers = forwardedNSs; (*SyncRes::t_sstorage.domainmap)[DNSName("refused.")] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -876,7 +876,7 @@ DNSName target("www.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); if (domain == target) { @@ -930,7 +930,7 @@ primeHints(); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -986,7 +986,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (domain != target) { return LWResult::Result::Timeout; @@ -1034,7 +1034,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -1102,7 +1102,7 @@ const DNSName target("powerdns.com."); size_t count = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -1151,7 +1151,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -1234,10 +1234,10 @@ SyncRes::addEDNSDomain(target); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1247,7 +1247,7 @@ addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); /* this one did not use the ECS info */ - srcmask = boost::none; + srcmask = std::nullopt; return LWResult::Result::Success; } @@ -1294,10 +1294,10 @@ SyncRes::addEDNSRemoteSubnet("192.0.2.1/32"); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("2001:DB8::FF/128"); + incomingECS.setSource(Netmask("2001:DB8::FF/128")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { BOOST_REQUIRE(!srcmask); @@ -1349,7 +1349,7 @@ // No incoming ECS data sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { BOOST_REQUIRE(!srcmask); @@ -1393,7 +1393,7 @@ // No incoming ECS data, Requestor IP not in ecs-add-for sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { BOOST_REQUIRE(!srcmask); @@ -1435,10 +1435,10 @@ SyncRes::clearEDNSLocalSubnets(); SyncRes::addEDNSLocalSubnet("192.0.2.254/32"); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.0.0/16"); + incomingECS.setSource(Netmask("192.0.0.0/16")); sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional(incomingECS)); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { BOOST_REQUIRE(!srcmask); @@ -1480,10 +1480,10 @@ SyncRes::clearEDNSLocalSubnets(); SyncRes::addEDNSLocalSubnet("192.0.2.254/32"); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("0.0.0.0/0"); + incomingECS.setSource(Netmask("0.0.0.0/0")); sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional(incomingECS)); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { BOOST_REQUIRE(!srcmask); @@ -1523,7 +1523,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1568,7 +1568,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1616,7 +1616,7 @@ const DNSName cnameTarget1("cname-target1.powerdns.com"); const DNSName cnameTarget("cname-target.powerdns.com"); - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1676,7 +1676,7 @@ const DNSName cnameTargeta("cname-targeta.powerdns.com"); const DNSName cnameTargetb("cname-targetb.powerdns.com"); - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1763,7 +1763,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1821,7 +1821,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -1872,7 +1872,7 @@ size_t count = 0; const DNSName target("cname.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { count++; if (isRootServer(address)) { @@ -1930,7 +1930,7 @@ ad.d_servers = forwardedNSs; (*SyncRes::t_sstorage.domainmap)[target] = ad; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { count++; if (isRootServer(address)) { @@ -1973,7 +1973,7 @@ const DNSName target3("cname3.powerdns.com."); const DNSName target4("cname4.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { count++; if (isRootServer(address)) { @@ -2028,6 +2028,117 @@ } } +BOOST_AUTO_TEST_CASE(test_cname_long_step0_shortcut) +{ + // This tets the case fixed /optimizaed in #14973 + std::unique_ptr resolver; + initSR(resolver); + resolver->setQNameMinimization(); + primeHints(); + resolver->setLogMode(SyncRes::Store); + + size_t count = 0; + const DNSName target1("cname1.powerdns.com."); + const DNSName target2("cname2.powerdns.com."); + const DNSName target3("cname3.powerdns.com."); + const DNSName target4("cname4.powerdns.com."); + + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int qtype, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + count++; + + if (domain == DNSName("com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + if (domain == DNSName("powerdns.com.")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "ns.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + if (address == ComboAddress("192.0.2.2:53")) { + + if (domain == target1) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, target2.toString()); + return LWResult::Result::Success; + } + if (domain == target2) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, target3.toString()); + return LWResult::Result::Success; + } + if (domain == target3) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, target4.toString()); + return LWResult::Result::Success; + } + if (domain == target4) { + setLWResult(res, 0, true, false, false); + if (qtype == QType::A) { + addRecordToLW(res, domain, QType::A, "1.2.3.4"); + } + else if (qtype == QType::AAAA) { + addRecordToLW(res, domain, QType::AAAA, "::1234"); + } + return LWResult::Result::Success; + } + + return LWResult::Result::Success; + } + + return LWResult::Result::Timeout; + }); + + // We analyze the trace to see how many cases of a failed Step0 occurs. This is a bit dirty, but + // we have no other way of telling how the resolving took place, as the number of cache lookups is + // not recorded by the record cache. Also, we like to know if something in Syncres changed that + // influences the number of failing Step0 lookups. + auto counter = [](const string& str) { + const std::string key = "Step0 Not cached"; + size_t occurrences = 0; + auto pos = str.find(key); + while (pos != std::string::npos) { + occurrences++; + pos = str.find(key, pos + 1); + } + return occurrences; + }; + vector ret; + int res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(count, 6U); + BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U); + auto trace = resolver->getTrace(); + trace = resolver->getTrace(); + BOOST_CHECK_EQUAL(counter(trace), 4U); + + // And again to check cache, all Step0 cases should succeed + ret.clear(); + res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(count, 6U); + BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U); + trace = resolver->getTrace(); + BOOST_CHECK_EQUAL(counter(trace), 4U); + + // And again to check a name that does not fully resolve, we expect Step0 failures to increase + g_recCache->doWipeCache(target4, false, QType::AAAA); + ret.clear(); + res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(count, 7U); + BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U); + trace = resolver->getTrace(); + // XXX This number feels pretty high (15 extra, same as before #14973, there seems to be room for more improvement). + BOOST_CHECK_EQUAL(counter(trace), 19U); +} + BOOST_AUTO_TEST_CASE(test_cname_length) { std::unique_ptr sr; @@ -2038,7 +2149,7 @@ size_t length = 0; const DNSName target("cname.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -2095,7 +2206,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(ipAddress)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -2138,7 +2249,7 @@ const DNSName target("cname.powerdns.com."); const DNSName cnameTarget("cname-target.powerdns.com"); - resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(ipAddress)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -2186,7 +2297,7 @@ timeval now{}; Utility::gettimeofday(&now, nullptr); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int qtype, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int qtype, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -2244,7 +2355,7 @@ size_t queries = 0; const DNSName target("cname.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -2300,7 +2411,7 @@ size_t queries = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -2437,14 +2548,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(dnameOwner, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(dnameTarget, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queries = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; /* We don't use the genericDSAndDNSKEYHandler here, as it would deny names existing at the wrong level of the tree, due to the way computeZoneCuts works * As such, we need to do some more work to make the answers correct. @@ -2589,13 +2700,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(dnameTarget, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queries = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (type == QType::DS || type == QType::DNSKEY) { @@ -2696,13 +2807,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(dnameOwner, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queries = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -2831,7 +2942,7 @@ size_t queries = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -2922,7 +3033,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (domain != target) { return LWResult::Result::Timeout; diff -Nru pdns-recursor-5.2.13/test-syncres_cc10.cc pdns-recursor-5.4.9/test-syncres_cc10.cc --- pdns-recursor-5.2.13/test-syncres_cc10.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc10.cc 2026-10-26 08:26:51.000000000 +0000 @@ -20,7 +20,7 @@ int queries = 0; const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -73,7 +73,7 @@ int queries = 0; const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -112,7 +112,7 @@ int queries = 0; const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -154,16 +154,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -284,15 +284,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -397,15 +397,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -541,15 +541,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -669,15 +669,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -797,15 +797,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -912,22 +912,22 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); /* Generate key material for "powerdns.com." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey key; key.setKey(std::move(dcke), 257); - DSRecordContent drc = makeDSFromDNSKey(DNSName("powerdns.com."), key.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(DNSName("powerdns.com."), key.getDNSKEY(), DNSSEC::DIGEST_SHA256); testkeysset_t wrongKeys; - auto wrongDcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto wrongDcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); wrongDcke->create(wrongDcke->getBits()); DNSSECPrivateKey wrongKey; wrongKey.setKey(std::move(wrongDcke), 256); - DSRecordContent uselessdrc = makeDSFromDNSKey(DNSName("powerdns.com."), wrongKey.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent uselessdrc = makeDSFromDNSKey(DNSName("powerdns.com."), wrongKey.getDNSKEY(), DNSSEC::DIGEST_SHA256); wrongKeys[DNSName("powerdns.com.")] = std::pair(wrongKey, uselessdrc); keys[DNSName("powerdns.com.")] = std::pair(key, drc); @@ -936,7 +936,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1018,22 +1018,22 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); /* Generate key material for "powerdns.com." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey key; key.setKey(std::move(dcke), 257); - DSRecordContent drc = makeDSFromDNSKey(DNSName("powerdns.com."), key.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(DNSName("powerdns.com."), key.getDNSKEY(), DNSSEC::DIGEST_SHA256); keys[DNSName("powerdns.com.")] = std::pair(key, drc); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DNSKEY) { @@ -1041,7 +1041,7 @@ } if (type == QType::DS) { if (domain == DNSName("www.powerdns.com.")) { - auto ret = genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, boost::none, false, false); + auto ret = genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, std::nullopt, false, false); for (auto& rec : res->d_records) { // We know the NSEC RRSIG for the DS is the only one if (rec.d_name == DNSName("www.powerdns.com") && rec.d_type == QType::RRSIG) { @@ -1165,7 +1165,7 @@ const int theTTL = 5; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(address) != downServers.end()) { downCount++; @@ -1301,7 +1301,7 @@ const int theTTL = 5; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(address) != downServers.end()) { downCount++; @@ -1436,7 +1436,7 @@ const int theTTL = 5; const int negTTL = 60; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(address) != downServers.end()) { downCount++; @@ -1533,7 +1533,7 @@ BOOST_CHECK(task.d_qname == target); BOOST_CHECK_EQUAL(task.d_qtype, QType::A); - // Now simulate a succeeding task execution an record has become available + // Now simulate a succeeding task execution and the record has become available negLookup = false; sr->setNow(timeval{now + 3 * (negTTL + 1), 0}); downServers.clear(); @@ -1579,7 +1579,7 @@ const int theTTL = 5; const int negTTL = 60; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(address) != downServers.end()) { downCount++; @@ -1732,7 +1732,7 @@ const time_t theTTL = 5; const time_t negTTL = 60; - sr->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(ipAddress) != downServers.end()) { downCount++; @@ -1880,7 +1880,7 @@ const int theTTL = 5; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (downServers.find(address) != downServers.end()) { @@ -1954,7 +1954,7 @@ const DNSName target1("powerdns.com."); const DNSName target2("pdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (domain != target1 && domain != target2) { return LWResult::Result::Timeout; @@ -2005,7 +2005,7 @@ } }); - // Lookup first name. We should see the address of an nameserver in the cache + // Lookup first name. We should see the address of a nameserver in the cache vector ret; int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); @@ -2027,7 +2027,7 @@ BOOST_CHECK_EQUAL(ret[0].d_name, target2); auto secondTTL = g_recCache->get(sr->getNow().tv_sec, DNSName("pdns-public-ns1.powerdns.com"), QType::A, MemRecursorCache::None, nullptr, ComboAddress()); - // TTL shoud be back to original value + // TTL should be back to original value BOOST_CHECK_EQUAL(firstTTL, secondTTL); } @@ -2045,7 +2045,7 @@ const DNSName target1("powerdns.com."); const DNSName target2("pdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (domain != target1 && domain != target2) { return LWResult::Result::Timeout; @@ -2096,7 +2096,7 @@ } }); - // Lookup first name. We should see the address of an nameserver in the cache + // Lookup first name. We should see the address of a nameserver in the cache vector ret; int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); @@ -2109,7 +2109,7 @@ // Move the time sr->setNow({sr->getNow().tv_sec + 2, sr->getNow().tv_usec}); - // Lookup second name. We should see the address of an nameserver in the cache *not* being updated + // Lookup second name. We should see the address of a nameserver in the cache *not* being updated ret.clear(); res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); @@ -2135,7 +2135,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { /* this will cause issue with qname minimization if we ever implement it */ if (domain != target) { return LWResult::Result::Timeout; @@ -2231,4 +2231,85 @@ BOOST_CHECK(!SyncRes::answerIsNOData(QType::A, RCode::NoError, vec)); } +BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_oob) +{ + std::unique_ptr sr; + initSR(sr, true, false); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + const ComboAddress targetAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + SyncRes::AuthDomain ad; + DNSRecord dr; + const DNSName authZone("10.in-addr.arpa."); + + dr.d_place = DNSResourceRecord::ANSWER; + dr.d_name = DNSName("a.10.in-addr.arpa."); + dr.d_type = QType::A; + dr.d_ttl = 1800; + dr.setContent(std::make_shared("192.0.2.1")); + ad.d_records.insert(dr); + + (*SyncRes::t_sstorage.domainmap)[authZone] = ad; + + size_t queriesCount = 0; + + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + queriesCount++; + + DNSName auth = domain; + + if (type == QType::DS || type == QType::DNSKEY) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == LWResult::Result::Timeout) { + return LWResult::Result::Timeout; + } + return LWResult::Result::Success; + } + + if (isRootServer(address)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.10.in-addr.arpa.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.10.in-addr.arpa.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + + if (address == ComboAddress("192.0.2.1:53")) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300, true); + return LWResult::Result::Success; + } + + return LWResult::Result::Timeout; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG); + BOOST_REQUIRE_EQUAL(ret.size(), 2U); + BOOST_CHECK_EQUAL(queriesCount, 5U); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG); + BOOST_REQUIRE_EQUAL(ret.size(), 2U); + BOOST_CHECK_EQUAL(queriesCount, 5U); +} + BOOST_AUTO_TEST_SUITE_END() diff -Nru pdns-recursor-5.2.13/test-syncres_cc2.cc pdns-recursor-5.4.9/test-syncres_cc2.cc --- pdns-recursor-5.2.13/test-syncres_cc2.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc2.cc 2026-10-26 08:26:51.000000000 +0000 @@ -20,7 +20,7 @@ size_t queries = 0; const DNSName target("www.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -118,7 +118,7 @@ const DNSName target2("powerdns.org."); size_t queriesToNS = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesToNS++; if (isRootServer(address)) { @@ -184,7 +184,7 @@ const DNSName target2("powerdns.org."); size_t queriesToNS = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesToNS++; if (isRootServer(address)) { @@ -249,7 +249,7 @@ size_t queryCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -343,7 +343,7 @@ size_t queries = 0; const DNSName target("cname.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queries++; if (isRootServer(address)) { @@ -387,7 +387,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesToNS = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -473,7 +473,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesToNS = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -517,7 +517,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -582,7 +582,7 @@ /* This time the root denies target1 with a "com." SOA instead of a "." one. We should add target1 to the negcache, but not "com.". */ - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -644,7 +644,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -707,7 +707,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -809,14 +809,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(parent1, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(parent2, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(parent1, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(parent2, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -974,7 +974,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -1048,7 +1048,7 @@ const ComboAddress ns("192.0.2.1:53"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -1121,10 +1121,10 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1133,7 +1133,7 @@ addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - srcmask = boost::none; + srcmask = std::nullopt; return LWResult::Result::Success; } @@ -1176,11 +1176,11 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::s_ecsipv4cachelimit = 24; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1215,11 +1215,11 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::s_ecsipv4cachelimit = 16; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1254,11 +1254,11 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::s_ecscachelimitttl = 30; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1293,12 +1293,12 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::s_ecscachelimitttl = 100; SyncRes::s_ecsipv4cachelimit = 24; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1333,12 +1333,12 @@ SyncRes::addEDNSDomain(DNSName("powerdns.com.")); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::s_ecscachelimitttl = 100; SyncRes::s_ecsipv4cachelimit = 16; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1366,13 +1366,15 @@ std::unique_ptr sr; initSR(sr); + BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0U); + primeHints(); const DNSName target("powerdns.com."); std::map nsCounts; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); @@ -1430,6 +1432,49 @@ BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1U); BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1U); BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1U); + + // read PB representation back and forth, compare using the text dump + std::string temp1{"/tmp/speedDump1XXXXXX"}; + std::string temp2{"/tmp/speedDump2XXXXXX"}; + auto fd1 = FDWrapper(mkstemp(temp1.data())); + auto fd2 = FDWrapper(mkstemp(temp2.data())); + auto count = SyncRes::doDumpNSSpeeds(fd1); + fd1.reset(); + std::string pbDump; + auto records = SyncRes::getNSSpeedTable(0, pbDump); + BOOST_CHECK_EQUAL(records, count); + + SyncRes::clearNSSpeeds(); + BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0U); + + // Put PB dump back + count = SyncRes::putIntoNSSpeedTable(pbDump); + BOOST_CHECK_EQUAL(records, count); + count = SyncRes::doDumpNSSpeeds(fd2); + fd2.reset(); + BOOST_CHECK_EQUAL(records, count); + + // NS speed table is a hashed unique table, which not necessarily stable wrt recreation + // So we read the lines, sort them and compare + std::ifstream file1(temp1); + std::ifstream file2(temp2); + std::vector lines1; + std::vector lines2; + while (file1.good()) { + std::string line; + std::getline(file1, line); + lines1.emplace_back(line); + } + while (file2.good()) { + std::string line; + std::getline(file2, line); + lines2.emplace_back(line); + } + unlink(temp1.data()); + unlink(temp2.data()); + std::sort(lines1.begin(), lines1.end()); + std::sort(lines2.begin(), lines2.end()); + BOOST_CHECK(lines1 == lines2); } BOOST_AUTO_TEST_CASE(test_flawed_nsset) @@ -1441,7 +1486,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); @@ -1465,7 +1510,7 @@ std::vector> sigs; addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600); - g_recCache->replace(now, target, QType(QType::NS), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); + g_recCache->replace(now, target, QType(QType::NS), records, sigs, {}, true, g_rootdnsname, std::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); @@ -1483,7 +1528,7 @@ const DNSName target("powerdns.com."); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address) && domain == target) { @@ -1519,7 +1564,7 @@ const DNSName target("powerdns.com."); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address) && domain == target) { @@ -1561,7 +1606,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { return LWResult::Result::Timeout; }); @@ -1571,7 +1616,7 @@ std::vector> sigs; addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600); - g_recCache->replace(now, target, QType(QType::A), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); + g_recCache->replace(now, target, QType(QType::A), records, sigs, {}, true, g_rootdnsname, std::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); @@ -1591,7 +1636,7 @@ sr->setCacheOnly(); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -1613,7 +1658,7 @@ const DNSName target("cachettl.powerdns.com."); const ComboAddress ns("192.0.2.1:53"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); @@ -1667,11 +1712,11 @@ const ComboAddress ns("192.0.2.1:53"); EDNSSubnetOpts incomingECS; - incomingECS.source = Netmask("192.0.2.128/32"); + incomingECS.setSource(Netmask("192.0.2.128/32")); sr->setQuerySource(ComboAddress(), boost::optional(incomingECS)); SyncRes::addEDNSDomain(target); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { BOOST_REQUIRE(srcmask); BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24"); @@ -1680,7 +1725,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 20); - srcmask = boost::none; + srcmask = std::nullopt; return LWResult::Result::Success; } @@ -1735,7 +1780,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); @@ -1760,7 +1805,7 @@ std::vector> sigs; addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60); - g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); + g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, {}, true, g_rootdnsname, std::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); @@ -1780,7 +1825,7 @@ const DNSName target("powerdns.com."); - auto callback = [&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + auto callback = [&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); @@ -1806,12 +1851,12 @@ std::vector> sigs; addRecordToList(records, target, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, now + 29); - g_recCache->replace(now - 30, target, QType(QType::A), records, sigs, {}, true, g_rootdnsname, boost::optional(), boost::none, vState::Indeterminate, boost::none, false, now - 31); + g_recCache->replace(now - 30, target, QType(QType::A), records, sigs, {}, true, g_rootdnsname, std::optional(), MemRecursorCache::NOTAG, vState::Indeterminate, std::nullopt, false, now - 31); /* Same for the NS record */ std::vector ns; addRecordToList(ns, target, QType::NS, "pdns-public-ns1.powerdns.com", DNSResourceRecord::ANSWER, now + 29); - g_recCache->replace(now - 30, target, QType::NS, ns, sigs, {}, false, target, boost::optional(), boost::none, vState::Indeterminate, boost::none, false, now - 31); + g_recCache->replace(now - 30, target, QType::NS, ns, sigs, {}, false, target, std::optional(), MemRecursorCache::NOTAG, vState::Indeterminate, std::nullopt, false, now - 31); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); diff -Nru pdns-recursor-5.2.13/test-syncres_cc3.cc pdns-recursor-5.4.9/test-syncres_cc3.cc --- pdns-recursor-5.2.13/test-syncres_cc3.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc3.cc 2026-10-26 08:26:51.000000000 +0000 @@ -19,7 +19,7 @@ check that we only return one result, and we only cache one too. */ const DNSName target("cache-auth.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10); addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 10); @@ -54,7 +54,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -112,7 +112,7 @@ sr->setAsyncCallback( [&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, - struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, + struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); return LWResult::Result::Success; @@ -146,7 +146,7 @@ const DNSName target2("www2.powerdns.com."); // in bailiwick, but not asked for const DNSName target3("www.random.net."); // out of bailiwick and not asked for - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -203,11 +203,11 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com"), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com"), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (type == QType::DS || type == QType::DNSKEY) { return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); } @@ -264,7 +264,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.42"); addRecordToLW(res, domain, QType::ANY, "\\# 0"); @@ -287,7 +287,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); /* the NSEC and RRSIG contents are complete garbage, please ignore them */ @@ -312,7 +312,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); /* the NSEC and RRSIG contents are complete garbage, please ignore them */ @@ -337,7 +337,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, RCode::NXDomain, true, false, true); addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); /* the NSEC and RRSIG contents are complete garbage, please ignore them */ @@ -362,7 +362,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, RCode::NXDomain, true, false, true); addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); /* the NSEC and RRSIG contents are complete garbage, please ignore them */ @@ -388,7 +388,7 @@ /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -410,7 +410,7 @@ const DNSName target("powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.1"); return LWResult::Result::Success; @@ -426,8 +426,8 @@ /* check that the record in the answer section has not been cached */ const ComboAddress who; vector cached; - vector> signatures; - BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::None, &cached, who, boost::none, &signatures), 0); + MemRecursorCache::SigRecs signatures; + BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::None, &cached, who, MemRecursorCache::NOTAG, &signatures), 0); } BOOST_AUTO_TEST_CASE(test_special_types) @@ -440,7 +440,7 @@ /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { cerr << "asyncresolve called to ask " << address.toStringWithPort() << " about " << domain.toString() << " / " << QType(type).toString() << " over " << (doTCP ? "TCP" : "UDP") << " (rd: " << sendRDQuery << ", EDNS0 level: " << EDNS0Level << ")" << endl; queriesCount++; return LWResult::Result::Timeout; @@ -480,7 +480,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -603,7 +603,7 @@ const DNSName target("rpz.powerdns.com."); const ComboAddress ns("192.0.2.1:53"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, false, true, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -644,7 +644,7 @@ const DNSName target("rpz.powerdns.com."); const ComboAddress ns("[2001:DB8::42]:53"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -686,7 +686,7 @@ const ComboAddress ns("192.0.2.1:53"); const DNSName nsName("ns1.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800); @@ -728,7 +728,7 @@ const ComboAddress ns("192.0.2.1:53"); const DNSName nsName("ns1.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address)) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800); @@ -765,6 +765,72 @@ BOOST_CHECK_EQUAL(ret.size(), 1U); } +BOOST_AUTO_TEST_CASE(test_nameserver_rpz_nodata_vs_dnssec) +{ + std::unique_ptr resolver; + initSR(resolver, true); + setDNSSECValidation(resolver, DNSSECMode::ValidateAll); + + primeHints(); + + const DNSName apex("powerdns.com."); + const DNSName target("cname.powerdns.com."); + + testkeysset_t keys; + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + // zone itself is not signed + g_luaconfs.setState(luaconfsCopy); + + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + + if (isRootServer(address)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + if (address == ComboAddress("192.0.2.1:53")) { + + if (domain == target) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::CNAME, apex.toString()); + return LWResult::Result::Success; + } + if (domain == apex) { + setLWResult(res, 0, true, false, false); + addRecordToLW(res, domain, QType::A, "192.0.2.2"); + return LWResult::Result::Success; + } + } + + return LWResult::Result::Timeout; + }); + + DNSFilterEngine::Policy pol; + pol.d_kind = DNSFilterEngine::PolicyKind::NODATA; + std::shared_ptr zone = std::make_shared(); + zone->setName("Unit test policy 0"); + zone->addQNameTrigger(apex, std::move(pol)); + zone->setExtendedErrorCode(99); + luaconfsCopy.dfe.clearZones(); + luaconfsCopy.dfe.addZone(zone); + g_luaconfs.setState(luaconfsCopy); + + vector ret; + auto res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(resolver->getValidationState(), vState::Insecure); + BOOST_REQUIRE_EQUAL(ret.size(), 0U); + BOOST_REQUIRE(resolver->d_appliedPolicy.d_zoneData->d_extendedErrorCode); + BOOST_CHECK_EQUAL(*resolver->d_appliedPolicy.d_zoneData->d_extendedErrorCode, 99U); +} + BOOST_AUTO_TEST_CASE(test_forward_zone_nord) { std::unique_ptr sr; @@ -783,7 +849,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { ++queriesCount; if (address == forwardedNS) { BOOST_CHECK_EQUAL(sendRDQuery, false); @@ -842,7 +908,7 @@ ad.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[target] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (address == forwardedNS) { @@ -893,7 +959,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { ++queriesCount; if (address == forwardedNS) { BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -951,7 +1017,7 @@ ad.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[target] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (address == forwardedNS) { BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -985,8 +1051,8 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); const ComboAddress forwardedNS("192.0.2.42:53"); @@ -997,7 +1063,7 @@ ad.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -1055,8 +1121,8 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("test."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("test."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); const ComboAddress forwardedNS("192.0.2.42:53"); @@ -1068,7 +1134,7 @@ ad.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[DNSName("test.")] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; BOOST_CHECK_EQUAL(sendRDQuery, false); @@ -1157,9 +1223,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(cnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(cnameTarget, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); const ComboAddress forwardedNS("192.0.2.42:53"); @@ -1170,7 +1236,7 @@ ad.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -1225,9 +1291,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); const ComboAddress forwardedNS("192.0.2.42:53"); @@ -1238,7 +1304,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -1289,7 +1355,7 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); const ComboAddress forwardedNS("192.0.2.42:53"); @@ -1300,7 +1366,7 @@ authDomain.d_servers.push_back(forwardedNS); (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = authDomain; - testSR->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + testSR->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool sendRDQuery, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; BOOST_CHECK_EQUAL(sendRDQuery, true); @@ -1319,7 +1385,7 @@ addRecordToLW(res, target, QType::CNAME, cnameTarget.toString()); addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1"); /* the RRSIG proves that the cnameTarget was expanded from a wildcard */ - addRRSIG(keys, res->d_records, g_rootdnsname, 300, false, boost::none, DNSName("*")); + addRRSIG(keys, res->d_records, g_rootdnsname, 300, false, std::nullopt, DNSName("*")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ addNSECRecordToLW(DNSName("cnamd."), DNSName("cnamf."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records); addRRSIG(keys, res->d_records, g_rootdnsname, 300); @@ -1341,6 +1407,7 @@ res = testSR->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(testSR->getValidationState(), vState::Insecure); + BOOST_CHECK(MemRecursorCache::s_emptyAuthRecs->empty()); BOOST_REQUIRE_EQUAL(ret.size(), 5U); BOOST_CHECK_EQUAL(queriesCount, 3U); } @@ -1369,7 +1436,7 @@ (*SyncRes::t_sstorage.domainmap)[authZone] = ad; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -1437,7 +1504,7 @@ (*SyncRes::t_sstorage.domainmap)[authZone] = ad; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; }); @@ -1502,7 +1569,7 @@ (*SyncRes::t_sstorage.domainmap)[authZone] = authDomain; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address) || domain == DNSName("com") || domain == DNSName("example.com")) { setLWResult(res, 0, false, false, true); @@ -1570,7 +1637,7 @@ (*SyncRes::t_sstorage.domainmap)[authZone] = authDomain; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (isRootServer(address) || domain == DNSName("com") || domain == DNSName("example.com")) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); @@ -1641,7 +1708,7 @@ (*map)[target] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.42"); @@ -1690,7 +1757,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target) { @@ -1746,7 +1813,7 @@ (*map)[target] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == externalCNAME) { @@ -1802,7 +1869,7 @@ (*map)[target] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type != QType::DS) { setLWResult(res, 0, true, false, true); diff -Nru pdns-recursor-5.2.13/test-syncres_cc4.cc pdns-recursor-5.4.9/test-syncres_cc4.cc --- pdns-recursor-5.2.13/test-syncres_cc4.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc4.cc 2026-10-26 08:26:51.000000000 +0000 @@ -40,7 +40,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; @@ -79,7 +79,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; @@ -138,7 +138,7 @@ testkeysset_t keys; auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); /* make sure that the signature inception and validity times are computed @@ -146,7 +146,7 @@ takes too long. */ const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == DNSName("com.") || domain == authZone, fixedNow); @@ -213,7 +213,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (address == ComboAddress(nsAddr.toString(), 53) && domain == target) { @@ -266,7 +266,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; @@ -321,7 +321,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; @@ -371,7 +371,7 @@ (*map)[authZone] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) { queriesCount++; return LWResult::Result::Timeout; @@ -417,7 +417,7 @@ (*map)[target] = ad; SyncRes::setDomainMap(map); - sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&queriesCount](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.42"); @@ -440,7 +440,7 @@ { initSR(); - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey dpk; dpk.setKey(std::move(dcke), 256); @@ -453,7 +453,7 @@ time_t now = time(nullptr); RRSIGRecordContent rrc; /* this RRSIG is valid for the current second only */ - computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now); + computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, std::nullopt, now); skeyset_t keyset; keyset.insert(std::make_shared(dpk.getDNSKEY())); @@ -466,6 +466,90 @@ BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 1U); } +BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_future) +{ + initSR(); + + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); + dcke->create(dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.setKey(std::move(dcke), 256); + + sortedRecords_t recordcontents; + recordcontents.insert(getRecordContent(QType::A, "192.0.2.1")); + + DNSName qname("powerdns.com."); + + time_t inception = 0xf0000000U; + auto validity = 0xffffffffU; + RRSIGRecordContent rrc; + computeRRSIG(dpk, qname, qname, QType::A, 600, validity, rrc, recordcontents, std::nullopt, inception, 0); + + skeyset_t keyset; + keyset.insert(std::make_shared(dpk.getDNSKEY())); + + std::vector> sigs; + sigs.push_back(std::make_shared(rrc)); + + pdns::validation::ValidationContext validationContext; + time_t now = 0xe0000000; + // Case 1: current time before inception + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::BogusSignatureNotYetValid); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 0U); + + // Case 2: we're in Jan 1970 + now = 1; // Both inception and expiry are in the past (1969) + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::BogusSignatureExpired); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 0U); + + // Case 3: we're in 2038 + now = 0xffff0001; // should be ok, we're inside validity + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::Secure); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 1U); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_extreme_timestamps) +{ + initSR(); + + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); + dcke->create(dcke->getBits()); + DNSSECPrivateKey dpk; + dpk.setKey(std::move(dcke), 256); + + sortedRecords_t recordcontents; + recordcontents.insert(getRecordContent(QType::A, "192.0.2.1")); + + DNSName qname("powerdns.com."); + + time_t inception = 0U; // Interpreted as jan 1st 1970, until it is more than 68 years in the past + auto validity = 0xffffffffU; // Will be interpreted as end of 1969, as is more than 68 years in the future (until it isn't) + RRSIGRecordContent rrc; + computeRRSIG(dpk, qname, qname, QType::A, 600, validity, rrc, recordcontents, std::nullopt, inception, 0); + + skeyset_t keyset; + keyset.insert(std::make_shared(dpk.getDNSKEY())); + + std::vector> sigs; + sigs.push_back(std::make_shared(rrc)); + + pdns::validation::ValidationContext validationContext; + time_t now = time(nullptr); + // Case 1: interpretion depends on current time, test below will start to fail around 1970 + 68 = 2038 as it will be interpeted as the 3rd case + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::BogusSignatureExpired); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 0U); + + // Case 2: we're in Jan 1970 + now = 1; // sig inception is OK, but expiry is in 1969: not valid + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::BogusSignatureExpired); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 0U); + + // Case 3: we're in 2038 + now = 0xffff0000; // inception (0) will be interpreted as being in the future + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset, std::nullopt, validationContext) == vState::BogusSignatureNotYetValid); + BOOST_CHECK_EQUAL(validationContext.d_validationsCounter, 0U); +} + BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) { std::unique_ptr sr; @@ -479,12 +563,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -546,17 +630,17 @@ testkeysset_t kskeys; /* Generate key material for "." */ - auto dckeZ = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dckeZ = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dckeZ->create(dckeZ->getBits()); DNSSECPrivateKey ksk; ksk.setKey(std::move(dckeZ), 257); - DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSEC::DIGEST_SHA256); - auto dckeK = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dckeK = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dckeK->create(dckeK->getBits()); DNSSECPrivateKey zsk; zsk.setKey(std::move(dckeK), 256); - DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSEC::DIGEST_SHA256); kskeys[target] = std::pair(ksk, kskds); zskeys[target] = std::pair(zsk, zskds); @@ -569,7 +653,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -632,12 +716,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -697,23 +781,23 @@ testkeysset_t keys; /* Generate key material for "." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey csk; csk.setKey(std::move(dcke), 0); - DSRecordContent ds = makeDSFromDNSKey(target, csk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent dsContent = makeDSFromDNSKey(target, csk.getDNSKEY(), DNSSEC::DIGEST_SHA256); - keys[target] = std::pair(csk, ds); + keys[target] = std::pair(csk, dsContent); /* Set the root DS */ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - luaconfsCopy.dsAnchors[g_rootdnsname].insert(ds); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(dsContent); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -773,23 +857,23 @@ testkeysset_t keys; /* Generate key material for "." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey csk; csk.setKey(std::move(dcke), 257 | 128); - DSRecordContent ds = makeDSFromDNSKey(target, csk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent dsContent = makeDSFromDNSKey(target, csk.getDNSKEY(), DNSSEC::DIGEST_SHA256); - keys[target] = std::pair(csk, ds); + keys[target] = std::pair(csk, dsContent); /* Set the root DS */ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - luaconfsCopy.dsAnchors[g_rootdnsname].insert(ds); + luaconfsCopy.dsAnchors[g_rootdnsname].insert(dsContent); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -850,17 +934,17 @@ testkeysset_t keys; /* Generate key material for "." */ - auto dckeDS = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dckeDS = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dckeDS->create(dckeDS->getBits()); DNSSECPrivateKey dskey; dskey.setKey(std::move(dckeDS), 257); - DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSEC::DIGEST_SHA256); - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey dpk; dpk.setKey(std::move(dcke), 256); - DSRecordContent seconddrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent seconddrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSEC::DIGEST_SHA256); dskeys[target] = std::pair(dskey, drc); keys[target] = std::pair(dpk, seconddrc); @@ -873,7 +957,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -974,13 +1058,13 @@ luaconfsCopy.dsAnchors.clear(); /* generate more DSs for the zone than we are willing to consider: only the last one will be used to generate DNSKEY records */ for (size_t idx = 0; idx < (g_maxDSsToConsider + 10U); idx++) { - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); } g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1054,7 +1138,7 @@ DNSSECPrivateKey dskey; dskey.setKey(std::move(dckeDS), 257); assert(dskey.getTag() == 31337); - DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSEC::DIGEST_SHA256); dskeys[target] = std::pair(dskey, drc); /* Different key, same tag */ @@ -1064,7 +1148,7 @@ DNSSECPrivateKey dpk; dpk.setKey(std::move(dcke), 256); assert(dpk.getTag() == dskey.getTag()); - DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSEC::DIGEST_SHA256); keys[target] = std::pair(dpk, uselessdrc); /* Set the root DS (one of them!) */ @@ -1075,7 +1159,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys, dskeys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys, dskeys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1154,7 +1238,7 @@ DNSSECPrivateKey dskey; dskey.setKey(std::move(dckeDS), 257); assert(dskey.getTag() == 31337); - DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSEC::DIGEST_SHA256); dskeys[target] = std::pair(dskey, drc); /* Different key, same tag */ @@ -1166,7 +1250,7 @@ // so that the validation of the DNSKEY rrset succeeds dpk.setKey(std::move(dcke), 258); assert(dpk.getTag() == dskey.getTag()); - DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSEC::DIGEST_SHA256); keys[target] = std::pair(dpk, uselessdrc); /* Set the root DSs (only one of them) */ @@ -1177,7 +1261,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys, dskeys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys, dskeys](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1248,20 +1332,20 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); - auto dckeRRSIG = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dckeRRSIG = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dckeRRSIG->create(dckeRRSIG->getBits()); DNSSECPrivateKey rrsigkey; rrsigkey.setKey(std::move(dckeRRSIG), 257); - DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSEC::DIGEST_SHA256); rrsigkeys[target] = std::pair(rrsigkey, rrsigds); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1323,12 +1407,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1398,12 +1482,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1473,13 +1557,13 @@ testkeysset_t keys; /* Generate key material for "." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey dpk; /* Fake algorithm number (private) */ dpk.setKey(std::move(dcke), 256, 253); - DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSEC::DIGEST_SHA256); keys[target] = std::pair(dpk, drc); /* Fake algorithm number (private) */ drc.d_algorithm = 253; @@ -1492,7 +1576,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1554,11 +1638,11 @@ testkeysset_t keys; /* Generate key material for "." */ - auto dcke = DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256); + auto dcke = DNSCryptoKeyEngine::make(DNSSEC::ECDSA256); dcke->create(dcke->getBits()); DNSSECPrivateKey dpk; dpk.setKey(std::move(dcke), 256); - DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::DIGEST_SHA256); + DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSEC::DIGEST_SHA256); /* Fake digest number (reserved) */ drc.d_digesttype = 0; @@ -1572,7 +1656,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1635,7 +1719,7 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); /* make sure that the signature inception and validity times are computed @@ -1645,7 +1729,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1657,7 +1741,7 @@ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); } - addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, true, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); @@ -1669,7 +1753,7 @@ setLWResult(res, 0, true, false, true); addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); return LWResult::Result::Success; } @@ -1707,7 +1791,7 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); /* make sure that the signature inception and validity times are computed @@ -1717,7 +1801,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys, fixedNow](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys, fixedNow](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1729,9 +1813,9 @@ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); } - addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow); - addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, 1, std::nullopt, std::nullopt, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, 2, std::nullopt, std::nullopt, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, 0, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); @@ -1743,7 +1827,7 @@ setLWResult(res, 0, true, false, true); addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); return LWResult::Result::Success; } @@ -1785,7 +1869,7 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); /* make sure that the signature inception and validity times are computed @@ -1795,7 +1879,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys, fixedNow](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys, fixedNow](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1807,8 +1891,8 @@ addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600); } - addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, true, std::nullopt, std::nullopt, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); @@ -1820,7 +1904,7 @@ setLWResult(res, 0, true, false, true); addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); return LWResult::Result::Success; } @@ -1849,13 +1933,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1868,7 +1952,7 @@ } /* FORCE WRONG ALGO */ - addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256); + addRRSIG(keys, res->d_records, domain, 300, false, DNSSEC::RSASHA256); addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600); addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600); @@ -1919,14 +2003,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -2000,14 +2084,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; diff -Nru pdns-recursor-5.2.13/test-syncres_cc5.cc pdns-recursor-5.4.9/test-syncres_cc5.cc --- pdns-recursor-5.2.13/test-syncres_cc5.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc5.cc 2026-10-26 08:26:51.000000000 +0000 @@ -23,9 +23,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::DIGEST_SHA384, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA384, DNSSEC::DIGEST_SHA384, keys); g_luaconfs.setState(luaconfsCopy); @@ -37,7 +37,7 @@ const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -53,7 +53,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } @@ -62,7 +62,7 @@ if (domain == DNSName("com.")) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, domain, 300); } @@ -70,7 +70,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("com."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } return LWResult::Result::Success; @@ -80,14 +80,14 @@ if (type == QType::NS) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, auth, 300); } else { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } return LWResult::Result::Success; } @@ -125,15 +125,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::DIGEST_SHA384, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::RSASHA512, DNSSEC::DIGEST_SHA384, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA384, DNSSEC::DIGEST_SHA384, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -149,7 +149,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } @@ -158,15 +158,15 @@ if (domain == DNSName("com.")) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); } else { setLWResult(res, 0, false, false, true); addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("com."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } return LWResult::Result::Success; @@ -176,14 +176,14 @@ if (type == QType::NS) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } else { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } return LWResult::Result::Success; } @@ -251,14 +251,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -355,13 +355,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -456,9 +456,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); /* Add a NTA for "powerdns.com" */ luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com"; @@ -467,7 +467,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -557,9 +557,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); /* Add a NTA for "powerdns.com" */ luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com"; @@ -568,7 +568,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -644,15 +644,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -735,15 +735,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -849,15 +849,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -915,7 +915,7 @@ } else { addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records); addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); @@ -947,6 +947,117 @@ BOOST_CHECK_EQUAL(queriesCount, 6U); } +BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_does_not_deny_next_closer) +{ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("a.b.powerdns.com."); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + queriesCount++; + + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return LWResult::Result::Success; + } + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + { + if (isRootServer(address)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + if (address == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, domain, 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("powerdns.com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + } + return LWResult::Result::Success; + } + if (address == ComboAddress("192.0.2.2:53")) { + setLWResult(res, 0, true, false, true); + if (type == QType::NS) { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + else { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + } + else { + addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); + /* we need to add the proof that this name does not exist, so the wildcard may apply */ + addNSECRecordToLW(DNSName("b.powerdns.com."), DNSName("c.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + } + return LWResult::Result::Success; + } + } + + return LWResult::Result::Timeout; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial); + BOOST_REQUIRE_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(queriesCount, 6U); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial); + BOOST_REQUIRE_EQUAL(ret.size(), 4U); + for (const auto& rec : ret) { + /* check that we applied the lowest TTL, here this is from the NSEC proving that the exact name did not exist */ + BOOST_CHECK_LE(rec.d_ttl, 60U); + } + BOOST_CHECK_EQUAL(queriesCount, 6U); +} + BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_proof_before_rrsig) { /* this tests makes sure that we correctly detect that we need to gather @@ -966,15 +1077,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1032,7 +1143,7 @@ } else { addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records); addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); @@ -1086,15 +1197,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1151,7 +1262,7 @@ } else if (domain == target) { addRecordToLW(res, domain, QType::CNAME, "alias.powerdns.com", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply, and we are NOT including it */ } @@ -1200,15 +1311,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1265,7 +1376,7 @@ } else if (domain == target) { addRecordToLW(res, domain, QType::CNAME, "alias.powerdns.com", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* proof that this name does not exist, so the wildcard may apply */ addNSECRecordToLW(DNSName("wwv.powerdns.com."), DNSName("wwx.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); /* INVALID RRSIG!! */ @@ -1310,14 +1421,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1353,7 +1464,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSECRecordToLW(DNSName("*.com."), DNSName("com."), {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1390,14 +1501,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1416,7 +1527,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -1444,7 +1555,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1481,14 +1592,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1507,7 +1618,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -1535,7 +1646,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1571,14 +1682,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([target, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, boost::optional /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1597,7 +1708,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -1625,7 +1736,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1652,14 +1763,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1678,7 +1789,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -1692,6 +1803,7 @@ addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } + // The code below introduces duplicate NSEC3 records if (address == ComboAddress("192.0.2.1:53")) { setLWResult(res, 0, true, false, true); /* no data */ @@ -1708,7 +1820,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1720,7 +1832,7 @@ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); - /* because we pass along the duplicated NSEC3 */ + /* the duplicated NSEC3 have not been dedupped */ BOOST_REQUIRE_EQUAL(ret.size(), 9U); BOOST_CHECK_EQUAL(queriesCount, 4U); @@ -1729,7 +1841,7 @@ res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); - /* because we pass along the duplicated NSEC3 */ + /* the duplicated NSEC3 have not been dedupped */ BOOST_REQUIRE_EQUAL(ret.size(), 9U); BOOST_CHECK_EQUAL(queriesCount, 4U); } @@ -1747,14 +1859,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1773,7 +1885,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records, g_maxNSEC3Iterations + 100); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -1801,7 +1913,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); /* a wildcard matches but has no record for this type */ addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records, g_maxNSEC3Iterations + 100); - addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("com"), 300, false, std::nullopt, DNSName("*.com")); return LWResult::Result::Success; } } @@ -1839,15 +1951,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1910,7 +2022,7 @@ } else { addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ /* first the closest encloser */ addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records); @@ -1960,15 +2072,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /*sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /*sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -2018,14 +2130,14 @@ else { if (domain == target) { addRecordToLW(res, domain, QType::CNAME, "alias.powerdns.com.", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply but we are NOT adding it! */ /* first the closest encloser */ } else if (domain == alias) { addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); } } return LWResult::Result::Success; @@ -2063,15 +2175,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -2129,7 +2241,7 @@ } else { addRecordToLW(res, domain, QType::A, "192.0.2.42"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ /* first the closest encloser */ addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records); @@ -2176,15 +2288,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -2242,7 +2354,7 @@ } else { addRecordToLW(res, domain, QType::A, "192.0.2.42"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); } return LWResult::Result::Success; } @@ -2280,13 +2392,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (type == QType::DS || type == QType::DNSKEY) { if (domain == target) { const auto auth = DNSName("powerdns.com."); @@ -2305,11 +2417,11 @@ { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.42"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); /* we don't _really_ need to add the proof that the exact name does not exist because it does, it's the wildcard itself, but let's do it so other validators don't choke on it */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } }); @@ -2335,13 +2447,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (type == QType::DS || type == QType::DNSKEY) { if (domain == target) { const auto auth = DNSName("powerdns.com."); @@ -2363,7 +2475,7 @@ addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); /* add the proof that the exact name does exist but that this type does not */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("\\000.*.powerdns.com."), {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } }); @@ -2389,13 +2501,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (type == QType::DS || type == QType::DNSKEY) { if (domain == target) { const auto auth = DNSName("powerdns.com."); @@ -2404,7 +2516,7 @@ addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); addRRSIG(keys, res->d_records, auth, 300); addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } if (domain == DNSName("sub.powerdns.com.")) { @@ -2415,7 +2527,7 @@ addRRSIG(keys, res->d_records, auth, 300); /* add a NSEC denying the DS */ addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); @@ -2423,9 +2535,9 @@ { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.42"); - addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, std::nullopt, DNSName("*.powerdns.com")); addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.powerdns.com")); return LWResult::Result::Success; } }); @@ -2451,15 +2563,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -2518,7 +2630,7 @@ else { addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600); /* this pretends that the wildcard lives out of the powerdns.com zone, even though it will be signed by the powerdns.com key */ - addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.com")); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, std::nullopt, DNSName("*.com")); /* we need to add the proof that this name does not exist, so the wildcard may apply */ addNSECRecordToLW(DNSName("wwa.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records); addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); @@ -2563,16 +2675,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("net."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("herokuapp.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("nsone.net."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("net."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("herokuapp.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("nsone.net."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth(domain); @@ -2697,9 +2809,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); @@ -2711,7 +2823,7 @@ const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -2732,7 +2844,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } @@ -2741,7 +2853,7 @@ if (domain == DNSName("com.")) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, domain, 300); } @@ -2750,7 +2862,7 @@ addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); /* do NOT include the DS here */ // addDS(auth, 300, res->d_records, keys); - // addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow); + // addRRSIG(keys, res->d_records, DNSName("com."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } return LWResult::Result::Success; @@ -2760,14 +2872,14 @@ if (type == QType::NS) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, auth, 300); } else { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } return LWResult::Result::Success; } @@ -2808,9 +2920,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); @@ -2822,7 +2934,7 @@ const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -2843,7 +2955,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } @@ -2852,7 +2964,7 @@ if (domain == DNSName("com.")) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, domain, 300); } @@ -2860,7 +2972,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("com."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } return LWResult::Result::Success; @@ -2870,14 +2982,14 @@ if (type == QType::NS) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, auth, 300); } else { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } return LWResult::Result::Success; } @@ -2930,9 +3042,9 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, pdnskeys); g_luaconfs.setState(luaconfsCopy); @@ -2944,7 +3056,7 @@ const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -2966,7 +3078,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return LWResult::Result::Success; } @@ -2975,7 +3087,7 @@ if (domain == DNSName("com.")) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(keys, res->d_records, domain, 300); } @@ -2983,7 +3095,7 @@ setLWResult(res, 0, false, false, true); addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, DNSName("com."), 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } return LWResult::Result::Success; @@ -2993,14 +3105,14 @@ if (type == QType::NS) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(pdnskeys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(pdnskeys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); addRRSIG(pdnskeys, res->d_records, auth, 300); } else { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(pdnskeys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow); + addRRSIG(pdnskeys, res->d_records, auth, 300, false, std::nullopt, std::nullopt, fixedNow); } return LWResult::Result::Success; } diff -Nru pdns-recursor-5.2.13/test-syncres_cc6.cc pdns-recursor-5.4.9/test-syncres_cc6.cc --- pdns-recursor-5.2.13/test-syncres_cc6.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc6.cc 2026-10-26 08:26:51.000000000 +0000 @@ -21,16 +21,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; size_t dsQueriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -140,16 +140,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("www.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -260,15 +260,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.insecure.powerdns."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.insecure.powerdns."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DNSKEY || (type == QType::DS && domain != target)) { @@ -338,13 +338,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -395,17 +395,17 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("www.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -505,15 +505,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("unpublished.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("unpublished.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -603,15 +603,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("unpublished.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("unpublished.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -627,7 +627,7 @@ addRRSIG(keys, res->d_records, auth, 300, false); return LWResult::Result::Success; } - return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, boost::none, true /* nsec3 */); + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, std::nullopt, true /* nsec3 */); } if (type == QType::DNSKEY) { if (domain == target) { @@ -640,7 +640,7 @@ addRRSIG(keys, res->d_records, domain, 300, false); return LWResult::Result::Success; } - return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, boost::none, true /* nsec3 */); + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, std::nullopt, true /* nsec3 */); } else { if (isRootServer(address)) { @@ -700,15 +700,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; size_t dsQueriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -810,15 +810,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -898,15 +898,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -987,14 +987,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1095,14 +1095,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1118,7 +1118,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); return LWResult::Result::Success; } - return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, boost::none, true, true); + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, std::nullopt, true, true); } if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.")) { @@ -1208,14 +1208,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1231,7 +1231,7 @@ addRRSIG(keys, res->d_records, DNSName("com."), 300); return LWResult::Result::Success; } - return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, boost::none, true, true); + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, std::nullopt, true, true); } if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.")) { @@ -1313,15 +1313,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1380,14 +1380,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1443,15 +1443,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1564,15 +1564,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1661,15 +1661,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1759,17 +1759,17 @@ luaconfsCopy.dsAnchors.clear(); // We have two set of keys as powerdns.com and sub.powerdns.com are Insecure but still have RRSIGS - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, pdnskeys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, pdnskeys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1865,16 +1865,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { diff -Nru pdns-recursor-5.2.13/test-syncres_cc7.cc pdns-recursor-5.4.9/test-syncres_cc7.cc --- pdns-recursor-5.2.13/test-syncres_cc7.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc7.cc 2026-10-26 08:26:51.000000000 +0000 @@ -22,16 +22,16 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); /* No key material for .com */ /* But TA for sub.powerdns.com. */ - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -149,14 +149,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -277,14 +277,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -403,14 +403,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -523,14 +523,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -645,15 +645,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -741,15 +741,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -837,15 +837,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -933,15 +933,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("power-dns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1050,15 +1050,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); /* No key material for .com */ - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); luaconfsCopy.dsAnchors[target].insert(keys[target].second); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DNSKEY) { @@ -1146,15 +1146,15 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); /* No key material for .com */ - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); luaconfsCopy.dsAnchors[target].insert(keys[target].second); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DNSKEY) { @@ -1241,14 +1241,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); /* Add a NTA for "." */ luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root"; g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1314,7 +1314,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain == target && type == QType::NS) { @@ -1365,14 +1365,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1427,13 +1427,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1500,13 +1500,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1573,14 +1573,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1638,13 +1638,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { @@ -1773,13 +1773,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS) { diff -Nru pdns-recursor-5.2.13/test-syncres_cc8.cc pdns-recursor-5.4.9/test-syncres_cc8.cc --- pdns-recursor-5.2.13/test-syncres_cc8.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc8.cc 2026-10-26 08:26:51.000000000 +0000 @@ -20,7 +20,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -69,7 +69,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -105,7 +105,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -141,7 +141,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -177,7 +177,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -222,7 +222,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -273,8 +273,8 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -305,7 +305,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -347,7 +347,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -362,7 +362,7 @@ * NSEC3 RR. */ /* - The RRSIG from "." denies the existence of any type at a except NS and SOA. + The RRSIG from "." denies the existence of any type at "a" except NS and SOA. NS has to be set since it is proving an insecure delegation, but SOA should NOT! */ addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS, QType::SOA}, 600, records); @@ -387,7 +387,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -416,7 +416,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -451,7 +451,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -480,7 +480,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -508,7 +508,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -548,17 +548,17 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; sortedRecords_t recordContents; vector> signatureContents; - /* proves that a.example.com does exist, and has been generated from a wildcard (see the RRSIG below) */ + /* proves that b.example.com does NOT exist, and the answer has been generated from a wildcard (see the RRSIG below) */ addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); recordContents.insert(records.at(0).getContent()); - addRRSIG(keys, records, DNSName("example.org."), 300, false, boost::none, DNSName("example.org.")); + addRRSIG(keys, records, DNSName("example.org."), 300, false); signatureContents.push_back(getRR(records.at(1))); records.clear(); @@ -570,16 +570,47 @@ /* This is an expanded wildcard proof, meaning that it does prove that the exact name does not exist so the wildcard can apply */ - dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType(0).getCode(), false, false, std::nullopt, false, /* normally retrieved from the RRSIG's d_labels */ 2); + dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType(0).getCode(), false, false, std::nullopt, false, /* normally retrieved from the RRSIG's d_labels */ 2); BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); } +BOOST_AUTO_TEST_CASE(test_nsec_expanded_wildcard_proof_missing_next_closer) +{ + initSR(true); + + testkeysset_t keys; + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + + vector records; + + sortedRecords_t recordContents; + vector> signatureContents; + + /* proves that a.b.example.com does not exist, and the answer has been generated from a wildcard (see the RRSIG below) */ + addNSECRecordToLW(DNSName("b.example.org."), DNSName("c.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); + recordContents.insert(records.at(0).getContent()); + addRRSIG(keys, records, DNSName("example.org."), 300, false); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::pair(DNSName("b.example.org."), QType::NSEC)] = pair; + + /* This is an expanded wildcard proof, meaning that it does prove that the exact name + does not exist so the wildcard might apply EXCEPT the next closer does exist! */ + dState denialState = getDenial(denialMap, DNSName("a.b.example.org."), QType(0).getCode(), false, false, std::nullopt, false, /* normally retrieved from the RRSIG's d_labels */ 2); + BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE); +} + BOOST_AUTO_TEST_CASE(test_nsec_wildcard_with_cname) { initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -645,7 +676,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -723,7 +754,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -782,8 +813,8 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -819,8 +850,8 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("sub.example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("sub.example.org."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -875,7 +906,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -955,7 +986,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -985,7 +1016,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -1047,7 +1078,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -1089,7 +1120,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -1104,7 +1135,7 @@ * NSEC3 RR. */ /* - The RRSIG from "." denies the existence of any type at a except NS and SOA. + The RRSIG from "." denies the existence of any type at "a" except NS and SOA. NS has to be set since it is proving an insecure delegation, but SOA should NOT! */ addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS, QType::SOA}, 600, records); @@ -1129,7 +1160,7 @@ initSR(); testkeysset_t keys; - generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); vector records; @@ -1141,7 +1172,7 @@ * A recently discovered corner case (see RFC Errata ID 3441 [Err3441]) * shows that not only those delegations remain insecure but also the * empty non-terminal space that is derived from those delegations. - */ + */ /* We have a NSEC3 proving that was.here does exist, and a second one proving that ent.was.here. does not, @@ -1191,14 +1222,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -1212,7 +1243,7 @@ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); addRRSIG(keys, res->d_records, domain, 300); addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 1, false, std::nullopt, std::nullopt, fixedNow); return LWResult::Result::Success; } @@ -1259,14 +1290,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -1331,14 +1362,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; const time_t tnow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -1350,7 +1381,7 @@ { setLWResult(res, RCode::NoError, true, false, true); addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, tnow); + addRRSIG(keys, res->d_records, domain, 1, false, std::nullopt, std::nullopt, tnow); return LWResult::Result::Success; } @@ -1367,10 +1398,10 @@ /* check that the entry has not been cached for longer than the RRSIG validity */ const ComboAddress who; vector cached; - vector> signatures; - BOOST_REQUIRE_EQUAL(g_recCache->get(tnow, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who, boost::none, &signatures), 1); + MemRecursorCache::SigRecs signatures; + BOOST_REQUIRE_EQUAL(g_recCache->get(tnow, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who, MemRecursorCache::NOTAG, &signatures), 1); BOOST_REQUIRE_EQUAL(cached.size(), 1U); - BOOST_REQUIRE_EQUAL(signatures.size(), 1U); + BOOST_REQUIRE_EQUAL(signatures->size(), 1U); BOOST_CHECK_EQUAL((cached[0].d_ttl - tnow), 1); /* again, to test the cache */ @@ -1401,12 +1432,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1472,7 +1503,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1533,12 +1564,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -1621,12 +1652,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { diff -Nru pdns-recursor-5.2.13/test-syncres_cc9.cc pdns-recursor-5.4.9/test-syncres_cc9.cc --- pdns-recursor-5.2.13/test-syncres_cc9.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-syncres_cc9.cc 2026-10-26 08:26:51.000000000 +0000 @@ -28,12 +28,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -108,7 +108,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -176,12 +176,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -271,12 +271,12 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -353,14 +353,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; const time_t fixedNow = sr->getNow().tv_sec; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -374,7 +374,7 @@ addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); addRRSIG(keys, res->d_records, domain, 300); addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 600, res->d_records); - addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow); + addRRSIG(keys, res->d_records, domain, 1, false, std::nullopt, std::nullopt, fixedNow); return LWResult::Result::Success; } @@ -439,13 +439,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (type == QType::DS || type == QType::DNSKEY) { @@ -501,7 +501,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -572,13 +572,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; DNSName auth = domain; @@ -678,7 +678,7 @@ const DNSName target("WWW.POWERDNS.COM"); const DNSName cname("WWW.PowerDNS.org"); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { sentOutQnames.push_back(domain); if (isRootServer(address)) { @@ -742,17 +742,17 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA1, keys2); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA1, keys2); // But add the existing root key otherwise no RRSIG can be created auto rootkey = keys.find(g_rootdnsname); keys2.insert(*rootkey); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { DNSName auth = domain; auth.chopOff(); if (type == QType::DS || type == QType::DNSKEY) { @@ -771,7 +771,7 @@ BOOST_CHECK_EQUAL(state, vState::Secure); BOOST_REQUIRE_EQUAL(dsSet.size(), 1U); for (const auto& dsRecord : dsSet) { - BOOST_CHECK_EQUAL(dsRecord.d_digesttype, DNSSECKeeper::DIGEST_SHA256); + BOOST_CHECK_EQUAL(dsRecord.d_digesttype, DNSSEC::DIGEST_SHA256); } } @@ -788,21 +788,21 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA1, keys2); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA1, keys2); // But add the existing root key otherwise no RRSIG can be created auto rootkey = keys.find(g_rootdnsname); keys2.insert(*rootkey); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA384, keys3); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA384, keys3); // But add the existing root key otherwise no RRSIG can be created keys3.insert(*rootkey); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { DNSName auth = domain; auth.chopOff(); if (type == QType::DS || type == QType::DNSKEY) { @@ -824,7 +824,7 @@ BOOST_CHECK_EQUAL(state, vState::Secure); BOOST_REQUIRE_EQUAL(dsSet.size(), 2U); for (const auto& dsRecord : dsSet) { - BOOST_CHECK(dsRecord.d_digesttype == DNSSECKeeper::DIGEST_SHA384 || dsRecord.d_digesttype == DNSSECKeeper::DIGEST_SHA256); + BOOST_CHECK(dsRecord.d_digesttype == DNSSEC::DIGEST_SHA384 || dsRecord.d_digesttype == DNSSEC::DIGEST_SHA256); } } @@ -841,21 +841,21 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys2); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys2); // But add the existing root key otherwise no RRSIG can be created auto rootkey = keys.find(g_rootdnsname); keys2.insert(*rootkey); - generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA1, keys3); + generateKeyMaterial(target, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA1, keys3); // But add the existing root key otherwise no RRSIG can be created keys3.insert(*rootkey); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { DNSName auth = domain; auth.chopOff(); if (type == QType::DS || type == QType::DNSKEY) { @@ -877,7 +877,7 @@ BOOST_CHECK_EQUAL(state, vState::Secure); BOOST_REQUIRE_EQUAL(dsSet.size(), 2U); for (const auto& dsRecord : dsSet) { - BOOST_CHECK_EQUAL(dsRecord.d_digesttype, DNSSECKeeper::DIGEST_SHA256); + BOOST_CHECK_EQUAL(dsRecord.d_digesttype, DNSSEC::DIGEST_SHA256); } } @@ -892,7 +892,7 @@ const DNSName cnameTarget("cname-target.powerdns.com"); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -940,7 +940,7 @@ vector cached; bool wasAuth = false; - auto ttl = g_recCache->get(now, DNSName("powerdns.com."), QType(QType::NS), MemRecursorCache::None, &cached, who, boost::none, nullptr, nullptr, nullptr, nullptr, &wasAuth); + auto ttl = g_recCache->get(now, DNSName("powerdns.com."), QType(QType::NS), MemRecursorCache::None, &cached, who, MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, nullptr, &wasAuth); BOOST_REQUIRE_GE(ttl, 1); BOOST_REQUIRE_LE(ttl, 42); BOOST_CHECK_EQUAL(cached.size(), 1U); @@ -948,8 +948,8 @@ cached.clear(); - /* Also check that the the part in additional is still not auth */ - BOOST_REQUIRE_GE(g_recCache->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), MemRecursorCache::None, &cached, who, boost::none, nullptr, nullptr, nullptr, nullptr, &wasAuth), -1); + /* Also check that the part in additional is still not auth */ + BOOST_REQUIRE_GE(g_recCache->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), MemRecursorCache::None, &cached, who, MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, nullptr, &wasAuth), -1); BOOST_CHECK_EQUAL(cached.size(), 1U); BOOST_CHECK_EQUAL(wasAuth, false); } @@ -966,12 +966,12 @@ testkeysset_t keys; auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("powerdns.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { if (type == QType::DS || type == QType::DNSKEY) { if (domain == DNSName("cname.powerdns.com.")) { return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false /* no cut */); @@ -1017,7 +1017,7 @@ vector cached; bool wasAuth = false; vState retrievedState = vState::Insecure; - BOOST_CHECK_GT(g_recCache->get(now, DNSName("powerdns.com."), QType(QType::SOA), MemRecursorCache::RequireAuth, &cached, who, boost::none, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), 0); + BOOST_CHECK_GT(g_recCache->get(now, DNSName("powerdns.com."), QType(QType::SOA), MemRecursorCache::RequireAuth, &cached, who, MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), 0); BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure)); BOOST_CHECK_EQUAL(wasAuth, true); @@ -1027,7 +1027,7 @@ BOOST_REQUIRE_EQUAL(ret.size(), 2U); cached.clear(); - BOOST_CHECK_GT(g_recCache->get(now, DNSName("powerdns.com."), QType(QType::SOA), MemRecursorCache::RequireAuth, &cached, who, boost::none, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), 0); + BOOST_CHECK_GT(g_recCache->get(now, DNSName("powerdns.com."), QType(QType::SOA), MemRecursorCache::RequireAuth, &cached, who, MemRecursorCache::NOTAG, nullptr, nullptr, nullptr, &retrievedState, &wasAuth), 0); BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure)); BOOST_CHECK_EQUAL(wasAuth, true); } @@ -1041,7 +1041,7 @@ const DNSName target("sanitization.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.1"); /* should be scrubbed because it doesn't match the QType */ @@ -1087,7 +1087,7 @@ const DNSName target("sanitization.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, 0, true, false, true); addRecordToLW(res, domain, QType::A, "192.0.2.1"); addRecordToLW(res, domain, QType::AAAA, "2001:db8::1", DNSResourceRecord::ADDITIONAL); @@ -1121,7 +1121,7 @@ size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (isRootServer(address)) { @@ -1189,7 +1189,7 @@ const DNSName target("sanitization-ns-nxd.powerdns.com."); - sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { setLWResult(res, RCode::NXDomain, true, false, true); addRecordToLW(res, "powerdns.com.", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY); addRecordToLW(res, "powerdns.com.", QType::NS, "spoofed.ns.", DNSResourceRecord::AUTHORITY, 172800); @@ -1233,13 +1233,13 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("signed.ds-ignorant.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("signed.ds-ignorant.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain.isPartOf(DNSName("signed.ds-ignorant.com.")) && address == ComboAddress("192.0.2.1:53")) { @@ -1321,14 +1321,14 @@ auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); - generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); - generateKeyMaterial(DNSName("ds-ignorant.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); - generateKeyMaterial(DNSName("signed.ds-ignorant.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + generateKeyMaterial(g_rootdnsname, DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("ds-ignorant.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); + generateKeyMaterial(DNSName("signed.ds-ignorant.com."), DNSSEC::ECDSA256, DNSSEC::DIGEST_SHA256, keys); g_luaconfs.setState(luaconfsCopy); size_t queriesCount = 0; - sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { + sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, std::optional& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) { queriesCount++; if (domain.isPartOf(DNSName("signed.ds-ignorant.com.")) && address == ComboAddress("192.0.2.1:53")) { diff -Nru pdns-recursor-5.2.13/test-tsig.cc pdns-recursor-5.4.9/test-tsig.cc --- pdns-recursor-5.2.13/test-tsig.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/test-tsig.cc 2026-10-26 09:46:36.000000000 +0000 @@ -141,6 +141,17 @@ checkTSIG(tsigName, tsigAlgo.makeLowerCase(), tsigSecret, packet); } +BOOST_AUTO_TEST_CASE(test_TSIG_different_case_name) { + DNSName tsigName("tsig.Name"); + DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); + DNSName qname("test.valid.tsig"); + string tsigSecret("verysecret"); + + vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); + + checkTSIG(tsigName.makeLowerCase(), tsigAlgo.makeLowerCase(), tsigSecret, packet); +} + BOOST_AUTO_TEST_CASE(test_TSIG_different_name_same_algo) { DNSName tsigName("tsig.name"); DNSName tsigAlgo("HMAC-MD5.SIG-ALG.REG.INT"); @@ -149,7 +160,7 @@ vector packet = generateTSIGQuery(qname, tsigName, tsigAlgo, tsigSecret); - checkTSIG(tsigName, DNSName("hmac-md5."), tsigSecret, packet); + checkTSIG(tsigName, g_hmacmd5dnsname, tsigSecret, packet); } BOOST_AUTO_TEST_CASE(test_TSIG_bad_key_name) { diff -Nru pdns-recursor-5.2.13/testrunner.cc pdns-recursor-5.4.9/testrunner.cc --- pdns-recursor-5.2.13/testrunner.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/testrunner.cc 2026-10-26 08:26:51.000000000 +0000 @@ -46,11 +46,11 @@ buf.str(""); buf << "msg=" << std::quoted(entry.message); if (entry.error) { - buf << " oserror=" << std::quoted(entry.error.get()); + buf << " oserror=" << std::quoted(entry.error.value()); } if (entry.name) { - buf << " subsystem=" << std::quoted(entry.name.get()); + buf << " subsystem=" << std::quoted(entry.name.value()); } buf << " level=" << entry.level; if (entry.d_priority != 0) { @@ -68,8 +68,6 @@ static bool init_unit_test() { - ::arg().set("rng") = "auto"; - ::arg().set("entropy-source") = "/dev/urandom"; // Force init while we are still unthreaded dns_random_uint16(); g_slog = Logging::Logger::create(loggerBackend); diff -Nru pdns-recursor-5.2.13/threadname.cc pdns-recursor-5.4.9/threadname.cc --- pdns-recursor-5.2.13/threadname.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/threadname.cc 2026-10-26 09:46:36.000000000 +0000 @@ -71,11 +71,11 @@ if (retval != 0) { #ifdef DNSDIST - warnlog("Could not set thread name %s for thread: %s", threadName, strerror(retval)); + SLOG(warnlog("Could not set thread name %s for thread: %s", threadName, strerror(retval)), + dnsdist::logging::getTopLogger("runtime")->error(Logr::Warning, retval, "Could not set thread name", "name", Logging::Loggable(threadName))); #else SLOG(g_log<withName("runtime")->error(Logr::Warning, retval, "Could not set thread name", "name", Logging::Loggable(threadName))); #endif } } - diff -Nru pdns-recursor-5.2.13/ueberbackend.hh pdns-recursor-5.4.9/ueberbackend.hh --- pdns-recursor-5.2.13/ueberbackend.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ueberbackend.hh 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +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 -#include -#include -#include -#include -#include - -#include - -#include "dnspacket.hh" -#include "dnsbackend.hh" -#include "lock.hh" -#include "namespaces.hh" - -/** This is a very magic backend that allows us to load modules dynamically, - and query them in order. This is persistent over all UeberBackend instantiations - across multiple threads. - - The UeberBackend is transparent for exceptions, which should fall straight through. -*/ - -class UeberBackend : public boost::noncopyable -{ -public: - UeberBackend(const string& pname = "default"); - ~UeberBackend(); - - bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector& nsset, string* nameserver, string* account, DNSBackend** dnsBackend); - - bool autoPrimaryAdd(const AutoPrimary& primary); - bool autoPrimaryRemove(const struct AutoPrimary& primary); - bool autoPrimariesList(std::vector& primaries); - - /** Tracks all created UeberBackend instances for us. We use this vector to notify - existing threads of new modules - */ - static LockGuarded> d_instances; - - static bool loadmodule(const string& name); - static bool loadModules(const vector& modules, const string& path); - - static void go(); - - /** This contains all registered backends. The DynListener modifies this list for us when - new modules are loaded */ - vector> backends; - - //! the very magic handle for UeberBackend questions - class handle - { - public: - bool get(DNSZoneRecord& record); - handle(); - ~handle(); - - //! The UeberBackend class where this handle belongs to - UeberBackend* parent{nullptr}; - //! The current real backend, which is answering questions - DNSBackend* d_hinterBackend{nullptr}; - - //! DNSPacket who asked this question - DNSPacket* pkt_p{nullptr}; - DNSName qname; - - //! Index of the current backend within the backends vector - unsigned int i{0}; - QType qtype; - int zoneId{-1}; - - private: - static AtomicCounter instances; - }; - - 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); - void getAllDomains(vector* domains, bool getSerial, bool include_disabled); - - void getUnfreshSecondaryInfos(vector* domains); - void getUpdatedPrimaries(vector& domains, std::unordered_set& catalogs, CatalogHashMap& catalogHashes); - bool getDomainInfo(const DNSName& domain, DomainInfo& domainInfo, bool getSerial = true); - bool createDomain(const DNSName& domain, DomainInfo::DomainKind kind, const vector& primaries, const string& account); - - bool doesDNSSEC(); - bool addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& keyID); - bool getDomainKeys(const DNSName& name, std::vector& keys); - bool getAllDomainMetadata(const DNSName& name, std::map>& meta); - bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector& meta); - bool getDomainMetadata(const DNSName& name, const std::string& kind, std::string& meta); - bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector& meta); - bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::string& meta); - - bool removeDomainKey(const DNSName& name, unsigned int keyID); - bool activateDomainKey(const DNSName& name, unsigned int keyID); - bool deactivateDomainKey(const DNSName& name, unsigned int keyID); - bool publishDomainKey(const DNSName& name, unsigned int keyID); - bool unpublishDomainKey(const DNSName& name, unsigned int keyID); - - void alsoNotifies(const DNSName& domain, set* ips); - void rediscover(string* status = nullptr); - void reload(); - - bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content); - bool getTSIGKey(const DNSName& name, DNSName& algorithm, string& content); - bool getTSIGKeys(std::vector& keys); - bool deleteTSIGKey(const DNSName& name); - - bool searchRecords(const string& pattern, vector::size_type maxResults, vector& result); - bool searchComments(const string& pattern, size_t maxResults, vector& result); - - void updateZoneCache(); - - bool inTransaction(); - -private: - handle d_handle; - vector d_answers; - vector::const_iterator d_cachehandleiter; - - static std::mutex d_mut; - static std::condition_variable d_cond; - - struct Question - { - DNSName qname; - int zoneId; - QType qtype; - } d_question; - - unsigned int d_cache_ttl, d_negcache_ttl; - uint16_t d_qtype{0}; - - bool d_negcached{false}; - bool d_cached{false}; - static AtomicCounter* s_backendQueries; - static bool d_go; - bool d_stale{false}; - static bool s_doANYLookupsOnly; - - enum CacheResult - { - Miss = -1, - NegativeMatch = 0, - Hit = 1, - }; - - CacheResult cacheHas(const Question& question, vector& resourceRecords) const; - void addNegCache(const Question& question) const; - void addCache(const Question& question, vector&& rrs) const; - - bool fillSOAFromZoneRecord(DNSName& shorter, int zoneId, SOAData* soaData); - CacheResult fillSOAFromCache(SOAData* soaData, DNSName& shorter); -}; diff -Nru pdns-recursor-5.2.13/unix_utility.cc pdns-recursor-5.4.9/unix_utility.cc --- pdns-recursor-5.2.13/unix_utility.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/unix_utility.cc 2026-10-26 09:46:36.000000000 +0000 @@ -239,9 +239,10 @@ time_t i; time_t years = t->tm_year - 70; + // We allow for some benign out-of-range values if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } - if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; } + if (t->tm_hour>24) { t->tm_mday += t->tm_hour/24; t->tm_hour%=24; } if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } while (t->tm_mday>spm[1+t->tm_mon]) { diff -Nru pdns-recursor-5.2.13/utility.hh pdns-recursor-5.4.9/utility.hh --- pdns-recursor-5.2.13/utility.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/utility.hh 2026-10-26 09:46:36.000000000 +0000 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff -Nru pdns-recursor-5.2.13/validate-recursor.cc pdns-recursor-5.4.9/validate-recursor.cc --- pdns-recursor-5.2.13/validate-recursor.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/validate-recursor.cc 2026-10-26 08:26:51.000000000 +0000 @@ -4,7 +4,7 @@ #include "logger.hh" #include "rec-lua-conf.hh" #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include "zoneparser-tng.hh" #include "rec-tcounters.hh" @@ -21,8 +21,7 @@ if (g_dnssecmode == DNSSECMode::Off) { if (!msg.empty()) { auto log = g_slog->withName("config"); - SLOG(g_log << Logger::Warning << msg << endl, - log->info(Logr::Warning, msg)); + log->info(Logr::Warning, msg); } return true; } @@ -64,17 +63,15 @@ if (dnskeyr == nullptr) { throw PDNSException("Unable to parse DNSKEY record '" + resourceRecord.qname.toString() + " " + resourceRecord.getZoneRepresentation() + "'"); } - auto dsr = makeDSFromDNSKey(resourceRecord.qname, *dnskeyr, DNSSECKeeper::DIGEST_SHA256); - newDSAnchors[resourceRecord.qname].insert(dsr); + auto dsr = makeDSFromDNSKey(resourceRecord.qname, *dnskeyr, DNSSEC::DIGEST_SHA256); + newDSAnchors[resourceRecord.qname].insert(std::move(dsr)); } } if (dsAnchors == newDSAnchors) { - SLOG(g_log << Logger::Debug << "Read Trust Anchors from file, no changes detected" << endl, - log->info(Logr::Debug, "Read Trust Anchors from file, no changes detected")); + log->info(Logr::Debug, "Read Trust Anchors from file, no changes detected"); return false; } - SLOG(g_log << Logger::Info << "Read changed Trust Anchors from file, updating" << endl, - log->info(Logr::Info, "Read changed Trust Anchors from file, updating")); + log->info(Logr::Info, "Read changed Trust Anchors from file, updating"); dsAnchors = std::move(newDSAnchors); return true; } diff -Nru pdns-recursor-5.2.13/validate.cc pdns-recursor-5.4.9/validate.cc --- pdns-recursor-5.2.13/validate.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/validate.cc 2026-10-26 09:46:36.000000000 +0000 @@ -23,12 +23,12 @@ #include "validate.hh" #include "misc.hh" #include "dnssecinfra.hh" -#include "dnsseckeeper.hh" +#include "dnssec.hh" #include "rec-lua-conf.hh" #include "base32.hh" #include "logger.hh" -time_t g_signatureInceptionSkew{0}; +uint32_t g_signatureInceptionSkew{0}; uint16_t g_maxNSEC3Iterations{0}; uint16_t g_maxRRSIGsPerRecordToConsider{0}; uint16_t g_maxNSEC3sPerRecordToConsider{0}; @@ -81,26 +81,64 @@ bool isCoveredByNSEC3Hash(const std::string& hash, const std::string& beginHash, const std::string& nextHash) { - return ((beginHash < hash && hash < nextHash) || // no wrap BEGINNING --- HASH -- END - (nextHash > hash && beginHash > nextHash) || // wrap HASH --- END --- BEGINNING - (nextHash < beginHash && beginHash < hash) || // wrap other case END --- BEGINNING --- HASH - (beginHash == nextHash && hash != beginHash)); // "we have only 1 NSEC3 record, LOL!" + int order_bh = beginHash.compare(hash); + int order_hn = hash.compare(nextHash); + if (order_bh < 0 && order_hn < 0) { // beginHash < hash && hash < nextHash + return true; // no wrap BEGINNING --- HASH -- END + } + int order_bn = beginHash.compare(nextHash); + if (order_hn < 0 && order_bn > 0) { // nextHash > hash && beginHash > nextHash + return true; // wrap HASH --- END --- BEGINNING + } + if (order_bn > 0 && order_bh < 0) { // nextHash < beginHash && beginHash < hash + return true; // wrap other case END --- BEGINNING --- HASH + } + if (order_bn == 0 && order_bh != 0) { // beginHash == nextHash && hash != beginHash + return true; // "we have only 1 NSEC3 record, LOL!" + } + return false; } +// Same logic as above, using DNSName::canonCompare_three_way instead of std::string::compare. bool isCoveredByNSEC3Hash(const DNSName& name, const DNSName& beginHash, const DNSName& nextHash) { - return ((beginHash.canonCompare(name) && name.canonCompare(nextHash)) || // no wrap BEGINNING --- HASH -- END - (name.canonCompare(nextHash) && nextHash.canonCompare(beginHash)) || // wrap HASH --- END --- BEGINNING - (nextHash.canonCompare(beginHash) && beginHash.canonCompare(name)) || // wrap other case END --- BEGINNING --- HASH - (beginHash == nextHash && name != beginHash)); // "we have only 1 NSEC3 record, LOL!" + int order_bh = beginHash.canonCompare_three_way(name); + int order_hn = name.canonCompare_three_way(nextHash); + if (order_bh < 0 && order_hn < 0) { + return true; // no wrap BEGINNING --- HASH -- END + } + int order_bn = beginHash.canonCompare_three_way(nextHash); + if (order_hn < 0 && order_bn > 0) { + return true; // wrap HASH --- END --- BEGINNING + } + if (order_bn > 0 && order_bh < 0) { + return true; // wrap other case END --- BEGINNING --- HASH + } + if (order_bn == 0 && order_bh != 0) { + return true; // "we have only 1 NSEC3 record, LOL!" + } + return false; } +// Exact same logic as above, except that the arguments are not hashes. bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNSName& next) { - return ((begin.canonCompare(name) && name.canonCompare(next)) || // no wrap BEGINNING --- NAME --- NEXT - (name.canonCompare(next) && next.canonCompare(begin)) || // wrap NAME --- NEXT --- BEGINNING - (next.canonCompare(begin) && begin.canonCompare(name)) || // wrap other case NEXT --- BEGINNING --- NAME - (begin == next && name != begin)); // "we have only 1 NSEC record, LOL!" + int order_bh = begin.canonCompare_three_way(name); + int order_hn = name.canonCompare_three_way(next); + if (order_bh < 0 && order_hn < 0) { + return true; // no wrap BEGINNING --- NAME -- NEXT + } + int order_bn = begin.canonCompare_three_way(next); + if (order_hn < 0 && order_bn > 0) { + return true; // wrap NEXT --- END --- BEGINNING + } + if (order_bn > 0 && order_bh < 0) { + return true; // wrap other case END --- BEGINNING --- NEXT + } + if (order_bn == 0 && order_bh != 0) { + return true; // "we have only 1 NSEC record, LOL!" + } + return false; } static bool nsecProvesENT(const DNSName& name, const DNSName& begin, const DNSName& next) @@ -186,7 +224,7 @@ return false; } - const string beginHash = fromBase32Hex(record.d_name.getRawLabels()[0]); + const string beginHash = fromBase32Hex(record.d_name.getRawLabel(0)); if (beginHash == hash) { return !nsec3->isSet(QType::NS); } @@ -404,7 +442,7 @@ return false; } VLOG(log, closestEncloser << ":\tWildcard hash: "< "<d_nexthash)< qname.countLabels()) { throw PDNSException("Invalid wildcard labels count for the validation of a positive answer synthesized from a wildcard"); } @@ -551,10 +589,22 @@ continue; } + DNSName nameToDeny; + if (!needWildcardProof) { + /* we are trying to prove that a wildcard can apply, so in effect we need to prove that the + next closer does not exist: the next closer can be different from the qname, + and can prevent the wildcard from applying. + */ + nameToDeny = qname; + nameToDeny.trimToLabels(wildcardLabelsCount + 1); + } + else { + nameToDeny = qname; + } const DNSName owner = getNSECOwnerName(validset.first.first, validset.second.signatures); const DNSName signer = getSigner(validset.second.signatures); - if (!validset.first.first.isPartOf(signer) || !owner.isPartOf(signer) || !qname.isPartOf(signer)) { - continue; + if (!validset.first.first.isPartOf(signer) || !owner.isPartOf(signer) || !nameToDeny.isPartOf(signer)) { + continue; } /* The NSEC is either a delegation one, from the parent zone, and @@ -563,7 +613,7 @@ */ const bool notApex = signer.countLabels() < owner.countLabels(); if (notApex && nsec->isSet(QType::NS) && nsec->isSet(QType::SOA)) { - VLOG(log, qname << ": However, that NSEC is not at the apex and has both the NS and the SOA bits set!"<isSet(QType::NS)) { - VLOG(log, qname << ": However, no NS record exists at this level!"<d_next); - if (provesNoWildCard(qname, qtype, closestEncloser, validrrsets, log)) { + DNSName closestEncloser = getClosestEncloserFromNSEC(nameToDeny, owner, nsec->d_next); + if (provesNoWildCard(nameToDeny, qtype, closestEncloser, validrrsets, log)) { return dState::NXQTYPE; } - VLOG(log, qname << ": But the existence of a wildcard is not denied for "<isSet(QType::DNAME)) { + if (nameToDeny.isPartOf(owner) && nsec->isSet(QType::DNAME)) { /* rfc6672 section 5.3.2: DNAME Bit in NSEC Type Map In any negative response, the NSEC or NSEC3 [RFC5155] record type @@ -638,23 +688,23 @@ asserted, then DNAME substitution should have been done, but the substitution has not been done as specified. */ - VLOG(log, qname << ": The DNAME bit is set and the query name is a subdomain of that NSEC"<< endl); + VLOG(log, nameToDeny << ": The DNAME bit is set and the query name is a subdomain of that NSEC" << endl); return dState::NODENIAL; } /* check if the whole NAME is denied existing */ - if (isCoveredByNSEC(qname, owner, nsec->d_next)) { - VLOG(log, qname<< ": Is covered by ("<d_next<<") "); + if (isCoveredByNSEC(nameToDeny, owner, nsec->d_next)) { + VLOG(log, nameToDeny << ": Is covered by (" << owner << " to " << nsec->d_next << ") "); - if (nsecProvesENT(qname, owner, nsec->d_next)) { + if (nsecProvesENT(nameToDeny, owner, nsec->d_next)) { if (wantsNoDataProof) { /* if the name is an ENT and we received a NODATA answer, we are fine with a NSEC proving that the name does not exist. */ - VLOG_NO_PREFIX(log, "Denies existence of type "<d_next); + DNSName closestEncloser = getClosestEncloserFromNSEC(nameToDeny, owner, nsec->d_next); if (wantsNoDataProof) { - VLOG_NO_PREFIX(log, "looking for NODATA proof"<isSet(qtype)<<", next: "<d_next<isSet(qtype) << ", next: " << nsec->d_next << endl); } } else if(validset.first.second==QType::NSEC3) { for (const auto& record : validset.second.records) { @@ -729,7 +779,7 @@ nsec3Seen = true; VLOG(log, qname << ":\tquery hash: "< "<d_nexthash)<d_nexthash)) { @@ -979,14 +1029,16 @@ bool isRRSIGNotExpired(const time_t now, const RRSIGRecordContent& sig) { - // Should use https://www.rfc-editor.org/rfc/rfc4034.txt section 3.1.5 - return sig.d_sigexpire >= now; + // it's an uint32_t rfc1982 compare, explicitly cast now to uint32_t to avoid Coverity warning + // implicitly converting a time_t to a smaller int. + return rfc1982LessThanOrEqual(static_cast(now), sig.d_sigexpire); } bool isRRSIGIncepted(const time_t now, const RRSIGRecordContent& sig) { - // Should use https://www.rfc-editor.org/rfc/rfc4034.txt section 3.1.5 - return sig.d_siginception - g_signatureInceptionSkew <= now; + // it's an uint32_t rfc1982 compare, explicitly cast now to uint32_t to avoid Coverity warning + // implicitly converting a time_t to a smaller int. + return rfc1982LessThanOrEqual(sig.d_siginception - g_signatureInceptionSkew, static_cast(now)); } namespace { @@ -996,10 +1048,17 @@ - The validator's notion of the current time MUST be less than or equal to the time listed in the RRSIG RR's Expiration field. - The validator's notion of the current time MUST be greater than or equal to the time listed in the RRSIG RR's Inception field. */ - if (isRRSIGIncepted(now, sig) && isRRSIGNotExpired(now, sig)) { + vState localEDE = vState::Indeterminate; + if (!isRRSIGIncepted(now, sig)) { + localEDE = vState::BogusSignatureNotYetValid; + } + else if (!isRRSIGNotExpired(now, sig)) { + localEDE = vState::BogusSignatureExpired; + } + if (localEDE == vState::Indeterminate) { return true; } - ede = ((sig.d_siginception - g_signatureInceptionSkew) > now) ? vState::BogusSignatureNotYetValid : vState::BogusSignatureExpired; + ede = localEDE; VLOG(log, qname << ": Signature is "<<(ede == vState::BogusSignatureNotYetValid ? "not yet valid" : "expired")<<" (inception: "<verify(msg, sig.d_signature); - VLOG(log, qname << ": Signature by key with tag "< get(const DNSName& qname, uint16_t qtype) = 0; -}; - - struct ContentSigPair { sortedRecords_t records; diff -Nru pdns-recursor-5.2.13/version.cc pdns-recursor-5.4.9/version.cc --- pdns-recursor-5.2.13/version.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/version.cc 2026-10-26 09:46:36.000000000 +0000 @@ -153,6 +153,12 @@ #ifdef HAVE_LIBSODIUM << " sodium" #endif +#ifdef HAVE_LIBSSL + << " libssl" +#endif +#ifdef HAVE_GNUTLS + << " gnutls" +#endif #ifdef HAVE_LIBCURL << " curl" #endif @@ -168,6 +174,9 @@ #ifdef VERBOSELOG << " verboselog" #endif +#ifdef HAVE_LIBCAP + << " libcap" +#endif << endl; #ifdef PDNS_MODULES // Auth only diff -Nru pdns-recursor-5.2.13/version.sh pdns-recursor-5.4.9/version.sh --- pdns-recursor-5.2.13/version.sh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-5.4.9/version.sh 2026-10-26 08:26:51.000000000 +0000 @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ "$1" = "get-vcs" ]; then + builder-support/gen-version +elif [ "$1" = "set-dist" ]; then + $MESONREWRITE -V --sourcedir="$MESON_PROJECT_DIST_ROOT" kwargs set project / version "$2" +else + exit 1 +fi diff -Nru pdns-recursor-5.2.13/webserver.cc pdns-recursor-5.4.9/webserver.cc --- pdns-recursor-5.2.13/webserver.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/webserver.cc 2026-10-26 09:46:36.000000000 +0000 @@ -19,9 +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. */ -#ifdef HAVE_CONFIG_H + #include "config.h" -#endif + #include "utility.hh" #include "webserver.hh" #include "misc.hh" @@ -37,7 +37,14 @@ #include "uuid-utils.hh" #include #include -#include +#include +#include + +#if !defined(RUST_WS) +#include + +namespace filesystem = std::filesystem; +#endif json11::Json HttpRequest::json() { @@ -136,6 +143,8 @@ this->status = status_; } +#ifndef RUST_WS + static void bareHandlerWrapper(const WebServer::HandlerFunction& handler, YaHTTP::Request* req, YaHTTP::Response* resp) { // wrapper to convert from YaHTTP::* to our subclasses @@ -157,7 +166,7 @@ throw HttpUnauthorizedException("X-API-Key"); } - bool auth_ok = req->compareHeader("x-api-key", *d_apikey) || d_apikey->matches(req->getvars["api-key"]); + bool auth_ok = req->compareHeader("x-api-key", *d_apikey); if (!auth_ok && allowPassword) { if (d_webserverPassword) { @@ -200,8 +209,8 @@ } void WebServer::registerApiHandler(const string& url, const HandlerFunction& handler, const std::string& method, bool allowPassword) { - auto f = [=](HttpRequest *req, HttpResponse* resp){apiWrapper(handler, req, resp, allowPassword);}; - registerBareHandler(url, f, method); + auto func = [handler, allowPassword, this](HttpRequest *req, HttpResponse* resp){apiWrapper(handler, req, resp, allowPassword);}; + registerBareHandler(url, func, method); } void WebServer::webWrapper(const WebServer::HandlerFunction& handler, HttpRequest* req, HttpResponse* resp) { @@ -218,8 +227,8 @@ } void WebServer::registerWebHandler(const string& url, const HandlerFunction& handler, const std::string& method) { - auto f = [=](HttpRequest *req, HttpResponse *resp){webWrapper(handler, req, resp);}; - registerBareHandler(url, f, method); + auto func = [handler, this](HttpRequest *req, HttpResponse *resp){webWrapper(handler, req, resp);}; + registerBareHandler(url, func, method); } static void* WebServerConnectionThreadStart(const WebServer* webServer, const std::shared_ptr& client) @@ -244,6 +253,34 @@ return nullptr; } +// Decide which content type to use for the answer, based on the +// `accept' request header. If this header is missing, we try to +// reply with the same content type as the request. +static void setupAllowedContentType(HttpRequest& req) +{ + auto header = req.headers.find("accept"); + if (header != req.headers.end()) { + // If Accept: */* then we'll happily serve anything! + if (header->second.find("*/*") != std::string::npos) { + req.accept_yaml = req.accept_json = req.accept_html = true; + return; + } + } + else { + header = req.headers.find("content-type"); + } + if (header != req.headers.end()) { + // yaml wins over json, json wins over html + if (header->second.find("application/x-yaml") != std::string::npos || header->second.find("text/x-yaml") != std::string::npos) { + req.accept_yaml = true; + } else if (header->second.find("application/json") != std::string::npos) { + req.accept_json = true; + } else if (header->second.find("text/html") != std::string::npos) { + req.accept_html = true; + } + } +} + void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp) const { // set default headers @@ -262,20 +299,7 @@ SLOG(g_log<info(Logr::Debug, "Handling request")); - YaHTTP::strstr_map_t::iterator header; - - if ((header = req.headers.find("accept")) != req.headers.end()) { - // yaml wins over json, json wins over html - if (header->second.find("application/x-yaml") != std::string::npos) { - req.accept_yaml = true; - } else if (header->second.find("text/x-yaml") != std::string::npos) { - req.accept_yaml = true; - } else if (header->second.find("application/json") != std::string::npos) { - req.accept_json = true; - } else if (header->second.find("text/html") != std::string::npos) { - req.accept_html = true; - } - } + setupAllowedContentType(req); YaHTTP::THandlerFunction handler; YaHTTP::RoutingResult res = YaHTTP::Router::Route(&req, handler); @@ -587,8 +611,8 @@ d_listenaddress(std::move(listenaddress)), d_port(port), d_server(nullptr), - d_maxbodysize(2*1024*1024), - d_connectiontimeout(5) + d_maxbodysize(static_cast(2 * 1024 * 1024)) + { YaHTTP::Router::Map("OPTIONS", "/<*url>", [](YaHTTP::Request *req, YaHTTP::Response *resp) { // look for url in routes @@ -624,10 +648,25 @@ void WebServer::bind() { + if (filesystem::is_socket(d_listenaddress.c_str())) { + int err=unlink(d_listenaddress.c_str()); + if(err < 0 && errno!=ENOENT) { + SLOG(g_log<error(Logr::Error, e.what(), "Listening on HTTP socket failed, unable to remove existing socket", "exception", d_listenaddress)); + d_server = nullptr; + return; + } + } + try { d_server = createServer(); - SLOG(g_log<d_local.toStringWithPort()<info(Logr::Info, "Listening for HTTP requests", "address", Logging::Loggable(d_server->d_local))); + if (d_server->d_local.isUnixSocket()) { + SLOG(g_log<info(Logr::Info, "Listening for HTTP requests", "path", Logging::Loggable(d_listenaddress))); + } else { + SLOG(g_log<d_local.toStringWithPort()<info(Logr::Info, "Listening for HTTP requests", "address", Logging::Loggable(d_server->d_local))); + } } catch(NetworkError &e) { SLOG(g_log<acl(d_acl)) { + if (d_server->d_local.isUnixSocket() || client->acl(d_acl)) { std::thread webHandler(WebServerConnectionThreadStart, this, client); webHandler.detach(); } else { @@ -686,3 +725,4 @@ } _exit(1); } +#endif // !RUST_WS diff -Nru pdns-recursor-5.2.13/webserver.hh pdns-recursor-5.4.9/webserver.hh --- pdns-recursor-5.2.13/webserver.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/webserver.hh 2026-10-26 09:46:36.000000000 +0000 @@ -20,12 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once -#include -#include -#include + +#include "config.h" + +#ifdef RECURSOR +// Network facing/routing part of webserver is implemented in rust. We still use a few classes from +// yahttp, but do not link to it. +#define RUST_WS +#endif + #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverloaded-virtual" +#include #include #pragma GCC diagnostic pop @@ -33,12 +40,15 @@ #include "credentials.hh" #include "namespaces.hh" +#ifndef REST_WS #include "sstuff.hh" +#endif #include "logging.hh" class HttpRequest : public YaHTTP::Request { public: - HttpRequest(const string& logprefix_="") : YaHTTP::Request(), logprefix(logprefix_) { }; + HttpRequest(string logprefix_ = "") : + YaHTTP::Request(), logprefix(std::move(logprefix_)) {}; string logprefix; bool accept_yaml{false}; @@ -157,6 +167,8 @@ } }; +#ifndef RUST_WS + class Server { public: @@ -167,7 +179,7 @@ } virtual ~Server() = default; - ComboAddress d_local; + SockaddrWrapper d_local; std::shared_ptr accept() { return std::shared_ptr(d_server_socket.accept()); @@ -289,7 +301,7 @@ std::unique_ptr d_webserverPassword{nullptr}; ssize_t d_maxbodysize; // in bytes - int d_connectiontimeout; // in seconds + int d_connectiontimeout{5}; // in seconds NetmaskGroup d_acl; @@ -298,3 +310,5 @@ // Describes the amount of logging the webserver does WebServer::LogLevel d_loglevel{WebServer::LogLevel::Detailed}; }; + +#endif // !RUST_WS diff -Nru pdns-recursor-5.2.13/ws-api.cc pdns-recursor-5.4.9/ws-api.cc --- pdns-recursor-5.2.13/ws-api.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ws-api.cc 2026-10-26 09:46:36.000000000 +0000 @@ -50,47 +50,6 @@ extern StatBag S; #endif -#ifndef HAVE_STRCASESTR - -/* - * strcasestr() locates the first occurrence in the string s1 of the - * sequence of characters (excluding the terminating null character) - * in the string s2, ignoring case. strcasestr() returns a pointer - * to the located string, or a null pointer if the string is not found. - * If s2 is empty, the function returns s1. - */ - -static char* -strcasestr(const char* s1, const char* s2) -{ - int* cm = __trans_lower; - const uchar_t* us1 = (const uchar_t*)s1; - const uchar_t* us2 = (const uchar_t*)s2; - const uchar_t* tptr; - int c; - - if (us2 == NULL || *us2 == '\0') - return ((char*)us1); - - c = cm[*us2]; - while (*us1 != '\0') { - if (c == cm[*us1++]) { - tptr = us1; - while (cm[c = *++us2] == cm[*us1++] && c != '\0') - continue; - if (c == '\0') - return ((char*)tptr - 1); - us1 = tptr; - us2 = (const uchar_t*)s2; - c = cm[*us2]; - } - } - - return (NULL); -} - -#endif // HAVE_STRCASESTR - static Json getServerDetail() { return Json::object{ @@ -307,7 +266,27 @@ } } -DNSName apiZoneIdToName(const string& identifier) +#if defined(PDNS_AUTH) +ZoneName apiNameToZoneName(const string& name) +{ + // Split the variant name, if any, in order to be able to invoke + // isCanonical on the right subset. + if (auto sep = ZoneName::findVariantSeparator(name); sep != std::string_view::npos) { + if (!isCanonical(std::string_view(name).substr(0, sep))) { + throw ApiException("Zone Name '" + name + "' is not canonical"); + } + try { + return ZoneName(name, sep); + } + catch (...) { + throw ApiException("Unable to parse Zone Name '" + name + "'"); + } + } + return ZoneName(apiNameToDNSName(name)); +} +#endif + +ZoneName apiZoneIdToName(const string& identifier) { string zonename; ostringstream outputStringStream; @@ -355,16 +334,15 @@ zonename = outputStringStream.str(); try { - return DNSName(zonename); + return ZoneName(zonename); } catch (...) { throw ApiException("Unable to parse DNS Name '" + zonename + "'"); } } -string apiZoneNameToId(const DNSName& dname) +static string encodeName(const string& name) { - string name = dname.toString(); ostringstream outputStringStream; for (char iter : name) { @@ -376,14 +354,34 @@ } } - string identifier = outputStringStream.str(); + return outputStringStream.str(); +} + +string apiZoneNameToId(const ZoneName& dname) +{ +#if defined(PDNS_AUTH) + std::string ret = apiNameToId(dname.operator const DNSName&().toString()); + // Add the variant, if any + if (dname.hasVariant()) { + ret += "."; + ret += encodeName(dname.getVariant()); + } + return ret; +#else + return apiNameToId(dname.toString()); +#endif +} + +string apiNameToId(const string& name) +{ + string identifier = encodeName(name); // add trailing dot if (identifier.empty() || identifier.substr(identifier.size() - 1) != ".") { identifier += "."; } - // special handling for the root zone, as a dot on it's own doesn't work + // special handling for the root zone, as a dot on its own doesn't work // everywhere. if (identifier == ".") { identifier = (boost::format("=%02X") % (int)('.')).str(); @@ -391,14 +389,14 @@ return identifier; } -void apiCheckNameAllowedCharacters(const string& name) +void apiCheckNameAllowedCharacters(std::string_view name) { if (name.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_/.-") != std::string::npos) { - throw ApiException("Name '" + name + "' contains unsupported characters"); + throw ApiException("Name '" + std::string(name) + "' contains unsupported characters"); } } -void apiCheckQNameAllowedCharacters(const string& qname) +void apiCheckQNameAllowedCharacters(std::string_view qname) { if (qname.compare(0, 2, "*.") == 0) { apiCheckNameAllowedCharacters(qname.substr(2)); diff -Nru pdns-recursor-5.2.13/ws-api.hh pdns-recursor-5.4.9/ws-api.hh --- pdns-recursor-5.2.13/ws-api.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ws-api.hh 2026-10-26 09:46:36.000000000 +0000 @@ -32,11 +32,15 @@ void apiServerStatistics(HttpRequest* req, HttpResponse* resp); // helpers -DNSName apiZoneIdToName(const string& identifier); -string apiZoneNameToId(const DNSName& name); -void apiCheckNameAllowedCharacters(const string& name); -void apiCheckQNameAllowedCharacters(const string& name); +ZoneName apiZoneIdToName(const string& identifier); +string apiZoneNameToId(const ZoneName& name); +string apiNameToId(const std::string& name); +void apiCheckNameAllowedCharacters(std::string_view name); +void apiCheckQNameAllowedCharacters(std::string_view name); DNSName apiNameToDNSName(const string& name); +#if defined(PDNS_AUTH) +ZoneName apiNameToZoneName(const string& name); +#endif // To be provided by product code. void productServerStatisticsFetch(std::map& out); diff -Nru pdns-recursor-5.2.13/ws-recursor.cc pdns-recursor-5.4.9/ws-recursor.cc --- pdns-recursor-5.2.13/ws-recursor.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ws-recursor.cc 2026-10-26 08:26:51.000000000 +0000 @@ -19,12 +19,13 @@ * 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 "ws-recursor.hh" #include "json.hh" +#include #include #include "namespaces.hh" #include @@ -41,10 +42,11 @@ #include "logging.hh" #include "rec-lua-conf.hh" #include "rpzloader.hh" -#include "uuid-utils.hh" -#include "tcpiohandler.hh" #include "rec-main.hh" -#include "settings/cxxsettings.hh" // IWYU pragma: keep, needed by included generated file +#include "rec-rust-lib/cxxsettings.hh" // IWYU pragma: keep, needed by included generated file +#include "rec-rust-lib/rust/src/bridge.hh" +#include "rec-rust-lib/rust/web.rs.h" +#include "rec-rust-lib/rust/misc.rs.h" using json11::Json; @@ -89,11 +91,13 @@ { // Return currently configured ACLs vector entries; - if (t_allowFrom && aclType == "allow-from") { - entries = t_allowFrom->toStringVector(); + auto lock1 = g_initialAllowFrom.lock(); + auto lock2 = g_initialAllowNotifyFrom.lock(); + if (*lock1 && aclType == "allow-from") { + entries = (*lock1)->toStringVector(); } - else if (t_allowNotifyFrom && aclType == "allow-notify-from") { - entries = t_allowNotifyFrom->toStringVector(); + else if (*lock2 && aclType == "allow-notify-from") { + entries = (*lock2)->toStringVector(); } resp->setJsonBody(Json::object{ @@ -181,10 +185,28 @@ apiServerConfigACLPUT("allow-notify-from", req, resp); } +static bool isAllowedNotify(DNSName qname) +{ + auto lock = g_initialAllowNotifyFor.lock(); + + if (*lock == nullptr || (*lock)->empty()) { + return false; + } + + do { + auto ret = (*lock)->find(qname); + if (ret != (*lock)->end()) { + return true; + } + } while (qname.chopOff()); + return false; +} + static void fillZone(const DNSName& zonename, HttpResponse* resp) { - auto iter = SyncRes::t_sstorage.domainmap->find(zonename); - if (iter == SyncRes::t_sstorage.domainmap->end()) { + auto lock = g_initialDomainMap.lock(); + auto iter = (*lock)->find(zonename); + if (iter == (*lock)->end()) { throw ApiException("Could not find domain '" + zonename.toLogString() + "'"); } @@ -213,7 +235,7 @@ {"kind", zone.d_servers.empty() ? "Native" : "Forwarded"}, {"servers", servers}, {"recursion_desired", zone.d_servers.empty() ? false : zone.d_rdForward}, - {"notify_allowed", isAllowNotifyForZone(zonename)}, + {"notify_allowed", isAllowedNotify(zonename)}, {"records", records}}; resp->setJsonBody(doc); @@ -357,13 +379,14 @@ Json document = req->json(); DNSName zonename = apiNameToDNSName(stringFromJson(document, "name")); - - const auto& iter = SyncRes::t_sstorage.domainmap->find(zonename); - if (iter != SyncRes::t_sstorage.domainmap->cend()) { - throw ApiException("Zone already exists"); + { + auto map = g_initialDomainMap.lock(); + const auto& iter = (*map)->find(zonename); + if (iter != (*map)->cend()) { + throw ApiException("Zone already exists"); + } + doCreateZone(document); } - - doCreateZone(document); reloadZoneConfiguration(g_yamlSettings); fillZone(zonename, resp); resp->status = 201; @@ -372,7 +395,8 @@ static void apiServerZonesGET(HttpRequest* /* req */, HttpResponse* resp) { Json::array doc; - for (const auto& val : *SyncRes::t_sstorage.domainmap) { + auto lock = g_initialDomainMap.lock(); + for (const auto& val : **lock) { const SyncRes::AuthDomain& zone = val.second; Json::array servers; for (const auto& server : zone.d_servers) { @@ -394,7 +418,8 @@ static inline DNSName findZoneById(HttpRequest* req) { auto zonename = apiZoneIdToName(req->parameters["id"]); - if (SyncRes::t_sstorage.domainmap->find(zonename) == SyncRes::t_sstorage.domainmap->end()) { + auto lock = g_initialDomainMap.lock(); + if ((*lock)->find(zonename) == (*lock)->end()) { throw ApiException("Could not find domain '" + zonename.toLogString() + "'"); } return zonename; @@ -438,8 +463,9 @@ throw ApiException("Query q can't be blank"); } + auto lock = g_initialDomainMap.lock(); Json::array doc; - for (const SyncRes::domainmap_t::value_type& val : *SyncRes::t_sstorage.domainmap) { + for (const SyncRes::domainmap_t::value_type& val : **lock) { string zoneId = apiZoneNameToId(val.first); string zoneName = val.first.toString(); if (pdns_ci_find(zoneName, qVar) != string::npos) { @@ -517,6 +543,167 @@ resp->setJsonBody(ret); } +static void apiServerOTConditionsGET(HttpRequest* /* req */, HttpResponse* resp) +{ + Json::array doc; + auto lock = g_initialOpenTelemetryConditions.lock(); + if (*lock) { + for (const auto& condition : **lock) { + Json::object object{ + {"acl", condition.first.toString()}, + {"type", "OpenTelemetryTraceCondition"}, + {"edns_option_required", condition.second.d_edns_option_required}, + {"traceid_only", condition.second.d_traceid_only}, + }; + if (condition.second.d_qid) { + object.emplace("qid", *condition.second.d_qid); + } + if (condition.second.d_qnames) { + Json::array array; + for (const auto& name : condition.second.d_qnames->toVector()) { + array.emplace_back(name.toString()); + } + object.emplace("qnames", array); + } + if (condition.second.d_qtypes) { + Json::array array; + for (const auto& name : *condition.second.d_qtypes) { + array.emplace_back(name.toString()); + } + object.emplace("qtypes", array); + } + + doc.emplace_back(std::move(object)); + } + } + resp->setJsonBody(doc); +} + +static void fillOTCondition(const Netmask& netmask, HttpResponse* resp) +{ + auto lock = g_initialOpenTelemetryConditions.lock(); + if (*lock) { + auto condition = (*lock)->lookup(netmask); + if (condition != nullptr && condition->first == netmask) { // exact match + Json::object object{ + {"acl", condition->first.toString()}, + {"type", "OpenTelemetryTraceCondition"}, + {"edns_option_required", condition->second.d_edns_option_required}, + {"traceid_only", condition->second.d_traceid_only}, + }; + if (condition->second.d_qid) { + object.emplace("qid", *condition->second.d_qid); + } + if (condition->second.d_qnames) { + Json::array array; + for (const auto& name : condition->second.d_qnames->toVector()) { + array.emplace_back(name.toString()); + } + object.emplace("qnames", array); + } + if (condition->second.d_qtypes) { + Json::array array; + for (const auto& name : *condition->second.d_qtypes) { + array.emplace_back(name.toString()); + } + object.emplace("qtypes", array); + } + resp->setJsonBody(object); + return; + } + } + throw ApiException("Could not find otcondition '" + netmask.toString() + "'"); +} + +static void apiServerOTConditionDetailGET(HttpRequest* req, HttpResponse* resp) +{ + try { + Netmask netmask{req->parameters["acl"]}; + fillOTCondition(netmask, resp); + } + catch (NetmaskException& ex) { + throw ApiException("Could not parse netmask"); + } +} + +static void apiServerOTConditionDetailDELETE(HttpRequest* req, HttpResponse* resp) +{ + try { + Netmask netmask{req->parameters["acl"]}; + auto lock = g_initialOpenTelemetryConditions.lock(); + if (*lock) { + auto condition = (*lock)->lookup(netmask); + if (condition != nullptr && condition->first == netmask) { // exact match + (*lock)->erase(condition->first); + updateOTConditions(**lock); + // empty body on success + resp->body = ""; + resp->status = 204; // No Content: declare that the condition is gone now + return; + } + } + throw ApiException("Could not find otcondition '" + netmask.toString() + "'"); + } + catch (NetmaskException&) { + throw ApiException("Could not parse netmask"); + } +} + +static void apiServerOTConditionDetailPOST(HttpRequest* req, HttpResponse* resp) +{ + Netmask netmask; + try { + Json document = req->json(); + if (auto acl = document["acl"]; acl != Json()) { + netmask = Netmask{acl.string_value()}; + } + else { + throw ApiException("Required parameter acl missing"); + } + auto lock = g_initialOpenTelemetryConditions.lock(); + if (!*lock) { + *lock = std::make_unique(); + } + auto conditionPtr = (*lock)->lookup(netmask); + if (conditionPtr != nullptr && conditionPtr->first == netmask) { // exact match + throw ApiException("OTCondition already exists"); + } + + OpenTelemetryTraceCondition condition; + if (auto traceid_only = document["traceid_only"]; traceid_only.is_bool()) { + condition.d_traceid_only = traceid_only.bool_value(); + } + if (auto edns = document["edns_option_required"]; edns.is_bool()) { + condition.d_edns_option_required = edns.bool_value(); + } + if (auto qnames = document["qnames"]; qnames.is_array() && !qnames.array_items().empty()) { + condition.d_qnames = SuffixMatchNode(); + for (const auto& qname : qnames.array_items()) { + condition.d_qnames->add(DNSName(qname.string_value())); + } + } + if (auto qtypes = document["qtypes"]; qtypes.is_array() && !qtypes.array_items().empty()) { + condition.d_qtypes = std::unordered_set(); + for (const auto& qtype : qtypes.array_items()) { + if (auto qcode = QType::chartocode(qtype.string_value().c_str()); qcode > 0) { + condition.d_qtypes->insert(qcode); + } + } + } + if (auto qid = document["qid"]; qid.is_number()) { + condition.d_qid = qid.int_value(); + } + (*lock)->insert(netmask).second = std::move(condition); + updateOTConditions(**lock); + } + catch (NetmaskException&) { + throw ApiException("Could not parse netmask"); + } + fillOTCondition(netmask, resp); + resp->status = 201; + return; +} + static void prometheusMetrics(HttpRequest* /* req */, HttpResponse* resp) { static MetricDefinitionStorage s_metricDefinitions; @@ -529,12 +716,15 @@ for (const auto& tup : varmap) { std::string metricName = tup.first; std::string prometheusMetricName = tup.second.d_prometheusName; + std::string prometheusTypeName; + std::string prometheusDescr; std::string helpname = tup.second.d_prometheusName; MetricDefinition metricDetails; if (s_metricDefinitions.getMetricDetails(metricName, metricDetails)) { - std::string prometheusTypeName = MetricDefinitionStorage::getPrometheusStringMetricType( + prometheusTypeName = MetricDefinitionStorage::getPrometheusStringMetricType( metricDetails.d_prometheusType); + prometheusDescr = metricDetails.d_description; if (prometheusTypeName.empty()) { continue; @@ -547,8 +737,22 @@ // name is XXX_count, strip the _count part helpname = helpname.substr(0, helpname.length() - 6); } + } + else { + if (tup.second.d_prometheusType) { + prometheusTypeName = MetricDefinitionStorage::getPrometheusStringMetricType( + *tup.second.d_prometheusType); + } + if (tup.second.d_prometheusDescr) { + prometheusDescr = *tup.second.d_prometheusDescr; + } + } + + if (!prometheusTypeName.empty()) { output << "# TYPE " << helpname << " " << prometheusTypeName << "\n"; - output << "# HELP " << helpname << " " << metricDetails.d_description << "\n"; + } + if (!prometheusDescr.empty()) { + output << "# HELP " << helpname << " " << prometheusDescr << "\n"; } output << prometheusMetricName << " " << tup.second.d_value << "\n"; } @@ -612,6 +816,8 @@ #include "rec-prometheus-gen.h" }; +#ifndef RUST_WS + constexpr bool CHECK_PROMETHEUS_METRICS = false; static void validatePrometheusMetrics() @@ -637,8 +843,7 @@ MetricDefinition metricDetails; if (!s_metricDefinitions.getMetricDetails(metricName, metricDetails)) { - SLOG(g_log << Logger::Debug << "{ \"" << metricName << "\", MetricDefinition(PrometheusMetricType::counter, \"\")}," << endl, - g_slog->info(Logr::Debug, "{ \"" + metricName + "\", MetricDefinition(PrometheusMetricType::counter, \"\")},")); + g_slog->info(Logr::Debug, "{ \"" + metricName + "\", MetricDefinition(PrometheusMetricType::counter, \"\")},"); } } } @@ -692,8 +897,9 @@ d_ws->registerWebHandler("/metrics", prometheusMetrics, "GET"); d_ws->go(); } +#endif // !RUST_WS -void RecursorWebServer::jsonstat(HttpRequest* req, HttpResponse* resp) +static void jsonstat(HttpRequest* req, HttpResponse* resp) { string command; @@ -806,6 +1012,8 @@ resp->setErrorResult("Command '" + command + "' not found", 404); } +#ifndef RUST_WS + void AsyncServerNewConnectionMT(void* arg) { auto* server = static_cast(arg); @@ -818,14 +1026,11 @@ } catch (NetworkError& e) { // we're running in a shared process/thread, so can't just terminate/abort. - SLOG(g_log << Logger::Warning << "Network error in web thread: " << e.what() << endl, - g_slog->withName("webserver")->error(Logr::Warning, e.what(), "Exception in web tread", Logging::Loggable("NetworkError"))); + g_slog->withName("webserver")->error(Logr::Warning, e.what(), "Exception in web tread", Logging::Loggable("NetworkError")); return; } catch (...) { - SLOG(g_log << Logger::Warning << "Unknown error in web thread" << endl, - g_slog->withName("webserver")->info(Logr::Warning, "Exception in web tread")); - + g_slog->withName("webserver")->info(Logr::Warning, "Exception in web tread"); return; } } @@ -867,10 +1072,8 @@ yarl.initialize(&req); socket->setNonBlocking(); - const struct timeval timeout - { - g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000 - }; + const struct timeval timeout{ + g_networkTimeoutMsec / 1000, static_cast(g_networkTimeoutMsec) % 1000 * 1000}; std::shared_ptr tlsCtx{nullptr}; if (d_loglevel > WebServer::LogLevel::None) { socket->getRemote(remote); @@ -894,8 +1097,7 @@ } catch (YaHTTP::ParseError& e) { // request stays incomplete - SLOG(g_log << Logger::Warning << logprefix << "Unable to parse request: " << e.what() << endl, - req.d_slog->error(Logr::Warning, e.what(), "Unable to parse request")); + req.d_slog->error(Logr::Warning, e.what(), "Unable to parse request"); } if (!validURL(req.url)) { @@ -913,30 +1115,25 @@ // now send the reply if (asendtcp(reply, handler) != LWResult::Result::Success || reply.empty()) { - SLOG(g_log << Logger::Error << logprefix << "Failed sending reply to HTTP client" << endl, - req.d_slog->info(Logr::Error, "Failed sending reply to HTTP client")); + req.d_slog->info(Logr::Error, "Failed sending reply to HTTP client"); } handler->close(); // needed to signal "done" to client if (d_loglevel >= WebServer::LogLevel::Normal) { - SLOG(g_log << Logger::Notice << logprefix << remote << " \"" << req.method << " " << req.url.path << " HTTP/" << req.versionStr(req.version) << "\" " << resp.status << " " << reply.size() << endl, - req.d_slog->info(Logr::Info, "Request", "remote", Logging::Loggable(remote), "method", Logging::Loggable(req.method), - "urlpath", Logging::Loggable(req.url.path), "HTTPVersion", Logging::Loggable(req.versionStr(req.version)), - "status", Logging::Loggable(resp.status), "respsize", Logging::Loggable(reply.size()))); + req.d_slog->info(Logr::Info, "Request", "remote", Logging::Loggable(remote), "method", Logging::Loggable(req.method), + "urlpath", Logging::Loggable(req.url.path), "HTTPVersion", Logging::Loggable(req.versionStr(req.version)), + "status", Logging::Loggable(resp.status), "respsize", Logging::Loggable(reply.size())); } } catch (PDNSException& e) { - SLOG(g_log << Logger::Error << logprefix << "Exception: " << e.reason << endl, - req.d_slog->error(Logr::Error, e.reason, "Exception handing request", "exception", Logging::Loggable("PDNSException"))); + req.d_slog->error(Logr::Error, e.reason, "Exception handing request", "exception", Logging::Loggable("PDNSException")); } catch (std::exception& e) { if (strstr(e.what(), "timeout") == nullptr) { - SLOG(g_log << Logger::Error << logprefix << "STL Exception: " << e.what() << endl, - req.d_slog->error(Logr::Error, e.what(), "Exception handing request", "exception", Logging::Loggable("std::exception"))); + req.d_slog->error(Logr::Error, e.what(), "Exception handing request", "exception", Logging::Loggable("std::exception"))) } } catch (...) { - SLOG(g_log << Logger::Error << logprefix << "Unknown exception" << endl, - req.d_slog->error(Logr::Error, "Exception handing request")); + req.d_slog->error(Logr::Error, "Exception handing request"); } } @@ -951,3 +1148,139 @@ } server->asyncWaitForConnections(d_fdm, [this](const std::shared_ptr& socket) { serveConnection(socket); }); } +#endif // !RUST_WS + +void serveRustWeb() +{ + ::rust::Vec config; + + if (g_yamlSettings) { + auto settings = g_yamlStruct.lock(); + for (const auto& listen : settings->webservice.listen) { + pdns::rust::web::rec::IncomingWSConfig tmp; + for (const auto& address : listen.addresses) { + tmp.addresses.emplace_back(address); + } + tmp.tls = pdns::rust::web::rec::IncomingTLS{listen.tls.certificate, listen.tls.key}; + config.emplace_back(tmp); + } + } + if (config.empty()) { + auto address = ComboAddress(arg()["webserver-address"], arg().asNum("webserver-port")); + pdns::rust::web::rec::IncomingWSConfig tmp{{::rust::String{address.toStringWithPort()}}, {}}; + config.emplace_back(tmp); + } + + auto passwordString = arg()["webserver-password"]; + std::unique_ptr password; + if (!passwordString.empty()) { + password = std::make_unique(std::move(passwordString), arg().mustDo("webserver-hash-plaintext-credentials")); + } + auto apikeyString = arg()["api-key"]; + std::unique_ptr apikey; + if (!apikeyString.empty()) { + apikey = std::make_unique(std::move(apikeyString), arg().mustDo("webserver-hash-plaintext-credentials")); + } + NetmaskGroup acl; + acl.toMasks(::arg()["webserver-allow-from"]); + auto aclPtr = std::make_unique(acl); + + auto logPtr = g_slog->withName("webserver"); + + if (arg()["webserver-password"].empty()) { + logPtr->info(Logr::Warning, "Webserver launched without a password set!"); + } + pdns::rust::misc::LogLevel loglevel = pdns::rust::misc::LogLevel::Normal; + const auto& configLevel = ::arg()["webserver-loglevel"]; + if (configLevel == "none") { + loglevel = pdns::rust::misc::LogLevel::None; + } + else if (configLevel == "detailed") { + loglevel = pdns::rust::misc::LogLevel::Detailed; + } + // This function returns after having created the web server object that handles the requests. + // That object and its runtime are associated with a Posix thread that waits until all tasks are + // done, which normally never happens. See rec-rust-lib/rust/src/web.rs for details + pdns::rust::web::rec::serveweb(config, std::move(password), std::move(apikey), std::move(aclPtr), std::move(logPtr), loglevel, arg().asNum("webserver-max-request-size") * 1024 * 1024); +} + +static void fromCxxToRust(const HttpResponse& cxxresp, pdns::rust::web::rec::Response& rustResponse) +{ + if (cxxresp.status != 0) { + rustResponse.status = cxxresp.status; + } + rustResponse.body = ::rust::Vec<::rust::u8>(); + rustResponse.body.reserve(cxxresp.body.size()); + std::copy(cxxresp.body.cbegin(), cxxresp.body.cend(), std::back_inserter(rustResponse.body)); + for (const auto& header : cxxresp.headers) { + rustResponse.headers.emplace_back(pdns::rust::web::rec::KeyValue{header.first, header.second}); + } +} + +// Convert what we receive from Rust into C++ data, call functions and convert results back to Rust data +static void rustWrapper(const std::function& func, const pdns::rust::web::rec::Request& rustRequest, pdns::rust::web::rec::Response& rustResponse) +{ + HttpRequest request; + HttpResponse response; + request.body = std::string(reinterpret_cast(rustRequest.body.data()), rustRequest.body.size()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + request.url = std::string(rustRequest.uri); + for (const auto& [key, value] : rustRequest.vars) { + request.getvars[std::string(key)] = std::string(value); + } + for (const auto& [key, value] : rustRequest.parameters) { + request.parameters[std::string(key)] = std::string(value); + } + // These two log objects are not used by the Rust code, as they take the logging object from the + // context, initialized from an argument to pdns::rust::web::rec::serveweb() + request.d_slog = g_slog; + response.d_slog = g_slog; + try { + func(&request, &response); + } + catch (HttpException& e) { + response.body = e.response().body; + response.status = e.response().status; + } + catch (const ApiException& e) { + response.setErrorResult(e.what(), 422); + } + catch (const JsonException& e) { + response.setErrorResult(e.what(), 422); + } + fromCxxToRust(response, rustResponse); +} + +namespace pdns::rust::web::rec +{ + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define WRAPPER(A) \ + void A(const Request& rustRequest, Response& rustResponse) { rustWrapper(::A, rustRequest, rustResponse); } + +WRAPPER(jsonstat) +WRAPPER(apiDiscovery) +WRAPPER(apiDiscoveryV1) +WRAPPER(apiServer) +WRAPPER(apiServerCacheFlush) +WRAPPER(apiServerConfig) +WRAPPER(apiServerConfigAllowFromGET) +WRAPPER(apiServerConfigAllowFromPUT) +WRAPPER(apiServerConfigAllowNotifyFromGET) +WRAPPER(apiServerConfigAllowNotifyFromPUT) +WRAPPER(apiServerDetail) +WRAPPER(apiServerRPZStats) +WRAPPER(apiServerSearchData) +WRAPPER(apiServerStatistics) +WRAPPER(apiServerZoneDetailDELETE) +WRAPPER(apiServerZoneDetailGET) +WRAPPER(apiServerZoneDetailPUT) +WRAPPER(apiServerZonesGET) +WRAPPER(apiServerZonesPOST) +WRAPPER(apiServerOTConditionsGET) +WRAPPER(apiServerOTConditionDetailGET) +WRAPPER(apiServerOTConditionDetailDELETE) +WRAPPER(apiServerOTConditionDetailPOST) +WRAPPER(prometheusMetrics) +WRAPPER(serveStuff) + +} diff -Nru pdns-recursor-5.2.13/ws-recursor.hh pdns-recursor-5.4.9/ws-recursor.hh --- pdns-recursor-5.2.13/ws-recursor.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/ws-recursor.hh 2026-10-26 08:26:51.000000000 +0000 @@ -20,13 +20,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once -#include -#include "namespaces.hh" -#include "mplexer.hh" + #include "webserver.hh" class HttpRequest; class HttpResponse; +extern void serveRustWeb(); + +#ifndef RUST_WS + +#include +#include "namespaces.hh" +#include "mplexer.hh" class AsyncServer : public Server { @@ -52,7 +57,7 @@ { public: AsyncWebServer(FDMultiplexer* fdm, const string& listenaddress, int port) : - WebServer(listenaddress, port), d_fdm(fdm){}; + WebServer(listenaddress, port), d_fdm(fdm) {}; void go(); private: @@ -75,3 +80,4 @@ private: std::unique_ptr d_ws{nullptr}; }; +#endif diff -Nru pdns-recursor-5.2.13/zonemd.cc pdns-recursor-5.4.9/zonemd.cc --- pdns-recursor-5.2.13/zonemd.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/zonemd.cc 2026-10-26 09:46:36.000000000 +0000 @@ -17,11 +17,11 @@ } catch (const PDNSException& pe) { std::string err = "Bad record content in record for '" + dnsResourceRecord.qname.toStringNoDot() + "'|" + dnsResourceRecord.qtype.toString() + ": " + pe.reason; - throw PDNSException(err); + throw PDNSException(std::move(err)); } catch (const std::exception& e) { std::string err = "Bad record content in record for '" + dnsResourceRecord.qname.toStringNoDot() + "|" + dnsResourceRecord.qtype.toString() + "': " + e.what(); - throw PDNSException(err); + throw PDNSException(std::move(err)); } DNSRecord rec; rec.d_name = dnsResourceRecord.qname; @@ -43,7 +43,7 @@ void pdns::ZoneMD::processRecord(const DNSRecord& record) { - if (record.d_class == QClass::IN && record.d_name == d_zone) { + if (record.d_class == QClass::IN && record.d_name == DNSName(d_zone)) { switch (record.d_type) { case QType::SOA: { d_soaRecordContent = getRR(record); @@ -104,8 +104,8 @@ return; } d_nsec3params.emplace_back(param); - d_nsec3label = d_zone; - d_nsec3label.prependRawLabel(toBase32Hex(hashQNameWithSalt(param->d_salt, param->d_iterations, d_zone))); + d_nsec3label = DNSName(d_zone); + d_nsec3label.prependRawLabel(toBase32Hex(hashQNameWithSalt(param->d_salt, param->d_iterations, DNSName(d_zone)))); // Zap the NSEC3 at labels that we now know are not relevant for (auto item = d_nsec3s.begin(); item != d_nsec3s.end();) { if (item->first != d_nsec3label) { @@ -126,7 +126,7 @@ void pdns::ZoneMD::readRecord(const DNSRecord& record) { - if (!record.d_name.isPartOf(d_zone) && record.d_name != d_zone) { + if (!record.d_name.isPartOf(d_zone)) { return; } if (record.d_class == QClass::IN && record.d_type == QType::SOA && d_soaRecordContent) { @@ -224,7 +224,7 @@ for (auto& rrset : d_resourceRecordSets) { const auto& qname = rrset.first.first; const auto& qtype = rrset.first.second; - if (qtype == QType::ZONEMD && qname == d_zone) { + if (qtype == QType::ZONEMD && qname == DNSName(d_zone)) { continue; // the apex ZONEMD is not digested } @@ -235,7 +235,7 @@ if (rrsig == nullptr) { continue; } - if (rrsig->d_type == QType::ZONEMD && qname == d_zone) { + if (rrsig->d_type == QType::ZONEMD && qname == DNSName(d_zone)) { continue; } } diff -Nru pdns-recursor-5.2.13/zonemd.hh pdns-recursor-5.4.9/zonemd.hh --- pdns-recursor-5.2.13/zonemd.hh 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/zonemd.hh 2026-10-26 09:46:36.000000000 +0000 @@ -50,7 +50,7 @@ ValidationFailure }; - ZoneMD(DNSName zone) : + ZoneMD(ZoneName zone) : d_zone(std::move(zone)) {} void readRecords(ZoneParserTNG& zpt); @@ -116,12 +116,8 @@ { bool operator()(const RRSetKey_t& lhs, const RRSetKey_t& rhs) const { - // FIXME surely we can be smarter here - if (lhs.first.canonCompare(rhs.first)) { - return true; - } - if (rhs.first.canonCompare(lhs.first)) { - return false; + if (int rc = lhs.first.canonCompare_three_way(rhs.first); rc != 0) { + return rc < 0; } return lhs.second < rhs.second; } @@ -148,7 +144,7 @@ ContentSigPair d_nsecs; map d_nsec3s; DNSName d_nsec3label; - const DNSName d_zone; + const ZoneName d_zone; const ContentSigPair empty; }; diff -Nru pdns-recursor-5.2.13/zoneparser-tng.cc pdns-recursor-5.4.9/zoneparser-tng.cc --- pdns-recursor-5.2.13/zoneparser-tng.cc 2026-08-05 12:00:38.000000000 +0000 +++ pdns-recursor-5.4.9/zoneparser-tng.cc 2026-10-26 09:46:36.000000000 +0000 @@ -38,18 +38,18 @@ const static string g_INstr("IN"); -ZoneParserTNG::ZoneParserTNG(const string& fname, DNSName zname, string reldir, bool upgradeContent): +ZoneParserTNG::ZoneParserTNG(const string& fname, ZoneName zname, string reldir, bool upgradeContent): d_reldir(std::move(reldir)), d_zonename(std::move(zname)), d_defaultttl(3600), d_templatecounter(0), d_templatestop(0), d_templatestep(0), - d_havedollarttl(false), d_fromfile(true), d_upgradeContent(upgradeContent) + d_havespecificttl(false), d_fromfile(true), d_upgradeContent(upgradeContent) { stackFile(fname); } -ZoneParserTNG::ZoneParserTNG(const vector& zonedata, DNSName zname, bool upgradeContent): +ZoneParserTNG::ZoneParserTNG(const vector& zonedata, ZoneName zname, bool upgradeContent): d_zonename(std::move(zname)), d_zonedata(zonedata), d_defaultttl(3600), d_templatecounter(0), d_templatestop(0), d_templatestep(0), - d_havedollarttl(false), d_fromfile(false), d_upgradeContent(upgradeContent) + d_havespecificttl(false), d_fromfile(false), d_upgradeContent(upgradeContent) { d_zonedataline = d_zonedata.begin(); } @@ -90,6 +90,7 @@ filestate fs(fp, fname); d_filestates.push(fs); d_fromfile = true; + d_fileset.emplace_back(std::make_pair(fname, st.st_ctime)); } ZoneParserTNG::~ZoneParserTNG() @@ -314,7 +315,7 @@ return false; } -DNSName ZoneParserTNG::getZoneName() +ZoneName ZoneParserTNG::getZoneName() { return d_zonename; } @@ -338,6 +339,7 @@ return {d_filestates.top().d_filename, d_filestates.top().d_lineno}; } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment) { retry:; @@ -363,16 +365,21 @@ string command=makeString(d_line, d_parts[0]); if(pdns_iequals(command,"$TTL") && d_parts.size() > 1) { d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, d_parts[1]), boost::is_any_of(";"))); - d_havedollarttl=true; + d_havespecificttl=true; } else if(pdns_iequals(command,"$INCLUDE") && d_parts.size() > 1 && d_fromfile) { string fname=unquotify(makeString(d_line, d_parts[1])); - if(!fname.empty() && fname[0]!='/' && !d_reldir.empty()) - fname=d_reldir+"/"+fname; + // Find the first semicolon and remove everything after it, including the semicolon + if (auto semicolon_pos = fname.find(';'); semicolon_pos != string::npos) { + fname.resize(semicolon_pos); + } + if (!fname.empty() && fname[0] != '/' && !d_reldir.empty()) { + fname = d_reldir + "/" + fname; + } stackFile(fname); } else if(pdns_iequals(command, "$ORIGIN") && d_parts.size() > 1) { - d_zonename = DNSName(makeString(d_line, d_parts[1])); + d_zonename = ZoneName(makeString(d_line, d_parts[1])); } else if(pdns_iequals(command, "$GENERATE") && d_parts.size() > 2) { if (!d_generateEnabled) { @@ -481,9 +488,9 @@ goto retry; } if(qname=="@") - rr.qname=d_zonename; + rr.qname=DNSName(d_zonename); else if(!prevqname && !isCanonical(qname)) - rr.qname += d_zonename; + rr.qname += DNSName(d_zonename); d_prevqname=rr.qname; if(d_parts.empty()) @@ -515,8 +522,9 @@ } if(!haveTTL && !haveQTYPE && isTimeSpec(nextpart)) { rr.ttl=makeTTLFromZone(nextpart); - if(!d_havedollarttl) + if (!d_havespecificttl) { d_defaultttl = rr.ttl; + } haveTTL=true; // cout<<"ttl is probably: "<& zonedata, DNSName zname, bool upgradeContent=false); + ZoneParserTNG(const string& fname, ZoneName zname=g_rootzonename, string reldir="", bool upgradeContent=false); + ZoneParserTNG(const vector& zonedata, ZoneName zname, bool upgradeContent=false); ~ZoneParserTNG(); bool get(DNSResourceRecord& rr, std::string* comment=0); typedef runtime_error exception; typedef std::deque > parts_t; - DNSName getZoneName(); + ZoneName getZoneName(); string getLineOfFile(); // for error reporting purposes pair getLineNumAndFile(); // idem void disableGenerate() @@ -53,6 +53,12 @@ { d_maxIncludes = max; } + void setDefaultTTL(int ttl) + { + d_defaultttl = ttl; + d_havespecificttl = true; + } + std::vector> getFileset() const { return d_fileset; } private: bool getLine(); bool getTemplateLine(); @@ -60,17 +66,18 @@ unsigned makeTTLFromZone(const std::string& str); struct filestate { - filestate(FILE* fp, string filename) : d_fp(fp), d_filename(std::move(filename)), d_lineno(0){} + filestate(FILE* fp, string filename) : + d_fp(fp), d_filename(std::move(filename)) {} FILE *d_fp; string d_filename; - int d_lineno; + int d_lineno{0}; }; parts_t d_parts; string d_reldir; string d_line; DNSName d_prevqname; - DNSName d_zonename; + ZoneName d_zonename; string d_templateline; vector d_zonedata; vector::iterator d_zonedataline; @@ -80,9 +87,10 @@ size_t d_maxIncludes{20}; int d_defaultttl; uint32_t d_templatecounter, d_templatestop, d_templatestep; - bool d_havedollarttl; + bool d_havespecificttl; bool d_fromfile; bool d_generateEnabled{true}; bool d_upgradeContent; bool d_templateCounterWrapped{false}; + std::vector> d_fileset; };