summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
commitbc282425088455198a7a99511c75914477d4ed32 (patch)
tree1b1fb887a634136a093deea7e4dd95d054201e7a
parentReleasing progress-linux version 1.8.3-3~progress7.99u1. (diff)
downloaddnsdist-bc282425088455198a7a99511c75914477d4ed32.tar.xz
dnsdist-bc282425088455198a7a99511c75914477d4ed32.zip
Merging upstream version 1.9.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--DNSDIST-MIB.txt12
-rw-r--r--Makefile.am171
-rw-r--r--Makefile.in845
-rw-r--r--aclocal.m4396
-rw-r--r--base64.hh2
-rw-r--r--bpf-filter.cc91
-rw-r--r--cachecleaner.hh13
-rw-r--r--capabilities.cc2
-rw-r--r--channel.cc115
-rw-r--r--channel.hh356
-rwxr-xr-xcompile6
-rwxr-xr-xconfig.guess1486
-rw-r--r--config.h.in61
-rwxr-xr-xconfig.sub2601
-rwxr-xr-xconfigure12114
-rw-r--r--configure.ac71
-rw-r--r--coverage.cc50
-rw-r--r--coverage.hh27
-rw-r--r--credentials.cc19
-rw-r--r--credentials.hh2
-rw-r--r--delaypipe.cc58
-rw-r--r--delaypipe.hh7
-rwxr-xr-xdepcomp2
-rw-r--r--dns.cc8
-rw-r--r--dns.hh95
-rw-r--r--dns_random.hh93
-rw-r--r--dnscrypt.cc7
-rw-r--r--dnscrypt.hh2
-rw-r--r--dnsdist-async.cc154
-rw-r--r--dnsdist-async.hh18
-rw-r--r--dnsdist-backend.cc174
-rw-r--r--dnsdist-cache.cc20
-rw-r--r--dnsdist-cache.hh39
-rw-r--r--dnsdist-carbon.cc25
-rw-r--r--dnsdist-console.cc256
-rw-r--r--dnsdist-console.hh3
-rw-r--r--dnsdist-crypto.cc573
-rw-r--r--dnsdist-crypto.hh73
-rw-r--r--dnsdist-discovery.cc6
-rw-r--r--dnsdist-dnscrypt.cc3
-rw-r--r--dnsdist-dnsparser.cc28
-rw-r--r--dnsdist-dnsparser.hh6
-rw-r--r--dnsdist-doh-common.cc193
-rw-r--r--dnsdist-doh-common.hh248
-rw-r--r--dnsdist-dynblocks.cc511
-rw-r--r--dnsdist-dynblocks.hh221
-rw-r--r--dnsdist-dynbpf.cc2
-rw-r--r--dnsdist-ecs.cc114
-rw-r--r--dnsdist-ecs.hh1
-rw-r--r--dnsdist-edns.cc94
-rw-r--r--dnsdist-edns.hh34
-rw-r--r--dnsdist-healthchecks.cc216
-rw-r--r--dnsdist-healthchecks.hh5
-rw-r--r--dnsdist-idstate.hh40
-rw-r--r--dnsdist-internal-queries.cc19
-rw-r--r--dnsdist-kvs.cc20
-rw-r--r--dnsdist-lbpolicies.cc14
-rw-r--r--dnsdist-lbpolicies.hh4
-rw-r--r--dnsdist-lua-actions.cc2001
-rw-r--r--dnsdist-lua-bindings-dnscrypt.cc20
-rw-r--r--dnsdist-lua-bindings-dnsparser.cc2
-rw-r--r--dnsdist-lua-bindings-dnsquestion.cc78
-rw-r--r--dnsdist-lua-bindings-network.cc2
-rw-r--r--dnsdist-lua-bindings-packetcache.cc5
-rw-r--r--dnsdist-lua-bindings-rings.cc8
-rw-r--r--dnsdist-lua-bindings.cc206
-rw-r--r--dnsdist-lua-ffi-interface.h43
-rw-r--r--dnsdist-lua-ffi-interface.inc93
-rw-r--r--dnsdist-lua-ffi.cc420
-rw-r--r--dnsdist-lua-ffi.hh12
-rw-r--r--dnsdist-lua-hooks.cc37
-rw-r--r--dnsdist-lua-hooks.hh35
-rw-r--r--dnsdist-lua-inspection-ffi.cc7
-rw-r--r--dnsdist-lua-inspection-ffi.h42
-rw-r--r--dnsdist-lua-inspection.cc158
-rw-r--r--dnsdist-lua-network.cc69
-rw-r--r--dnsdist-lua-network.hh26
-rw-r--r--dnsdist-lua-rules.cc216
-rw-r--r--dnsdist-lua-vars.cc1
-rw-r--r--dnsdist-lua.cc1081
-rw-r--r--dnsdist-lua.hh20
-rw-r--r--dnsdist-metrics.cc180
-rw-r--r--dnsdist-metrics.hh63
-rw-r--r--dnsdist-nghttp2-in.cc1187
-rw-r--r--dnsdist-nghttp2-in.hh159
-rw-r--r--dnsdist-nghttp2.cc386
-rw-r--r--dnsdist-prometheus.hh17
-rw-r--r--dnsdist-protobuf.cc213
-rw-r--r--dnsdist-protobuf.hh64
-rw-r--r--dnsdist-protocols.cc13
-rw-r--r--dnsdist-protocols.hh7
-rw-r--r--dnsdist-proxy-protocol.cc9
-rw-r--r--dnsdist-resolver.cc52
-rw-r--r--dnsdist-resolver.hh28
-rw-r--r--dnsdist-rings.cc9
-rw-r--r--dnsdist-rings.hh6
-rw-r--r--dnsdist-rules.hh72
-rw-r--r--dnsdist-secpoll.cc13
-rw-r--r--dnsdist-snmp.cc93
-rw-r--r--dnsdist-tcp-downstream.cc78
-rw-r--r--dnsdist-tcp-downstream.hh2
-rw-r--r--dnsdist-tcp-upstream.hh74
-rw-r--r--dnsdist-tcp.cc1383
-rw-r--r--dnsdist-tcp.hh60
-rw-r--r--dnsdist-web.cc229
-rw-r--r--dnsdist-web.hh5
-rw-r--r--dnsdist-xpf.cc7
-rw-r--r--dnsdist-xsk.cc260
-rw-r--r--dnsdist-xsk.hh46
-rw-r--r--dnsdist.16
-rw-r--r--dnsdist.cc1783
-rw-r--r--dnsdist.conf-dist4
-rw-r--r--dnsdist.hh288
-rw-r--r--dnslabeltext.cc38
-rw-r--r--dnsmessage.proto7
-rw-r--r--dnsname.cc267
-rw-r--r--dnsname.hh13
-rw-r--r--dnsparser.cc67
-rw-r--r--dnsparser.hh8
-rw-r--r--dnstap.cc71
-rw-r--r--dnstap.hh34
-rw-r--r--dnswriter.hh2
-rw-r--r--doh.cc1174
-rw-r--r--doh.hh271
-rw-r--r--doh3.cc1031
-rw-r--r--doh3.hh119
-rw-r--r--dolog.cc96
-rw-r--r--dolog.hh268
-rw-r--r--doq-common.cc263
-rw-r--r--doq-common.hh102
-rw-r--r--doq.cc822
-rw-r--r--doq.hh119
-rw-r--r--ednscookies.cc4
-rw-r--r--ednscookies.hh2
-rw-r--r--ednsextendederror.cc65
-rw-r--r--ednsextendederror.hh66
-rw-r--r--ednssubnet.cc82
-rw-r--r--ednssubnet.hh4
-rw-r--r--epollmplexer.cc2
-rw-r--r--ext/arc4random/Makefile.am11
-rw-r--r--ext/arc4random/Makefile.in750
-rw-r--r--ext/arc4random/arc4random.c256
-rw-r--r--ext/arc4random/arc4random.h89
-rw-r--r--ext/arc4random/arc4random.hh21
-rw-r--r--ext/arc4random/arc4random_uniform.c64
-rw-r--r--ext/arc4random/bsd-getentropy.c83
-rw-r--r--ext/arc4random/chacha_private.h224
-rw-r--r--ext/arc4random/explicit_bzero.c65
-rw-r--r--ext/arc4random/includes.h29
-rw-r--r--ext/arc4random/log.h1
-rw-r--r--ext/ipcrypt/Makefile.in28
-rw-r--r--ext/libbpf/libbpf.h13
-rw-r--r--ext/lmdb-safe/lmdb-safe.cc7
-rw-r--r--ext/lmdb-safe/lmdb-safe.hh5
-rw-r--r--ext/luawrapper/include/LuaContext.hpp3
-rw-r--r--ext/yahttp/Makefile.in30
-rw-r--r--ext/yahttp/yahttp/Makefile.in28
-rw-r--r--ext/yahttp/yahttp/cookie.hpp2
-rw-r--r--ext/yahttp/yahttp/reqresp.cpp2
-rw-r--r--ext/yahttp/yahttp/router.cpp134
-rw-r--r--ext/yahttp/yahttp/router.hpp31
-rw-r--r--ext/yahttp/yahttp/utility.hpp2
-rw-r--r--fuzz_dnsdistcache.cc61
-rw-r--r--fuzz_xsk.cc58
-rw-r--r--gettime.cc3
-rw-r--r--html/index.html2
-rw-r--r--html/local.js9
-rw-r--r--htmlfiles.h927
-rwxr-xr-xinstall-sh161
-rw-r--r--iputils.cc96
-rw-r--r--iputils.hh72
-rw-r--r--libssl.cc95
-rw-r--r--libssl.hh10
-rw-r--r--lock.hh18
-rw-r--r--logging.hh21
-rw-r--r--ltmain.sh855
-rw-r--r--m4/boost.m43
-rw-r--r--m4/dnsdist_enable_doh.m42
-rw-r--r--m4/dnsdist_enable_doh3.m414
-rw-r--r--m4/dnsdist_enable_doq.m414
-rw-r--r--m4/libtool.m4227
-rw-r--r--m4/ltoptions.m44
-rw-r--r--m4/ltsugar.m42
-rw-r--r--m4/ltversion.m413
-rw-r--r--m4/lt~obsolete.m44
-rw-r--r--m4/pdns_check_libh2o_evloop.m443
-rw-r--r--m4/pdns_check_secure_memset.m42
-rw-r--r--m4/pdns_enable_coverage.m432
-rw-r--r--m4/pdns_enable_fuzz_targets.m411
-rw-r--r--m4/pdns_with_net_snmp.m44
-rw-r--r--m4/pdns_with_nghttp2.m47
-rw-r--r--m4/pdns_with_quiche.m425
-rw-r--r--m4/pdns_with_xsk.m438
-rw-r--r--misc.cc169
-rw-r--r--misc.hh69
-rwxr-xr-xmissing2
-rw-r--r--mplexer.hh13
-rw-r--r--pollmplexer.cc3
-rw-r--r--protozero.cc2
-rw-r--r--protozero.hh10
-rw-r--r--proxy-protocol.hh2
-rw-r--r--remote_logger.cc2
-rw-r--r--snmp-agent.cc58
-rw-r--r--snmp-agent.hh14
-rw-r--r--sodcrypto.cc354
-rw-r--r--sodcrypto.hh78
-rw-r--r--sstuff.hh64
-rw-r--r--standalone_fuzz_target_runner.cc52
-rw-r--r--stat_t.hh2
-rw-r--r--statnode.cc8
-rw-r--r--statnode.hh11
-rw-r--r--tcpiohandler-mplexer.hh8
-rw-r--r--tcpiohandler.cc177
-rw-r--r--tcpiohandler.hh38
-rw-r--r--test-base64_cc.cc3
-rw-r--r--test-channel.cc157
-rw-r--r--test-connectionmanagement_hh.cc4
-rw-r--r--test-credentials_cc.cc3
-rw-r--r--test-delaypipe_hh.cc13
-rw-r--r--test-dnscrypt_cc.cc6
-rw-r--r--test-dnsdist-connections-cache.cc3
-rw-r--r--test-dnsdist-dnsparser.cc5
-rw-r--r--test-dnsdist-lua-ffi.cc76
-rw-r--r--test-dnsdist_cc.cc20
-rw-r--r--test-dnsdistasync.cc38
-rw-r--r--test-dnsdistbackend_cc.cc11
-rw-r--r--test-dnsdistdynblocks_hh.cc355
-rw-r--r--test-dnsdistedns.cc202
-rw-r--r--test-dnsdistkvs_cc.cc3
-rw-r--r--test-dnsdistlbpolicies_cc.cc347
-rw-r--r--test-dnsdistluanetwork.cc3
-rw-r--r--test-dnsdistnghttp2-in_cc.cc773
-rw-r--r--test-dnsdistnghttp2_cc.cc184
-rw-r--r--test-dnsdistnghttp2_common.hh155
-rw-r--r--test-dnsdistpacketcache_cc.cc298
-rw-r--r--test-dnsdistrings_cc.cc3
-rw-r--r--test-dnsdistrules_cc.cc74
-rw-r--r--test-dnsdistsvc_cc.cc3
-rw-r--r--test-dnsdisttcp_cc.cc171
-rw-r--r--test-dnsparser_cc.cc5
-rwxr-xr-xtest-driver19
-rw-r--r--test-iputils_hh.cc22
-rw-r--r--test-luawrapper.cc4
-rw-r--r--test-mplexer.cc12
-rw-r--r--test-proxy_protocol_cc.cc4
-rw-r--r--testrunner.cc3
-rw-r--r--views.hh55
-rw-r--r--xsk.cc1262
-rw-r--r--xsk.hh340
249 files changed, 33450 insertions, 15234 deletions
diff --git a/DNSDIST-MIB.txt b/DNSDIST-MIB.txt
index d6f5a92..bedf9bc 100644
--- a/DNSDIST-MIB.txt
+++ b/DNSDIST-MIB.txt
@@ -139,7 +139,7 @@ latency01 OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in less than 1 ms"
+ "Number of UDP queries answered in less than 1 ms"
::= { stats 14 }
latency110 OBJECT-TYPE
@@ -147,7 +147,7 @@ latency110 OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in 1-10 ms"
+ "Number of UDP queries answered in 1-10 ms"
::= { stats 15 }
latency1050 OBJECT-TYPE
@@ -155,7 +155,7 @@ latency1050 OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in 10-50 ms"
+ "Number of UDP queries answered in 10-50 ms"
::= { stats 16 }
latency50100 OBJECT-TYPE
@@ -163,7 +163,7 @@ latency50100 OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in 50-100 ms"
+ "Number of UDP queries answered in 50-100 ms"
::= { stats 17 }
latency1001000 OBJECT-TYPE
@@ -171,7 +171,7 @@ latency1001000 OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in 100-1000 ms"
+ "Number of UDP queries answered in 100-1000 ms"
::= { stats 18 }
latencySlow OBJECT-TYPE
@@ -179,7 +179,7 @@ latencySlow OBJECT-TYPE
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Number of queries answered in more than 1s"
+ "Number of UDP queries answered in more than 1s"
::= { stats 19 }
latencyAVG100 OBJECT-TYPE
diff --git a/Makefile.am b/Makefile.am
index f81f8bf..faaeefd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,8 @@ AM_CPPFLAGS += $(SYSTEMD_CFLAGS) \
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS=ext/ipcrypt \
+SUBDIRS=ext/arc4random \
+ ext/ipcrypt \
ext/yahttp
CLEANFILES = \
@@ -79,6 +80,10 @@ if HAVE_LIBSSL
AM_CPPFLAGS += $(LIBSSL_CFLAGS)
endif
+if HAVE_GNUTLS
+AM_CPPFLAGS += $(GNUTLS_CFLAGS)
+endif
+
if HAVE_LIBH2OEVLOOP
AM_CPPFLAGS += $(LIBH2OEVLOOP_CFLAGS)
endif
@@ -105,6 +110,7 @@ EXTRA_DIST=COPYING \
kqueuemplexer.cc \
portsmplexer.cc \
cdb.cc cdb.hh \
+ standalone_fuzz_target_runner.cc \
ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh \
ext/protozero/include/* \
builder-support/gen-version
@@ -113,7 +119,7 @@ bin_PROGRAMS = dnsdist
if UNIT_TESTS
noinst_PROGRAMS = testrunner
-TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)'
+TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message BOOST_TEST_RANDOM=1 SRCDIR='$(srcdir)'
TESTS=testrunner
else
check-local:
@@ -130,8 +136,10 @@ dnsdist_SOURCES = \
burtle.hh \
cachecleaner.hh \
capabilities.cc capabilities.hh \
+ channel.cc channel.hh \
circular_buffer.hh \
connection-management.hh \
+ coverage.cc coverage.hh \
credentials.cc credentials.hh \
dns.cc dns.hh \
dns_random.hh \
@@ -143,13 +151,16 @@ dnsdist_SOURCES = \
dnsdist-carbon.cc dnsdist-carbon.hh \
dnsdist-concurrent-connections.hh \
dnsdist-console.cc dnsdist-console.hh \
+ dnsdist-crypto.cc dnsdist-crypto.hh \
dnsdist-discovery.cc dnsdist-discovery.hh \
dnsdist-dnscrypt.cc \
dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
+ dnsdist-edns.cc dnsdist-edns.hh \
dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
dnsdist-idstate.hh \
dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
@@ -167,6 +178,7 @@ dnsdist_SOURCES = \
dnsdist-lua-bindings.cc \
dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \
+ dnsdist-lua-hooks.cc dnsdist-lua-hooks.hh \
dnsdist-lua-inspection-ffi.cc dnsdist-lua-inspection-ffi.h \
dnsdist-lua-inspection.cc \
dnsdist-lua-network.cc dnsdist-lua-network.hh \
@@ -176,12 +188,14 @@ dnsdist_SOURCES = \
dnsdist-lua.cc dnsdist-lua.hh \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
+ dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh \
dnsdist-prometheus.hh \
dnsdist-protobuf.cc dnsdist-protobuf.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
dnsdist-random.cc dnsdist-random.hh \
+ dnsdist-resolver.cc dnsdist-resolver.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dnsdist-rules.cc dnsdist-rules.hh \
dnsdist-secpoll.cc dnsdist-secpoll.hh \
@@ -194,15 +208,20 @@ dnsdist_SOURCES = \
dnsdist-tcp.cc dnsdist-tcp.hh \
dnsdist-web.cc dnsdist-web.hh \
dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.cc dnsdist.hh \
dnslabeltext.cc \
dnsname.cc dnsname.hh \
dnsparser.hh dnsparser.cc \
dnstap.cc dnstap.hh \
dnswriter.cc dnswriter.hh \
- doh.hh doh.cc \
- dolog.hh \
+ doh.hh \
+ doh3.hh \
+ dolog.cc dolog.hh \
+ doq-common.hh \
+ doq.hh \
ednscookies.cc ednscookies.hh \
+ ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
ext/json11/json11.cpp \
@@ -229,7 +248,6 @@ dnsdist_SOURCES = \
remote_logger.cc remote_logger.hh \
sholder.hh \
snmp-agent.cc snmp-agent.hh \
- sodcrypto.cc sodcrypto.hh \
sstuff.hh \
stat_t.hh \
statnode.cc statnode.hh \
@@ -238,12 +256,15 @@ dnsdist_SOURCES = \
tcpiohandler.cc tcpiohandler.hh \
threadname.hh threadname.cc \
uuid-utils.hh uuid-utils.cc \
- xpf.cc xpf.hh
+ views.hh \
+ xpf.cc xpf.hh \
+ xsk.cc xsk.hh
testrunner_SOURCES = \
base64.hh \
bpf-filter.cc bpf-filter.hh \
cachecleaner.hh \
+ channel.cc channel.hh \
circular_buffer.hh \
connection-management.hh \
credentials.cc credentials.hh \
@@ -254,11 +275,14 @@ testrunner_SOURCES = \
dnsdist-backoff.hh \
dnsdist-cache.cc dnsdist-cache.hh \
dnsdist-concurrent-connections.hh \
+ dnsdist-crypto.cc dnsdist-crypto.hh \
dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh \
dnsdist-dynblocks.cc dnsdist-dynblocks.hh \
dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
+ dnsdist-edns.cc dnsdist-edns.hh \
dnsdist-idstate.hh \
dnsdist-kvs.cc dnsdist-kvs.hh \
dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
@@ -271,10 +295,12 @@ testrunner_SOURCES = \
dnsdist-lua-vars.cc \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
+ dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
dnsdist-random.cc dnsdist-random.hh \
+ dnsdist-resolver.cc dnsdist-resolver.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dnsdist-rules.cc dnsdist-rules.hh \
dnsdist-session-cache.cc dnsdist-session-cache.hh \
@@ -282,13 +308,15 @@ testrunner_SOURCES = \
dnsdist-tcp-downstream.cc \
dnsdist-tcp.cc dnsdist-tcp.hh \
dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.hh \
dnslabeltext.cc \
dnsname.cc dnsname.hh \
dnsparser.hh dnsparser.cc \
dnswriter.cc dnswriter.hh \
- dolog.hh \
+ dolog.cc dolog.hh \
ednscookies.cc ednscookies.hh \
+ ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
ext/luawrapper/include/LuaContext.hpp \
@@ -302,12 +330,12 @@ testrunner_SOURCES = \
proxy-protocol.cc proxy-protocol.hh \
qtype.cc qtype.hh \
sholder.hh \
- sodcrypto.cc \
sstuff.hh \
stat_t.hh \
statnode.cc statnode.hh \
svc-records.cc svc-records.hh \
test-base64_cc.cc \
+ test-channel.cc \
test-connectionmanagement_hh.cc \
test-credentials_cc.cc \
test-delaypipe_hh.cc \
@@ -320,10 +348,11 @@ testrunner_SOURCES = \
test-dnsdistbackend_cc.cc \
test-dnsdistbackoff.cc \
test-dnsdistdynblocks_hh.cc \
+ test-dnsdistedns.cc \
test-dnsdistkvs_cc.cc \
test-dnsdistlbpolicies_cc.cc \
test-dnsdistluanetwork.cc \
- test-dnsdistnghttp2_cc.cc \
+ test-dnsdistnghttp2_common.hh \
test-dnsdistpacketcache_cc.cc \
test-dnsdistrings_cc.cc \
test-dnsdistrules_cc.cc \
@@ -337,7 +366,8 @@ testrunner_SOURCES = \
testrunner.cc \
threadname.hh threadname.cc \
uuid-utils.hh uuid-utils.cc \
- xpf.cc xpf.hh
+ xpf.cc xpf.hh \
+ xsk.cc xsk.hh
dnsdist_LDFLAGS = \
$(AM_LDFLAGS) \
@@ -354,7 +384,8 @@ dnsdist_LDADD = \
$(SYSTEMD_LIBS) \
$(NET_SNMP_LIBS) \
$(LIBCAP_LIBS) \
- $(IPCRYPT_LIBS)
+ $(IPCRYPT_LIBS) \
+ $(ARC4RANDOM_LIBS)
testrunner_LDFLAGS = \
$(AM_LDFLAGS) \
@@ -368,7 +399,8 @@ testrunner_LDADD = \
$(LIBSODIUM_LIBS) \
$(LUA_LIBS) \
$(RT_LIBS) \
- $(LIBCAP_LIBS)
+ $(LIBCAP_LIBS) \
+ $(ARC4RANDOM_LIBS)
if HAVE_CDB
dnsdist_LDADD += $(CDB_LDFLAGS) $(CDB_LIBS)
@@ -385,6 +417,13 @@ if HAVE_LIBSSL
dnsdist_LDADD += $(LIBSSL_LIBS)
endif
+if HAVE_XSK
+dnsdist_LDADD += -lbpf
+dnsdist_LDADD += -lxdp
+testrunner_LDADD += -lbpf
+testrunner_LDADD += -lxdp
+endif
+
if HAVE_LIBCRYPTO
dnsdist_LDADD += $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
testrunner_LDADD += $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
@@ -406,17 +445,42 @@ endif
if HAVE_DNS_OVER_HTTPS
-if HAVE_LIBH2OEVLOOP
-dnsdist_LDADD += $(LIBH2OEVLOOP_LIBS)
+if HAVE_GNUTLS
+dnsdist_LDADD += -lgnutls
endif
+if HAVE_LIBH2OEVLOOP
+dnsdist_SOURCES += doh.cc
+dnsdist_LDADD += $(LIBH2OEVLOOP_LIBS)
endif
if HAVE_NGHTTP2
+dnsdist_SOURCES += dnsdist-nghttp2-in.cc
+dnsdist_SOURCES += dnsdist-nghttp2.cc
+testrunner_SOURCES += dnsdist-nghttp2-in.cc
+testrunner_SOURCES += dnsdist-nghttp2.cc
+testrunner_SOURCES += test-dnsdistnghttp2-in_cc.cc \
+ test-dnsdistnghttp2_cc.cc
dnsdist_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
testrunner_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
endif
+endif
+
+if HAVE_DNS_OVER_QUIC
+dnsdist_SOURCES += doq.cc
+endif
+
+if HAVE_DNS_OVER_HTTP3
+dnsdist_SOURCES += doh3.cc
+endif
+
+if HAVE_QUICHE
+AM_CPPFLAGS += $(QUICHE_CFLAGS)
+dnsdist_LDADD += $(QUICHE_LDFLAGS) $(QUICHE_LIBS)
+dnsdist_SOURCES += doq-common.cc
+endif
+
if !HAVE_LUA_HPP
BUILT_SOURCES += lua.hpp
nodist_dnsdist_SOURCES = lua.hpp
@@ -448,6 +512,81 @@ testrunner_SOURCES += \
portsmplexer.cc
endif
+if FUZZ_TARGETS
+
+LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
+
+standalone_fuzz_target_runner.o: standalone_fuzz_target_runner.cc
+
+fuzz_targets_programs = \
+ fuzz_target_dnsdistcache
+
+if HAVE_XSK
+fuzz_targets_programs += \
+ fuzz_target_xsk
+endif
+
+fuzz_targets: $(ARC4RANDOM_LIBS) $(fuzz_targets_programs)
+
+bin_PROGRAMS += \
+ $(fuzz_targets_programs)
+
+fuzz_targets_libs = \
+ $(LIBCRYPTO_LIBS) \
+ $(ARC4RANDOM_LIBS) \
+ $(LIB_FUZZING_ENGINE)
+
+fuzz_targets_ldflags = \
+ $(AM_LDFLAGS) \
+ $(DYNLINKFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(FUZZING_LDFLAGS)
+
+# we need the mockup runner to be built, but not linked if a real fuzzing engine is used
+fuzz_targets_deps = standalone_fuzz_target_runner.o
+
+fuzz_target_dnsdistcache_SOURCES = \
+ channel.hh channel.cc \
+ dns.cc dns.hh \
+ dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-ecs.cc dnsdist-ecs.hh \
+ dnsdist-idstate.hh \
+ dnsdist-protocols.cc dnsdist-protocols.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnswriter.cc dnswriter.hh \
+ doh.hh \
+ ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh \
+ fuzz_dnsdistcache.cc \
+ iputils.cc iputils.hh \
+ misc.cc misc.hh \
+ packetcache.hh \
+ qtype.cc qtype.hh \
+ svc-records.cc svc-records.hh
+
+fuzz_target_dnsdistcache_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_target_dnsdistcache_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_target_dnsdistcache_LDADD = $(fuzz_targets_libs)
+
+if HAVE_XSK
+fuzz_target_xsk_SOURCES = \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ fuzz_xsk.cc \
+ gettime.cc gettime.hh \
+ iputils.cc iputils.hh \
+ misc.cc misc.hh \
+ xsk.cc xsk.hh
+fuzz_target_xsk_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_target_xsk_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_target_xsk_LDADD = $(fuzz_targets_libs) -lbpf -lxdp
+endif # HAVE_XSK
+
+endif # FUZZ_TARGETS
+
MANPAGES=dnsdist.1
dist_man_MANS=$(MANPAGES)
diff --git a/Makefile.in b/Makefile.in
index ef43a30..b21b7d0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# 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,
@@ -98,43 +98,65 @@ host_triplet = @host@
@HAVE_CDB_TRUE@am__append_5 = $(CDB_CFLAGS)
@HAVE_LMDB_TRUE@am__append_6 = $(LMDB_CFLAGS)
@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBSSL_TRUE@am__append_7 = $(LIBSSL_CFLAGS)
-@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__append_8 = $(LIBH2OEVLOOP_CFLAGS)
-bin_PROGRAMS = dnsdist$(EXEEXT)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_GNUTLS_TRUE@am__append_8 = $(GNUTLS_CFLAGS)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__append_9 = $(LIBH2OEVLOOP_CFLAGS)
+bin_PROGRAMS = dnsdist$(EXEEXT) $(am__EXEEXT_3)
@UNIT_TESTS_TRUE@noinst_PROGRAMS = testrunner$(EXEEXT)
@UNIT_TESTS_TRUE@TESTS = testrunner$(EXEEXT)
-@HAVE_CDB_TRUE@am__append_9 = $(CDB_LDFLAGS) $(CDB_LIBS)
@HAVE_CDB_TRUE@am__append_10 = $(CDB_LDFLAGS) $(CDB_LIBS)
-@HAVE_CDB_TRUE@am__append_11 = cdb.cc cdb.hh
+@HAVE_CDB_TRUE@am__append_11 = $(CDB_LDFLAGS) $(CDB_LIBS)
@HAVE_CDB_TRUE@am__append_12 = cdb.cc cdb.hh
-@HAVE_RE2_TRUE@am__append_13 = $(RE2_LIBS)
-@HAVE_LIBSSL_TRUE@am__append_14 = $(LIBSSL_LIBS)
-@HAVE_LIBCRYPTO_TRUE@am__append_15 = $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
-@HAVE_LIBCRYPTO_TRUE@am__append_16 = $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
-@HAVE_LIBCRYPTO_TRUE@am__append_17 = ipcipher.cc ipcipher.hh
-@HAVE_LMDB_TRUE@am__append_18 = $(LMDB_LDFLAGS) $(LMDB_LIBS)
-@HAVE_LMDB_TRUE@am__append_19 = $(LMDB_LDFLAGS) $(LMDB_LIBS)
-@HAVE_LMDB_TRUE@am__append_20 = ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh
-@HAVE_LMDB_TRUE@am__append_21 = ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh
-@HAVE_DNS_OVER_TLS_TRUE@@HAVE_GNUTLS_TRUE@am__append_22 = -lgnutls
-@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__append_23 = $(LIBH2OEVLOOP_LIBS)
-@HAVE_NGHTTP2_TRUE@am__append_24 = $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
-@HAVE_NGHTTP2_TRUE@am__append_25 = $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
-@HAVE_LUA_HPP_FALSE@am__append_26 = lua.hpp
-@HAVE_FREEBSD_TRUE@am__append_27 = kqueuemplexer.cc
-@HAVE_FREEBSD_TRUE@am__append_28 = kqueuemplexer.cc
-@HAVE_OPENBSD_TRUE@am__append_29 = kqueuemplexer.cc
-@HAVE_OPENBSD_TRUE@am__append_30 = kqueuemplexer.cc
-@HAVE_LINUX_TRUE@am__append_31 = epollmplexer.cc
-@HAVE_LINUX_TRUE@am__append_32 = epollmplexer.cc
-@HAVE_SOLARIS_TRUE@am__append_33 = \
+@HAVE_CDB_TRUE@am__append_13 = cdb.cc cdb.hh
+@HAVE_RE2_TRUE@am__append_14 = $(RE2_LIBS)
+@HAVE_LIBSSL_TRUE@am__append_15 = $(LIBSSL_LIBS)
+@HAVE_XSK_TRUE@am__append_16 = -lbpf -lxdp
+@HAVE_XSK_TRUE@am__append_17 = -lbpf -lxdp
+@HAVE_LIBCRYPTO_TRUE@am__append_18 = $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
+@HAVE_LIBCRYPTO_TRUE@am__append_19 = $(LIBCRYPTO_LDFLAGS) $(LIBCRYPTO_LIBS)
+@HAVE_LIBCRYPTO_TRUE@am__append_20 = ipcipher.cc ipcipher.hh
+@HAVE_LMDB_TRUE@am__append_21 = $(LMDB_LDFLAGS) $(LMDB_LIBS)
+@HAVE_LMDB_TRUE@am__append_22 = $(LMDB_LDFLAGS) $(LMDB_LIBS)
+@HAVE_LMDB_TRUE@am__append_23 = ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh
+@HAVE_LMDB_TRUE@am__append_24 = ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh
+@HAVE_DNS_OVER_TLS_TRUE@@HAVE_GNUTLS_TRUE@am__append_25 = -lgnutls
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_GNUTLS_TRUE@am__append_26 = -lgnutls
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__append_27 = doh.cc
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__append_28 = $(LIBH2OEVLOOP_LIBS)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__append_29 = dnsdist-nghttp2-in.cc \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ dnsdist-nghttp2.cc
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__append_30 = dnsdist-nghttp2-in.cc \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ dnsdist-nghttp2.cc \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ test-dnsdistnghttp2-in_cc.cc \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ test-dnsdistnghttp2_cc.cc
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__append_31 = $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__append_32 = $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS)
+@HAVE_DNS_OVER_QUIC_TRUE@am__append_33 = doq.cc
+@HAVE_DNS_OVER_HTTP3_TRUE@am__append_34 = doh3.cc
+@HAVE_QUICHE_TRUE@am__append_35 = $(QUICHE_CFLAGS)
+@HAVE_QUICHE_TRUE@am__append_36 = $(QUICHE_LDFLAGS) $(QUICHE_LIBS)
+@HAVE_QUICHE_TRUE@am__append_37 = doq-common.cc
+@HAVE_LUA_HPP_FALSE@am__append_38 = lua.hpp
+@HAVE_FREEBSD_TRUE@am__append_39 = kqueuemplexer.cc
+@HAVE_FREEBSD_TRUE@am__append_40 = kqueuemplexer.cc
+@HAVE_OPENBSD_TRUE@am__append_41 = kqueuemplexer.cc
+@HAVE_OPENBSD_TRUE@am__append_42 = kqueuemplexer.cc
+@HAVE_LINUX_TRUE@am__append_43 = epollmplexer.cc
+@HAVE_LINUX_TRUE@am__append_44 = epollmplexer.cc
+@HAVE_SOLARIS_TRUE@am__append_45 = \
@HAVE_SOLARIS_TRUE@ devpollmplexer.cc \
@HAVE_SOLARIS_TRUE@ portsmplexer.cc
-@HAVE_SOLARIS_TRUE@am__append_34 = \
+@HAVE_SOLARIS_TRUE@am__append_46 = \
@HAVE_SOLARIS_TRUE@ devpollmplexer.cc \
@HAVE_SOLARIS_TRUE@ portsmplexer.cc
-@HAVE_SYSTEMD_TRUE@am__append_35 = \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@am__append_47 = \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ fuzz_target_xsk
+
+@FUZZ_TARGETS_TRUE@am__append_48 = \
+@FUZZ_TARGETS_TRUE@ $(fuzz_targets_programs)
+
+@HAVE_SYSTEMD_TRUE@am__append_49 = \
@HAVE_SYSTEMD_TRUE@ dnsdist.service \
@HAVE_SYSTEMD_TRUE@ dnsdist@.service
@@ -147,6 +169,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \
$(top_srcdir)/m4/dnsdist_enable_dnscrypt.m4 \
$(top_srcdir)/m4/dnsdist_enable_doh.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh3.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doq.m4 \
$(top_srcdir)/m4/dnsdist_enable_tls_providers.m4 \
$(top_srcdir)/m4/dnsdist_with_cdb.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
@@ -166,6 +190,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_check_ragel.m4 \
$(top_srcdir)/m4/pdns_check_secure_memset.m4 \
$(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_fuzz_targets.m4 \
$(top_srcdir)/m4/pdns_enable_ipcipher.m4 \
$(top_srcdir)/m4/pdns_enable_lto.m4 \
$(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
@@ -183,10 +209,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_with_lua.m4 \
$(top_srcdir)/m4/pdns_with_net_snmp.m4 \
$(top_srcdir)/m4/pdns_with_nghttp2.m4 \
+ $(top_srcdir)/m4/pdns_with_quiche.m4 \
$(top_srcdir)/m4/pdns_with_re2.m4 \
$(top_srcdir)/m4/pdns_with_service_user.m4 \
- $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \
- $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/pdns_with_xsk.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 $(top_srcdir)/configure \
@@ -197,27 +224,35 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@am__EXEEXT_1 = \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ fuzz_target_xsk$(EXEEXT)
+@FUZZ_TARGETS_TRUE@am__EXEEXT_2 = fuzz_target_dnsdistcache$(EXEEXT) \
+@FUZZ_TARGETS_TRUE@ $(am__EXEEXT_1)
+@FUZZ_TARGETS_TRUE@am__EXEEXT_3 = $(am__EXEEXT_2)
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
"$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(systemdsystemunitdir)"
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am__dnsdist_SOURCES_DIST = base64.hh bpf-filter.cc bpf-filter.hh \
burtle.hh cachecleaner.hh capabilities.cc capabilities.hh \
- circular_buffer.hh connection-management.hh credentials.cc \
- credentials.hh dns.cc dns.hh dns_random.hh dnscrypt.cc \
- dnscrypt.hh dnsdist-async.cc dnsdist-async.hh \
+ channel.cc channel.hh circular_buffer.hh \
+ connection-management.hh coverage.cc coverage.hh \
+ credentials.cc credentials.hh dns.cc dns.hh dns_random.hh \
+ dnscrypt.cc dnscrypt.hh dnsdist-async.cc dnsdist-async.hh \
dnsdist-backend.cc dnsdist-backoff.hh dnsdist-cache.cc \
dnsdist-cache.hh dnsdist-carbon.cc dnsdist-carbon.hh \
dnsdist-concurrent-connections.hh dnsdist-console.cc \
- dnsdist-console.hh dnsdist-discovery.cc dnsdist-discovery.hh \
- dnsdist-dnscrypt.cc dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-console.hh dnsdist-crypto.cc dnsdist-crypto.hh \
+ dnsdist-discovery.cc dnsdist-discovery.hh dnsdist-dnscrypt.cc \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh dnsdist-dynblocks.cc \
dnsdist-dynblocks.hh dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
- dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-healthchecks.cc \
- dnsdist-healthchecks.hh dnsdist-idstate.hh \
- dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
- dnsdist-kvs.hh dnsdist-kvs.cc dnsdist-lbpolicies.cc \
- dnsdist-lbpolicies.hh dnsdist-lua-actions.cc \
- dnsdist-lua-bindings-dnscrypt.cc \
+ dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
+ dnsdist-idstate.hh dnsdist-internal-queries.cc \
+ dnsdist-internal-queries.hh dnsdist-kvs.hh dnsdist-kvs.cc \
+ dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+ dnsdist-lua-actions.cc dnsdist-lua-bindings-dnscrypt.cc \
dnsdist-lua-bindings-dnsparser.cc \
dnsdist-lua-bindings-dnsquestion.cc \
dnsdist-lua-bindings-kvs.cc dnsdist-lua-bindings-network.cc \
@@ -225,61 +260,75 @@ am__dnsdist_SOURCES_DIST = base64.hh bpf-filter.cc bpf-filter.hh \
dnsdist-lua-bindings-protobuf.cc dnsdist-lua-bindings-rings.cc \
dnsdist-lua-bindings.cc dnsdist-lua-ffi-interface.h \
dnsdist-lua-ffi-interface.inc dnsdist-lua-ffi.cc \
- dnsdist-lua-ffi.hh dnsdist-lua-inspection-ffi.cc \
- dnsdist-lua-inspection-ffi.h dnsdist-lua-inspection.cc \
- dnsdist-lua-network.cc dnsdist-lua-network.hh \
- dnsdist-lua-rules.cc dnsdist-lua-vars.cc dnsdist-lua-web.cc \
- dnsdist-lua.cc dnsdist-lua.hh dnsdist-mac-address.cc \
- dnsdist-mac-address.hh dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh dnsdist-prometheus.hh \
- dnsdist-protobuf.cc dnsdist-protobuf.hh dnsdist-protocols.cc \
- dnsdist-protocols.hh dnsdist-proxy-protocol.cc \
- dnsdist-proxy-protocol.hh dnsdist-random.cc dnsdist-random.hh \
- dnsdist-rings.cc dnsdist-rings.hh dnsdist-rules.cc \
- dnsdist-rules.hh dnsdist-secpoll.cc dnsdist-secpoll.hh \
- dnsdist-session-cache.cc dnsdist-session-cache.hh \
- dnsdist-snmp.cc dnsdist-snmp.hh dnsdist-svc.cc dnsdist-svc.hh \
- dnsdist-systemd.cc dnsdist-systemd.hh \
- dnsdist-tcp-downstream.cc dnsdist-tcp-downstream.hh \
- dnsdist-tcp-upstream.hh dnsdist-tcp.cc dnsdist-tcp.hh \
- dnsdist-web.cc dnsdist-web.hh dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-lua-ffi.hh dnsdist-lua-hooks.cc dnsdist-lua-hooks.hh \
+ dnsdist-lua-inspection-ffi.cc dnsdist-lua-inspection-ffi.h \
+ dnsdist-lua-inspection.cc dnsdist-lua-network.cc \
+ dnsdist-lua-network.hh dnsdist-lua-rules.cc \
+ dnsdist-lua-vars.cc dnsdist-lua-web.cc dnsdist-lua.cc \
+ dnsdist-lua.hh dnsdist-mac-address.cc dnsdist-mac-address.hh \
+ dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh dnsdist-prometheus.hh dnsdist-protobuf.cc \
+ dnsdist-protobuf.hh dnsdist-protocols.cc dnsdist-protocols.hh \
+ dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
+ dnsdist-random.cc dnsdist-random.hh dnsdist-resolver.cc \
+ dnsdist-resolver.hh dnsdist-rings.cc dnsdist-rings.hh \
+ dnsdist-rules.cc dnsdist-rules.hh dnsdist-secpoll.cc \
+ dnsdist-secpoll.hh dnsdist-session-cache.cc \
+ dnsdist-session-cache.hh dnsdist-snmp.cc dnsdist-snmp.hh \
+ dnsdist-svc.cc dnsdist-svc.hh dnsdist-systemd.cc \
+ dnsdist-systemd.hh dnsdist-tcp-downstream.cc \
+ dnsdist-tcp-downstream.hh dnsdist-tcp-upstream.hh \
+ dnsdist-tcp.cc dnsdist-tcp.hh dnsdist-web.cc dnsdist-web.hh \
+ dnsdist-xpf.cc dnsdist-xpf.hh dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.cc dnsdist.hh dnslabeltext.cc dnsname.cc dnsname.hh \
dnsparser.hh dnsparser.cc dnstap.cc dnstap.hh dnswriter.cc \
- dnswriter.hh doh.hh doh.cc dolog.hh ednscookies.cc \
- ednscookies.hh ednsoptions.cc ednsoptions.hh ednssubnet.cc \
- ednssubnet.hh ext/json11/json11.cpp ext/json11/json11.hpp \
- ext/libbpf/libbpf.h ext/luawrapper/include/LuaContext.hpp \
- fstrm_logger.cc fstrm_logger.hh gettime.cc gettime.hh \
- htmlfiles.h iputils.cc iputils.hh libssl.cc libssl.hh lock.hh \
- logging.hh misc.cc misc.hh mplexer.hh namespaces.hh \
- noinitvector.hh packetcache.hh pdnsexception.hh pollmplexer.cc \
- protozero.cc protozero.hh proxy-protocol.cc proxy-protocol.hh \
- qtype.cc qtype.hh remote_logger.cc remote_logger.hh sholder.hh \
- snmp-agent.cc snmp-agent.hh sodcrypto.cc sodcrypto.hh \
- sstuff.hh stat_t.hh statnode.cc statnode.hh svc-records.cc \
- svc-records.hh tcpiohandler-mplexer.hh tcpiohandler.cc \
- tcpiohandler.hh threadname.hh threadname.cc uuid-utils.hh \
- uuid-utils.cc xpf.cc xpf.hh cdb.cc cdb.hh ipcipher.cc \
+ dnswriter.hh doh.hh doh3.hh dolog.cc dolog.hh doq-common.hh \
+ doq.hh ednscookies.cc ednscookies.hh ednsextendederror.cc \
+ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh ext/json11/json11.cpp \
+ ext/json11/json11.hpp ext/libbpf/libbpf.h \
+ ext/luawrapper/include/LuaContext.hpp fstrm_logger.cc \
+ fstrm_logger.hh gettime.cc gettime.hh htmlfiles.h iputils.cc \
+ iputils.hh libssl.cc libssl.hh lock.hh logging.hh misc.cc \
+ misc.hh mplexer.hh namespaces.hh noinitvector.hh \
+ packetcache.hh pdnsexception.hh pollmplexer.cc protozero.cc \
+ protozero.hh proxy-protocol.cc proxy-protocol.hh qtype.cc \
+ qtype.hh remote_logger.cc remote_logger.hh sholder.hh \
+ snmp-agent.cc snmp-agent.hh sstuff.hh stat_t.hh statnode.cc \
+ statnode.hh svc-records.cc svc-records.hh \
+ tcpiohandler-mplexer.hh tcpiohandler.cc tcpiohandler.hh \
+ threadname.hh threadname.cc uuid-utils.hh uuid-utils.cc \
+ views.hh xpf.cc xpf.hh xsk.cc xsk.hh cdb.cc cdb.hh ipcipher.cc \
ipcipher.hh ext/lmdb-safe/lmdb-safe.cc \
- ext/lmdb-safe/lmdb-safe.hh kqueuemplexer.cc epollmplexer.cc \
- devpollmplexer.cc portsmplexer.cc
+ ext/lmdb-safe/lmdb-safe.hh doh.cc dnsdist-nghttp2-in.cc \
+ dnsdist-nghttp2.cc doq.cc doh3.cc doq-common.cc \
+ kqueuemplexer.cc epollmplexer.cc devpollmplexer.cc \
+ portsmplexer.cc
am__dirstamp = $(am__leading_dot)dirstamp
@HAVE_CDB_TRUE@am__objects_1 = cdb.$(OBJEXT)
@HAVE_LIBCRYPTO_TRUE@am__objects_2 = ipcipher.$(OBJEXT)
@HAVE_LMDB_TRUE@am__objects_3 = ext/lmdb-safe/lmdb-safe.$(OBJEXT)
-@HAVE_FREEBSD_TRUE@am__objects_4 = kqueuemplexer.$(OBJEXT)
-@HAVE_OPENBSD_TRUE@am__objects_5 = kqueuemplexer.$(OBJEXT)
-@HAVE_LINUX_TRUE@am__objects_6 = epollmplexer.$(OBJEXT)
-@HAVE_SOLARIS_TRUE@am__objects_7 = devpollmplexer.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__objects_4 = doh.$(OBJEXT)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__objects_5 = dnsdist-nghttp2-in.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ dnsdist-nghttp2.$(OBJEXT)
+@HAVE_DNS_OVER_QUIC_TRUE@am__objects_6 = doq.$(OBJEXT)
+@HAVE_DNS_OVER_HTTP3_TRUE@am__objects_7 = doh3.$(OBJEXT)
+@HAVE_QUICHE_TRUE@am__objects_8 = doq-common.$(OBJEXT)
+@HAVE_FREEBSD_TRUE@am__objects_9 = kqueuemplexer.$(OBJEXT)
+@HAVE_OPENBSD_TRUE@am__objects_10 = kqueuemplexer.$(OBJEXT)
+@HAVE_LINUX_TRUE@am__objects_11 = epollmplexer.$(OBJEXT)
+@HAVE_SOLARIS_TRUE@am__objects_12 = devpollmplexer.$(OBJEXT) \
@HAVE_SOLARIS_TRUE@ portsmplexer.$(OBJEXT)
am_dnsdist_OBJECTS = bpf-filter.$(OBJEXT) capabilities.$(OBJEXT) \
- credentials.$(OBJEXT) dns.$(OBJEXT) dnscrypt.$(OBJEXT) \
- dnsdist-async.$(OBJEXT) dnsdist-backend.$(OBJEXT) \
- dnsdist-cache.$(OBJEXT) dnsdist-carbon.$(OBJEXT) \
- dnsdist-console.$(OBJEXT) dnsdist-discovery.$(OBJEXT) \
+ channel.$(OBJEXT) coverage.$(OBJEXT) credentials.$(OBJEXT) \
+ dns.$(OBJEXT) dnscrypt.$(OBJEXT) dnsdist-async.$(OBJEXT) \
+ dnsdist-backend.$(OBJEXT) dnsdist-cache.$(OBJEXT) \
+ dnsdist-carbon.$(OBJEXT) dnsdist-console.$(OBJEXT) \
+ dnsdist-crypto.$(OBJEXT) dnsdist-discovery.$(OBJEXT) \
dnsdist-dnscrypt.$(OBJEXT) dnsdist-dnsparser.$(OBJEXT) \
- dnsdist-dynblocks.$(OBJEXT) dnsdist-dynbpf.$(OBJEXT) \
- dnsdist-ecs.$(OBJEXT) dnsdist-healthchecks.$(OBJEXT) \
+ dnsdist-doh-common.$(OBJEXT) dnsdist-dynblocks.$(OBJEXT) \
+ dnsdist-dynbpf.$(OBJEXT) dnsdist-ecs.$(OBJEXT) \
+ dnsdist-edns.$(OBJEXT) dnsdist-healthchecks.$(OBJEXT) \
dnsdist-internal-queries.$(OBJEXT) dnsdist-kvs.$(OBJEXT) \
dnsdist-lbpolicies.$(OBJEXT) dnsdist-lua-actions.$(OBJEXT) \
dnsdist-lua-bindings-dnscrypt.$(OBJEXT) \
@@ -291,32 +340,36 @@ am_dnsdist_OBJECTS = bpf-filter.$(OBJEXT) capabilities.$(OBJEXT) \
dnsdist-lua-bindings-protobuf.$(OBJEXT) \
dnsdist-lua-bindings-rings.$(OBJEXT) \
dnsdist-lua-bindings.$(OBJEXT) dnsdist-lua-ffi.$(OBJEXT) \
+ dnsdist-lua-hooks.$(OBJEXT) \
dnsdist-lua-inspection-ffi.$(OBJEXT) \
dnsdist-lua-inspection.$(OBJEXT) dnsdist-lua-network.$(OBJEXT) \
dnsdist-lua-rules.$(OBJEXT) dnsdist-lua-vars.$(OBJEXT) \
dnsdist-lua-web.$(OBJEXT) dnsdist-lua.$(OBJEXT) \
dnsdist-mac-address.$(OBJEXT) dnsdist-metrics.$(OBJEXT) \
- dnsdist-nghttp2.$(OBJEXT) dnsdist-protobuf.$(OBJEXT) \
- dnsdist-protocols.$(OBJEXT) dnsdist-proxy-protocol.$(OBJEXT) \
- dnsdist-random.$(OBJEXT) dnsdist-rings.$(OBJEXT) \
+ dnsdist-protobuf.$(OBJEXT) dnsdist-protocols.$(OBJEXT) \
+ dnsdist-proxy-protocol.$(OBJEXT) dnsdist-random.$(OBJEXT) \
+ dnsdist-resolver.$(OBJEXT) dnsdist-rings.$(OBJEXT) \
dnsdist-rules.$(OBJEXT) dnsdist-secpoll.$(OBJEXT) \
dnsdist-session-cache.$(OBJEXT) dnsdist-snmp.$(OBJEXT) \
dnsdist-svc.$(OBJEXT) dnsdist-systemd.$(OBJEXT) \
dnsdist-tcp-downstream.$(OBJEXT) dnsdist-tcp.$(OBJEXT) \
- dnsdist-web.$(OBJEXT) dnsdist-xpf.$(OBJEXT) dnsdist.$(OBJEXT) \
- dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
- dnstap.$(OBJEXT) dnswriter.$(OBJEXT) doh.$(OBJEXT) \
- ednscookies.$(OBJEXT) ednsoptions.$(OBJEXT) \
+ dnsdist-web.$(OBJEXT) dnsdist-xpf.$(OBJEXT) \
+ dnsdist-xsk.$(OBJEXT) dnsdist.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnsparser.$(OBJEXT) dnstap.$(OBJEXT) \
+ dnswriter.$(OBJEXT) dolog.$(OBJEXT) ednscookies.$(OBJEXT) \
+ ednsextendederror.$(OBJEXT) ednsoptions.$(OBJEXT) \
ednssubnet.$(OBJEXT) ext/json11/json11.$(OBJEXT) \
fstrm_logger.$(OBJEXT) gettime.$(OBJEXT) iputils.$(OBJEXT) \
libssl.$(OBJEXT) misc.$(OBJEXT) pollmplexer.$(OBJEXT) \
protozero.$(OBJEXT) proxy-protocol.$(OBJEXT) qtype.$(OBJEXT) \
remote_logger.$(OBJEXT) snmp-agent.$(OBJEXT) \
- sodcrypto.$(OBJEXT) statnode.$(OBJEXT) svc-records.$(OBJEXT) \
+ statnode.$(OBJEXT) svc-records.$(OBJEXT) \
tcpiohandler.$(OBJEXT) threadname.$(OBJEXT) \
- uuid-utils.$(OBJEXT) xpf.$(OBJEXT) $(am__objects_1) \
- $(am__objects_2) $(am__objects_3) $(am__objects_4) \
- $(am__objects_5) $(am__objects_6) $(am__objects_7)
+ uuid-utils.$(OBJEXT) xpf.$(OBJEXT) xsk.$(OBJEXT) \
+ $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+ $(am__objects_4) $(am__objects_5) $(am__objects_6) \
+ $(am__objects_7) $(am__objects_8) $(am__objects_9) \
+ $(am__objects_10) $(am__objects_11) $(am__objects_12)
nodist_dnsdist_OBJECTS =
dnsdist_OBJECTS = $(am_dnsdist_OBJECTS) $(nodist_dnsdist_OBJECTS)
am__DEPENDENCIES_1 =
@@ -327,16 +380,19 @@ am__DEPENDENCIES_1 =
@HAVE_LIBCRYPTO_TRUE@ $(am__DEPENDENCIES_1)
@HAVE_LMDB_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1)
@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_LIBH2OEVLOOP_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
-@HAVE_NGHTTP2_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@HAVE_QUICHE_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
dnsdist_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
- $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_5) \
$(am__DEPENDENCIES_6) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_7) \
+ $(am__DEPENDENCIES_8) $(am__DEPENDENCIES_9)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
@@ -344,80 +400,140 @@ am__v_lt_1 =
dnsdist_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(dnsdist_LDFLAGS) $(LDFLAGS) -o $@
+am__fuzz_target_dnsdistcache_SOURCES_DIST = channel.hh channel.cc \
+ dns.cc dns.hh dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-dnsparser.cc dnsdist-dnsparser.hh dnsdist-ecs.cc \
+ dnsdist-ecs.hh dnsdist-idstate.hh dnsdist-protocols.cc \
+ dnsdist-protocols.hh dnslabeltext.cc dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh dnswriter.cc dnswriter.hh doh.hh \
+ ednsoptions.cc ednsoptions.hh ednssubnet.cc ednssubnet.hh \
+ fuzz_dnsdistcache.cc iputils.cc iputils.hh misc.cc misc.hh \
+ packetcache.hh qtype.cc qtype.hh svc-records.cc svc-records.hh
+@FUZZ_TARGETS_TRUE@am_fuzz_target_dnsdistcache_OBJECTS = \
+@FUZZ_TARGETS_TRUE@ channel.$(OBJEXT) dns.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnsdist-cache.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnsdist-dnsparser.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnsdist-ecs.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnsdist-protocols.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ dnsparser.$(OBJEXT) dnswriter.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ ednsoptions.$(OBJEXT) ednssubnet.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ fuzz_dnsdistcache.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ iputils.$(OBJEXT) misc.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@ qtype.$(OBJEXT) svc-records.$(OBJEXT)
+fuzz_target_dnsdistcache_OBJECTS = \
+ $(am_fuzz_target_dnsdistcache_OBJECTS)
+@FUZZ_TARGETS_TRUE@am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1) \
+@FUZZ_TARGETS_TRUE@ $(am__DEPENDENCIES_1)
+fuzz_target_dnsdistcache_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(fuzz_target_dnsdistcache_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__fuzz_target_xsk_SOURCES_DIST = dnslabeltext.cc dnsname.cc \
+ dnsname.hh fuzz_xsk.cc gettime.cc gettime.hh iputils.cc \
+ iputils.hh misc.cc misc.hh xsk.cc xsk.hh
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@am_fuzz_target_xsk_OBJECTS = \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ dnslabeltext.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ dnsname.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ fuzz_xsk.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ gettime.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ iputils.$(OBJEXT) \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ misc.$(OBJEXT) xsk.$(OBJEXT)
+fuzz_target_xsk_OBJECTS = $(am_fuzz_target_xsk_OBJECTS)
+fuzz_target_xsk_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(fuzz_target_xsk_LDFLAGS) \
+ $(LDFLAGS) -o $@
am__testrunner_SOURCES_DIST = base64.hh bpf-filter.cc bpf-filter.hh \
- cachecleaner.hh circular_buffer.hh connection-management.hh \
- credentials.cc credentials.hh dns.cc dns.hh dnscrypt.cc \
- dnscrypt.hh dnsdist-async.cc dnsdist-async.hh \
- dnsdist-backend.cc dnsdist-backoff.hh dnsdist-cache.cc \
- dnsdist-cache.hh dnsdist-concurrent-connections.hh \
- dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ cachecleaner.hh channel.cc channel.hh circular_buffer.hh \
+ connection-management.hh credentials.cc credentials.hh dns.cc \
+ dns.hh dnscrypt.cc dnscrypt.hh dnsdist-async.cc \
+ dnsdist-async.hh dnsdist-backend.cc dnsdist-backoff.hh \
+ dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-concurrent-connections.hh dnsdist-crypto.cc \
+ dnsdist-crypto.hh dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh dnsdist-dynblocks.cc \
dnsdist-dynblocks.hh dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
- dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-idstate.hh \
- dnsdist-kvs.cc dnsdist-kvs.hh dnsdist-lbpolicies.cc \
- dnsdist-lbpolicies.hh dnsdist-lua-bindings-dnsquestion.cc \
+ dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-idstate.hh dnsdist-kvs.cc dnsdist-kvs.hh \
+ dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+ dnsdist-lua-bindings-dnsquestion.cc \
dnsdist-lua-bindings-kvs.cc dnsdist-lua-bindings.cc \
dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh dnsdist-lua-network.cc \
dnsdist-lua-network.hh dnsdist-lua-vars.cc \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
- dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2.cc \
+ dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2-in.hh \
dnsdist-nghttp2.hh dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
- dnsdist-random.cc dnsdist-random.hh dnsdist-rings.cc \
- dnsdist-rings.hh dnsdist-rules.cc dnsdist-rules.hh \
- dnsdist-session-cache.cc dnsdist-session-cache.hh \
- dnsdist-svc.cc dnsdist-svc.hh dnsdist-tcp-downstream.cc \
- dnsdist-tcp.cc dnsdist-tcp.hh dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-random.cc dnsdist-random.hh dnsdist-resolver.cc \
+ dnsdist-resolver.hh dnsdist-rings.cc dnsdist-rings.hh \
+ dnsdist-rules.cc dnsdist-rules.hh dnsdist-session-cache.cc \
+ dnsdist-session-cache.hh dnsdist-svc.cc dnsdist-svc.hh \
+ dnsdist-tcp-downstream.cc dnsdist-tcp.cc dnsdist-tcp.hh \
+ dnsdist-xpf.cc dnsdist-xpf.hh dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.hh dnslabeltext.cc dnsname.cc dnsname.hh dnsparser.hh \
- dnsparser.cc dnswriter.cc dnswriter.hh dolog.hh ednscookies.cc \
- ednscookies.hh ednsoptions.cc ednsoptions.hh ednssubnet.cc \
- ednssubnet.hh ext/luawrapper/include/LuaContext.hpp gettime.cc \
- gettime.hh iputils.cc iputils.hh misc.cc misc.hh namespaces.hh \
+ dnsparser.cc dnswriter.cc dnswriter.hh dolog.cc dolog.hh \
+ ednscookies.cc ednscookies.hh ednsextendederror.cc \
+ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh \
+ ext/luawrapper/include/LuaContext.hpp gettime.cc gettime.hh \
+ iputils.cc iputils.hh misc.cc misc.hh namespaces.hh \
noinitvector.hh pdnsexception.hh pollmplexer.cc \
proxy-protocol.cc proxy-protocol.hh qtype.cc qtype.hh \
- sholder.hh sodcrypto.cc sstuff.hh stat_t.hh statnode.cc \
- statnode.hh svc-records.cc svc-records.hh test-base64_cc.cc \
- test-connectionmanagement_hh.cc test-credentials_cc.cc \
- test-delaypipe_hh.cc test-dnscrypt_cc.cc \
- test-dnsdist-connections-cache.cc test-dnsdist-dnsparser.cc \
- test-dnsdist-lua-ffi.cc test-dnsdist_cc.cc \
- test-dnsdistasync.cc test-dnsdistbackend_cc.cc \
- test-dnsdistbackoff.cc test-dnsdistdynblocks_hh.cc \
+ sholder.hh sstuff.hh stat_t.hh statnode.cc statnode.hh \
+ svc-records.cc svc-records.hh test-base64_cc.cc \
+ test-channel.cc test-connectionmanagement_hh.cc \
+ test-credentials_cc.cc test-delaypipe_hh.cc \
+ test-dnscrypt_cc.cc test-dnsdist-connections-cache.cc \
+ test-dnsdist-dnsparser.cc test-dnsdist-lua-ffi.cc \
+ test-dnsdist_cc.cc test-dnsdistasync.cc \
+ test-dnsdistbackend_cc.cc test-dnsdistbackoff.cc \
+ test-dnsdistdynblocks_hh.cc test-dnsdistedns.cc \
test-dnsdistkvs_cc.cc test-dnsdistlbpolicies_cc.cc \
- test-dnsdistluanetwork.cc test-dnsdistnghttp2_cc.cc \
+ test-dnsdistluanetwork.cc test-dnsdistnghttp2_common.hh \
test-dnsdistpacketcache_cc.cc test-dnsdistrings_cc.cc \
test-dnsdistrules_cc.cc test-dnsdistsvc_cc.cc \
test-dnsdisttcp_cc.cc test-dnsparser_cc.cc test-iputils_hh.cc \
test-luawrapper.cc test-mplexer.cc test-proxy_protocol_cc.cc \
testrunner.cc threadname.hh threadname.cc uuid-utils.hh \
- uuid-utils.cc xpf.cc xpf.hh cdb.cc cdb.hh \
+ uuid-utils.cc xpf.cc xpf.hh xsk.cc xsk.hh cdb.cc cdb.hh \
ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh \
+ dnsdist-nghttp2-in.cc dnsdist-nghttp2.cc \
+ test-dnsdistnghttp2-in_cc.cc test-dnsdistnghttp2_cc.cc \
kqueuemplexer.cc epollmplexer.cc devpollmplexer.cc \
portsmplexer.cc
-am_testrunner_OBJECTS = bpf-filter.$(OBJEXT) credentials.$(OBJEXT) \
- dns.$(OBJEXT) dnscrypt.$(OBJEXT) dnsdist-async.$(OBJEXT) \
- dnsdist-backend.$(OBJEXT) dnsdist-cache.$(OBJEXT) \
- dnsdist-dnsparser.$(OBJEXT) dnsdist-dynblocks.$(OBJEXT) \
- dnsdist-dynbpf.$(OBJEXT) dnsdist-ecs.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@am__objects_13 = dnsdist-nghttp2-in.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ dnsdist-nghttp2.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ test-dnsdistnghttp2-in_cc.$(OBJEXT) \
+@HAVE_DNS_OVER_HTTPS_TRUE@@HAVE_NGHTTP2_TRUE@ test-dnsdistnghttp2_cc.$(OBJEXT)
+am_testrunner_OBJECTS = bpf-filter.$(OBJEXT) channel.$(OBJEXT) \
+ credentials.$(OBJEXT) dns.$(OBJEXT) dnscrypt.$(OBJEXT) \
+ dnsdist-async.$(OBJEXT) dnsdist-backend.$(OBJEXT) \
+ dnsdist-cache.$(OBJEXT) dnsdist-crypto.$(OBJEXT) \
+ dnsdist-dnsparser.$(OBJEXT) dnsdist-doh-common.$(OBJEXT) \
+ dnsdist-dynblocks.$(OBJEXT) dnsdist-dynbpf.$(OBJEXT) \
+ dnsdist-ecs.$(OBJEXT) dnsdist-edns.$(OBJEXT) \
dnsdist-kvs.$(OBJEXT) dnsdist-lbpolicies.$(OBJEXT) \
dnsdist-lua-bindings-dnsquestion.$(OBJEXT) \
dnsdist-lua-bindings-kvs.$(OBJEXT) \
dnsdist-lua-bindings.$(OBJEXT) dnsdist-lua-ffi.$(OBJEXT) \
dnsdist-lua-network.$(OBJEXT) dnsdist-lua-vars.$(OBJEXT) \
dnsdist-mac-address.$(OBJEXT) dnsdist-metrics.$(OBJEXT) \
- dnsdist-nghttp2.$(OBJEXT) dnsdist-protocols.$(OBJEXT) \
- dnsdist-proxy-protocol.$(OBJEXT) dnsdist-random.$(OBJEXT) \
+ dnsdist-protocols.$(OBJEXT) dnsdist-proxy-protocol.$(OBJEXT) \
+ dnsdist-random.$(OBJEXT) dnsdist-resolver.$(OBJEXT) \
dnsdist-rings.$(OBJEXT) dnsdist-rules.$(OBJEXT) \
dnsdist-session-cache.$(OBJEXT) dnsdist-svc.$(OBJEXT) \
dnsdist-tcp-downstream.$(OBJEXT) dnsdist-tcp.$(OBJEXT) \
- dnsdist-xpf.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
- dnsparser.$(OBJEXT) dnswriter.$(OBJEXT) ednscookies.$(OBJEXT) \
- ednsoptions.$(OBJEXT) ednssubnet.$(OBJEXT) gettime.$(OBJEXT) \
- iputils.$(OBJEXT) misc.$(OBJEXT) pollmplexer.$(OBJEXT) \
- proxy-protocol.$(OBJEXT) qtype.$(OBJEXT) sodcrypto.$(OBJEXT) \
- statnode.$(OBJEXT) svc-records.$(OBJEXT) \
- test-base64_cc.$(OBJEXT) \
+ dnsdist-xpf.$(OBJEXT) dnsdist-xsk.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnswriter.$(OBJEXT) dolog.$(OBJEXT) ednscookies.$(OBJEXT) \
+ ednsextendederror.$(OBJEXT) ednsoptions.$(OBJEXT) \
+ ednssubnet.$(OBJEXT) gettime.$(OBJEXT) iputils.$(OBJEXT) \
+ misc.$(OBJEXT) pollmplexer.$(OBJEXT) proxy-protocol.$(OBJEXT) \
+ qtype.$(OBJEXT) statnode.$(OBJEXT) svc-records.$(OBJEXT) \
+ test-base64_cc.$(OBJEXT) test-channel.$(OBJEXT) \
test-connectionmanagement_hh.$(OBJEXT) \
test-credentials_cc.$(OBJEXT) test-delaypipe_hh.$(OBJEXT) \
test-dnscrypt_cc.$(OBJEXT) \
@@ -426,11 +542,10 @@ am_testrunner_OBJECTS = bpf-filter.$(OBJEXT) credentials.$(OBJEXT) \
test-dnsdist-lua-ffi.$(OBJEXT) test-dnsdist_cc.$(OBJEXT) \
test-dnsdistasync.$(OBJEXT) test-dnsdistbackend_cc.$(OBJEXT) \
test-dnsdistbackoff.$(OBJEXT) \
- test-dnsdistdynblocks_hh.$(OBJEXT) \
+ test-dnsdistdynblocks_hh.$(OBJEXT) test-dnsdistedns.$(OBJEXT) \
test-dnsdistkvs_cc.$(OBJEXT) \
test-dnsdistlbpolicies_cc.$(OBJEXT) \
test-dnsdistluanetwork.$(OBJEXT) \
- test-dnsdistnghttp2_cc.$(OBJEXT) \
test-dnsdistpacketcache_cc.$(OBJEXT) \
test-dnsdistrings_cc.$(OBJEXT) test-dnsdistrules_cc.$(OBJEXT) \
test-dnsdistsvc_cc.$(OBJEXT) test-dnsdisttcp_cc.$(OBJEXT) \
@@ -438,13 +553,15 @@ am_testrunner_OBJECTS = bpf-filter.$(OBJEXT) credentials.$(OBJEXT) \
test-luawrapper.$(OBJEXT) test-mplexer.$(OBJEXT) \
test-proxy_protocol_cc.$(OBJEXT) testrunner.$(OBJEXT) \
threadname.$(OBJEXT) uuid-utils.$(OBJEXT) xpf.$(OBJEXT) \
- $(am__objects_1) $(am__objects_3) $(am__objects_4) \
- $(am__objects_5) $(am__objects_6) $(am__objects_7)
+ xsk.$(OBJEXT) $(am__objects_1) $(am__objects_3) \
+ $(am__objects_13) $(am__objects_9) $(am__objects_10) \
+ $(am__objects_11) $(am__objects_12)
testrunner_OBJECTS = $(am_testrunner_OBJECTS)
testrunner_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_5) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_5) \
$(am__DEPENDENCIES_6) $(am__DEPENDENCIES_8)
testrunner_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
@@ -466,16 +583,19 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/bpf-filter.Po \
./$(DEPDIR)/capabilities.Po ./$(DEPDIR)/cdb.Po \
+ ./$(DEPDIR)/channel.Po ./$(DEPDIR)/coverage.Po \
./$(DEPDIR)/credentials.Po ./$(DEPDIR)/devpollmplexer.Po \
./$(DEPDIR)/dns.Po ./$(DEPDIR)/dnscrypt.Po \
./$(DEPDIR)/dnsdist-async.Po ./$(DEPDIR)/dnsdist-backend.Po \
./$(DEPDIR)/dnsdist-cache.Po ./$(DEPDIR)/dnsdist-carbon.Po \
- ./$(DEPDIR)/dnsdist-console.Po \
+ ./$(DEPDIR)/dnsdist-console.Po ./$(DEPDIR)/dnsdist-crypto.Po \
./$(DEPDIR)/dnsdist-discovery.Po \
./$(DEPDIR)/dnsdist-dnscrypt.Po \
./$(DEPDIR)/dnsdist-dnsparser.Po \
+ ./$(DEPDIR)/dnsdist-doh-common.Po \
./$(DEPDIR)/dnsdist-dynblocks.Po ./$(DEPDIR)/dnsdist-dynbpf.Po \
- ./$(DEPDIR)/dnsdist-ecs.Po ./$(DEPDIR)/dnsdist-healthchecks.Po \
+ ./$(DEPDIR)/dnsdist-ecs.Po ./$(DEPDIR)/dnsdist-edns.Po \
+ ./$(DEPDIR)/dnsdist-healthchecks.Po \
./$(DEPDIR)/dnsdist-internal-queries.Po \
./$(DEPDIR)/dnsdist-kvs.Po ./$(DEPDIR)/dnsdist-lbpolicies.Po \
./$(DEPDIR)/dnsdist-lua-actions.Po \
@@ -489,39 +609,45 @@ am__depfiles_remade = ./$(DEPDIR)/bpf-filter.Po \
./$(DEPDIR)/dnsdist-lua-bindings-rings.Po \
./$(DEPDIR)/dnsdist-lua-bindings.Po \
./$(DEPDIR)/dnsdist-lua-ffi.Po \
+ ./$(DEPDIR)/dnsdist-lua-hooks.Po \
./$(DEPDIR)/dnsdist-lua-inspection-ffi.Po \
./$(DEPDIR)/dnsdist-lua-inspection.Po \
./$(DEPDIR)/dnsdist-lua-network.Po \
./$(DEPDIR)/dnsdist-lua-rules.Po \
./$(DEPDIR)/dnsdist-lua-vars.Po ./$(DEPDIR)/dnsdist-lua-web.Po \
./$(DEPDIR)/dnsdist-lua.Po ./$(DEPDIR)/dnsdist-mac-address.Po \
- ./$(DEPDIR)/dnsdist-metrics.Po ./$(DEPDIR)/dnsdist-nghttp2.Po \
- ./$(DEPDIR)/dnsdist-protobuf.Po \
+ ./$(DEPDIR)/dnsdist-metrics.Po \
+ ./$(DEPDIR)/dnsdist-nghttp2-in.Po \
+ ./$(DEPDIR)/dnsdist-nghttp2.Po ./$(DEPDIR)/dnsdist-protobuf.Po \
./$(DEPDIR)/dnsdist-protocols.Po \
./$(DEPDIR)/dnsdist-proxy-protocol.Po \
- ./$(DEPDIR)/dnsdist-random.Po ./$(DEPDIR)/dnsdist-rings.Po \
- ./$(DEPDIR)/dnsdist-rules.Po ./$(DEPDIR)/dnsdist-secpoll.Po \
+ ./$(DEPDIR)/dnsdist-random.Po ./$(DEPDIR)/dnsdist-resolver.Po \
+ ./$(DEPDIR)/dnsdist-rings.Po ./$(DEPDIR)/dnsdist-rules.Po \
+ ./$(DEPDIR)/dnsdist-secpoll.Po \
./$(DEPDIR)/dnsdist-session-cache.Po \
./$(DEPDIR)/dnsdist-snmp.Po ./$(DEPDIR)/dnsdist-svc.Po \
./$(DEPDIR)/dnsdist-systemd.Po \
./$(DEPDIR)/dnsdist-tcp-downstream.Po \
./$(DEPDIR)/dnsdist-tcp.Po ./$(DEPDIR)/dnsdist-web.Po \
- ./$(DEPDIR)/dnsdist-xpf.Po ./$(DEPDIR)/dnsdist.Po \
- ./$(DEPDIR)/dnslabeltext.Po ./$(DEPDIR)/dnsname.Po \
- ./$(DEPDIR)/dnsparser.Po ./$(DEPDIR)/dnstap.Po \
- ./$(DEPDIR)/dnswriter.Po ./$(DEPDIR)/doh.Po \
- ./$(DEPDIR)/ednscookies.Po ./$(DEPDIR)/ednsoptions.Po \
- ./$(DEPDIR)/ednssubnet.Po ./$(DEPDIR)/epollmplexer.Po \
- ./$(DEPDIR)/fstrm_logger.Po ./$(DEPDIR)/gettime.Po \
- ./$(DEPDIR)/ipcipher.Po ./$(DEPDIR)/iputils.Po \
- ./$(DEPDIR)/kqueuemplexer.Po ./$(DEPDIR)/libssl.Po \
- ./$(DEPDIR)/misc.Po ./$(DEPDIR)/pollmplexer.Po \
- ./$(DEPDIR)/portsmplexer.Po ./$(DEPDIR)/protozero.Po \
- ./$(DEPDIR)/proxy-protocol.Po ./$(DEPDIR)/qtype.Po \
- ./$(DEPDIR)/remote_logger.Po ./$(DEPDIR)/snmp-agent.Po \
- ./$(DEPDIR)/sodcrypto.Po ./$(DEPDIR)/statnode.Po \
+ ./$(DEPDIR)/dnsdist-xpf.Po ./$(DEPDIR)/dnsdist-xsk.Po \
+ ./$(DEPDIR)/dnsdist.Po ./$(DEPDIR)/dnslabeltext.Po \
+ ./$(DEPDIR)/dnsname.Po ./$(DEPDIR)/dnsparser.Po \
+ ./$(DEPDIR)/dnstap.Po ./$(DEPDIR)/dnswriter.Po \
+ ./$(DEPDIR)/doh.Po ./$(DEPDIR)/doh3.Po ./$(DEPDIR)/dolog.Po \
+ ./$(DEPDIR)/doq-common.Po ./$(DEPDIR)/doq.Po \
+ ./$(DEPDIR)/ednscookies.Po ./$(DEPDIR)/ednsextendederror.Po \
+ ./$(DEPDIR)/ednsoptions.Po ./$(DEPDIR)/ednssubnet.Po \
+ ./$(DEPDIR)/epollmplexer.Po ./$(DEPDIR)/fstrm_logger.Po \
+ ./$(DEPDIR)/fuzz_dnsdistcache.Po ./$(DEPDIR)/fuzz_xsk.Po \
+ ./$(DEPDIR)/gettime.Po ./$(DEPDIR)/ipcipher.Po \
+ ./$(DEPDIR)/iputils.Po ./$(DEPDIR)/kqueuemplexer.Po \
+ ./$(DEPDIR)/libssl.Po ./$(DEPDIR)/misc.Po \
+ ./$(DEPDIR)/pollmplexer.Po ./$(DEPDIR)/portsmplexer.Po \
+ ./$(DEPDIR)/protozero.Po ./$(DEPDIR)/proxy-protocol.Po \
+ ./$(DEPDIR)/qtype.Po ./$(DEPDIR)/remote_logger.Po \
+ ./$(DEPDIR)/snmp-agent.Po ./$(DEPDIR)/statnode.Po \
./$(DEPDIR)/svc-records.Po ./$(DEPDIR)/tcpiohandler.Po \
- ./$(DEPDIR)/test-base64_cc.Po \
+ ./$(DEPDIR)/test-base64_cc.Po ./$(DEPDIR)/test-channel.Po \
./$(DEPDIR)/test-connectionmanagement_hh.Po \
./$(DEPDIR)/test-credentials_cc.Po \
./$(DEPDIR)/test-delaypipe_hh.Po \
@@ -534,9 +660,11 @@ am__depfiles_remade = ./$(DEPDIR)/bpf-filter.Po \
./$(DEPDIR)/test-dnsdistbackend_cc.Po \
./$(DEPDIR)/test-dnsdistbackoff.Po \
./$(DEPDIR)/test-dnsdistdynblocks_hh.Po \
+ ./$(DEPDIR)/test-dnsdistedns.Po \
./$(DEPDIR)/test-dnsdistkvs_cc.Po \
./$(DEPDIR)/test-dnsdistlbpolicies_cc.Po \
./$(DEPDIR)/test-dnsdistluanetwork.Po \
+ ./$(DEPDIR)/test-dnsdistnghttp2-in_cc.Po \
./$(DEPDIR)/test-dnsdistnghttp2_cc.Po \
./$(DEPDIR)/test-dnsdistpacketcache_cc.Po \
./$(DEPDIR)/test-dnsdistrings_cc.Po \
@@ -549,7 +677,7 @@ am__depfiles_remade = ./$(DEPDIR)/bpf-filter.Po \
./$(DEPDIR)/test-proxy_protocol_cc.Po \
./$(DEPDIR)/testrunner.Po ./$(DEPDIR)/threadname.Po \
./$(DEPDIR)/uuid-utils.Po ./$(DEPDIR)/xpf.Po \
- ext/json11/$(DEPDIR)/json11.Po \
+ ./$(DEPDIR)/xsk.Po ext/json11/$(DEPDIR)/json11.Po \
ext/lmdb-safe/$(DEPDIR)/lmdb-safe.Po
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
@@ -589,8 +717,11 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dnsdist_SOURCES) $(nodist_dnsdist_SOURCES) \
+ $(fuzz_target_dnsdistcache_SOURCES) $(fuzz_target_xsk_SOURCES) \
$(testrunner_SOURCES)
DIST_SOURCES = $(am__dnsdist_SOURCES_DIST) \
+ $(am__fuzz_target_dnsdistcache_SOURCES_DIST) \
+ $(am__fuzz_target_xsk_SOURCES_DIST) \
$(am__testrunner_SOURCES_DIST)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
@@ -645,8 +776,8 @@ am__recursive_targets = \
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
cscope check recheck distdir distdir-am dist dist-all \
distcheck
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
- $(LISP)config.h.in
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ config.h.in
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
@@ -663,9 +794,6 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-CSCOPE = cscope
am__tty_colors_dummy = \
mgn= red= grn= lgn= blu= brg= std=; \
am__color_tests=no
@@ -821,6 +949,7 @@ am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
RECHECK_LOGS = $(TEST_LOGS)
TEST_SUITE_LOG = test-suite.log
TEST_EXTENSIONS = @EXEEXT@ .test
@@ -885,6 +1014,8 @@ am__relativize = \
GZIP_ENV = --best
DIST_ARCHIVES = $(distdir).tar.bz2
DIST_TARGETS = dist-bzip2
+# Exists only to be overridden by the user if desired.
+AM_DISTCHECK_DVI_TARGET = dvi
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
@@ -899,9 +1030,10 @@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(SYSTEMD_CFLAGS) $(LUA_CFLAGS) \
-DBOOST_CONTAINER_USE_STD_EXCEPTIONS $(am__append_1) \
$(am__append_2) $(am__append_3) $(am__append_4) \
$(am__append_5) $(am__append_6) $(am__append_7) \
- $(am__append_8)
+ $(am__append_8) $(am__append_9) $(am__append_35)
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
+ARC4RANDOM_LIBS = @ARC4RANDOM_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -912,13 +1044,16 @@ BOOST_ROOT = @BOOST_ROOT@
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@
+BPF_CFLAGS = @BPF_CFLAGS@
+BPF_LIBS = @BPF_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_CFLAGS = @CDB_CFLAGS@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
-CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -935,8 +1070,10 @@ 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@
GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -1008,6 +1145,8 @@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
+QUICHE_CFLAGS = @QUICHE_CFLAGS@
+QUICHE_LIBS = @QUICHE_LIBS@
RAGEL = @RAGEL@
RANLIB = @RANLIB@
RE2_CFLAGS = @RE2_CFLAGS@
@@ -1027,6 +1166,8 @@ SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
THREADFLAGS = @THREADFLAGS@
VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
+XDP_CFLAGS = @XDP_CFLAGS@
+XDP_LIBS = @XDP_LIBS@
YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
YAHTTP_LIBS = @YAHTTP_LIBS@
abs_builddir = @abs_builddir@
@@ -1091,14 +1232,15 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = ext/ipcrypt \
+SUBDIRS = ext/arc4random \
+ ext/ipcrypt \
ext/yahttp
CLEANFILES = htmlfiles.h.tmp htmlfiles.h dnsdist-lua-ffi-interface.inc \
- lua.hpp $(am__append_35)
+ lua.hpp $(am__append_49)
sysconf_DATA = dnsdist.conf-dist
BUILT_SOURCES = htmlfiles.h dnsdist-lua-ffi-interface.inc \
- dnslabeltext.cc $(am__append_26)
+ dnslabeltext.cc $(am__append_38)
SRC_JS_FILES := $(wildcard src_js/*.js)
MIN_JS_FILES := $(patsubst src_js/%.js,html/js/%.min.js,$(SRC_JS_FILES))
EXTRA_DIST = COPYING \
@@ -1122,29 +1264,32 @@ EXTRA_DIST = COPYING \
kqueuemplexer.cc \
portsmplexer.cc \
cdb.cc cdb.hh \
+ standalone_fuzz_target_runner.cc \
ext/lmdb-safe/lmdb-safe.cc ext/lmdb-safe/lmdb-safe.hh \
ext/protozero/include/* \
builder-support/gen-version
-@UNIT_TESTS_TRUE@TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)'
+@UNIT_TESTS_TRUE@TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message BOOST_TEST_RANDOM=1 SRCDIR='$(srcdir)'
dnsdist_SOURCES = base64.hh bpf-filter.cc bpf-filter.hh burtle.hh \
- cachecleaner.hh capabilities.cc capabilities.hh \
- circular_buffer.hh connection-management.hh credentials.cc \
- credentials.hh dns.cc dns.hh dns_random.hh dnscrypt.cc \
- dnscrypt.hh dnsdist-async.cc dnsdist-async.hh \
- dnsdist-backend.cc dnsdist-backoff.hh dnsdist-cache.cc \
- dnsdist-cache.hh dnsdist-carbon.cc dnsdist-carbon.hh \
- dnsdist-concurrent-connections.hh dnsdist-console.cc \
- dnsdist-console.hh dnsdist-discovery.cc dnsdist-discovery.hh \
+ cachecleaner.hh capabilities.cc capabilities.hh channel.cc \
+ channel.hh circular_buffer.hh connection-management.hh \
+ coverage.cc coverage.hh credentials.cc credentials.hh dns.cc \
+ dns.hh dns_random.hh dnscrypt.cc dnscrypt.hh dnsdist-async.cc \
+ dnsdist-async.hh dnsdist-backend.cc dnsdist-backoff.hh \
+ dnsdist-cache.cc dnsdist-cache.hh dnsdist-carbon.cc \
+ dnsdist-carbon.hh dnsdist-concurrent-connections.hh \
+ dnsdist-console.cc dnsdist-console.hh dnsdist-crypto.cc \
+ dnsdist-crypto.hh dnsdist-discovery.cc dnsdist-discovery.hh \
dnsdist-dnscrypt.cc dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh dnsdist-dynblocks.cc \
dnsdist-dynblocks.hh dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
- dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-healthchecks.cc \
- dnsdist-healthchecks.hh dnsdist-idstate.hh \
- dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
- dnsdist-kvs.hh dnsdist-kvs.cc dnsdist-lbpolicies.cc \
- dnsdist-lbpolicies.hh dnsdist-lua-actions.cc \
- dnsdist-lua-bindings-dnscrypt.cc \
+ dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
+ dnsdist-idstate.hh dnsdist-internal-queries.cc \
+ dnsdist-internal-queries.hh dnsdist-kvs.hh dnsdist-kvs.cc \
+ dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+ dnsdist-lua-actions.cc dnsdist-lua-bindings-dnscrypt.cc \
dnsdist-lua-bindings-dnsparser.cc \
dnsdist-lua-bindings-dnsquestion.cc \
dnsdist-lua-bindings-kvs.cc dnsdist-lua-bindings-network.cc \
@@ -1152,93 +1297,106 @@ dnsdist_SOURCES = base64.hh bpf-filter.cc bpf-filter.hh burtle.hh \
dnsdist-lua-bindings-protobuf.cc dnsdist-lua-bindings-rings.cc \
dnsdist-lua-bindings.cc dnsdist-lua-ffi-interface.h \
dnsdist-lua-ffi-interface.inc dnsdist-lua-ffi.cc \
- dnsdist-lua-ffi.hh dnsdist-lua-inspection-ffi.cc \
- dnsdist-lua-inspection-ffi.h dnsdist-lua-inspection.cc \
- dnsdist-lua-network.cc dnsdist-lua-network.hh \
- dnsdist-lua-rules.cc dnsdist-lua-vars.cc dnsdist-lua-web.cc \
- dnsdist-lua.cc dnsdist-lua.hh dnsdist-mac-address.cc \
- dnsdist-mac-address.hh dnsdist-metrics.cc dnsdist-metrics.hh \
- dnsdist-nghttp2.cc dnsdist-nghttp2.hh dnsdist-prometheus.hh \
- dnsdist-protobuf.cc dnsdist-protobuf.hh dnsdist-protocols.cc \
- dnsdist-protocols.hh dnsdist-proxy-protocol.cc \
- dnsdist-proxy-protocol.hh dnsdist-random.cc dnsdist-random.hh \
- dnsdist-rings.cc dnsdist-rings.hh dnsdist-rules.cc \
- dnsdist-rules.hh dnsdist-secpoll.cc dnsdist-secpoll.hh \
- dnsdist-session-cache.cc dnsdist-session-cache.hh \
- dnsdist-snmp.cc dnsdist-snmp.hh dnsdist-svc.cc dnsdist-svc.hh \
- dnsdist-systemd.cc dnsdist-systemd.hh \
- dnsdist-tcp-downstream.cc dnsdist-tcp-downstream.hh \
- dnsdist-tcp-upstream.hh dnsdist-tcp.cc dnsdist-tcp.hh \
- dnsdist-web.cc dnsdist-web.hh dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-lua-ffi.hh dnsdist-lua-hooks.cc dnsdist-lua-hooks.hh \
+ dnsdist-lua-inspection-ffi.cc dnsdist-lua-inspection-ffi.h \
+ dnsdist-lua-inspection.cc dnsdist-lua-network.cc \
+ dnsdist-lua-network.hh dnsdist-lua-rules.cc \
+ dnsdist-lua-vars.cc dnsdist-lua-web.cc dnsdist-lua.cc \
+ dnsdist-lua.hh dnsdist-mac-address.cc dnsdist-mac-address.hh \
+ dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2-in.hh \
+ dnsdist-nghttp2.hh dnsdist-prometheus.hh dnsdist-protobuf.cc \
+ dnsdist-protobuf.hh dnsdist-protocols.cc dnsdist-protocols.hh \
+ dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
+ dnsdist-random.cc dnsdist-random.hh dnsdist-resolver.cc \
+ dnsdist-resolver.hh dnsdist-rings.cc dnsdist-rings.hh \
+ dnsdist-rules.cc dnsdist-rules.hh dnsdist-secpoll.cc \
+ dnsdist-secpoll.hh dnsdist-session-cache.cc \
+ dnsdist-session-cache.hh dnsdist-snmp.cc dnsdist-snmp.hh \
+ dnsdist-svc.cc dnsdist-svc.hh dnsdist-systemd.cc \
+ dnsdist-systemd.hh dnsdist-tcp-downstream.cc \
+ dnsdist-tcp-downstream.hh dnsdist-tcp-upstream.hh \
+ dnsdist-tcp.cc dnsdist-tcp.hh dnsdist-web.cc dnsdist-web.hh \
+ dnsdist-xpf.cc dnsdist-xpf.hh dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.cc dnsdist.hh dnslabeltext.cc dnsname.cc dnsname.hh \
dnsparser.hh dnsparser.cc dnstap.cc dnstap.hh dnswriter.cc \
- dnswriter.hh doh.hh doh.cc dolog.hh ednscookies.cc \
- ednscookies.hh ednsoptions.cc ednsoptions.hh ednssubnet.cc \
- ednssubnet.hh ext/json11/json11.cpp ext/json11/json11.hpp \
- ext/libbpf/libbpf.h ext/luawrapper/include/LuaContext.hpp \
- fstrm_logger.cc fstrm_logger.hh gettime.cc gettime.hh \
- htmlfiles.h iputils.cc iputils.hh libssl.cc libssl.hh lock.hh \
- logging.hh misc.cc misc.hh mplexer.hh namespaces.hh \
- noinitvector.hh packetcache.hh pdnsexception.hh pollmplexer.cc \
- protozero.cc protozero.hh proxy-protocol.cc proxy-protocol.hh \
- qtype.cc qtype.hh remote_logger.cc remote_logger.hh sholder.hh \
- snmp-agent.cc snmp-agent.hh sodcrypto.cc sodcrypto.hh \
- sstuff.hh stat_t.hh statnode.cc statnode.hh svc-records.cc \
- svc-records.hh tcpiohandler-mplexer.hh tcpiohandler.cc \
- tcpiohandler.hh threadname.hh threadname.cc uuid-utils.hh \
- uuid-utils.cc xpf.cc xpf.hh $(am__append_11) $(am__append_17) \
- $(am__append_20) $(am__append_27) $(am__append_29) \
- $(am__append_31) $(am__append_33)
+ dnswriter.hh doh.hh doh3.hh dolog.cc dolog.hh doq-common.hh \
+ doq.hh ednscookies.cc ednscookies.hh ednsextendederror.cc \
+ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh ext/json11/json11.cpp \
+ ext/json11/json11.hpp ext/libbpf/libbpf.h \
+ ext/luawrapper/include/LuaContext.hpp fstrm_logger.cc \
+ fstrm_logger.hh gettime.cc gettime.hh htmlfiles.h iputils.cc \
+ iputils.hh libssl.cc libssl.hh lock.hh logging.hh misc.cc \
+ misc.hh mplexer.hh namespaces.hh noinitvector.hh \
+ packetcache.hh pdnsexception.hh pollmplexer.cc protozero.cc \
+ protozero.hh proxy-protocol.cc proxy-protocol.hh qtype.cc \
+ qtype.hh remote_logger.cc remote_logger.hh sholder.hh \
+ snmp-agent.cc snmp-agent.hh sstuff.hh stat_t.hh statnode.cc \
+ statnode.hh svc-records.cc svc-records.hh \
+ tcpiohandler-mplexer.hh tcpiohandler.cc tcpiohandler.hh \
+ threadname.hh threadname.cc uuid-utils.hh uuid-utils.cc \
+ views.hh xpf.cc xpf.hh xsk.cc xsk.hh $(am__append_12) \
+ $(am__append_20) $(am__append_23) $(am__append_27) \
+ $(am__append_29) $(am__append_33) $(am__append_34) \
+ $(am__append_37) $(am__append_39) $(am__append_41) \
+ $(am__append_43) $(am__append_45)
testrunner_SOURCES = base64.hh bpf-filter.cc bpf-filter.hh \
- cachecleaner.hh circular_buffer.hh connection-management.hh \
- credentials.cc credentials.hh dns.cc dns.hh dnscrypt.cc \
- dnscrypt.hh dnsdist-async.cc dnsdist-async.hh \
- dnsdist-backend.cc dnsdist-backoff.hh dnsdist-cache.cc \
- dnsdist-cache.hh dnsdist-concurrent-connections.hh \
- dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ cachecleaner.hh channel.cc channel.hh circular_buffer.hh \
+ connection-management.hh credentials.cc credentials.hh dns.cc \
+ dns.hh dnscrypt.cc dnscrypt.hh dnsdist-async.cc \
+ dnsdist-async.hh dnsdist-backend.cc dnsdist-backoff.hh \
+ dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-concurrent-connections.hh dnsdist-crypto.cc \
+ dnsdist-crypto.hh dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+ dnsdist-doh-common.cc dnsdist-doh-common.hh \
dnsdist-downstream-connection.hh dnsdist-dynblocks.cc \
dnsdist-dynblocks.hh dnsdist-dynbpf.cc dnsdist-dynbpf.hh \
- dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-idstate.hh \
- dnsdist-kvs.cc dnsdist-kvs.hh dnsdist-lbpolicies.cc \
- dnsdist-lbpolicies.hh dnsdist-lua-bindings-dnsquestion.cc \
+ dnsdist-ecs.cc dnsdist-ecs.hh dnsdist-edns.cc dnsdist-edns.hh \
+ dnsdist-idstate.hh dnsdist-kvs.cc dnsdist-kvs.hh \
+ dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
+ dnsdist-lua-bindings-dnsquestion.cc \
dnsdist-lua-bindings-kvs.cc dnsdist-lua-bindings.cc \
dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh dnsdist-lua-network.cc \
dnsdist-lua-network.hh dnsdist-lua-vars.cc \
dnsdist-mac-address.cc dnsdist-mac-address.hh \
- dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2.cc \
+ dnsdist-metrics.cc dnsdist-metrics.hh dnsdist-nghttp2-in.hh \
dnsdist-nghttp2.hh dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
- dnsdist-random.cc dnsdist-random.hh dnsdist-rings.cc \
- dnsdist-rings.hh dnsdist-rules.cc dnsdist-rules.hh \
- dnsdist-session-cache.cc dnsdist-session-cache.hh \
- dnsdist-svc.cc dnsdist-svc.hh dnsdist-tcp-downstream.cc \
- dnsdist-tcp.cc dnsdist-tcp.hh dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnsdist-random.cc dnsdist-random.hh dnsdist-resolver.cc \
+ dnsdist-resolver.hh dnsdist-rings.cc dnsdist-rings.hh \
+ dnsdist-rules.cc dnsdist-rules.hh dnsdist-session-cache.cc \
+ dnsdist-session-cache.hh dnsdist-svc.cc dnsdist-svc.hh \
+ dnsdist-tcp-downstream.cc dnsdist-tcp.cc dnsdist-tcp.hh \
+ dnsdist-xpf.cc dnsdist-xpf.hh dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.hh dnslabeltext.cc dnsname.cc dnsname.hh dnsparser.hh \
- dnsparser.cc dnswriter.cc dnswriter.hh dolog.hh ednscookies.cc \
- ednscookies.hh ednsoptions.cc ednsoptions.hh ednssubnet.cc \
- ednssubnet.hh ext/luawrapper/include/LuaContext.hpp gettime.cc \
- gettime.hh iputils.cc iputils.hh misc.cc misc.hh namespaces.hh \
+ dnsparser.cc dnswriter.cc dnswriter.hh dolog.cc dolog.hh \
+ ednscookies.cc ednscookies.hh ednsextendederror.cc \
+ ednsextendederror.hh ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc ednssubnet.hh \
+ ext/luawrapper/include/LuaContext.hpp gettime.cc gettime.hh \
+ iputils.cc iputils.hh misc.cc misc.hh namespaces.hh \
noinitvector.hh pdnsexception.hh pollmplexer.cc \
proxy-protocol.cc proxy-protocol.hh qtype.cc qtype.hh \
- sholder.hh sodcrypto.cc sstuff.hh stat_t.hh statnode.cc \
- statnode.hh svc-records.cc svc-records.hh test-base64_cc.cc \
- test-connectionmanagement_hh.cc test-credentials_cc.cc \
- test-delaypipe_hh.cc test-dnscrypt_cc.cc \
- test-dnsdist-connections-cache.cc test-dnsdist-dnsparser.cc \
- test-dnsdist-lua-ffi.cc test-dnsdist_cc.cc \
- test-dnsdistasync.cc test-dnsdistbackend_cc.cc \
- test-dnsdistbackoff.cc test-dnsdistdynblocks_hh.cc \
+ sholder.hh sstuff.hh stat_t.hh statnode.cc statnode.hh \
+ svc-records.cc svc-records.hh test-base64_cc.cc \
+ test-channel.cc test-connectionmanagement_hh.cc \
+ test-credentials_cc.cc test-delaypipe_hh.cc \
+ test-dnscrypt_cc.cc test-dnsdist-connections-cache.cc \
+ test-dnsdist-dnsparser.cc test-dnsdist-lua-ffi.cc \
+ test-dnsdist_cc.cc test-dnsdistasync.cc \
+ test-dnsdistbackend_cc.cc test-dnsdistbackoff.cc \
+ test-dnsdistdynblocks_hh.cc test-dnsdistedns.cc \
test-dnsdistkvs_cc.cc test-dnsdistlbpolicies_cc.cc \
- test-dnsdistluanetwork.cc test-dnsdistnghttp2_cc.cc \
+ test-dnsdistluanetwork.cc test-dnsdistnghttp2_common.hh \
test-dnsdistpacketcache_cc.cc test-dnsdistrings_cc.cc \
test-dnsdistrules_cc.cc test-dnsdistsvc_cc.cc \
test-dnsdisttcp_cc.cc test-dnsparser_cc.cc test-iputils_hh.cc \
test-luawrapper.cc test-mplexer.cc test-proxy_protocol_cc.cc \
testrunner.cc threadname.hh threadname.cc uuid-utils.hh \
- uuid-utils.cc xpf.cc xpf.hh $(am__append_12) $(am__append_21) \
- $(am__append_28) $(am__append_30) $(am__append_32) \
- $(am__append_34)
+ uuid-utils.cc xpf.cc xpf.hh xsk.cc xsk.hh $(am__append_13) \
+ $(am__append_24) $(am__append_30) $(am__append_40) \
+ $(am__append_42) $(am__append_44) $(am__append_46)
dnsdist_LDFLAGS = \
$(AM_LDFLAGS) \
$(PROGRAM_LDFLAGS) \
@@ -1247,9 +1405,10 @@ dnsdist_LDFLAGS = \
dnsdist_LDADD = $(LUA_LIBS) $(LIBEDIT_LIBS) $(RT_LIBS) $(YAHTTP_LIBS) \
$(LIBSODIUM_LIBS) $(FSTRM_LIBS) $(SYSTEMD_LIBS) \
$(NET_SNMP_LIBS) $(LIBCAP_LIBS) $(IPCRYPT_LIBS) \
- $(am__append_9) $(am__append_13) $(am__append_14) \
- $(am__append_15) $(am__append_18) $(am__append_22) \
- $(am__append_23) $(am__append_24)
+ $(ARC4RANDOM_LIBS) $(am__append_10) $(am__append_14) \
+ $(am__append_15) $(am__append_16) $(am__append_18) \
+ $(am__append_21) $(am__append_25) $(am__append_26) \
+ $(am__append_28) $(am__append_31) $(am__append_36)
testrunner_LDFLAGS = \
$(AM_LDFLAGS) \
$(PROGRAM_LDFLAGS) \
@@ -1258,9 +1417,62 @@ testrunner_LDFLAGS = \
testrunner_LDADD = $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) $(FSTRM_LIBS) \
$(LIBSODIUM_LIBS) $(LUA_LIBS) $(RT_LIBS) $(LIBCAP_LIBS) \
- $(am__append_10) $(am__append_16) $(am__append_19) \
- $(am__append_25)
+ $(ARC4RANDOM_LIBS) $(am__append_11) $(am__append_17) \
+ $(am__append_19) $(am__append_22) $(am__append_32)
@HAVE_LUA_HPP_FALSE@nodist_dnsdist_SOURCES = lua.hpp
+@FUZZ_TARGETS_TRUE@fuzz_targets_programs = fuzz_target_dnsdistcache \
+@FUZZ_TARGETS_TRUE@ $(am__append_47)
+@FUZZ_TARGETS_TRUE@fuzz_targets_libs = \
+@FUZZ_TARGETS_TRUE@ $(LIBCRYPTO_LIBS) \
+@FUZZ_TARGETS_TRUE@ $(ARC4RANDOM_LIBS) \
+@FUZZ_TARGETS_TRUE@ $(LIB_FUZZING_ENGINE)
+
+@FUZZ_TARGETS_TRUE@fuzz_targets_ldflags = \
+@FUZZ_TARGETS_TRUE@ $(AM_LDFLAGS) \
+@FUZZ_TARGETS_TRUE@ $(DYNLINKFLAGS) \
+@FUZZ_TARGETS_TRUE@ $(LIBCRYPTO_LDFLAGS) \
+@FUZZ_TARGETS_TRUE@ $(FUZZING_LDFLAGS)
+
+
+# we need the mockup runner to be built, but not linked if a real fuzzing engine is used
+@FUZZ_TARGETS_TRUE@fuzz_targets_deps = standalone_fuzz_target_runner.o
+@FUZZ_TARGETS_TRUE@fuzz_target_dnsdistcache_SOURCES = \
+@FUZZ_TARGETS_TRUE@ channel.hh channel.cc \
+@FUZZ_TARGETS_TRUE@ dns.cc dns.hh \
+@FUZZ_TARGETS_TRUE@ dnsdist-cache.cc dnsdist-cache.hh \
+@FUZZ_TARGETS_TRUE@ dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
+@FUZZ_TARGETS_TRUE@ dnsdist-ecs.cc dnsdist-ecs.hh \
+@FUZZ_TARGETS_TRUE@ dnsdist-idstate.hh \
+@FUZZ_TARGETS_TRUE@ dnsdist-protocols.cc dnsdist-protocols.hh \
+@FUZZ_TARGETS_TRUE@ dnslabeltext.cc \
+@FUZZ_TARGETS_TRUE@ dnsname.cc dnsname.hh \
+@FUZZ_TARGETS_TRUE@ dnsparser.cc dnsparser.hh \
+@FUZZ_TARGETS_TRUE@ dnswriter.cc dnswriter.hh \
+@FUZZ_TARGETS_TRUE@ doh.hh \
+@FUZZ_TARGETS_TRUE@ ednsoptions.cc ednsoptions.hh \
+@FUZZ_TARGETS_TRUE@ ednssubnet.cc ednssubnet.hh \
+@FUZZ_TARGETS_TRUE@ fuzz_dnsdistcache.cc \
+@FUZZ_TARGETS_TRUE@ iputils.cc iputils.hh \
+@FUZZ_TARGETS_TRUE@ misc.cc misc.hh \
+@FUZZ_TARGETS_TRUE@ packetcache.hh \
+@FUZZ_TARGETS_TRUE@ qtype.cc qtype.hh \
+@FUZZ_TARGETS_TRUE@ svc-records.cc svc-records.hh
+
+@FUZZ_TARGETS_TRUE@fuzz_target_dnsdistcache_DEPENDENCIES = $(fuzz_targets_deps)
+@FUZZ_TARGETS_TRUE@fuzz_target_dnsdistcache_LDFLAGS = $(fuzz_targets_ldflags)
+@FUZZ_TARGETS_TRUE@fuzz_target_dnsdistcache_LDADD = $(fuzz_targets_libs)
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@fuzz_target_xsk_SOURCES = \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ dnslabeltext.cc \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ dnsname.cc dnsname.hh \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ fuzz_xsk.cc \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ gettime.cc gettime.hh \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ iputils.cc iputils.hh \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ misc.cc misc.hh \
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@ xsk.cc xsk.hh
+
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@fuzz_target_xsk_DEPENDENCIES = $(fuzz_targets_deps)
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@fuzz_target_xsk_LDFLAGS = $(fuzz_targets_ldflags)
+@FUZZ_TARGETS_TRUE@@HAVE_XSK_TRUE@fuzz_target_xsk_LDADD = $(fuzz_targets_libs) -lbpf -lxdp
MANPAGES = dnsdist.1
dist_man_MANS = $(MANPAGES)
@HAVE_SYSTEMD_TRUE@systemdsystemunitdir = $(SYSTEMD_DIR)
@@ -1401,6 +1613,14 @@ dnsdist$(EXEEXT): $(dnsdist_OBJECTS) $(dnsdist_DEPENDENCIES) $(EXTRA_dnsdist_DEP
@rm -f dnsdist$(EXEEXT)
$(AM_V_CXXLD)$(dnsdist_LINK) $(dnsdist_OBJECTS) $(dnsdist_LDADD) $(LIBS)
+fuzz_target_dnsdistcache$(EXEEXT): $(fuzz_target_dnsdistcache_OBJECTS) $(fuzz_target_dnsdistcache_DEPENDENCIES) $(EXTRA_fuzz_target_dnsdistcache_DEPENDENCIES)
+ @rm -f fuzz_target_dnsdistcache$(EXEEXT)
+ $(AM_V_CXXLD)$(fuzz_target_dnsdistcache_LINK) $(fuzz_target_dnsdistcache_OBJECTS) $(fuzz_target_dnsdistcache_LDADD) $(LIBS)
+
+fuzz_target_xsk$(EXEEXT): $(fuzz_target_xsk_OBJECTS) $(fuzz_target_xsk_DEPENDENCIES) $(EXTRA_fuzz_target_xsk_DEPENDENCIES)
+ @rm -f fuzz_target_xsk$(EXEEXT)
+ $(AM_V_CXXLD)$(fuzz_target_xsk_LINK) $(fuzz_target_xsk_OBJECTS) $(fuzz_target_xsk_LDADD) $(LIBS)
+
testrunner$(EXEEXT): $(testrunner_OBJECTS) $(testrunner_DEPENDENCIES) $(EXTRA_testrunner_DEPENDENCIES)
@rm -f testrunner$(EXEEXT)
$(AM_V_CXXLD)$(testrunner_LINK) $(testrunner_OBJECTS) $(testrunner_LDADD) $(LIBS)
@@ -1416,6 +1636,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf-filter.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/capabilities.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coverage.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/credentials.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devpollmplexer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Po@am__quote@ # am--include-marker
@@ -1425,12 +1647,15 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-cache.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-carbon.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-console.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-crypto.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-discovery.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-dnscrypt.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-dnsparser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-doh-common.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-dynblocks.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-dynbpf.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-ecs.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-edns.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-healthchecks.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-internal-queries.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-kvs.Po@am__quote@ # am--include-marker
@@ -1446,6 +1671,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-bindings-rings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-bindings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-ffi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-hooks.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-inspection-ffi.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-inspection.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua-network.Po@am__quote@ # am--include-marker
@@ -1455,11 +1681,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-lua.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-mac-address.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-metrics.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-nghttp2-in.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-nghttp2.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-protobuf.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-protocols.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-proxy-protocol.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-random.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-resolver.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-rings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-rules.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-secpoll.Po@am__quote@ # am--include-marker
@@ -1471,6 +1699,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-tcp.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-web.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-xpf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist-xsk.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdist.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnslabeltext.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsname.Po@am__quote@ # am--include-marker
@@ -1478,11 +1707,18 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnstap.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnswriter.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doh.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doh3.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dolog.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doq-common.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doq.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednscookies.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednsextendederror.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednsoptions.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednssubnet.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epollmplexer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fstrm_logger.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz_dnsdistcache.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz_xsk.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettime.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcipher.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iputils.Po@am__quote@ # am--include-marker
@@ -1496,11 +1732,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote_logger.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snmp-agent.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sodcrypto.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statnode.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svc-records.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpiohandler.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base64_cc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-channel.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-connectionmanagement_hh.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-credentials_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-delaypipe_hh.Po@am__quote@ # am--include-marker
@@ -1513,9 +1749,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistbackend_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistbackoff.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistdynblocks_hh.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistedns.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistkvs_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistlbpolicies_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistluanetwork.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistnghttp2-in_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistnghttp2_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistpacketcache_cc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsdistrings_cc.Po@am__quote@ # am--include-marker
@@ -1531,6 +1769,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threadname.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uuid-utils.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xpf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsk.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@ext/json11/$(DEPDIR)/json11.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@ext/lmdb-safe/$(DEPDIR)/lmdb-safe.Po@am__quote@ # am--include-marker
@@ -1895,7 +2134,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \
echo "$${col}$$br$${std}"; \
- echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
@@ -1950,7 +2189,6 @@ testrunner.log: testrunner$(EXEEXT)
@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -2033,6 +2271,10 @@ dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__post_remove_distdir)
+dist-zstd: distdir
+ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
+ $(am__post_remove_distdir)
+
dist-tarZ: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@@ -2075,6 +2317,8 @@ distcheck: dist
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
+ *.tar.zst*) \
+ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
@@ -2090,7 +2334,7 @@ distcheck: dist
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
@@ -2154,7 +2398,8 @@ installdirs-am:
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-recursive
-install-exec: install-exec-recursive
+install-exec: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
@@ -2202,6 +2447,8 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/bpf-filter.Po
-rm -f ./$(DEPDIR)/capabilities.Po
-rm -f ./$(DEPDIR)/cdb.Po
+ -rm -f ./$(DEPDIR)/channel.Po
+ -rm -f ./$(DEPDIR)/coverage.Po
-rm -f ./$(DEPDIR)/credentials.Po
-rm -f ./$(DEPDIR)/devpollmplexer.Po
-rm -f ./$(DEPDIR)/dns.Po
@@ -2211,12 +2458,15 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/dnsdist-cache.Po
-rm -f ./$(DEPDIR)/dnsdist-carbon.Po
-rm -f ./$(DEPDIR)/dnsdist-console.Po
+ -rm -f ./$(DEPDIR)/dnsdist-crypto.Po
-rm -f ./$(DEPDIR)/dnsdist-discovery.Po
-rm -f ./$(DEPDIR)/dnsdist-dnscrypt.Po
-rm -f ./$(DEPDIR)/dnsdist-dnsparser.Po
+ -rm -f ./$(DEPDIR)/dnsdist-doh-common.Po
-rm -f ./$(DEPDIR)/dnsdist-dynblocks.Po
-rm -f ./$(DEPDIR)/dnsdist-dynbpf.Po
-rm -f ./$(DEPDIR)/dnsdist-ecs.Po
+ -rm -f ./$(DEPDIR)/dnsdist-edns.Po
-rm -f ./$(DEPDIR)/dnsdist-healthchecks.Po
-rm -f ./$(DEPDIR)/dnsdist-internal-queries.Po
-rm -f ./$(DEPDIR)/dnsdist-kvs.Po
@@ -2232,6 +2482,7 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/dnsdist-lua-bindings-rings.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-bindings.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-ffi.Po
+ -rm -f ./$(DEPDIR)/dnsdist-lua-hooks.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-inspection-ffi.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-inspection.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-network.Po
@@ -2241,11 +2492,13 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/dnsdist-lua.Po
-rm -f ./$(DEPDIR)/dnsdist-mac-address.Po
-rm -f ./$(DEPDIR)/dnsdist-metrics.Po
+ -rm -f ./$(DEPDIR)/dnsdist-nghttp2-in.Po
-rm -f ./$(DEPDIR)/dnsdist-nghttp2.Po
-rm -f ./$(DEPDIR)/dnsdist-protobuf.Po
-rm -f ./$(DEPDIR)/dnsdist-protocols.Po
-rm -f ./$(DEPDIR)/dnsdist-proxy-protocol.Po
-rm -f ./$(DEPDIR)/dnsdist-random.Po
+ -rm -f ./$(DEPDIR)/dnsdist-resolver.Po
-rm -f ./$(DEPDIR)/dnsdist-rings.Po
-rm -f ./$(DEPDIR)/dnsdist-rules.Po
-rm -f ./$(DEPDIR)/dnsdist-secpoll.Po
@@ -2257,6 +2510,7 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/dnsdist-tcp.Po
-rm -f ./$(DEPDIR)/dnsdist-web.Po
-rm -f ./$(DEPDIR)/dnsdist-xpf.Po
+ -rm -f ./$(DEPDIR)/dnsdist-xsk.Po
-rm -f ./$(DEPDIR)/dnsdist.Po
-rm -f ./$(DEPDIR)/dnslabeltext.Po
-rm -f ./$(DEPDIR)/dnsname.Po
@@ -2264,11 +2518,18 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/dnstap.Po
-rm -f ./$(DEPDIR)/dnswriter.Po
-rm -f ./$(DEPDIR)/doh.Po
+ -rm -f ./$(DEPDIR)/doh3.Po
+ -rm -f ./$(DEPDIR)/dolog.Po
+ -rm -f ./$(DEPDIR)/doq-common.Po
+ -rm -f ./$(DEPDIR)/doq.Po
-rm -f ./$(DEPDIR)/ednscookies.Po
+ -rm -f ./$(DEPDIR)/ednsextendederror.Po
-rm -f ./$(DEPDIR)/ednsoptions.Po
-rm -f ./$(DEPDIR)/ednssubnet.Po
-rm -f ./$(DEPDIR)/epollmplexer.Po
-rm -f ./$(DEPDIR)/fstrm_logger.Po
+ -rm -f ./$(DEPDIR)/fuzz_dnsdistcache.Po
+ -rm -f ./$(DEPDIR)/fuzz_xsk.Po
-rm -f ./$(DEPDIR)/gettime.Po
-rm -f ./$(DEPDIR)/ipcipher.Po
-rm -f ./$(DEPDIR)/iputils.Po
@@ -2282,11 +2543,11 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/remote_logger.Po
-rm -f ./$(DEPDIR)/snmp-agent.Po
- -rm -f ./$(DEPDIR)/sodcrypto.Po
-rm -f ./$(DEPDIR)/statnode.Po
-rm -f ./$(DEPDIR)/svc-records.Po
-rm -f ./$(DEPDIR)/tcpiohandler.Po
-rm -f ./$(DEPDIR)/test-base64_cc.Po
+ -rm -f ./$(DEPDIR)/test-channel.Po
-rm -f ./$(DEPDIR)/test-connectionmanagement_hh.Po
-rm -f ./$(DEPDIR)/test-credentials_cc.Po
-rm -f ./$(DEPDIR)/test-delaypipe_hh.Po
@@ -2299,9 +2560,11 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/test-dnsdistbackend_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistbackoff.Po
-rm -f ./$(DEPDIR)/test-dnsdistdynblocks_hh.Po
+ -rm -f ./$(DEPDIR)/test-dnsdistedns.Po
-rm -f ./$(DEPDIR)/test-dnsdistkvs_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistlbpolicies_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistluanetwork.Po
+ -rm -f ./$(DEPDIR)/test-dnsdistnghttp2-in_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistnghttp2_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistpacketcache_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistrings_cc.Po
@@ -2317,6 +2580,7 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/threadname.Po
-rm -f ./$(DEPDIR)/uuid-utils.Po
-rm -f ./$(DEPDIR)/xpf.Po
+ -rm -f ./$(DEPDIR)/xsk.Po
-rm -f ext/json11/$(DEPDIR)/json11.Po
-rm -f ext/lmdb-safe/$(DEPDIR)/lmdb-safe.Po
-rm -f Makefile
@@ -2369,6 +2633,8 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/bpf-filter.Po
-rm -f ./$(DEPDIR)/capabilities.Po
-rm -f ./$(DEPDIR)/cdb.Po
+ -rm -f ./$(DEPDIR)/channel.Po
+ -rm -f ./$(DEPDIR)/coverage.Po
-rm -f ./$(DEPDIR)/credentials.Po
-rm -f ./$(DEPDIR)/devpollmplexer.Po
-rm -f ./$(DEPDIR)/dns.Po
@@ -2378,12 +2644,15 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/dnsdist-cache.Po
-rm -f ./$(DEPDIR)/dnsdist-carbon.Po
-rm -f ./$(DEPDIR)/dnsdist-console.Po
+ -rm -f ./$(DEPDIR)/dnsdist-crypto.Po
-rm -f ./$(DEPDIR)/dnsdist-discovery.Po
-rm -f ./$(DEPDIR)/dnsdist-dnscrypt.Po
-rm -f ./$(DEPDIR)/dnsdist-dnsparser.Po
+ -rm -f ./$(DEPDIR)/dnsdist-doh-common.Po
-rm -f ./$(DEPDIR)/dnsdist-dynblocks.Po
-rm -f ./$(DEPDIR)/dnsdist-dynbpf.Po
-rm -f ./$(DEPDIR)/dnsdist-ecs.Po
+ -rm -f ./$(DEPDIR)/dnsdist-edns.Po
-rm -f ./$(DEPDIR)/dnsdist-healthchecks.Po
-rm -f ./$(DEPDIR)/dnsdist-internal-queries.Po
-rm -f ./$(DEPDIR)/dnsdist-kvs.Po
@@ -2399,6 +2668,7 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/dnsdist-lua-bindings-rings.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-bindings.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-ffi.Po
+ -rm -f ./$(DEPDIR)/dnsdist-lua-hooks.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-inspection-ffi.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-inspection.Po
-rm -f ./$(DEPDIR)/dnsdist-lua-network.Po
@@ -2408,11 +2678,13 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/dnsdist-lua.Po
-rm -f ./$(DEPDIR)/dnsdist-mac-address.Po
-rm -f ./$(DEPDIR)/dnsdist-metrics.Po
+ -rm -f ./$(DEPDIR)/dnsdist-nghttp2-in.Po
-rm -f ./$(DEPDIR)/dnsdist-nghttp2.Po
-rm -f ./$(DEPDIR)/dnsdist-protobuf.Po
-rm -f ./$(DEPDIR)/dnsdist-protocols.Po
-rm -f ./$(DEPDIR)/dnsdist-proxy-protocol.Po
-rm -f ./$(DEPDIR)/dnsdist-random.Po
+ -rm -f ./$(DEPDIR)/dnsdist-resolver.Po
-rm -f ./$(DEPDIR)/dnsdist-rings.Po
-rm -f ./$(DEPDIR)/dnsdist-rules.Po
-rm -f ./$(DEPDIR)/dnsdist-secpoll.Po
@@ -2424,6 +2696,7 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/dnsdist-tcp.Po
-rm -f ./$(DEPDIR)/dnsdist-web.Po
-rm -f ./$(DEPDIR)/dnsdist-xpf.Po
+ -rm -f ./$(DEPDIR)/dnsdist-xsk.Po
-rm -f ./$(DEPDIR)/dnsdist.Po
-rm -f ./$(DEPDIR)/dnslabeltext.Po
-rm -f ./$(DEPDIR)/dnsname.Po
@@ -2431,11 +2704,18 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/dnstap.Po
-rm -f ./$(DEPDIR)/dnswriter.Po
-rm -f ./$(DEPDIR)/doh.Po
+ -rm -f ./$(DEPDIR)/doh3.Po
+ -rm -f ./$(DEPDIR)/dolog.Po
+ -rm -f ./$(DEPDIR)/doq-common.Po
+ -rm -f ./$(DEPDIR)/doq.Po
-rm -f ./$(DEPDIR)/ednscookies.Po
+ -rm -f ./$(DEPDIR)/ednsextendederror.Po
-rm -f ./$(DEPDIR)/ednsoptions.Po
-rm -f ./$(DEPDIR)/ednssubnet.Po
-rm -f ./$(DEPDIR)/epollmplexer.Po
-rm -f ./$(DEPDIR)/fstrm_logger.Po
+ -rm -f ./$(DEPDIR)/fuzz_dnsdistcache.Po
+ -rm -f ./$(DEPDIR)/fuzz_xsk.Po
-rm -f ./$(DEPDIR)/gettime.Po
-rm -f ./$(DEPDIR)/ipcipher.Po
-rm -f ./$(DEPDIR)/iputils.Po
@@ -2449,11 +2729,11 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/remote_logger.Po
-rm -f ./$(DEPDIR)/snmp-agent.Po
- -rm -f ./$(DEPDIR)/sodcrypto.Po
-rm -f ./$(DEPDIR)/statnode.Po
-rm -f ./$(DEPDIR)/svc-records.Po
-rm -f ./$(DEPDIR)/tcpiohandler.Po
-rm -f ./$(DEPDIR)/test-base64_cc.Po
+ -rm -f ./$(DEPDIR)/test-channel.Po
-rm -f ./$(DEPDIR)/test-connectionmanagement_hh.Po
-rm -f ./$(DEPDIR)/test-credentials_cc.Po
-rm -f ./$(DEPDIR)/test-delaypipe_hh.Po
@@ -2466,9 +2746,11 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/test-dnsdistbackend_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistbackoff.Po
-rm -f ./$(DEPDIR)/test-dnsdistdynblocks_hh.Po
+ -rm -f ./$(DEPDIR)/test-dnsdistedns.Po
-rm -f ./$(DEPDIR)/test-dnsdistkvs_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistlbpolicies_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistluanetwork.Po
+ -rm -f ./$(DEPDIR)/test-dnsdistnghttp2-in_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistnghttp2_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistpacketcache_cc.Po
-rm -f ./$(DEPDIR)/test-dnsdistrings_cc.Po
@@ -2484,6 +2766,7 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/threadname.Po
-rm -f ./$(DEPDIR)/uuid-utils.Po
-rm -f ./$(DEPDIR)/xpf.Po
+ -rm -f ./$(DEPDIR)/xsk.Po
-rm -f ext/json11/$(DEPDIR)/json11.Po
-rm -f ext/lmdb-safe/$(DEPDIR)/lmdb-safe.Po
-rm -f Makefile
@@ -2508,15 +2791,15 @@ uninstall-am: uninstall-binPROGRAMS uninstall-man \
uninstall-man: uninstall-man1
.MAKE: $(am__recursive_targets) all check check-am install install-am \
- install-strip
+ install-exec install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--depfiles am--refresh check check-TESTS check-am \
check-local clean clean-binPROGRAMS clean-cscope clean-generic \
clean-libtool clean-noinstPROGRAMS cscope cscopelist-am ctags \
ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \
- dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
- distclean-compile distclean-generic distclean-hdr \
+ dist-shar dist-tarZ dist-xz dist-zip dist-zstd distcheck \
+ distclean distclean-compile distclean-generic distclean-hdr \
distclean-libtool distclean-tags distcleancheck distdir \
distuninstallcheck dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-data \
@@ -2558,6 +2841,12 @@ min_js: $(MIN_JS_FILES)
dnsdist-web.$(OBJEXT): htmlfiles.h
dnsdist-lua-ffi.$(OBJEXT): dnsdist-lua-ffi-interface.inc
+@FUZZ_TARGETS_TRUE@LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
+
+@FUZZ_TARGETS_TRUE@standalone_fuzz_target_runner.o: standalone_fuzz_target_runner.cc
+
+@FUZZ_TARGETS_TRUE@fuzz_targets: $(ARC4RANDOM_LIBS) $(fuzz_targets_programs)
+
@HAVE_MANPAGES_FALSE@@HAVE_VENV_TRUE@$(MANPAGES): %: docs/manpages/%.rst .venv
@HAVE_MANPAGES_FALSE@@HAVE_VENV_TRUE@ $(AM_V_GEN).venv/bin/python -msphinx -b man docs . $<
diff --git a/aclocal.m4 b/aclocal.m4
index 3f99c79..ff3aabd 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.16.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -14,14 +14,14 @@
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.69],,
-[m4_warning([this file was generated for autoconf 2.69.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],,
+[m4_warning([this file was generated for autoconf 2.71.
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'.])])
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 11 (pkg-config-0.29.1)
+# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
+# serial 12 (pkg-config-0.29.2)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@@ -63,7 +63,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29.1])
+[m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
@@ -108,7 +108,7 @@ dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-dnl only at the first occurence in configure.ac, so if the first place
+dnl only at the first occurrence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS],
@@ -164,7 +164,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
-AC_MSG_CHECKING([for $1])
+AC_MSG_CHECKING([for $2])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -174,17 +174,17 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
+ AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
- m4_default([$4], [AC_MSG_ERROR(
+ m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
@@ -195,8 +195,8 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
- m4_default([$4], [AC_MSG_FAILURE(
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
[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.
@@ -206,10 +206,10 @@ _PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
- $3
+ $3
fi[]dnl
])dnl PKG_CHECK_MODULES
@@ -364,7 +364,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
-# Copyright (C) 2002-2018 Free Software Foundation, Inc.
+# Copyright (C) 2002-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -379,7 +379,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.16'
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.1], [],
+m4_if([$1], [1.16.5], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -395,14 +395,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# 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.1])dnl
+[AM_AUTOMAKE_VERSION([1.16.5])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-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -454,7 +454,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
# AM_COND_IF -*- Autoconf -*-
-# Copyright (C) 2008-2018 Free Software Foundation, Inc.
+# Copyright (C) 2008-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -491,7 +491,7 @@ fi[]dnl
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -522,7 +522,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -713,7 +713,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -752,7 +752,9 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
done
if test $am_rc -ne 0; then
AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments
- for automatic dependency tracking. Try re-running configure with the
+ 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).])
fi
@@ -779,7 +781,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -807,6 +809,10 @@ m4_defn([AC_PROG_CC])
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.65])dnl
+m4_ifdef([_$0_ALREADY_INIT],
+ [m4_fatal([$0 expanded multiple times
+]m4_defn([_$0_ALREADY_INIT]))],
+ [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
@@ -843,7 +849,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
[_AM_SET_OPTIONS([$1])dnl
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
m4_if(
- m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]),
[ok:ok],,
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
@@ -895,6 +901,20 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
[m4_define([AC_PROG_OBJCXX],
m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
])
+# Variables for tags utilities; see am/tags.am
+if test -z "$CTAGS"; then
+ CTAGS=ctags
+fi
+AC_SUBST([CTAGS])
+if test -z "$ETAGS"; then
+ ETAGS=etags
+fi
+AC_SUBST([ETAGS])
+if test -z "$CSCOPE"; then
+ CSCOPE=cscope
+fi
+AC_SUBST([CSCOPE])
+
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
@@ -976,7 +996,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -997,7 +1017,7 @@ if test x"${install_sh+set}" != xset; then
fi
AC_SUBST([install_sh])])
-# Copyright (C) 2003-2018 Free Software Foundation, Inc.
+# Copyright (C) 2003-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1018,7 +1038,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1061,7 +1081,7 @@ AC_SUBST([am__quote])])
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1082,12 +1102,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([missing])dnl
if test x"${MISSING+set}" != xset; then
- case $am_aux_dir in
- *\ * | *\ *)
- MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
- *)
- MISSING="\${SHELL} $am_aux_dir/missing" ;;
- esac
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
fi
# Use eval to expand $SHELL
if eval "$MISSING --is-lightweight"; then
@@ -1100,7 +1115,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1129,7 +1144,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1176,7 +1191,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1211,6 +1226,7 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl supported. (2.0 was released on October 16, 2000).
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
[python python2 python3 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.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
@@ -1255,34 +1271,141 @@ AC_DEFUN([AM_PATH_PYTHON],
])
if test "$PYTHON" = :; then
- dnl Run any user-specified action, or abort.
+ dnl Run any user-specified action, or abort.
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
else
- dnl Query Python for its version number. Getting [:3] seems to be
- dnl the best way to do this; it's what "site.py" does in the standard
- dnl library.
-
+ dnl Query Python for its version number. Although site.py simply uses
+ dnl sys.version[:3], printing that failed with Python 3.10, since the
+ dnl trailing zero was eliminated. So now we output just the major
+ dnl and minor version numbers, as numbers. Apparently the tertiary
+ dnl version is not of interest.
+ dnl
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
- [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
+ [am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
- dnl Use the values of $prefix and $exec_prefix for the corresponding
- dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
- dnl distinct variables so they can be overridden if need be. However,
- dnl general consensus is that you shouldn't need this ability.
-
- AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
- AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
-
- dnl At times (like when building shared libraries) you may want
+ dnl At times, e.g., when building shared libraries, you may want
dnl to know which OS platform Python thinks this is.
-
+ dnl
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
- # Just factor out some code duplication.
+ dnl emacs-page
+ dnl If --with-python-sys-prefix is given, use the values of sys.prefix
+ dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
+ dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
+ dnl ${exec_prefix} variables.
+ dnl
+ dnl The two are made distinct variables so they can be overridden if
+ dnl need be, although general consensus is that you shouldn't need
+ dnl this separation.
+ dnl
+ dnl Also allow directly setting the prefixes via configure options,
+ dnl overriding any default.
+ dnl
+ if test "x$prefix" = xNONE; then
+ am__usable_prefix=$ac_default_prefix
+ else
+ am__usable_prefix=$prefix
+ fi
+
+ # Allow user to request using sys.* values from Python,
+ # instead of the GNU $prefix values.
+ AC_ARG_WITH([python-sys-prefix],
+ [AS_HELP_STRING([--with-python-sys-prefix],
+ [use Python's sys.prefix and sys.exec_prefix values])],
+ [am_use_python_sys=:],
+ [am_use_python_sys=false])
+
+ # Allow user to override whatever the default Python prefix is.
+ AC_ARG_WITH([python_prefix],
+ [AS_HELP_STRING([--with-python_prefix],
+ [override the default PYTHON_PREFIX])],
+ [am_python_prefix_subst=$withval
+ am_cv_python_prefix=$withval
+ AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
+ AC_MSG_RESULT([$am_cv_python_prefix])],
+ [
+ if $am_use_python_sys; then
+ # using python sys.prefix value, not GNU
+ AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
+ [am_cv_python_prefix],
+ [am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
+
+ dnl If sys.prefix is a subdir of $prefix, replace the literal value of
+ dnl $prefix with a variable reference so it can be overridden.
+ case $am_cv_python_prefix in
+ $am__usable_prefix*)
+ am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
+ am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
+ ;;
+ *)
+ am_python_prefix_subst=$am_cv_python_prefix
+ ;;
+ esac
+ else # using GNU prefix value, not python sys.prefix
+ am_python_prefix_subst='${prefix}'
+ am_python_prefix=$am_python_prefix_subst
+ AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
+ AC_MSG_RESULT([$am_python_prefix])
+ fi])
+ # Substituting python_prefix_subst value.
+ AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
+
+ # emacs-page Now do it all over again for Python exec_prefix, but with yet
+ # another conditional: fall back to regular prefix if that was specified.
+ AC_ARG_WITH([python_exec_prefix],
+ [AS_HELP_STRING([--with-python_exec_prefix],
+ [override the default PYTHON_EXEC_PREFIX])],
+ [am_python_exec_prefix_subst=$withval
+ am_cv_python_exec_prefix=$withval
+ AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_cv_python_exec_prefix])],
+ [
+ # no explicit --with-python_exec_prefix, but if
+ # --with-python_prefix was given, use its value for python_exec_prefix too.
+ AS_IF([test -n "$with_python_prefix"],
+ [am_python_exec_prefix_subst=$with_python_prefix
+ am_cv_python_exec_prefix=$with_python_prefix
+ AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_cv_python_exec_prefix])],
+ [
+ # 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
+ am__usable_exec_prefix=$am__usable_prefix
+ else
+ am__usable_exec_prefix=$exec_prefix
+ fi
+ #
+ if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
+ AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
+ [am_cv_python_exec_prefix],
+ [am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
+ dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
+ dnl literal value of $exec_prefix with a variable reference so it can
+ dnl be overridden.
+ case $am_cv_python_exec_prefix in
+ $am__usable_exec_prefix*)
+ am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
+ am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
+ ;;
+ *)
+ am_python_exec_prefix_subst=$am_cv_python_exec_prefix
+ ;;
+ esac
+ else # using GNU $exec_prefix, not python sys.exec_prefix
+ am_python_exec_prefix_subst='${exec_prefix}'
+ am_python_exec_prefix=$am_python_exec_prefix_subst
+ AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
+ AC_MSG_RESULT([$am_python_exec_prefix])
+ fi])])
+ # Substituting python_exec_prefix_subst.
+ AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
+
+ # Factor out some code duplication into this shell variable.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
@@ -1302,96 +1425,95 @@ try:
except ImportError:
pass"
- dnl Set up 4 directories:
+ dnl emacs-page Set up 4 directories:
- dnl 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 is more consistent with lispdir.m4 for example.
+ 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 is more consistent with lispdir.m4 for example.
dnl Query distutils for this directory.
- AC_CACHE_CHECK([for $am_display_PYTHON script directory],
- [am_cv_python_pythondir],
- [if test "x$prefix" = xNONE
- then
- am_py_prefix=$ac_default_prefix
- else
- am_py_prefix=$prefix
- fi
- am_cv_python_pythondir=`$PYTHON -c "
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
+ [am_cv_python_pythondir],
+ [if test "x$am_cv_python_prefix" = x; then
+ am_py_prefix=$am__usable_prefix
+ else
+ am_py_prefix=$am_cv_python_prefix
+ fi
+ am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
- sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
+ 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')
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
- case $am_cv_python_pythondir in
- $am_py_prefix*)
- am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
- am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
- ;;
- *)
- case $am_py_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
+ #
+ case $am_cv_python_pythondir in
+ $am_py_prefix*)
+ am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
+ am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
+ ;;
+ *)
+ case $am_py_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
esac
- ])
+ ;;
+ esac
+ ])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
- dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
- dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
- dnl more consistent with the rest of automake.
-
+ dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
+ dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
+ dnl more consistent with the rest of automake.
+ dnl
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
- dnl pyexecdir -- directory for installing python extension modules
- dnl (shared libraries)
+ dnl 3. pyexecdir: directory for installing python extension modules
+ dnl (shared libraries).
dnl Query distutils for this directory.
- AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
- [am_cv_python_pyexecdir],
- [if test "x$exec_prefix" = xNONE
- then
- am_py_exec_prefix=$am_py_prefix
- else
- am_py_exec_prefix=$exec_prefix
- fi
- am_cv_python_pyexecdir=`$PYTHON -c "
+ dnl
+ AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
+ [am_cv_python_pyexecdir],
+ [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
+ fi
+ am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
- sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
+ 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_prefix')
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
sys.stdout.write(sitedir)"`
- case $am_cv_python_pyexecdir in
- $am_py_exec_prefix*)
- am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
- am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
- ;;
- *)
- case $am_py_exec_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
+ #
+ case $am_cv_python_pyexecdir in
+ $am_py_exec_prefix*)
+ am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
+ am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
+ ;;
+ *)
+ case $am_py_exec_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
esac
- ])
+ ;;
+ esac
+ ])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
- dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
-
+ dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
+ dnl
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action.
$2
fi
-
])
@@ -1414,7 +1536,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
-# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1433,7 +1555,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1514,7 +1636,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
-# Copyright (C) 2009-2018 Free Software Foundation, Inc.
+# Copyright (C) 2009-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1574,7 +1696,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
-# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1602,7 +1724,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2018 Free Software Foundation, Inc.
+# Copyright (C) 2006-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1621,7 +1743,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2018 Free Software Foundation, Inc.
+# Copyright (C) 2004-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1760,6 +1882,8 @@ m4_include([m4/ax_python_module.m4])
m4_include([m4/boost.m4])
m4_include([m4/dnsdist_enable_dnscrypt.m4])
m4_include([m4/dnsdist_enable_doh.m4])
+m4_include([m4/dnsdist_enable_doh3.m4])
+m4_include([m4/dnsdist_enable_doq.m4])
m4_include([m4/dnsdist_enable_tls_providers.m4])
m4_include([m4/dnsdist_with_cdb.m4])
m4_include([m4/libtool.m4])
@@ -1781,6 +1905,8 @@ m4_include([m4/pdns_check_python_venv.m4])
m4_include([m4/pdns_check_ragel.m4])
m4_include([m4/pdns_check_secure_memset.m4])
m4_include([m4/pdns_d_fortify_source.m4])
+m4_include([m4/pdns_enable_coverage.m4])
+m4_include([m4/pdns_enable_fuzz_targets.m4])
m4_include([m4/pdns_enable_ipcipher.m4])
m4_include([m4/pdns_enable_lto.m4])
m4_include([m4/pdns_enable_sanitizers.m4])
@@ -1799,7 +1925,9 @@ m4_include([m4/pdns_with_libssl.m4])
m4_include([m4/pdns_with_lua.m4])
m4_include([m4/pdns_with_net_snmp.m4])
m4_include([m4/pdns_with_nghttp2.m4])
+m4_include([m4/pdns_with_quiche.m4])
m4_include([m4/pdns_with_re2.m4])
m4_include([m4/pdns_with_service_user.m4])
+m4_include([m4/pdns_with_xsk.m4])
m4_include([m4/systemd.m4])
m4_include([m4/warnings.m4])
diff --git a/base64.hh b/base64.hh
index a84181d..f07814b 100644
--- a/base64.hh
+++ b/base64.hh
@@ -22,5 +22,5 @@
#pragma once
#include <string>
-template<typename Container> int B64Decode(const std::string& src, Container& dst);
+template<typename Container> int B64Decode(const std::string& strInput, Container& strOutput);
std::string Base64Encode (const std::string& src);
diff --git a/bpf-filter.cc b/bpf-filter.cc
index bb0c58e..4a12d9d 100644
--- a/bpf-filter.cc
+++ b/bpf-filter.cc
@@ -33,18 +33,18 @@
#include "misc.hh"
-static __u64 ptr_to_u64(void *ptr)
+static __u64 ptr_to_u64(const void *ptr)
{
return (__u64) (unsigned long) ptr;
}
/* these can be static as they are not declared in libbpf.h: */
-static int bpf_pin_map(int fd, const std::string& path)
+static int bpf_pin_map(int descriptor, const std::string& path)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.bpf_fd = fd;
- attr.pathname = ptr_to_u64(const_cast<char*>(path.c_str()));
+ attr.bpf_fd = descriptor;
+ attr.pathname = ptr_to_u64(path.c_str());
return syscall(SYS_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
}
@@ -52,11 +52,11 @@ static int bpf_load_pinned_map(const std::string& path)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.pathname = ptr_to_u64(const_cast<char*>(path.c_str()));
+ attr.pathname = ptr_to_u64(path.c_str());
return syscall(SYS_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
}
-static void bpf_check_map_sizes(int fd, uint32_t expectedKeySize, uint32_t expectedValueSize)
+static void bpf_check_map_sizes(int descriptor, uint32_t expectedKeySize, uint32_t expectedValueSize)
{
struct bpf_map_info info;
uint32_t info_len = sizeof(info);
@@ -64,7 +64,7 @@ static void bpf_check_map_sizes(int fd, uint32_t expectedKeySize, uint32_t expec
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.info.bpf_fd = fd;
+ attr.info.bpf_fd = descriptor;
attr.info.info_len = info_len;
attr.info.info = ptr_to_u64(&info);
@@ -83,8 +83,9 @@ static void bpf_check_map_sizes(int fd, uint32_t expectedKeySize, uint32_t expec
}
}
-int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
- int max_entries, int map_flags)
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
+ int max_entries, int map_flags)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
@@ -96,56 +97,56 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
return syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}
-int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)
+static int bpf_update_elem(int descriptor, void *key, void *value, unsigned long long flags)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.map_fd = fd;
+ attr.map_fd = descriptor;
attr.key = ptr_to_u64(key);
attr.value = ptr_to_u64(value);
attr.flags = flags;
return syscall(SYS_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
-int bpf_lookup_elem(int fd, void *key, void *value)
+static int bpf_lookup_elem(int descriptor, void *key, void *value)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.map_fd = fd;
+ attr.map_fd = descriptor;
attr.key = ptr_to_u64(key);
attr.value = ptr_to_u64(value);
return syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
-int bpf_delete_elem(int fd, void *key)
+static int bpf_delete_elem(int descriptor, void *key)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.map_fd = fd;
+ attr.map_fd = descriptor;
attr.key = ptr_to_u64(key);
return syscall(SYS_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
-int bpf_get_next_key(int fd, void *key, void *next_key)
+static int bpf_get_next_key(int descriptor, void *key, void *next_key)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.map_fd = fd;
+ attr.map_fd = descriptor;
attr.key = ptr_to_u64(key);
attr.next_key = ptr_to_u64(next_key);
return syscall(SYS_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
}
-int bpf_prog_load(enum bpf_prog_type prog_type,
- const struct bpf_insn *insns, int prog_len,
- const char *license, int kern_version)
+static int bpf_prog_load(enum bpf_prog_type prog_type,
+ const struct bpf_insn *insns, size_t prog_len,
+ const char *license, int kern_version)
{
char log_buf[65535];
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.prog_type = prog_type;
attr.insns = ptr_to_u64((void *) insns);
- attr.insn_cnt = prog_len / sizeof(struct bpf_insn);
+ attr.insn_cnt = static_cast<int>(prog_len / sizeof(struct bpf_insn));
attr.license = ptr_to_u64((void *) license);
attr.log_buf = ptr_to_u64(log_buf);
attr.log_size = sizeof(log_buf);
@@ -337,15 +338,15 @@ BPFFilter::Map::Map(const BPFFilter::MapConfiguration& config, BPFFilter::MapFor
static FDWrapper loadProgram(const struct bpf_insn* filter, size_t filterSize)
{
- auto fd = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
- filter,
- filterSize,
- "GPL",
- 0));
- if (fd.getHandle() == -1) {
+ auto descriptor = FDWrapper(bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
+ filter,
+ filterSize,
+ "GPL",
+ 0));
+ if (descriptor.getHandle() == -1) {
throw std::runtime_error("error loading BPF filter: " + stringerror());
}
- return fd;
+ return descriptor;
}
@@ -428,8 +429,8 @@ BPFFilter::BPFFilter(std::unordered_map<std::string, MapConfiguration>& configs,
void BPFFilter::addSocket(int sock)
{
- int fd = d_mainfilter.getHandle();
- int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &fd, sizeof(fd));
+ int descriptor = d_mainfilter.getHandle();
+ int res = setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &descriptor, sizeof(descriptor));
if (res != 0) {
throw std::runtime_error("Error attaching BPF filter to this socket: " + stringerror());
@@ -438,8 +439,8 @@ void BPFFilter::addSocket(int sock)
void BPFFilter::removeSocket(int sock)
{
- int fd = d_mainfilter.getHandle();
- int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &fd, sizeof(fd));
+ int descriptor = d_mainfilter.getHandle();
+ int res = setsockopt(sock, SOL_SOCKET, SO_DETACH_BPF, &descriptor, sizeof(descriptor));
if (res != 0) {
throw std::runtime_error("Error detaching BPF filter from this socket: " + stringerror());
@@ -717,21 +718,21 @@ std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
result.reserve(maps->d_v4.d_count + maps->d_v6.d_count);
}
- sockaddr_in v4Addr;
+ sockaddr_in v4Addr{};
memset(&v4Addr, 0, sizeof(v4Addr));
v4Addr.sin_family = AF_INET;
uint32_t v4Key = 0;
- uint32_t nextV4Key;
- CounterAndActionValue value;
+ uint32_t nextV4Key{};
+ CounterAndActionValue value{};
- uint8_t v6Key[16];
- uint8_t nextV6Key[16];
- sockaddr_in6 v6Addr;
+ std::array<uint8_t, 16> v6Key{};
+ std::array<uint8_t, 16> nextV6Key{};
+ sockaddr_in6 v6Addr{};
memset(&v6Addr, 0, sizeof(v6Addr));
v6Addr.sin6_family = AF_INET6;
- static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == sizeof(v6Key), "POSIX mandates s6_addr to be an array of 16 uint8_t");
+ static_assert(sizeof(v6Addr.sin6_addr.s6_addr) == v6Key.size(), "POSIX mandates s6_addr to be an array of 16 uint8_t");
memset(&v6Key, 0, sizeof(v6Key));
auto maps = d_maps.lock();
@@ -753,16 +754,16 @@ std::vector<std::pair<ComboAddress, uint64_t> > BPFFilter::getAddrStats()
{
auto& map = maps->d_v6;
- int res = bpf_get_next_key(map.d_fd.getHandle(), &v6Key, &nextV6Key);
+ int res = bpf_get_next_key(map.d_fd.getHandle(), v6Key.data(), nextV6Key.data());
while (res == 0) {
- if (bpf_lookup_elem(map.d_fd.getHandle(), &nextV6Key, &value) == 0) {
- memcpy(&v6Addr.sin6_addr.s6_addr, &nextV6Key, sizeof(nextV6Key));
+ if (bpf_lookup_elem(map.d_fd.getHandle(), nextV6Key.data(), &value) == 0) {
+ memcpy(&v6Addr.sin6_addr.s6_addr, nextV6Key.data(), nextV6Key.size());
result.emplace_back(ComboAddress(&v6Addr), value.counter);
}
- res = bpf_get_next_key(map.d_fd.getHandle(), &nextV6Key, &nextV6Key);
+ res = bpf_get_next_key(map.d_fd.getHandle(), nextV6Key.data(), nextV6Key.data());
}
}
@@ -832,7 +833,7 @@ std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
while (res == 0) {
if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
- result.push_back(std::make_tuple(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter));
+ result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), value.qtype, value.counter);
}
res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
@@ -853,7 +854,7 @@ std::vector<std::tuple<DNSName, uint16_t, uint64_t> > BPFFilter::getQNameStats()
while (res == 0) {
if (bpf_lookup_elem(map.d_fd.getHandle(), &nextKey, &value) == 0) {
nextKey.qname[sizeof(nextKey.qname) - 1 ] = '\0';
- result.push_back(std::make_tuple(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter));
+ result.emplace_back(DNSName(reinterpret_cast<const char*>(nextKey.qname), sizeof(nextKey.qname), 0, false), key.qtype, value.counter);
}
res = bpf_get_next_key(map.d_fd.getHandle(), &nextKey, &nextKey);
diff --git a/cachecleaner.hh b/cachecleaner.hh
index 9ec8e13..aaf7981 100644
--- a/cachecleaner.hh
+++ b/cachecleaner.hh
@@ -130,10 +130,9 @@ uint64_t pruneLockedCollectionsVector(std::vector<T>& maps)
return totErased;
}
-template <typename S, typename C, typename T>
-uint64_t pruneMutexCollectionsVector(C& container, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
+template <typename S, typename T>
+uint64_t pruneMutexCollectionsVector(time_t now, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
{
- const time_t now = time(nullptr);
uint64_t totErased = 0;
uint64_t toTrim = 0;
uint64_t lookAt = 0;
@@ -164,10 +163,10 @@ uint64_t pruneMutexCollectionsVector(C& container, std::vector<T>& maps, uint64_
uint64_t lookedAt = 0;
for (auto i = sidx.begin(); i != sidx.end(); lookedAt++) {
if (i->isStale(now)) {
- container.preRemoval(*shard, *i);
+ shard->preRemoval(*i);
i = sidx.erase(i);
erased++;
- --content.d_entriesCount;
+ content.decEntriesCount();
}
else {
++i;
@@ -224,9 +223,9 @@ uint64_t pruneMutexCollectionsVector(C& container, std::vector<T>& maps, uint64_
auto& sidx = boost::multi_index::get<S>(shard->d_map);
size_t removed = 0;
for (auto i = sidx.begin(); i != sidx.end() && removed < toTrimForThisShard; removed++) {
- container.preRemoval(*shard, *i);
+ shard->preRemoval(*i);
i = sidx.erase(i);
- --content.d_entriesCount;
+ content.decEntriesCount();
++totErased;
if (--toTrim == 0) {
return totErased;
diff --git a/capabilities.cc b/capabilities.cc
index e073d2c..2747fc9 100644
--- a/capabilities.cc
+++ b/capabilities.cc
@@ -33,7 +33,7 @@
#include "capabilities.hh"
#include "misc.hh"
-bool dropCapabilities(std::set<std::string> capabilitiesToKeep)
+bool dropCapabilities([[maybe_unused]] std::set<std::string> capabilitiesToKeep)
{
#ifdef HAVE_LIBCAP
cap_t caps = cap_get_proc();
diff --git a/channel.cc b/channel.cc
new file mode 100644
index 0000000..d6a3039
--- /dev/null
+++ b/channel.cc
@@ -0,0 +1,115 @@
+/*
+ * 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 "channel.hh"
+
+namespace pdns::channel
+{
+
+Notifier::Notifier(FDWrapper&& descriptor) :
+ d_fd(std::move(descriptor))
+{
+}
+
+bool Notifier::notify() const
+{
+ char data = 'a';
+ while (true) {
+ auto sent = write(d_fd.getHandle(), &data, sizeof(data));
+ if (sent == 0) {
+ throw std::runtime_error("Unable to write to channel notifier pipe: remote end has been closed");
+ }
+ if (sent != sizeof(data)) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return false;
+ }
+ throw std::runtime_error("Unable to write to channel notifier pipe: " + stringerror());
+ }
+ return true;
+ }
+}
+
+Waiter::Waiter(FDWrapper&& descriptor, bool throwOnEOF) :
+ d_fd(std::move(descriptor)), d_throwOnEOF(throwOnEOF)
+{
+}
+
+void Waiter::clear()
+{
+ ssize_t got{0};
+ do {
+ char data{0};
+ got = read(d_fd.getHandle(), &data, sizeof(data));
+ if (got == 0) {
+ d_closed = true;
+ if (!d_throwOnEOF) {
+ return;
+ }
+ throw std::runtime_error("EOF while clearing channel notifier pipe");
+ }
+ if (got == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ break;
+ }
+ throw std::runtime_error("Error while clearing channel notifier pipe: " + stringerror());
+ }
+ } while (got > 0);
+}
+
+int Waiter::getDescriptor() const
+{
+ return d_fd.getHandle();
+}
+
+std::pair<Notifier, Waiter> createNotificationQueue(bool nonBlocking, size_t pipeBufferSize, bool throwOnEOF)
+{
+ std::array<int, 2> fds = {-1, -1};
+ if (pipe(fds.data()) < 0) {
+ throw std::runtime_error("Error creating notification channel pipe: " + stringerror());
+ }
+
+ FDWrapper sender(fds[1]);
+ FDWrapper receiver(fds[0]);
+
+ if (nonBlocking && !setNonBlocking(receiver.getHandle())) {
+ int err = errno;
+ throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err));
+ }
+
+ if (nonBlocking && !setNonBlocking(sender.getHandle())) {
+ int err = errno;
+ throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err));
+ }
+
+ if (pipeBufferSize > 0 && getPipeBufferSize(receiver.getHandle()) < pipeBufferSize) {
+ setPipeBufferSize(receiver.getHandle(), pipeBufferSize);
+ }
+
+ return {Notifier(std::move(sender)), Waiter(std::move(receiver), throwOnEOF)};
+}
+}
diff --git a/channel.hh b/channel.hh
new file mode 100644
index 0000000..a7ba0ee
--- /dev/null
+++ b/channel.hh
@@ -0,0 +1,356 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <memory>
+#include <optional>
+
+#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(<sanitizer/tsan_interface.h>)
+#include <sanitizer/tsan_interface.h>
+#else /* __has_include(<sanitizer/tsan_interface.h>) */
+extern "C" void __tsan_acquire(void* addr);
+extern "C" void __tsan_release(void* addr);
+#endif /* __has_include(<sanitizer/tsan_interface.h>) */
+#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__ */
+
+namespace pdns
+{
+namespace channel
+{
+ enum class SenderBlockingMode
+ {
+ SenderNonBlocking,
+ SenderBlocking
+ };
+ enum class ReceiverBlockingMode
+ {
+ ReceiverNonBlocking,
+ ReceiverBlocking
+ };
+
+ /**
+ * The sender's end of a channel used to pass objects between threads.
+ *
+ * A sender can be used by several threads in a safe way.
+ */
+ template <typename T, typename D = std::default_delete<T>>
+ class Sender
+ {
+ public:
+ Sender() = default;
+ Sender(FDWrapper&& descriptor) :
+ d_fd(std::move(descriptor))
+ {
+ }
+ Sender(const Sender&) = delete;
+ Sender& operator=(const Sender&) = delete;
+ Sender(Sender&&) = default;
+ Sender& operator=(Sender&&) = default;
+ ~Sender() = default;
+ /**
+ * \brief Try to send the supplied object to the other end of that channel. Might block if the channel was created in blocking mode.
+ *
+ * \return True if the object was properly sent, False if the channel is full.
+ *
+ * \throw runtime_error if the channel is broken, for example if the other end has been closed.
+ */
+ bool send(std::unique_ptr<T, D>&&) const;
+ void close();
+
+ private:
+ FDWrapper d_fd;
+ };
+
+ /**
+ * The receiver's end of a channel used to pass objects between threads.
+ *
+ * A receiver can be used by several threads in a safe way, but in that case spurious wake up might happen.
+ */
+ template <typename T, typename D = std::default_delete<T>>
+ class Receiver
+ {
+ public:
+ Receiver() = default;
+ Receiver(FDWrapper&& descriptor, bool throwOnEOF = true) :
+ d_fd(std::move(descriptor)), d_throwOnEOF(throwOnEOF)
+ {
+ }
+ Receiver(const Receiver&) = delete;
+ Receiver& operator=(const Receiver&) = delete;
+ Receiver(Receiver&&) = default;
+ Receiver& operator=(Receiver&&) = default;
+ ~Receiver() = default;
+ /**
+ * \brief Try to read an object sent by the other end of that channel. Might block if the channel was created in blocking mode.
+ *
+ * \return An object if one was available, and std::nullopt otherwise.
+ *
+ * \throw runtime_error if the channel is broken, for example if the other end has been closed.
+ */
+ std::optional<std::unique_ptr<T, D>> receive();
+ std::optional<std::unique_ptr<T, D>> receive(D deleter);
+
+ /**
+ * \brief Get a descriptor that can be used with an I/O multiplexer to wait for an object to become available.
+ *
+ * \return A valid descriptor or -1 if the Receiver was not properly initialized.
+ */
+ int getDescriptor() const
+ {
+ return d_fd.getHandle();
+ }
+ /**
+ * \brief Whether the remote end has closed the channel.
+ */
+ bool isClosed() const
+ {
+ return d_closed;
+ }
+
+ private:
+ FDWrapper d_fd;
+ bool d_closed{false};
+ bool d_throwOnEOF{true};
+ };
+
+ /**
+ * \brief Create a channel to pass objects between threads, accepting multiple senders and receivers.
+ *
+ * \return A pair of Sender and Receiver objects.
+ *
+ * \throw runtime_error if the channel creation failed.
+ */
+ template <typename T, typename D = std::default_delete<T>>
+ std::pair<Sender<T, D>, Receiver<T, D>> createObjectQueue(SenderBlockingMode senderBlockingMode = SenderBlockingMode::SenderNonBlocking, ReceiverBlockingMode receiverBlockingMode = ReceiverBlockingMode::ReceiverNonBlocking, size_t pipeBufferSize = 0, bool throwOnEOF = true);
+
+ /**
+ * The notifier's end of a channel used to communicate between threads.
+ *
+ * A notifier can be used by several threads in a safe way.
+ */
+ class Notifier
+ {
+ public:
+ Notifier() = default;
+ Notifier(FDWrapper&&);
+ Notifier(const Notifier&) = delete;
+ Notifier& operator=(const Notifier&) = delete;
+ Notifier(Notifier&&) = default;
+ Notifier& operator=(Notifier&&) = default;
+ ~Notifier() = default;
+
+ /**
+ * \brief Queue a notification to wake up the other end of the channel.
+ *
+ * \return True if the notification was properly sent, False if the channel is full.
+ *
+ * \throw runtime_error if the channel is broken, for example if the other end has been closed.
+ */
+ bool notify() const;
+
+ private:
+ FDWrapper d_fd;
+ };
+
+ /**
+ * The waiter's end of a channel used to communicate between threads.
+ *
+ * A waiter can be used by several threads in a safe way, but in that case spurious wake up might happen.
+ */
+ class Waiter
+ {
+ public:
+ Waiter() = default;
+ Waiter(FDWrapper&&, bool throwOnEOF = true);
+ Waiter(const Waiter&) = delete;
+ Waiter& operator=(const Waiter&) = delete;
+ Waiter(Waiter&&) = default;
+ Waiter& operator=(Waiter&&) = default;
+ ~Waiter() = default;
+
+ /**
+ * \brief Clear all notifications queued on that channel, if any.
+ */
+ void clear();
+ /**
+ * \brief Get a descriptor that can be used with an I/O multiplexer to wait for a notification to arrive.
+ *
+ * \return A valid descriptor or -1 if the Waiter was not properly initialized.
+ */
+ int getDescriptor() const;
+ /**
+ * \brief Whether the remote end has closed the channel.
+ */
+ bool isClosed() const
+ {
+ return d_closed;
+ }
+
+ private:
+ FDWrapper d_fd;
+ bool d_closed{false};
+ bool d_throwOnEOF{true};
+ };
+
+ /**
+ * \brief Create a channel to notify one thread from another one, accepting multiple senders and receivers.
+ *
+ * \return A pair of Notifier and Sender objects.
+ *
+ * \throw runtime_error if the channel creation failed.
+ */
+ std::pair<Notifier, Waiter> createNotificationQueue(bool nonBlocking = true, size_t pipeBufferSize = 0, bool throwOnEOF = true);
+
+ template <typename T, typename D>
+ bool Sender<T, D>::send(std::unique_ptr<T, D>&& object) const
+ {
+ /* we cannot touch the initial unique pointer after writing to the pipe,
+ 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");
+ while (true) {
+#if __SANITIZE_THREAD__
+ __tsan_release(ptr);
+#endif /* __SANITIZE_THREAD__ */
+ ssize_t sent = write(d_fd.getHandle(), &ptr, sizeof(ptr));
+
+ if (sent == sizeof(ptr)) {
+ // coverity[leaked_storage]
+ localObj.release();
+ return true;
+ }
+ else if (sent == 0) {
+#if __SANITIZE_THREAD__
+ __tsan_acquire(ptr);
+#endif /* __SANITIZE_THREAD__ */
+ throw std::runtime_error("Unable to write to channel: remote end has been closed");
+ }
+ else {
+#if __SANITIZE_THREAD__
+ __tsan_acquire(ptr);
+#endif /* __SANITIZE_THREAD__ */
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ object = std::move(localObj);
+ return false;
+ }
+ else {
+ throw std::runtime_error("Unable to write to channel:" + stringerror());
+ }
+ }
+ }
+ }
+
+ template <typename T, typename D>
+ void Sender<T, D>::close()
+ {
+ d_fd.reset();
+ }
+
+ template <typename T, typename D>
+ std::optional<std::unique_ptr<T, D>> Receiver<T, D>::receive()
+ {
+ return receive(D());
+ }
+
+ template <typename T, typename D>
+ std::optional<std::unique_ptr<T, D>> Receiver<T, D>::receive(D deleter)
+ {
+ while (true) {
+ std::optional<std::unique_ptr<T, D>> result;
+ T* objPtr{nullptr};
+ ssize_t got = read(d_fd.getHandle(), &objPtr, sizeof(objPtr));
+ if (got == sizeof(objPtr)) {
+#if __SANITIZE_THREAD__
+ __tsan_acquire(objPtr);
+#endif /* __SANITIZE_THREAD__ */
+ return std::unique_ptr<T, D>(objPtr, deleter);
+ }
+ else if (got == 0) {
+ d_closed = true;
+ if (!d_throwOnEOF) {
+ return result;
+ }
+ throw std::runtime_error("EOF while reading from Channel receiver");
+ }
+ else if (got == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return result;
+ }
+ throw std::runtime_error("Error while reading from Channel receiver: " + stringerror());
+ }
+ else {
+ throw std::runtime_error("Partial read from Channel receiver");
+ }
+ }
+ }
+
+ template <typename T, typename D>
+ std::pair<Sender<T, D>, Receiver<T, D>> createObjectQueue(SenderBlockingMode senderBlockingMode, ReceiverBlockingMode receiverBlockingMode, size_t pipeBufferSize, bool throwOnEOF)
+ {
+ int fds[2] = {-1, -1};
+ if (pipe(fds) < 0) {
+ throw std::runtime_error("Error creating channel pipe: " + stringerror());
+ }
+
+ FDWrapper sender(fds[1]);
+ FDWrapper receiver(fds[0]);
+ if (receiverBlockingMode == ReceiverBlockingMode::ReceiverNonBlocking && !setNonBlocking(receiver.getHandle())) {
+ int err = errno;
+ throw std::runtime_error("Error making channel pipe non-blocking: " + stringerror(err));
+ }
+
+ if (senderBlockingMode == SenderBlockingMode::SenderNonBlocking && !setNonBlocking(sender.getHandle())) {
+ int err = errno;
+ throw std::runtime_error("Error making channel pipe non-blocking: " + stringerror(err));
+ }
+
+ if (pipeBufferSize > 0 && getPipeBufferSize(receiver.getHandle()) < pipeBufferSize) {
+ setPipeBufferSize(receiver.getHandle(), pipeBufferSize);
+ }
+
+ return {Sender<T, D>(std::move(sender)), Receiver<T, D>(std::move(receiver), throwOnEOF)};
+ }
+}
+}
diff --git a/compile b/compile
index 99e5052..df363c8 100755
--- a/compile
+++ b/compile
@@ -3,7 +3,7 @@
scriptversion=2018-03-07.03; # UTC
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@@ -53,7 +53,7 @@ func_file_conv ()
MINGW*)
file_conv=mingw
;;
- CYGWIN*)
+ CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
@@ -67,7 +67,7 @@ func_file_conv ()
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
- cygwin/*)
+ cygwin/* | msys/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
diff --git a/config.guess b/config.guess
index 256083a..e81d3ae 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2018 Free Software Foundation, Inc.
+# Copyright 1992-2021 Free Software Foundation, Inc.
-timestamp='2018-03-08'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2021-06-03'
# 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
@@ -27,11 +29,19 @@ timestamp='2018-03-08'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to <config-patches@gnu.org>.
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
@@ -50,7 +60,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2021 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."
@@ -84,7 +94,8 @@ if test $# != 0; then
exit 1
fi
-trap 'exit 1' 1 2 15
+# Just in case it came from the environment.
+GUESS=
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
@@ -96,73 +107,90 @@ trap 'exit 1' 1 2 15
# Portable tmp directory creation inspired by the Autoconf team.
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int x;" > "$dummy.c" ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+ # prevent multiple calls if $tmp is already set
+ test "$tmp" && return 0
+ : "${TMPDIR=/tmp}"
+ # shellcheck disable=SC2039,SC3028
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+ dummy=$tmp/dummy
+ case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+ ,,) echo "int x;" > "$dummy.c"
+ for driver in cc gcc c89 c99 ; do
+ if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD=$driver
+ break
+ fi
+ done
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+ esac
+}
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-case "$UNAME_SYSTEM" in
+case $UNAME_SYSTEM in
Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
+ LIBC=unknown
- eval "$set_cc_for_build"
+ set_cc_for_build
cat <<-EOF > "$dummy.c"
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
- #else
+ #elif defined(__GLIBC__)
LIBC=gnu
+ #else
+ #include <stdarg.h>
+ /* First heuristic to detect musl libc. */
+ #ifdef __DEFINED_va_list
+ LIBC=musl
+ #endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+ cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ eval "$cc_set_libc"
- # If ldd exists, use it to detect musl libc.
- if command -v ldd >/dev/null && \
- ldd --version 2>&1 | grep -q ^musl
- then
- LIBC=musl
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
fi
;;
esac
# Note: order is significant - the case branches are not exclusive.
-case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -174,12 +202,12 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
- "/sbin/$sysctl" 2>/dev/null || \
- "/usr/sbin/$sysctl" 2>/dev/null || \
+ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
echo unknown)`
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
+ aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
@@ -188,18 +216,18 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
earmv*)
arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
- machine="${arch}${endian}"-unknown
+ machine=${arch}${endian}-unknown
;;
- *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ *) machine=$UNAME_MACHINE_ARCH-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently (or will in the future) and ABI.
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
earm*)
os=netbsdelf
;;
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval "$set_cc_for_build"
+ set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
then
@@ -215,7 +243,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
;;
esac
# Determine ABI tags.
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
@@ -226,7 +254,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# thus, need a distinct triplet. However, they do not need
# kernel version information, so it can be replaced with a
# suitable tag, in the style of linux-gnu.
- case "$UNAME_VERSION" in
+ case $UNAME_VERSION in
Debian*)
release='-gnu'
;;
@@ -237,45 +265,57 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "$machine-${os}${release}${abi}"
- exit ;;
+ GUESS=$machine-${os}${release}${abi-}
+ ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+ ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+ ;;
+ *:SecBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+ ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+ ;;
*:MidnightBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+ ;;
*:ekkoBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+ ;;
*:SolidBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+ ;;
+ *:OS108:*:*)
+ GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+ ;;
macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:MirBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:Sortix:*:*)
- echo "$UNAME_MACHINE"-unknown-sortix
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sortix
+ ;;
+ *:Twizzler:*:*)
+ GUESS=$UNAME_MACHINE-unknown-twizzler
+ ;;
*:Redox:*:*)
- echo "$UNAME_MACHINE"-unknown-redox
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-redox
+ ;;
mips:OSF1:*.*)
- echo mips-dec-osf1
- exit ;;
+ GUESS=mips-dec-osf1
+ ;;
alpha:OSF1:*:*)
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ trap '' 0
case $UNAME_RELEASE in
*4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
@@ -289,7 +329,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
- case "$ALPHA_CPU_TYPE" in
+ case $ALPHA_CPU_TYPE in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
"EV4.5 (21064)")
@@ -326,75 +366,76 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
- # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
- exitcode=$?
- trap '' 0
- exit $exitcode ;;
+ OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+ ;;
Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
+ GUESS=m68k-unknown-sysv4
+ ;;
*:[Aa]miga[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-amigaos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-amigaos
+ ;;
*:[Mm]orph[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-morphos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-morphos
+ ;;
*:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
+ GUESS=i370-ibm-openedition
+ ;;
*:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
+ GUESS=s390-ibm-zvmoe
+ ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
+ GUESS=powerpc-ibm-os400
+ ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix"$UNAME_RELEASE"
- exit ;;
+ GUESS=arm-acorn-riscix$UNAME_RELEASE
+ ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
+ GUESS=arm-unknown-riscos
+ ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
+ GUESS=hppa1.1-hitachi-hiuxmpp
+ ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
+ case `(/bin/universe) 2>/dev/null` in
+ att) GUESS=pyramid-pyramid-sysv3 ;;
+ *) GUESS=pyramid-pyramid-bsd ;;
+ esac
+ ;;
NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
+ GUESS=pyramid-pyramid-svr4
+ ;;
DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
+ GUESS=sparc-icl-nx6
+ ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
+ sparc) GUESS=sparc-icl-nx7 ;;
+ esac
+ ;;
s390x:SunOS:*:*)
- echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+ ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-hal-solaris2$SUN_REL
+ ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris2$SUN_REL
+ ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
- echo i386-pc-auroraux"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-pc-auroraux$UNAME_RELEASE
+ ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ 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) | \
grep IS_64BIT_ARCH >/dev/null
@@ -402,41 +443,44 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
SUN_ARCH=x86_64
fi
fi
- echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+ ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris3$SUN_REL
+ ;;
sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
+ case `/usr/bin/arch -k` in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+ GUESS=sparc-sun-sunos$SUN_REL
+ ;;
sun3*:SunOS:*:*)
- echo m68k-sun-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
+ ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
- case "`/bin/arch`" in
+ case `/bin/arch` in
sun3)
- echo m68k-sun-sunos"$UNAME_RELEASE"
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
;;
sun4)
- echo sparc-sun-sunos"$UNAME_RELEASE"
+ GUESS=sparc-sun-sunos$UNAME_RELEASE
;;
esac
- exit ;;
+ ;;
aushp:SunOS:*:*)
- echo sparc-auspex-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-auspex-sunos$UNAME_RELEASE
+ ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
@@ -446,43 +490,43 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-milan-mint$UNAME_RELEASE
+ ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-hades-mint$UNAME_RELEASE
+ ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-mint$UNAME_RELEASE
+ ;;
m68k:machten:*:*)
- echo m68k-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-machten$UNAME_RELEASE
+ ;;
powerpc:machten:*:*)
- echo powerpc-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-machten$UNAME_RELEASE
+ ;;
RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
+ GUESS=mips-dec-mach_bsd4.3
+ ;;
RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dec-ultrix$UNAME_RELEASE
+ ;;
VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=vax-dec-ultrix$UNAME_RELEASE
+ ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix"$UNAME_RELEASE"
- exit ;;
+ GUESS=clipper-intergraph-clix$UNAME_RELEASE
+ ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#ifdef __cplusplus
#include <stdio.h> /* for printf() prototype */
@@ -508,78 +552,79 @@ EOF
dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-mips-riscos$UNAME_RELEASE
+ ;;
Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
+ GUESS=powerpc-motorola-powermax
+ ;;
Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
+ GUESS=powerpc-harris-powerunix
+ ;;
m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
+ GUESS=m88k-harris-cxux7
+ ;;
m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
+ GUESS=m88k-motorola-sysv4
+ ;;
m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
- if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
- [ "$TARGET_BINARY_INTERFACE"x = x ]
+ if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+ test "$TARGET_BINARY_INTERFACE"x = x
then
- echo m88k-dg-dgux"$UNAME_RELEASE"
+ GUESS=m88k-dg-dgux$UNAME_RELEASE
else
- echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
fi
else
- echo i586-dg-dgux"$UNAME_RELEASE"
+ GUESS=i586-dg-dgux$UNAME_RELEASE
fi
- exit ;;
+ ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
+ GUESS=m88k-dolphin-sysv3
+ ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
+ GUESS=m88k-tektronix-sysv3
+ ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
+ GUESS=m68k-tektronix-bsd
+ ;;
*:IRIX*:*:*)
- echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
- exit ;;
+ IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+ GUESS=mips-sgi-irix$IRIX_REL
+ ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
+ GUESS=i386-ibm-aix
+ ;;
ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
+ if test -x /usr/bin/oslevel ; then
IBM_REV=`/usr/bin/oslevel`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+ ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
@@ -593,16 +638,16 @@ EOF
EOF
if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
then
- echo "$SYSTEM_NAME"
+ GUESS=$SYSTEM_NAME
else
- echo rs6000-ibm-aix3.2.5
+ GUESS=rs6000-ibm-aix3.2.5
fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
+ GUESS=rs6000-ibm-aix3.2.4
else
- echo rs6000-ibm-aix3.2
+ GUESS=rs6000-ibm-aix3.2
fi
- exit ;;
+ ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
@@ -610,57 +655,57 @@ EOF
else
IBM_ARCH=powerpc
fi
- if [ -x /usr/bin/lslpp ] ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ if test -x /usr/bin/lslpp ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+ ;;
*:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
+ GUESS=rs6000-ibm-aix
+ ;;
ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
+ GUESS=romp-ibm-bsd4.4
+ ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
+ GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to
+ ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
+ GUESS=rs6000-bull-bosx
+ ;;
DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
+ GUESS=m68k-bull-sysv3
+ ;;
9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
+ GUESS=m68k-hp-bsd
+ ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
+ GUESS=m68k-hp-bsd4.4
+ ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
- case "$UNAME_MACHINE" in
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ case $UNAME_MACHINE in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
+ if test -x /usr/bin/getconf; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "$sc_cpu_version" in
+ case $sc_cpu_version in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
- case "$sc_kernel_bits" in
+ case $sc_kernel_bits in
32) HP_ARCH=hppa2.0n ;;
64) HP_ARCH=hppa2.0w ;;
'') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;;
esac
fi
- if [ "$HP_ARCH" = "" ]; then
- eval "$set_cc_for_build"
+ if test "$HP_ARCH" = ""; then
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#define _HPUX_SOURCE
@@ -698,9 +743,9 @@ EOF
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ "$HP_ARCH" = hppa2.0w ]
+ if test "$HP_ARCH" = hppa2.0w
then
- eval "$set_cc_for_build"
+ set_cc_for_build
# hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
# 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
@@ -719,14 +764,14 @@ EOF
HP_ARCH=hppa64
fi
fi
- echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
- exit ;;
+ GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+ ;;
ia64:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux"$HPUX_REV"
- exit ;;
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ GUESS=ia64-hp-hpux$HPUX_REV
+ ;;
3050*:HI-UX:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#include <unistd.h>
int
@@ -754,36 +799,36 @@ EOF
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
+ GUESS=unknown-hitachi-hiuxwe2
+ ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
- echo hppa1.1-hp-bsd
- exit ;;
+ GUESS=hppa1.1-hp-bsd
+ ;;
9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
+ GUESS=hppa1.0-hp-bsd
+ ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
+ GUESS=hppa1.0-hp-mpeix
+ ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
- echo hppa1.1-hp-osf
- exit ;;
+ GUESS=hppa1.1-hp-osf
+ ;;
hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
+ GUESS=hppa1.0-hp-osf
+ ;;
i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo "$UNAME_MACHINE"-unknown-osf1mk
+ if test -x /usr/sbin/sysversion ; then
+ GUESS=$UNAME_MACHINE-unknown-osf1mk
else
- echo "$UNAME_MACHINE"-unknown-osf1
+ GUESS=$UNAME_MACHINE-unknown-osf1
fi
- exit ;;
+ ;;
parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
+ GUESS=hppa1.1-hp-lites
+ ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
+ GUESS=c1-convex-bsd
+ ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
@@ -791,17 +836,18 @@ EOF
fi
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
+ GUESS=c34-convex-bsd
+ ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
+ GUESS=c38-convex-bsd
+ ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
+ GUESS=c4-convex-bsd
+ ;;
CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=ymp-cray-unicos$CRAY_REL
+ ;;
CRAY*[A-Z]90:*:*:*)
echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -809,103 +855,126 @@ EOF
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
- echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=t90-cray-unicos$CRAY_REL
+ ;;
CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=alphaev5-cray-unicosmk$CRAY_REL
+ ;;
CRAY*SV1:*:*:*)
- echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=sv1-cray-unicos$CRAY_REL
+ ;;
*:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=craynv-cray-unicosmp$CRAY_REL
+ ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+ ;;
sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+ ;;
*:BSD/OS:*:*)
- echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+ ;;
+ arm:FreeBSD:*:*)
+ UNAME_PROCESSOR=`uname -p`
+ set_cc_for_build
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
+ else
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
+ fi
+ ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
- case "$UNAME_PROCESSOR" in
+ case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
- echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
- exit ;;
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+ ;;
i*:CYGWIN*:*)
- echo "$UNAME_MACHINE"-pc-cygwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-cygwin
+ ;;
*:MINGW64*:*)
- echo "$UNAME_MACHINE"-pc-mingw64
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw64
+ ;;
*:MINGW*:*)
- echo "$UNAME_MACHINE"-pc-mingw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw32
+ ;;
*:MSYS*:*)
- echo "$UNAME_MACHINE"-pc-msys
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msys
+ ;;
i*:PW*:*)
- echo "$UNAME_MACHINE"-pc-pw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-pw32
+ ;;
*:Interix*:*)
- case "$UNAME_MACHINE" in
+ case $UNAME_MACHINE in
x86)
- echo i586-pc-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=i586-pc-interix$UNAME_RELEASE
+ ;;
authenticamd | genuineintel | EM64T)
- echo x86_64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=x86_64-unknown-interix$UNAME_RELEASE
+ ;;
IA64)
- echo ia64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=ia64-unknown-interix$UNAME_RELEASE
+ ;;
esac ;;
i*:UWIN*:*)
- echo "$UNAME_MACHINE"-pc-uwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-uwin
+ ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
+ GUESS=x86_64-pc-cygwin
+ ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=powerpcle-unknown-solaris2$SUN_REL
+ ;;
*:GNU:*:*)
# the GNU system
- echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
- exit ;;
+ GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+ GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+ ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
- exit ;;
- i*86:Minix:*:*)
- echo "$UNAME_MACHINE"-pc-minix
- exit ;;
+ GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+ ;;
+ *:Minix:*:*)
+ GUESS=$UNAME_MACHINE-unknown-minix
+ ;;
aarch64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -916,183 +985,225 @@ EOF
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
arm*:Linux:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
else
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
fi
fi
- exit ;;
+ ;;
avr32*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
cris:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
crisv32:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
e2k:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
frv:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
hexagon:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+ ;;
ia64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
k1om:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m32r*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m68*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
mips:Linux:*:* | mips64:Linux:*:*)
- eval "$set_cc_for_build"
+ set_cc_for_build
+ IS_GLIBC=0
+ test x"${LIBC}" = xgnu && IS_GLIBC=1
sed 's/^ //' << EOF > "$dummy.c"
#undef CPU
- #undef ${UNAME_MACHINE}
- #undef ${UNAME_MACHINE}el
+ #undef mips
+ #undef mipsel
+ #undef mips64
+ #undef mips64el
+ #if ${IS_GLIBC} && defined(_ABI64)
+ LIBCABI=gnuabi64
+ #else
+ #if ${IS_GLIBC} && defined(_ABIN32)
+ LIBCABI=gnuabin32
+ #else
+ LIBCABI=${LIBC}
+ #endif
+ #endif
+
+ #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa64r6
+ #else
+ #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa32r6
+ #else
+ #if defined(__mips64)
+ CPU=mips64
+ #else
+ CPU=mips
+ #endif
+ #endif
+ #endif
+
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=${UNAME_MACHINE}el
+ MIPS_ENDIAN=el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=${UNAME_MACHINE}
+ MIPS_ENDIAN=
#else
- CPU=
+ MIPS_ENDIAN=
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
- test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+ cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+ eval "$cc_set_vars"
+ test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
openrisc*:Linux:*:*)
- echo or1k-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=or1k-unknown-linux-$LIBC
+ ;;
or32:Linux:*:* | or1k*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=sparc-unknown-linux-$LIBC
+ ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=hppa64-unknown-linux-$LIBC
+ ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
- PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
- *) echo hppa-unknown-linux-"$LIBC" ;;
+ PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+ PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+ *) GUESS=hppa-unknown-linux-$LIBC ;;
esac
- exit ;;
+ ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64-unknown-linux-$LIBC
+ ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc-unknown-linux-$LIBC
+ ;;
ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64le-unknown-linux-$LIBC
+ ;;
ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-"$LIBC"
- exit ;;
- riscv32:Linux:*:* | riscv64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpcle-unknown-linux-$LIBC
+ ;;
+ riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+ ;;
sh64*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sh*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
tile*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
vax:Linux:*:*)
- echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+ ;;
x86_64:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
- exit ;;
+ set_cc_for_build
+ 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
+ fi
+ GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+ ;;
xtensa*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
+ GUESS=i386-sequent-sysv4
+ ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
- echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+ ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
- echo "$UNAME_MACHINE"-pc-os2-emx
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-os2-emx
+ ;;
i*86:XTS-300:*:STOP)
- echo "$UNAME_MACHINE"-unknown-stop
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-stop
+ ;;
i*86:atheos:*:*)
- echo "$UNAME_MACHINE"-unknown-atheos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-atheos
+ ;;
i*86:syllable:*:*)
- echo "$UNAME_MACHINE"-pc-syllable
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-syllable
+ ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
- echo i386-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-unknown-lynxos$UNAME_RELEASE
+ ;;
i*86:*DOS:*:*)
- echo "$UNAME_MACHINE"-pc-msdosdjgpp
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+ ;;
i*86:*:4.*:*)
UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
fi
- exit ;;
+ ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
@@ -1100,12 +1211,12 @@ EOF
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
- echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
elif /bin/uname -X 2>/dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1115,11 +1226,11 @@ EOF
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
- echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv32
+ GUESS=$UNAME_MACHINE-pc-sysv32
fi
- exit ;;
+ ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1127,31 +1238,31 @@ EOF
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
- echo i586-pc-msdosdjgpp
- exit ;;
+ GUESS=i586-pc-msdosdjgpp
+ ;;
Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
+ GUESS=i386-pc-mach3
+ ;;
paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
+ GUESS=i860-intel-osf1
+ ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4
fi
- exit ;;
+ ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
- echo m68010-convergent-sysv
- exit ;;
+ GUESS=m68010-convergent-sysv
+ ;;
mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
+ GUESS=m68k-convergent-sysv
+ ;;
M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
+ GUESS=m68k-diab-dnix
+ ;;
M68*:*:R3V[5678]*:*)
test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
@@ -1176,249 +1287,401 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+ ;;
mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
+ GUESS=m68k-atari-sysv4
+ ;;
TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+ ;;
rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+ ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
- echo powerpc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+ ;;
SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dde-sysv$UNAME_RELEASE
+ ;;
RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo "$UNAME_MACHINE"-sni-sysv4
+ GUESS=$UNAME_MACHINE-sni-sysv4
else
- echo ns32k-sni-sysv
+ GUESS=ns32k-sni-sysv
fi
- exit ;;
+ ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
+ GUESS=i586-unisys-sysv4
+ ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
+ GUESS=hppa1.1-stratus-sysv4
+ ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit ;;
+ GUESS=i860-stratus-sysv4
+ ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
- echo "$UNAME_MACHINE"-stratus-vos
- exit ;;
+ GUESS=$UNAME_MACHINE-stratus-vos
+ ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit ;;
+ GUESS=hppa1.1-stratus-vos
+ ;;
mc68*:A/UX:*:*)
- echo m68k-apple-aux"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-aux$UNAME_RELEASE
+ ;;
news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
+ GUESS=mips-sony-newsos6
+ ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv"$UNAME_RELEASE"
+ if test -d /usr/nec; then
+ GUESS=mips-nec-sysv$UNAME_RELEASE
else
- echo mips-unknown-sysv"$UNAME_RELEASE"
+ GUESS=mips-unknown-sysv$UNAME_RELEASE
fi
- exit ;;
+ ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
+ GUESS=powerpc-be-beos
+ ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
+ GUESS=powerpc-apple-beos
+ ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
+ GUESS=i586-pc-beos
+ ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
- echo i586-pc-haiku
- exit ;;
+ GUESS=i586-pc-haiku
+ ;;
x86_64:Haiku:*:*)
- echo x86_64-unknown-haiku
- exit ;;
+ GUESS=x86_64-unknown-haiku
+ ;;
SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx4-nec-superux$UNAME_RELEASE
+ ;;
SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx5-nec-superux$UNAME_RELEASE
+ ;;
SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx6-nec-superux$UNAME_RELEASE
+ ;;
SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx7-nec-superux$UNAME_RELEASE
+ ;;
SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8-nec-superux$UNAME_RELEASE
+ ;;
SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8r-nec-superux$UNAME_RELEASE
+ ;;
SX-ACE:SUPER-UX:*:*)
- echo sxace-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sxace-nec-superux$UNAME_RELEASE
+ ;;
Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+ ;;
*:Rhapsody:*:*)
- echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+ ;;
+ arm64:Darwin:*:*)
+ GUESS=aarch64-apple-darwin$UNAME_RELEASE
+ ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval "$set_cc_for_build"
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
+ UNAME_PROCESSOR=`uname -p`
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ if command -v xcode-select > /dev/null 2> /dev/null && \
+ ! xcode-select --print-path > /dev/null 2> /dev/null ; then
+ # Avoid executing cc if there is no toolchain installed as
+ # cc will be a stub that puts up a graphical alert
+ # prompting the user to install developer tools.
+ CC_FOR_BUILD=no_compiler_found
+ else
+ set_cc_for_build
fi
- if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
- # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
- if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_PPC >/dev/null
- then
- UNAME_PROCESSOR=powerpc
- fi
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
- # Avoid executing cc on OS X 10.9, as it ships with a stub
- # that puts up a graphical alert prompting to install
- # developer tools. Any system running Mac OS X 10.7 or
- # later (Darwin 11 and later) is required to have a 64-bit
- # processor. This is not true of the ARM version of Darwin
- # that Apple uses in portable devices.
- UNAME_PROCESSOR=x86_64
+ # uname -m returns i386 or x86_64
+ UNAME_PROCESSOR=$UNAME_MACHINE
fi
- echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+ ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
- echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+ ;;
*:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
+ GUESS=i386-pc-qnx
+ ;;
NEO-*:NONSTOP_KERNEL:*:*)
- echo neo-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=neo-tandem-nsk$UNAME_RELEASE
+ ;;
NSE-*:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nse-tandem-nsk$UNAME_RELEASE
+ ;;
NSR-*:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsr-tandem-nsk$UNAME_RELEASE
+ ;;
NSV-*:NONSTOP_KERNEL:*:*)
- echo nsv-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsv-tandem-nsk$UNAME_RELEASE
+ ;;
NSX-*:NONSTOP_KERNEL:*:*)
- echo nsx-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsx-tandem-nsk$UNAME_RELEASE
+ ;;
*:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
+ GUESS=mips-compaq-nonstopux
+ ;;
BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
+ GUESS=bs2000-siemens-sysv
+ ;;
DS/*:UNIX_System_V:*:*)
- echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+ ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- if test "$cputype" = 386; then
+ if test "${cputype-}" = 386; then
UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
+ elif test "x${cputype-}" != x; then
+ UNAME_MACHINE=$cputype
fi
- echo "$UNAME_MACHINE"-unknown-plan9
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-plan9
+ ;;
*:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
+ GUESS=pdp10-unknown-tops10
+ ;;
*:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
+ GUESS=pdp10-unknown-tenex
+ ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
+ GUESS=pdp10-dec-tops20
+ ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
+ GUESS=pdp10-xkl-tops20
+ ;;
*:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
+ GUESS=pdp10-unknown-tops20
+ ;;
*:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
+ GUESS=pdp10-unknown-its
+ ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-sei-seiux$UNAME_RELEASE
+ ;;
*:DragonFly:*:*)
- echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
- exit ;;
+ DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+ ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "$UNAME_MACHINE" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
+ case $UNAME_MACHINE in
+ A*) GUESS=alpha-dec-vms ;;
+ I*) GUESS=ia64-dec-vms ;;
+ V*) GUESS=vax-dec-vms ;;
esac ;;
*:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
+ GUESS=i386-pc-xenix
+ ;;
i*86:skyos:*:*)
- echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
- exit ;;
+ SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+ GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+ ;;
i*86:rdos:*:*)
- echo "$UNAME_MACHINE"-pc-rdos
- exit ;;
- i*86:AROS:*:*)
- echo "$UNAME_MACHINE"-pc-aros
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-rdos
+ ;;
+ *:AROS:*:*)
+ GUESS=$UNAME_MACHINE-unknown-aros
+ ;;
x86_64:VMkernel:*:*)
- echo "$UNAME_MACHINE"-unknown-esx
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-esx
+ ;;
amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
- exit ;;
+ GUESS=x86_64-unknown-onefs
+ ;;
+ *:Unleashed:*:*)
+ GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+ ;;
esac
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+ echo "$GUESS"
+ exit
+fi
+
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname un;
+ uname (&un);
+ printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname *un;
+ uname (&un);
+ printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
echo "$0: unable to guess system type" >&2
-case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+case $UNAME_MACHINE:$UNAME_SYSTEM in
mips:Linux | mips64:Linux)
# If we got here on MIPS GNU/Linux, output extra information.
cat >&2 <<EOF
@@ -1435,9 +1698,17 @@ This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite *all*
copies of config.guess and config.sub with the latest versions from:
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
and
- https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+ https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+EOF
+
+our_year=`echo $timestamp | sed 's,-.*,,'`
+thisyear=`date +%Y`
+# shellcheck disable=SC2003
+script_age=`expr "$thisyear" - "$our_year"`
+if test "$script_age" -lt 3 ; then
+ cat >&2 <<EOF
If $0 has already been updated, send the following data and any
information you think might be pertinent to config-patches@gnu.org to
@@ -1465,6 +1736,7 @@ UNAME_RELEASE = "$UNAME_RELEASE"
UNAME_SYSTEM = "$UNAME_SYSTEM"
UNAME_VERSION = "$UNAME_VERSION"
EOF
+fi
exit 1
diff --git a/config.h.in b/config.h.in
index 9bd40c5..bce954e 100644
--- a/config.h.in
+++ b/config.h.in
@@ -6,6 +6,15 @@
/* Define to 1 if you have the `accept4' function. */
#undef HAVE_ACCEPT4
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#undef HAVE_ARC4RANDOM_BUF
+
+/* Define to 1 if you have the `arc4random_uniform' function. */
+#undef HAVE_ARC4RANDOM_UNIFORM
+
/* Defined if the requested minimum BOOST version is satisfied */
#undef HAVE_BOOST
@@ -15,6 +24,12 @@
/* Defined if the Boost unit_test_framework library is available */
#undef HAVE_BOOST_UNIT_TEST_FRAMEWORK
+/* Define to 1 if you have the BPF library */
+#undef HAVE_BPF
+
+/* Define to 1 if you have the `bpf_xdp_query' function. */
+#undef HAVE_BPF_XDP_QUERY
+
/* Define to 1 if you have CDB */
#undef HAVE_CDB
@@ -58,9 +73,15 @@
/* Define to 1 if you enable dnscrypt support */
#undef HAVE_DNSCRYPT
+/* Define to 1 if you enable DNS over HTTP/3 support */
+#undef HAVE_DNS_OVER_HTTP3
+
/* Define to 1 if you enable DNS over HTTPS support */
#undef HAVE_DNS_OVER_HTTPS
+/* Define to 1 if you enable DNS over QUIC support */
+#undef HAVE_DNS_OVER_QUIC
+
/* Define to 1 if you enable DNS over TLS support */
#undef HAVE_DNS_OVER_TLS
@@ -91,6 +112,9 @@
/* 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. */
+#undef HAVE_GETENTROPY
+
/* Define to 1 if you have getifaddrs */
#undef HAVE_GETIFADDRS
@@ -134,7 +158,7 @@
/* Define to 1 if you have libedit */
#undef HAVE_LIBEDIT
-/* Define to 1 if you have libh2o-evloop */
+/* Define to 1 if you enable h2o-evloop support */
#undef HAVE_LIBH2OEVLOOP
/* Define to 1 if you have libsodium */
@@ -161,8 +185,8 @@
/* Define to 1 if you have lua */
#undef HAVE_LUA
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
+/* Define to 1 if you have the `memset_s' function. */
+#undef HAVE_MEMSET_S
/* Define if using Net SNMP. */
#undef HAVE_NET_SNMP
@@ -170,6 +194,16 @@
/* Define to 1 if you have nghttp2 */
#undef HAVE_NGHTTP2
+/* Define to 1 if you have the `nghttp2_check_header_value_rfc9113' function.
+ */
+#undef HAVE_NGHTTP2_CHECK_HEADER_VALUE_RFC9113
+
+/* Define to 1 if you have the `nghttp2_check_method' function. */
+#undef HAVE_NGHTTP2_CHECK_METHOD
+
+/* Define to 1 if you have the `nghttp2_check_path' function. */
+#undef HAVE_NGHTTP2_CHECK_PATH
+
/* Define to 1 if you have the `OCSP_basic_sign' function. */
#undef HAVE_OCSP_BASIC_SIGN
@@ -206,6 +240,9 @@
/* 2-arg void pthread_set_name_np */
#undef HAVE_PTHREAD_SET_NAME_NP_2_VOID
+/* Define to 1 if you have quiche */
+#undef HAVE_QUICHE
+
/* Define to 1 if you have the `randombytes_stir' function. */
#undef HAVE_RANDOMBYTES_STIR
@@ -282,10 +319,13 @@
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
-/* Define to 1 if you have the `strerror_r' function. */
+/* Define if you have `strerror_r'. */
#undef HAVE_STRERROR_R
/* Define to 1 if you have the <strings.h> header file. */
@@ -297,6 +337,9 @@
/* Systemd available and enabled */
#undef HAVE_SYSTEMD
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
@@ -309,6 +352,12 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to 1 if you have the XDP library */
+#undef HAVE_XDP
+
+/* Define to 1 if you have AF_XDP (XSK) support enabled */
+#undef HAVE_XSK
+
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
@@ -342,7 +391,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 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
/* Define to 1 if strerror_r returns char *. */
diff --git a/config.sub b/config.sub
index 9ccf09a..d74fb6d 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2018 Free Software Foundation, Inc.
+# Copyright 1992-2021 Free Software Foundation, Inc.
-timestamp='2018-03-08'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2021-08-14'
# 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
@@ -33,7 +35,7 @@ timestamp='2018-03-08'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -50,6 +52,13 @@ timestamp='2018-03-08'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
@@ -67,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2018 Free Software Foundation, Inc.
+Copyright 1992-2021 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."
@@ -89,7 +98,7 @@ while test $# -gt 0 ; do
- ) # Use stdin as input.
break ;;
-* )
- echo "$me: invalid option $1$help"
+ echo "$me: invalid option $1$help" >&2
exit 1 ;;
*local*)
@@ -110,1223 +119,1181 @@ case $# in
exit 1;;
esac
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
- kopensolaris*-gnu* | cloudabi*-eabi* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- android-linux)
- os=-linux-android
- basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
- ;;
- *)
- basic_machine=`echo "$1" | sed 's/-[^-]*$//'`
- if [ "$basic_machine" != "$1" ]
- then os=`echo "$1" | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
+# Split fields of configuration type
+# shellcheck disable=SC2162
+saved_IFS=$IFS
+IFS="-" read field1 field2 field3 field4 <<EOF
+$1
+EOF
+IFS=$saved_IFS
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray | -microblaze*)
- os=
- basic_machine=$1
- ;;
- -bluegene*)
- os=-cnk
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*178)
- os=-lynxos178
- ;;
- -lynx*5)
- os=-lynxos5
+# Separate into logical components for further validation
+case $1 in
+ *-*-*-*-*)
+ echo Invalid configuration \`"$1"\': more than four components >&2
+ exit 1
;;
- -lynx*)
- os=-lynxos
+ *-*-*-*)
+ basic_machine=$field1-$field2
+ basic_os=$field3-$field4
;;
- -ptx*)
- basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'`
+ *-*-*)
+ # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+ # parts
+ maybe_os=$field2-$field3
+ case $maybe_os in
+ 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*)
+ basic_machine=$field1
+ basic_os=$maybe_os
+ ;;
+ android-linux)
+ basic_machine=$field1-unknown
+ basic_os=linux-android
+ ;;
+ *)
+ basic_machine=$field1-$field2
+ basic_os=$field3
+ ;;
+ esac
;;
- -psos*)
- os=-psos
+ *-*)
+ # A lone config we happen to match not fitting any pattern
+ case $field1-$field2 in
+ decstation-3100)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ *-*)
+ # Second component is usually, but not always the OS
+ case $field2 in
+ # Prevent following clause from handling this valid os
+ sun*os*)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
+ # Manufacturers
+ dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+ | unicom* | ibm* | next | hp | isi* | apollo | altos* \
+ | convergent* | ncr* | news | 32* | 3600* | 3100* \
+ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+ | ultra | tti* | harris | dolphin | highlevel | gould \
+ | cbm | ns | masscomp | apple | axis | knuth | cray \
+ | microblaze* | sim | cisco \
+ | oki | wec | wrs | winbond)
+ basic_machine=$field1-$field2
+ basic_os=
+ ;;
+ *)
+ basic_machine=$field1
+ basic_os=$field2
+ ;;
+ esac
+ ;;
+ esac
;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
+ *)
+ # Convert single-component short-hands not valid as part of
+ # multi-component configurations.
+ case $field1 in
+ 386bsd)
+ basic_machine=i386-pc
+ basic_os=bsd
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ basic_os=scout
+ ;;
+ alliant)
+ basic_machine=fx80-alliant
+ basic_os=
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ basic_os=
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ basic_os=bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ basic_os=sysv
+ ;;
+ amiga)
+ basic_machine=m68k-unknown
+ basic_os=
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ basic_os=amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ basic_os=sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ basic_os=sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ basic_os=bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ basic_os=aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ basic_os=aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ basic_os=dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ basic_os=linux
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ basic_os=cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ basic_os=bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ basic_os=bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ basic_os=bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ basic_os=bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ basic_os=bsd
+ ;;
+ cray)
+ basic_machine=j90-cray
+ basic_os=unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ basic_os=
+ ;;
+ da30)
+ basic_machine=m68k-da30
+ basic_os=
+ ;;
+ decstation | pmax | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ basic_os=
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ basic_os=sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ basic_os=dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ basic_os=msdosdjgpp
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ basic_os=ebmon
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ basic_os=ose
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ basic_os=sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ basic_os=go32
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ basic_os=hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ basic_os=xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ basic_os=hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ basic_os=sysv3
+ ;;
+ hp300 | hp300hpux)
+ basic_machine=m68k-hp
+ basic_os=hpux
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ basic_os=bsd
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ basic_os=osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ basic_os=proelf
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ basic_os=mach
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ basic_os=sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ basic_os=linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ basic_os=sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ basic_os=sysv
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ basic_os=mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ basic_os=mingw32ce
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ basic_os=morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ basic_os=moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ basic_os=msdos
+ ;;
+ msys)
+ basic_machine=i686-pc
+ basic_os=msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ basic_os=mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ basic_os=nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ basic_os=sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-pc
+ basic_os=netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ basic_os=linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ basic_os=newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ basic_os=newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ basic_os=sysv
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ basic_os=cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ basic_os=cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ basic_os=nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ basic_os=mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ basic_os=nonstopux
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ basic_os=os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ basic_os=ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ basic_os=os68k
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ basic_os=osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ basic_os=linux
+ ;;
+ psp)
+ basic_machine=mipsallegrexel-sony
+ basic_os=psp
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ basic_os=pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ basic_os=rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ basic_os=rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ basic_os=coff
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ sei)
+ basic_machine=mips-sei
+ basic_os=seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ basic_os=
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ basic_os=sysv2
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ basic_os=
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ basic_os=sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ basic_os=
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ basic_os=sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ basic_os=sunos4
+ ;;
+ sun3)
+ basic_machine=m68k-sun
+ basic_os=
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ basic_os=sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ basic_os=sunos4
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ basic_os=
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ basic_os=sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ basic_os=sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ basic_os=solaris2
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ basic_os=
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ basic_os=unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ basic_os=dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ basic_os=unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ basic_os=unicos
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ basic_os=tops20
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ basic_os=tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ basic_os=udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ basic_os=sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ basic_os=none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ basic_os=sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ basic_os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ basic_os=vsta
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ basic_os=vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ basic_os=vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ basic_os=vxworks
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ basic_os=mingw32
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ basic_os=unicos
+ ;;
+ *)
+ basic_machine=$1
+ basic_os=
+ ;;
+ esac
;;
esac
-# Decode aliases for certain CPU-COMPANY combinations.
+# Decode 1-component or ad-hoc basic machines
case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | aarch64 | aarch64_be \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arceb \
- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
- | avr | avr32 \
- | ba \
- | be32 | be64 \
- | bfin \
- | c4x | c8051 | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | epiphany \
- | fido | fr30 | frv | ft32 \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | hexagon \
- | i370 | i860 | i960 | ia16 | ia64 \
- | ip2k | iq2000 \
- | k1om \
- | le32 | le64 \
- | lm32 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | moxie \
- | mt \
- | msp430 \
- | nds32 | nds32le | nds32be \
- | nios | nios2 | nios2eb | nios2el \
- | ns16k | ns32k \
- | open8 | or1k | or1knd | or32 \
- | pdp10 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle \
- | pru \
- | pyramid \
- | riscv32 | riscv64 \
- | rl78 | rx \
- | score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu \
- | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
- | ubicom32 \
- | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
- | visium \
- | wasm32 \
- | x86 | xc16x | xstormy16 | xtensa \
- | z8k | z80)
- basic_machine=$basic_machine-unknown
- ;;
- c54x)
- basic_machine=tic54x-unknown
- ;;
- c55x)
- basic_machine=tic55x-unknown
- ;;
- c6x)
- basic_machine=tic6x-unknown
- ;;
- leon|leon[3-9])
- basic_machine=sparc-$basic_machine
+ # Here we handle the default manufacturer of certain CPU types. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ cpu=hppa1.1
+ vendor=winbond
;;
- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
- basic_machine=$basic_machine-unknown
- os=-none
+ op50n)
+ cpu=hppa1.1
+ vendor=oki
;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+ op60c)
+ cpu=hppa1.1
+ vendor=oki
;;
- ms1)
- basic_machine=mt-unknown
+ ibm*)
+ cpu=i370
+ vendor=ibm
;;
-
- strongarm | thumb | xscale)
- basic_machine=arm-unknown
- ;;
- xgate)
- basic_machine=$basic_machine-unknown
- os=-none
+ orion105)
+ cpu=clipper
+ vendor=highlevel
;;
- xscaleeb)
- basic_machine=armeb-unknown
+ mac | mpw | mac-mpw)
+ cpu=m68k
+ vendor=apple
;;
-
- xscaleel)
- basic_machine=armel-unknown
+ pmac | pmac-mpw)
+ cpu=powerpc
+ vendor=apple
;;
- # 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)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | aarch64-* | aarch64_be-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | ba-* \
- | be32-* | be64-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* \
- | c8051-* | clipper-* | craynv-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | e2k-* | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | hexagon-* \
- | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
- | ip2k-* | iq2000-* \
- | k1om-* \
- | le32-* | le64-* \
- | lm32-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | microblaze-* | microblazeel-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64octeon-* | mips64octeonel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64r5900-* | mips64r5900el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa32r6-* | mipsisa32r6el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64r6-* | mipsisa64r6el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nds32-* | nds32le-* | nds32be-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | open8-* \
- | or1k*-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
- | pru-* \
- | pyramid-* \
- | riscv32-* | riscv64-* \
- | rl78-* | romp-* | rs6000-* | rx-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
- | tahoe-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
- | tile*-* \
- | tron-* \
- | ubicom32-* \
- | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
- | vax-* \
- | visium-* \
- | wasm32-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* \
- | xstormy16-* | xtensa*-* \
- | ymp-* \
- | z8k-* | z80-*)
- ;;
- # Recognize the basic CPU types without company name, with glob match.
- xtensa*)
- basic_machine=$basic_machine-unknown
- ;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-pc
- os=-bsd
- ;;
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
+ cpu=m68000
+ vendor=att
;;
3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aros)
- basic_machine=i386-pc
- os=-aros
- ;;
- asmjs)
- basic_machine=asmjs-unknown
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- blackfin)
- basic_machine=bfin-unknown
- os=-linux
- ;;
- blackfin-*)
- basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=-linux
+ cpu=we32k
+ vendor=att
;;
bluegene*)
- basic_machine=powerpc-ibm
- os=-cnk
- ;;
- c54x-*)
- basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c55x-*)
- basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c6x-*)
- basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- cegcc)
- basic_machine=arm-unknown
- os=-cegcc
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- craynv)
- basic_machine=craynv-cray
- os=-unicosmp
- ;;
- cr16 | cr16-*)
- basic_machine=cr16-unknown
- os=-elf
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=-elf
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
+ cpu=powerpc
+ vendor=ibm
+ basic_os=cnk
;;
decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops10
;;
decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
+ cpu=pdp10
+ vendor=dec
+ basic_os=tops20
;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dicos)
- basic_machine=i686-pc
- os=-dicos
- ;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
+ cpu=m68k
+ vendor=motorola
;;
dpx2*)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- e500v[12])
- basic_machine=powerpc-unknown
- os=$os"spe"
- ;;
- e500v[12]-*)
- basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=$os"spe"
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
+ cpu=m68k
+ vendor=bull
+ basic_os=sysv3
;;
encore | umax | mmax)
- basic_machine=ns32k-encore
+ cpu=ns32k
+ vendor=encore
;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
+ elxsi)
+ cpu=elxsi
+ vendor=elxsi
+ basic_os=${basic_os:-bsd}
;;
fx2800)
- basic_machine=i860-alliant
+ cpu=i860
+ vendor=alliant
;;
genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
+ cpu=ns32k
+ vendor=ns
;;
h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
+ cpu=m68000
+ vendor=hp
;;
hp9k3[2-9][0-9])
- basic_machine=m68k-hp
+ cpu=m68k
+ vendor=hp
;;
hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k78[0-9] | hp78[0-9])
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
+ cpu=hppa1.0
+ vendor=hp
;;
i*86v32)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=-sysv32
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv32
;;
i*86v4*)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=-sysv4
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv4
;;
i*86v)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=-sysv
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=sysv
;;
i*86sol2)
- basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
- os=-solaris2
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ basic_os=solaris2
;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- vsta)
- basic_machine=i386-unknown
- os=-vsta
+ j90 | j90-cray)
+ cpu=j90
+ vendor=cray
+ basic_os=${basic_os:-unicos}
;;
iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
+ cpu=mips
+ vendor=sgi
+ case $basic_os in
+ irix*)
;;
*)
- os=-irix4
+ basic_os=irix4
;;
esac
;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- leon-*|leon[3-9]-*)
- basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
- ;;
- m68knommu)
- basic_machine=m68k-unknown
- os=-linux
- ;;
- m68knommu-*)
- basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- microblaze*)
- basic_machine=microblaze-xilinx
- ;;
- mingw64)
- basic_machine=x86_64-pc
- os=-mingw64
- ;;
- mingw32)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- mingw32ce)
- basic_machine=arm-unknown
- os=-mingw32ce
- ;;
miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- moxiebox)
- basic_machine=moxie-unknown
- os=-moxiebox
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
+ cpu=m68000
+ vendor=convergent
;;
- ms1-*)
- basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
- ;;
- msys)
- basic_machine=i686-pc
- os=-msys
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- nacl)
- basic_machine=le32-unknown
- os=-nacl
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
+ *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ cpu=m68k
+ vendor=atari
+ basic_os=mint
;;
news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
+ cpu=mips
+ vendor=sony
+ basic_os=newsos
;;
next | m*-next)
- basic_machine=m68k-next
- case $os in
- -nextstep* )
+ cpu=m68k
+ vendor=next
+ case $basic_os in
+ openstep*)
+ ;;
+ nextstep*)
;;
- -ns2*)
- os=-nextstep2
+ ns2*)
+ basic_os=nextstep2
;;
*)
- os=-nextstep3
+ basic_os=nextstep3
;;
esac
;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
np1)
- basic_machine=np1-gould
- ;;
- neo-tandem)
- basic_machine=neo-tandem
- ;;
- nse-tandem)
- basic_machine=nse-tandem
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
- ;;
- nsv-tandem)
- basic_machine=nsv-tandem
- ;;
- nsx-tandem)
- basic_machine=nsx-tandem
+ cpu=np1
+ vendor=gould
;;
op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
- ;;
- os400)
- basic_machine=powerpc-ibm
- os=-os400
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
+ cpu=hppa1.1
+ vendor=oki
+ basic_os=proelf
;;
pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- parisc)
- basic_machine=hppa-unknown
- os=-linux
- ;;
- parisc-*)
- basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- os=-linux
+ cpu=hppa1.1
+ vendor=hitachi
+ basic_os=hiuxwe2
;;
pbd)
- basic_machine=sparc-tti
+ cpu=sparc
+ vendor=tti
;;
pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
- ;;
- pentium4)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ cpu=m68k
+ vendor=tti
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- pentium4-*)
- basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ pc532)
+ cpu=ns32k
+ vendor=pc532
;;
pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc | ppcbe) basic_machine=powerpc-unknown
- ;;
- ppc-* | ppcbe-*)
- basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle)
- basic_machine=powerpcle-unknown
+ cpu=pn
+ vendor=gould
;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ power)
+ cpu=power
+ vendor=ibm
;;
- ppc64) basic_machine=powerpc64-unknown
+ ps2)
+ cpu=i386
+ vendor=ibm
;;
- ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ rm[46]00)
+ cpu=mips
+ vendor=siemens
;;
- ppc64le | powerpc64little)
- basic_machine=powerpc64le-unknown
+ rtpc | rtpc-*)
+ cpu=romp
+ vendor=ibm
;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ sde)
+ cpu=mipsisa32
+ vendor=sde
+ basic_os=${basic_os:-elf}
;;
- ps2)
- basic_machine=i386-ibm
+ simso-wrs)
+ cpu=sparclite
+ vendor=wrs
+ basic_os=vxworks
;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
+ tower | tower-32)
+ cpu=m68k
+ vendor=ncr
;;
- rdos | rdos64)
- basic_machine=x86_64-pc
- os=-rdos
+ vpp*|vx|vx-*)
+ cpu=f301
+ vendor=fujitsu
;;
- rdos32)
- basic_machine=i386-pc
- os=-rdos
+ w65)
+ cpu=w65
+ vendor=wdc
;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
+ w89k-*)
+ cpu=hppa1.1
+ vendor=winbond
+ basic_os=proelf
;;
- rm[46]00)
- basic_machine=mips-siemens
+ none)
+ cpu=none
+ vendor=none
;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
+ leon|leon[3-9])
+ cpu=sparc
+ vendor=$basic_machine
;;
- s390 | s390-*)
- basic_machine=s390-ibm
+ leon-*|leon[3-9]-*)
+ cpu=sparc
+ vendor=`echo "$basic_machine" | sed 's/-.*//'`
;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
+
+ *-*)
+ # shellcheck disable=SC2162
+ saved_IFS=$IFS
+ IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
+ IFS=$saved_IFS
;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
+ # 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)
+ cpu=$basic_machine
+ vendor=pc
;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
+ # These rules are duplicated from below for sake of the special case above;
+ # i.e. things that normalized to x86 arches should also default to "pc"
+ pc98)
+ cpu=i386
+ vendor=pc
;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
+ x64 | amd64)
+ cpu=x86_64
+ vendor=pc
;;
- sde)
- basic_machine=mipsisa32-sde
- os=-elf
+ # Recognize the basic CPU types without company name.
+ *)
+ cpu=$basic_machine
+ vendor=unknown
;;
- sei)
- basic_machine=mips-sei
- os=-seiux
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+ # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ craynv-unknown)
+ vendor=cray
+ basic_os=${basic_os:-unicosmp}
;;
- sequent)
- basic_machine=i386-sequent
+ c90-unknown | c90-cray)
+ vendor=cray
+ basic_os=${Basic_os:-unicos}
;;
- sh5el)
- basic_machine=sh5le-unknown
+ fx80-unknown)
+ vendor=alliant
;;
- simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
+ romp-unknown)
+ vendor=ibm
;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
+ mmix-unknown)
+ vendor=knuth
;;
- spur)
- basic_machine=spur-unknown
+ microblaze-unknown | microblazeel-unknown)
+ vendor=xilinx
;;
- st2000)
- basic_machine=m68k-tandem
+ rs6000-unknown)
+ vendor=ibm
;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
+ vax-unknown)
+ vendor=dec
;;
- strongarm-* | thumb-*)
- basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ pdp11-unknown)
+ vendor=dec
;;
- sun2)
- basic_machine=m68000-sun
+ we32k-unknown)
+ vendor=att
;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
+ cydra-unknown)
+ vendor=cydrome
;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
+ i370-ibm*)
+ vendor=ibm
;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
+ orion-unknown)
+ vendor=highlevel
;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
+ xps-unknown | xps100-unknown)
+ cpu=xps100
+ vendor=honeywell
;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
+
+ # Here we normalize CPU types with a missing or matching vendor
+ dpx20-unknown | dpx20-bull)
+ cpu=rs6000
+ vendor=bull
+ basic_os=${basic_os:-bosx}
;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
+
+ # Here we normalize CPU types irrespective of the vendor
+ amd64-*)
+ cpu=x86_64
;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
+ blackfin-*)
+ cpu=bfin
+ basic_os=linux
;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
+ c54x-*)
+ cpu=tic54x
;;
- sun4)
- basic_machine=sparc-sun
+ c55x-*)
+ cpu=tic55x
;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
+ c6x-*)
+ cpu=tic6x
;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
+ e500v[12]-*)
+ cpu=powerpc
+ basic_os=${basic_os}"spe"
;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
+ mips3*-*)
+ cpu=mips64
;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
+ ms1-*)
+ cpu=mt
;;
- t90)
- basic_machine=t90-cray
- os=-unicos
+ m68knommu-*)
+ cpu=m68k
+ basic_os=linux
;;
- tile*)
- basic_machine=$basic_machine-unknown
- os=-linux-gnu
+ m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+ cpu=s12z
;;
- tx39)
- basic_machine=mipstx39-unknown
+ openrisc-*)
+ cpu=or32
;;
- tx39el)
- basic_machine=mipstx39el-unknown
+ parisc-*)
+ cpu=hppa
+ basic_os=linux
;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
;;
- tower | tower-32)
- basic_machine=m68k-ncr
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ cpu=i686
;;
- tpf)
- basic_machine=s390x-ibm
- os=-tpf
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ cpu=i686
;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
+ pentium4-*)
+ cpu=i786
;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
+ pc98-*)
+ cpu=i386
;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
+ ppc-* | ppcbe-*)
+ cpu=powerpc
;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
+ ppcle-* | powerpclittle-*)
+ cpu=powerpcle
;;
- vms)
- basic_machine=vax-dec
- os=-vms
+ ppc64-*)
+ cpu=powerpc64
;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
+ ppc64le-* | powerpc64little-*)
+ cpu=powerpc64le
;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
+ sb1-*)
+ cpu=mipsisa64sb1
;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
+ sb1el-*)
+ cpu=mipsisa64sb1el
;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
+ sh5e[lb]-*)
+ cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
;;
- w65*)
- basic_machine=w65-wdc
- os=-none
+ spur-*)
+ cpu=spur
;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
+ strongarm-* | thumb-*)
+ cpu=arm
;;
- x64)
- basic_machine=x86_64-pc
+ tx39-*)
+ cpu=mipstx39
;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
+ tx39el-*)
+ cpu=mipstx39el
;;
- xps | xps100)
- basic_machine=xps100-honeywell
+ x64-*)
+ cpu=x86_64
;;
xscale-* | xscalee[bl]-*)
- basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
- ;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
+ cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
- none)
- basic_machine=none-none
- os=-none
+ arm64-*)
+ cpu=aarch64
;;
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- mmix)
- basic_machine=mmix-knuth
+ # Recognize the canonical CPU Types that limit and/or modify the
+ # company names they are paired with.
+ cr16-*)
+ basic_os=${basic_os:-elf}
;;
- rs6000)
- basic_machine=rs6000-ibm
+ crisv32-* | etraxfs*-*)
+ cpu=crisv32
+ vendor=axis
;;
- vax)
- basic_machine=vax-dec
+ cris-* | etrax*-*)
+ cpu=cris
+ vendor=axis
;;
- pdp11)
- basic_machine=pdp11-dec
+ crx-*)
+ basic_os=${basic_os:-elf}
;;
- we32k)
- basic_machine=we32k-att
+ neo-tandem)
+ cpu=neo
+ vendor=tandem
;;
- sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
+ nse-tandem)
+ cpu=nse
+ vendor=tandem
;;
- cydra)
- basic_machine=cydra-cydrome
+ nsr-tandem)
+ cpu=nsr
+ vendor=tandem
;;
- orion)
- basic_machine=orion-highlevel
+ nsv-tandem)
+ cpu=nsv
+ vendor=tandem
;;
- orion105)
- basic_machine=clipper-highlevel
+ nsx-tandem)
+ cpu=nsx
+ vendor=tandem
;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
+ mipsallegrexel-sony)
+ cpu=mipsallegrexel
+ vendor=sony
;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
+ tile*-*)
+ basic_os=${basic_os:-linux-gnu}
;;
+
*)
- echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
- exit 1
+ # Recognize the canonical CPU types that are allowed with any
+ # company name.
+ case $cpu in
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | abacus \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+ | alphapca5[67] | alpha64pca5[67] \
+ | am33_2.0 \
+ | amdgcn \
+ | arc | arceb | arc32 | arc64 \
+ | arm | arm[lb]e | arme[lb] | armv* \
+ | avr | avr32 \
+ | asmjs \
+ | ba \
+ | be32 | be64 \
+ | bfin | bpf | bs2000 \
+ | c[123]* | c30 | [cjt]90 | c4x \
+ | c8051 | clipper | craynv | csky | cydra \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | elxsi | epiphany \
+ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+ | h8300 | h8500 \
+ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | loongarch32 | loongarch64 | loongarchx32 \
+ | 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 \
+ | mmix \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nfp \
+ | nios | nios2 | nios2eb | nios2el \
+ | none | np1 | ns16k | ns32k | nvptx \
+ | open8 \
+ | or1k* \
+ | or32 \
+ | orion \
+ | picochip \
+ | pdp10 | pdp11 | pj | pjl | pn | power \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pru \
+ | pyramid \
+ | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
+ | rl78 | romp | rs6000 | rx \
+ | s390 | s390x \
+ | score \
+ | sh | shl \
+ | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+ | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | spu \
+ | tahoe \
+ | thumbv7* \
+ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tron \
+ | ubicom32 \
+ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | vax \
+ | visium \
+ | w65 \
+ | wasm32 | wasm64 \
+ | we32k \
+ | x86 | x86_64 | xc16x | xgate | xps100 \
+ | xstormy16 | xtensa* \
+ | ymp \
+ | z8k | z80)
+ ;;
+
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ exit 1
+ ;;
+ esac
;;
esac
# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+case $vendor in
+ digital*)
+ vendor=dec
;;
- *-commodore*)
- basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+ commodore*)
+ vendor=cbm
;;
*)
;;
@@ -1334,203 +1301,215 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if [ x"$os" != x"" ]
+if test x$basic_os != x
then
+
+# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# set os.
+case $basic_os in
+ gnu/linux*)
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
+ ;;
+ os2-emx)
+ kernel=os2
+ os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
+ ;;
+ nto-qnx*)
+ kernel=nto
+ os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
+ ;;
+ *-*)
+ # shellcheck disable=SC2162
+ saved_IFS=$IFS
+ IFS="-" read kernel os <<EOF
+$basic_os
+EOF
+ IFS=$saved_IFS
+ ;;
+ # Default OS when just kernel was specified
+ nto*)
+ kernel=nto
+ os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
+ ;;
+ linux*)
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+ ;;
+ *)
+ kernel=
+ os=$basic_os
+ ;;
+esac
+
+# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+# etc.)
case $os in
# First match some system type aliases that might get confused
# with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -auroraux)
- os=-auroraux
+ # solaris* is a basic system type, with this one exception.
+ auroraux)
+ os=auroraux
;;
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ bluegene*)
+ os=cnk
;;
- -solaris)
- os=-solaris2
+ solaris1 | solaris1.*)
+ os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
;;
- -unixware*)
- os=-sysv4.2uw
+ solaris)
+ os=solaris2
;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ unixware*)
+ os=sysv4.2uw
;;
# es1800 is here to avoid being matched by es* (a different OS)
- -es1800*)
- os=-ose
+ es1800*)
+ os=ose
;;
- # Now accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST end in a * to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
- | -sym* | -kopensolaris* | -plan9* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* | -cloudabi* | -sortix* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \
- | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
- | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
- | -linux-newlib* | -linux-musl* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \
- | -midnightbsd*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=-nto$os
- ;;
- esac
+ # Some version numbers need modification
+ chorusos*)
+ os=chorusos
;;
- -nto-qnx*)
+ isc)
+ os=isc2.2
;;
- -nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ sco6)
+ os=sco5v6
;;
- -sim | -xray | -os68k* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ sco5)
+ os=sco3.2v5
;;
- -mac*)
- os=`echo "$os" | sed -e 's|mac|macos|'`
+ sco4)
+ os=sco3.2v4
;;
- -linux-dietlibc)
- os=-linux-dietlibc
+ sco3.2.[4-9]*)
+ os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ sco*v* | scout)
+ # Don't match below
;;
- -sunos5*)
- os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ sco*)
+ os=sco3.2v2
;;
- -sunos6*)
- os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ psos*)
+ os=psos
;;
- -opened*)
- os=-openedition
+ qnx*)
+ os=qnx
;;
- -os400*)
- os=-os400
+ hiux*)
+ os=hiuxwe2
;;
- -wince*)
- os=-wince
+ lynx*178)
+ os=lynxos178
;;
- -utek*)
- os=-bsd
+ lynx*5)
+ os=lynxos5
;;
- -dynix*)
- os=-bsd
+ lynxos*)
+ # don't get caught up in next wildcard
;;
- -acis*)
- os=-aos
+ lynx*)
+ os=lynxos
;;
- -atheos*)
- os=-atheos
+ mac[0-9]*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
;;
- -syllable*)
- os=-syllable
+ opened*)
+ os=openedition
;;
- -386bsd)
- os=-bsd
+ os400*)
+ os=os400
;;
- -ctix* | -uts*)
- os=-sysv
+ sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
;;
- -nova*)
- os=-rtmk-nova
+ sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
;;
- -ns2)
- os=-nextstep2
+ wince*)
+ os=wince
;;
- -nsk*)
- os=-nsk
+ utek*)
+ os=bsd
;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
+ dynix*)
+ os=bsd
;;
- -sinix*)
- os=-sysv4
+ acis*)
+ os=aos
;;
- -tpf*)
- os=-tpf
+ atheos*)
+ os=atheos
;;
- -triton*)
- os=-sysv3
+ syllable*)
+ os=syllable
+ ;;
+ 386bsd)
+ os=bsd
+ ;;
+ ctix* | uts*)
+ os=sysv
+ ;;
+ nova*)
+ os=rtmk-nova
+ ;;
+ ns2)
+ os=nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ sinix5.*)
+ os=`echo "$os" | sed -e 's|sinix|sysv|'`
;;
- -oss*)
- os=-sysv3
+ sinix*)
+ os=sysv4
;;
- -svr4*)
- os=-sysv4
+ tpf*)
+ os=tpf
;;
- -svr3)
- os=-sysv3
+ triton*)
+ os=sysv3
;;
- -sysvr4)
- os=-sysv4
+ oss*)
+ os=sysv3
;;
- # This must come after -sysvr4.
- -sysv*)
+ svr4*)
+ os=sysv4
;;
- -ose*)
- os=-ose
+ svr3)
+ os=sysv3
;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
+ sysvr4)
+ os=sysv4
;;
- -zvmoe)
- os=-zvmoe
+ ose*)
+ os=ose
;;
- -dicos*)
- os=-dicos
+ *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ os=mint
;;
- -pikeos*)
+ dicos*)
+ os=dicos
+ ;;
+ pikeos*)
# Until real need of OS specific support for
# particular features comes up, bare metal
# configurations are quite functional.
- case $basic_machine in
+ case $cpu in
arm*)
- os=-eabi
+ os=eabi
;;
*)
- os=-elf
+ os=elf
;;
esac
;;
- -nacl*)
- ;;
- -ios)
- ;;
- -none)
- ;;
*)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
- exit 1
+ # No normalization, but not necessarily accepted, that comes below.
;;
esac
+
else
# Here we handle the default operating systems that come with various machines.
@@ -1543,254 +1522,358 @@ else
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.
-case $basic_machine in
+kernel=
+case $cpu-$vendor in
score-*)
- os=-elf
+ os=elf
;;
spu-*)
- os=-elf
+ os=elf
;;
*-acorn)
- os=-riscix1.2
+ os=riscix1.2
;;
arm*-rebel)
- os=-linux
+ kernel=linux
+ os=gnu
;;
arm*-semi)
- os=-aout
+ os=aout
;;
c4x-* | tic4x-*)
- os=-coff
+ os=coff
;;
c8051-*)
- os=-elf
+ os=elf
+ ;;
+ clipper-intergraph)
+ os=clix
;;
hexagon-*)
- os=-elf
+ os=elf
;;
tic54x-*)
- os=-coff
+ os=coff
;;
tic55x-*)
- os=-coff
+ os=coff
;;
tic6x-*)
- os=-coff
+ os=coff
;;
# This must come before the *-dec entry.
pdp10-*)
- os=-tops20
+ os=tops20
;;
pdp11-*)
- os=-none
+ os=none
;;
*-dec | vax-*)
- os=-ultrix4.2
+ os=ultrix4.2
;;
m68*-apollo)
- os=-domain
+ os=domain
;;
i386-sun)
- os=-sunos4.0.2
+ os=sunos4.0.2
;;
m68000-sun)
- os=-sunos3
+ os=sunos3
;;
m68*-cisco)
- os=-aout
+ os=aout
;;
mep-*)
- os=-elf
+ os=elf
;;
mips*-cisco)
- os=-elf
+ os=elf
;;
mips*-*)
- os=-elf
+ os=elf
;;
or32-*)
- os=-coff
+ os=coff
;;
*-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
+ os=sysv3
;;
sparc-* | *-sun)
- os=-sunos4.1.1
+ os=sunos4.1.1
;;
pru-*)
- os=-elf
+ os=elf
;;
*-be)
- os=-beos
+ os=beos
;;
*-ibm)
- os=-aix
+ os=aix
;;
*-knuth)
- os=-mmixware
+ os=mmixware
;;
*-wec)
- os=-proelf
+ os=proelf
;;
*-winbond)
- os=-proelf
+ os=proelf
;;
*-oki)
- os=-proelf
+ os=proelf
;;
*-hp)
- os=-hpux
+ os=hpux
;;
*-hitachi)
- os=-hiux
+ os=hiux
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
+ os=sysv
;;
*-cbm)
- os=-amigaos
+ os=amigaos
;;
*-dg)
- os=-dgux
+ os=dgux
;;
*-dolphin)
- os=-sysv3
+ os=sysv3
;;
m68k-ccur)
- os=-rtu
+ os=rtu
;;
m88k-omron*)
- os=-luna
+ os=luna
;;
*-next)
- os=-nextstep
+ os=nextstep
;;
*-sequent)
- os=-ptx
+ os=ptx
;;
*-crds)
- os=-unos
+ os=unos
;;
*-ns)
- os=-genix
+ os=genix
;;
i370-*)
- os=-mvs
+ os=mvs
;;
*-gould)
- os=-sysv
+ os=sysv
;;
*-highlevel)
- os=-bsd
+ os=bsd
;;
*-encore)
- os=-bsd
+ os=bsd
;;
*-sgi)
- os=-irix
+ os=irix
;;
*-siemens)
- os=-sysv4
+ os=sysv4
;;
*-masscomp)
- os=-rtu
+ os=rtu
;;
f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
+ os=uxpv
;;
*-rom68k)
- os=-coff
+ os=coff
;;
*-*bug)
- os=-coff
+ os=coff
;;
*-apple)
- os=-macos
+ os=macos
;;
*-atari*)
- os=-mint
+ os=mint
+ ;;
+ *-wrs)
+ os=vxworks
;;
*)
- os=-none
+ os=none
;;
esac
+
fi
+# Now, validate our (potentially fixed-up) OS.
+case $os in
+ # Sometimes we do "kernel-libc", so those need to count as OSes.
+ musl* | newlib* | relibc* | uclibc*)
+ ;;
+ # Likewise for "kernel-abi"
+ eabi* | gnueabi*)
+ ;;
+ # VxWorks passes extra cpu info in the 4th filed.
+ simlinux | simwindows | spe)
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
+ | hiux* | abug | nacl* | netware* | windows* \
+ | os9* | macos* | osx* | ios* \
+ | mpw* | magic* | mmixware* | mon960* | lnews* \
+ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+ | aos* | aros* | cloudabi* | sortix* | twizzler* \
+ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+ | 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* \
+ | udi* | lites* | ieee* | go32* | aux* | hcos* \
+ | chorusrdb* | cegcc* | glidix* | serenity* \
+ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+ | midipix* | mingw32* | mingw64* | mint* \
+ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+ | interix* | uwin* | mks* | rhapsody* | darwin* \
+ | openstep* | oskit* | conix* | pw32* | nonstopux* \
+ | storm-chaos* | tops10* | tenex* | tops20* | its* \
+ | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+ | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+ | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*)
+ ;;
+ # 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.
+ ;;
+ none)
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 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* )
+ ;;
+ uclinux-uclibc* )
+ ;;
+ -dietlibc* | -newlib* | -musl* | -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
+ exit 1
+ ;;
+ kfreebsd*-gnu* | kopensolaris*-gnu*)
+ ;;
+ vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+ ;;
+ nto-qnx*)
+ ;;
+ os2-emx)
+ ;;
+ *-eabi* | *-gnueabi*)
+ ;;
+ -*)
+ # Blank kernel with real OS is always fine.
+ ;;
+ *-*)
+ echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+ exit 1
+ ;;
+esac
+
# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
+case $vendor in
+ unknown)
+ case $cpu-$os in
+ *-riscix*)
vendor=acorn
;;
- -sunos*)
+ *-sunos*)
vendor=sun
;;
- -cnk*|-aix*)
+ *-cnk* | *-aix*)
vendor=ibm
;;
- -beos*)
+ *-beos*)
vendor=be
;;
- -hpux*)
+ *-hpux*)
vendor=hp
;;
- -mpeix*)
+ *-mpeix*)
vendor=hp
;;
- -hiux*)
+ *-hiux*)
vendor=hitachi
;;
- -unos*)
+ *-unos*)
vendor=crds
;;
- -dgux*)
+ *-dgux*)
vendor=dg
;;
- -luna*)
+ *-luna*)
vendor=omron
;;
- -genix*)
+ *-genix*)
vendor=ns
;;
- -mvs* | -opened*)
+ *-clix*)
+ vendor=intergraph
+ ;;
+ *-mvs* | *-opened*)
+ vendor=ibm
+ ;;
+ *-os400*)
vendor=ibm
;;
- -os400*)
+ s390-* | s390x-*)
vendor=ibm
;;
- -ptx*)
+ *-ptx*)
vendor=sequent
;;
- -tpf*)
+ *-tpf*)
vendor=ibm
;;
- -vxsim* | -vxworks* | -windiss*)
+ *-vxsim* | *-vxworks* | *-windiss*)
vendor=wrs
;;
- -aux*)
+ *-aux*)
vendor=apple
;;
- -hms*)
+ *-hms*)
vendor=hitachi
;;
- -mpw* | -macos*)
+ *-mpw* | *-macos*)
vendor=apple
;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
vendor=atari
;;
- -vos*)
+ *-vos*)
vendor=stratus
;;
esac
- basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
;;
esac
-echo "$basic_machine$os"
+echo "$cpu-$vendor-${kernel:+$kernel-}$os"
exit
# Local variables:
diff --git a/configure b/configure
index d7dfd55..bcab271 100755
--- a/configure
+++ b/configure
@@ -1,9 +1,10 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for dnsdist 1.8.3.
+# Generated by GNU Autoconf 2.71 for dnsdist 1.9.3.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
+# Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -14,14 +15,16 @@
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -31,46 +34,46 @@ esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
@@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
@@ -94,8 +90,12 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
@@ -107,30 +107,10 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# Use a proper internal environment variable to ensure we don't fall
# into an infinite loop, continuously re-executing ourselves.
@@ -152,20 +132,22 @@ 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'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
+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="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ as_bourne_compatible="as_nop=:
+if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
# is contrary to our usage. Disable this feature.
alias -g '\${1+\"\$@\"}'='\"\$@\"'
setopt NO_GLOB_SUBST
-else
+else \$as_nop
case \`(set -o) 2>/dev/null\` in #(
*posix*) :
set -o posix ;; #(
@@ -185,12 +167,15 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+if ( set x; as_fn_ret_success y && test x = \"\$1\" )
+then :
-else
+else \$as_nop
exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1
+blah=\$(echo \$(echo blah))
+test x\"\$blah\" = xblah || exit 1
test -x / || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
@@ -205,30 +190,38 @@ test -x / || exit 1"
test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
|| test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null; then :
+ if (eval "$as_required") 2>/dev/null
+then :
as_have_required=yes
-else
+else $as_nop
as_have_required=no
fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
+then :
-else
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
as_found=:
case $as_dir in #(
/*)
for as_base in sh bash ksh sh5; do
# Try only shells that exist, to save several forks.
- as_shell=$as_dir/$as_base
+ as_shell=$as_dir$as_base
if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
CONFIG_SHELL=$as_shell as_have_required=yes
- if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
+then :
break 2
fi
fi
@@ -236,14 +229,21 @@ fi
esac
as_found=false
done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ 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
- if test "x$CONFIG_SHELL" != x; then :
+ if test "x$CONFIG_SHELL" != x
+then :
export CONFIG_SHELL
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
@@ -261,18 +261,19 @@ 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'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi
- if test x$as_have_required = xno; then :
- $as_echo "$0: This script requires a shell more modern than all"
- $as_echo "$0: the shells that I found on your system."
- if test x${ZSH_VERSION+set} = xset ; then
- $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ if test x$as_have_required = xno
+then :
+ printf "%s\n" "$0: This script requires a shell more modern than all"
+ printf "%s\n" "$0: the shells that I found on your system."
+ if test ${ZSH_VERSION+y} ; then
+ printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
else
- $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+ printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
@@ -299,6 +300,7 @@ as_fn_unset ()
}
as_unset=as_fn_unset
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
@@ -316,6 +318,14 @@ as_fn_exit ()
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
# -------------
@@ -330,7 +340,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -339,7 +349,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -378,12 +388,13 @@ as_fn_executable_p ()
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
@@ -395,18 +406,27 @@ fi # as_fn_append
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
}
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]
# ----------------------------------------
@@ -418,9 +438,9 @@ as_fn_error ()
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -447,7 +467,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -491,7 +511,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
s/-\n.*//
' >$as_me.lineno &&
chmod +x "$as_me.lineno" ||
- { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
# already done that, so ensure we don't try to do so again and fall
@@ -505,6 +525,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
exit
}
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -518,6 +542,13 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+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
@@ -587,48 +618,44 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='dnsdist'
PACKAGE_TARNAME='dnsdist'
-PACKAGE_VERSION='1.8.3'
-PACKAGE_STRING='dnsdist 1.8.3'
+PACKAGE_VERSION='1.9.3'
+PACKAGE_STRING='dnsdist 1.9.3'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Factoring default headers for most tests.
ac_includes_default="\
-#include <stdio.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
+#include <stddef.h>
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
#endif
-#ifdef STDC_HEADERS
+#ifdef HAVE_STDLIB_H
# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
#endif
#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-# include <memory.h>
-# endif
# include <string.h>
#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"
-ac_func_list=
+ac_header_c_list=
+ac_func_cxx_list=
ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
@@ -644,9 +671,9 @@ pkgpyexecdir
pyexecdir
pkgpythondir
pythondir
-PYTHON_PLATFORM
PYTHON_EXEC_PREFIX
PYTHON_PREFIX
+PYTHON_PLATFORM
PYTHON_VERSION
PYTHON
WARN_CFLAGS
@@ -661,16 +688,16 @@ LMDB_LIBS
LMDB_CFLAGS
CDB_LIBS
CDB_CFLAGS
-HAVE_NGHTTP2_FALSE
-HAVE_NGHTTP2_TRUE
-NGHTTP2_LIBS
-NGHTTP2_CFLAGS
-HAVE_LIBH2OEVLOOP_FALSE
-HAVE_LIBH2OEVLOOP_TRUE
LIBH2OEVLOOP_LIBS
LIBH2OEVLOOP_CFLAGS
+NGHTTP2_LIBS
+NGHTTP2_CFLAGS
GNUTLS_LIBS
GNUTLS_CFLAGS
+HAVE_DNS_OVER_HTTP3_FALSE
+HAVE_DNS_OVER_HTTP3_TRUE
+HAVE_DNS_OVER_QUIC_FALSE
+HAVE_DNS_OVER_QUIC_TRUE
HAVE_DNS_OVER_HTTPS_FALSE
HAVE_DNS_OVER_HTTPS_TRUE
HAVE_DNS_OVER_TLS_FALSE
@@ -684,20 +711,25 @@ HAVE_LIBCRYPTO_TRUE
LIBCRYPTO_LDFLAGS
LIBCRYPTO_LIBS
LIBCRYPTO_INCLUDES
-HAVE_CDB_FALSE
-HAVE_CDB_TRUE
+HAVE_NGHTTP2_FALSE
+HAVE_NGHTTP2_TRUE
HAVE_LMDB_FALSE
HAVE_LMDB_TRUE
HAVE_LIBSSL_FALSE
HAVE_LIBSSL_TRUE
+HAVE_LIBH2OEVLOOP_FALSE
+HAVE_LIBH2OEVLOOP_TRUE
HAVE_GNUTLS_FALSE
HAVE_GNUTLS_TRUE
+HAVE_CDB_FALSE
+HAVE_CDB_TRUE
HAVE_LUA_HPP_FALSE
HAVE_LUA_HPP_TRUE
LUA_FALSE
LUA_TRUE
LUA_LIBS
LUA_CFLAGS
+ARC4RANDOM_LIBS
IPCRYPT_LIBS
IPCRYPT_CFLAGS
YAHTTP_LIBS
@@ -773,6 +805,12 @@ LIBCAP_CFLAGS
HAVE_NET_SNMP_FALSE
HAVE_NET_SNMP_TRUE
NET_SNMP_LIBS
+HAVE_XSK_FALSE
+HAVE_XSK_TRUE
+BPF_LIBS
+BPF_CFLAGS
+XDP_LIBS
+XDP_CFLAGS
HAVE_EBPF_FALSE
HAVE_EBPF_TRUE
DNSCRYPT_FALSE
@@ -781,6 +819,8 @@ HAVE_RE2_FALSE
HAVE_RE2_TRUE
RE2_LIBS
RE2_CFLAGS
+FUZZ_TARGETS_FALSE
+FUZZ_TARGETS_TRUE
BOOST_UNIT_TEST_FRAMEWORK_LIBS
BOOST_LDPATH
BOOST_UNIT_TEST_FRAMEWORK_LDPATH
@@ -812,6 +852,10 @@ FSTRM_FALSE
FSTRM_TRUE
FSTRM_LIBS
FSTRM_CFLAGS
+HAVE_QUICHE_FALSE
+HAVE_QUICHE_TRUE
+QUICHE_LIBS
+QUICHE_CFLAGS
LIBSODIUM_FALSE
LIBSODIUM_TRUE
LIBSODIUM_LIBS
@@ -820,7 +864,6 @@ PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
CXXCPP
-CPP
LT_SYS_LIBRARY_PATH
OTOOL64
OTOOL
@@ -833,6 +876,7 @@ ac_ct_AR
AR
DLLTOOL
OBJDUMP
+FILECMD
LN_S
NM
ac_ct_DUMPBIN
@@ -877,6 +921,9 @@ AM_BACKSLASH
AM_DEFAULT_VERBOSITY
AM_DEFAULT_V
AM_V
+CSCOPE
+ETAGS
+CTAGS
am__untar
am__tar
AMTAR
@@ -954,14 +1001,17 @@ with_gnu_ld
with_sysroot
enable_libtool_lock
with_libsodium
+with_quiche
enable_dnstap
with_libedit
with_boost
enable_unit_tests
enable_static_boost
+enable_fuzz_targets
with_re2
enable_dnscrypt
with_ebpf
+with_xsk
with_net_snmp
with_libcap
enable_systemd
@@ -973,9 +1023,12 @@ with_libcrypto
enable_tls_providers
enable_dns_over_tls
enable_dns_over_https
+enable_dns_over_quic
+enable_dns_over_http3
with_libssl
with_gnutls
with_nghttp2
+with_h2o
with_cdb
with_lmdb
enable_ipcipher
@@ -988,6 +1041,10 @@ enable_tsan
enable_lsan
enable_ubsan
enable_lto
+enable_coverage
+with_python_sys_prefix
+with_python_prefix
+with_python_exec_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1001,13 +1058,14 @@ CXX
CXXFLAGS
CCC
LT_SYS_LIBRARY_PATH
-CPP
CXXCPP
PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
LIBSODIUM_CFLAGS
LIBSODIUM_LIBS
+QUICHE_CFLAGS
+QUICHE_LIBS
FSTRM_CFLAGS
FSTRM_LIBS
LIBEDIT_CFLAGS
@@ -1015,6 +1073,10 @@ LIBEDIT_LIBS
BOOST_ROOT
RE2_CFLAGS
RE2_LIBS
+XDP_CFLAGS
+XDP_LIBS
+BPF_CFLAGS
+BPF_LIBS
LIBCAP_CFLAGS
LIBCAP_LIBS
SYSTEMD_CFLAGS
@@ -1025,10 +1087,10 @@ LIBSSL_CFLAGS
LIBSSL_LIBS
GNUTLS_CFLAGS
GNUTLS_LIBS
-LIBH2OEVLOOP_CFLAGS
-LIBH2OEVLOOP_LIBS
NGHTTP2_CFLAGS
NGHTTP2_LIBS
+LIBH2OEVLOOP_CFLAGS
+LIBH2OEVLOOP_LIBS
CDB_CFLAGS
CDB_LIBS
LMDB_CFLAGS
@@ -1103,8 +1165,6 @@ do
*) ac_optarg=yes ;;
esac
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
case $ac_dashdash$ac_option in
--)
ac_dashdash=yes ;;
@@ -1145,9 +1205,9 @@ do
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=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -1171,9 +1231,9 @@ do
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=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -1384,9 +1444,9 @@ do
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=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1400,9 +1460,9 @@ do
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=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1446,9 +1506,9 @@ Try \`$0 --help' for more information"
*)
# FIXME: should be removed in autoconf 3.0.
- $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
: "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
;;
@@ -1464,7 +1524,7 @@ if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1528,7 +1588,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_myself" : 'X\(//\)[^/]' \| \
X"$as_myself" : 'X\(//\)$' \| \
X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
+printf "%s\n" X"$as_myself" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -1585,7 +1645,7 @@ if test "$ac_init_help" = "long"; then
# 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 dnsdist 1.8.3 to adapt to many kinds of systems.
+\`configure' configures dnsdist 1.9.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1656,7 +1716,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dnsdist 1.8.3:";;
+ short | recursive ) echo "Configuration of dnsdist 1.9.3:";;
esac
cat <<\_ACEOF
@@ -1679,6 +1739,7 @@ Optional Features:
--enable-unit-tests enable unit test building [default=no]
--enable-static-boost Prefer the static boost libraries over the shared
ones [no]
+ --enable-fuzz-targets enable fuzz targets [default=no]
--enable-dnscrypt enable DNSCrypt support (requires libsodium)
[default=no]
--enable-systemd Enable systemd support (default is DISABLED, but
@@ -1688,7 +1749,11 @@ Optional Features:
--enable-dns-over-tls enable DNS over TLS support (requires GnuTLS or
OpenSSL) [default=no]
--enable-dns-over-https enable incoming DNS over HTTPS (DoH) support
- (requires libh2o) [default=no]
+ (requires libh2o or nghttp2) [default=no]
+ --enable-dns-over-quic enable incoming DNS over QUIC (DoQ) support
+ (requires quiche) [default=no]
+ --enable-dns-over-http3 enable incoming DNS over HTTP3 (DoH3) support
+ (requires quiche) [default=no]
--enable-ipcipher enable ipcipher support (requires libcrypto)
[default=auto]
--disable-hardening disable compiler security checks [default=no]
@@ -1702,6 +1767,7 @@ Optional Features:
--enable-ubsan enable Undefined Behaviour Sanitizer [default=no]
--enable-lto enable Link-Time Optimizations (LTO) support
[default=no]
+ --enable-coverage enable code coverage [default=no]
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1715,11 +1781,13 @@ Optional Packages:
--with-sysroot[=DIR] Search for dependent libraries within DIR (or the
compiler's sysroot if not specified).
--with-libsodium use libsodium [default=auto]
+ --with-quiche use quiche [default=auto]
--with-libedit enable libedit support [default=yes]
--with-boost=DIR prefix of Boost 1.42 [guess]
--with-re2 with libre2 [default=no]
--with-ebpf enable eBPF support [default=auto]
- --with-net-snmp enable net snmp support [default=auto]
+ --with-xsk enable AF_XDP (XDK) support [default=auto]
+ --with-net-snmp enable net snmp support [default=no]
--with-libcap use libcap [default=auto]
--with-systemd set directory for systemd service files
--with-systemd-modules-load set directory for systemd modules load files
@@ -1737,8 +1805,14 @@ Optional Packages:
--with-libssl use OpenSSL libssl [default=auto]
--with-gnutls use GnuTLS [default=auto]
--with-nghttp2 use nghttp2 [default=auto]
+ --with-h2o use libh2o-evloop [default=no]
--with-cdb use CDB [default=auto]
--with-lmdb lmdb library to use [default=auto]
+ --with-python-sys-prefix
+ use Python's sys.prefix and sys.exec_prefix values
+ --with-python_prefix override the default PYTHON_PREFIX
+ --with-python_exec_prefix
+ override the default PYTHON_EXEC_PREFIX
Some influential environment variables:
CC C compiler command
@@ -1752,7 +1826,6 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags
LT_SYS_LIBRARY_PATH
User-defined run-time library search path.
- CPP C preprocessor
CXXCPP C++ preprocessor
PKG_CONFIG path to pkg-config utility
PKG_CONFIG_PATH
@@ -1763,6 +1836,9 @@ Some influential environment variables:
C compiler flags for LIBSODIUM, overriding pkg-config
LIBSODIUM_LIBS
linker flags for LIBSODIUM, overriding pkg-config
+ QUICHE_CFLAGS
+ C compiler flags for QUICHE, overriding pkg-config
+ QUICHE_LIBS linker flags for QUICHE, overriding pkg-config
FSTRM_CFLAGS
C compiler flags for FSTRM, overriding pkg-config
FSTRM_LIBS linker flags for FSTRM, overriding pkg-config
@@ -1773,6 +1849,10 @@ Some influential environment variables:
BOOST_ROOT Location of Boost installation
RE2_CFLAGS C compiler flags for RE2, overriding pkg-config
RE2_LIBS linker flags for RE2, overriding pkg-config
+ XDP_CFLAGS C compiler flags for XDP, overriding pkg-config
+ XDP_LIBS linker flags for XDP, overriding pkg-config
+ BPF_CFLAGS C compiler flags for BPF, overriding pkg-config
+ BPF_LIBS linker flags for BPF, overriding pkg-config
LIBCAP_CFLAGS
C compiler flags for LIBCAP, overriding pkg-config
LIBCAP_LIBS linker flags for LIBCAP, overriding pkg-config
@@ -1788,14 +1868,14 @@ Some influential environment variables:
GNUTLS_CFLAGS
C compiler flags for GNUTLS, overriding pkg-config
GNUTLS_LIBS linker flags for GNUTLS, overriding pkg-config
- LIBH2OEVLOOP_CFLAGS
- C compiler flags for LIBH2OEVLOOP, overriding pkg-config
- LIBH2OEVLOOP_LIBS
- linker flags for LIBH2OEVLOOP, overriding pkg-config
NGHTTP2_CFLAGS
C compiler flags for NGHTTP2, overriding pkg-config
NGHTTP2_LIBS
linker flags for NGHTTP2, overriding pkg-config
+ LIBH2OEVLOOP_CFLAGS
+ C compiler flags for LIBH2OEVLOOP, overriding pkg-config
+ LIBH2OEVLOOP_LIBS
+ linker flags for LIBH2OEVLOOP, overriding pkg-config
CDB_CFLAGS C compiler flags for CDB, overriding pkg-config
CDB_LIBS linker flags for CDB, overriding pkg-config
LMDB_CFLAGS C compiler flags for LMDB, overriding pkg-config
@@ -1823,9 +1903,9 @@ if test "$ac_init_help" = "recursive"; then
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
@@ -1853,7 +1933,8 @@ esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for guested configure.
+ # Check for configure.gnu first; this name is used for a wrapper for
+ # Metaconfig's "Configure" on case-insensitive file systems.
if test -f "$ac_srcdir/configure.gnu"; then
echo &&
$SHELL "$ac_srcdir/configure.gnu" --help=recursive
@@ -1861,7 +1942,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
echo &&
$SHELL "$ac_srcdir/configure" --help=recursive
else
- $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
fi || ac_status=$?
cd "$ac_pwd" || { ac_status=$?; break; }
done
@@ -1870,10 +1951,10 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dnsdist configure 1.8.3
-generated by GNU Autoconf 2.69
+dnsdist configure 1.9.3
+generated by GNU Autoconf 2.71
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1890,14 +1971,14 @@ fi
ac_fn_c_try_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext
+ rm -f conftest.$ac_objext conftest.beam
if { { ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1905,14 +1986,15 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
- } && test -s conftest.$ac_objext; then :
+ } && test -s conftest.$ac_objext
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1928,14 +2010,14 @@ fi
ac_fn_cxx_try_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext
+ rm -f conftest.$ac_objext conftest.beam
if { { ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1943,14 +2025,15 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
- } && test -s conftest.$ac_objext; then :
+ } && test -s conftest.$ac_objext
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1966,14 +2049,14 @@ fi
ac_fn_c_try_link ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest$ac_exeext
+ rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1981,17 +2064,18 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
test -x conftest$ac_exeext
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -2013,120 +2097,44 @@ fi
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } > conftest.i && {
- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
- test ! -s conftest.err
- }; then :
- ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_cpp
-
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
-ac_fn_c_try_run ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then :
- ac_retval=0
-else
- $as_echo "$as_me: program exited with status $ac_status" >&5
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=$ac_status
-fi
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
ac_fn_c_check_func ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
@@ -2134,16 +2142,9 @@ else
#define $2 innocuous_$2
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below.
- Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- <limits.h> exists even on freestanding compilers. */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+ which can conflict with char $2 (); below. */
+#include <limits.h>
#undef $2
/* Override any GCC internal prototype to avoid an error.
@@ -2161,24 +2162,25 @@ choke me
#endif
int
-main ()
+main (void)
{
return $2 ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_func
@@ -2195,7 +2197,7 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -2203,14 +2205,15 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } > conftest.i && {
test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
test ! -s conftest.err
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -2226,14 +2229,14 @@ fi
ac_fn_cxx_try_link ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest$ac_exeext
+ rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -2241,17 +2244,18 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
test -x conftest$ac_exeext
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -2272,11 +2276,12 @@ fi
ac_fn_cxx_check_func ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
@@ -2284,16 +2289,9 @@ else
#define $2 innocuous_$2
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below.
- Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- <limits.h> exists even on freestanding compilers. */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+ which can conflict with char $2 (); below. */
+#include <limits.h>
#undef $2
/* Override any GCC internal prototype to avoid an error.
@@ -2311,24 +2309,25 @@ choke me
#endif
int
-main ()
+main (void)
{
return $2 ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_cxx_check_func
@@ -2340,49 +2339,54 @@ $as_echo "$ac_res" >&6; }
ac_fn_cxx_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_cxx_check_header_compile
-# ac_fn_cxx_check_decl LINENO SYMBOL VAR INCLUDES
-# -----------------------------------------------
+# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
+# ------------------------------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly.
-ac_fn_cxx_check_decl ()
+# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
+ac_fn_check_decl ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
as_decl_name=`echo $2|sed 's/ *(.*//'`
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+printf %s "checking whether $as_decl_name is declared... " >&6; }
+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'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ eval ac_save_FLAGS=\$$6
+ as_fn_append $6 " $5"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
int
-main ()
+main (void)
{
#ifndef $as_decl_name
#ifdef __cplusplus
@@ -2396,156 +2400,50 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_cxx_check_decl
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ eval $6=\$ac_save_FLAGS
-# ac_fn_cxx_try_run LINENO
-# ------------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
-ac_fn_cxx_try_run ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then :
- ac_retval=0
-else
- $as_echo "$as_me: program exited with status $ac_status" >&5
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=$ac_status
fi
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+eval ac_res=\$$3
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_cxx_try_run
-# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
-# ---------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_cxx_check_header_mongrel ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
- # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
- ac_header_compiler=yes
-else
- ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+} # ac_fn_check_decl
+ac_configure_args_raw=
+for ac_arg
+do
+ case $ac_arg in
+ *\'*)
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_configure_args_raw " '$ac_arg'"
+done
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <$2>
-_ACEOF
-if ac_fn_cxx_try_cpp "$LINENO"; then :
- ac_header_preproc=yes
-else
- ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So? What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
- yes:no: )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
- ;;
- no:yes:* )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
- ;;
+case $ac_configure_args_raw in
+ *$as_nl*)
+ ac_safe_unquote= ;;
+ *)
+ ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
+ ac_unsafe_a="$ac_unsafe_z#~"
+ ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
+ ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-} # ac_fn_cxx_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dnsdist $as_me 1.8.3, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+It was created by dnsdist $as_me 1.9.3, which was
+generated by GNU Autoconf 2.71. Invocation command line was
- $ $0 $@
+ $ $0$ac_configure_args_raw
_ACEOF
exec 5>>config.log
@@ -2578,8 +2476,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- $as_echo "PATH: $as_dir"
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ printf "%s\n" "PATH: $as_dir"
done
IFS=$as_save_IFS
@@ -2614,7 +2516,7 @@ do
| -silent | --silent | --silen | --sile | --sil)
continue ;;
*\'*)
- ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
case $ac_pass in
1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
@@ -2649,11 +2551,13 @@ done
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
+ # Sanitize IFS.
+ IFS=" "" $as_nl"
# Save into config.log some information that might help in debugging.
{
echo
- $as_echo "## ---------------- ##
+ printf "%s\n" "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
echo
@@ -2664,8 +2568,8 @@ trap 'exit_status=$?
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -2689,7 +2593,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
)
echo
- $as_echo "## ----------------- ##
+ printf "%s\n" "## ----------------- ##
## Output variables. ##
## ----------------- ##"
echo
@@ -2697,14 +2601,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
if test -n "$ac_subst_files"; then
- $as_echo "## ------------------- ##
+ printf "%s\n" "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
echo
@@ -2712,15 +2616,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
fi
if test -s confdefs.h; then
- $as_echo "## ----------- ##
+ printf "%s\n" "## ----------- ##
## confdefs.h. ##
## ----------- ##"
echo
@@ -2728,8 +2632,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
echo
fi
test "$ac_signal" != 0 &&
- $as_echo "$as_me: caught signal $ac_signal"
- $as_echo "$as_me: exit $exit_status"
+ printf "%s\n" "$as_me: caught signal $ac_signal"
+ printf "%s\n" "$as_me: exit $exit_status"
} >&5
rm -f core *.core core.conftest.* &&
rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
@@ -2743,63 +2647,48 @@ ac_signal=0
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h
-$as_echo "/* confdefs.h */" > confdefs.h
+printf "%s\n" "/* confdefs.h */" > confdefs.h
# Predefined preprocessor variables.
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
+printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
+printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
+printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
+printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
- # We do not want a PATH search for config.site.
- case $CONFIG_SITE in #((
- -*) ac_site_file1=./$CONFIG_SITE;;
- */*) ac_site_file1=$CONFIG_SITE;;
- *) ac_site_file1=./$CONFIG_SITE;;
- esac
+ ac_site_files="$CONFIG_SITE"
elif test "x$prefix" != xNONE; then
- ac_site_file1=$prefix/share/config.site
- ac_site_file2=$prefix/etc/config.site
+ ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
else
- ac_site_file1=$ac_default_prefix/share/config.site
- ac_site_file2=$ac_default_prefix/etc/config.site
+ ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+
+for ac_site_file in $ac_site_files
do
- test "x$ac_site_file" = xNONE && continue
- if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ case $ac_site_file in #(
+ */*) :
+ ;; #(
+ *) :
+ ac_site_file=./$ac_site_file ;;
+esac
+ if test -f "$ac_site_file" && test -r "$ac_site_file"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
. "$ac_site_file" \
- || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$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; }
fi
@@ -2809,22 +2698,657 @@ if test -r "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special files
# actually), so we avoid doing that. DJGPP emulates it as a regular file.
if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
[\\/]* | ?:[\\/]* ) . "$cache_file";;
*) . "./$cache_file";;
esac
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
-as_fn_append ac_func_list " localtime_r"
-as_fn_append ac_func_list " gmtime_r"
-as_fn_append ac_func_list " getrandom"
+# Test code for whether the C compiler supports C89 (global declarations)
+ac_c_conftest_c89_globals='
+/* Does the compiler advertise C89 conformance?
+ Do not test the value of __STDC__, because some compilers set it to 0
+ while being otherwise adequately conformant. */
+#if !defined __STDC__
+# error "Compiler does not advertise C89 conformance"
+#endif
+
+#include <stddef.h>
+#include <stdarg.h>
+struct stat;
+/* 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;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* 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
+ as an "x". The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously \x00 != x always comes out true, for an
+ array size at least. It is necessary to write \x00 == 0 to get something
+ that is true only with -std. */
+int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) '\''x'\''
+int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),
+ int, int);'
+
+# Test code for whether the C compiler supports C89 (body of main).
+ac_c_conftest_c89_main='
+ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
+'
+
+# Test code for whether the C compiler supports C99 (global declarations)
+ac_c_conftest_c99_globals='
+// Does the compiler advertise C99 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
+# error "Compiler does not advertise C99 conformance"
+#endif
+
+#include <stdbool.h>
+extern int puts (const char *);
+extern int printf (const char *, ...);
+extern int dprintf (int, const char *, ...);
+extern void *malloc (size_t);
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+// dprintf is used instead of fprintf to avoid needing to declare
+// FILE and stderr.
+#define debug(...) dprintf (2, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ #error "your preprocessor is broken"
+#endif
+#if BIG_OK
+#else
+ #error "your preprocessor is broken"
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+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)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static bool
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str = "";
+ int number = 0;
+ float fnumber = 0;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case '\''s'\'': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case '\''d'\'': // int
+ number = va_arg (args_copy, int);
+ break;
+ case '\''f'\'': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+
+ return *str && number && fnumber;
+}
+'
+
+# Test code for whether the C compiler supports C99 (body of main).
+ac_c_conftest_c99_main='
+ // Check bool.
+ _Bool success = false;
+ success |= (argc != 0);
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[0] = argv[0][0];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
+ || dynamic_array[ni.number - 1] != 543);
+'
+
+# Test code for whether the C compiler supports C11 (global declarations)
+ac_c_conftest_c11_globals='
+// Does the compiler advertise C11 conformance?
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
+#endif
+
+// Check _Alignas.
+char _Alignas (double) aligned_as_double;
+char _Alignas (0) no_special_alignment;
+extern char aligned_as_int;
+char _Alignas (0) _Alignas (int) aligned_as_int;
+
+// Check _Alignof.
+enum
+{
+ int_alignment = _Alignof (int),
+ int_array_alignment = _Alignof (int[100]),
+ char_alignment = _Alignof (char)
+};
+_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
+
+// Check _Noreturn.
+int _Noreturn does_not_return (void) { for (;;) continue; }
+
+// Check _Static_assert.
+struct test_static_assert
+{
+ int x;
+ _Static_assert (sizeof (int) <= sizeof (long int),
+ "_Static_assert does not work in struct");
+ long int y;
+};
+
+// Check UTF-8 literals.
+#define u8 syntax error!
+char const utf8_literal[] = u8"happens to be ASCII" "another string";
+
+// Check duplicate typedefs.
+typedef long *long_ptr;
+typedef long int *long_ptr;
+typedef long_ptr long_ptr;
+
+// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
+struct anonymous
+{
+ union {
+ struct { int i; int j; };
+ struct { int k; long int l; } w;
+ };
+ int m;
+} v1;
+'
+
+# Test code for whether the C compiler supports C11 (body of main).
+ac_c_conftest_c11_main='
+ _Static_assert ((offsetof (struct anonymous, i)
+ == offsetof (struct anonymous, w.k)),
+ "Anonymous union alignment botch");
+ v1.i = 2;
+ v1.w.k = 5;
+ ok |= v1.i != 5;
+'
+
+# Test code for whether the C compiler supports C11 (complete).
+ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+${ac_c_conftest_c11_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ ${ac_c_conftest_c11_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C99 (complete).
+ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
+${ac_c_conftest_c99_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ ${ac_c_conftest_c99_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C89 (complete).
+ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_c_conftest_c89_main}
+ return ok;
+}
+"
+
+# Test code for whether the C++ compiler supports C++98 (global declarations)
+ac_cxx_conftest_cxx98_globals='
+// Does the compiler advertise C++98 conformance?
+#if !defined __cplusplus || __cplusplus < 199711L
+# error "Compiler does not advertise C++98 conformance"
+#endif
+
+// These inclusions are to reject old compilers that
+// lack the unsuffixed header files.
+#include <cstdlib>
+#include <exception>
+
+// <cassert> and <cstring> are *not* freestanding headers in C++98.
+extern void assert (int);
+namespace std {
+ extern int strcmp (const char *, const char *);
+}
+
+// Namespaces, exceptions, and templates were all added after "C++ 2.0".
+using std::exception;
+using std::strcmp;
+
+namespace {
+
+void test_exception_syntax()
+{
+ try {
+ throw "test";
+ } catch (const char *s) {
+ // Extra parentheses suppress a warning when building autoconf itself,
+ // due to lint rules shared with more typical C programs.
+ assert (!(strcmp) (s, "test"));
+ }
+}
+
+template <typename T> struct test_template
+{
+ T const val;
+ explicit test_template(T t) : val(t) {}
+ template <typename U> T add(U u) { return static_cast<T>(u) + val; }
+};
+
+} // anonymous namespace
+'
+
+# Test code for whether the C++ compiler supports C++98 (body of main)
+ac_cxx_conftest_cxx98_main='
+ assert (argc);
+ assert (! argv[0]);
+{
+ test_exception_syntax ();
+ test_template<double> tt (2.0);
+ assert (tt.add (4) == 6.0);
+ assert (true && !false);
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (global declarations)
+ac_cxx_conftest_cxx11_globals='
+// Does the compiler advertise C++ 2011 conformance?
+#if !defined __cplusplus || __cplusplus < 201103L
+# error "Compiler does not advertise C++11 conformance"
+#endif
+
+namespace cxx11test
+{
+ constexpr int get_val() { return 20; }
+
+ struct testinit
+ {
+ int i;
+ double d;
+ };
+
+ class delegate
+ {
+ public:
+ delegate(int n) : n(n) {}
+ delegate(): delegate(2354) {}
+
+ virtual int getval() { return this->n; };
+ protected:
+ int n;
+ };
+
+ class overridden : public delegate
+ {
+ public:
+ overridden(int n): delegate(n) {}
+ virtual int getval() override final { return this->n * 2; }
+ };
+
+ class nocopy
+ {
+ public:
+ nocopy(int i): i(i) {}
+ nocopy() = default;
+ nocopy(const nocopy&) = delete;
+ nocopy & operator=(const nocopy&) = delete;
+ private:
+ int i;
+ };
+
+ // for testing lambda expressions
+ template <typename Ret, typename Fn> Ret eval(Fn f, Ret v)
+ {
+ return f(v);
+ }
+
+ // for testing variadic templates and trailing return types
+ template <typename V> auto sum(V first) -> V
+ {
+ return first;
+ }
+ template <typename V, typename... Args> auto sum(V first, Args... rest) -> V
+ {
+ return first + sum(rest...);
+ }
+}
+'
+
+# Test code for whether the C++ compiler supports C++11 (body of main)
+ac_cxx_conftest_cxx11_main='
+{
+ // Test auto and decltype
+ auto a1 = 6538;
+ auto a2 = 48573953.4;
+ auto a3 = "String literal";
+
+ int total = 0;
+ for (auto i = a3; *i; ++i) { total += *i; }
+
+ decltype(a2) a4 = 34895.034;
+}
+{
+ // Test constexpr
+ short sa[cxx11test::get_val()] = { 0 };
+}
+{
+ // Test initializer lists
+ cxx11test::testinit il = { 4323, 435234.23544 };
+}
+{
+ // Test range-based for
+ int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3,
+ 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};
+ for (auto &x : array) { x += 23; }
+}
+{
+ // Test lambda expressions
+ using cxx11test::eval;
+ assert (eval ([](int x) { return x*2; }, 21) == 42);
+ double d = 2.0;
+ assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0);
+ assert (d == 5.0);
+ assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0);
+ assert (d == 5.0);
+}
+{
+ // Test use of variadic templates
+ using cxx11test::sum;
+ auto a = sum(1);
+ auto b = sum(1, 2);
+ auto c = sum(1.0, 2.0, 3.0);
+}
+{
+ // Test constructor delegation
+ cxx11test::delegate d1;
+ cxx11test::delegate d2();
+ cxx11test::delegate d3(45);
+}
+{
+ // Test override and final
+ cxx11test::overridden o1(55464);
+}
+{
+ // Test nullptr
+ char *c = nullptr;
+}
+{
+ // Test template brackets
+ test_template<::test_template<int>> v(test_template<int>(12));
+}
+{
+ // Unicode literals
+ char const *utf8 = u8"UTF-8 string \u2500";
+ char16_t const *utf16 = u"UTF-8 string \u2500";
+ char32_t const *utf32 = U"UTF-32 string \u2500";
+}
+'
+
+# Test code for whether the C compiler supports C++11 (complete).
+ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals}
+${ac_cxx_conftest_cxx11_globals}
+
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_cxx_conftest_cxx98_main}
+ ${ac_cxx_conftest_cxx11_main}
+ return ok;
+}
+"
+
+# Test code for whether the C compiler supports C++98 (complete).
+ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals}
+int
+main (int argc, char **argv)
+{
+ int ok = 0;
+ ${ac_cxx_conftest_cxx98_main}
+ return ok;
+}
+"
+
+as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
+as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
+as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
+as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
+as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
+as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
+as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
+as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
+as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
+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 " getrandom HAVE_GETRANDOM"
+as_fn_append ac_func_cxx_list " getentropy HAVE_GETENTROPY"
+as_fn_append ac_func_cxx_list " arc4random HAVE_ARC4RANDOM"
+as_fn_append ac_func_cxx_list " arc4random_uniform HAVE_ARC4RANDOM_UNIFORM"
+as_fn_append ac_func_cxx_list " arc4random_buf HAVE_ARC4RANDOM_BUF"
+
+# Auxiliary files required by this configure script.
+ac_aux_files="config.guess config.sub ltmain.sh compile missing install-sh"
+
+# Locations in which to look for auxiliary files.
+ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.."
+
+# Search for a directory containing all of the required auxiliary files,
+# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
+# If we don't find one directory that contains all the files we need,
+# we report the set of missing files from the *first* directory in
+# $ac_aux_dir_candidates and give up.
+ac_missing_aux_files=""
+ac_first_candidate=:
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in $ac_aux_dir_candidates
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ as_found=:
+
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
+ ac_aux_dir_found=yes
+ ac_install_sh=
+ for ac_aux in $ac_aux_files
+ do
+ # As a special case, if "install-sh" is required, that requirement
+ # can be satisfied by any of "install-sh", "install.sh", or "shtool",
+ # and $ac_install_sh is set appropriately for whichever one is found.
+ if test x"$ac_aux" = x"install-sh"
+ then
+ if test -f "${as_dir}install-sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
+ ac_install_sh="${as_dir}install-sh -c"
+ elif test -f "${as_dir}install.sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
+ ac_install_sh="${as_dir}install.sh -c"
+ elif test -f "${as_dir}shtool"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
+ ac_install_sh="${as_dir}shtool install -c"
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} install-sh"
+ else
+ break
+ fi
+ fi
+ else
+ if test -f "${as_dir}${ac_aux}"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
+ else
+ break
+ fi
+ fi
+ fi
+ done
+ if test "$ac_aux_dir_found" = yes; then
+ ac_aux_dir="$as_dir"
+ break
+ fi
+ ac_first_candidate=false
+
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5
+fi
+
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+if test -f "${ac_aux_dir}config.guess"; then
+ ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
+fi
+if test -f "${ac_aux_dir}config.sub"; then
+ ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
+fi
+if test -f "$ac_aux_dir/configure"; then
+ ac_configure="$SHELL ${ac_aux_dir}configure"
+fi
+
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
@@ -2835,12 +3359,12 @@ for ac_var in $ac_precious_vars; do
eval ac_new_val=\$ac_env_${ac_var}_value
case $ac_old_set,$ac_new_set in
set,)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$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)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$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=: ;;
,);;
*)
@@ -2849,24 +3373,24 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
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
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$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
- { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$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
- { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-$as_echo "$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.
if test "$ac_new_set" = set; then
case $ac_new_val in
- *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
*) ac_arg=$ac_var=$ac_new_val ;;
esac
case " $ac_configure_args " in
@@ -2876,11 +3400,12 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
fi
done
if $ac_cache_corrupted; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 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: 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'
+ and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
@@ -2895,36 +3420,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
am__api_version='1.16'
-ac_aux_dir=
-for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
-# Find a good install program. We prefer a C program (faster),
+ # Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
@@ -2938,20 +3436,25 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+printf %s "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test ${ac_cv_path_install+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
- ./ | .// | /[cC]/* | \
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ # Account for fact that we put trailing slashes in our PATH walk.
+case $as_dir in #((
+ ./ | /[cC]/* | \
/etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
/usr/ucb/* ) ;;
@@ -2961,13 +3464,13 @@ case $as_dir/ in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
:
elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# program-specific install script used by HP pwplus--don't use.
:
else
@@ -2975,12 +3478,12 @@ case $as_dir/ in #((
echo one > conftest.one
echo two > conftest.two
mkdir conftest.dir
- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
test -s conftest.one && test -s conftest.two &&
test -s conftest.dir/conftest.one &&
test -s conftest.dir/conftest.two
then
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
break 3
fi
fi
@@ -2996,7 +3499,7 @@ IFS=$as_save_IFS
rm -rf conftest.one conftest.two conftest.dir
fi
- if test "${ac_cv_path_install+set}" = set; then
+ if test ${ac_cv_path_install+y}; then
INSTALL=$ac_cv_path_install
else
# As a last resort, use the slow shell script. Don't cache a
@@ -3006,8 +3509,8 @@ fi
INSTALL=$ac_install_sh
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+printf "%s\n" "$INSTALL" >&6; }
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
@@ -3017,8 +3520,8 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
-$as_echo_n "checking whether build environment is sane... " >&6; }
+{ 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
# name. Accept space and tab only in the latter.
am_lf='
@@ -3072,8 +3575,8 @@ else
as_fn_error $? "newly created file is older than distributed files!
Check your system clock" "$LINENO" 5
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+{ 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=
@@ -3092,26 +3595,23 @@ test "$program_suffix" != NONE &&
# Double any \ or $.
# By default was `s,x,x', remove it if useless.
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
-program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"`
+
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
-if test x"${MISSING+set}" != xset; then
- case $am_aux_dir in
- *\ * | *\ *)
- MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
- *)
- MISSING="\${SHELL} $am_aux_dir/missing" ;;
- esac
+
+ if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
fi
# Use eval to expand $SHELL
if eval "$MISSING --is-lightweight"; then
am_missing_run="$MISSING "
else
am_missing_run=
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
-$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
fi
if test x"${install_sh+set}" != xset; then
@@ -3131,11 +3631,12 @@ if test "$cross_compiling" != no; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_STRIP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$STRIP"; then
ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
else
@@ -3143,11 +3644,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3158,11 +3663,11 @@ fi
fi
STRIP=$ac_cv_prog_STRIP
if test -n "$STRIP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-$as_echo "$STRIP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+printf "%s\n" "$STRIP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3171,11 +3676,12 @@ if test -z "$ac_cv_prog_STRIP"; then
ac_ct_STRIP=$STRIP
# Extract the first word of "strip", so it can be a program name with args.
set dummy strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_STRIP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_STRIP"; then
ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
else
@@ -3183,11 +3689,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_STRIP="strip"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3198,11 +3708,11 @@ fi
fi
ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
if test -n "$ac_ct_STRIP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-$as_echo "$ac_ct_STRIP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+printf "%s\n" "$ac_ct_STRIP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_STRIP" = x; then
@@ -3210,8 +3720,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
STRIP=$ac_ct_STRIP
@@ -3223,25 +3733,31 @@ fi
fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
-$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5
+printf %s "checking for a race-free mkdir -p... " >&6; }
if test -z "$MKDIR_P"; then
- if ${ac_cv_path_mkdir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${ac_cv_path_mkdir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; do
- 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 (GNU coreutils) '* | \
- 'mkdir (coreutils) '* | \
+ 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 '* | \
'mkdir (fileutils) '4.1*)
- ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext
break 3;;
esac
done
@@ -3252,7 +3768,7 @@ IFS=$as_save_IFS
fi
test -d ./--version && rmdir ./--version
- if test "${ac_cv_path_mkdir+set}" = set; then
+ 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
@@ -3262,18 +3778,19 @@ fi
MKDIR_P="$ac_install_sh -d"
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
-$as_echo "$MKDIR_P" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+printf "%s\n" "$MKDIR_P" >&6; }
for ac_prog in gawk mawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_AWK+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$AWK"; then
ac_cv_prog_AWK="$AWK" # Let the user override the test.
else
@@ -3281,11 +3798,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_AWK="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3296,24 +3817,25 @@ fi
fi
AWK=$ac_cv_prog_AWK
if test -n "$AWK"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+printf "%s\n" "$AWK" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -n "$AWK" && break
done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
set x ${MAKE-make}
-ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval test \${ac_cv_prog_make_${ac_make}_set+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat >conftest.make <<\_ACEOF
SHELL = /bin/sh
all:
@@ -3329,12 +3851,12 @@ esac
rm -f conftest.make
fi
if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
SET_MAKE=
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
SET_MAKE="MAKE=${MAKE-make}"
fi
@@ -3348,7 +3870,8 @@ fi
rmdir .tst 2>/dev/null
# Check whether --enable-silent-rules was given.
-if test "${enable_silent_rules+set}" = set; then :
+if test ${enable_silent_rules+y}
+then :
enableval=$enable_silent_rules;
fi
@@ -3358,12 +3881,13 @@ case $enable_silent_rules in # (((
*) AM_DEFAULT_VERBOSITY=1;;
esac
am_make=${MAKE-make}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
-if ${am_cv_make_support_nested_variables+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if $as_echo 'TRUE=$(BAR$(V))
+{ 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
@@ -3375,8 +3899,8 @@ else
am_cv_make_support_nested_variables=no
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-$as_echo "$am_cv_make_support_nested_variables" >&6; }
+{ 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)'
@@ -3408,17 +3932,13 @@ fi
# Define the identity of the package.
PACKAGE='dnsdist'
- VERSION='1.8.3'
+ VERSION='1.9.3'
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE "$PACKAGE"
-_ACEOF
+printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define VERSION "$VERSION"
-_ACEOF
+printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h
# Some tools Automake needs.
@@ -3464,29 +3984,29 @@ _am_tools='gnutar plaintar pax cpio none'
# (that is, avoid stderr redirection).
am_uid=`id -u || echo unknown`
am_gid=`id -g || echo unknown`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5
-$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; }
+ { 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
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
_am_tools=none
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5
-$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; }
+ { 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
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
_am_tools=none
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5
-$as_echo_n "checking how to create a ustar tar archive... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5
+printf %s "checking how to create a ustar tar archive... " >&6; }
# Go ahead even if we have the value already cached. We do so because we
# need to set the values for the 'am__tar' and 'am__untar' variables.
@@ -3561,19 +4081,34 @@ $as_echo_n "checking how to create a ustar tar archive... " >&6; }
done
rm -rf conftest.dir
- if ${am_cv_prog_tar_ustar+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${am_cv_prog_tar_ustar+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
am_cv_prog_tar_ustar=$_am_tool
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5
-$as_echo "$am_cv_prog_tar_ustar" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5
+printf "%s\n" "$am_cv_prog_tar_ustar" >&6; }
+# Variables for tags utilities; see am/tags.am
+if test -z "$CTAGS"; then
+ CTAGS=ctags
+fi
+
+if test -z "$ETAGS"; then
+ ETAGS=etags
+fi
+
+if test -z "$CSCOPE"; then
+ CSCOPE=cscope
+fi
+
+
# 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
@@ -3618,7 +4153,8 @@ END
fi
# Check whether --enable-silent-rules was given.
-if test "${enable_silent_rules+set}" = set; then :
+if test ${enable_silent_rules+y}
+then :
enableval=$enable_silent_rules;
fi
@@ -3628,12 +4164,13 @@ case $enable_silent_rules in # (((
*) AM_DEFAULT_VERBOSITY=0;;
esac
am_make=${MAKE-make}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
-if ${am_cv_make_support_nested_variables+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if $as_echo 'TRUE=$(BAR$(V))
+{ 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
@@ -3645,8 +4182,8 @@ else
am_cv_make_support_nested_variables=no
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-$as_echo "$am_cv_make_support_nested_variables" >&6; }
+{ 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)'
@@ -3659,6 +4196,15 @@ AM_BACKSLASH='\'
ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+
+
+
+
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3667,11 +4213,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -3679,11 +4226,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3694,11 +4245,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3707,11 +4258,12 @@ if test -z "$ac_cv_prog_CC"; then
ac_ct_CC=$CC
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
@@ -3719,11 +4271,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3734,11 +4290,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_CC" = x; then
@@ -3746,8 +4302,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -3760,11 +4316,12 @@ if test -z "$CC"; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -3772,11 +4329,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3787,11 +4348,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3800,11 +4361,12 @@ fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -3813,15 +4375,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
fi
ac_cv_prog_CC="cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3837,18 +4403,18 @@ if test $ac_prog_rejected = yes; then
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@"
fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3859,11 +4425,12 @@ if test -z "$CC"; then
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -3871,11 +4438,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3886,11 +4457,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3903,11 +4474,12 @@ if test -z "$CC"; then
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
@@ -3915,11 +4487,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -3930,11 +4506,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -3946,8 +4522,8 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -3955,25 +4531,129 @@ esac
fi
fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
+set dummy ${ac_tool_prefix}clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}clang"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "clang", so it can be a program name with args.
+set dummy clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="clang"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$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; }
# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
+for ac_option in --version -v -V -qversion -version; do
{ { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -3983,7 +4663,7 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
@@ -3991,7 +4671,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
@@ -4003,9 +4683,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+printf %s "checking whether the C compiler works... " >&6; }
+ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
@@ -4026,11 +4706,12 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link_default") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ 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'
# in a Makefile. We should not override ac_cv_exeext if it was cached,
@@ -4047,7 +4728,7 @@ do
# certainly right.
break;;
*.* )
- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
then :; else
ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
fi
@@ -4063,44 +4744,46 @@ do
done
test "$ac_cv_exeext" = no && ac_cv_exeext=
-else
+else $as_nop
ac_file=''
fi
-if test -z "$ac_file"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
+if test -z "$ac_file"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$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_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+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; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+printf "%s\n" "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext
rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+printf %s "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ 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
@@ -4114,15 +4797,15 @@ for ac_file in conftest.exe conftest conftest.*; do
* ) break;;
esac
done
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+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;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+printf "%s\n" "$ac_cv_exeext" >&6; }
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
@@ -4131,7 +4814,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
@@ -4143,8 +4826,8 @@ _ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+printf %s "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
{ { ac_try="$ac_link"
case "(($ac_try" in
@@ -4152,10 +4835,10 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if { ac_try='./conftest$ac_cv_exeext'
{ { case "(($ac_try" in
@@ -4163,39 +4846,40 @@ $as_echo "$ac_try_echo"; } >&5
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
cross_compiling=no
else
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
+ { { 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; }
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
+{ 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
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ 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
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
@@ -4209,11 +4893,12 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
for ac_file in conftest.o conftest.obj conftest.*; do
test -f "$ac_file" || continue;
case $ac_file in
@@ -4222,31 +4907,32 @@ $as_echo "$ac_try_echo"; } >&5
break;;
esac
done
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$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; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+printf "%s\n" "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
+printf %s "checking whether the compiler supports GNU C... " >&6; }
+if test ${ac_cv_c_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
#ifndef __GNUC__
choke me
@@ -4256,29 +4942,33 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_compiler_gnu=yes
-else
+else $as_nop
ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
if test $ac_compiler_gnu = yes; then
GCC=yes
else
GCC=
fi
-ac_test_CFLAGS=${CFLAGS+set}
+ac_test_CFLAGS=${CFLAGS+y}
ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+printf %s "checking whether $CC accepts -g... " >&6; }
+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
ac_c_werror_flag=yes
ac_cv_prog_cc_g=no
@@ -4287,57 +4977,60 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
-else
+else $as_nop
CFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
+else $as_nop
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
+if test $ac_test_CFLAGS; then
CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
@@ -4352,94 +5045,144 @@ else
CFLAGS=
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
+ac_prog_cc_stdc=no
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
+printf %s "checking for $CC option to enable C11 features... " >&6; }
+if test ${ac_cv_prog_cc_c11+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c11=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* 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 don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+$ac_c_conftest_c11_program
+_ACEOF
+for ac_arg in '' -std=gnu11
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c11=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c11" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+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
+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
+printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
+ CC="$CC $ac_cv_prog_cc_c11"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+ ac_prog_cc_stdc=c11
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
+printf %s "checking for $CC option to enable C99 features... " >&6; }
+if test ${ac_cv_prog_cc_c99+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c99_program
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+fi
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
+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
+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
+printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
+ CC="$CC $ac_cv_prog_cc_c99"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+ ac_prog_cc_stdc=c99
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
+printf %s "checking for $CC option to enable C89 features... " >&6; }
+if test ${ac_cv_prog_cc_c89+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_c_conftest_c89_program
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
+ if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_c89=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
test "x$ac_cv_prog_cc_c89" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
-
fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
+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
+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
+printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
+ CC="$CC $ac_cv_prog_cc_c89"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+ ac_prog_cc_stdc=c89
+fi
fi
ac_ext=c
@@ -4448,21 +5191,23 @@ 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
-ac_ext=c
+
+ 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'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
-if ${am_cv_prog_cc_c_o+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+printf %s "checking whether $CC understands -c and -o together... " >&6; }
+if test ${am_cv_prog_cc_c_o+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
@@ -4490,8 +5235,8 @@ _ACEOF
rm -f core conftest*
unset am_i
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-$as_echo "$am_cv_prog_cc_c_o" >&6; }
+{ 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; }
if test "$am_cv_prog_cc_c_o" != yes; then
# Losing compiler, so override with the script.
# FIXME: It is wrong to rewrite CC.
@@ -4510,8 +5255,8 @@ DEPDIR="${am__leading_dot}deps"
ac_config_commands="$ac_config_commands depfiles"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
-$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
+printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; }
cat > confinc.mk << 'END'
am__doit:
@echo this is the am__doit target >confinc.out
@@ -4547,11 +5292,12 @@ esac
fi
done
rm -f confinc.* confmf.*
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
-$as_echo "${_am_result}" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
+printf "%s\n" "${_am_result}" >&6; }
# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then :
+if test ${enable_dependency_tracking+y}
+then :
enableval=$enable_dependency_tracking;
fi
@@ -4572,11 +5318,12 @@ fi
depcc="$CC" am_compiler_list=
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CC_dependencies_compiler_type+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+printf %s "checking dependency style of $depcc... " >&6; }
+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
# 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
@@ -4683,8 +5430,8 @@ else
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+{ 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; }
CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
if
@@ -4698,6 +5445,12 @@ else
fi
+
+
+
+
+
+
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -4708,15 +5461,16 @@ if test -z "$CXX"; then
CXX=$CCC
else
if test -n "$ac_tool_prefix"; then
- for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CXX"; then
ac_cv_prog_CXX="$CXX" # Let the user override the test.
else
@@ -4724,11 +5478,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4739,11 +5497,11 @@ fi
fi
CXX=$ac_cv_prog_CXX
if test -n "$CXX"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
-$as_echo "$CXX" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+printf "%s\n" "$CXX" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -4752,15 +5510,16 @@ fi
fi
if test -z "$CXX"; then
ac_ct_CXX=$CXX
- for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CXX"; then
ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
else
@@ -4768,11 +5527,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CXX="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4783,11 +5546,11 @@ fi
fi
ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
if test -n "$ac_ct_CXX"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
-$as_echo "$ac_ct_CXX" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+printf "%s\n" "$ac_ct_CXX" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -4799,8 +5562,8 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CXX=$ac_ct_CXX
@@ -4810,7 +5573,7 @@ fi
fi
fi
# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
@@ -4820,7 +5583,7 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -4830,20 +5593,21 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
-$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if ${ac_cv_cxx_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5
+printf %s "checking whether the compiler supports GNU C++... " >&6; }
+if test ${ac_cv_cxx_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
#ifndef __GNUC__
choke me
@@ -4853,29 +5617,33 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
ac_compiler_gnu=yes
-else
+else $as_nop
ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
-$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
if test $ac_compiler_gnu = yes; then
GXX=yes
else
GXX=
fi
-ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_test_CXXFLAGS=${CXXFLAGS+y}
ac_save_CXXFLAGS=$CXXFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
-$as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if ${ac_cv_prog_cxx_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+printf %s "checking whether $CXX accepts -g... " >&6; }
+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
ac_cxx_werror_flag=yes
ac_cv_prog_cxx_g=no
@@ -4884,57 +5652,60 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
ac_cv_prog_cxx_g=yes
-else
+else $as_nop
CXXFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
-else
+else $as_nop
ac_cxx_werror_flag=$ac_save_cxx_werror_flag
CXXFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
ac_cv_prog_cxx_g=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cxx_werror_flag=$ac_save_cxx_werror_flag
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
-$as_echo "$ac_cv_prog_cxx_g" >&6; }
-if test "$ac_test_CXXFLAGS" = set; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+printf "%s\n" "$ac_cv_prog_cxx_g" >&6; }
+if test $ac_test_CXXFLAGS; then
CXXFLAGS=$ac_save_CXXFLAGS
elif test $ac_cv_prog_cxx_g = yes; then
if test "$GXX" = yes; then
@@ -4949,6 +5720,100 @@ else
CXXFLAGS=
fi
fi
+ac_prog_cxx_stdcxx=no
+if test x$ac_prog_cxx_stdcxx = xno
+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}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cxx_11=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_cxx_conftest_cxx11_program
+_ACEOF
+for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA
+do
+ CXX="$ac_save_CXX $ac_arg"
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_cxx11=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cxx_cxx11" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+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
+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
+printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; }
+ CXX="$CXX $ac_cv_prog_cxx_cxx11"
+fi
+ ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11
+ ac_prog_cxx_stdcxx=cxx11
+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}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cxx_98=no
+ac_save_CXX=$CXX
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_cxx_conftest_cxx98_program
+_ACEOF
+for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA
+do
+ CXX="$ac_save_CXX $ac_arg"
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
+ ac_cv_prog_cxx_cxx98=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cxx_cxx98" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CXX=$ac_save_CXX
+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
+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
+printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; }
+ CXX="$CXX $ac_cv_prog_cxx_cxx98"
+fi
+ ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98
+ ac_prog_cxx_stdcxx=cxx98
+fi
+fi
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -4957,11 +5822,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
depcc="$CXX" am_compiler_list=
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+printf %s "checking dependency style of $depcc... " >&6; }
+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
# 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
@@ -5068,8 +5934,8 @@ else
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+{ 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; }
CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
if
@@ -5091,20 +5957,21 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-$as_echo "#define DNSDIST 1" >>confdefs.h
+printf "%s\n" "#define DNSDIST 1" >>confdefs.h
case `pwd` in
*\ * | *\ *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
esac
-macro_version='2.4.6'
-macro_revision='2.4.6'
+macro_version='2.4.7'
+macro_revision='2.4.7'
+
@@ -5120,26 +5987,29 @@ macro_revision='2.4.6'
ltmain=$ac_aux_dir/ltmain.sh
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+
+ # Make sure we can run config.sub.
+$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+printf %s "checking build system type... " >&6; }
+if test ${ac_cv_build+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+ 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
+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
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+printf "%s\n" "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
@@ -5158,21 +6028,22 @@ IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+printf %s "checking host system type... " >&6; }
+if test ${ac_cv_host+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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
+ 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
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+printf "%s\n" "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
@@ -5212,8 +6083,8 @@ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-$as_echo_n "checking how to print strings... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+printf %s "checking how to print strings... " >&6; }
# Test print first, because it will be a builtin if present.
if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
@@ -5239,12 +6110,12 @@ func_echo_all ()
}
case $ECHO in
- printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-$as_echo "printf" >&6; } ;;
- print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-$as_echo "print -r" >&6; } ;;
- *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-$as_echo "cat" >&6; } ;;
+ printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+printf "%s\n" "printf" >&6; } ;;
+ print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+printf "%s\n" "print -r" >&6; } ;;
+ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+printf "%s\n" "cat" >&6; } ;;
esac
@@ -5260,11 +6131,12 @@ esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
-$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+printf %s "checking for a sed that does not truncate output... " >&6; }
+if test ${ac_cv_path_SED+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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"
@@ -5278,10 +6150,15 @@ else
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in sed gsed; do
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in sed gsed
+ do
for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ ac_path_SED="$as_dir$ac_prog$ac_exec_ext"
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
@@ -5290,13 +6167,13 @@ case `"$ac_path_SED" --version 2>&1` in
ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo '' >> "conftest.nl"
+ printf "%s\n" '' >> "conftest.nl"
"$ac_path_SED" -f conftest.sed < "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
@@ -5324,8 +6201,8 @@ else
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
-$as_echo "$ac_cv_path_SED" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+printf "%s\n" "$ac_cv_path_SED" >&6; }
SED="$ac_cv_path_SED"
rm -f conftest.sed
@@ -5342,11 +6219,12 @@ Xsed="$SED -e 1s/^X//"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ 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
ac_path_GREP_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
@@ -5354,10 +6232,15 @@ else
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in grep ggrep; do
+ 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"
+ 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
@@ -5366,13 +6249,13 @@ case `"$ac_path_GREP" --version 2>&1` in
ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo 'GREP' >> "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
@@ -5400,16 +6283,17 @@ else
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
+{ 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"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ 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 $as_nop
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
then ac_cv_path_EGREP="$GREP -E"
else
@@ -5420,10 +6304,15 @@ else
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in egrep; do
+ 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"
+ 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
@@ -5432,13 +6321,13 @@ case `"$ac_path_EGREP" --version 2>&1` in
ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo 'EGREP' >> "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
@@ -5467,16 +6356,17 @@ fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
+{ 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"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
-$as_echo_n "checking for fgrep... " >&6; }
-if ${ac_cv_path_FGREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ 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
then ac_cv_path_FGREP="$GREP -F"
else
@@ -5487,10 +6377,15 @@ else
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in fgrep; do
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in fgrep
+ do
for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext"
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
@@ -5499,13 +6394,13 @@ case `"$ac_path_FGREP" --version 2>&1` in
ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo 'FGREP' >> "conftest.nl"
+ printf "%s\n" 'FGREP' >> "conftest.nl"
"$ac_path_FGREP" FGREP < "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
@@ -5534,8 +6429,8 @@ fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
-$as_echo "$ac_cv_path_FGREP" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+printf "%s\n" "$ac_cv_path_FGREP" >&6; }
FGREP="$ac_cv_path_FGREP"
@@ -5560,17 +6455,18 @@ test -z "$GREP" && GREP=grep
# Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then :
+if test ${with_gnu_ld+y}
+then :
withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
-else
+else $as_nop
with_gnu_ld=no
fi
ac_prog=ld
if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-$as_echo_n "checking for ld used by $CC... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+printf %s "checking for ld used by $CC... " >&6; }
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return, which upsets mingw
@@ -5599,15 +6495,16 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
;;
esac
elif test yes = "$with_gnu_ld"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-$as_echo_n "checking for GNU ld... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+printf %s "checking for GNU ld... " >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-$as_echo_n "checking for non-GNU ld... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+printf %s "checking for non-GNU ld... " >&6; }
fi
-if ${lt_cv_path_LD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test ${lt_cv_path_LD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -z "$LD"; then
lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
@@ -5636,18 +6533,19 @@ fi
LD=$lt_cv_path_LD
if test -n "$LD"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
-$as_echo "$LD" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+printf "%s\n" "$LD" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+printf %s "checking if the linker ($LD) is GNU ld... " >&6; }
+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.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
@@ -5658,8 +6556,8 @@ case `$LD -v 2>&1 </dev/null` in
;;
esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
-$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; }
with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -5670,11 +6568,12 @@ with_gnu_ld=$lt_cv_prog_gnu_ld
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
-$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
-if ${lt_cv_path_NM+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test ${lt_cv_path_NM+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$NM"; then
# Let the user override the test.
lt_cv_path_NM=$NM
@@ -5699,13 +6598,13 @@ else
mingw*) lt_bad_file=conftest.nm/nofile ;;
*) lt_bad_file=/dev/null ;;
esac
- case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in
*$lt_bad_file* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
break 2
;;
*)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
break 2
@@ -5724,8 +6623,8 @@ else
: ${lt_cv_path_NM=no}
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
-$as_echo "$lt_cv_path_NM" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+printf "%s\n" "$lt_cv_path_NM" >&6; }
if test no != "$lt_cv_path_NM"; then
NM=$lt_cv_path_NM
else
@@ -5738,11 +6637,12 @@ else
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DUMPBIN+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_DUMPBIN+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$DUMPBIN"; then
ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
else
@@ -5750,11 +6650,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -5765,11 +6669,11 @@ fi
fi
DUMPBIN=$ac_cv_prog_DUMPBIN
if test -n "$DUMPBIN"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
-$as_echo "$DUMPBIN" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+printf "%s\n" "$DUMPBIN" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -5782,11 +6686,12 @@ if test -z "$DUMPBIN"; then
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_DUMPBIN+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_DUMPBIN"; then
ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
else
@@ -5794,11 +6699,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -5809,11 +6718,11 @@ fi
fi
ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
if test -n "$ac_ct_DUMPBIN"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
-$as_echo "$ac_ct_DUMPBIN" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+printf "%s\n" "$ac_ct_DUMPBIN" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -5825,15 +6734,15 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
DUMPBIN=$ac_ct_DUMPBIN
fi
fi
- case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in
*COFF*)
DUMPBIN="$DUMPBIN -symbols -headers"
;;
@@ -5854,11 +6763,12 @@ test -z "$NM" && NM=nm
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
-$as_echo_n "checking the name lister ($NM) interface... " >&6; }
-if ${lt_cv_nm_interface+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+printf %s "checking the name lister ($NM) interface... " >&6; }
+if test ${lt_cv_nm_interface+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
@@ -5874,26 +6784,27 @@ else
fi
rm -f conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
-$as_echo "$lt_cv_nm_interface" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+printf "%s\n" "$lt_cv_nm_interface" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
-$as_echo_n "checking whether ln -s works... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+printf %s "checking whether ln -s works... " >&6; }
LN_S=$as_ln_s
if test "$LN_S" = "ln -s"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-$as_echo "no, using $LN_S" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+printf "%s\n" "no, using $LN_S" >&6; }
fi
# find the maximum length of command line arguments
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
-$as_echo_n "checking the maximum length of command line arguments... " >&6; }
-if ${lt_cv_sys_max_cmd_len+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+printf %s "checking the maximum length of command line arguments... " >&6; }
+if test ${lt_cv_sys_max_cmd_len+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
i=0
teststring=ABCD
@@ -5935,7 +6846,7 @@ else
lt_cv_sys_max_cmd_len=8192;
;;
- bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -5978,7 +6889,7 @@ else
sysv5* | sco5v6* | sysv4.2uw2*)
kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[ ]//'`
else
lt_cv_sys_max_cmd_len=32768
fi
@@ -6020,11 +6931,11 @@ else
fi
if test -n "$lt_cv_sys_max_cmd_len"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
-$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
-$as_echo "none" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
+printf "%s\n" "none" >&6; }
fi
max_cmd_len=$lt_cv_sys_max_cmd_len
@@ -6068,11 +6979,12 @@ esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
-$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
-if ${lt_cv_to_host_file_cmd+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+printf %s "checking how to convert $build file names to $host format... " >&6; }
+if test ${lt_cv_to_host_file_cmd+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $host in
*-*-mingw* )
case $build in
@@ -6108,18 +7020,19 @@ esac
fi
to_host_file_cmd=$lt_cv_to_host_file_cmd
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
-$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
-$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
-if ${lt_cv_to_tool_file_cmd+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+printf %s "checking how to convert $build file names to toolchain format... " >&6; }
+if test ${lt_cv_to_tool_file_cmd+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
#assume ordinary cross tools, or native build.
lt_cv_to_tool_file_cmd=func_convert_file_noop
case $host in
@@ -6135,22 +7048,23 @@ esac
fi
to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
-$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
-$as_echo_n "checking for $LD option to reload object files... " >&6; }
-if ${lt_cv_ld_reload_flag+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+printf %s "checking for $LD option to reload object files... " >&6; }
+if test ${lt_cv_ld_reload_flag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_ld_reload_flag='-r'
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
-$as_echo "$lt_cv_ld_reload_flag" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+printf "%s\n" "$lt_cv_ld_reload_flag" >&6; }
reload_flag=$lt_cv_ld_reload_flag
case $reload_flag in
"" | " "*) ;;
@@ -6181,13 +7095,122 @@ esac
if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args.
+set dummy ${ac_tool_prefix}file; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_FILECMD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$FILECMD"; then
+ ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_FILECMD="${ac_tool_prefix}file"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+FILECMD=$ac_cv_prog_FILECMD
+if test -n "$FILECMD"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5
+printf "%s\n" "$FILECMD" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_FILECMD"; then
+ ac_ct_FILECMD=$FILECMD
+ # Extract the first word of "file", so it can be a program name with args.
+set dummy file; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_FILECMD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_FILECMD="file"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD
+if test -n "$ac_ct_FILECMD"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5
+printf "%s\n" "$ac_ct_FILECMD" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_FILECMD" = x; then
+ FILECMD=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ FILECMD=$ac_ct_FILECMD
+ fi
+else
+ FILECMD="$ac_cv_prog_FILECMD"
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
set dummy ${ac_tool_prefix}objdump; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OBJDUMP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_OBJDUMP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$OBJDUMP"; then
ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
else
@@ -6195,11 +7218,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6210,11 +7237,11 @@ fi
fi
OBJDUMP=$ac_cv_prog_OBJDUMP
if test -n "$OBJDUMP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
-$as_echo "$OBJDUMP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+printf "%s\n" "$OBJDUMP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6223,11 +7250,12 @@ if test -z "$ac_cv_prog_OBJDUMP"; then
ac_ct_OBJDUMP=$OBJDUMP
# Extract the first word of "objdump", so it can be a program name with args.
set dummy objdump; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_OBJDUMP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_OBJDUMP"; then
ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
else
@@ -6235,11 +7263,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_OBJDUMP="objdump"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6250,11 +7282,11 @@ fi
fi
ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
if test -n "$ac_ct_OBJDUMP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
-$as_echo "$ac_ct_OBJDUMP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+printf "%s\n" "$ac_ct_OBJDUMP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_OBJDUMP" = x; then
@@ -6262,8 +7294,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
OBJDUMP=$ac_ct_OBJDUMP
@@ -6282,11 +7314,12 @@ test -z "$OBJDUMP" && OBJDUMP=objdump
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
-$as_echo_n "checking how to recognize dependent libraries... " >&6; }
-if ${lt_cv_deplibs_check_method+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+printf %s "checking how to recognize dependent libraries... " >&6; }
+if test ${lt_cv_deplibs_check_method+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_file_magic_cmd='$MAGIC_CMD'
lt_cv_file_magic_test_file=
lt_cv_deplibs_check_method='unknown'
@@ -6312,7 +7345,7 @@ beos*)
bsdi[45]*)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_cmd='$FILECMD -L'
lt_cv_file_magic_test_file=/shlib/libc.so
;;
@@ -6346,14 +7379,14 @@ darwin* | rhapsody*)
lt_cv_deplibs_check_method=pass_all
;;
-freebsd* | dragonfly*)
+freebsd* | dragonfly* | midnightbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
esac
@@ -6367,7 +7400,7 @@ haiku*)
;;
hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
case $host_cpu in
ia64*)
lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
@@ -6414,7 +7447,7 @@ netbsd*)
newos6*)
lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
lt_cv_file_magic_test_file=/usr/lib/libnls.so
;;
@@ -6482,8 +7515,8 @@ os2*)
esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
-$as_echo "$lt_cv_deplibs_check_method" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+printf "%s\n" "$lt_cv_deplibs_check_method" >&6; }
file_magic_glob=
want_nocaseglob=no
@@ -6527,11 +7560,12 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
set dummy ${ac_tool_prefix}dlltool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DLLTOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_DLLTOOL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$DLLTOOL"; then
ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
else
@@ -6539,11 +7573,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6554,11 +7592,11 @@ fi
fi
DLLTOOL=$ac_cv_prog_DLLTOOL
if test -n "$DLLTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
-$as_echo "$DLLTOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+printf "%s\n" "$DLLTOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6567,11 +7605,12 @@ if test -z "$ac_cv_prog_DLLTOOL"; then
ac_ct_DLLTOOL=$DLLTOOL
# Extract the first word of "dlltool", so it can be a program name with args.
set dummy dlltool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_DLLTOOL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_DLLTOOL"; then
ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
else
@@ -6579,11 +7618,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_DLLTOOL="dlltool"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6594,11 +7637,11 @@ fi
fi
ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
if test -n "$ac_ct_DLLTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
-$as_echo "$ac_ct_DLLTOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+printf "%s\n" "$ac_ct_DLLTOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_DLLTOOL" = x; then
@@ -6606,8 +7649,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
DLLTOOL=$ac_ct_DLLTOOL
@@ -6627,11 +7670,12 @@ test -z "$DLLTOOL" && DLLTOOL=dlltool
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
-$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
-if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+printf %s "checking how to associate runtime and link libraries... " >&6; }
+if test ${lt_cv_sharedlib_from_linklib_cmd+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_sharedlib_from_linklib_cmd='unknown'
case $host_os in
@@ -6654,8 +7698,8 @@ cygwin* | mingw* | pw32* | cegcc*)
esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
-$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+{ 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; }
sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
@@ -6671,11 +7715,12 @@ if test -n "$ac_tool_prefix"; then
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_AR+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$AR"; then
ac_cv_prog_AR="$AR" # Let the user override the test.
else
@@ -6683,11 +7728,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6698,11 +7747,11 @@ fi
fi
AR=$ac_cv_prog_AR
if test -n "$AR"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-$as_echo "$AR" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+printf "%s\n" "$AR" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6715,11 +7764,12 @@ if test -z "$AR"; then
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AR+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_AR+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_AR"; then
ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
@@ -6727,11 +7777,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_AR="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6742,11 +7796,11 @@ fi
fi
ac_ct_AR=$ac_cv_prog_ac_ct_AR
if test -n "$ac_ct_AR"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-$as_echo "$ac_ct_AR" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+printf "%s\n" "$ac_ct_AR" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6758,8 +7812,8 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
AR=$ac_ct_AR
@@ -6767,42 +7821,60 @@ esac
fi
: ${AR=ar}
-: ${AR_FLAGS=cru}
+# Use ARFLAGS variable as AR's operation code to sync the variable naming with
+# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
+# higher priority because thats what people were doing historically (setting
+# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS
+# variable obsoleted/removed.
+test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr}
+lt_ar_flags=$AR_FLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
-$as_echo_n "checking for archiver @FILE support... " >&6; }
-if ${lt_cv_ar_at_file+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+
+
+# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override
+# by AR_FLAGS because that was never working and AR_FLAGS is about to die.
+
+
+
+
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+printf %s "checking for archiver @FILE support... " >&6; }
+if test ${lt_cv_ar_at_file+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_ar_at_file=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
echo conftest.$ac_objext > conftest.lst
lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
(eval $lt_ar_try) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if test 0 -eq "$ac_status"; then
# Ensure the archiver fails upon bogus file names.
@@ -6810,7 +7882,7 @@ if ac_fn_cxx_try_compile "$LINENO"; then :
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
(eval $lt_ar_try) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if test 0 -ne "$ac_status"; then
lt_cv_ar_at_file=@
@@ -6819,11 +7891,11 @@ if ac_fn_cxx_try_compile "$LINENO"; then :
rm -f conftest.* libconftest.a
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
-$as_echo "$lt_cv_ar_at_file" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+printf "%s\n" "$lt_cv_ar_at_file" >&6; }
if test no = "$lt_cv_ar_at_file"; then
archiver_list_spec=
@@ -6840,11 +7912,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_STRIP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$STRIP"; then
ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
else
@@ -6852,11 +7925,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6867,11 +7944,11 @@ fi
fi
STRIP=$ac_cv_prog_STRIP
if test -n "$STRIP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-$as_echo "$STRIP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+printf "%s\n" "$STRIP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6880,11 +7957,12 @@ if test -z "$ac_cv_prog_STRIP"; then
ac_ct_STRIP=$STRIP
# Extract the first word of "strip", so it can be a program name with args.
set dummy strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_STRIP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_STRIP"; then
ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
else
@@ -6892,11 +7970,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_STRIP="strip"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6907,11 +7989,11 @@ fi
fi
ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
if test -n "$ac_ct_STRIP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-$as_echo "$ac_ct_STRIP" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+printf "%s\n" "$ac_ct_STRIP" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_STRIP" = x; then
@@ -6919,8 +8001,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
STRIP=$ac_ct_STRIP
@@ -6939,11 +8021,12 @@ test -z "$STRIP" && STRIP=:
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$RANLIB"; then
ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
@@ -6951,11 +8034,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -6966,11 +8053,11 @@ fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+printf "%s\n" "$RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -6979,11 +8066,12 @@ if test -z "$ac_cv_prog_RANLIB"; then
ac_ct_RANLIB=$RANLIB
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_RANLIB"; then
ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
@@ -6991,11 +8079,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -7006,11 +8098,11 @@ fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+printf "%s\n" "$ac_ct_RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_RANLIB" = x; then
@@ -7018,8 +8110,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
RANLIB=$ac_ct_RANLIB
@@ -7108,11 +8200,12 @@ compiler=$CC
# Check for command to grab the raw symbol name followed by C symbol from nm.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
-$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
-if ${lt_cv_sys_global_symbol_pipe+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+printf %s "checking command to parse $NM output from $compiler object... " >&6; }
+if test ${lt_cv_sys_global_symbol_pipe+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
# These are sane defaults that work on at least a few old systems.
# [They come from Ultrix. What could be older than Ultrix?!! ;)]
@@ -7167,7 +8260,7 @@ esac
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
# Gets list of data symbols to import.
- lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'"
# Adjust the below global symbol transforms to fixup imported variables.
lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
@@ -7185,20 +8278,20 @@ fi
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+lt_cv_sys_global_symbol_to_cdecl="$SED -n"\
$lt_cdecl_hook\
" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\
$lt_c_name_hook\
" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
# Transform an extracted symbol line into symbol name with lib prefix and
# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\
$lt_c_name_lib_hook\
" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
@@ -7222,7 +8315,7 @@ for ac_symprfx in "" "_"; do
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
# Fake it for dumpbin and say T for any non-static function,
# D for any global variable and I for any imported variable.
- # Also find C++ and __fastcall symbols from MSVC++,
+ # Also find C++ and __fastcall symbols from MSVC++ or ICC,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK '"\
" {last_section=section; section=\$ 3};"\
@@ -7240,9 +8333,9 @@ for ac_symprfx in "" "_"; do
" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx"
else
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'"
# Check to see that the pipe works correctly.
pipe_works=no
@@ -7264,14 +8357,14 @@ _LT_EOF
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
# Now try to grab the symbols.
nlist=conftest.nm
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
(eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && test -s "$nlist"; then
# Try sorting and uniquifying the output.
if sort "$nlist" | uniq > "$nlist"T; then
@@ -7340,7 +8433,7 @@ _LT_EOF
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
(eval $ac_link) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && test -s conftest$ac_exeext; then
pipe_works=yes
fi
@@ -7375,11 +8468,11 @@ if test -z "$lt_cv_sys_global_symbol_pipe"; then
lt_cv_sys_global_symbol_to_cdecl=
fi
if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-$as_echo "failed" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+printf "%s\n" "failed" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-$as_echo "ok" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+printf "%s\n" "ok" >&6; }
fi
# Response file support.
@@ -7425,13 +8518,14 @@ fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
-$as_echo_n "checking for sysroot... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+printf %s "checking for sysroot... " >&6; }
# Check whether --with-sysroot was given.
-if test "${with_sysroot+set}" = set; then :
+if test ${with_sysroot+y}
+then :
withval=$with_sysroot;
-else
+else $as_nop
with_sysroot=no
fi
@@ -7444,29 +8538,30 @@ case $with_sysroot in #(
fi
;; #(
/*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"`
;; #(
no|'')
;; #(
*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
-$as_echo "$with_sysroot" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+printf "%s\n" "$with_sysroot" >&6; }
as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
-$as_echo "${lt_sysroot:-no}" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+printf "%s\n" "${lt_sysroot:-no}" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
-$as_echo_n "checking for a working dd... " >&6; }
-if ${ac_cv_path_lt_DD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+printf %s "checking for a working dd... " >&6; }
+if test ${ac_cv_path_lt_DD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
printf 0123456789abcdef0123456789abcdef >conftest.i
cat conftest.i conftest.i >conftest2.i
: ${lt_DD:=$DD}
@@ -7477,10 +8572,15 @@ if test -z "$lt_DD"; then
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in dd; do
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in dd
+ do
for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+ ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext"
as_fn_executable_p "$ac_path_lt_DD" || continue
if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
cmp -s conftest.i conftest.out \
@@ -7500,15 +8600,16 @@ fi
rm -f conftest.i conftest2.i conftest.out
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
-$as_echo "$ac_cv_path_lt_DD" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+printf "%s\n" "$ac_cv_path_lt_DD" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
-$as_echo_n "checking how to truncate binary pipes... " >&6; }
-if ${lt_cv_truncate_bin+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+printf %s "checking how to truncate binary pipes... " >&6; }
+if test ${lt_cv_truncate_bin+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
printf 0123456789abcdef0123456789abcdef >conftest.i
cat conftest.i conftest.i >conftest2.i
lt_cv_truncate_bin=
@@ -7519,8 +8620,8 @@ fi
rm -f conftest.i conftest2.i conftest.out
test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
-$as_echo "$lt_cv_truncate_bin" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+printf "%s\n" "$lt_cv_truncate_bin" >&6; }
@@ -7544,7 +8645,8 @@ func_cc_basename ()
# Check whether --enable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then :
+if test ${enable_libtool_lock+y}
+then :
enableval=$enable_libtool_lock;
fi
@@ -7560,9 +8662,9 @@ ia64-*-hpux*)
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*ELF-32*)
HPUX_IA64_MODE=32
;;
@@ -7580,10 +8682,10 @@ ia64-*-hpux*)
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
if test yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
;;
@@ -7595,7 +8697,7 @@ ia64-*-hpux*)
;;
esac
else
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -32"
;;
@@ -7618,10 +8720,10 @@ mips64*-*linux*)
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
emul=elf
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
emul="${emul}32"
;;
@@ -7629,7 +8731,7 @@ mips64*-*linux*)
emul="${emul}64"
;;
esac
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*MSB*)
emul="${emul}btsmip"
;;
@@ -7637,7 +8739,7 @@ mips64*-*linux*)
emul="${emul}ltsmip"
;;
esac
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*N32*)
emul="${emul}n32"
;;
@@ -7659,16 +8761,16 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*32-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*x86-64*)
LD="${LD-ld} -m elf32_x86_64"
;;
@@ -7722,11 +8824,12 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
SAVE_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -belf"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
-$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
-if ${lt_cv_cc_needs_belf+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+printf %s "checking whether the C compiler needs -belf... " >&6; }
+if test ${lt_cv_cc_needs_belf+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -7737,19 +8840,20 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
lt_cv_cc_needs_belf=yes
-else
+else $as_nop
lt_cv_cc_needs_belf=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -7758,8 +8862,8 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
-$as_echo "$lt_cv_cc_needs_belf" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+printf "%s\n" "$lt_cv_cc_needs_belf" >&6; }
if test yes != "$lt_cv_cc_needs_belf"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
CFLAGS=$SAVE_CFLAGS
@@ -7772,9 +8876,9 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*64-bit*)
case $lt_cv_prog_gnu_ld in
yes*)
@@ -7809,11 +8913,12 @@ need_locks=$enable_libtool_lock
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
set dummy ${ac_tool_prefix}mt; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_MANIFEST_TOOL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$MANIFEST_TOOL"; then
ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
else
@@ -7821,11 +8926,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -7836,11 +8945,11 @@ fi
fi
MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
if test -n "$MANIFEST_TOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
-$as_echo "$MANIFEST_TOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+printf "%s\n" "$MANIFEST_TOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -7849,11 +8958,12 @@ if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
# Extract the first word of "mt", so it can be a program name with args.
set dummy mt; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+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
ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
else
@@ -7861,11 +8971,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -7876,11 +8990,11 @@ fi
fi
ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
if test -n "$ac_ct_MANIFEST_TOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
-$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_MANIFEST_TOOL" = x; then
@@ -7888,8 +9002,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
@@ -7899,11 +9013,12 @@ else
fi
test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
-$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
-if ${lt_cv_path_mainfest_tool+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if test ${lt_cv_path_mainfest_tool+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_path_mainfest_tool=no
echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
$MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
@@ -7913,8 +9028,8 @@ else
fi
rm -f conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
-$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; }
if test yes != "$lt_cv_path_mainfest_tool"; then
MANIFEST_TOOL=:
fi
@@ -7929,11 +9044,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DSYMUTIL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_DSYMUTIL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$DSYMUTIL"; then
ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
else
@@ -7941,11 +9057,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -7956,11 +9076,11 @@ fi
fi
DSYMUTIL=$ac_cv_prog_DSYMUTIL
if test -n "$DSYMUTIL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
-$as_echo "$DSYMUTIL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+printf "%s\n" "$DSYMUTIL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -7969,11 +9089,12 @@ if test -z "$ac_cv_prog_DSYMUTIL"; then
ac_ct_DSYMUTIL=$DSYMUTIL
# Extract the first word of "dsymutil", so it can be a program name with args.
set dummy dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_DSYMUTIL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_DSYMUTIL"; then
ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
else
@@ -7981,11 +9102,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -7996,11 +9121,11 @@ fi
fi
ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
if test -n "$ac_ct_DSYMUTIL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
-$as_echo "$ac_ct_DSYMUTIL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+printf "%s\n" "$ac_ct_DSYMUTIL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_DSYMUTIL" = x; then
@@ -8008,8 +9133,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
DSYMUTIL=$ac_ct_DSYMUTIL
@@ -8021,11 +9146,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
set dummy ${ac_tool_prefix}nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_NMEDIT+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_NMEDIT+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$NMEDIT"; then
ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
else
@@ -8033,11 +9159,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8048,11 +9178,11 @@ fi
fi
NMEDIT=$ac_cv_prog_NMEDIT
if test -n "$NMEDIT"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
-$as_echo "$NMEDIT" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+printf "%s\n" "$NMEDIT" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -8061,11 +9191,12 @@ if test -z "$ac_cv_prog_NMEDIT"; then
ac_ct_NMEDIT=$NMEDIT
# Extract the first word of "nmedit", so it can be a program name with args.
set dummy nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_NMEDIT+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_NMEDIT"; then
ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
else
@@ -8073,11 +9204,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_NMEDIT="nmedit"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8088,11 +9223,11 @@ fi
fi
ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
if test -n "$ac_ct_NMEDIT"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
-$as_echo "$ac_ct_NMEDIT" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+printf "%s\n" "$ac_ct_NMEDIT" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_NMEDIT" = x; then
@@ -8100,8 +9235,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
NMEDIT=$ac_ct_NMEDIT
@@ -8113,11 +9248,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
set dummy ${ac_tool_prefix}lipo; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LIPO+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_LIPO+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$LIPO"; then
ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
else
@@ -8125,11 +9261,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8140,11 +9280,11 @@ fi
fi
LIPO=$ac_cv_prog_LIPO
if test -n "$LIPO"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
-$as_echo "$LIPO" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+printf "%s\n" "$LIPO" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -8153,11 +9293,12 @@ if test -z "$ac_cv_prog_LIPO"; then
ac_ct_LIPO=$LIPO
# Extract the first word of "lipo", so it can be a program name with args.
set dummy lipo; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_LIPO+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_LIPO"; then
ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
else
@@ -8165,11 +9306,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_LIPO="lipo"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8180,11 +9325,11 @@ fi
fi
ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
if test -n "$ac_ct_LIPO"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
-$as_echo "$ac_ct_LIPO" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+printf "%s\n" "$ac_ct_LIPO" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_LIPO" = x; then
@@ -8192,8 +9337,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
LIPO=$ac_ct_LIPO
@@ -8205,11 +9350,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
set dummy ${ac_tool_prefix}otool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_OTOOL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$OTOOL"; then
ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
else
@@ -8217,11 +9363,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8232,11 +9382,11 @@ fi
fi
OTOOL=$ac_cv_prog_OTOOL
if test -n "$OTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+printf "%s\n" "$OTOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -8245,11 +9395,12 @@ if test -z "$ac_cv_prog_OTOOL"; then
ac_ct_OTOOL=$OTOOL
# Extract the first word of "otool", so it can be a program name with args.
set dummy otool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_OTOOL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_OTOOL"; then
ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
else
@@ -8257,11 +9408,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_OTOOL="otool"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8272,11 +9427,11 @@ fi
fi
ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
if test -n "$ac_ct_OTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
-$as_echo "$ac_ct_OTOOL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+printf "%s\n" "$ac_ct_OTOOL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_OTOOL" = x; then
@@ -8284,8 +9439,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
OTOOL=$ac_ct_OTOOL
@@ -8297,11 +9452,12 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
set dummy ${ac_tool_prefix}otool64; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL64+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_OTOOL64+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$OTOOL64"; then
ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
else
@@ -8309,11 +9465,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8324,11 +9484,11 @@ fi
fi
OTOOL64=$ac_cv_prog_OTOOL64
if test -n "$OTOOL64"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
-$as_echo "$OTOOL64" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+printf "%s\n" "$OTOOL64" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -8337,11 +9497,12 @@ if test -z "$ac_cv_prog_OTOOL64"; then
ac_ct_OTOOL64=$OTOOL64
# Extract the first word of "otool64", so it can be a program name with args.
set dummy otool64; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_OTOOL64+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_OTOOL64"; then
ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
else
@@ -8349,11 +9510,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_OTOOL64="otool64"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -8364,11 +9529,11 @@ fi
fi
ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
if test -n "$ac_ct_OTOOL64"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
-$as_echo "$ac_ct_OTOOL64" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+printf "%s\n" "$ac_ct_OTOOL64" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_OTOOL64" = x; then
@@ -8376,8 +9541,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
OTOOL64=$ac_ct_OTOOL64
@@ -8412,11 +9577,12 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
-$as_echo_n "checking for -single_module linker flag... " >&6; }
-if ${lt_cv_apple_cc_single_mod+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+printf %s "checking for -single_module linker flag... " >&6; }
+if test ${lt_cv_apple_cc_single_mod+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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
@@ -8445,14 +9611,15 @@ else
rm -f conftest.*
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
-$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+{ 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; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
-$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
-if ${lt_cv_ld_exported_symbols_list+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+printf %s "checking for -exported_symbols_list linker flag... " >&6; }
+if test ${lt_cv_ld_exported_symbols_list+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_ld_exported_symbols_list=no
save_LDFLAGS=$LDFLAGS
echo "_main" > conftest.sym
@@ -8461,39 +9628,41 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
lt_cv_ld_exported_symbols_list=yes
-else
+else $as_nop
lt_cv_ld_exported_symbols_list=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LDFLAGS=$save_LDFLAGS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
-$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+{ 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; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
-$as_echo_n "checking for -force_load linker flag... " >&6; }
-if ${lt_cv_ld_force_load+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+printf %s "checking for -force_load linker flag... " >&6; }
+if test ${lt_cv_ld_force_load+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_ld_force_load=no
cat > conftest.c << _LT_EOF
int forced_loaded() { return 2;}
_LT_EOF
echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
$LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
- echo "$AR cru libconftest.a conftest.o" >&5
- $AR cru libconftest.a conftest.o 2>&5
+ echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5
+ $AR $AR_FLAGS libconftest.a conftest.o 2>&5
echo "$RANLIB libconftest.a" >&5
$RANLIB libconftest.a 2>&5
cat > conftest.c << _LT_EOF
@@ -8513,24 +9682,19 @@ _LT_EOF
rm -rf conftest.dSYM
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
-$as_echo "$lt_cv_ld_force_load" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+printf "%s\n" "$lt_cv_ld_force_load" >&6; }
case $host_os in
rhapsody* | darwin1.[012])
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[012][,.]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ darwin*)
+ case $MACOSX_DEPLOYMENT_TARGET,$host in
+ 10.[012],*|,*powerpc*-darwin[5-8]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ *)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
@@ -8585,286 +9749,43 @@ func_munge_path_list ()
esac
}
-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'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
+ac_header= ac_cache=
+for ac_item in $ac_header_c_list
do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-
-else
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- # Broken: success on invalid input.
-continue
-else
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
+ if test $ac_cache; then
+ ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
+ if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
+ printf "%s\n" "#define $ac_item 1" >> confdefs.h
+ fi
+ ac_header= ac_cache=
+ elif test $ac_header; then
+ ac_cache=$ac_item
+ else
+ ac_header=$ac_item
+ fi
done
-# 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 :
- break
-fi
- done
- ac_cv_prog_CPP=$CPP
-fi
- CPP=$ac_cv_prog_CPP
-else
- ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-else
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- # Broken: success on invalid input.
-continue
-else
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# 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_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-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'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
+if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
+then :
-int
-main ()
-{
+printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdc=yes
-else
- ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "free" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
- (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- return 2;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
- inttypes.h stdint.h unistd.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+if test "x$ac_cv_header_dlfcn_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h
fi
-done
-
-
-for ac_header in dlfcn.h
-do :
- ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
-"
-if test "x$ac_cv_header_dlfcn_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_DLFCN_H 1
-_ACEOF
-
-fi
-
-done
-
func_stripname_cnf ()
@@ -8881,7 +9802,8 @@ func_stripname_cnf ()
# Set options
# Check whether --enable-static was given.
-if test "${enable_static+set}" = set; then :
+if test ${enable_static+y}
+then :
enableval=$enable_static; p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
@@ -8899,7 +9821,7 @@ if test "${enable_static+set}" = set; then :
IFS=$lt_save_ifs
;;
esac
-else
+else $as_nop
enable_static=no
fi
@@ -8919,7 +9841,8 @@ fi
# Check whether --enable-shared was given.
-if test "${enable_shared+set}" = set; then :
+if test ${enable_shared+y}
+then :
enableval=$enable_shared; p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
@@ -8937,7 +9860,7 @@ if test "${enable_shared+set}" = set; then :
IFS=$lt_save_ifs
;;
esac
-else
+else $as_nop
enable_shared=yes
fi
@@ -8952,7 +9875,8 @@ fi
# Check whether --with-pic was given.
-if test "${with_pic+set}" = set; then :
+if test ${with_pic+y}
+then :
withval=$with_pic; lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
@@ -8969,7 +9893,7 @@ if test "${with_pic+set}" = set; then :
IFS=$lt_save_ifs
;;
esac
-else
+else $as_nop
pic_mode=default
fi
@@ -8981,7 +9905,8 @@ fi
# Check whether --enable-fast-install was given.
-if test "${enable_fast_install+set}" = set; then :
+if test ${enable_fast_install+y}
+then :
enableval=$enable_fast_install; p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
@@ -8999,7 +9924,7 @@ if test "${enable_fast_install+set}" = set; then :
IFS=$lt_save_ifs
;;
esac
-else
+else $as_nop
enable_fast_install=yes
fi
@@ -9013,11 +9938,12 @@ fi
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[5-9]*,yes)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
-$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+printf %s "checking which variant of shared library versioning to provide... " >&6; }
# Check whether --with-aix-soname was given.
-if test "${with_aix_soname+set}" = set; then :
+if test ${with_aix_soname+y}
+then :
withval=$with_aix_soname; case $withval in
aix|svr4|both)
;;
@@ -9026,18 +9952,19 @@ if test "${with_aix_soname+set}" = set; then :
;;
esac
lt_cv_with_aix_soname=$with_aix_soname
-else
- if ${lt_cv_with_aix_soname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ if test ${lt_cv_with_aix_soname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_with_aix_soname=aix
fi
with_aix_soname=$lt_cv_with_aix_soname
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
-$as_echo "$with_aix_soname" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+printf "%s\n" "$with_aix_soname" >&6; }
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
@@ -9119,11 +10046,12 @@ if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
-$as_echo_n "checking for objdir... " >&6; }
-if ${lt_cv_objdir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+printf %s "checking for objdir... " >&6; }
+if test ${lt_cv_objdir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
rm -f .libs 2>/dev/null
mkdir .libs 2>/dev/null
if test -d .libs; then
@@ -9134,17 +10062,15 @@ else
fi
rmdir .libs 2>/dev/null
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
-$as_echo "$lt_cv_objdir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+printf "%s\n" "$lt_cv_objdir" >&6; }
objdir=$lt_cv_objdir
-cat >>confdefs.h <<_ACEOF
-#define LT_OBJDIR "$lt_cv_objdir/"
-_ACEOF
+printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h
@@ -9165,8 +10091,8 @@ esac
ofile=libtool
can_build_shared=yes
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
+# All known linkers require a '.a' archive for static linking (except MSVC and
+# ICC, which need '.lib').
libext=a
with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -9190,11 +10116,12 @@ test -z "$MAGIC_CMD" && MAGIC_CMD=file
case $deplibs_check_method in
file_magic*)
if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
-$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
-if ${lt_cv_path_MAGIC_CMD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+printf %s "checking for ${ac_tool_prefix}file... " >&6; }
+if test ${lt_cv_path_MAGIC_CMD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $MAGIC_CMD in
[\\/*] | ?:[\\/]*)
lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
@@ -9243,11 +10170,11 @@ fi
MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-$as_echo "$MAGIC_CMD" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+printf "%s\n" "$MAGIC_CMD" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -9256,11 +10183,12 @@ fi
if test -z "$lt_cv_path_MAGIC_CMD"; then
if test -n "$ac_tool_prefix"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
-$as_echo_n "checking for file... " >&6; }
-if ${lt_cv_path_MAGIC_CMD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+printf %s "checking for file... " >&6; }
+if test ${lt_cv_path_MAGIC_CMD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $MAGIC_CMD in
[\\/*] | ?:[\\/]*)
lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
@@ -9309,11 +10237,11 @@ fi
MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-$as_echo "$MAGIC_CMD" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+printf "%s\n" "$MAGIC_CMD" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -9398,11 +10326,12 @@ if test yes = "$GCC"; then
lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
-$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test ${lt_cv_prog_compiler_rtti_exceptions+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler_rtti_exceptions=no
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
@@ -9433,8 +10362,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
-$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+{ 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; }
if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
@@ -9675,7 +10604,7 @@ lt_prog_compiler_static=
lt_prog_compiler_static='-qstaticlink'
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
# Sun Fortran 8.3 passes all unrecognized flags to the linker
lt_prog_compiler_pic='-KPIC'
@@ -9791,26 +10720,28 @@ case $host_os in
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
-$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
-if ${lt_cv_prog_compiler_pic+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+printf %s "checking for $compiler option to produce PIC... " >&6; }
+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
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
-$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; }
lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
#
# Check to make sure the PIC flag actually works.
#
if test -n "$lt_prog_compiler_pic"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
-$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
-if ${lt_cv_prog_compiler_pic_works+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test ${lt_cv_prog_compiler_pic_works+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler_pic_works=no
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
@@ -9841,8 +10772,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
-$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+{ 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; }
if test yes = "$lt_cv_prog_compiler_pic_works"; then
case $lt_prog_compiler_pic in
@@ -9870,11 +10801,12 @@ fi
# Check to make sure the static flag actually works.
#
wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
-$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if ${lt_cv_prog_compiler_static_works+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test ${lt_cv_prog_compiler_static_works+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler_static_works=no
save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
@@ -9898,8 +10830,8 @@ else
LDFLAGS=$save_LDFLAGS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
-$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+{ 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; }
if test yes = "$lt_cv_prog_compiler_static_works"; then
:
@@ -9913,11 +10845,12 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test ${lt_cv_prog_compiler_c_o+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler_c_o=no
$RM -r conftest 2>/dev/null
mkdir conftest
@@ -9960,19 +10893,20 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+{ 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; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test ${lt_cv_prog_compiler_c_o+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler_c_o=no
$RM -r conftest 2>/dev/null
mkdir conftest
@@ -10015,8 +10949,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+{ 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; }
@@ -10024,19 +10958,19 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; }
hard_links=nottested
if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
-$as_echo_n "checking if we can lock with hard links... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+printf %s "checking if we can lock with hard links... " >&6; }
hard_links=yes
$RM conftest*
ln conftest.a conftest.b 2>/dev/null && hard_links=no
touch conftest.a
ln conftest.a conftest.b 2>&5 || hard_links=no
ln conftest.a conftest.b 2>/dev/null && hard_links=no
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
-$as_echo "$hard_links" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+printf "%s\n" "$hard_links" >&6; }
if test no = "$hard_links"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
-$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
need_locks=warn
fi
else
@@ -10048,8 +10982,8 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
runpath_var=
allow_undefined_flag=
@@ -10093,15 +11027,15 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
+ # Microsoft Visual C++ or Intel C++ Compiler.
if test yes != "$GCC"; then
with_gnu_ld=no
fi
;;
interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
+ # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
with_gnu_ld=yes
;;
openbsd* | bitrig*)
@@ -10153,7 +11087,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
whole_archive_flag_spec=
fi
supports_anon_versioning=no
- case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -10265,6 +11199,7 @@ _LT_EOF
emximp -o $lib $output_objdir/$libname.def'
old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
enable_shared_with_static_runtimes=yes
+ file_list_spec='@'
;;
interix[3-9]*)
@@ -10279,7 +11214,7 @@ _LT_EOF
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
@@ -10322,7 +11257,7 @@ _LT_EOF
compiler_needs_object=yes
;;
esac
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*) # Sun C 5.9
whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
compiler_needs_object=yes
@@ -10334,7 +11269,7 @@ _LT_EOF
if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
@@ -10350,7 +11285,7 @@ _LT_EOF
archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
@@ -10482,7 +11417,7 @@ _LT_EOF
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
@@ -10604,21 +11539,23 @@ _LT_EOF
if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
- if ${lt_cv_aix_libpath_+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_aix_libpath_+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
lt_aix_libpath_sed='
/Import File Strings/,/^$/ {
@@ -10633,7 +11570,7 @@ if ac_fn_c_try_link "$LINENO"; then :
lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath_"; then
lt_cv_aix_libpath_=/usr/lib:/lib
@@ -10657,21 +11594,23 @@ fi
if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
- if ${lt_cv_aix_libpath_+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_aix_libpath_+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
lt_aix_libpath_sed='
/Import File Strings/,/^$/ {
@@ -10686,7 +11625,7 @@ if ac_fn_c_try_link "$LINENO"; then :
lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath_"; then
lt_cv_aix_libpath_=/usr/lib:/lib
@@ -10749,12 +11688,12 @@ fi
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
+ # Microsoft Visual C++ or Intel C++ Compiler.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
case $cc_basename in
- cl*)
- # Native MSVC
+ cl* | icl*)
+ # Native MSVC or ICC
hardcode_libdir_flag_spec=' '
allow_undefined_flag=unsupported
always_export_symbols=yes
@@ -10795,7 +11734,7 @@ fi
fi'
;;
*)
- # Assume MSVC wrapper
+ # Assume MSVC and ICC wrapper
hardcode_libdir_flag_spec=' '
allow_undefined_flag=unsupported
# Tell ltmain to make .lib files, not .a files.
@@ -10836,8 +11775,8 @@ fi
output_verbose_link_cmd=func_echo_all
archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
- archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
- module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
else
ld_shlibs=no
@@ -10871,7 +11810,7 @@ fi
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
@@ -10937,11 +11876,12 @@ fi
# Older versions of the 11.00 compiler do not understand -b yet
# (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
-$as_echo_n "checking if $CC understands -b... " >&6; }
-if ${lt_cv_prog_compiler__b+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+printf %s "checking if $CC understands -b... " >&6; }
+if test ${lt_cv_prog_compiler__b+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_prog_compiler__b=no
save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -b"
@@ -10965,8 +11905,8 @@ else
LDFLAGS=$save_LDFLAGS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
-$as_echo "$lt_cv_prog_compiler__b" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+printf "%s\n" "$lt_cv_prog_compiler__b" >&6; }
if test yes = "$lt_cv_prog_compiler__b"; then
archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
@@ -11006,28 +11946,30 @@ fi
# work, assume that -exports_file does not work either and
# implicitly export all symbols.
# This should be the same for all languages, so no per-tag cache variable.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
-$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
-if ${lt_cv_irix_exported_symbol+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if test ${lt_cv_irix_exported_symbol+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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. */
int foo (void) { return 0; }
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
lt_cv_irix_exported_symbol=yes
-else
+else $as_nop
lt_cv_irix_exported_symbol=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LDFLAGS=$save_LDFLAGS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
-$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; }
if test yes = "$lt_cv_irix_exported_symbol"; then
archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi
@@ -11119,6 +12061,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
emximp -o $lib $output_objdir/$libname.def'
old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
enable_shared_with_static_runtimes=yes
+ file_list_spec='@'
;;
osf3*)
@@ -11307,8 +12250,8 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
-$as_echo "$ld_shlibs" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+printf "%s\n" "$ld_shlibs" >&6; }
test no = "$ld_shlibs" && can_build_shared=no
with_gnu_ld=$with_gnu_ld
@@ -11344,18 +12287,19 @@ x|xyes)
# Test whether the compiler implicitly links with -lc since on some
# systems, -lgcc has to come before -lc. If gcc already passes -lc
# to ld, don't add -lc before -lgcc.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
-$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
-if ${lt_cv_archive_cmds_need_lc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+printf %s "checking whether -lc should be explicitly linked in... " >&6; }
+if test ${lt_cv_archive_cmds_need_lc+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
$RM conftest*
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } 2>conftest.err; then
soname=conftest
lib=conftest
@@ -11373,7 +12317,7 @@ else
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
(eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
then
lt_cv_archive_cmds_need_lc=no
@@ -11387,8 +12331,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
-$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+{ 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; }
archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
;;
esac
@@ -11547,8 +12491,8 @@ esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
-$as_echo_n "checking dynamic linker characteristics... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+printf %s "checking dynamic linker characteristics... " >&6; }
if test yes = "$GCC"; then
case $host_os in
@@ -11810,7 +12754,7 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
;;
@@ -11820,14 +12764,14 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
;;
- *,cl*)
- # Native MSVC
+ *,cl* | *,icl*)
+ # Native MSVC or ICC
libname_spec='$name'
soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
library_names_spec='$libname.dll.lib'
@@ -11846,7 +12790,7 @@ cygwin* | mingw* | pw32* | cegcc*)
done
IFS=$lt_save_ifs
# Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
;;
cygwin*)
# Convert to unix form, then to dos form, then back to unix form
@@ -11883,7 +12827,7 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
*)
- # Assume MSVC wrapper
+ # Assume MSVC and ICC wrapper
library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
@@ -11916,7 +12860,7 @@ dgux*)
shlibpath_var=LD_LIBRARY_PATH
;;
-freebsd* | dragonfly*)
+freebsd* | dragonfly* | midnightbsd*)
# DragonFly does not have aout. When/if they implement a new
# versioning mechanism, adjust this.
if test -x /usr/bin/objformat; then
@@ -12109,9 +13053,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
shlibpath_overrides_runpath=no
# Some binutils ld are patched to set DT_RUNPATH
- if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_shlibpath_overrides_runpath+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_shlibpath_overrides_runpath=no
save_LDFLAGS=$LDFLAGS
save_libdir=$libdir
@@ -12121,19 +13066,21 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+if ac_fn_c_try_link "$LINENO"
+then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null
+then :
lt_cv_shlibpath_overrides_runpath=yes
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LDFLAGS=$save_LDFLAGS
libdir=$save_libdir
@@ -12365,8 +13312,8 @@ uts4*)
dynamic_linker=no
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
-$as_echo "$dynamic_linker" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+printf "%s\n" "$dynamic_linker" >&6; }
test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
@@ -12487,8 +13434,8 @@ configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
-$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+printf %s "checking how to hardcode library paths into programs... " >&6; }
hardcode_action=
if test -n "$hardcode_libdir_flag_spec" ||
test -n "$runpath_var" ||
@@ -12512,8 +13459,8 @@ else
# directories.
hardcode_action=unsupported
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
-$as_echo "$hardcode_action" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+printf "%s\n" "$hardcode_action" >&6; }
if test relink = "$hardcode_action" ||
test yes = "$inherit_rpath"; then
@@ -12557,11 +13504,12 @@ else
darwin*)
# if libdl is installed we need to link against it
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { 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
LIBS="-ldl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12570,32 +13518,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlopen ();
int
-main ()
+main (void)
{
return dlopen ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dl_dlopen=yes
-else
+else $as_nop
ac_cv_lib_dl_dlopen=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+{ 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
+else $as_nop
lt_cv_dlopen=dyld
lt_cv_dlopen_libs=
@@ -12615,14 +13562,16 @@ fi
*)
ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
-if test "x$ac_cv_func_shl_load" = xyes; then :
+if test "x$ac_cv_func_shl_load" = xyes
+then :
lt_cv_dlopen=shl_load
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-$as_echo_n "checking for shl_load in -ldld... " >&6; }
-if ${ac_cv_lib_dld_shl_load+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { 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
LIBS="-ldld $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12631,41 +13580,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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. */
-#ifdef __cplusplus
-extern "C"
-#endif
char shl_load ();
int
-main ()
+main (void)
{
return shl_load ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dld_shl_load=yes
-else
+else $as_nop
ac_cv_lib_dld_shl_load=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+{ 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
+else $as_nop
ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
-if test "x$ac_cv_func_dlopen" = xyes; then :
+if test "x$ac_cv_func_dlopen" = xyes
+then :
lt_cv_dlopen=dlopen
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { 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
LIBS="-ldl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12674,37 +13624,37 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlopen ();
int
-main ()
+main (void)
{
return dlopen ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dl_dlopen=yes
-else
+else $as_nop
ac_cv_lib_dl_dlopen=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+{ 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_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
-$as_echo_n "checking for dlopen in -lsvld... " >&6; }
-if ${ac_cv_lib_svld_dlopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { 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
LIBS="-lsvld $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12713,37 +13663,37 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dlopen ();
int
-main ()
+main (void)
{
return dlopen ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_svld_dlopen=yes
-else
+else $as_nop
ac_cv_lib_svld_dlopen=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
-$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
-if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+{ 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_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
-$as_echo_n "checking for dld_link in -ldld... " >&6; }
-if ${ac_cv_lib_dld_dld_link+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+else $as_nop
+ { 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
LIBS="-ldld $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12752,30 +13702,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dld_link ();
int
-main ()
+main (void)
{
return dld_link ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dld_dld_link=yes
-else
+else $as_nop
ac_cv_lib_dld_dld_link=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
-$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
-if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+{ 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; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes
+then :
lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
fi
@@ -12814,11 +13763,12 @@ fi
save_LIBS=$LIBS
LIBS="$lt_cv_dlopen_libs $LIBS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
-$as_echo_n "checking whether a program can dlopen itself... " >&6; }
-if ${lt_cv_dlopen_self+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+printf %s "checking whether a program can dlopen itself... " >&6; }
+if test ${lt_cv_dlopen_self+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test yes = "$cross_compiling"; then :
lt_cv_dlopen_self=cross
else
@@ -12897,7 +13847,7 @@ _LT_EOF
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
(eval $ac_link) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
(./conftest; exit; ) >&5 2>/dev/null
lt_status=$?
@@ -12915,16 +13865,17 @@ rm -fr conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
-$as_echo "$lt_cv_dlopen_self" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+printf "%s\n" "$lt_cv_dlopen_self" >&6; }
if test yes = "$lt_cv_dlopen_self"; then
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
-$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
-if ${lt_cv_dlopen_self_static+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+printf %s "checking whether a statically linked program can dlopen itself... " >&6; }
+if test ${lt_cv_dlopen_self_static+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test yes = "$cross_compiling"; then :
lt_cv_dlopen_self_static=cross
else
@@ -13003,7 +13954,7 @@ _LT_EOF
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
(eval $ac_link) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
(./conftest; exit; ) >&5 2>/dev/null
lt_status=$?
@@ -13021,8 +13972,8 @@ rm -fr conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
-$as_echo "$lt_cv_dlopen_self_static" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+printf "%s\n" "$lt_cv_dlopen_self_static" >&6; }
fi
CPPFLAGS=$save_CPPFLAGS
@@ -13060,32 +14011,43 @@ fi
striplib=
old_striplib=
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
-$as_echo_n "checking whether stripping libraries is possible... " >&6; }
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+printf %s "checking whether stripping libraries is possible... " >&6; }
+if test -z "$STRIP"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+else
+ if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ old_striplib="$STRIP --strip-debug"
+ striplib="$STRIP --strip-unneeded"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ else
+ case $host_os in
+ darwin*)
+ # FIXME - insert some real tests, host_os isn't really good enough
striplib="$STRIP -x"
old_striplib="$STRIP -S"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- fi
- ;;
- *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- ;;
- esac
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ ;;
+ freebsd*)
+ if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then
+ old_striplib="$STRIP --strip-debug"
+ striplib="$STRIP --strip-unneeded"
+ { 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" "no" >&6; }
+ fi
+ ;;
+ *)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ ;;
+ esac
+ fi
fi
@@ -13100,13 +14062,13 @@ fi
# Report what library types will actually be built
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
-$as_echo_n "checking if libtool supports shared libraries... " >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
-$as_echo "$can_build_shared" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+printf %s "checking if libtool supports shared libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+printf "%s\n" "$can_build_shared" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
-$as_echo_n "checking whether to build shared libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+printf %s "checking whether to build shared libraries... " >&6; }
test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
@@ -13130,15 +14092,15 @@ $as_echo_n "checking whether to build shared libraries... " >&6; }
fi
;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
-$as_echo "$enable_shared" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+printf "%s\n" "$enable_shared" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
-$as_echo_n "checking whether to build static libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+printf %s "checking whether to build static libraries... " >&6; }
# Make sure either enable_shared or enable_static is yes.
test yes = "$enable_shared" || enable_static=yes
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
-$as_echo "$enable_static" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+printf "%s\n" "$enable_static" >&6; }
@@ -13160,36 +14122,32 @@ 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'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
-$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+printf %s "checking how to run the C++ preprocessor... " >&6; }
if test -z "$CXXCPP"; then
- if ${ac_cv_prog_CXXCPP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- # Double quotes because CXXCPP needs to be expanded
- for CXXCPP in "$CXX -E" "/lib/cpp"
+ if test ${ac_cv_prog_CXXCPP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ # Double quotes because $CXX needs to be expanded
+ for CXXCPP in "$CXX -E" cpp /lib/cpp
do
ac_preproc_ok=false
for ac_cxx_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_cxx_try_cpp "$LINENO"; then :
+if ac_fn_cxx_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
@@ -13201,10 +14159,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_cxx_try_cpp "$LINENO"; then :
+if ac_fn_cxx_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
@@ -13214,7 +14173,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext
done
# 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 :
+if $ac_preproc_ok
+then :
break
fi
@@ -13226,29 +14186,24 @@ fi
else
ac_cv_prog_CXXCPP=$CXXCPP
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
-$as_echo "$CXXCPP" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+printf "%s\n" "$CXXCPP" >&6; }
ac_preproc_ok=false
for ac_cxx_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_cxx_try_cpp "$LINENO"; then :
+if ac_fn_cxx_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
@@ -13260,10 +14215,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_cxx_try_cpp "$LINENO"; then :
+if ac_fn_cxx_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
@@ -13273,11 +14229,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext
done
# 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 :
+if $ac_preproc_ok
+then :
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+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;}
as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi
@@ -13413,17 +14370,18 @@ cc_basename=$func_cc_basename_result
# Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then :
+if test ${with_gnu_ld+y}
+then :
withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
-else
+else $as_nop
with_gnu_ld=no
fi
ac_prog=ld
if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-$as_echo_n "checking for ld used by $CC... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+printf %s "checking for ld used by $CC... " >&6; }
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return, which upsets mingw
@@ -13452,15 +14410,16 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
;;
esac
elif test yes = "$with_gnu_ld"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-$as_echo_n "checking for GNU ld... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+printf %s "checking for GNU ld... " >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-$as_echo_n "checking for non-GNU ld... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+printf %s "checking for non-GNU ld... " >&6; }
fi
-if ${lt_cv_path_LD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test ${lt_cv_path_LD+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -z "$LD"; then
lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
@@ -13489,18 +14448,19 @@ fi
LD=$lt_cv_path_LD
if test -n "$LD"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
-$as_echo "$LD" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+printf "%s\n" "$LD" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+printf %s "checking if the linker ($LD) is GNU ld... " >&6; }
+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.
case `$LD -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
@@ -13511,8 +14471,8 @@ case `$LD -v 2>&1 </dev/null` in
;;
esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
-$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; }
with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -13566,8 +14526,8 @@ with_gnu_ld=$lt_cv_prog_gnu_ld
fi
# PORTME: fill in a description of your system's C++ link characteristics
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
ld_shlibs_CXX=yes
case $host_os in
aix3*)
@@ -13705,21 +14665,23 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
- if ${lt_cv_aix_libpath__CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_aix_libpath__CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
lt_aix_libpath_sed='
/Import File Strings/,/^$/ {
@@ -13734,7 +14696,7 @@ if ac_fn_cxx_try_link "$LINENO"; then :
lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath__CXX"; then
lt_cv_aix_libpath__CXX=/usr/lib:/lib
@@ -13759,21 +14721,23 @@ fi
if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
- if ${lt_cv_aix_libpath__CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_aix_libpath__CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
lt_aix_libpath_sed='
/Import File Strings/,/^$/ {
@@ -13788,7 +14752,7 @@ if ac_fn_cxx_try_link "$LINENO"; then :
lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath__CXX"; then
lt_cv_aix_libpath__CXX=/usr/lib:/lib
@@ -13853,8 +14817,8 @@ fi
cygwin* | mingw* | pw32* | cegcc*)
case $GXX,$cc_basename in
- ,cl* | no,cl*)
- # Native MSVC
+ ,cl* | no,cl* | ,icl* | no,icl*)
+ # Native MSVC or ICC
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec_CXX=' '
@@ -13945,11 +14909,11 @@ fi
output_verbose_link_cmd=func_echo_all
archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
- archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
- module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ archive_expsym_cmds_CXX="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds_CXX="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
if test yes != "$lt_cv_apple_cc_single_mod"; then
archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
- archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+ archive_expsym_cmds_CXX="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
fi
else
@@ -13984,6 +14948,7 @@ fi
emximp -o $lib $output_objdir/$libname.def'
old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
enable_shared_with_static_runtimes_CXX=yes
+ file_list_spec_CXX='@'
;;
dgux*)
@@ -14014,7 +14979,7 @@ fi
archive_cmds_need_lc_CXX=no
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
# FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
# conventions
ld_shlibs_CXX=yes
@@ -14151,7 +15116,7 @@ fi
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
@@ -14291,13 +15256,13 @@ fi
archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*)
# Sun C++ 5.9
no_undefined_flag_CXX=' -zdefs'
@@ -14639,8 +15604,8 @@ fi
;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
-$as_echo "$ld_shlibs_CXX" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+printf "%s\n" "$ld_shlibs_CXX" >&6; }
test no = "$ld_shlibs_CXX" && can_build_shared=no
GCC_CXX=$GXX
@@ -14678,7 +15643,7 @@ esac
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
# Parse the compiler output and extract the necessary
# objects, libraries and library flags.
@@ -14954,7 +15919,7 @@ lt_prog_compiler_static_CXX=
;;
esac
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
# FreeBSD uses GNU C++
;;
hpux9* | hpux10* | hpux11*)
@@ -15037,7 +16002,7 @@ lt_prog_compiler_static_CXX=
lt_prog_compiler_static_CXX='-qstaticlink'
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*)
# Sun C++ 5.9
lt_prog_compiler_pic_CXX='-KPIC'
@@ -15159,26 +16124,28 @@ case $host_os in
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
-$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
-if ${lt_cv_prog_compiler_pic_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+printf %s "checking for $compiler option to produce PIC... " >&6; }
+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
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5
-$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; }
+{ 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; }
lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX
#
# Check to make sure the PIC flag actually works.
#
if test -n "$lt_prog_compiler_pic_CXX"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
-$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
-if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+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
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
@@ -15209,8 +16176,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
-$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+{ 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; }
if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then
case $lt_prog_compiler_pic_CXX in
@@ -15232,11 +16199,12 @@ fi
# Check to make sure the static flag actually works.
#
wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
-$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+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
save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
@@ -15260,8 +16228,8 @@ else
LDFLAGS=$save_LDFLAGS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
-$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+{ 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; }
if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then
:
@@ -15272,11 +16240,12 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+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
$RM -r conftest 2>/dev/null
mkdir conftest
@@ -15319,16 +16288,17 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
-$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+{ 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; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+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
$RM -r conftest 2>/dev/null
mkdir conftest
@@ -15371,8 +16341,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
-$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+{ 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; }
@@ -15380,19 +16350,19 @@ $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
hard_links=nottested
if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
-$as_echo_n "checking if we can lock with hard links... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+printf %s "checking if we can lock with hard links... " >&6; }
hard_links=yes
$RM conftest*
ln conftest.a conftest.b 2>/dev/null && hard_links=no
touch conftest.a
ln conftest.a conftest.b 2>&5 || hard_links=no
ln conftest.a conftest.b 2>/dev/null && hard_links=no
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
-$as_echo "$hard_links" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+printf "%s\n" "$hard_links" >&6; }
if test no = "$hard_links"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
-$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
need_locks=warn
fi
else
@@ -15401,8 +16371,8 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
@@ -15419,7 +16389,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
@@ -15427,7 +16397,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
- cl*)
+ cl* | icl*)
exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
;;
*)
@@ -15441,8 +16411,8 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
-$as_echo "$ld_shlibs_CXX" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+printf "%s\n" "$ld_shlibs_CXX" >&6; }
test no = "$ld_shlibs_CXX" && can_build_shared=no
with_gnu_ld_CXX=$with_gnu_ld
@@ -15469,18 +16439,19 @@ x|xyes)
# Test whether the compiler implicitly links with -lc since on some
# systems, -lgcc has to come before -lc. If gcc already passes -lc
# to ld, don't add -lc before -lgcc.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
-$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
-if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+printf %s "checking whether -lc should be explicitly linked in... " >&6; }
+if test ${lt_cv_archive_cmds_need_lc_CXX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
$RM conftest*
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } 2>conftest.err; then
soname=conftest
lib=conftest
@@ -15498,7 +16469,7 @@ else
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
(eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
then
lt_cv_archive_cmds_need_lc_CXX=no
@@ -15512,8 +16483,8 @@ else
$RM conftest*
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
-$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+{ 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; }
archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
;;
esac
@@ -15582,8 +16553,8 @@ esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
-$as_echo_n "checking dynamic linker characteristics... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+printf %s "checking dynamic linker characteristics... " >&6; }
library_names_spec=
libname_spec='lib$name'
@@ -15774,7 +16745,7 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
mingw* | cegcc*)
@@ -15783,14 +16754,14 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
;;
- *,cl*)
- # Native MSVC
+ *,cl* | *,icl*)
+ # Native MSVC or ICC
libname_spec='$name'
soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
library_names_spec='$libname.dll.lib'
@@ -15809,7 +16780,7 @@ cygwin* | mingw* | pw32* | cegcc*)
done
IFS=$lt_save_ifs
# Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
;;
cygwin*)
# Convert to unix form, then to dos form, then back to unix form
@@ -15846,7 +16817,7 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
*)
- # Assume MSVC wrapper
+ # Assume MSVC and ICC wrapper
library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
@@ -15878,7 +16849,7 @@ dgux*)
shlibpath_var=LD_LIBRARY_PATH
;;
-freebsd* | dragonfly*)
+freebsd* | dragonfly* | midnightbsd*)
# DragonFly does not have aout. When/if they implement a new
# versioning mechanism, adjust this.
if test -x /usr/bin/objformat; then
@@ -16071,9 +17042,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
shlibpath_overrides_runpath=no
# Some binutils ld are patched to set DT_RUNPATH
- if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${lt_cv_shlibpath_overrides_runpath+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
lt_cv_shlibpath_overrides_runpath=no
save_LDFLAGS=$LDFLAGS
save_libdir=$libdir
@@ -16083,19 +17055,21 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
- if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null
+then :
lt_cv_shlibpath_overrides_runpath=yes
fi
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LDFLAGS=$save_LDFLAGS
libdir=$save_libdir
@@ -16327,8 +17301,8 @@ uts4*)
dynamic_linker=no
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
-$as_echo "$dynamic_linker" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+printf "%s\n" "$dynamic_linker" >&6; }
test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
@@ -16392,8 +17366,8 @@ configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
-$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+printf %s "checking how to hardcode library paths into programs... " >&6; }
hardcode_action_CXX=
if test -n "$hardcode_libdir_flag_spec_CXX" ||
test -n "$runpath_var_CXX" ||
@@ -16417,8 +17391,8 @@ else
# directories.
hardcode_action_CXX=unsupported
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
-$as_echo "$hardcode_action_CXX" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+printf "%s\n" "$hardcode_action_CXX" >&6; }
if test relink = "$hardcode_action_CXX" ||
test yes = "$inherit_rpath_CXX"; then
@@ -16493,11 +17467,12 @@ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PKG_CONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $PKG_CONFIG in
[\\/]* | ?:[\\/]*)
ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
@@ -16507,11 +17482,15 @@ else
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -16523,11 +17502,11 @@ esac
fi
PKG_CONFIG=$ac_cv_path_PKG_CONFIG
if test -n "$PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+printf "%s\n" "$PKG_CONFIG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -16536,11 +17515,12 @@ if test -z "$ac_cv_path_PKG_CONFIG"; then
ac_pt_PKG_CONFIG=$PKG_CONFIG
# Extract the first word of "pkg-config", so it can be a program name with args.
set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_ac_pt_PKG_CONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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.
@@ -16550,11 +17530,15 @@ else
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -16566,11 +17550,11 @@ esac
fi
ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
if test -n "$ac_pt_PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_pt_PKG_CONFIG" = x; then
@@ -16578,8 +17562,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
PKG_CONFIG=$ac_pt_PKG_CONFIG
@@ -16591,48 +17575,51 @@ fi
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=0.9.0
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
PKG_CONFIG=""
fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libsodium" >&5
-$as_echo_n "checking whether we will be linking in libsodium... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libsodium" >&5
+printf %s "checking whether we will be linking in libsodium... " >&6; }
# Check whether --with-libsodium was given.
-if test "${with_libsodium+set}" = set; then :
+if test ${with_libsodium+y}
+then :
withval=$with_libsodium; with_libsodium=$withval
-else
+else $as_nop
with_libsodium=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libsodium" >&5
-$as_echo "$with_libsodium" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libsodium" >&5
+printf "%s\n" "$with_libsodium" >&6; }
- if test "x$with_libsodium" != "xno"; then :
+ if test "x$with_libsodium" != "xno"
+then :
- if test "x$with_libsodium" = "xyes" -o "x$with_libsodium" = "xauto"; then :
+ if test "x$with_libsodium" = "xyes" -o "x$with_libsodium" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSODIUM" >&5
-$as_echo_n "checking for LIBSODIUM... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsodium" >&5
+printf %s "checking for libsodium... " >&6; }
if test -n "$LIBSODIUM_CFLAGS"; then
pkg_cv_LIBSODIUM_CFLAGS="$LIBSODIUM_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
($PKG_CONFIG --exists --print-errors "libsodium") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSODIUM_CFLAGS=`$PKG_CONFIG --cflags "libsodium" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16646,10 +17633,10 @@ if test -n "$LIBSODIUM_LIBS"; then
pkg_cv_LIBSODIUM_LIBS="$LIBSODIUM_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
($PKG_CONFIG --exists --print-errors "libsodium") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSODIUM_LIBS=`$PKG_CONFIG --libs "libsodium" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16663,8 +17650,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -16672,42 +17659,61 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium" 2>&1`
+ LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium" 2>&1`
else
- LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium" 2>&1`
+ LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBSODIUM_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBSODIUM_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBSODIUM_CFLAGS=$pkg_cv_LIBSODIUM_CFLAGS
- LIBSODIUM_LIBS=$pkg_cv_LIBSODIUM_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBSODIUM_CFLAGS=$pkg_cv_LIBSODIUM_CFLAGS
+ LIBSODIUM_LIBS=$pkg_cv_LIBSODIUM_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LIBSODIUM 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBSODIUM 1" >>confdefs.h
save_CFLAGS=$CFLAGS
save_LIBS=$LIBS
CFLAGS="$LIBSODIUM_CFLAGS $CFLAGS"
LIBS="$LIBSODIUM_LIBS $LIBS"
- for ac_func in crypto_box_easy_afternm crypto_box_curve25519xchacha20poly1305_easy randombytes_stir sodium_memcmp crypto_shorthash
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "crypto_box_easy_afternm" "ac_cv_func_crypto_box_easy_afternm"
+if test "x$ac_cv_func_crypto_box_easy_afternm" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_BOX_EASY_AFTERNM 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "crypto_box_curve25519xchacha20poly1305_easy" "ac_cv_func_crypto_box_curve25519xchacha20poly1305_easy"
+if test "x$ac_cv_func_crypto_box_curve25519xchacha20poly1305_easy" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "randombytes_stir" "ac_cv_func_randombytes_stir"
+if test "x$ac_cv_func_randombytes_stir" = xyes
+then :
+ printf "%s\n" "#define HAVE_RANDOMBYTES_STIR 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "sodium_memcmp" "ac_cv_func_sodium_memcmp"
+if test "x$ac_cv_func_sodium_memcmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_SODIUM_MEMCMP 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "crypto_shorthash" "ac_cv_func_crypto_shorthash"
+if test "x$ac_cv_func_crypto_shorthash" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_SHORTHASH 1" >>confdefs.h
fi
-done
CFLAGS=$save_CFLAGS
LIBS=$save_LIBS
@@ -16725,9 +17731,11 @@ else
LIBSODIUM_FALSE=
fi
- if test "x$with_libsodium" = "xyes"; then :
+ if test "x$with_libsodium" = "xyes"
+then :
- if test x"$LIBSODIUM_LIBS" = "x"; then :
+ if test x"$LIBSODIUM_LIBS" = "x"
+then :
as_fn_error $? "libsodium requested but libraries were not found" "$LINENO" 5
@@ -16736,35 +17744,160 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will have dnstap" >&5
-$as_echo_n "checking whether we will have dnstap... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in quiche" >&5
+printf %s "checking whether we will be linking in quiche... " >&6; }
+ HAVE_QUICHE=0
+
+# Check whether --with-quiche was given.
+if test ${with_quiche+y}
+then :
+ withval=$with_quiche; with_quiche=$withval
+else $as_nop
+ with_quiche=auto
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_quiche" >&5
+printf "%s\n" "$with_quiche" >&6; }
+
+ if test "x$with_quiche" != "xno"
+then :
+
+ if test "x$with_quiche" = "xyes" -o "x$with_quiche" = "xauto"
+then :
+
+
+pkg_failed=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for quiche >= 0.15.0" >&5
+printf %s "checking for quiche >= 0.15.0... " >&6; }
+
+if test -n "$QUICHE_CFLAGS"; then
+ pkg_cv_QUICHE_CFLAGS="$QUICHE_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"quiche >= 0.15.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "quiche >= 0.15.0") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_QUICHE_CFLAGS=`$PKG_CONFIG --cflags "quiche >= 0.15.0" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$QUICHE_LIBS"; then
+ pkg_cv_QUICHE_LIBS="$QUICHE_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"quiche >= 0.15.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "quiche >= 0.15.0") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_QUICHE_LIBS=`$PKG_CONFIG --libs "quiche >= 0.15.0" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ QUICHE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "quiche >= 0.15.0" 2>&1`
+ else
+ QUICHE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "quiche >= 0.15.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$QUICHE_PKG_ERRORS" >&5
+
+ :
+elif test $pkg_failed = untried; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
+else
+ QUICHE_CFLAGS=$pkg_cv_QUICHE_CFLAGS
+ QUICHE_LIBS=$pkg_cv_QUICHE_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+ HAVE_QUICHE=1
+
+printf "%s\n" "#define HAVE_QUICHE 1" >>confdefs.h
+
+
+fi
+
+fi
+
+fi
+ if test "x$QUICHE_LIBS" != "x"; then
+ HAVE_QUICHE_TRUE=
+ HAVE_QUICHE_FALSE='#'
+else
+ HAVE_QUICHE_TRUE='#'
+ HAVE_QUICHE_FALSE=
+fi
+
+ if test "x$with_quiche" = "xyes"
+then :
+
+ if test x"$QUICHE_LIBS" = "x"
+then :
+
+ as_fn_error $? "quiche requested but libraries were not found" "$LINENO" 5
+
+fi
+
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will have dnstap" >&5
+printf %s "checking whether we will have dnstap... " >&6; }
# Check whether --enable-dnstap was given.
-if test "${enable_dnstap+set}" = set; then :
+if test ${enable_dnstap+y}
+then :
enableval=$enable_dnstap; enable_dnstap=$enableval
-else
+else $as_nop
enable_dnstap=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dnstap" >&5
-$as_echo "$enable_dnstap" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dnstap" >&5
+printf "%s\n" "$enable_dnstap" >&6; }
- if test "x$enable_dnstap" != "xno"; then :
+ if test "x$enable_dnstap" != "xno"
+then :
- if test "x$enable_dnstap" = "xyes" -o "x$enable_dnstap" = "xauto"; then :
+ if test "x$enable_dnstap" = "xyes" -o "x$enable_dnstap" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FSTRM" >&5
-$as_echo_n "checking for FSTRM... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libfstrm" >&5
+printf %s "checking for libfstrm... " >&6; }
if test -n "$FSTRM_CFLAGS"; then
pkg_cv_FSTRM_CFLAGS="$FSTRM_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libfstrm\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libfstrm\""; } >&5
($PKG_CONFIG --exists --print-errors "libfstrm") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_FSTRM_CFLAGS=`$PKG_CONFIG --cflags "libfstrm" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16778,10 +17911,10 @@ if test -n "$FSTRM_LIBS"; then
pkg_cv_FSTRM_LIBS="$FSTRM_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libfstrm\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libfstrm\""; } >&5
($PKG_CONFIG --exists --print-errors "libfstrm") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_FSTRM_LIBS=`$PKG_CONFIG --libs "libfstrm" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16795,8 +17928,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -16804,41 +17937,37 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- FSTRM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libfstrm" 2>&1`
+ FSTRM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libfstrm" 2>&1`
else
- FSTRM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libfstrm" 2>&1`
+ FSTRM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libfstrm" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$FSTRM_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$FSTRM_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- FSTRM_CFLAGS=$pkg_cv_FSTRM_CFLAGS
- FSTRM_LIBS=$pkg_cv_FSTRM_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ FSTRM_CFLAGS=$pkg_cv_FSTRM_CFLAGS
+ FSTRM_LIBS=$pkg_cv_FSTRM_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_FSTRM 1" >>confdefs.h
+printf "%s\n" "#define HAVE_FSTRM 1" >>confdefs.h
save_CFLAGS=$CFLAGS
save_LIBS=$LIBS
CFLAGS="$FSTRM_CFLAGS $CFLAGS"
LIBS="$FSTRM_LIBS $LIBS"
- for ac_func in fstrm_tcp_writer_init
-do :
- ac_fn_cxx_check_func "$LINENO" "fstrm_tcp_writer_init" "ac_cv_func_fstrm_tcp_writer_init"
-if test "x$ac_cv_func_fstrm_tcp_writer_init" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_FSTRM_TCP_WRITER_INIT 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "fstrm_tcp_writer_init" "ac_cv_func_fstrm_tcp_writer_init"
+if test "x$ac_cv_func_fstrm_tcp_writer_init" = xyes
+then :
+ printf "%s\n" "#define HAVE_FSTRM_TCP_WRITER_INIT 1" >>confdefs.h
fi
-done
CFLAGS=$save_CFLAGS
LIBS=$save_LIBS
@@ -16857,9 +17986,11 @@ else
FSTRM_FALSE=
fi
- if test "x$enable_dnstap" = "xyes"; then :
+ if test "x$enable_dnstap" = "xyes"
+then :
- if test x"$FSTRM_LIBS" = "x"; then :
+ if test x"$FSTRM_LIBS" = "x"
+then :
as_fn_error $? "dnstap requested but libfstrm was not found" "$LINENO" 5
@@ -16870,11 +18001,12 @@ fi
# Extract the first word of "ragel", so it can be a program name with args.
set dummy ragel; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RAGEL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_RAGEL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$RAGEL"; then
ac_cv_prog_RAGEL="$RAGEL" # Let the user override the test.
else
@@ -16882,11 +18014,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_RAGEL="ragel"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -16897,11 +18033,11 @@ fi
fi
RAGEL=$ac_cv_prog_RAGEL
if test -n "$RAGEL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAGEL" >&5
-$as_echo "$RAGEL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RAGEL" >&5
+printf "%s\n" "$RAGEL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -16912,37 +18048,40 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to link in libedit" >&5
-$as_echo_n "checking whether to link in libedit... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to link in libedit" >&5
+printf %s "checking whether to link in libedit... " >&6; }
# Check whether --with-libedit was given.
-if test "${with_libedit+set}" = set; then :
+if test ${with_libedit+y}
+then :
withval=$with_libedit; with_libedit=$enableval
-else
+else $as_nop
with_libedit=yes
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libedit" >&5
-$as_echo "$with_libedit" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libedit" >&5
+printf "%s\n" "$with_libedit" >&6; }
- if test "x$with_libedit" != "xno"; then :
+ if test "x$with_libedit" != "xno"
+then :
- if test "x$with_libedit" = "xyes" -o "x$with_libedit" = "xauto"; then :
+ if test "x$with_libedit" = "xyes" -o "x$with_libedit" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5
-$as_echo_n "checking for LIBEDIT... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libedit" >&5
+printf %s "checking for libedit... " >&6; }
if test -n "$LIBEDIT_CFLAGS"; then
pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBEDIT_CFLAGS=`$PKG_CONFIG --cflags "libedit" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16956,10 +18095,10 @@ if test -n "$LIBEDIT_LIBS"; then
pkg_cv_LIBEDIT_LIBS="$LIBEDIT_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBEDIT_LIBS=`$PKG_CONFIG --libs "libedit" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -16973,8 +18112,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -16982,27 +18121,27 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedit" 2>&1`
+ LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedit" 2>&1`
else
- LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedit" 2>&1`
+ LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedit" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBEDIT_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBEDIT_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBEDIT_CFLAGS=$pkg_cv_LIBEDIT_CFLAGS
- LIBEDIT_LIBS=$pkg_cv_LIBEDIT_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBEDIT_CFLAGS=$pkg_cv_LIBEDIT_CFLAGS
+ LIBEDIT_LIBS=$pkg_cv_LIBEDIT_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_LIBEDIT=1
-$as_echo "#define HAVE_LIBEDIT 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBEDIT 1" >>confdefs.h
fi
@@ -17018,9 +18157,11 @@ else
HAVE_LIBEDIT_FALSE=
fi
- if test "x$with_libedit" = "xyes"; then :
+ if test "x$with_libedit" = "xyes"
+then :
- if test x"$LIBEDIT_LIBS" = "x"; then :
+ if test x"$LIBEDIT_LIBS" = "x"
+then :
as_fn_error $? "libedit support requested but library not found" "$LINENO" 5
@@ -17030,61 +18171,63 @@ fi
OLD_LIBS="$LIBS"; LIBS=""
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
-$as_echo_n "checking for library containing clock_gettime... " >&6; }
-if ${ac_cv_search_clock_gettime+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+printf %s "checking for library containing clock_gettime... " >&6; }
+if test ${ac_cv_search_clock_gettime+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char clock_gettime ();
+namespace conftest {
+ extern "C" int clock_gettime ();
+}
int
-main ()
+main (void)
{
-return clock_gettime ();
+return conftest::clock_gettime ();
;
return 0;
}
_ACEOF
-for ac_lib in '' rt; do
+for ac_lib in '' rt
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_clock_gettime=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_clock_gettime+:} false; then :
+ if test ${ac_cv_search_clock_gettime+y}
+then :
break
fi
done
-if ${ac_cv_search_clock_gettime+:} false; then :
+if test ${ac_cv_search_clock_gettime+y}
+then :
-else
+else $as_nop
ac_cv_search_clock_gettime=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
-$as_echo "$ac_cv_search_clock_gettime" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+printf "%s\n" "$ac_cv_search_clock_gettime" >&6; }
ac_res=$ac_cv_search_clock_gettime
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
fi
@@ -17104,10 +18247,10 @@ fi
;;
solaris2.8 | solaris2.9 )
-$as_echo "#define NEED_POSIX_TYPEDEF /**/" >>confdefs.h
+printf "%s\n" "#define NEED_POSIX_TYPEDEF /**/" >>confdefs.h
-$as_echo "#define NEED_INET_NTOP_PROTO /**/" >>confdefs.h
+printf "%s\n" "#define NEED_INET_NTOP_PROTO /**/" >>confdefs.h
LIBS="-lposix4 -lpthread $LIBS"
CXXFLAGS="-D_REENTRANT $CXXFLAGS"
@@ -17176,13 +18319,13 @@ else
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -latomic is needed for __atomic builtins" >&5
-$as_echo_n "checking whether -latomic is needed for __atomic builtins... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -latomic is needed for __atomic builtins" >&5
+printf %s "checking whether -latomic is needed for __atomic builtins... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdint.h>
int
-main ()
+main (void)
{
uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);
@@ -17190,16 +18333,17 @@ uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-else
+if ac_fn_cxx_try_link "$LINENO"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+else $as_nop
LIBS="$LIBS -latomic"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdint.h>
int
-main ()
+main (void)
{
uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);
@@ -17207,21 +18351,22 @@ uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+if ac_fn_cxx_try_link "$LINENO"
+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;}
as_fn_error $? "libatomic needed, but linking with -latomic failed, cannot continue
See \`config.log' for more details" "$LINENO" 5; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
@@ -17232,23 +18377,18 @@ rm -f core conftest.err conftest.$ac_objext \
stored_LIBS="$LIBS"
LIBS="-lpthread"
# pthread setname (4 non-portable variants...)
- for ac_header in pthread_np.h
-do :
ac_fn_cxx_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "#include <pthread.h>
"
-if test "x$ac_cv_header_pthread_np_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PTHREAD_NP_H 1
-_ACEOF
+if test "x$ac_cv_header_pthread_np_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h
fi
-done
-
# 2-arg setname (e.g. Linux/glibc, QNX, IBM)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 2-arg pthread_setname_np" >&5
-$as_echo_n "checking for 2-arg pthread_setname_np... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 2-arg pthread_setname_np" >&5
+printf %s "checking for 2-arg pthread_setname_np... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -17258,7 +18398,7 @@ $as_echo_n "checking for 2-arg pthread_setname_np... " >&6; }
#endif
int
-main ()
+main (void)
{
pthread_setname_np(pthread_self(), "foo")
@@ -17267,22 +18407,23 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_PTHREAD_SETNAME_NP_2 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP_2 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
# 2-arg set_name (e.g. FreeBSD, OpenBSD)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 2-arg pthread_set_name_np" >&5
-$as_echo_n "checking for 2-arg pthread_set_name_np... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 2-arg pthread_set_name_np" >&5
+printf %s "checking for 2-arg pthread_set_name_np... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -17292,7 +18433,7 @@ $as_echo_n "checking for 2-arg pthread_set_name_np... " >&6; }
#endif
int
-main ()
+main (void)
{
return pthread_set_name_np(pthread_self(), "foo");
@@ -17301,22 +18442,23 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_PTHREAD_SET_NAME_NP_2 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SET_NAME_NP_2 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
# 2-arg void set_name (e.g. FreeBSD, OpenBSD)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 2-arg void pthread_set_name_np" >&5
-$as_echo_n "checking for 2-arg void pthread_set_name_np... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 2-arg void pthread_set_name_np" >&5
+printf %s "checking for 2-arg void pthread_set_name_np... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -17326,7 +18468,7 @@ $as_echo_n "checking for 2-arg void pthread_set_name_np... " >&6; }
#endif
int
-main ()
+main (void)
{
pthread_set_name_np(pthread_self(), "foo");
@@ -17335,22 +18477,23 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_PTHREAD_SET_NAME_NP_2_VOID 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SET_NAME_NP_2_VOID 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
# 1-arg setname (e.g. Darwin)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 1-arg pthread_setname_np" >&5
-$as_echo_n "checking for 1-arg pthread_setname_np... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 1-arg pthread_setname_np" >&5
+printf %s "checking for 1-arg pthread_setname_np... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -17360,7 +18503,7 @@ $as_echo_n "checking for 1-arg pthread_setname_np... " >&6; }
#endif
int
-main ()
+main (void)
{
return pthread_setname_np("foo");
@@ -17369,22 +18512,23 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_PTHREAD_SETNAME_NP_1 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP_1 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
# 3-arg setname (e.g. NetBSD)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 3-arg pthread_setname_np" >&5
-$as_echo_n "checking for 3-arg pthread_setname_np... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 3-arg pthread_setname_np" >&5
+printf %s "checking for 3-arg pthread_setname_np... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -17394,7 +18538,7 @@ $as_echo_n "checking for 3-arg pthread_setname_np... " >&6; }
#endif
int
-main ()
+main (void)
{
return pthread_setname_np(pthread_self(), "foo", NULL);
@@ -17403,569 +18547,678 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
-$as_echo "#define HAVE_PTHREAD_SETNAME_NP_3 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP_3 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$stored_LIBS
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX options needed to detect all undeclared functions" >&5
+printf %s "checking for $CXX options needed to detect all undeclared functions... " >&6; }
+if test ${ac_cv_cxx_undeclared_builtin_options+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ 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"
+ # This test program should *not* compile successfully.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5
-$as_echo_n "checking for library containing inet_aton... " >&6; }
-if ${ac_cv_search_inet_aton+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+int
+main (void)
+{
+(void) strchr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+
+else $as_nop
+ # 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
+ # off chance that they somehow elicit warnings.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <float.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+extern void ac_decl (int, char *);
+
+int
+main (void)
+{
+(void) ac_decl (0, (char *) 0);
+ (void) ac_decl;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"
+then :
+ 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
+fi
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ done
+ CFLAGS=$ac_save_CFLAGS
+
+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;}
+as_fn_error $? "cannot make $CXX report undeclared builtins
+See \`config.log' for more details" "$LINENO" 5; } ;; #(
+ 'none needed') :
+ ac_cxx_undeclared_builtin_options='' ;; #(
+ *) :
+ ac_cxx_undeclared_builtin_options=$ac_cv_cxx_undeclared_builtin_options ;;
+esac
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5
+printf %s "checking for library containing inet_aton... " >&6; }
+if test ${ac_cv_search_inet_aton+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char inet_aton ();
+namespace conftest {
+ extern "C" int inet_aton ();
+}
int
-main ()
+main (void)
{
-return inet_aton ();
+return conftest::inet_aton ();
;
return 0;
}
_ACEOF
-for ac_lib in '' resolv; do
+for ac_lib in '' resolv
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_inet_aton=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_inet_aton+:} false; then :
+ if test ${ac_cv_search_inet_aton+y}
+then :
break
fi
done
-if ${ac_cv_search_inet_aton+:} false; then :
+if test ${ac_cv_search_inet_aton+y}
+then :
-else
+else $as_nop
ac_cv_search_inet_aton=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5
-$as_echo "$ac_cv_search_inet_aton" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5
+printf "%s\n" "$ac_cv_search_inet_aton" >&6; }
ac_res=$ac_cv_search_inet_aton
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
-$as_echo_n "checking for library containing gethostbyname... " >&6; }
-if ${ac_cv_search_gethostbyname+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
+printf %s "checking for library containing gethostbyname... " >&6; }
+if test ${ac_cv_search_gethostbyname+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gethostbyname ();
+namespace conftest {
+ extern "C" int gethostbyname ();
+}
int
-main ()
+main (void)
{
-return gethostbyname ();
+return conftest::gethostbyname ();
;
return 0;
}
_ACEOF
-for ac_lib in '' nsl; do
+for ac_lib in '' nsl
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_gethostbyname=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_gethostbyname+:} false; then :
+ if test ${ac_cv_search_gethostbyname+y}
+then :
break
fi
done
-if ${ac_cv_search_gethostbyname+:} false; then :
+if test ${ac_cv_search_gethostbyname+y}
+then :
-else
+else $as_nop
ac_cv_search_gethostbyname=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
-$as_echo "$ac_cv_search_gethostbyname" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
+printf "%s\n" "$ac_cv_search_gethostbyname" >&6; }
ac_res=$ac_cv_search_gethostbyname
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5
-$as_echo_n "checking for library containing socket... " >&6; }
-if ${ac_cv_search_socket+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5
+printf %s "checking for library containing socket... " >&6; }
+if test ${ac_cv_search_socket+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char socket ();
+namespace conftest {
+ extern "C" int socket ();
+}
int
-main ()
+main (void)
{
-return socket ();
+return conftest::socket ();
;
return 0;
}
_ACEOF
-for ac_lib in '' socket; do
+for ac_lib in '' socket
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_socket=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_socket+:} false; then :
+ if test ${ac_cv_search_socket+y}
+then :
break
fi
done
-if ${ac_cv_search_socket+:} false; then :
+if test ${ac_cv_search_socket+y}
+then :
-else
+else $as_nop
ac_cv_search_socket=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5
-$as_echo "$ac_cv_search_socket" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5
+printf "%s\n" "$ac_cv_search_socket" >&6; }
ac_res=$ac_cv_search_socket
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostent" >&5
-$as_echo_n "checking for library containing gethostent... " >&6; }
-if ${ac_cv_search_gethostent+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing gethostent" >&5
+printf %s "checking for library containing gethostent... " >&6; }
+if test ${ac_cv_search_gethostent+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gethostent ();
+namespace conftest {
+ extern "C" int gethostent ();
+}
int
-main ()
+main (void)
{
-return gethostent ();
+return conftest::gethostent ();
;
return 0;
}
_ACEOF
-for ac_lib in '' nsl; do
+for ac_lib in '' nsl
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_gethostent=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_gethostent+:} false; then :
+ if test ${ac_cv_search_gethostent+y}
+then :
break
fi
done
-if ${ac_cv_search_gethostent+:} false; then :
+if test ${ac_cv_search_gethostent+y}
+then :
-else
+else $as_nop
ac_cv_search_gethostent=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostent" >&5
-$as_echo "$ac_cv_search_gethostent" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostent" >&5
+printf "%s\n" "$ac_cv_search_gethostent" >&6; }
ac_res=$ac_cv_search_gethostent
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
- for ac_func in recvmmsg sendmmsg accept4
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "recvmmsg" "ac_cv_func_recvmmsg"
+if test "x$ac_cv_func_recvmmsg" = xyes
+then :
+ printf "%s\n" "#define HAVE_RECVMMSG 1" >>confdefs.h
fi
-done
+ac_fn_cxx_check_func "$LINENO" "sendmmsg" "ac_cv_func_sendmmsg"
+if test "x$ac_cv_func_sendmmsg" = xyes
+then :
+ printf "%s\n" "#define HAVE_SENDMMSG 1" >>confdefs.h
- ac_fn_cxx_check_decl "$LINENO" "getifaddrs" "ac_cv_have_decl_getifaddrs" "#include <ifaddrs.h>
-"
-if test "x$ac_cv_have_decl_getifaddrs" = xyes; then :
-
-$as_echo "#define HAVE_GETIFADDRS 1" >>confdefs.h
+fi
+ac_fn_cxx_check_func "$LINENO" "accept4" "ac_cv_func_accept4"
+if test "x$ac_cv_func_accept4" = xyes
+then :
+ printf "%s\n" "#define HAVE_ACCEPT4 1" >>confdefs.h
fi
+ ac_fn_check_decl "$LINENO" "getifaddrs" "ac_cv_have_decl_getifaddrs" "#include <ifaddrs.h>
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_getifaddrs" = xyes
+then :
+printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_setaffinity_np" >&5
-$as_echo_n "checking for library containing pthread_setaffinity_np... " >&6; }
-if ${ac_cv_search_pthread_setaffinity_np+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_setaffinity_np" >&5
+printf %s "checking for library containing pthread_setaffinity_np... " >&6; }
+if test ${ac_cv_search_pthread_setaffinity_np+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_setaffinity_np ();
+namespace conftest {
+ extern "C" int pthread_setaffinity_np ();
+}
int
-main ()
+main (void)
{
-return pthread_setaffinity_np ();
+return conftest::pthread_setaffinity_np ();
;
return 0;
}
_ACEOF
-for ac_lib in '' pthread; do
+for ac_lib in '' pthread
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_pthread_setaffinity_np=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_pthread_setaffinity_np+:} false; then :
+ if test ${ac_cv_search_pthread_setaffinity_np+y}
+then :
break
fi
done
-if ${ac_cv_search_pthread_setaffinity_np+:} false; then :
+if test ${ac_cv_search_pthread_setaffinity_np+y}
+then :
-else
+else $as_nop
ac_cv_search_pthread_setaffinity_np=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_setaffinity_np" >&5
-$as_echo "$ac_cv_search_pthread_setaffinity_np" >&6; }
+{ 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; }
ac_res=$ac_cv_search_pthread_setaffinity_np
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_PTHREAD_SETAFFINITY_NP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_SETAFFINITY_NP 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_getattr_np" >&5
-$as_echo_n "checking for library containing pthread_getattr_np... " >&6; }
-if ${ac_cv_search_pthread_getattr_np+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_getattr_np" >&5
+printf %s "checking for library containing pthread_getattr_np... " >&6; }
+if test ${ac_cv_search_pthread_getattr_np+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_getattr_np ();
+namespace conftest {
+ extern "C" int pthread_getattr_np ();
+}
int
-main ()
+main (void)
{
-return pthread_getattr_np ();
+return conftest::pthread_getattr_np ();
;
return 0;
}
_ACEOF
-for ac_lib in '' pthread; do
+for ac_lib in '' pthread
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_pthread_getattr_np=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_pthread_getattr_np+:} false; then :
+ if test ${ac_cv_search_pthread_getattr_np+y}
+then :
break
fi
done
-if ${ac_cv_search_pthread_getattr_np+:} false; then :
+if test ${ac_cv_search_pthread_getattr_np+y}
+then :
-else
+else $as_nop
ac_cv_search_pthread_getattr_np=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_getattr_np" >&5
-$as_echo "$ac_cv_search_pthread_getattr_np" >&6; }
+{ 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; }
ac_res=$ac_cv_search_pthread_getattr_np
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_PTHREAD_GETATTR_NP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_GETATTR_NP 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_get_stackaddr_np" >&5
-$as_echo_n "checking for library containing pthread_get_stackaddr_np... " >&6; }
-if ${ac_cv_search_pthread_get_stackaddr_np+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_get_stackaddr_np" >&5
+printf %s "checking for library containing pthread_get_stackaddr_np... " >&6; }
+if test ${ac_cv_search_pthread_get_stackaddr_np+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_get_stackaddr_np ();
+namespace conftest {
+ extern "C" int pthread_get_stackaddr_np ();
+}
int
-main ()
+main (void)
{
-return pthread_get_stackaddr_np ();
+return conftest::pthread_get_stackaddr_np ();
;
return 0;
}
_ACEOF
-for ac_lib in '' pthread; do
+for ac_lib in '' pthread
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_pthread_get_stackaddr_np=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_pthread_get_stackaddr_np+:} false; then :
+ if test ${ac_cv_search_pthread_get_stackaddr_np+y}
+then :
break
fi
done
-if ${ac_cv_search_pthread_get_stackaddr_np+:} false; then :
+if test ${ac_cv_search_pthread_get_stackaddr_np+y}
+then :
-else
+else $as_nop
ac_cv_search_pthread_get_stackaddr_np=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_get_stackaddr_np" >&5
-$as_echo "$ac_cv_search_pthread_get_stackaddr_np" >&6; }
+{ 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; }
ac_res=$ac_cv_search_pthread_get_stackaddr_np
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_PTHREAD_GET_STACKADDR_NP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_GET_STACKADDR_NP 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_get_stacksize_np" >&5
-$as_echo_n "checking for library containing pthread_get_stacksize_np... " >&6; }
-if ${ac_cv_search_pthread_get_stacksize_np+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_get_stacksize_np" >&5
+printf %s "checking for library containing pthread_get_stacksize_np... " >&6; }
+if test ${ac_cv_search_pthread_get_stacksize_np+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_get_stacksize_np ();
+namespace conftest {
+ extern "C" int pthread_get_stacksize_np ();
+}
int
-main ()
+main (void)
{
-return pthread_get_stacksize_np ();
+return conftest::pthread_get_stacksize_np ();
;
return 0;
}
_ACEOF
-for ac_lib in '' pthread; do
+for ac_lib in '' pthread
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_pthread_get_stacksize_np=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_pthread_get_stacksize_np+:} false; then :
+ if test ${ac_cv_search_pthread_get_stacksize_np+y}
+then :
break
fi
done
-if ${ac_cv_search_pthread_get_stacksize_np+:} false; then :
+if test ${ac_cv_search_pthread_get_stacksize_np+y}
+then :
-else
+else $as_nop
ac_cv_search_pthread_get_stacksize_np=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_get_stacksize_np" >&5
-$as_echo "$ac_cv_search_pthread_get_stacksize_np" >&6; }
+{ 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; }
ac_res=$ac_cv_search_pthread_get_stacksize_np
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-$as_echo "#define HAVE_PTHREAD_GET_STACKSIZE_NP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_PTHREAD_GET_STACKSIZE_NP 1" >>confdefs.h
fi
- for ac_func in explicit_bzero explicit_memset
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
+if test "x$ac_cv_func_explicit_bzero" = xyes
+then :
+ printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "explicit_memset" "ac_cv_func_explicit_memset"
+if test "x$ac_cv_func_explicit_memset" = xyes
+then :
+ printf "%s\n" "#define HAVE_EXPLICIT_MEMSET 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "memset_s" "ac_cv_func_memset_s"
+if test "x$ac_cv_func_memset_s" = xyes
+then :
+ printf "%s\n" "#define HAVE_MEMSET_S 1" >>confdefs.h
fi
-done
-ac_fn_cxx_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default"
-if test "x$ac_cv_have_decl_strerror_r" = xyes; then :
+ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_strerror_r" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_STRERROR_R $ac_have_decl
-_ACEOF
-for ac_func in strerror_r
-do :
- ac_fn_cxx_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r"
-if test "x$ac_cv_func_strerror_r" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_STRERROR_R 1
-_ACEOF
+if test $ac_cv_have_decl_strerror_r = yes; then
+ # For backward compatibility's sake, define HAVE_STRERROR_R.
+ # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well
+ # as AC_CHECK_DECLS_ONCE.)
+
+printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h
fi
-done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
-$as_echo_n "checking whether strerror_r returns char *... " >&6; }
-if ${ac_cv_func_strerror_r_char_p+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
+printf %s "checking whether strerror_r returns char *... " >&6; }
+if test ${ac_cv_func_strerror_r_char_p+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
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
/* end confdefs.h. */
-$ac_includes_default
+#include <string.h>
int
-main ()
+main (void)
{
char buf[100];
@@ -17977,49 +19230,20 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
ac_cv_func_strerror_r_char_p=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- else
- # strerror_r is not declared. Choose between
- # systems that have relatively inaccessible declarations for the
- # function. BeOS and DEC UNIX 4.0 fall in this category, but the
- # former has a strerror_r that returns char*, while the latter
- # has a strerror_r that returns `int'.
- # This test should segfault on the DEC system.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_includes_default
- extern char *strerror_r ();
-int
-main ()
-{
-char buf[100];
- char x = *strerror_r (0, buf, sizeof buf);
- return ! isalpha (x);
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_run "$LINENO"; then :
- ac_cv_func_strerror_r_char_p=yes
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
-$as_echo "$ac_cv_func_strerror_r_char_p" >&6; }
+{ 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; }
if test $ac_cv_func_strerror_r_char_p = yes; then
-$as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h
+printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h
fi
@@ -18036,28 +19260,30 @@ boost_version_req=`expr "$1" '*' 100000 + "$2" '*' 100 + "$3"`
boost_version_req_string=$1.$2.$3
# Check whether --with-boost was given.
-if test "${with_boost+set}" = set; then :
+if test ${with_boost+y}
+then :
withval=$with_boost;
fi
# If BOOST_ROOT is set and the user has not provided a value to
# --with-boost, then treat BOOST_ROOT as if it the user supplied it.
if test x"$BOOST_ROOT" != x; then
if test x"$with_boost" = x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&5
-$as_echo "$as_me: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&5
+printf "%s\n" "$as_me: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&6;}
with_boost=$BOOST_ROOT
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&5
-$as_echo "$as_me: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&5
+printf "%s\n" "$as_me: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&6;}
fi
fi
DISTCHECK_CONFIGURE_FLAGS="$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'"
boost_save_CPPFLAGS=$CPPFLAGS
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost headers version >= $boost_version_req_string" >&5
-$as_echo_n "checking for Boost headers version >= $boost_version_req_string... " >&6; }
-if ${boost_cv_inc_path+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Boost headers version >= $boost_version_req_string" >&5
+printf %s "checking for Boost headers version >= $boost_version_req_string... " >&6; }
+if test ${boost_cv_inc_path+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
boost_cv_inc_path=no
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
@@ -18074,7 +19300,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
#endif
int
-main ()
+main (void)
{
;
@@ -18124,12 +19350,13 @@ _ACEOF
test -e "$boost_inc/boost/version.hpp" || continue
CPPFLAGS="$CPPFLAGS -I$boost_inc"
fi
- if ac_fn_cxx_try_compile "$LINENO"; then :
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
boost_cv_inc_path=yes
-else
+else $as_nop
boost_cv_version=no
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
if test x"$boost_cv_inc_path" = xyes; then
if test x"$boost_inc" != x; then
boost_cv_inc_path=$boost_inc
@@ -18145,8 +19372,8 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_inc_path" >&5
-$as_echo "$boost_cv_inc_path" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_inc_path" >&5
+printf "%s\n" "$boost_cv_inc_path" >&6; }
case $boost_cv_inc_path in #(
no)
boost_errmsg="cannot find Boost headers version >= $boost_version_req_string"
@@ -18162,13 +19389,14 @@ $as_echo "$boost_cv_inc_path" >&6; }
esac
if test x"$boost_cv_inc_path" != xno; then
-$as_echo "#define HAVE_BOOST 1" >>confdefs.h
+printf "%s\n" "#define HAVE_BOOST 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost's header version" >&5
-$as_echo_n "checking for Boost's header version... " >&6; }
-if ${boost_cv_lib_version+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Boost's header version" >&5
+printf %s "checking for Boost's header version... " >&6; }
+if test ${boost_cv_lib_version+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -18184,7 +19412,8 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
grep -v '^[[:space:]]*$' |
tr -d '\r' |
tr -s '\n' ' ' |
- $SED -n -e "/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}" >conftest.i 2>&1; then :
+ $SED -n -e "/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}" >conftest.i 2>&1
+then :
boost_cv_lib_version=`cat conftest.i`
fi
rm -rf conftest*
@@ -18195,8 +19424,8 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_version" >&5
-$as_echo "$boost_cv_lib_version" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_version" >&5
+printf "%s\n" "$boost_cv_lib_version" >&6; }
# e.g. "134" for 1_34_1 or "135" for 1_35
boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'`
case $boost_major_version in #(
@@ -18208,11 +19437,12 @@ fi
CPPFLAGS=$boost_save_CPPFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5
-$as_echo_n "checking for the toolset name used by Boost for $CXX... " >&6; }
-if ${boost_cv_lib_tag+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5
+printf %s "checking for the toolset name used by Boost for $CXX... " >&6; }
+if test ${boost_cv_lib_tag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
boost_cv_lib_tag=unknown
if test x$boost_cv_inc_path != xno; then
ac_ext=cpp
@@ -18234,6 +19464,9 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
# I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
# the same defines as GCC's).
for i in \
+ "defined __clang__ && __clang_major__ == 17 && __clang_minor__ == 0 @ clang170" \
+ "defined __clang__ && __clang_major__ == 16 && __clang_minor__ == 0 @ clang160" \
+ "defined __clang__ && __clang_major__ == 15 && __clang_minor__ == 0 @ clang150" \
"defined __clang__ && __clang_major__ == 14 && __clang_minor__ == 0 @ clang140" \
"defined __clang__ && __clang_major__ == 13 && __clang_minor__ == 0 @ clang130" \
"defined __clang__ && __clang_major__ == 12 && __clang_minor__ == 0 @ clang120" \
@@ -18450,17 +19683,18 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
#endif
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
boost_cv_lib_tag=$boost_tag; break
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
done
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
@@ -18485,19 +19719,20 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
;; #(
unknown)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5
-$as_echo "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5
+printf "%s\n" "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;}
boost_cv_lib_tag=
;;
esac
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5
-$as_echo "$boost_cv_lib_tag" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5
+printf "%s\n" "$boost_cv_lib_tag" >&6; }
# Check whether --enable-static-boost was given.
-if test "${enable_static_boost+set}" = set; then :
+if test ${enable_static_boost+y}
+then :
enableval=$enable_static_boost; enable_static_boost=yes
-else
+else $as_nop
enable_static_boost=no
fi
@@ -18517,19 +19752,20 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#endif
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
boost_guess_use_mt=:
-else
+else $as_nop
boost_guess_use_mt=false
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -18537,18 +19773,19 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit test building" >&5
-$as_echo_n "checking whether to enable unit test building... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable unit test building" >&5
+printf %s "checking whether to enable unit test building... " >&6; }
# Check whether --enable-unit-tests was given.
-if test "${enable_unit_tests+set}" = set; then :
+if test ${enable_unit_tests+y}
+then :
enableval=$enable_unit_tests; enable_unit_tests=$enableval
-else
+else $as_nop
enable_unit_tests=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_unit_tests" >&5
-$as_echo "$enable_unit_tests" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_unit_tests" >&5
+printf "%s\n" "$enable_unit_tests" >&6; }
if test "x$enable_unit_tests" != "xno"; then
UNIT_TESTS_TRUE=
UNIT_TESTS_FALSE='#'
@@ -18558,18 +19795,20 @@ else
fi
- if test "x$enable_unit_tests" != "xno"; then :
+ if test "x$enable_unit_tests" != "xno"
+then :
if test x"$boost_cv_inc_path" = xno; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost unit_test_framework library" >&5
-$as_echo "$as_me: Boost not available, not searching for the Boost unit_test_framework library" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost unit_test_framework library" >&5
+printf "%s\n" "$as_me: Boost not available, not searching for the Boost unit_test_framework library" >&6;}
else
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'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-if test x"" = "xno"; then :
+if test x"" = "xno"
+then :
not_found_header='true'
fi
if test x"$boost_cv_inc_path" = xno; then
@@ -18582,16 +19821,16 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
boost_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-ac_fn_cxx_check_header_mongrel "$LINENO" "boost/test/unit_test.hpp" "ac_cv_header_boost_test_unit_test_hpp" "$ac_includes_default"
-if test "x$ac_cv_header_boost_test_unit_test_hpp" = xyes; then :
+ac_fn_cxx_check_header_compile "$LINENO" "boost/test/unit_test.hpp" "ac_cv_header_boost_test_unit_test_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_test_unit_test_hpp" = xyes
+then :
-$as_echo "#define HAVE_BOOST_TEST_UNIT_TEST_HPP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_BOOST_TEST_UNIT_TEST_HPP 1" >>confdefs.h
-else
+else $as_nop
$not_found_header
fi
-
CPPFLAGS=$boost_save_CPPFLAGS
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
@@ -18602,11 +19841,12 @@ fi
boost_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost unit_test_framework library" >&5
-$as_echo_n "checking for the Boost unit_test_framework library... " >&6; }
-if ${boost_cv_lib_unit_test_framework+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Boost unit_test_framework library" >&5
+printf %s "checking for the Boost unit_test_framework library... " >&6; }
+if test ${boost_cv_lib_unit_test_framework+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
boost_cv_lib_unit_test_framework=no
case "mt" in #(
(mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
@@ -18640,24 +19880,26 @@ using boost::unit_test::test_suite;
test_suite* init_unit_test_suite(int argc, char ** argv)
{ return NULL; }
int
-main ()
+main (void)
{
BOOST_CHECK(2 == 2);
;
return 0;
}
_ACEOF
- if ac_fn_cxx_try_compile "$LINENO"; then :
+ if ac_fn_cxx_try_compile "$LINENO"
+then :
ac_objext=do_not_rm_me_plz
-else
- if test x"" != x"no"; then :
+else $as_nop
+ if test x"" != x"no"
+then :
as_fn_error $? "cannot compile a test that uses Boost unit_test_framework" "$LINENO" 5
fi
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
ac_objext=$boost_save_ac_objext
boost_failed_libs=
# Don't bother to ident the following nested for loops, only the 2
@@ -18710,14 +19952,14 @@ boost_use_source=:
# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
# tries to link the existing object file instead of compiling from source.
test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
- $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -18725,18 +19967,19 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
$as_executable_p conftest$ac_exeext
- }; then :
+ }
+then :
boost_cv_lib_unit_test_framework=yes
-else
+else $as_nop
if $boost_use_source; then
- $as_echo "$as_me: failed program was:" >&5
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
@@ -18754,9 +19997,10 @@ rm -f core conftest.err conftest_ipa8_conftest.oo \
# -rpath makes sense. Some implementations of ld, such as for
# Mac OSX, require -rpath but -R is the flag known to work on
# other systems. https://github.com/tsuna/boost.m4/issues/19
- if ${boost_cv_rpath_link_ldflag+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ if test ${boost_cv_rpath_link_ldflag+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $boost_ldpath in
'') # Nothing to do.
boost_cv_rpath_link_ldflag=
@@ -18771,14 +20015,14 @@ boost_use_source=:
# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
# tries to link the existing object file instead of compiling from source.
test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
- $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -18786,19 +20030,20 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
$as_executable_p conftest$ac_exeext
- }; then :
+ }
+then :
boost_rpath_link_ldflag_found=yes
break
-else
+else $as_nop
if $boost_use_source; then
- $as_echo "$as_me: failed program was:" >&5
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
@@ -18811,7 +20056,8 @@ rm -f core conftest.err conftest_ipa8_conftest.oo \
done
;;
esac
- if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"
+then :
as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
fi
LDFLAGS=$boost_save_LDFLAGS
@@ -18837,23 +20083,24 @@ done # boost_lib_
rm -f conftest.$ac_objext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_unit_test_framework" >&5
-$as_echo "$boost_cv_lib_unit_test_framework" >&6; }
+{ 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; }
case $boost_cv_lib_unit_test_framework in #(
- (yes) $as_echo "$as_me: failed program was:" >&5
+ (yes) printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-$as_echo "#define HAVE_BOOST_UNIT_TEST_FRAMEWORK 1" >>confdefs.h
+printf "%s\n" "#define HAVE_BOOST_UNIT_TEST_FRAMEWORK 1" >>confdefs.h
BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS=$boost_cv_lib_unit_test_framework_LDFLAGS
BOOST_UNIT_TEST_FRAMEWORK_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH
BOOST_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH
BOOST_UNIT_TEST_FRAMEWORK_LIBS=$boost_cv_lib_unit_test_framework_LIBS
;;
- (no) $as_echo "$as_me: failed program was:" >&5
+ (no) printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
- if test x"" != "xno"; then :
+ if test x"" != "xno"
+then :
as_fn_error $? "cannot find flags to link with the Boost unit_test_framework library (libboost-unit_test_framework)" "$LINENO" 5
@@ -18870,7 +20117,8 @@ fi
- if test "$boost_cv_lib_unit_test_framework" = "no"; then :
+ if test "$boost_cv_lib_unit_test_framework" = "no"
+then :
as_fn_error $? "Boost Unit Test library not found" "$LINENO" 5
@@ -18879,35 +20127,60 @@ fi
fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable fuzzing targets" >&5
+printf %s "checking whether to enable fuzzing targets... " >&6; }
+ # Check whether --enable-fuzz_targets was given.
+if test ${enable_fuzz_targets+y}
+then :
+ enableval=$enable_fuzz_targets; enable_fuzz_targets=$enableval
+else $as_nop
+ enable_fuzz_targets=no
+
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_fuzz_targets" >&5
+printf "%s\n" "$enable_fuzz_targets" >&6; }
+ if test "x$enable_fuzz_targets" != "xno"; then
+ FUZZ_TARGETS_TRUE=
+ FUZZ_TARGETS_FALSE='#'
+else
+ FUZZ_TARGETS_TRUE='#'
+ FUZZ_TARGETS_FALSE=
+fi
+
+
+
HAVE_RE2=0
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we should compile in libre2 for dnsdist" >&5
-$as_echo_n "checking if we should compile in libre2 for dnsdist... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we should compile in libre2 for dnsdist" >&5
+printf %s "checking if we should compile in libre2 for dnsdist... " >&6; }
# Check whether --with-re2 was given.
-if test "${with_re2+set}" = set; then :
+if test ${with_re2+y}
+then :
withval=$with_re2; with_re2=$withval
-else
+else $as_nop
with_re2=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_re2" >&5
-$as_echo "$with_re2" >&6; }
- if test "x$with_re2" = "xyes"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_re2" >&5
+printf "%s\n" "$with_re2" >&6; }
+ if test "x$with_re2" = "xyes"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RE2" >&5
-$as_echo_n "checking for RE2... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for re2" >&5
+printf %s "checking for re2... " >&6; }
if test -n "$RE2_CFLAGS"; then
pkg_cv_RE2_CFLAGS="$RE2_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"re2\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"re2\""; } >&5
($PKG_CONFIG --exists --print-errors "re2") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_RE2_CFLAGS=`$PKG_CONFIG --cflags "re2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -18921,10 +20194,10 @@ if test -n "$RE2_LIBS"; then
pkg_cv_RE2_LIBS="$RE2_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"re2\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"re2\""; } >&5
($PKG_CONFIG --exists --print-errors "re2") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_RE2_LIBS=`$PKG_CONFIG --libs "re2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -18938,8 +20211,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -18947,52 +20220,58 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- RE2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "re2" 2>&1`
+ RE2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "re2" 2>&1`
else
- RE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "re2" 2>&1`
+ RE2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "re2" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$RE2_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$RE2_PKG_ERRORS" >&5
- ac_fn_cxx_check_header_mongrel "$LINENO" "re2/re2.h" "ac_cv_header_re2_re2_h" "$ac_includes_default"
-if test "x$ac_cv_header_re2_re2_h" = xyes; then :
+ ac_fn_cxx_check_header_compile "$LINENO" "re2/re2.h" "ac_cv_header_re2_re2_h" "$ac_includes_default"
+if test "x$ac_cv_header_re2_re2_h" = xyes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lre2" >&5
-$as_echo_n "checking for main in -lre2... " >&6; }
-if ${ac_cv_lib_re2_main+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lre2" >&5
+printf %s "checking for main in -lre2... " >&6; }
+if test ${ac_cv_lib_re2_main+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lre2 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
+namespace conftest {
+ extern "C" int main ();
+}
int
-main ()
+main (void)
{
-return main ();
+return conftest::main ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_lib_re2_main=yes
-else
+else $as_nop
ac_cv_lib_re2_main=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_re2_main" >&5
-$as_echo "$ac_cv_lib_re2_main" >&6; }
-if test "x$ac_cv_lib_re2_main" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_re2_main" >&5
+printf "%s\n" "$ac_cv_lib_re2_main" >&6; }
+if test "x$ac_cv_lib_re2_main" = xyes
+then :
HAVE_RE2=1
RE2_LIBS="-lre2"
-else
+else $as_nop
:
fi
@@ -19000,49 +20279,54 @@ fi
fi
-
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
- ac_fn_cxx_check_header_mongrel "$LINENO" "re2/re2.h" "ac_cv_header_re2_re2_h" "$ac_includes_default"
-if test "x$ac_cv_header_re2_re2_h" = xyes; then :
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lre2" >&5
-$as_echo_n "checking for main in -lre2... " >&6; }
-if ${ac_cv_lib_re2_main+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+ ac_fn_cxx_check_header_compile "$LINENO" "re2/re2.h" "ac_cv_header_re2_re2_h" "$ac_includes_default"
+if test "x$ac_cv_header_re2_re2_h" = xyes
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lre2" >&5
+printf %s "checking for main in -lre2... " >&6; }
+if test ${ac_cv_lib_re2_main+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lre2 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
+namespace conftest {
+ extern "C" int main ();
+}
int
-main ()
+main (void)
{
-return main ();
+return conftest::main ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_lib_re2_main=yes
-else
+else $as_nop
ac_cv_lib_re2_main=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_re2_main" >&5
-$as_echo "$ac_cv_lib_re2_main" >&6; }
-if test "x$ac_cv_lib_re2_main" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_re2_main" >&5
+printf "%s\n" "$ac_cv_lib_re2_main" >&6; }
+if test "x$ac_cv_lib_re2_main" = xyes
+then :
HAVE_RE2=1
RE2_LIBS="-lre2"
-else
+else $as_nop
:
fi
@@ -19050,16 +20334,16 @@ fi
fi
-
else
- RE2_CFLAGS=$pkg_cv_RE2_CFLAGS
- RE2_LIBS=$pkg_cv_RE2_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ RE2_CFLAGS=$pkg_cv_RE2_CFLAGS
+ RE2_LIBS=$pkg_cv_RE2_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_RE2=1
fi
- if test "$HAVE_RE2" -ne 1; then :
+ if test "$HAVE_RE2" -ne 1
+then :
as_fn_error $? "Could not find libre2" "$LINENO" 5
fi
@@ -19072,25 +20356,27 @@ else
HAVE_RE2_FALSE=
fi
- if test "$HAVE_RE2" -eq 1; then :
+ if test "$HAVE_RE2" -eq 1
+then :
-$as_echo "#define HAVE_RE2 1" >>confdefs.h
+printf "%s\n" "#define HAVE_RE2 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable DNSCrypt support" >&5
-$as_echo_n "checking whether to enable DNSCrypt support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable DNSCrypt support" >&5
+printf %s "checking whether to enable DNSCrypt support... " >&6; }
# Check whether --enable-dnscrypt was given.
-if test "${enable_dnscrypt+set}" = set; then :
+if test ${enable_dnscrypt+y}
+then :
enableval=$enable_dnscrypt; enable_dnscrypt=$enableval
-else
+else $as_nop
enable_dnscrypt=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dnscrypt" >&5
-$as_echo "$enable_dnscrypt" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dnscrypt" >&5
+printf "%s\n" "$enable_dnscrypt" >&6; }
if test "x$enable_dnscrypt" != "xno"; then
DNSCRYPT_TRUE=
DNSCRYPT_FALSE='#'
@@ -19105,7 +20391,7 @@ fi
if test -z "$LIBSODIUM_TRUE"; then :
-$as_echo "#define HAVE_DNSCRYPT 1" >>confdefs.h
+printf "%s\n" "#define HAVE_DNSCRYPT 1" >>confdefs.h
else
@@ -19117,44 +20403,47 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have eBPF support" >&5
-$as_echo_n "checking if we have eBPF support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we have eBPF support" >&5
+printf %s "checking if we have eBPF support... " >&6; }
# Check whether --with-ebpf was given.
-if test "${with_ebpf+set}" = set; then :
+if test ${with_ebpf+y}
+then :
withval=$with_ebpf; with_ebpf=$withval
-else
+else $as_nop
with_ebpf=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_ebpf" >&5
-$as_echo "$with_ebpf" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_ebpf" >&5
+printf "%s\n" "$with_ebpf" >&6; }
- if test "x$with_ebpf" != "xno"; then :
+ if test "x$with_ebpf" != "xno"
+then :
- if test "x$with_ebpf" = "xyes" -o "x$with_ebpf" = "xauto"; then :
+ if test "x$with_ebpf" = "xyes" -o "x$with_ebpf" = "xauto"
+then :
- for ac_header in linux/bpf.h
+ for ac_header in linux/bpf.h
do :
- ac_fn_cxx_check_header_mongrel "$LINENO" "linux/bpf.h" "ac_cv_header_linux_bpf_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_bpf_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LINUX_BPF_H 1
-_ACEOF
+ ac_fn_cxx_check_header_compile "$LINENO" "linux/bpf.h" "ac_cv_header_linux_bpf_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_bpf_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LINUX_BPF_H 1" >>confdefs.h
bpf_headers=yes
-else
+else $as_nop
bpf_headers=no
fi
done
-
fi
fi
- if test "x$with_ebpf" = "xyes"; then :
+ if test "x$with_ebpf" = "xyes"
+then :
- if test x"$bpf_headers" = "no"; then :
+ if test x"$bpf_headers" = "no"
+then :
as_fn_error $? "EBPF support requested but required eBPF headers were not found" "$LINENO" 5
@@ -19169,64 +20458,288 @@ else
HAVE_EBPF_FALSE=
fi
- if test x"$bpf_headers" = "xyes" ; then :
- ac_fn_cxx_check_decl "$LINENO" "BPF_FUNC_tail_call" "ac_cv_have_decl_BPF_FUNC_tail_call" "#include <linux/bpf.h>
+ if test x"$bpf_headers" = "xyes"
+then :
+ ac_fn_check_decl "$LINENO" "BPF_FUNC_tail_call" "ac_cv_have_decl_BPF_FUNC_tail_call" "#include <linux/bpf.h>
-"
-if test "x$ac_cv_have_decl_BPF_FUNC_tail_call" = xyes; then :
- ac_fn_cxx_check_decl "$LINENO" "SO_ATTACH_BPF" "ac_cv_have_decl_SO_ATTACH_BPF" "#include <sys/socket.h>
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_BPF_FUNC_tail_call" = xyes
+then :
+ ac_fn_check_decl "$LINENO" "SO_ATTACH_BPF" "ac_cv_have_decl_SO_ATTACH_BPF" "#include <sys/socket.h>
-"
-if test "x$ac_cv_have_decl_SO_ATTACH_BPF" = xyes; then :
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_SO_ATTACH_BPF" = xyes
+then :
-$as_echo "#define HAVE_EBPF 1" >>confdefs.h
+printf "%s\n" "#define HAVE_EBPF 1" >>confdefs.h
-else
- if test "x$with_ebpf" = "xyes"; then :
+else $as_nop
+ if test "x$with_ebpf" = "xyes"
+then :
as_fn_error $? "EBPF support requested but SO_ATTACH_BPF not found" "$LINENO" 5
fi
fi
+else $as_nop
+ if test "x$with_ebpf" = "xyes"
+then :
+
+ as_fn_error $? "EBPF support requested but BPF_FUNC_tail_call not found in the eBPF headers" "$LINENO" 5
+
+fi
+fi
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we have AF_XDP (XSK) support" >&5
+printf %s "checking if we have AF_XDP (XSK) support... " >&6; }
+
+# Check whether --with-xsk was given.
+if test ${with_xsk+y}
+then :
+ withval=$with_xsk; with_xsk=$withval
+else $as_nop
+ with_xsk=auto
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_xsk" >&5
+printf "%s\n" "$with_xsk" >&6; }
+
+ if test "x$with_xsk" != "xno"
+then :
+
+ if test "x$with_xsk" = "xyes" -o "x$with_xsk" = "xauto"
+then :
+
+
+pkg_failed=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libxdp" >&5
+printf %s "checking for libxdp... " >&6; }
+
+if test -n "$XDP_CFLAGS"; then
+ pkg_cv_XDP_CFLAGS="$XDP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxdp\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libxdp") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_XDP_CFLAGS=`$PKG_CONFIG --cflags "libxdp" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
else
- if test "x$with_ebpf" = "xyes"; then :
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$XDP_LIBS"; then
+ pkg_cv_XDP_LIBS="$XDP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxdp\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libxdp") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_XDP_LIBS=`$PKG_CONFIG --libs "libxdp" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
- as_fn_error $? "EBPF support requested but BPF_FUNC_tail_call not found in the eBPF headers" "$LINENO" 5
+if test $pkg_failed = yes; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
fi
+ if test $_pkg_short_errors_supported = yes; then
+ XDP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libxdp" 2>&1`
+ else
+ XDP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libxdp" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$XDP_PKG_ERRORS" >&5
+
+ :
+elif test $pkg_failed = untried; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
+else
+ XDP_CFLAGS=$pkg_cv_XDP_CFLAGS
+ XDP_LIBS=$pkg_cv_XDP_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+
+printf "%s\n" "#define HAVE_XDP 1" >>confdefs.h
+
+
fi
+pkg_failed=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbpf" >&5
+printf %s "checking for libbpf... " >&6; }
+if test -n "$BPF_CFLAGS"; then
+ pkg_cv_BPF_CFLAGS="$BPF_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbpf\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libbpf") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_BPF_CFLAGS=`$PKG_CONFIG --cflags "libbpf" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$BPF_LIBS"; then
+ pkg_cv_BPF_LIBS="$BPF_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbpf\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libbpf") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_BPF_LIBS=`$PKG_CONFIG --libs "libbpf" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need to link in Net SNMP" >&5
-$as_echo_n "checking if we need to link in Net SNMP... " >&6; }
+
+if test $pkg_failed = yes; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ BPF_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libbpf" 2>&1`
+ else
+ BPF_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libbpf" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$BPF_PKG_ERRORS" >&5
+
+ :
+elif test $pkg_failed = untried; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
+else
+ BPF_CFLAGS=$pkg_cv_BPF_CFLAGS
+ BPF_LIBS=$pkg_cv_BPF_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+
+
+printf "%s\n" "#define HAVE_BPF 1" >>confdefs.h
+
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$BPF_CFLAGS $CFLAGS"
+ LIBS="$BPF_LIBS $LIBS"
+ ac_fn_cxx_check_func "$LINENO" "bpf_xdp_query" "ac_cv_func_bpf_xdp_query"
+if test "x$ac_cv_func_bpf_xdp_query" = xyes
+then :
+ printf "%s\n" "#define HAVE_BPF_XDP_QUERY 1" >>confdefs.h
+
+fi
+
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
+
+fi
+
+fi
+
+fi
+
+ if test x"$BPF_LIBS" != "x" -a x"$XDP_LIBS" != "x"; then
+ HAVE_XSK_TRUE=
+ HAVE_XSK_FALSE='#'
+else
+ HAVE_XSK_TRUE='#'
+ HAVE_XSK_FALSE=
+fi
+
+ if test -z "$HAVE_XSK_TRUE"; then :
+
+
+printf "%s\n" "#define HAVE_XSK 1" >>confdefs.h
+
+
+fi
+
+ if test "x$with_xsk" = "xyes"
+then :
+
+ if test x"$BPF_LIBS" = "x" -o x"$XDP_LIBS" = "x"
+then :
+
+ as_fn_error $? "AF_XDP (XSK) support requested but required libbpf and/or libxdp were not found" "$LINENO" 5
+
+fi
+
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we need to link in Net SNMP" >&5
+printf %s "checking if we need to link in Net SNMP... " >&6; }
# Check whether --with-net-snmp was given.
-if test "${with_net_snmp+set}" = set; then :
+if test ${with_net_snmp+y}
+then :
withval=$with_net_snmp; with_net_snmp=$withval
-else
- with_net_snmp=auto
+else $as_nop
+ with_net_snmp=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_net_snmp" >&5
-$as_echo "$with_net_snmp" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_net_snmp" >&5
+printf "%s\n" "$with_net_snmp" >&6; }
- if test "x$with_net_snmp" != "xno"; then :
+ if test "x$with_net_snmp" != "xno"
+then :
- if test "x$with_net_snmp" = "xyes" -o "x$with_net_snmp" = "xauto"; then :
+ if test "x$with_net_snmp" = "xyes" -o "x$with_net_snmp" = "xauto"
+then :
# Extract the first word of "net-snmp-config", so it can be a program name with args.
set dummy net-snmp-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_NET_SNMP_LIBS+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_NET_SNMP_LIBS+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$NET_SNMP_LIBS"; then
ac_cv_prog_NET_SNMP_LIBS="$NET_SNMP_LIBS" # Let the user override the test.
else
@@ -19234,11 +20747,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_NET_SNMP_LIBS="`net-snmp-config --netsnmp-agent-libs`"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -19249,15 +20766,15 @@ fi
fi
NET_SNMP_LIBS=$ac_cv_prog_NET_SNMP_LIBS
if test -n "$NET_SNMP_LIBS"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NET_SNMP_LIBS" >&5
-$as_echo "$NET_SNMP_LIBS" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NET_SNMP_LIBS" >&5
+printf "%s\n" "$NET_SNMP_LIBS" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
- ac_fn_cxx_check_decl "$LINENO" "snmp_select_info2" "ac_cv_have_decl_snmp_select_info2" "$ac_includes_default
+ ac_fn_check_decl "$LINENO" "snmp_select_info2" "ac_cv_have_decl_snmp_select_info2" "$ac_includes_default
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/definitions.h>
#include <net-snmp/types.h>
@@ -19265,23 +20782,22 @@ fi
#include <net-snmp/config_api.h>
#include <net-snmp/session_api.h>
-"
-if test "x$ac_cv_have_decl_snmp_select_info2" = xyes; then :
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_snmp_select_info2" = xyes
+then :
ac_have_decl=1
-else
+else $as_nop
ac_have_decl=0
fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_SNMP_SELECT_INFO2 $ac_have_decl
-_ACEOF
-if test $ac_have_decl = 1; then :
+printf "%s\n" "#define HAVE_DECL_SNMP_SELECT_INFO2 $ac_have_decl" >>confdefs.h
+if test $ac_have_decl = 1
+then :
-$as_echo "#define HAVE_SNMP_SELECT_INFO2 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SNMP_SELECT_INFO2 1" >>confdefs.h
-else
+else $as_nop
:
fi
@@ -19289,9 +20805,11 @@ fi
fi
fi
- if test "x$with_net_snmp" = "xyes"; then :
+ if test "x$with_net_snmp" = "xyes"
+then :
- if test x"$NET_SNMP_LIBS" = "x"; then :
+ if test x"$NET_SNMP_LIBS" = "x"
+then :
as_fn_error $? "Net SNMP requested but libraries were not found" "$LINENO" 5
@@ -19306,44 +20824,48 @@ else
HAVE_NET_SNMP_FALSE=
fi
- if test x"$NET_SNMP_LIBS" != "x"; then :
+ if test x"$NET_SNMP_LIBS" != "x"
+then :
-$as_echo "#define HAVE_NET_SNMP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_NET_SNMP 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libcap" >&5
-$as_echo_n "checking whether we will be linking in libcap... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libcap" >&5
+printf %s "checking whether we will be linking in libcap... " >&6; }
HAVE_LIBCAPS=0
# Check whether --with-libcap was given.
-if test "${with_libcap+set}" = set; then :
+if test ${with_libcap+y}
+then :
withval=$with_libcap; with_libcap=$withval
-else
+else $as_nop
with_libcap=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libcap" >&5
-$as_echo "$with_libcap" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libcap" >&5
+printf "%s\n" "$with_libcap" >&6; }
- if test "x$with_libcap" != "xno"; then :
+ if test "x$with_libcap" != "xno"
+then :
- if test "x$with_libcap" = "xyes" -o "x$with_libcap" = "xauto"; then :
+ if test "x$with_libcap" = "xyes" -o "x$with_libcap" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBCAP" >&5
-$as_echo_n "checking for LIBCAP... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libcap " >&5
+printf %s "checking for libcap ... " >&6; }
if test -n "$LIBCAP_CFLAGS"; then
pkg_cv_LIBCAP_CFLAGS="$LIBCAP_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap \""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap \""; } >&5
($PKG_CONFIG --exists --print-errors "libcap ") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBCAP_CFLAGS=`$PKG_CONFIG --cflags "libcap " 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -19357,10 +20879,10 @@ if test -n "$LIBCAP_LIBS"; then
pkg_cv_LIBCAP_LIBS="$LIBCAP_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap \""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcap \""; } >&5
($PKG_CONFIG --exists --print-errors "libcap ") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBCAP_LIBS=`$PKG_CONFIG --libs "libcap " 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -19374,8 +20896,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -19383,27 +20905,27 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBCAP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcap " 2>&1`
+ LIBCAP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcap " 2>&1`
else
- LIBCAP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcap " 2>&1`
+ LIBCAP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcap " 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBCAP_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBCAP_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBCAP_CFLAGS=$pkg_cv_LIBCAP_CFLAGS
- LIBCAP_LIBS=$pkg_cv_LIBCAP_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBCAP_CFLAGS=$pkg_cv_LIBCAP_CFLAGS
+ LIBCAP_LIBS=$pkg_cv_LIBCAP_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_LIBCAP=1
-$as_echo "#define HAVE_LIBCAP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBCAP 1" >>confdefs.h
fi
@@ -19419,9 +20941,11 @@ else
HAVE_LIBCAP_FALSE=
fi
- if test "x$with_libcap" = "xyes"; then :
+ if test "x$with_libcap" = "xyes"
+then :
- if test x"$LIBCAP_LIBS" = "x"; then :
+ if test x"$LIBCAP_LIBS" = "x"
+then :
as_fn_error $? "libcap requested but libraries were not found" "$LINENO" 5
@@ -19434,20 +20958,24 @@ fi
# Check whether --enable-systemd was given.
-if test "${enable_systemd+set}" = set; then :
+if test ${enable_systemd+y}
+then :
enableval=$enable_systemd;
fi
-if test "x$enable_systemd" = "xno"; then :
+if test "x$enable_systemd" = "xno"
+then :
ax_cv_systemd="n"
-elif test "x$enable_systemd" = "xyes"; then :
+elif test "x$enable_systemd" = "xyes"
+then :
ax_cv_systemd="y"
-elif test -z $ax_cv_systemd; then :
+elif test -z $ax_cv_systemd
+then :
ax_cv_systemd="n"
@@ -19458,9 +20986,10 @@ systemd=$ax_cv_systemd
# Check whether --with-systemd was given.
-if test "${with_systemd+set}" = set; then :
+if test ${with_systemd+y}
+then :
withval=$with_systemd; SYSTEMD_DIR="$withval"
-else
+else $as_nop
SYSTEMD_DIR=""
fi
@@ -19468,9 +20997,10 @@ fi
# Check whether --with-systemd was given.
-if test "${with_systemd+set}" = set; then :
+if test ${with_systemd+y}
+then :
withval=$with_systemd; SYSTEMD_MODULES_LOAD="$withval"
-else
+else $as_nop
SYSTEMD_MODULES_LOAD=""
fi
@@ -19478,49 +21008,49 @@ fi
- ac_fn_cxx_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default"
-if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then :
+ ac_fn_cxx_check_header_compile "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default"
+if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes
+then :
for libname in systemd-daemon systemd; do
- as_ac_Lib=`$as_echo "ac_cv_lib_$libname''_sd_listen_fds" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sd_listen_fds in -l$libname" >&5
-$as_echo_n "checking for sd_listen_fds in -l$libname... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ as_ac_Lib=`printf "%s\n" "ac_cv_lib_$libname""_sd_listen_fds" | $as_tr_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
LIBS="-l$libname $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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sd_listen_fds ();
+namespace conftest {
+ extern "C" int sd_listen_fds ();
+}
int
-main ()
+main (void)
{
-return sd_listen_fds ();
+return conftest::sd_listen_fds ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
eval "$as_ac_Lib=yes"
-else
+else $as_nop
eval "$as_ac_Lib=no"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
eval ac_res=\$$as_ac_Lib
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"
+then :
libsystemd_daemon="lib$libname"
systemd=y
@@ -19534,18 +21064,20 @@ fi
+ if test "x$enable_systemd" != "xno"
+then :
- if test "x$enable_systemd" != "xno"; then :
+ if test "x$systemd" = "xy"
+then :
- if test "x$systemd" = "xy" ; then :
-
-$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SYSTEMD 1" >>confdefs.h
systemd=y
- if test "x$libsystemd" = x; then :
+ if test "x$libsystemd" = x
+then :
as_fn_error $? "Unable to find a suitable libsystemd library" "$LINENO" 5
@@ -19553,17 +21085,17 @@ fi
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
-$as_echo_n "checking for SYSTEMD... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $libsystemd_daemon" >&5
+printf %s "checking for $libsystemd_daemon... " >&6; }
if test -n "$SYSTEMD_CFLAGS"; then
pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "$libsystemd_daemon" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -19577,10 +21109,10 @@ if test -n "$SYSTEMD_LIBS"; then
pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "$libsystemd_daemon" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -19594,8 +21126,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -19603,14 +21135,14 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
+ SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
else
- SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
+ SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$SYSTEMD_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$SYSTEMD_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements ($libsystemd_daemon) were not met:
+ as_fn_error $? "Package requirements ($libsystemd_daemon) were not met:
$SYSTEMD_PKG_ERRORS
@@ -19621,10 +21153,10 @@ Alternatively, you may set the environment variables SYSTEMD_CFLAGS
and SYSTEMD_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { 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;}
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.
@@ -19636,59 +21168,65 @@ See the pkg-config man page for more details.
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
See \`config.log' for more details" "$LINENO" 5; }
else
- SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
- SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
+ SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
fi
- if test "x$SYSTEMD_DIR" = x; then :
+ if test "x$SYSTEMD_DIR" = x
+then :
SYSTEMD_DIR="\$(prefix)/lib/systemd/system/"
fi
- if test "x$SYSTEMD_DIR" = x; then :
+ if test "x$SYSTEMD_DIR" = x
+then :
as_fn_error $? "SYSTEMD_DIR is unset" "$LINENO" 5
fi
- if test "x$SYSTEMD_MODULES_LOAD" = x; then :
+ if test "x$SYSTEMD_MODULES_LOAD" = x
+then :
SYSTEMD_MODULES_LOAD="\$(prefix)/lib/modules-load.d/"
fi
- if test "x$SYSTEMD_MODULES_LOAD" = x; then :
+ if test "x$SYSTEMD_MODULES_LOAD" = x
+then :
as_fn_error $? "SYSTEMD_MODULES_LOAD is unset" "$LINENO" 5
fi
-else
+else $as_nop
systemd=n
fi
-else
+else $as_nop
systemd=n
fi
- if test x"$systemd" = "xy"; then :
+ if test x"$systemd" = "xy"
+then :
# Extract the first word of "systemctl", so it can be a program name with args.
set dummy systemctl; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SYSTEMCTL+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_SYSTEMCTL+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $SYSTEMCTL in
[\\/]* | ?:[\\/]*)
ac_cv_path_SYSTEMCTL="$SYSTEMCTL" # Let the user override the test with a path.
@@ -19698,11 +21236,15 @@ else
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_SYSTEMCTL="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_SYSTEMCTL="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -19715,17 +21257,18 @@ esac
fi
SYSTEMCTL=$ac_cv_path_SYSTEMCTL
if test -n "$SYSTEMCTL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYSTEMCTL" >&5
-$as_echo "$SYSTEMCTL" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SYSTEMCTL" >&5
+printf "%s\n" "$SYSTEMCTL" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
- if test "$SYSTEMCTL" = "no"; then :
+ if test "$SYSTEMCTL" = "no"
+then :
as_fn_error $? "systemctl not found" "$LINENO" 5
-else
+else $as_nop
_systemd_version=`${SYSTEMCTL} --version|head -1 |cut -d" " -f 2`
if test $_systemd_version -ge 183; then
@@ -20022,14 +21565,15 @@ else
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking What user and group will be used by service" >&5
-$as_echo_n "checking What user and group will be used by service... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking What user and group will be used by service" >&5
+printf %s "checking What user and group will be used by service... " >&6; }
# Check whether --with-service-user was given.
-if test "${with_service_user+set}" = set; then :
+if test ${with_service_user+y}
+then :
withval=$with_service_user; service_user=$withval
-else
+else $as_nop
service_user=dnsdist
@@ -20038,38 +21582,39 @@ fi
# Check whether --with-service-group was given.
-if test "${with_service_group+set}" = set; then :
+if test ${with_service_group+y}
+then :
withval=$with_service_group; service_group=$withval
-else
+else $as_nop
service_group=dnsdist
fi
- if test -z "$service_user"; then :
+ if test -z "$service_user"
+then :
as_fn_error $? "No service user has been defined!" "$LINENO" 5
-else
+else $as_nop
:
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $service_user" >&5
-$as_echo "$service_user" >&6; }
-
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $service_user" >&5
+printf "%s\n" "$service_user" >&6; }
-
-
- for ac_func in $ac_func_list
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-fi
+ac_func=
+for ac_item in $ac_func_cxx_list
+do
+ if test $ac_func; then
+ ac_fn_cxx_check_func "$LINENO" $ac_func ac_cv_func_$ac_func
+ if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then
+ echo "#define $ac_item 1" >> confdefs.h
+ fi
+ ac_func=
+ else
+ ac_func=$ac_item
+ fi
done
@@ -20087,13 +21632,24 @@ IPCRYPT_CFLAGS='-I$(top_srcdir)/ext/ipcrypt'
IPCRYPT_LIBS='$(top_builddir)/ext/ipcrypt/libipcrypt.la'
+ARC4RANDOM_LIBS='$(top_builddir)/ext/arc4random/libarc4random.la'
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ac_fn_cxx_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_random_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h
+
+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
ac_path_GREP_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
@@ -20101,10 +21657,15 @@ else
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in grep ggrep; do
+ 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"
+ 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
@@ -20113,13 +21674,13 @@ case `"$ac_path_GREP" --version 2>&1` in
ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
+ printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
- $as_echo 'GREP' >> "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
@@ -20147,35 +21708,38 @@ else
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
+{ 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"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking which Lua implementation to use" >&5
-$as_echo_n "checking which Lua implementation to use... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which Lua implementation to use" >&5
+printf %s "checking which Lua implementation to use... " >&6; }
# Check whether --with-lua was given.
-if test "${with_lua+set}" = set; then :
+if test ${with_lua+y}
+then :
withval=$with_lua;
with_lua=$withval
-else
+else $as_nop
with_lua=auto
fi
- if test "x$with_lua" = "xyes"; then :
+ if test "x$with_lua" = "xyes"
+then :
with_lua=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lua" >&5
-$as_echo "$with_lua" >&6; }
+ { 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"; then :
+ if test "x$with_lua" = "xno" -a "mandatory" = "mandatory"
+then :
as_fn_error $? "--without-lua specified, but Lua is not optional" "$LINENO" 5
@@ -20185,27 +21749,30 @@ fi
luajit_min_version='2.0.2'
lua_min_version='5.1'
- if test "x$with_lua" != "xno"; then :
+ if test "x$with_lua" != "xno"
+then :
- 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; then :
+ if echo "x$with_lua" | ${GREP} 'jit' >/dev/null 2>&1
+then :
with_lua_version=${luajit_min_version}
fi
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $with_lua >= $with_lua_version" >&5
+printf %s "checking for $with_lua >= $with_lua_version... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$with_lua >= \$with_lua_version\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$with_lua >= \$with_lua_version\""; } >&5
($PKG_CONFIG --exists --print-errors "$with_lua >= $with_lua_version") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$with_lua >= $with_lua_version" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20219,10 +21786,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$with_lua >= \$with_lua_version\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$with_lua >= \$with_lua_version\""; } >&5
($PKG_CONFIG --exists --print-errors "$with_lua >= $with_lua_version") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$with_lua >= $with_lua_version" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20236,8 +21803,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20245,50 +21812,50 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$with_lua >= $with_lua_version" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$with_lua >= $with_lua_version" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$with_lua >= $with_lua_version" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$with_lua >= $with_lua_version" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
as_fn_error $? "Selected Lua ($with_lua) not found" "$LINENO" 5
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { 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
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
LUAPC=$with_lua
fi
-else
+else $as_nop
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for luajit >= ${luajit_min_version}" >&5
+printf %s "checking for luajit >= ${luajit_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit >= \${luajit_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit >= \${luajit_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "luajit >= ${luajit_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "luajit >= ${luajit_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20302,10 +21869,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit >= \${luajit_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit >= \${luajit_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "luajit >= ${luajit_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "luajit >= ${luajit_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20319,8 +21886,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20328,49 +21895,51 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit >= ${luajit_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit >= ${luajit_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit >= ${luajit_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit >= ${luajit_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
LUAPC=luajit
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
fi
- if test -z "$LUAPC"; then :
+ if test -z "$LUAPC"
+then :
found_lua=n
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua5.3 >= ${lua_min_version}" >&5
+printf %s "checking for lua5.3 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.3 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.3 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.3 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua5.3 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20384,10 +21953,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.3 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.3 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.3 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua5.3 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20401,8 +21970,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20410,26 +21979,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.3 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.3 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.3 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.3 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua5.3
@@ -20438,21 +22007,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua-5.3 >= ${lua_min_version}" >&5
+printf %s "checking for lua-5.3 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.3 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.3 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.3 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua-5.3 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20466,10 +22036,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.3 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.3 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.3 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua-5.3 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20483,8 +22053,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20492,26 +22062,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.3 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.3 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.3 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.3 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua-5.3
@@ -20520,21 +22090,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua53 >= ${lua_min_version}" >&5
+printf %s "checking for lua53 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua53 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua53 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua53 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua53 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20548,10 +22119,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua53 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua53 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua53 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua53 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20565,8 +22136,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20574,26 +22145,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua53 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua53 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua53 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua53 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua53
@@ -20602,21 +22173,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua5.2 >= ${lua_min_version}" >&5
+printf %s "checking for lua5.2 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.2 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.2 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.2 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua5.2 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20630,10 +22202,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.2 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.2 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.2 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua5.2 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20647,8 +22219,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20656,26 +22228,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.2 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.2 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.2 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.2 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua5.2
@@ -20684,21 +22256,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua-5.2 >= ${lua_min_version}" >&5
+printf %s "checking for lua-5.2 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.2 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.2 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.2 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua-5.2 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20712,10 +22285,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.2 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.2 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.2 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua-5.2 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20729,8 +22302,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20738,26 +22311,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.2 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.2 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.2 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.2 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua-5.2
@@ -20766,21 +22339,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua52 >= ${lua_min_version}" >&5
+printf %s "checking for lua52 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua52 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua52 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua52 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua52 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20794,10 +22368,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua52 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua52 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua52 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua52 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20811,8 +22385,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20820,26 +22394,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua52 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua52 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua52 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua52 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua52
@@ -20848,21 +22422,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua5.1 >= ${lua_min_version}" >&5
+printf %s "checking for lua5.1 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.1 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.1 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.1 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua5.1 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20876,10 +22451,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.1 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua5.1 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua5.1 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua5.1 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20893,8 +22468,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20902,26 +22477,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.1 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua5.1 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.1 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua5.1 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua5.1
@@ -20930,21 +22505,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua-5.1 >= ${lua_min_version}" >&5
+printf %s "checking for lua-5.1 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.1 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.1 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.1 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua-5.1 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20958,10 +22534,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.1 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua-5.1 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua-5.1 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua-5.1 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -20975,8 +22551,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -20984,26 +22560,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.1 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua-5.1 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.1 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua-5.1 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua-5.1
@@ -21012,21 +22588,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua51 >= ${lua_min_version}" >&5
+printf %s "checking for lua51 >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua51 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua51 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua51 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua51 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21040,10 +22617,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua51 >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua51 >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua51 >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua51 >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21057,8 +22634,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -21066,26 +22643,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua51 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua51 >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua51 >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua51 >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua51
@@ -21094,21 +22671,22 @@ fi
fi
- if test "$found_lua" != "y"; then :
+ if test "$found_lua" != "y"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
-$as_echo_n "checking for LUA... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lua >= ${lua_min_version}" >&5
+printf %s "checking for lua >= ${lua_min_version}... " >&6; }
if test -n "$LUA_CFLAGS"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21122,10 +22700,10 @@ if test -n "$LUA_LIBS"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua >= \${lua_min_version}\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lua >= \${lua_min_version}\""; } >&5
($PKG_CONFIG --exists --print-errors "lua >= ${lua_min_version}") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua >= ${lua_min_version}" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21139,8 +22717,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -21148,26 +22726,26 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lua >= ${lua_min_version}" 2>&1`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua >= ${lua_min_version}" 2>&1`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lua >= ${lua_min_version}" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LUA_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
- LUA_LIBS=$pkg_cv_LUA_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LUA 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LUA 1" >>confdefs.h
found_lua=y
LUAPC=lua
@@ -21183,7 +22761,8 @@ fi
fi
- if test -z "$LUAPC" -a "mandatory" = "mandatory"; then :
+ if test -z "$LUAPC" -a "mandatory" = "mandatory"
+then :
as_fn_error $? "No Lua not found, but is mandatory" "$LINENO" 5
@@ -21198,26 +22777,28 @@ else
fi
-if test "x$LUAPC" = "xluajit"; then :
+if test "x$LUAPC" = "xluajit"
+then :
# export all symbols with default visibility, to be able to use the Lua FFI interface
- { $as_echo "$as_me:${as_lineno-$LINENO}: Adding -rdynamic to export all symbols for the Lua FFI interface" >&5
-$as_echo "$as_me: Adding -rdynamic to export all symbols for the Lua FFI interface" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Adding -rdynamic to export all symbols for the Lua FFI interface" >&5
+printf "%s\n" "$as_me: Adding -rdynamic to export all symbols for the Lua FFI interface" >&6;}
LDFLAGS="$LDFLAGS -rdynamic"
fi
- if test "x$LUAPC" != "x" ; then :
+ if test "x$LUAPC" != "x"
+then :
OLD_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $LUA_CFLAGS"
- ac_fn_cxx_check_header_mongrel "$LINENO" "lua.hpp" "ac_cv_header_lua_hpp" "$ac_includes_default"
-if test "x$ac_cv_header_lua_hpp" = xyes; then :
+ ac_fn_cxx_check_header_compile "$LINENO" "lua.hpp" "ac_cv_header_lua_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_lua_hpp" = xyes
+then :
have_lua_hpp=y
fi
-
CPPFLAGS="$OLD_CPPFLAGS"
fi
@@ -21232,6 +22813,14 @@ fi
if false; then
+ HAVE_CDB_TRUE=
+ HAVE_CDB_FALSE='#'
+else
+ HAVE_CDB_TRUE='#'
+ HAVE_CDB_FALSE=
+fi
+
+ if false; then
HAVE_GNUTLS_TRUE=
HAVE_GNUTLS_FALSE='#'
else
@@ -21240,6 +22829,14 @@ else
fi
if false; then
+ HAVE_LIBH2OEVLOOP_TRUE=
+ HAVE_LIBH2OEVLOOP_FALSE='#'
+else
+ HAVE_LIBH2OEVLOOP_TRUE='#'
+ HAVE_LIBH2OEVLOOP_FALSE=
+fi
+
+ if false; then
HAVE_LIBSSL_TRUE=
HAVE_LIBSSL_FALSE='#'
else
@@ -21256,11 +22853,11 @@ else
fi
if false; then
- HAVE_CDB_TRUE=
- HAVE_CDB_FALSE='#'
+ HAVE_NGHTTP2_TRUE=
+ HAVE_NGHTTP2_FALSE='#'
else
- HAVE_CDB_TRUE='#'
- HAVE_CDB_FALSE=
+ HAVE_NGHTTP2_TRUE='#'
+ HAVE_NGHTTP2_FALSE=
fi
@@ -21268,7 +22865,8 @@ fi
found=false
# Check whether --with-libcrypto was given.
-if test "${with_libcrypto+set}" = set; then :
+if test ${with_libcrypto+y}
+then :
withval=$with_libcrypto;
case "$withval" in
"" | y | ye | yes | n | no)
@@ -21278,18 +22876,19 @@ if test "${with_libcrypto+set}" = set; then :
;;
esac
-else
+else $as_nop
# 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
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_PKG_CONFIG+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$PKG_CONFIG"; then
ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
else
@@ -21297,11 +22896,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -21312,11 +22915,11 @@ fi
fi
PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
if test -n "$PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+printf "%s\n" "$PKG_CONFIG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -21325,11 +22928,12 @@ if test -z "$ac_cv_prog_PKG_CONFIG"; then
ac_ct_PKG_CONFIG=$PKG_CONFIG
# Extract the first word of "pkg-config", so it can be a program name with args.
set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+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
ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test.
else
@@ -21337,11 +22941,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -21352,11 +22960,11 @@ fi
fi
ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG
if test -n "$ac_ct_PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
-$as_echo "$ac_ct_PKG_CONFIG" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
+printf "%s\n" "$ac_ct_PKG_CONFIG" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_PKG_CONFIG" = x; then
@@ -21364,8 +22972,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
PKG_CONFIG=$ac_ct_PKG_CONFIG
@@ -21400,19 +23008,19 @@ fi
if ! $found; then
LIBCRYPTO_INCLUDES=
for ssldir in $ssldirs; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h in $ssldir" >&5
-$as_echo_n "checking for openssl/crypto.h in $ssldir... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h in $ssldir" >&5
+printf %s "checking for openssl/crypto.h in $ssldir... " >&6; }
if test -f "$ssldir/include/openssl/crypto.h"; then
LIBCRYPTO_INCLUDES="-I$ssldir/include"
LIBCRYPTO_LDFLAGS="-L$ssldir/lib"
LIBCRYPTO_LIBS="-lcrypto"
found=true
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
break
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
done
@@ -21422,15 +23030,15 @@ $as_echo "no" >&6; }
if $found; then
-$as_echo "#define HAVE_LIBCRYPTO 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBCRYPTO 1" >>confdefs.h
fi
# try the preprocessor and linker with our new flags,
# being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL's libcrypto works" >&5
-$as_echo_n "checking whether compiling and linking against OpenSSL's libcrypto works... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL's libcrypto works" >&5
+printf %s "checking whether compiling and linking against OpenSSL's libcrypto works... " >&6; }
echo "Trying link with LIBCRYPTO_LDFLAGS=$LIBCRYPTO_LDFLAGS;" \
"LIBCRYPTO_LIBS=$LIBCRYPTO_LIBS; LIBCRYPTO_INCLUDES=$LIBCRYPTO_INCLUDES" >&5
@@ -21444,52 +23052,84 @@ $as_echo_n "checking whether compiling and linking against OpenSSL's libcrypto w
/* end confdefs.h. */
#include <openssl/bn.h>
int
-main ()
+main (void)
{
BN_new()
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- for ac_func in RAND_bytes RAND_pseudo_bytes CRYPTO_memcmp OPENSSL_init_crypto EVP_MD_CTX_new EVP_MD_CTX_free RSA_get0_key
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ ac_fn_cxx_check_func "$LINENO" "RAND_bytes" "ac_cv_func_RAND_bytes"
+if test "x$ac_cv_func_RAND_bytes" = xyes
+then :
+ printf "%s\n" "#define HAVE_RAND_BYTES 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "RAND_pseudo_bytes" "ac_cv_func_RAND_pseudo_bytes"
+if test "x$ac_cv_func_RAND_pseudo_bytes" = xyes
+then :
+ printf "%s\n" "#define HAVE_RAND_PSEUDO_BYTES 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "CRYPTO_memcmp" "ac_cv_func_CRYPTO_memcmp"
+if test "x$ac_cv_func_CRYPTO_memcmp" = xyes
+then :
+ printf "%s\n" "#define HAVE_CRYPTO_MEMCMP 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "OPENSSL_init_crypto" "ac_cv_func_OPENSSL_init_crypto"
+if test "x$ac_cv_func_OPENSSL_init_crypto" = xyes
+then :
+ printf "%s\n" "#define HAVE_OPENSSL_INIT_CRYPTO 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "EVP_MD_CTX_new" "ac_cv_func_EVP_MD_CTX_new"
+if test "x$ac_cv_func_EVP_MD_CTX_new" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_NEW 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "EVP_MD_CTX_free" "ac_cv_func_EVP_MD_CTX_free"
+if test "x$ac_cv_func_EVP_MD_CTX_free" = xyes
+then :
+ printf "%s\n" "#define HAVE_EVP_MD_CTX_FREE 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "RSA_get0_key" "ac_cv_func_RSA_get0_key"
+if test "x$ac_cv_func_RSA_get0_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_RSA_GET0_KEY 1" >>confdefs.h
fi
-done
# you might be wondering why the stdarg.h and stddef.h includes,
# in which case please have a look at https://github.com/PowerDNS/pdns/issues/12926
# and weep, yelling at Red Hat
- ac_fn_cxx_check_decl "$LINENO" "EVP_PKEY_CTX_set1_scrypt_salt" "ac_cv_have_decl_EVP_PKEY_CTX_set1_scrypt_salt" "#include <stdarg.h>
+ ac_fn_check_decl "$LINENO" "EVP_PKEY_CTX_set1_scrypt_salt" "ac_cv_have_decl_EVP_PKEY_CTX_set1_scrypt_salt" "#include <stdarg.h>
#include <stddef.h>
#include <openssl/kdf.h>
-"
-if test "x$ac_cv_have_decl_EVP_PKEY_CTX_set1_scrypt_salt" = xyes; then :
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_EVP_PKEY_CTX_set1_scrypt_salt" = xyes
+then :
-$as_echo "#define HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT 1" >>confdefs.h
+printf "%s\n" "#define HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT 1" >>confdefs.h
fi
+else $as_nop
-else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CPPFLAGS="$save_CPPFLAGS"
LDFLAGS="$save_LDFLAGS"
@@ -21509,18 +23149,19 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable OpenSSL >= 3.0 TLS providers (experimental)" >&5
-$as_echo_n "checking whether to enable OpenSSL >= 3.0 TLS providers (experimental)... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable OpenSSL >= 3.0 TLS providers (experimental)" >&5
+printf %s "checking whether to enable OpenSSL >= 3.0 TLS providers (experimental)... " >&6; }
# Check whether --enable-tls-providers was given.
-if test "${enable_tls_providers+set}" = set; then :
+if test ${enable_tls_providers+y}
+then :
enableval=$enable_tls_providers; enable_tls_providers=$enableval
-else
+else $as_nop
enable_tls_providers=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tls_providers" >&5
-$as_echo "$enable_tls_providers" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_tls_providers" >&5
+printf "%s\n" "$enable_tls_providers" >&6; }
if test "x$enable_tls_providers" != "xno"; then
HAVE_TLS_PROVIDERS_TRUE=
HAVE_TLS_PROVIDERS_FALSE='#'
@@ -21532,17 +23173,17 @@ fi
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSSL" >&5
-$as_echo_n "checking for LIBSSL... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssl >= 3.0" >&5
+printf %s "checking for libssl >= 3.0... " >&6; }
if test -n "$LIBSSL_CFLAGS"; then
pkg_cv_LIBSSL_CFLAGS="$LIBSSL_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl >= 3.0\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl >= 3.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libssl >= 3.0") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSSL_CFLAGS=`$PKG_CONFIG --cflags "libssl >= 3.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21556,10 +23197,10 @@ if test -n "$LIBSSL_LIBS"; then
pkg_cv_LIBSSL_LIBS="$LIBSSL_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl >= 3.0\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl >= 3.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libssl >= 3.0") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSSL_LIBS=`$PKG_CONFIG --libs "libssl >= 3.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21573,8 +23214,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -21582,27 +23223,27 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libssl >= 3.0" 2>&1`
+ LIBSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libssl >= 3.0" 2>&1`
else
- LIBSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libssl >= 3.0" 2>&1`
+ LIBSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libssl >= 3.0" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBSSL_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBSSL_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBSSL_CFLAGS=$pkg_cv_LIBSSL_CFLAGS
- LIBSSL_LIBS=$pkg_cv_LIBSSL_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBSSL_CFLAGS=$pkg_cv_LIBSSL_CFLAGS
+ LIBSSL_LIBS=$pkg_cv_LIBSSL_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_LIBSSL_3_PLUS=1
-$as_echo "#define HAVE_LIBSSL_3_PLUS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBSSL_3_PLUS 1" >>confdefs.h
fi
@@ -21610,9 +23251,10 @@ fi
if test -z "$HAVE_TLS_PROVIDERS_TRUE"; then :
-$as_echo "#define HAVE_TLS_PROVIDERS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_TLS_PROVIDERS 1" >>confdefs.h
- if test "x$HAVE_LIBSSL_3_PLUS" != "x1"; then :
+ if test "x$HAVE_LIBSSL_3_PLUS" != "x1"
+then :
as_fn_error $? "TLS providers support requires OpenSSL >= 3.0" "$LINENO" 5
@@ -21622,18 +23264,19 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable DNS over TLS support" >&5
-$as_echo_n "checking whether to enable DNS over TLS support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable DNS over TLS support" >&5
+printf %s "checking whether to enable DNS over TLS support... " >&6; }
# Check whether --enable-dns-over-tls was given.
-if test "${enable_dns_over_tls+set}" = set; then :
+if test ${enable_dns_over_tls+y}
+then :
enableval=$enable_dns_over_tls; enable_dns_over_tls=$enableval
-else
+else $as_nop
enable_dns_over_tls=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_tls" >&5
-$as_echo "$enable_dns_over_tls" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_tls" >&5
+printf "%s\n" "$enable_dns_over_tls" >&6; }
if test "x$enable_dns_over_tls" != "xno"; then
HAVE_DNS_OVER_TLS_TRUE=
HAVE_DNS_OVER_TLS_FALSE='#'
@@ -21646,24 +23289,25 @@ fi
if test -z "$HAVE_DNS_OVER_TLS_TRUE"; then :
-$as_echo "#define HAVE_DNS_OVER_TLS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_DNS_OVER_TLS 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable incoming DNS over HTTPS (DoH) support" >&5
-$as_echo_n "checking whether to enable incoming DNS over HTTPS (DoH) support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable incoming DNS over HTTPS (DoH) support" >&5
+printf %s "checking whether to enable incoming DNS over HTTPS (DoH) support... " >&6; }
# Check whether --enable-dns-over-https was given.
-if test "${enable_dns_over_https+set}" = set; then :
+if test ${enable_dns_over_https+y}
+then :
enableval=$enable_dns_over_https; enable_dns_over_https=$enableval
-else
+else $as_nop
enable_dns_over_https=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_https" >&5
-$as_echo "$enable_dns_over_https" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_https" >&5
+printf "%s\n" "$enable_dns_over_https" >&6; }
if test "x$enable_dns_over_https" != "xno"; then
HAVE_DNS_OVER_HTTPS_TRUE=
HAVE_DNS_OVER_HTTPS_FALSE='#'
@@ -21676,46 +23320,112 @@ fi
if test -z "$HAVE_DNS_OVER_HTTPS_TRUE"; then :
-$as_echo "#define HAVE_DNS_OVER_HTTPS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_DNS_OVER_HTTPS 1" >>confdefs.h
fi
-if test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable incoming DNS over QUIC (DoQ) support" >&5
+printf %s "checking whether to enable incoming DNS over QUIC (DoQ) support... " >&6; }
+ # Check whether --enable-dns-over-quic was given.
+if test ${enable_dns_over_quic+y}
+then :
+ enableval=$enable_dns_over_quic; enable_dns_over_quic=$enableval
+else $as_nop
+ enable_dns_over_quic=no
+fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in OpenSSL libssl" >&5
-$as_echo_n "checking whether we will be linking in OpenSSL libssl... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_quic" >&5
+printf "%s\n" "$enable_dns_over_quic" >&6; }
+ if test "x$enable_dns_over_quic" != "xno"; then
+ HAVE_DNS_OVER_QUIC_TRUE=
+ HAVE_DNS_OVER_QUIC_FALSE='#'
+else
+ HAVE_DNS_OVER_QUIC_TRUE='#'
+ HAVE_DNS_OVER_QUIC_FALSE=
+fi
+
+
+ if test -z "$HAVE_DNS_OVER_QUIC_TRUE"; then :
+
+
+printf "%s\n" "#define HAVE_DNS_OVER_QUIC 1" >>confdefs.h
+
+
+fi
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable incoming DNS over HTTP3 (DoH3) support" >&5
+printf %s "checking whether to enable incoming DNS over HTTP3 (DoH3) support... " >&6; }
+ # Check whether --enable-dns-over-http3 was given.
+if test ${enable_dns_over_http3+y}
+then :
+ enableval=$enable_dns_over_http3; enable_dns_over_http3=$enableval
+else $as_nop
+ enable_dns_over_http3=no
+
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dns_over_http3" >&5
+printf "%s\n" "$enable_dns_over_http3" >&6; }
+ if test "x$enable_dns_over_http3" != "xno"; then
+ HAVE_DNS_OVER_HTTP3_TRUE=
+ HAVE_DNS_OVER_HTTP3_FALSE='#'
+else
+ HAVE_DNS_OVER_HTTP3_TRUE='#'
+ HAVE_DNS_OVER_HTTP3_FALSE=
+fi
+
+
+ if test -z "$HAVE_DNS_OVER_HTTP3_TRUE"; then :
+
+
+printf "%s\n" "#define HAVE_DNS_OVER_HTTP3 1" >>confdefs.h
+
+
+fi
+
+
+if test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno" -o "x$enable_dns_over_quic" != "xno"
+then :
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in OpenSSL libssl" >&5
+printf %s "checking whether we will be linking in OpenSSL libssl... " >&6; }
HAVE_LIBSSL=0
# Check whether --with-libssl was given.
-if test "${with_libssl+set}" = set; then :
+if test ${with_libssl+y}
+then :
withval=$with_libssl; with_libssl=$withval
-else
+else $as_nop
with_libssl=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_libssl" >&5
-$as_echo "$with_libssl" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libssl" >&5
+printf "%s\n" "$with_libssl" >&6; }
- if test "x$with_libssl" != "xno"; then :
+ if test "x$with_libssl" != "xno"
+then :
- if test "x$with_libssl" = "xyes" -o "x$with_libssl" = "xauto"; then :
+ if test "x$with_libssl" = "xyes" -o "x$with_libssl" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSSL" >&5
-$as_echo_n "checking for LIBSSL... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssl" >&5
+printf %s "checking for libssl... " >&6; }
if test -n "$LIBSSL_CFLAGS"; then
pkg_cv_LIBSSL_CFLAGS="$LIBSSL_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl\""; } >&5
($PKG_CONFIG --exists --print-errors "libssl") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSSL_CFLAGS=`$PKG_CONFIG --cflags "libssl" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21729,10 +23439,10 @@ if test -n "$LIBSSL_LIBS"; then
pkg_cv_LIBSSL_LIBS="$LIBSSL_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libssl\""; } >&5
($PKG_CONFIG --exists --print-errors "libssl") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBSSL_LIBS=`$PKG_CONFIG --libs "libssl" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21746,8 +23456,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -21755,43 +23465,110 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libssl" 2>&1`
+ LIBSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libssl" 2>&1`
else
- LIBSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libssl" 2>&1`
+ LIBSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libssl" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBSSL_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBSSL_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBSSL_CFLAGS=$pkg_cv_LIBSSL_CFLAGS
- LIBSSL_LIBS=$pkg_cv_LIBSSL_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBSSL_CFLAGS=$pkg_cv_LIBSSL_CFLAGS
+ LIBSSL_LIBS=$pkg_cv_LIBSSL_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_LIBSSL=1
-$as_echo "#define HAVE_LIBSSL 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBSSL 1" >>confdefs.h
save_CFLAGS=$CFLAGS
save_LIBS=$LIBS
CFLAGS="$LIBSSL_CFLAGS $CFLAGS"
LIBS="$LIBSSL_LIBS -lcrypto $LIBS"
- for ac_func in SSL_CTX_set_ciphersuites OCSP_basic_sign SSL_CTX_set_num_tickets SSL_CTX_set_keylog_callback SSL_CTX_get0_privatekey SSL_CTX_set_min_proto_version 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
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_ciphersuites" "ac_cv_func_SSL_CTX_set_ciphersuites"
+if test "x$ac_cv_func_SSL_CTX_set_ciphersuites" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_CIPHERSUITES 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "OCSP_basic_sign" "ac_cv_func_OCSP_basic_sign"
+if test "x$ac_cv_func_OCSP_basic_sign" = xyes
+then :
+ printf "%s\n" "#define HAVE_OCSP_BASIC_SIGN 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_num_tickets" "ac_cv_func_SSL_CTX_set_num_tickets"
+if test "x$ac_cv_func_SSL_CTX_set_num_tickets" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_NUM_TICKETS 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_keylog_callback" "ac_cv_func_SSL_CTX_set_keylog_callback"
+if test "x$ac_cv_func_SSL_CTX_set_keylog_callback" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_KEYLOG_CALLBACK 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_get0_privatekey" "ac_cv_func_SSL_CTX_get0_privatekey"
+if test "x$ac_cv_func_SSL_CTX_get0_privatekey" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_GET0_PRIVATEKEY 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_min_proto_version" "ac_cv_func_SSL_CTX_set_min_proto_version"
+if test "x$ac_cv_func_SSL_CTX_set_min_proto_version" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_MIN_PROTO_VERSION 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_set_hostflags" "ac_cv_func_SSL_set_hostflags"
+if test "x$ac_cv_func_SSL_set_hostflags" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_SET_HOSTFLAGS 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_alpn_protos" "ac_cv_func_SSL_CTX_set_alpn_protos"
+if test "x$ac_cv_func_SSL_CTX_set_alpn_protos" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_ALPN_PROTOS 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_next_proto_select_cb" "ac_cv_func_SSL_CTX_set_next_proto_select_cb"
+if test "x$ac_cv_func_SSL_CTX_set_next_proto_select_cb" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_get0_alpn_selected" "ac_cv_func_SSL_get0_alpn_selected"
+if test "x$ac_cv_func_SSL_get0_alpn_selected" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_GET0_ALPN_SELECTED 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_get0_next_proto_negotiated" "ac_cv_func_SSL_get0_next_proto_negotiated"
+if test "x$ac_cv_func_SSL_get0_next_proto_negotiated" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_GET0_NEXT_PROTO_NEGOTIATED 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_set_alpn_select_cb" "ac_cv_func_SSL_CTX_set_alpn_select_cb"
+if test "x$ac_cv_func_SSL_CTX_set_alpn_select_cb" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_ALPN_SELECT_CB 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "SSL_CTX_use_cert_and_key" "ac_cv_func_SSL_CTX_use_cert_and_key"
+if test "x$ac_cv_func_SSL_CTX_use_cert_and_key" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_USE_CERT_AND_KEY 1" >>confdefs.h
fi
-done
CFLAGS=$save_CFLAGS
LIBS=$save_LIBS
@@ -21810,9 +23587,11 @@ else
HAVE_LIBSSL_FALSE=
fi
- if test "x$with_libssl" = "xyes"; then :
+ if test "x$with_libssl" = "xyes"
+then :
- if test x"$LIBSSL_LIBS" = "x"; then :
+ if test x"$LIBSSL_LIBS" = "x"
+then :
as_fn_error $? "OpenSSL libssl requested but libraries were not found" "$LINENO" 5
@@ -21820,44 +23599,45 @@ fi
fi
-
-fi
-
-if test "x$enable_dns_over_tls" != "xno"; then :
+ if test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in GnuTLS" >&5
-$as_echo_n "checking whether we will be linking in GnuTLS... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in GnuTLS" >&5
+printf %s "checking whether we will be linking in GnuTLS... " >&6; }
HAVE_GNUTLS=0
# Check whether --with-gnutls was given.
-if test "${with_gnutls+set}" = set; then :
+if test ${with_gnutls+y}
+then :
withval=$with_gnutls; with_gnutls=$withval
-else
+else $as_nop
with_gnutls=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_gnutls" >&5
-$as_echo "$with_gnutls" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_gnutls" >&5
+printf "%s\n" "$with_gnutls" >&6; }
- if test "x$with_gnutls" != "xno"; then :
+ if test "x$with_gnutls" != "xno"
+then :
- if test "x$with_gnutls" = "xyes" -o "x$with_gnutls" = "xauto"; then :
+ if test "x$with_gnutls" = "xyes" -o "x$with_gnutls" = "xauto"
+then :
# we require gnutls_certificate_set_x509_key_file, added in 3.1.11
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNUTLS" >&5
-$as_echo_n "checking for GNUTLS... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnutls >= 3.1.11" >&5
+printf %s "checking for gnutls >= 3.1.11... " >&6; }
if test -n "$GNUTLS_CFLAGS"; then
pkg_cv_GNUTLS_CFLAGS="$GNUTLS_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.1.11\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.1.11\""; } >&5
($PKG_CONFIG --exists --print-errors "gnutls >= 3.1.11") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GNUTLS_CFLAGS=`$PKG_CONFIG --cflags "gnutls >= 3.1.11" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21871,10 +23651,10 @@ if test -n "$GNUTLS_LIBS"; then
pkg_cv_GNUTLS_LIBS="$GNUTLS_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.1.11\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnutls >= 3.1.11\""; } >&5
($PKG_CONFIG --exists --print-errors "gnutls >= 3.1.11") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GNUTLS_LIBS=`$PKG_CONFIG --libs "gnutls >= 3.1.11" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -21888,8 +23668,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -21897,43 +23677,56 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- GNUTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls >= 3.1.11" 2>&1`
+ GNUTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnutls >= 3.1.11" 2>&1`
else
- GNUTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls >= 3.1.11" 2>&1`
+ GNUTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnutls >= 3.1.11" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$GNUTLS_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$GNUTLS_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- GNUTLS_CFLAGS=$pkg_cv_GNUTLS_CFLAGS
- GNUTLS_LIBS=$pkg_cv_GNUTLS_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ GNUTLS_CFLAGS=$pkg_cv_GNUTLS_CFLAGS
+ GNUTLS_LIBS=$pkg_cv_GNUTLS_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_GNUTLS=1
-$as_echo "#define HAVE_GNUTLS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_GNUTLS 1" >>confdefs.h
save_CFLAGS=$CFLAGS
save_LIBS=$LIBS
CFLAGS="$GNUTLS_CFLAGS $CFLAGS"
LIBS="$GNUTLS_LIBS $LIBS"
- for ac_func in gnutls_memset gnutls_session_set_verify_cert gnutls_session_get_verify_cert_status gnutls_alpn_set_protocols
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "gnutls_memset" "ac_cv_func_gnutls_memset"
+if test "x$ac_cv_func_gnutls_memset" = xyes
+then :
+ printf "%s\n" "#define HAVE_GNUTLS_MEMSET 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "gnutls_session_set_verify_cert" "ac_cv_func_gnutls_session_set_verify_cert"
+if test "x$ac_cv_func_gnutls_session_set_verify_cert" = xyes
+then :
+ printf "%s\n" "#define HAVE_GNUTLS_SESSION_SET_VERIFY_CERT 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "gnutls_session_get_verify_cert_status" "ac_cv_func_gnutls_session_get_verify_cert_status"
+if test "x$ac_cv_func_gnutls_session_get_verify_cert_status" = xyes
+then :
+ printf "%s\n" "#define HAVE_GNUTLS_SESSION_GET_VERIFY_CERT_STATUS 1" >>confdefs.h
+
+fi
+ac_fn_cxx_check_func "$LINENO" "gnutls_alpn_set_protocols" "ac_cv_func_gnutls_alpn_set_protocols"
+if test "x$ac_cv_func_gnutls_alpn_set_protocols" = xyes
+then :
+ printf "%s\n" "#define HAVE_GNUTLS_ALPN_SET_PROTOCOLS 1" >>confdefs.h
fi
-done
CFLAGS=$save_CFLAGS
LIBS=$save_LIBS
@@ -21952,9 +23745,11 @@ else
HAVE_GNUTLS_FALSE=
fi
- if test "x$with_gnutls" = "xyes"; then :
+ if test "x$with_gnutls" = "xyes"
+then :
- if test x"$GNUTLS_LIBS" = "x"; then :
+ if test x"$GNUTLS_LIBS" = "x"
+then :
as_fn_error $? "GnuTLS requested but libraries were not found" "$LINENO" 5
@@ -21963,7 +23758,15 @@ fi
fi
- if test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"; then :
+fi
+
+fi
+
+if test "x$enable_dns_over_tls" != "xno"
+then :
+
+ if test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"
+then :
as_fn_error $? "DNS over TLS support requested but neither GnuTLS nor OpenSSL are available" "$LINENO" 5
@@ -21971,23 +23774,46 @@ fi
fi
+if test "x$enable_dns_over_https" != "xno"
+then :
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in nghttp2" >&5
+printf %s "checking whether we will be linking in nghttp2... " >&6; }
+ HAVE_NGHTTP2=0
+
+# Check whether --with-nghttp2 was given.
+if test ${with_nghttp2+y}
+then :
+ withval=$with_nghttp2; with_nghttp2=$withval
+else $as_nop
+ with_nghttp2=auto
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_nghttp2" >&5
+printf "%s\n" "$with_nghttp2" >&6; }
+
+ if test "x$with_nghttp2" != "xno"
+then :
+
+ if test "x$with_nghttp2" = "xyes" -o "x$with_nghttp2" = "xauto"
+then :
- HAVE_LIBH2OEVLOOP=0
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBH2OEVLOOP" >&5
-$as_echo_n "checking for LIBH2OEVLOOP... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnghttp2" >&5
+printf %s "checking for libnghttp2... " >&6; }
-if test -n "$LIBH2OEVLOOP_CFLAGS"; then
- pkg_cv_LIBH2OEVLOOP_CFLAGS="$LIBH2OEVLOOP_CFLAGS"
+if test -n "$NGHTTP2_CFLAGS"; then
+ pkg_cv_NGHTTP2_CFLAGS="$NGHTTP2_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libh2o-evloop\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libh2o-evloop") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnghttp2") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_LIBH2OEVLOOP_CFLAGS=`$PKG_CONFIG --cflags "libh2o-evloop" 2>/dev/null`
+ pkg_cv_NGHTTP2_CFLAGS=`$PKG_CONFIG --cflags "libnghttp2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -21995,16 +23821,16 @@ fi
else
pkg_failed=untried
fi
-if test -n "$LIBH2OEVLOOP_LIBS"; then
- pkg_cv_LIBH2OEVLOOP_LIBS="$LIBH2OEVLOOP_LIBS"
+if test -n "$NGHTTP2_LIBS"; then
+ pkg_cv_NGHTTP2_LIBS="$NGHTTP2_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libh2o-evloop\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libh2o-evloop") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnghttp2") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_LIBH2OEVLOOP_LIBS=`$PKG_CONFIG --libs "libh2o-evloop" 2>/dev/null`
+ pkg_cv_NGHTTP2_LIBS=`$PKG_CONFIG --libs "libnghttp2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -22016,8 +23842,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -22025,118 +23851,113 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBH2OEVLOOP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libh2o-evloop" 2>&1`
+ NGHTTP2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnghttp2" 2>&1`
else
- LIBH2OEVLOOP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libh2o-evloop" 2>&1`
+ NGHTTP2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnghttp2" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LIBH2OEVLOOP_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$NGHTTP2_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LIBH2OEVLOOP_CFLAGS=$pkg_cv_LIBH2OEVLOOP_CFLAGS
- LIBH2OEVLOOP_LIBS=$pkg_cv_LIBH2OEVLOOP_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ NGHTTP2_CFLAGS=$pkg_cv_NGHTTP2_CFLAGS
+ NGHTTP2_LIBS=$pkg_cv_NGHTTP2_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
- HAVE_LIBH2OEVLOOP=1
+ HAVE_NGHTTP2=1
-$as_echo "#define HAVE_LIBH2OEVLOOP 1" >>confdefs.h
+printf "%s\n" "#define HAVE_NGHTTP2 1" >>confdefs.h
- save_CFLAGS=$CFLAGS
- save_LIBS=$LIBS
- CFLAGS="$LIBH2OEVLOOP_CFLAGS $CFLAGS"
- LIBS="$LIBH2OEVLOOP_LIBS $LIBS"
- ac_fn_cxx_check_decl "$LINENO" "h2o_socket_get_ssl_server_name" "ac_cv_have_decl_h2o_socket_get_ssl_server_name" "$ac_includes_default
- #include <h2o/socket.h>
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$NGHTTP2_CFLAGS $CFLAGS"
+ LIBS="$NGHTTP2_LIBS $LIBS"
+ ac_fn_cxx_check_func "$LINENO" "nghttp2_check_header_value_rfc9113" "ac_cv_func_nghttp2_check_header_value_rfc9113"
+if test "x$ac_cv_func_nghttp2_check_header_value_rfc9113" = xyes
+then :
+ printf "%s\n" "#define HAVE_NGHTTP2_CHECK_HEADER_VALUE_RFC9113 1" >>confdefs.h
-"
-if test "x$ac_cv_have_decl_h2o_socket_get_ssl_server_name" = xyes; then :
- ac_have_decl=1
-else
- ac_have_decl=0
fi
+ac_fn_cxx_check_func "$LINENO" "nghttp2_check_method" "ac_cv_func_nghttp2_check_method"
+if test "x$ac_cv_func_nghttp2_check_method" = xyes
+then :
+ printf "%s\n" "#define HAVE_NGHTTP2_CHECK_METHOD 1" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_H2O_SOCKET_GET_SSL_SERVER_NAME $ac_have_decl
-_ACEOF
-if test $ac_have_decl = 1; then :
-
+fi
+ac_fn_cxx_check_func "$LINENO" "nghttp2_check_path" "ac_cv_func_nghttp2_check_path"
+if test "x$ac_cv_func_nghttp2_check_path" = xyes
+then :
+ printf "%s\n" "#define HAVE_NGHTTP2_CHECK_PATH 1" >>confdefs.h
-$as_echo "#define HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME 1" >>confdefs.h
+fi
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
-else
- :
fi
- CFLAGS=$save_CFLAGS
- LIBS=$save_LIBS
+fi
fi
- if test "x$LIBH2OEVLOOP_LIBS" != "x"; then
- HAVE_LIBH2OEVLOOP_TRUE=
- HAVE_LIBH2OEVLOOP_FALSE='#'
+ if test "x$NGHTTP2_LIBS" != "x"; then
+ HAVE_NGHTTP2_TRUE=
+ HAVE_NGHTTP2_FALSE='#'
else
- HAVE_LIBH2OEVLOOP_TRUE='#'
- HAVE_LIBH2OEVLOOP_FALSE=
+ HAVE_NGHTTP2_TRUE='#'
+ HAVE_NGHTTP2_FALSE=
fi
+ if test "x$with_nghttp2" = "xyes"
+then :
-if test "x$enable_dns_over_https" != "xno"; then :
-
- if test "x$HAVE_LIBH2OEVLOOP" != "x1"; then :
+ if test x"$NGHTTP2_LIBS" = "x"
+then :
- as_fn_error $? "DNS over HTTPS support requested but libh2o-evloop was not found" "$LINENO" 5
-
-fi
-
- if test "x$HAVE_LIBSSL" != "x1"; then :
-
- as_fn_error $? "DNS over HTTPS support requested but OpenSSL was not found" "$LINENO" 5
+ as_fn_error $? "nghttp2 requested but libraries were not found" "$LINENO" 5
fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in nghttp2" >&5
-$as_echo_n "checking whether we will be linking in nghttp2... " >&6; }
- HAVE_NGHTTP2=0
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libh2o-evloop" >&5
+printf %s "checking whether we will be linking in libh2o-evloop... " >&6; }
+ HAVE_LIBH2OEVLOOP=0
-# Check whether --with-nghttp2 was given.
-if test "${with_nghttp2+set}" = set; then :
- withval=$with_nghttp2; with_nghttp2=$withval
-else
- with_nghttp2=auto
+# Check whether --with-h2o was given.
+if test ${with_h2o+y}
+then :
+ withval=$with_h2o; with_h2o=$withval
+else $as_nop
+ with_h2o=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_nghttp2" >&5
-$as_echo "$with_nghttp2" >&6; }
-
- if test "x$with_nghttp2" != "xno"; then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_h2o" >&5
+printf "%s\n" "$with_h2o" >&6; }
- if test "x$with_nghttp2" = "xyes" -o "x$with_nghttp2" = "xauto"; then :
+ if test "x$with_h2o" = "xyes" -o "x$with_h2o" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NGHTTP2" >&5
-$as_echo_n "checking for NGHTTP2... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libh2o-evloop" >&5
+printf %s "checking for libh2o-evloop... " >&6; }
-if test -n "$NGHTTP2_CFLAGS"; then
- pkg_cv_NGHTTP2_CFLAGS="$NGHTTP2_CFLAGS"
+if test -n "$LIBH2OEVLOOP_CFLAGS"; then
+ pkg_cv_LIBH2OEVLOOP_CFLAGS="$LIBH2OEVLOOP_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libnghttp2") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libh2o-evloop\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libh2o-evloop") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_NGHTTP2_CFLAGS=`$PKG_CONFIG --cflags "libnghttp2" 2>/dev/null`
+ pkg_cv_LIBH2OEVLOOP_CFLAGS=`$PKG_CONFIG --cflags "libh2o-evloop" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -22144,16 +23965,16 @@ fi
else
pkg_failed=untried
fi
-if test -n "$NGHTTP2_LIBS"; then
- pkg_cv_NGHTTP2_LIBS="$NGHTTP2_LIBS"
+if test -n "$LIBH2OEVLOOP_LIBS"; then
+ pkg_cv_LIBH2OEVLOOP_LIBS="$LIBH2OEVLOOP_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libnghttp2") 2>&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libh2o-evloop\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libh2o-evloop") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_NGHTTP2_LIBS=`$PKG_CONFIG --libs "libnghttp2" 2>/dev/null`
+ pkg_cv_LIBH2OEVLOOP_LIBS=`$PKG_CONFIG --libs "libh2o-evloop" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -22165,8 +23986,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -22174,86 +23995,171 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- NGHTTP2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnghttp2" 2>&1`
+ LIBH2OEVLOOP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libh2o-evloop" 2>&1`
else
- NGHTTP2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnghttp2" 2>&1`
+ LIBH2OEVLOOP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libh2o-evloop" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$NGHTTP2_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBH2OEVLOOP_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- NGHTTP2_CFLAGS=$pkg_cv_NGHTTP2_CFLAGS
- NGHTTP2_LIBS=$pkg_cv_NGHTTP2_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LIBH2OEVLOOP_CFLAGS=$pkg_cv_LIBH2OEVLOOP_CFLAGS
+ LIBH2OEVLOOP_LIBS=$pkg_cv_LIBH2OEVLOOP_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
- HAVE_NGHTTP2=1
+ HAVE_LIBH2OEVLOOP=1
-$as_echo "#define HAVE_NGHTTP2 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBH2OEVLOOP 1" >>confdefs.h
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$LIBH2OEVLOOP_CFLAGS $CFLAGS"
+ LIBS="$LIBH2OEVLOOP_LIBS $LIBS"
+ ac_fn_check_decl "$LINENO" "h2o_socket_get_ssl_server_name" "ac_cv_have_decl_h2o_socket_get_ssl_server_name" "$ac_includes_default
+ #include <h2o/socket.h>
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl_h2o_socket_get_ssl_server_name" = xyes
+then :
+ ac_have_decl=1
+else $as_nop
+ ac_have_decl=0
fi
+printf "%s\n" "#define HAVE_DECL_H2O_SOCKET_GET_SSL_SERVER_NAME $ac_have_decl" >>confdefs.h
+if test $ac_have_decl = 1
+then :
+
+printf "%s\n" "#define HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME 1" >>confdefs.h
+
+
+else $as_nop
+ :
fi
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
+
fi
- if test "x$NGHTTP2_LIBS" != "x"; then
- HAVE_NGHTTP2_TRUE=
- HAVE_NGHTTP2_FALSE='#'
+
+fi
+ if test "x$LIBH2OEVLOOP_LIBS" != "x"; then
+ HAVE_LIBH2OEVLOOP_TRUE=
+ HAVE_LIBH2OEVLOOP_FALSE='#'
else
- HAVE_NGHTTP2_TRUE='#'
- HAVE_NGHTTP2_FALSE=
+ HAVE_LIBH2OEVLOOP_TRUE='#'
+ HAVE_LIBH2OEVLOOP_FALSE=
fi
- if test "x$with_nghttp2" = "xyes"; then :
+ if test -z "$HAVE_LIBH2OEVLOOP_TRUE"; then :
- if test x"$NGHTTP2_LIBS" = "x"; then :
- as_fn_error $? "nghttp2 requested but libraries were not found" "$LINENO" 5
+printf "%s\n" "#define HAVE_LIBH2OEVLOOP 1" >>confdefs.h
+
+
+fi
+
+ if test "x$with_h2o" = "xyes"
+then :
+
+ if test x"LIBH2OEVLOOP_LIBS" = "x"
+then :
+
+ as_fn_error $? "h2o-evloop requested but libraries were not found" "$LINENO" 5
+
+fi
+
+fi
+
+
+ if test "x$HAVE_LIBH2OEVLOOP" != "x1" -a "x$HAVE_NGHTTP2" != "x1"
+then :
+
+ as_fn_error $? "DNS over HTTPS support requested but neither libh2o-evloop nor nghttp2 was not found" "$LINENO" 5
+
+fi
+
+ if test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"
+then :
+
+ as_fn_error $? "DNS over HTTPS support requested but neither GnuTLS nor OpenSSL are available" "$LINENO" 5
+
+fi
+
+fi
+
+if test "x$enable_dns_over_quic" != "xno"
+then :
+
+ if test "x$HAVE_QUICHE" != "x1"
+then :
+
+ as_fn_error $? "DNS over QUIC support requested but quiche was not found" "$LINENO" 5
+
+fi
+ if test "x$HAVE_LIBSSL" != "x1"
+then :
+
+ as_fn_error $? "DNS over QUIC support requested but OpenSSL is not available" "$LINENO" 5
+
+fi
fi
+if test "x$enable_dns_over_http3" != "xno"
+then :
+
+ if test "x$HAVE_QUICHE" != "x1"
+then :
+
+ as_fn_error $? "DNS over HTTP/3 support requested but quiche was not found" "$LINENO" 5
+
fi
+fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will we liniking with libcdb" >&5
-$as_echo_n "checking whether we will we liniking with libcdb... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will we liniking with libcdb" >&5
+printf %s "checking whether we will we liniking with libcdb... " >&6; }
HAVE_CDB=0
# Check whether --with-cdb was given.
-if test "${with_cdb+set}" = set; then :
+if test ${with_cdb+y}
+then :
withval=$with_cdb; with_cdb=$withval
-else
+else $as_nop
with_cdb=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_cdb" >&5
-$as_echo "$with_cdb" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_cdb" >&5
+printf "%s\n" "$with_cdb" >&6; }
- if test "x$with_cdb" != "xno"; then :
+ if test "x$with_cdb" != "xno"
+then :
- if test "x$with_cdb" = "xyes" -o "x$with_cdb" = "xauto"; then :
+ if test "x$with_cdb" = "xyes" -o "x$with_cdb" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CDB" >&5
-$as_echo_n "checking for CDB... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libcdb" >&5
+printf %s "checking for libcdb... " >&6; }
if test -n "$CDB_CFLAGS"; then
pkg_cv_CDB_CFLAGS="$CDB_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
($PKG_CONFIG --exists --print-errors "libcdb") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_CDB_CFLAGS=`$PKG_CONFIG --cflags "libcdb" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -22267,10 +24173,10 @@ if test -n "$CDB_LIBS"; then
pkg_cv_CDB_LIBS="$CDB_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
($PKG_CONFIG --exists --print-errors "libcdb") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_CDB_LIBS=`$PKG_CONFIG --libs "libcdb" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -22284,8 +24190,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -22293,153 +24199,147 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- CDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcdb" 2>&1`
+ CDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcdb" 2>&1`
else
- CDB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcdb" 2>&1`
+ CDB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcdb" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$CDB_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$CDB_PKG_ERRORS" >&5
- for ac_header in cdb.h
+ for ac_header in cdb.h
do :
- ac_fn_cxx_check_header_mongrel "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
-if test "x$ac_cv_header_cdb_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_CDB_H 1
-_ACEOF
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
-$as_echo_n "checking for cdb_find in -lcdb... " >&6; }
-if ${ac_cv_lib_cdb_cdb_find+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ ac_fn_cxx_check_header_compile "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_cdb_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CDB_H 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
+printf %s "checking for cdb_find in -lcdb... " >&6; }
+if test ${ac_cv_lib_cdb_cdb_find+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lcdb $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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char cdb_find ();
+namespace conftest {
+ extern "C" int cdb_find ();
+}
int
-main ()
+main (void)
{
-return cdb_find ();
+return conftest::cdb_find ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_lib_cdb_cdb_find=yes
-else
+else $as_nop
ac_cv_lib_cdb_cdb_find=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
-$as_echo "$ac_cv_lib_cdb_cdb_find" >&6; }
-if test "x$ac_cv_lib_cdb_cdb_find" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
+printf "%s\n" "$ac_cv_lib_cdb_cdb_find" >&6; }
+if test "x$ac_cv_lib_cdb_cdb_find" = xyes
+then :
CDB_LIBS="-lcdb"
-$as_echo "#define HAVE_CDB 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CDB 1" >>confdefs.h
HAVE_CDB=1
-else
+else $as_nop
:
fi
-else
+else $as_nop
:
fi
done
-
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- for ac_header in cdb.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ for ac_header in cdb.h
do :
- ac_fn_cxx_check_header_mongrel "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
-if test "x$ac_cv_header_cdb_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_CDB_H 1
-_ACEOF
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
-$as_echo_n "checking for cdb_find in -lcdb... " >&6; }
-if ${ac_cv_lib_cdb_cdb_find+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ ac_fn_cxx_check_header_compile "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_cdb_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CDB_H 1" >>confdefs.h
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
+printf %s "checking for cdb_find in -lcdb... " >&6; }
+if test ${ac_cv_lib_cdb_cdb_find+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lcdb $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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char cdb_find ();
+namespace conftest {
+ extern "C" int cdb_find ();
+}
int
-main ()
+main (void)
{
-return cdb_find ();
+return conftest::cdb_find ();
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_lib_cdb_cdb_find=yes
-else
+else $as_nop
ac_cv_lib_cdb_cdb_find=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
-$as_echo "$ac_cv_lib_cdb_cdb_find" >&6; }
-if test "x$ac_cv_lib_cdb_cdb_find" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
+printf "%s\n" "$ac_cv_lib_cdb_cdb_find" >&6; }
+if test "x$ac_cv_lib_cdb_cdb_find" = xyes
+then :
CDB_LIBS="-lcdb"
-$as_echo "#define HAVE_CDB 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CDB 1" >>confdefs.h
HAVE_CDB=1
-else
+else $as_nop
:
fi
-else
+else $as_nop
:
fi
done
-
else
- CDB_CFLAGS=$pkg_cv_CDB_CFLAGS
- CDB_LIBS=$pkg_cv_CDB_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ CDB_CFLAGS=$pkg_cv_CDB_CFLAGS
+ CDB_LIBS=$pkg_cv_CDB_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
HAVE_CDB=1
-$as_echo "#define HAVE_CDB 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CDB 1" >>confdefs.h
fi
@@ -22457,9 +24357,11 @@ else
HAVE_CDB_FALSE=
fi
- if test "x$with_cdb" = "xyes"; then :
+ if test "x$with_cdb" = "xyes"
+then :
- if test x"$CDB_LIBS" = "x"; then :
+ if test x"$CDB_LIBS" = "x"
+then :
as_fn_error $? "CDB requested but libraries were not found" "$LINENO" 5
@@ -22468,40 +24370,43 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the lmdb library and headers" >&5
-$as_echo_n "checking where to find the lmdb library and headers... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the lmdb library and headers" >&5
+printf %s "checking where to find the lmdb library and headers... " >&6; }
# Check whether --with-lmdb was given.
-if test "${with_lmdb+set}" = set; then :
+if test ${with_lmdb+y}
+then :
withval=$with_lmdb;
with_lmdb=$withval
-else
+else $as_nop
with_lmdb=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lmdb" >&5
-$as_echo "$with_lmdb" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_lmdb" >&5
+printf "%s\n" "$with_lmdb" >&6; }
- if test "$with_lmdb" != "no"; then :
+ if test "$with_lmdb" != "no"
+then :
- if test "x$with_lmdb" = "xyes" -o "x$with_lmdb" = "xauto"; then :
+ if test "x$with_lmdb" = "xyes" -o "x$with_lmdb" = "xauto"
+then :
pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LMDB" >&5
-$as_echo_n "checking for LMDB... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lmdb" >&5
+printf %s "checking for lmdb... " >&6; }
if test -n "$LMDB_CFLAGS"; then
pkg_cv_LMDB_CFLAGS="$LMDB_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lmdb\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lmdb\""; } >&5
($PKG_CONFIG --exists --print-errors "lmdb") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LMDB_CFLAGS=`$PKG_CONFIG --cflags "lmdb" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -22515,10 +24420,10 @@ if test -n "$LMDB_LIBS"; then
pkg_cv_LMDB_LIBS="$LMDB_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lmdb\""; } >&5
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"lmdb\""; } >&5
($PKG_CONFIG --exists --print-errors "lmdb") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LMDB_LIBS=`$PKG_CONFIG --libs "lmdb" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
@@ -22532,8 +24437,8 @@ fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -22541,43 +24446,44 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LMDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lmdb" 2>&1`
+ LMDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "lmdb" 2>&1`
else
- LMDB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lmdb" 2>&1`
+ LMDB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "lmdb" 2>&1`
fi
- # Put the nasty error message in config.log where it belongs
- echo "$LMDB_PKG_ERRORS" >&5
+ # Put the nasty error message in config.log where it belongs
+ echo "$LMDB_PKG_ERRORS" >&5
- :
+ :
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+ :
else
- LMDB_CFLAGS=$pkg_cv_LMDB_CFLAGS
- LMDB_LIBS=$pkg_cv_LMDB_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ LMDB_CFLAGS=$pkg_cv_LMDB_CFLAGS
+ LMDB_LIBS=$pkg_cv_LMDB_LIBS
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
-$as_echo "#define HAVE_LMDB 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LMDB 1" >>confdefs.h
HAVE_LMDB=1
fi
-else
+else $as_nop
save_CPPFLAGS=$CPPFLAGS
save_LIBS=$LIBS
- if test -d "$with_lmdb/include"; then :
+ if test -d "$with_lmdb/include"
+then :
LMDB_CFLAGS="-I$with_lmdb/include"
LMDB_LIBS="-L$with_lmdb/lib"
-else
+else $as_nop
LMDB_CFLAGS="-I$with_lmdb"
LMDB_LIBS="-L$with_lmdb"
@@ -22586,82 +24492,82 @@ fi
CPPFLAGS="$LMDB_CFLAGS"
LIBS="$LMDB_LIBS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing mdb_env_open" >&5
-$as_echo_n "checking for library containing mdb_env_open... " >&6; }
-if ${ac_cv_search_mdb_env_open+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing mdb_env_open" >&5
+printf %s "checking for library containing mdb_env_open... " >&6; }
+if test ${ac_cv_search_mdb_env_open+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$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. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char mdb_env_open ();
+namespace conftest {
+ extern "C" int mdb_env_open ();
+}
int
-main ()
+main (void)
{
-return mdb_env_open ();
+return conftest::mdb_env_open ();
;
return 0;
}
_ACEOF
-for ac_lib in '' lmdb; do
+for ac_lib in '' lmdb
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_cxx_try_link "$LINENO"; then :
+ if ac_fn_cxx_try_link "$LINENO"
+then :
ac_cv_search_mdb_env_open=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_mdb_env_open+:} false; then :
+ if test ${ac_cv_search_mdb_env_open+y}
+then :
break
fi
done
-if ${ac_cv_search_mdb_env_open+:} false; then :
+if test ${ac_cv_search_mdb_env_open+y}
+then :
-else
+else $as_nop
ac_cv_search_mdb_env_open=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_mdb_env_open" >&5
-$as_echo "$ac_cv_search_mdb_env_open" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_mdb_env_open" >&5
+printf "%s\n" "$ac_cv_search_mdb_env_open" >&6; }
ac_res=$ac_cv_search_mdb_env_open
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- for ac_header in lmdb.h
+ for ac_header in lmdb.h
do :
- ac_fn_cxx_check_header_mongrel "$LINENO" "lmdb.h" "ac_cv_header_lmdb_h" "$ac_includes_default"
-if test "x$ac_cv_header_lmdb_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LMDB_H 1
-_ACEOF
+ ac_fn_cxx_check_header_compile "$LINENO" "lmdb.h" "ac_cv_header_lmdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_lmdb_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_LMDB_H 1" >>confdefs.h
LMDB_LIBS="$LMDB_LIBS $ac_cv_search_mdb_env_open"
-$as_echo "#define HAVE_LMDB 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LMDB 1" >>confdefs.h
HAVE_LMDB=1
-else
+else $as_nop
as_fn_error $? "lmdb headers not found in $with_lmdb" "$LINENO" 5
fi
done
-
CPPFLAGS="$save_CPPFLAGS"
LIBS="$save_LIBS"
@@ -22683,28 +24589,31 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ipcipher support" >&5
-$as_echo_n "checking whether to enable ipcipher support... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ipcipher support" >&5
+printf %s "checking whether to enable ipcipher support... " >&6; }
HAVE_IPCIPHER=0
# Check whether --enable-ipcipher was given.
-if test "${enable_ipcipher+set}" = set; then :
+if test ${enable_ipcipher+y}
+then :
enableval=$enable_ipcipher; enable_ipcipher=$enableval
-else
+else $as_nop
enable_ipcipher=auto
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ipcipher" >&5
-$as_echo "$enable_ipcipher" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_ipcipher" >&5
+printf "%s\n" "$enable_ipcipher" >&6; }
- if test "x$enable_ipcipher" != "xno"; then :
+ if test "x$enable_ipcipher" != "xno"
+then :
- if test "x$enable_ipcipher" = "xyes" -o "x$enable_ipcipher" = "xauto"; then :
+ if test "x$enable_ipcipher" = "xyes" -o "x$enable_ipcipher" = "xauto"
+then :
if test -z "$HAVE_LIBCRYPTO_TRUE"; then :
-$as_echo "#define HAVE_IPCIPHER 1" >>confdefs.h
+printf "%s\n" "#define HAVE_IPCIPHER 1" >>confdefs.h
HAVE_IPCIPHER=1
@@ -22722,9 +24631,11 @@ else
fi
- if test "x$enable_ipcipher" = "xyes"; then :
+ if test "x$enable_ipcipher" = "xyes"
+then :
- if test x"$HAVE_IPCIPHER" = "x0"; then :
+ if test x"$HAVE_IPCIPHER" = "x0"
+then :
as_fn_error $? "ipcipher support requested but libcrypto is not available" "$LINENO" 5
@@ -22746,12 +24657,13 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
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=`$as_echo "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5
-$as_echo_n "checking whether $CXX supports C++17 features with $switch... " >&6; }
-if eval \${$cachevar+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx17_$switch" | $as_tr_sh`
+ { 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"
CXX="$CXX $switch"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -23542,17 +25454,18 @@ namespace cxx17
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
eval $cachevar=yes
-else
+else $as_nop
eval $cachevar=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
CXX="$ac_save_CXX"
fi
eval ac_res=\$$cachevar
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
@@ -23580,35 +25493,37 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
fi
if test x$ac_success = xno; then
HAVE_CXX17=0
- { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++17 support was found" >&5
-$as_echo "$as_me: No compiler with C++17 support was found" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++17 support was found" >&5
+printf "%s\n" "$as_me: No compiler with C++17 support was found" >&6;}
else
HAVE_CXX17=1
-$as_echo "#define HAVE_CXX17 1" >>confdefs.h
+printf "%s\n" "#define HAVE_CXX17 1" >>confdefs.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will enable compiler security checks" >&5
-$as_echo_n "checking whether we will enable compiler security checks... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we will enable compiler security checks" >&5
+printf %s "checking whether we will enable compiler security checks... " >&6; }
# Check whether --enable-hardening was given.
-if test "${enable_hardening+set}" = set; then :
+if test ${enable_hardening+y}
+then :
enableval=$enable_hardening; enable_hardening=$enableval
-else
+else $as_nop
enable_hardening=yes
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5
-$as_echo "$enable_hardening" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5
+printf "%s\n" "$enable_hardening" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5
-$as_echo_n "checking whether C++ compiler handles -Werror -Wunknown-warning-option... " >&6; }
-if ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5
+printf %s "checking whether C++ compiler handles -Werror -Wunknown-warning-option... " >&6; }
+if test ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option"
@@ -23616,32 +25531,35 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__Werror__Wunknown_warning_option=yes
-else
+else $as_nop
gl_cv_warn_cxx__Werror__Wunknown_warning_option=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5
-$as_echo "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; }
-if test "x$gl_cv_warn_cxx__Werror__Wunknown_warning_option" = xyes; then :
+{ 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
+else $as_nop
gl_unknown_warnings_are_errors=
fi
-if test "x$enable_hardening" != "xno"; then :
+if test "x$enable_hardening" != "xno"
+then :
@@ -23652,11 +25570,12 @@ if test "x$enable_hardening" != "xno"; then :
*-*-mingw* | *-*-msvc* | *-*-cygwin* )
;; *)
CXXFLAGS="-fPIE -DPIE"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -pie" >&5
-$as_echo_n "checking whether C++ compiler handles -pie... " >&6; }
-if ${gl_cv_warn_cxx__pie+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -pie" >&5
+printf %s "checking whether C++ compiler handles -pie... " >&6; }
+if test ${gl_cv_warn_cxx__pie+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -pie"
@@ -23667,7 +25586,7 @@ else
__thread unsigned int t_id;
int
-main ()
+main (void)
{
t_id = 1;
;
@@ -23675,30 +25594,33 @@ t_id = 1;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__pie=yes
-else
+else $as_nop
gl_cv_warn_cxx__pie=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__pie" >&5
-$as_echo "$gl_cv_warn_cxx__pie" >&6; }
-if test "x$gl_cv_warn_cxx__pie" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__pie" >&5
+printf "%s\n" "$gl_cv_warn_cxx__pie" >&6; }
+if test "x$gl_cv_warn_cxx__pie" = xyes
+then :
PIE_CFLAGS="-fPIE -DPIE"
PIE_LDFLAGS="-pie"
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wl,-pie" >&5
-$as_echo_n "checking whether C++ compiler handles -Wl,-pie... " >&6; }
-if ${gl_cv_warn_cxx__Wl__pie+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { 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
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wl,-pie"
@@ -23709,7 +25631,7 @@ else
__thread unsigned int t_id;
int
-main ()
+main (void)
{
t_id = 1;
;
@@ -23717,19 +25639,21 @@ t_id = 1;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__Wl__pie=yes
-else
+else $as_nop
gl_cv_warn_cxx__Wl__pie=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wl__pie" >&5
-$as_echo "$gl_cv_warn_cxx__Wl__pie" >&6; }
-if test "x$gl_cv_warn_cxx__Wl__pie" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__Wl__pie" = xyes
+then :
PIE_CFLAGS="-fPIE -DPIE"
PIE_LDFLAGS="-Wl,-pie"
@@ -23745,11 +25669,12 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fstack-protector" >&5
-$as_echo_n "checking whether C++ compiler handles -fstack-protector... " >&6; }
-if ${gl_cv_warn_cxx__fstack_protector+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fstack-protector" >&5
+printf %s "checking whether C++ compiler handles -fstack-protector... " >&6; }
+if test ${gl_cv_warn_cxx__fstack_protector+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fstack-protector"
@@ -23757,26 +25682,28 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fstack_protector=yes
-else
+else $as_nop
gl_cv_warn_cxx__fstack_protector=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fstack_protector" >&5
-$as_echo "$gl_cv_warn_cxx__fstack_protector" >&6; }
-if test "x$gl_cv_warn_cxx__fstack_protector" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__fstack_protector" = xyes
+then :
CFLAGS="-fstack-protector $CFLAGS"
CXXFLAGS="-fstack-protector $CXXFLAGS"
@@ -23785,11 +25712,12 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles --param ssp-buffer-size=4" >&5
-$as_echo_n "checking whether C++ compiler handles --param ssp-buffer-size=4... " >&6; }
-if ${gl_cv_warn_cxx___param_ssp_buffer_size_4+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles --param ssp-buffer-size=4" >&5
+printf %s "checking whether C++ compiler handles --param ssp-buffer-size=4... " >&6; }
+if test ${gl_cv_warn_cxx___param_ssp_buffer_size_4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors --param ssp-buffer-size=4"
@@ -23797,26 +25725,28 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx___param_ssp_buffer_size_4=yes
-else
+else $as_nop
gl_cv_warn_cxx___param_ssp_buffer_size_4=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx___param_ssp_buffer_size_4" >&5
-$as_echo "$gl_cv_warn_cxx___param_ssp_buffer_size_4" >&6; }
-if test "x$gl_cv_warn_cxx___param_ssp_buffer_size_4" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx___param_ssp_buffer_size_4" = xyes
+then :
CFLAGS="--param ssp-buffer-size=4 $CFLAGS"
CXXFLAGS="--param ssp-buffer-size=4 $CXXFLAGS"
@@ -23826,28 +25756,33 @@ fi
# Check whether --enable-fortify-source was given.
-if test "${enable_fortify_source+set}" = set; then :
+if test ${enable_fortify_source+y}
+then :
enableval=$enable_fortify_source; enable_fortify_source=$enableval
-else
+else $as_nop
enable_fortify_source=2
fi
- if test "x$enable_fortify_source" != "xno"; then :
+ if test "x$enable_fortify_source" != "xno"
+then :
- if test "x$enable_fortify_source" == "xauto"; then :
+ if test "x$enable_fortify_source" == "xauto"
+then :
enable_fortify_source=3
fi
- if test "x$enable_fortify_source" == "x3"; then :
+ if test "x$enable_fortify_source" == "x3"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=3" >&5
-$as_echo_n "checking whether C++ compiler handles -D_FORTIFY_SOURCE=3... " >&6; }
-if ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=3" >&5
+printf %s "checking whether C++ compiler handles -D_FORTIFY_SOURCE=3... " >&6; }
+if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=3"
@@ -23855,44 +25790,48 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__D_FORTIFY_SOURCE_3=yes
-else
+else $as_nop
gl_cv_warn_cxx__D_FORTIFY_SOURCE_3=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" >&5
-$as_echo "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" >&6; }
-if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_3" = xyes
+then :
CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 $CFLAGS"
CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 $CXXFLAGS"
-else
+else $as_nop
enable_fortify_source=2
fi
fi
- if test "x$enable_fortify_source" == "x2"; then :
+ if test "x$enable_fortify_source" == "x2"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=2" >&5
-$as_echo_n "checking whether C++ compiler handles -D_FORTIFY_SOURCE=2... " >&6; }
-if ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_2+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=2" >&5
+printf %s "checking whether C++ compiler handles -D_FORTIFY_SOURCE=2... " >&6; }
+if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_2+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=2"
@@ -23900,44 +25839,48 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=yes
-else
+else $as_nop
gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&5
-$as_echo "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&6; }
-if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" = xyes
+then :
CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CXXFLAGS"
-else
+else $as_nop
enable_fortify_source=1
fi
fi
- if test "x$enable_fortify_source" == "x1"; then :
+ if test "x$enable_fortify_source" == "x1"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=1" >&5
-$as_echo_n "checking whether C++ compiler handles -D_FORTIFY_SOURCE=1... " >&6; }
-if ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_1+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=1" >&5
+printf %s "checking whether C++ compiler handles -D_FORTIFY_SOURCE=1... " >&6; }
+if test ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_1+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=1"
@@ -23945,31 +25888,33 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__D_FORTIFY_SOURCE_1=yes
-else
+else $as_nop
gl_cv_warn_cxx__D_FORTIFY_SOURCE_1=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" >&5
-$as_echo "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" >&6; }
-if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_1" = xyes
+then :
CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 $CFLAGS"
CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 $CXXFLAGS"
-else
+else $as_nop
enable_fortify_source=no
fi
@@ -23979,14 +25924,14 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether FORTIFY_SOURCE is supported" >&5
-$as_echo_n "checking whether FORTIFY_SOURCE is supported... " >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_fortify_source" >&5
-$as_echo "$enable_fortify_source" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether FORTIFY_SOURCE is supported" >&5
+printf %s "checking whether FORTIFY_SOURCE is supported... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_fortify_source" >&5
+printf "%s\n" "$enable_fortify_source" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for how to force completely read-only GOT table" >&5
-$as_echo_n "checking for how to force completely read-only GOT table... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for how to force completely read-only GOT table" >&5
+printf %s "checking for how to force completely read-only GOT table... " >&6; }
RELRO_LDFLAGS=
ld_help=`$CXX -Wl,-help 2>&1`
@@ -23997,12 +25942,13 @@ $as_echo_n "checking for how to force completely read-only GOT table... " >&6; }
*"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;;
esac
- if test "x$RELRO_LDFLAGS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RELRO_LDFLAGS" >&5
-$as_echo "$RELRO_LDFLAGS" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5
-$as_echo "unknown" >&6; }
+ if test "x$RELRO_LDFLAGS" != "x"
+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
+printf "%s\n" "unknown" >&6; }
fi
@@ -24010,31 +25956,35 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable initialization of automatic variables" >&5
-$as_echo_n "checking whether to enable initialization of automatic variables... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable initialization of automatic variables" >&5
+printf %s "checking whether to enable initialization of automatic variables... " >&6; }
# Check whether --enable-auto-var-init was given.
-if test "${enable_auto_var_init+set}" = set; then :
+if test ${enable_auto_var_init+y}
+then :
enableval=$enable_auto_var_init; enable_initautovars=$enableval
-else
+else $as_nop
enable_initautovars=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_initautovars" >&5
-$as_echo "$enable_initautovars" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_initautovars" >&5
+printf "%s\n" "$enable_initautovars" >&6; }
- if test "x$enable_initautovars" = "xyes"; then :
+ if test "x$enable_initautovars" = "xyes"
+then :
enable_initautovars=zero
fi
- if test "x$enable_initautovars" = "xzero" ; then :
+ if test "x$enable_initautovars" = "xzero"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -ftrivial-auto-var-init=zero" >&5
-$as_echo_n "checking whether C++ compiler handles -ftrivial-auto-var-init=zero... " >&6; }
-if ${gl_cv_warn_cxx__ftrivial_auto_var_init_zero+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -ftrivial-auto-var-init=zero" >&5
+printf %s "checking whether C++ compiler handles -ftrivial-auto-var-init=zero... " >&6; }
+if test ${gl_cv_warn_cxx__ftrivial_auto_var_init_zero+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -ftrivial-auto-var-init=zero"
@@ -24042,26 +25992,28 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__ftrivial_auto_var_init_zero=yes
-else
+else $as_nop
gl_cv_warn_cxx__ftrivial_auto_var_init_zero=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__ftrivial_auto_var_init_zero" >&5
-$as_echo "$gl_cv_warn_cxx__ftrivial_auto_var_init_zero" >&6; }
-if test "x$gl_cv_warn_cxx__ftrivial_auto_var_init_zero" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__ftrivial_auto_var_init_zero" = xyes
+then :
CFLAGS="-ftrivial-auto-var-init=zero $CFLAGS"
CXXFLAGS="-ftrivial-auto-var-init=zero $CXXFLAGS"
@@ -24071,13 +26023,15 @@ fi
fi
- if test "x$enable_initautovars" = "xpattern" ; then :
+ if test "x$enable_initautovars" = "xpattern"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -ftrivial-auto-var-init=pattern" >&5
-$as_echo_n "checking whether C++ compiler handles -ftrivial-auto-var-init=pattern... " >&6; }
-if ${gl_cv_warn_cxx__ftrivial_auto_var_init_pattern+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -ftrivial-auto-var-init=pattern" >&5
+printf %s "checking whether C++ compiler handles -ftrivial-auto-var-init=pattern... " >&6; }
+if test ${gl_cv_warn_cxx__ftrivial_auto_var_init_pattern+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -ftrivial-auto-var-init=pattern"
@@ -24085,26 +26039,28 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__ftrivial_auto_var_init_pattern=yes
-else
+else $as_nop
gl_cv_warn_cxx__ftrivial_auto_var_init_pattern=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" >&5
-$as_echo "$gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" >&6; }
-if test "x$gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__ftrivial_auto_var_init_pattern" = xyes
+then :
CFLAGS="-ftrivial-auto-var-init=pattern $CFLAGS"
CXXFLAGS="-ftrivial-auto-var-init=pattern $CXXFLAGS"
@@ -24118,26 +26074,29 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable AddressSanitizer" >&5
-$as_echo_n "checking whether to enable AddressSanitizer... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable AddressSanitizer" >&5
+printf %s "checking whether to enable AddressSanitizer... " >&6; }
# Check whether --enable-asan was given.
-if test "${enable_asan+set}" = set; then :
+if test ${enable_asan+y}
+then :
enableval=$enable_asan; enable_asan=$enableval
-else
+else $as_nop
enable_asan=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_asan" >&5
-$as_echo "$enable_asan" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_asan" >&5
+printf "%s\n" "$enable_asan" >&6; }
- if test "x$enable_asan" != "xno"; then :
+ if test "x$enable_asan" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=address" >&5
-$as_echo_n "checking whether C++ compiler handles -fsanitize=address... " >&6; }
-if ${gl_cv_warn_cxx__fsanitize_address+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=address" >&5
+printf %s "checking whether C++ compiler handles -fsanitize=address... " >&6; }
+if test ${gl_cv_warn_cxx__fsanitize_address+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=address"
@@ -24145,56 +26104,58 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fsanitize_address=yes
-else
+else $as_nop
gl_cv_warn_cxx__fsanitize_address=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_address" >&5
-$as_echo "$gl_cv_warn_cxx__fsanitize_address" >&6; }
-if test "x$gl_cv_warn_cxx__fsanitize_address" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__fsanitize_address" = xyes
+then :
SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"
- for ac_header in sanitizer/common_interface_defs.h
+ for ac_header in sanitizer/common_interface_defs.h
do :
- ac_fn_cxx_check_header_mongrel "$LINENO" "sanitizer/common_interface_defs.h" "ac_cv_header_sanitizer_common_interface_defs_h" "$ac_includes_default"
-if test "x$ac_cv_header_sanitizer_common_interface_defs_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H 1
-_ACEOF
+ ac_fn_cxx_check_header_compile "$LINENO" "sanitizer/common_interface_defs.h" "ac_cv_header_sanitizer_common_interface_defs_h" "$ac_includes_default"
+if test "x$ac_cv_header_sanitizer_common_interface_defs_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H 1" >>confdefs.h
asan_headers=yes
-else
+else $as_nop
asan_headers=no
fi
done
+ if test x"$asan_headers" = "xyes"
+then :
+ ac_fn_check_decl "$LINENO" "__sanitizer_start_switch_fiber" "ac_cv_have_decl___sanitizer_start_switch_fiber" "#include <sanitizer/common_interface_defs.h>
- if test x"$asan_headers" = "xyes" ; then :
- ac_fn_cxx_check_decl "$LINENO" "__sanitizer_start_switch_fiber" "ac_cv_have_decl___sanitizer_start_switch_fiber" "#include <sanitizer/common_interface_defs.h>
-
-"
-if test "x$ac_cv_have_decl___sanitizer_start_switch_fiber" = xyes; then :
+" "$ac_cxx_undeclared_builtin_options" "CXXFLAGS"
+if test "x$ac_cv_have_decl___sanitizer_start_switch_fiber" = xyes
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the exact signature of __sanitizer_finish_switch_fiber" >&5
-$as_echo_n "checking for the exact signature of __sanitizer_finish_switch_fiber... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the exact signature of __sanitizer_finish_switch_fiber" >&5
+printf %s "checking for the exact signature of __sanitizer_finish_switch_fiber... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sanitizer/common_interface_defs.h>
int
-main ()
+main (void)
{
__sanitizer_finish_switch_fiber(nullptr);
@@ -24204,25 +26165,26 @@ main ()
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: a single pointer" >&5
-$as_echo "a single pointer" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: a single pointer" >&5
+printf "%s\n" "a single pointer" >&6; }
-$as_echo "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h
+printf "%s\n" "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h
-$as_echo "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_SINGLE_PTR 1" >>confdefs.h
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sanitizer/common_interface_defs.h>
int
-main ()
+main (void)
{
__sanitizer_finish_switch_fiber(nullptr, nullptr, nullptr);
@@ -24232,41 +26194,41 @@ main ()
}
_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
+if ac_fn_cxx_try_compile "$LINENO"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: three pointers" >&5
-$as_echo "three pointers" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: three pointers" >&5
+printf "%s\n" "three pointers" >&6; }
-$as_echo "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h
+printf "%s\n" "#define HAVE_FIBER_SANITIZER 1" >>confdefs.h
-$as_echo "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS 1" >>confdefs.h
+printf "%s\n" "#define HAVE_SANITIZER_FINISH_SWITCH_FIBER_THREE_PTRS 1" >>confdefs.h
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5
-$as_echo "unknown" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available due to an unknown API version" >&5
-$as_echo "$as_me: ASAN fiber switching is not available due to an unknown API version" >&6;}
+ { 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;}
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-else
+else $as_nop
- { $as_echo "$as_me:${as_lineno-$LINENO}: ASAN fiber switching is not available" >&5
-$as_echo "$as_me: ASAN fiber switching is not available" >&6;}
+ { 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;}
fi
-
fi
-else
+else $as_nop
as_fn_error $? "Cannot enable AddressSanitizer" "$LINENO" 5
fi
@@ -24277,26 +26239,29 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable MemorySanitizer" >&5
-$as_echo_n "checking whether to enable MemorySanitizer... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable MemorySanitizer" >&5
+printf %s "checking whether to enable MemorySanitizer... " >&6; }
# Check whether --enable-msan was given.
-if test "${enable_msan+set}" = set; then :
+if test ${enable_msan+y}
+then :
enableval=$enable_msan; enable_msan=$enableval
-else
+else $as_nop
enable_msan=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_msan" >&5
-$as_echo "$enable_msan" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_msan" >&5
+printf "%s\n" "$enable_msan" >&6; }
- if test "x$enable_msan" != "xno"; then :
+ if test "x$enable_msan" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=memory" >&5
-$as_echo_n "checking whether C++ compiler handles -fsanitize=memory... " >&6; }
-if ${gl_cv_warn_cxx__fsanitize_memory+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=memory" >&5
+printf %s "checking whether C++ compiler handles -fsanitize=memory... " >&6; }
+if test ${gl_cv_warn_cxx__fsanitize_memory+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=memory"
@@ -24304,28 +26269,30 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fsanitize_memory=yes
-else
+else $as_nop
gl_cv_warn_cxx__fsanitize_memory=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_memory" >&5
-$as_echo "$gl_cv_warn_cxx__fsanitize_memory" >&6; }
-if test "x$gl_cv_warn_cxx__fsanitize_memory" = xyes; then :
+{ 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
+else $as_nop
as_fn_error $? "Cannot enable MemorySanitizer" "$LINENO" 5
fi
@@ -24336,26 +26303,29 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ThreadSanitizer" >&5
-$as_echo_n "checking whether to enable ThreadSanitizer... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ThreadSanitizer" >&5
+printf %s "checking whether to enable ThreadSanitizer... " >&6; }
# Check whether --enable-tsan was given.
-if test "${enable_tsan+set}" = set; then :
+if test ${enable_tsan+y}
+then :
enableval=$enable_tsan; enable_tsan=$enableval
-else
+else $as_nop
enable_tsan=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tsan" >&5
-$as_echo "$enable_tsan" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_tsan" >&5
+printf "%s\n" "$enable_tsan" >&6; }
- if test "x$enable_tsan" != "xno"; then :
+ if test "x$enable_tsan" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=thread" >&5
-$as_echo_n "checking whether C++ compiler handles -fsanitize=thread... " >&6; }
-if ${gl_cv_warn_cxx__fsanitize_thread+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=thread" >&5
+printf %s "checking whether C++ compiler handles -fsanitize=thread... " >&6; }
+if test ${gl_cv_warn_cxx__fsanitize_thread+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=thread"
@@ -24363,28 +26333,30 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fsanitize_thread=yes
-else
+else $as_nop
gl_cv_warn_cxx__fsanitize_thread=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_thread" >&5
-$as_echo "$gl_cv_warn_cxx__fsanitize_thread" >&6; }
-if test "x$gl_cv_warn_cxx__fsanitize_thread" = xyes; then :
+{ 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
+else $as_nop
as_fn_error $? "Cannot enable ThreadSanitizer" "$LINENO" 5
fi
@@ -24395,26 +26367,29 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable LeakSanitizer" >&5
-$as_echo_n "checking whether to enable LeakSanitizer... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable LeakSanitizer" >&5
+printf %s "checking whether to enable LeakSanitizer... " >&6; }
# Check whether --enable-lsan was given.
-if test "${enable_lsan+set}" = set; then :
+if test ${enable_lsan+y}
+then :
enableval=$enable_lsan; enable_lsan=$enableval
-else
+else $as_nop
enable_lsan=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lsan" >&5
-$as_echo "$enable_lsan" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_lsan" >&5
+printf "%s\n" "$enable_lsan" >&6; }
- if test "x$enable_lsan" != "xno"; then :
+ if test "x$enable_lsan" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=leak" >&5
-$as_echo_n "checking whether C++ compiler handles -fsanitize=leak... " >&6; }
-if ${gl_cv_warn_cxx__fsanitize_leak+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=leak" >&5
+printf %s "checking whether C++ compiler handles -fsanitize=leak... " >&6; }
+if test ${gl_cv_warn_cxx__fsanitize_leak+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=leak"
@@ -24422,28 +26397,30 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fsanitize_leak=yes
-else
+else $as_nop
gl_cv_warn_cxx__fsanitize_leak=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_leak" >&5
-$as_echo "$gl_cv_warn_cxx__fsanitize_leak" >&6; }
-if test "x$gl_cv_warn_cxx__fsanitize_leak" = xyes; then :
+{ 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
+else $as_nop
as_fn_error $? "Cannot enable LeakSanitizer" "$LINENO" 5
fi
@@ -24454,26 +26431,29 @@ fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable Undefined Behaviour Sanitizer" >&5
-$as_echo_n "checking whether to enable Undefined Behaviour Sanitizer... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable Undefined Behaviour Sanitizer" >&5
+printf %s "checking whether to enable Undefined Behaviour Sanitizer... " >&6; }
# Check whether --enable-ubsan was given.
-if test "${enable_ubsan+set}" = set; then :
+if test ${enable_ubsan+y}
+then :
enableval=$enable_ubsan; enable_ubsan=$enableval
-else
+else $as_nop
enable_ubsan=no
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ubsan" >&5
-$as_echo "$enable_ubsan" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_ubsan" >&5
+printf "%s\n" "$enable_ubsan" >&6; }
- if test "x$enable_ubsan" != "xno"; then :
+ if test "x$enable_ubsan" != "xno"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=undefined" >&5
-$as_echo_n "checking whether C++ compiler handles -fsanitize=undefined... " >&6; }
-if ${gl_cv_warn_cxx__fsanitize_undefined+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=undefined" >&5
+printf %s "checking whether C++ compiler handles -fsanitize=undefined... " >&6; }
+if test ${gl_cv_warn_cxx__fsanitize_undefined+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=undefined"
@@ -24481,28 +26461,30 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fsanitize_undefined=yes
-else
+else $as_nop
gl_cv_warn_cxx__fsanitize_undefined=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_undefined" >&5
-$as_echo "$gl_cv_warn_cxx__fsanitize_undefined" >&6; }
-if test "x$gl_cv_warn_cxx__fsanitize_undefined" = xyes; then :
+{ 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
+else $as_nop
as_fn_error $? "Cannot enable Undefined Behaviour Sanitizer" "$LINENO" 5
fi
@@ -24512,38 +26494,44 @@ fi
- if test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"; then :
+ if test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"
+then :
as_fn_error $? "Address Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5
fi
- if test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"; then :
+ if test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"
+then :
as_fn_error $? "Memory Sanitizer is not compatible with Address Sanitizer" "$LINENO" 5
fi
- if test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"; then :
+ if test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"
+then :
as_fn_error $? "Memory Sanitizer is not compatible with Leak Sanitizer" "$LINENO" 5
fi
- if test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"; then :
+ if test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"
+then :
as_fn_error $? "Memory Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5
fi
- if test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"; then :
+ if test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"
+then :
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-omit-frame-pointer" >&5
-$as_echo_n "checking whether C++ compiler handles -fno-omit-frame-pointer... " >&6; }
-if ${gl_cv_warn_cxx__fno_omit_frame_pointer+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-omit-frame-pointer" >&5
+printf %s "checking whether C++ compiler handles -fno-omit-frame-pointer... " >&6; }
+if test ${gl_cv_warn_cxx__fno_omit_frame_pointer+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fno-omit-frame-pointer"
@@ -24551,26 +26539,28 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__fno_omit_frame_pointer=yes
-else
+else $as_nop
gl_cv_warn_cxx__fno_omit_frame_pointer=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_omit_frame_pointer" >&5
-$as_echo "$gl_cv_warn_cxx__fno_omit_frame_pointer" >&6; }
-if test "x$gl_cv_warn_cxx__fno_omit_frame_pointer" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__fno_omit_frame_pointer" = xyes
+then :
as_fn_append WARN_CFLAGS " -fno-omit-frame-pointer"
fi
@@ -24580,24 +26570,28 @@ fi
# Check whether --enable-lto was given.
-if test "${enable_lto+set}" = set; then :
+if test ${enable_lto+y}
+then :
enableval=$enable_lto; enable_lto=$enableval
-else
+else $as_nop
enable_lto=no
fi
- if test "x$enable_lto" != "xno"; then :
+ if test "x$enable_lto" != "xno"
+then :
- if test "x$enable_lto" == "xthin"; then :
+ if test "x$enable_lto" == "xthin"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto=thin" >&5
-$as_echo_n "checking whether C++ compiler handles -flto=thin... " >&6; }
-if ${gl_cv_warn_cxx__flto_thin+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto=thin" >&5
+printf %s "checking whether C++ compiler handles -flto=thin... " >&6; }
+if test ${gl_cv_warn_cxx__flto_thin+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto=thin"
@@ -24605,45 +26599,49 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__flto_thin=yes
-else
+else $as_nop
gl_cv_warn_cxx__flto_thin=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto_thin" >&5
-$as_echo "$gl_cv_warn_cxx__flto_thin" >&6; }
-if test "x$gl_cv_warn_cxx__flto_thin" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__flto_thin" = xyes
+then :
CFLAGS="-flto=thin $CFLAGS"
CXXFLAGS="-flto=thin $CXXFLAGS"
LDFLAGS="-flto=thin $LDFLAGS"
-else
+else $as_nop
enable_lto=auto
fi
fi
- if test "x$enable_lto" == "xauto"; then :
+ if test "x$enable_lto" == "xauto"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto=auto" >&5
-$as_echo_n "checking whether C++ compiler handles -flto=auto... " >&6; }
-if ${gl_cv_warn_cxx__flto_auto+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto=auto" >&5
+printf %s "checking whether C++ compiler handles -flto=auto... " >&6; }
+if test ${gl_cv_warn_cxx__flto_auto+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto=auto"
@@ -24651,45 +26649,49 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__flto_auto=yes
-else
+else $as_nop
gl_cv_warn_cxx__flto_auto=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto_auto" >&5
-$as_echo "$gl_cv_warn_cxx__flto_auto" >&6; }
-if test "x$gl_cv_warn_cxx__flto_auto" = xyes; then :
+{ 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; }
+if test "x$gl_cv_warn_cxx__flto_auto" = xyes
+then :
CFLAGS="-flto=auto $CFLAGS"
CXXFLAGS="-flto=auto $CXXFLAGS"
LDFLAGS="-flto=auto $LDFLAGS"
-else
+else $as_nop
enable_lto=yes
fi
fi
- if test "x$enable_lto" == "xyes"; then :
+ if test "x$enable_lto" == "xyes"
+then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto" >&5
-$as_echo_n "checking whether C++ compiler handles -flto... " >&6; }
-if ${gl_cv_warn_cxx__flto+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -flto" >&5
+printf %s "checking whether C++ compiler handles -flto... " >&6; }
+if test ${gl_cv_warn_cxx__flto+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
gl_save_compiler_FLAGS="$CXXFLAGS"
as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -flto"
@@ -24697,32 +26699,34 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
+if ac_fn_cxx_try_link "$LINENO"
+then :
gl_cv_warn_cxx__flto=yes
-else
+else $as_nop
gl_cv_warn_cxx__flto=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
CXXFLAGS="$gl_save_compiler_FLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto" >&5
-$as_echo "$gl_cv_warn_cxx__flto" >&6; }
-if test "x$gl_cv_warn_cxx__flto" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__flto" >&5
+printf "%s\n" "$gl_cv_warn_cxx__flto" >&6; }
+if test "x$gl_cv_warn_cxx__flto" = xyes
+then :
CFLAGS="-flto $CFLAGS"
CXXFLAGS="-flto $CXXFLAGS"
LDFLAGS="-flto $LDFLAGS"
-else
+else $as_nop
enable_lto=no
fi
@@ -24731,10 +26735,128 @@ fi
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether link-time optimization is supported" >&5
-$as_echo_n "checking whether link-time optimization is supported... " >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lto" >&5
-$as_echo "$enable_lto" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether link-time optimization is supported" >&5
+printf %s "checking whether link-time optimization is supported... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_lto" >&5
+printf "%s\n" "$enable_lto" >&6; }
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable code coverage" >&5
+printf %s "checking whether to enable code coverage... " >&6; }
+ # Check whether --enable-coverage was given.
+if test ${enable_coverage+y}
+then :
+ enableval=$enable_coverage; enable_coverage=$enableval
+else $as_nop
+ enable_coverage=no
+
+fi
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_coverage" >&5
+printf "%s\n" "$enable_coverage" >&6; }
+
+ if test "x$enable_coverage" = "xclang"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fprofile-instr-generate -fcoverage-mapping" >&5
+printf %s "checking whether C++ compiler handles -fprofile-instr-generate -fcoverage-mapping... " >&6; }
+if test ${gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ 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
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+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; }
+if test "x$gl_cv_warn_cxx__fprofile_instr_generate__fcoverage_mapping" = xyes
+then :
+
+ CFLAGS="$CFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping"
+ CXXFLAGS="$CXXFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping"
+
+else $as_nop
+
+ as_fn_error $? "$CXX does not support gathering coverage data in the clang format" "$LINENO" 5
+
+fi
+
+
+fi
+
+ if test "x$enable_coverage" = "xyes"
+then :
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fprofile-arcs -ftest-coverage" >&5
+printf %s "checking whether C++ compiler handles -fprofile-arcs -ftest-coverage... " >&6; }
+if test ${gl_cv_warn_cxx__fprofile_arcs__ftest_coverage+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ 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
+/* end confdefs.h. */
+
+int
+main (void)
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+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
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+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; }
+if test "x$gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" = xyes
+then :
+
+ CFLAGS="$CFLAGS -DCOVERAGE --coverage"
+ CXXFLAGS="$CXXFLAGS -DCOVERAGE --coverage"
+ LDFLAGS="$LDFLAGS --coverage"
+
+else $as_nop
+
+ as_fn_error $? "$CXX does not support gathering coverage data" "$LINENO" 5
+
+fi
+
+
+fi
@@ -24746,8 +26868,8 @@ $as_echo "$enable_lto" >&6; }
if test -n "$PYTHON"; then
# If the user set $PYTHON, use it and don't search something else.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 3.6" >&5
-$as_echo_n "checking whether $PYTHON version is >= 3.6... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 3.6" >&5
+printf %s "checking whether $PYTHON version is >= 3.6... " >&6; }
prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
# because we need at least 4 digits for the hex conversion.
@@ -24761,25 +26883,27 @@ sys.exit(sys.hexversion < minverhex)"
($PYTHON -c "$prog") >&5 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ (exit $ac_status); }
+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
+printf "%s\n" "no" >&6; }
as_fn_error $? "Python interpreter is too old" "$LINENO" 5
fi
am_display_PYTHON=$PYTHON
else
# Otherwise, try each interpreter until we find one that satisfies
# VERSION.
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 3.6" >&5
-$as_echo_n "checking for a Python interpreter with version >= 3.6... " >&6; }
-if ${am_cv_pathless_PYTHON+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- for am_cv_pathless_PYTHON in python python2 python3 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
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 3.6" >&5
+printf %s "checking for a Python interpreter with version >= 3.6... " >&6; }
+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
test "$am_cv_pathless_PYTHON" = none && break
prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
@@ -24794,24 +26918,26 @@ sys.exit(sys.hexversion < minverhex)"
($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then :
+ (exit $ac_status); }
+then :
break
fi
done
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5
-$as_echo "$am_cv_pathless_PYTHON" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5
+printf "%s\n" "$am_cv_pathless_PYTHON" >&6; }
# Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
if test "$am_cv_pathless_PYTHON" = none; then
PYTHON=:
else
# Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args.
set dummy $am_cv_pathless_PYTHON; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PYTHON+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_PYTHON+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
case $PYTHON in
[\\/]* | ?:[\\/]*)
ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path.
@@ -24821,11 +26947,15 @@ else
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_path_PYTHON="$as_dir$ac_word$ac_exec_ext"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -24837,11 +26967,11 @@ esac
fi
PYTHON=$ac_cv_path_PYTHON
if test -n "$PYTHON"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5
-$as_echo "$PYTHON" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5
+printf "%s\n" "$PYTHON" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -24851,42 +26981,172 @@ fi
if test "$PYTHON" = :; then
- :
+ :
else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5
-$as_echo_n "checking for $am_display_PYTHON version... " >&6; }
-if ${am_cv_python_version+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"`
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5
+printf %s "checking for $am_display_PYTHON version... " >&6; }
+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])"`
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5
-$as_echo "$am_cv_python_version" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5
+printf "%s\n" "$am_cv_python_version" >&6; }
PYTHON_VERSION=$am_cv_python_version
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5
+printf %s "checking for $am_display_PYTHON platform... " >&6; }
+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)"`
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5
+printf "%s\n" "$am_cv_python_platform" >&6; }
+ PYTHON_PLATFORM=$am_cv_python_platform
- PYTHON_PREFIX='${prefix}'
-
- PYTHON_EXEC_PREFIX='${exec_prefix}'
+ if test "x$prefix" = xNONE; then
+ am__usable_prefix=$ac_default_prefix
+ else
+ am__usable_prefix=$prefix
+ fi
+ # Allow user to request using sys.* values from Python,
+ # instead of the GNU $prefix values.
+
+# Check whether --with-python-sys-prefix was given.
+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
+fi
+
+
+ # Allow user to override whatever the default Python prefix is.
+
+# Check whether --with-python_prefix was given.
+if test ${with_python_prefix+y}
+then :
+ withval=$with_python_prefix; am_python_prefix_subst=$withval
+ am_cv_python_prefix=$withval
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for explicit $am_display_PYTHON prefix" >&5
+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
+
+ 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
+printf %s "checking for python default $am_display_PYTHON prefix... " >&6; }
+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)"`
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_prefix" >&5
+printf "%s\n" "$am_cv_python_prefix" >&6; }
+
+ case $am_cv_python_prefix in
+ $am__usable_prefix*)
+ am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
+ am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
+ ;;
+ *)
+ am_python_prefix_subst=$am_cv_python_prefix
+ ;;
+ esac
+ else # using GNU prefix value, not python sys.prefix
+ am_python_prefix_subst='${prefix}'
+ am_python_prefix=$am_python_prefix_subst
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU default $am_display_PYTHON prefix" >&5
+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
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5
-$as_echo_n "checking for $am_display_PYTHON platform... " >&6; }
-if ${am_cv_python_platform+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`
+ # Substituting python_prefix_subst value.
+ PYTHON_PREFIX=$am_python_prefix_subst
+
+
+ # emacs-page Now do it all over again for Python exec_prefix, but with yet
+ # another conditional: fall back to regular prefix if that was specified.
+
+# Check whether --with-python_exec_prefix was given.
+if test ${with_python_exec_prefix+y}
+then :
+ withval=$with_python_exec_prefix; am_python_exec_prefix_subst=$withval
+ am_cv_python_exec_prefix=$withval
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for explicit $am_display_PYTHON exec_prefix" >&5
+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
+
+ # 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"
+then :
+ am_python_exec_prefix_subst=$with_python_prefix
+ am_cv_python_exec_prefix=$with_python_prefix
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for python_prefix-given $am_display_PYTHON exec_prefix" >&5
+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
+
+ # 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
+ am__usable_exec_prefix=$am__usable_prefix
+ else
+ am__usable_exec_prefix=$exec_prefix
+ fi
+ #
+ if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for python default $am_display_PYTHON exec_prefix" >&5
+printf %s "checking for python default $am_display_PYTHON exec_prefix... " >&6; }
+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)"`
+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; }
+ case $am_cv_python_exec_prefix in
+ $am__usable_exec_prefix*)
+ am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
+ am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
+ ;;
+ *)
+ am_python_exec_prefix_subst=$am_cv_python_exec_prefix
+ ;;
+ esac
+ else # using GNU $exec_prefix, not python sys.exec_prefix
+ am_python_exec_prefix_subst='${exec_prefix}'
+ am_python_exec_prefix=$am_python_exec_prefix_subst
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU default $am_display_PYTHON exec_prefix" >&5
+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
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5
-$as_echo "$am_cv_python_platform" >&6; }
- PYTHON_PLATFORM=$am_cv_python_platform
+fi
+
+ # Substituting python_exec_prefix_subst.
+ PYTHON_EXEC_PREFIX=$am_python_exec_prefix_subst
- # Just factor out some code duplication.
+ # Factor out some code duplication into this shell variable.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
@@ -24907,99 +27167,97 @@ except ImportError:
pass"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5
-$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; }
-if ${am_cv_python_pythondir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$prefix" = xNONE
- then
- am_py_prefix=$ac_default_prefix
- else
- am_py_prefix=$prefix
- fi
- am_cv_python_pythondir=`$PYTHON -c "
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory (pythondir)" >&5
+printf %s "checking for $am_display_PYTHON script directory (pythondir)... " >&6; }
+if test ${am_cv_python_pythondir+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "x$am_cv_python_prefix" = x; then
+ am_py_prefix=$am__usable_prefix
+ else
+ am_py_prefix=$am_cv_python_prefix
+ fi
+ am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
- sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
+ 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')
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
- case $am_cv_python_pythondir in
- $am_py_prefix*)
- am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
- am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
- ;;
- *)
- case $am_py_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
+ #
+ case $am_cv_python_pythondir in
+ $am_py_prefix*)
+ am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
+ am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
+ ;;
+ *)
+ case $am_py_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
esac
+ ;;
+ esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5
-$as_echo "$am_cv_python_pythondir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5
+printf "%s\n" "$am_cv_python_pythondir" >&6; }
pythondir=$am_cv_python_pythondir
-
- pkgpythondir=\${pythondir}/$PACKAGE
+ pkgpythondir=\${pythondir}/$PACKAGE
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5
-$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; }
-if ${am_cv_python_pyexecdir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$exec_prefix" = xNONE
- then
- am_py_exec_prefix=$am_py_prefix
- else
- am_py_exec_prefix=$exec_prefix
- fi
- am_cv_python_pyexecdir=`$PYTHON -c "
+ { 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
+ am_py_exec_prefix=$am__usable_exec_prefix
+ else
+ am_py_exec_prefix=$am_cv_python_exec_prefix
+ fi
+ am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
- sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
+ 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_prefix')
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
sys.stdout.write(sitedir)"`
- case $am_cv_python_pyexecdir in
- $am_py_exec_prefix*)
- am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
- am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
- ;;
- *)
- case $am_py_exec_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
+ #
+ case $am_cv_python_pyexecdir in
+ $am_py_exec_prefix*)
+ am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
+ am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
+ ;;
+ *)
+ case $am_py_exec_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
esac
+ ;;
+ esac
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5
-$as_echo "$am_cv_python_pyexecdir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5
+printf "%s\n" "$am_cv_python_pyexecdir" >&6; }
pyexecdir=$am_cv_python_pyexecdir
-
- pkgpyexecdir=\${pyexecdir}/$PACKAGE
+ pkgpyexecdir=\${pyexecdir}/$PACKAGE
fi
-
- if test "${PYTHON}" != ":"; then :
+ if test "${PYTHON}" != ":"
+then :
if test -z $PYTHON;
@@ -25012,17 +27270,17 @@ $as_echo "$am_cv_python_pyexecdir" >&6; }
fi
fi
PYTHON_NAME=`basename $PYTHON`
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking $PYTHON_NAME module: venv" >&5
-$as_echo_n "checking $PYTHON_NAME module: venv... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking $PYTHON_NAME module: venv" >&5
+printf %s "checking $PYTHON_NAME module: venv... " >&6; }
$PYTHON -c "import venv" 2>/dev/null
if test $? -eq 0;
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
eval HAVE_PYMOD_VENV=yes
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
eval HAVE_PYMOD_VENV=no
#
if test -n ""
@@ -25058,8 +27316,8 @@ if test -z "$HAVE_MANPAGES_TRUE"; then :
if test -z "$HAVE_VENV_TRUE"; then :
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Python 3 and/or venv module are not available, documentation will not be built." >&5
-$as_echo "$as_me: WARNING: Python 3 and/or venv module are not available, documentation will not be built." >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Python 3 and/or venv module are not available, documentation will not be built." >&5
+printf "%s\n" "$as_me: WARNING: Python 3 and/or venv module are not available, documentation will not be built." >&2;}
fi
@@ -25081,16 +27339,15 @@ AM_CPPFLAGS="-I\$(top_builddir) -I\$(top_srcdir) $THREADFLAGS $BOOST_CPPFLAGS"
-if test "x$PACKAGEVERSION" != "x"; then :
+if test "x$PACKAGEVERSION" != "x"
+then :
-cat >>confdefs.h <<_ACEOF
-#define PACKAGEVERSION "$PACKAGEVERSION"
-_ACEOF
+printf "%s\n" "#define PACKAGEVERSION \"$PACKAGEVERSION\"" >>confdefs.h
fi
-ac_config_files="$ac_config_files Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile ext/ipcrypt/Makefile"
+ac_config_files="$ac_config_files Makefile ext/arc4random/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile ext/ipcrypt/Makefile"
cat >confcache <<\_ACEOF
@@ -25120,8 +27377,8 @@ _ACEOF
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -25151,15 +27408,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
/^ac_cv_env_/b end
t clear
:clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
t end
s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
if test "x$cache_file" != "x/dev/null"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
@@ -25173,8 +27430,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;}
fi
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
fi
fi
rm -f confcache
@@ -25191,7 +27448,7 @@ U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
# 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
# will be set to the directory where LIBOBJS objects are built.
as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
@@ -25202,14 +27459,14 @@ LIBOBJS=$ac_libobjs
LTLIBOBJS=$ac_ltlibobjs
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
-$as_echo_n "checking that generated files are newer than configure... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+printf %s "checking that generated files are newer than configure... " >&6; }
if test -n "$am_sleep_pid"; then
# Hide warnings about reused PIDs.
wait $am_sleep_pid 2>/dev/null
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
-$as_echo "done" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5
+printf "%s\n" "done" >&6; }
if test -n "$EXEEXT"; then
am__EXEEXT_TRUE=
am__EXEEXT_FALSE='#'
@@ -25234,6 +27491,10 @@ if test -z "${LIBSODIUM_TRUE}" && test -z "${LIBSODIUM_FALSE}"; then
as_fn_error $? "conditional \"LIBSODIUM\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_QUICHE_TRUE}" && test -z "${HAVE_QUICHE_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_QUICHE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${FSTRM_TRUE}" && test -z "${FSTRM_FALSE}"; then
as_fn_error $? "conditional \"FSTRM\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25266,6 +27527,10 @@ if test -z "${UNIT_TESTS_TRUE}" && test -z "${UNIT_TESTS_FALSE}"; then
as_fn_error $? "conditional \"UNIT_TESTS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${FUZZ_TARGETS_TRUE}" && test -z "${FUZZ_TARGETS_FALSE}"; then
+ as_fn_error $? "conditional \"FUZZ_TARGETS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_RE2_TRUE}" && test -z "${HAVE_RE2_FALSE}"; then
as_fn_error $? "conditional \"HAVE_RE2\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25278,6 +27543,10 @@ if test -z "${HAVE_EBPF_TRUE}" && test -z "${HAVE_EBPF_FALSE}"; then
as_fn_error $? "conditional \"HAVE_EBPF\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_XSK_TRUE}" && test -z "${HAVE_XSK_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_XSK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_NET_SNMP_TRUE}" && test -z "${HAVE_NET_SNMP_FALSE}"; then
as_fn_error $? "conditional \"HAVE_NET_SNMP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25406,10 +27675,18 @@ if test -z "${HAVE_LUA_HPP_TRUE}" && test -z "${HAVE_LUA_HPP_FALSE}"; then
as_fn_error $? "conditional \"HAVE_LUA_HPP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_CDB_TRUE}" && test -z "${HAVE_CDB_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_CDB\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_GNUTLS_TRUE}" && test -z "${HAVE_GNUTLS_FALSE}"; then
as_fn_error $? "conditional \"HAVE_GNUTLS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_LIBH2OEVLOOP_TRUE}" && test -z "${HAVE_LIBH2OEVLOOP_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_LIBH2OEVLOOP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_LIBSSL_TRUE}" && test -z "${HAVE_LIBSSL_FALSE}"; then
as_fn_error $? "conditional \"HAVE_LIBSSL\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25418,8 +27695,8 @@ if test -z "${HAVE_LMDB_TRUE}" && test -z "${HAVE_LMDB_FALSE}"; then
as_fn_error $? "conditional \"HAVE_LMDB\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
-if test -z "${HAVE_CDB_TRUE}" && test -z "${HAVE_CDB_FALSE}"; then
- as_fn_error $? "conditional \"HAVE_CDB\" was never defined.
+if test -z "${HAVE_NGHTTP2_TRUE}" && test -z "${HAVE_NGHTTP2_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_NGHTTP2\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${HAVE_LIBCRYPTO_TRUE}" && test -z "${HAVE_LIBCRYPTO_FALSE}"; then
@@ -25438,6 +27715,14 @@ if test -z "${HAVE_DNS_OVER_HTTPS_TRUE}" && test -z "${HAVE_DNS_OVER_HTTPS_FALSE
as_fn_error $? "conditional \"HAVE_DNS_OVER_HTTPS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_DNS_OVER_QUIC_TRUE}" && test -z "${HAVE_DNS_OVER_QUIC_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_DNS_OVER_QUIC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_DNS_OVER_HTTP3_TRUE}" && test -z "${HAVE_DNS_OVER_HTTP3_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_DNS_OVER_HTTP3\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_LIBSSL_TRUE}" && test -z "${HAVE_LIBSSL_FALSE}"; then
as_fn_error $? "conditional \"HAVE_LIBSSL\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25446,14 +27731,14 @@ if test -z "${HAVE_GNUTLS_TRUE}" && test -z "${HAVE_GNUTLS_FALSE}"; then
as_fn_error $? "conditional \"HAVE_GNUTLS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
-if test -z "${HAVE_LIBH2OEVLOOP_TRUE}" && test -z "${HAVE_LIBH2OEVLOOP_FALSE}"; then
- as_fn_error $? "conditional \"HAVE_LIBH2OEVLOOP\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
if test -z "${HAVE_NGHTTP2_TRUE}" && test -z "${HAVE_NGHTTP2_FALSE}"; then
as_fn_error $? "conditional \"HAVE_NGHTTP2\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_LIBH2OEVLOOP_TRUE}" && test -z "${HAVE_LIBH2OEVLOOP_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_LIBH2OEVLOOP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_CDB_TRUE}" && test -z "${HAVE_CDB_FALSE}"; then
as_fn_error $? "conditional \"HAVE_CDB\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -25479,8 +27764,8 @@ fi
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
@@ -25503,14 +27788,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -25520,46 +27807,46 @@ esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
@@ -25568,13 +27855,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
@@ -25583,8 +27863,12 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
@@ -25596,30 +27880,10 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# as_fn_error STATUS ERROR [LINENO LOG_FD]
@@ -25632,13 +27896,14 @@ as_fn_error ()
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
@@ -25665,18 +27930,20 @@ as_fn_unset ()
{ eval $1=; unset $1;}
}
as_unset=as_fn_unset
+
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
@@ -25688,12 +27955,13 @@ fi # as_fn_append
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
@@ -25724,7 +27992,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -25746,6 +28014,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -25759,6 +28031,12 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+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
@@ -25800,7 +28078,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -25809,7 +28087,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -25871,8 +28149,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dnsdist $as_me 1.8.3, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+This file was extended by dnsdist $as_me 1.9.3, which was
+generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -25934,14 +28212,16 @@ $config_commands
Report bugs to the package provider."
_ACEOF
+ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
+ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-dnsdist config.status 1.8.3
-configured by $0, generated by GNU Autoconf 2.69,
+dnsdist config.status 1.9.3
+configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -25981,15 +28261,15 @@ do
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- $as_echo "$ac_cs_version"; exit ;;
+ printf "%s\n" "$ac_cs_version"; exit ;;
--config | --confi | --conf | --con | --co | --c )
- $as_echo "$ac_cs_config"; exit ;;
+ printf "%s\n" "$ac_cs_config"; exit ;;
--debug | --debu | --deb | --de | --d | -d )
debug=: ;;
--file | --fil | --fi | --f )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
'') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
@@ -25997,7 +28277,7 @@ do
--header | --heade | --head | --hea )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
as_fn_append CONFIG_HEADERS " '$ac_optarg'"
ac_need_defaults=false;;
@@ -26006,7 +28286,7 @@ do
as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
- $as_echo "$ac_cs_usage"; exit ;;
+ printf "%s\n" "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
ac_cs_silent=: ;;
@@ -26034,7 +28314,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
- \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
export CONFIG_SHELL
exec "\$@"
@@ -26048,7 +28328,7 @@ exec 5>>config.log
sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
- $as_echo "$ac_log"
+ printf "%s\n" "$ac_log"
} >&5
_ACEOF
@@ -26100,6 +28380,7 @@ lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_q
lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`'
OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
@@ -26108,6 +28389,7 @@ want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`'
AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
@@ -26282,6 +28564,7 @@ LN_S \
lt_SP2NL \
lt_NL2SP \
reload_flag \
+FILECMD \
OBJDUMP \
deplibs_check_method \
file_magic_cmd \
@@ -26290,7 +28573,6 @@ want_nocaseglob \
DLLTOOL \
sharedlib_from_linklib_cmd \
AR \
-AR_FLAGS \
archiver_list_spec \
STRIP \
RANLIB \
@@ -26451,6 +28733,7 @@ do
"depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
"libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "ext/arc4random/Makefile") CONFIG_FILES="$CONFIG_FILES ext/arc4random/Makefile" ;;
"ext/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/Makefile" ;;
"ext/yahttp/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/yahttp/Makefile" ;;
"ext/ipcrypt/Makefile") CONFIG_FILES="$CONFIG_FILES ext/ipcrypt/Makefile" ;;
@@ -26465,9 +28748,9 @@ done
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
- test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
- test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
- test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+ test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
+ test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
+ test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands
fi
# Have a temporary directory for convenience. Make it in the build tree
@@ -26803,7 +29086,7 @@ do
esac ||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
- case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; 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
@@ -26811,17 +29094,17 @@ do
# use $as_me), people would be surprised to read:
# /* config.h. Generated by config.status. */
configure_input='Generated from '`
- $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
`' by configure.'
if test x"$ac_file" != x-; then
configure_input="$ac_file. $configure_input"
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+printf "%s\n" "$as_me: creating $ac_file" >&6;}
fi
# Neutralize special characters interpreted by sed in replacement strings.
case $configure_input in #(
*\&* | *\|* | *\\* )
- ac_sed_conf_input=`$as_echo "$configure_input" |
+ ac_sed_conf_input=`printf "%s\n" "$configure_input" |
sed 's/[\\\\&|]/\\\\&/g'`;; #(
*) ac_sed_conf_input=$configure_input;;
esac
@@ -26838,7 +29121,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$ac_file" : 'X\(//\)[^/]' \| \
X"$ac_file" : 'X\(//\)$' \| \
X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
+printf "%s\n" X"$ac_file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -26862,9 +29145,9 @@ $as_echo X"$ac_file" |
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
@@ -26926,8 +29209,8 @@ ac_sed_dataroot='
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_datarootdir_hack='
@@ -26971,9 +29254,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
{ 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"; } &&
- { $as_echo "$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
-$as_echo "$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"
@@ -26989,20 +29272,20 @@ which seems to be undefined. Please make sure it is defined" >&2;}
#
if test x"$ac_file" != x-; then
{
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
} >"$ac_tmp/config.h" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+printf "%s\n" "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
mv "$ac_tmp/config.h" "$ac_file" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
fi
else
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
@@ -27022,7 +29305,7 @@ $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$_am_arg" : 'X\(//\)[^/]' \| \
X"$_am_arg" : 'X\(//\)$' \| \
X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$_am_arg" |
+printf "%s\n" X"$_am_arg" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -27042,8 +29325,8 @@ $as_echo X"$_am_arg" |
s/.*/./; q'`/stamp-h$_am_stamp_count
;;
- :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
-$as_echo "$as_me: executing $ac_file commands" >&6;}
+ :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+printf "%s\n" "$as_me: executing $ac_file commands" >&6;}
;;
esac
@@ -27069,7 +29352,7 @@ esac
for am_mf
do
# Strip MF so we end up with the name of the file.
- am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
+ am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'`
# Check whether this is an Automake generated Makefile which includes
# dependency-tracking related rules and includes.
# Grep'ing the whole file directly is not great: AIX grep has a line
@@ -27081,7 +29364,7 @@ $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$am_mf" : 'X\(//\)[^/]' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$am_mf" |
+printf "%s\n" X"$am_mf" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -27103,7 +29386,7 @@ $as_echo X"$am_mf" |
$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
X"$am_mf" : 'X\(//\)$' \| \
X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$am_mf" |
+printf "%s\n" X/"$am_mf" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -27128,10 +29411,12 @@ $as_echo X/"$am_mf" |
(exit $ac_status); } || am_rc=$?
done
if test $am_rc -ne 0; then
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$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. Try re-running configure with the
+ 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; }
@@ -27278,6 +29563,9 @@ to_host_file_cmd=$lt_cv_to_host_file_cmd
# convert \$build files to toolchain format.
to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+# A file(cmd) program that detects file types.
+FILECMD=$lt_FILECMD
+
# An object symbol dumper.
OBJDUMP=$lt_OBJDUMP
@@ -27302,8 +29590,11 @@ sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
# The archiver.
AR=$lt_AR
+# Flags to create an archive (by configure).
+lt_ar_flags=$lt_ar_flags
+
# Flags to create an archive.
-AR_FLAGS=$lt_AR_FLAGS
+AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"}
# How to feed a file listing to the archiver.
archiver_list_spec=$lt_archiver_list_spec
@@ -27685,6 +29976,7 @@ _LT_EOF
esac
+
ltmain=$ac_aux_dir/ltmain.sh
@@ -27692,7 +29984,7 @@ ltmain=$ac_aux_dir/ltmain.sh
# if finds mixed CR/LF and LF-only lines. Since sed operates in
# text mode, it properly converts lines to CR/LF. This bash problem
# is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
+ $SED '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
mv -f "$cfgfile" "$ofile" ||
@@ -27887,185 +30179,249 @@ if test "$no_create" != yes; then
$ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
-$as_echo "$as_me: " >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuration summary" >&5
-$as_echo "$as_me: Configuration summary" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: =====================" >&5
-$as_echo "$as_me: =====================" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
-$as_echo "$as_me: " >&6;}
-if test "x$ac_configure_args" != "x"; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5
+printf "%s\n" "$as_me: " >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuration summary" >&5
+printf "%s\n" "$as_me: Configuration summary" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: =====================" >&5
+printf "%s\n" "$as_me: =====================" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5
+printf "%s\n" "$as_me: " >&6;}
+if test "x$ac_configure_args" != "x"
+then :
summary_conf_opts=$ac_configure_args
-else
+else $as_nop
summary_conf_opts="(no options)"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: dnsdist configured with: $summary_conf_opts" >&5
-$as_echo "$as_me: dnsdist configured with: $summary_conf_opts" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
-$as_echo "$as_me: " >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: CC: $CC ($CCVERSION)" >&5
-$as_echo "$as_me: CC: $CC ($CCVERSION)" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: CXX: $CXX ($CXXVERSION)" >&5
-$as_echo "$as_me: CXX: $CXX ($CXXVERSION)" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: LD: $LD" >&5
-$as_echo "$as_me: LD: $LD" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: CFLAGS: $CFLAGS" >&5
-$as_echo "$as_me: CFLAGS: $CFLAGS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: CPPFLAGS: $CPPFLAGS" >&5
-$as_echo "$as_me: CPPFLAGS: $CPPFLAGS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: CXXFLAGS: $CXXFLAGS" >&5
-$as_echo "$as_me: CXXFLAGS: $CXXFLAGS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: LDFLAGS: $LDFLAGS" >&5
-$as_echo "$as_me: LDFLAGS: $LDFLAGS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: LIBS: $LIBS" >&5
-$as_echo "$as_me: LIBS: $LIBS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&5
-$as_echo "$as_me: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
-$as_echo "$as_me: " >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: Features enabled" >&5
-$as_echo "$as_me: Features enabled" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: ----------------" >&5
-$as_echo "$as_me: ----------------" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: Lua: $LUAPC" >&5
-$as_echo "$as_me: Lua: $LUAPC" >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: Protobuf: yes" >&5
-$as_echo "$as_me: Protobuf: yes" >&6;}
-if test "x$systemd" != "xn"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: yes" >&5
-$as_echo "$as_me: systemd: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: no" >&5
-$as_echo "$as_me: systemd: no" >&6;}
-
-fi
-if test "x$HAVE_IPCIPHER" = "x1"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: ipcipher: yes" >&5
-$as_echo "$as_me: ipcipher: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: ipcipher: no" >&5
-$as_echo "$as_me: ipcipher: no" >&6;}
-
-fi
-if test "x$LIBEDIT_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: libedit: yes" >&5
-$as_echo "$as_me: libedit: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: libedit: no" >&5
-$as_echo "$as_me: libedit: no" >&6;}
-
-fi
-if test "x$LIBSODIUM_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: libsodium: yes" >&5
-$as_echo "$as_me: libsodium: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: libsodium: no" >&5
-$as_echo "$as_me: libsodium: no" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: dnsdist configured with: $summary_conf_opts" >&5
+printf "%s\n" "$as_me: dnsdist configured with: $summary_conf_opts" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5
+printf "%s\n" "$as_me: " >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: CC: $CC ($CCVERSION)" >&5
+printf "%s\n" "$as_me: CC: $CC ($CCVERSION)" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: CXX: $CXX ($CXXVERSION)" >&5
+printf "%s\n" "$as_me: CXX: $CXX ($CXXVERSION)" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: LD: $LD" >&5
+printf "%s\n" "$as_me: LD: $LD" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: CFLAGS: $CFLAGS" >&5
+printf "%s\n" "$as_me: CFLAGS: $CFLAGS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: CPPFLAGS: $CPPFLAGS" >&5
+printf "%s\n" "$as_me: CPPFLAGS: $CPPFLAGS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: CXXFLAGS: $CXXFLAGS" >&5
+printf "%s\n" "$as_me: CXXFLAGS: $CXXFLAGS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: LDFLAGS: $LDFLAGS" >&5
+printf "%s\n" "$as_me: LDFLAGS: $LDFLAGS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: LIBS: $LIBS" >&5
+printf "%s\n" "$as_me: LIBS: $LIBS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&5
+printf "%s\n" "$as_me: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5
+printf "%s\n" "$as_me: " >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Features enabled" >&5
+printf "%s\n" "$as_me: Features enabled" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ----------------" >&5
+printf "%s\n" "$as_me: ----------------" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Lua: $LUAPC" >&5
+printf "%s\n" "$as_me: Lua: $LUAPC" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Protobuf: yes" >&5
+printf "%s\n" "$as_me: Protobuf: yes" >&6;}
+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
+printf "%s\n" "$as_me: systemd: no" >&6;}
+
+fi
+if test x"$BPF_LIBS" != "x" -a x"$XDP_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: AF_XDP/XSK: yes" >&5
+printf "%s\n" "$as_me: AF_XDP/XSK: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: AF_XDP/XSK: no" >&5
+printf "%s\n" "$as_me: AF_XDP/XSK: no" >&6;}
+
+fi
+if test "x$HAVE_IPCIPHER" = "x1"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ipcipher: yes" >&5
+printf "%s\n" "$as_me: ipcipher: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: ipcipher: no" >&5
+printf "%s\n" "$as_me: ipcipher: no" >&6;}
+
+fi
+if test "x$LIBEDIT_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libedit: yes" >&5
+printf "%s\n" "$as_me: libedit: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libedit: no" >&5
+printf "%s\n" "$as_me: libedit: no" >&6;}
+
+fi
+if test "x$LIBSODIUM_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libsodium: yes" >&5
+printf "%s\n" "$as_me: libsodium: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libsodium: no" >&5
+printf "%s\n" "$as_me: libsodium: no" >&6;}
+
+fi
+if test "x$enable_dnscrypt" != "xno"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNSCrypt: yes" >&5
+printf "%s\n" "$as_me: DNSCrypt: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNSCrypt: no" >&5
+printf "%s\n" "$as_me: DNSCrypt: no" >&6;}
+
+fi
+if test "x$FSTRM_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: dnstap: yes" >&5
+printf "%s\n" "$as_me: dnstap: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: dnstap: no" >&5
+printf "%s\n" "$as_me: dnstap: no" >&6;}
+
+fi
+if test "x$QUICHE_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: quiche: yes" >&5
+printf "%s\n" "$as_me: quiche: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: quiche: no" >&5
+printf "%s\n" "$as_me: quiche: no" >&6;}
+
+fi
+if test "x$RE2_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: re2: yes" >&5
+printf "%s\n" "$as_me: re2: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: re2: no" >&5
+printf "%s\n" "$as_me: re2: no" >&6;}
+
+fi
+if test "x$NET_SNMP_LIBS" != "x"
+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
+printf "%s\n" "$as_me: SNMP: no" >&6;}
+
+fi
+if test "x$enable_dns_over_tls" != "xno"
+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
+printf "%s\n" "$as_me: DNS over TLS: no" >&6;}
+
+fi
+if test "x$enable_dns_over_https" != "xno"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over HTTPS (DoH): yes" >&5
+printf "%s\n" "$as_me: DNS over HTTPS (DoH): yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over HTTPS (DoH): no" >&5
+printf "%s\n" "$as_me: DNS over HTTPS (DoH): no" >&6;}
fi
-if test "x$enable_dnscrypt" != "xno"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNSCrypt: yes" >&5
-$as_echo "$as_me: DNSCrypt: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNSCrypt: no" >&5
-$as_echo "$as_me: DNSCrypt: no" >&6;}
+if test "x$enable_dns_over_quic" != "xno"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over QUIC (DoQ): yes" >&5
+printf "%s\n" "$as_me: DNS over QUIC (DoQ): yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over QUIC (DoQ): no" >&5
+printf "%s\n" "$as_me: DNS over QUIC (DoQ): no" >&6;}
fi
-if test "x$FSTRM_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: dnstap: yes" >&5
-$as_echo "$as_me: dnstap: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: dnstap: no" >&5
-$as_echo "$as_me: dnstap: no" >&6;}
+if test "x$enable_dns_over_http3" != "xno"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over HTTP/3 (DoH3): yes" >&5
+printf "%s\n" "$as_me: DNS over HTTP/3 (DoH3): yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: DNS over HTTP/3 (DoH3): no" >&5
+printf "%s\n" "$as_me: DNS over HTTP/3 (DoH3): no" >&6;}
fi
-if test "x$RE2_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: re2: yes" >&5
-$as_echo "$as_me: re2: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: re2: no" >&5
-$as_echo "$as_me: re2: no" >&6;}
+if test "x$enable_dns_over_tls" != "xno"
+then :
-fi
-if test "x$NET_SNMP_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: SNMP: yes" >&5
-$as_echo "$as_me: SNMP: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: SNMP: no" >&5
-$as_echo "$as_me: SNMP: no" >&6;}
+ if test "x$GNUTLS_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: GnuTLS: yes" >&5
+printf "%s\n" "$as_me: GnuTLS: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: GnuTLS: no" >&5
+printf "%s\n" "$as_me: GnuTLS: no" >&6;}
fi
-if test "x$enable_dns_over_tls" != "xno"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNS over TLS: yes" >&5
-$as_echo "$as_me: DNS over TLS: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNS over TLS: no" >&5
-$as_echo "$as_me: DNS over TLS: no" >&6;}
fi
-if test "x$enable_dns_over_https" != "xno"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNS over HTTPS (DoH): yes" >&5
-$as_echo "$as_me: DNS over HTTPS (DoH): yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: DNS over HTTPS (DoH): no" >&5
-$as_echo "$as_me: DNS over HTTPS (DoH): no" >&6;}
+if test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"
+then :
-fi
-if test "x$enable_dns_over_tls" != "xno"; then :
-
- if test "x$GNUTLS_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: GnuTLS: yes" >&5
-$as_echo "$as_me: GnuTLS: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: GnuTLS: no" >&5
-$as_echo "$as_me: GnuTLS: no" >&6;}
+ if test "x$LIBSSL_LIBS" != "x"
+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
+printf "%s\n" "$as_me: OpenSSL: no" >&6;}
fi
fi
-if test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"; then :
-
- if test "x$LIBSSL_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL: yes" >&5
-$as_echo "$as_me: OpenSSL: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL: no" >&5
-$as_echo "$as_me: OpenSSL: no" >&6;}
+if test "x$LIBH2OEVLOOP_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: h2o-evloop: yes" >&5
+printf "%s\n" "$as_me: h2o-evloop: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: h2o-evloop: no" >&5
+printf "%s\n" "$as_me: h2o-evloop: no" >&6;}
fi
+if test "x$NGHTTP2_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: nghttp2: yes" >&5
+printf "%s\n" "$as_me: nghttp2: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: nghttp2: no" >&5
+printf "%s\n" "$as_me: nghttp2: no" >&6;}
fi
-if test "x$NGHTTP2_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: nghttp2: yes" >&5
-$as_echo "$as_me: nghttp2: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: nghttp2: no" >&5
-$as_echo "$as_me: nghttp2: no" >&6;}
+if test "x$CDB_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: cdb: yes" >&5
+printf "%s\n" "$as_me: cdb: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: cdb: no" >&5
+printf "%s\n" "$as_me: cdb: no" >&6;}
fi
-if test "x$CDB_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: cdb: yes" >&5
-$as_echo "$as_me: cdb: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: cdb: no" >&5
-$as_echo "$as_me: cdb: no" >&6;}
+if test "x$LMDB_LIBS" != "x"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: lmdb: yes" >&5
+printf "%s\n" "$as_me: lmdb: yes" >&6;}
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: lmdb: no" >&5
+printf "%s\n" "$as_me: lmdb: no" >&6;}
fi
-if test "x$LMDB_LIBS" != "x"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: lmdb: yes" >&5
-$as_echo "$as_me: lmdb: yes" >&6;}
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: lmdb: no" >&5
-$as_echo "$as_me: lmdb: no" >&6;}
-fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: " >&5
+printf "%s\n" "$as_me: " >&6;}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
-$as_echo "$as_me: " >&6;}
diff --git a/configure.ac b/configure.ac
index 8bda61b..5502b83 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([dnsdist], [1.8.3])
+AC_INIT([dnsdist], [1.9.3])
AM_INIT_AUTOMAKE([foreign tar-ustar dist-bzip2 no-dist-gzip parallel-tests 1.11 subdir-objects])
AM_SILENT_RULES([yes])
AC_CONFIG_MACRO_DIR([m4])
@@ -20,6 +20,7 @@ CFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -fvisibility=hidden
CXXFLAGS="-g -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -Wmissing-declarations -Wredundant-decls -fvisibility=hidden $CXXFLAGS"
PDNS_WITH_LIBSODIUM
+PDNS_WITH_QUICHE
PDNS_CHECK_DNSTAP([auto])
PDNS_CHECK_RAGEL([dnslabeltext.cc], [www.dnsdist.org])
PDNS_WITH_LIBEDIT
@@ -35,9 +36,11 @@ AC_FUNC_STRERROR_R
BOOST_REQUIRE([1.42])
PDNS_ENABLE_UNIT_TESTS
+PDNS_ENABLE_FUZZ_TARGETS
PDNS_WITH_RE2
DNSDIST_ENABLE_DNSCRYPT
PDNS_WITH_EBPF
+PDNS_WITH_XSK
PDNS_WITH_NET_SNMP
PDNS_WITH_LIBCAP
@@ -48,11 +51,15 @@ PDNS_WITH_SERVICE_USER([dnsdist])
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 getrandom])
+AC_CHECK_FUNCS_ONCE([localtime_r gmtime_r])
+AC_CHECK_FUNCS_ONCE([getrandom getentropy arc4random arc4random_uniform arc4random_buf])
AC_SUBST([YAHTTP_CFLAGS], ['-I$(top_srcdir)/ext/yahttp'])
AC_SUBST([YAHTTP_LIBS], ['$(top_builddir)/ext/yahttp/yahttp/libyahttp.la'])
AC_SUBST([IPCRYPT_CFLAGS], ['-I$(top_srcdir)/ext/ipcrypt'])
AC_SUBST([IPCRYPT_LIBS], ['$(top_builddir)/ext/ipcrypt/libipcrypt.la'])
+AC_SUBST([ARC4RANDOM_LIBS], ['$(top_builddir)/ext/arc4random/libarc4random.la'])
+
+AC_CHECK_HEADERS([sys/random.h])
PDNS_WITH_LUA([mandatory])
AS_IF([test "x$LUAPC" = "xluajit"], [
@@ -62,10 +69,12 @@ AS_IF([test "x$LUAPC" = "xluajit"], [
])
PDNS_CHECK_LUA_HPP
+AM_CONDITIONAL([HAVE_CDB], [false])
AM_CONDITIONAL([HAVE_GNUTLS], [false])
+AM_CONDITIONAL([HAVE_LIBH2OEVLOOP], [false])
AM_CONDITIONAL([HAVE_LIBSSL], [false])
AM_CONDITIONAL([HAVE_LMDB], [false])
-AM_CONDITIONAL([HAVE_CDB], [false])
+AM_CONDITIONAL([HAVE_NGHTTP2], [false])
PDNS_CHECK_LIBCRYPTO
@@ -73,31 +82,49 @@ DNSDIST_ENABLE_TLS_PROVIDERS
PDNS_ENABLE_DNS_OVER_TLS
DNSDIST_ENABLE_DNS_OVER_HTTPS
+DNSDIST_ENABLE_DNS_OVER_QUIC
+DNSDIST_ENABLE_DNS_OVER_HTTP3
-AS_IF([test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"], [
+AS_IF([test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno" -o "x$enable_dns_over_quic" != "xno" ], [
PDNS_WITH_LIBSSL
+ AS_IF([test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xno"], [
+ PDNS_WITH_GNUTLS
+ ])
])
AS_IF([test "x$enable_dns_over_tls" != "xno"], [
- PDNS_WITH_GNUTLS
-
AS_IF([test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"], [
AC_MSG_ERROR([DNS over TLS support requested but neither GnuTLS nor OpenSSL are available])
])
])
-PDNS_CHECK_LIBH2OEVLOOP
AS_IF([test "x$enable_dns_over_https" != "xno"], [
- AS_IF([test "x$HAVE_LIBH2OEVLOOP" != "x1"], [
- AC_MSG_ERROR([DNS over HTTPS support requested but libh2o-evloop was not found])
+ PDNS_WITH_NGHTTP2
+ PDNS_WITH_LIBH2OEVLOOP
+
+ AS_IF([test "x$HAVE_LIBH2OEVLOOP" != "x1" -a "x$HAVE_NGHTTP2" != "x1" ], [
+ AC_MSG_ERROR([DNS over HTTPS support requested but neither libh2o-evloop nor nghttp2 was not found])
])
+ AS_IF([test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"], [
+ AC_MSG_ERROR([DNS over HTTPS support requested but neither GnuTLS nor OpenSSL are available])
+ ])
+])
+
+AS_IF([test "x$enable_dns_over_quic" != "xno"], [
+ AS_IF([test "x$HAVE_QUICHE" != "x1"], [
+ AC_MSG_ERROR([DNS over QUIC support requested but quiche was not found])
+ ])
AS_IF([test "x$HAVE_LIBSSL" != "x1"], [
- AC_MSG_ERROR([DNS over HTTPS support requested but OpenSSL was not found])
+ AC_MSG_ERROR([DNS over QUIC support requested but OpenSSL is not available])
])
])
-PDNS_WITH_NGHTTP2
+AS_IF([test "x$enable_dns_over_http3" != "xno"], [
+ AS_IF([test "x$HAVE_QUICHE" != "x1"], [
+ AC_MSG_ERROR([DNS over HTTP/3 support requested but quiche was not found])
+ ])
+])
DNSDIST_WITH_CDB
PDNS_CHECK_LMDB
@@ -125,6 +152,7 @@ PDNS_INIT_AUTO_VARS
PDNS_ENABLE_SANITIZERS
PDNS_ENABLE_LTO
+PDNS_ENABLE_COVERAGE
PDNS_CHECK_PYTHON_VENV
@@ -156,6 +184,7 @@ AS_IF([test "x$PACKAGEVERSION" != "x"],
)
AC_CONFIG_FILES([Makefile
+ ext/arc4random/Makefile
ext/yahttp/Makefile
ext/yahttp/yahttp/Makefile
ext/ipcrypt/Makefile])
@@ -190,6 +219,10 @@ AS_IF([test "x$systemd" != "xn"],
[AC_MSG_NOTICE([systemd: yes])],
[AC_MSG_NOTICE([systemd: no])]
)
+AS_IF([test x"$BPF_LIBS" != "x" -a x"$XDP_LIBS" != "x"],
+ [AC_MSG_NOTICE([AF_XDP/XSK: yes])],
+ [AC_MSG_NOTICE([AF_XDP/XSK: no])]
+)
AS_IF([test "x$HAVE_IPCIPHER" = "x1"],
[AC_MSG_NOTICE([ipcipher: yes])],
[AC_MSG_NOTICE([ipcipher: no])]
@@ -210,6 +243,10 @@ AS_IF([test "x$FSTRM_LIBS" != "x"],
[AC_MSG_NOTICE([dnstap: yes])],
[AC_MSG_NOTICE([dnstap: no])]
)
+AS_IF([test "x$QUICHE_LIBS" != "x"],
+ [AC_MSG_NOTICE([quiche: yes])],
+ [AC_MSG_NOTICE([quiche: no])]
+)
AS_IF([test "x$RE2_LIBS" != "x"],
[AC_MSG_NOTICE([re2: yes])],
[AC_MSG_NOTICE([re2: no])]
@@ -226,6 +263,14 @@ AS_IF([test "x$enable_dns_over_https" != "xno"],
[AC_MSG_NOTICE([DNS over HTTPS (DoH): yes])],
[AC_MSG_NOTICE([DNS over HTTPS (DoH): no])]
)
+AS_IF([test "x$enable_dns_over_quic" != "xno"],
+ [AC_MSG_NOTICE([DNS over QUIC (DoQ): yes])],
+ [AC_MSG_NOTICE([DNS over QUIC (DoQ): no])]
+)
+AS_IF([test "x$enable_dns_over_http3" != "xno"],
+ [AC_MSG_NOTICE([DNS over HTTP/3 (DoH3): yes])],
+ [AC_MSG_NOTICE([DNS over HTTP/3 (DoH3): no])]
+)
AS_IF([test "x$enable_dns_over_tls" != "xno"], [
AS_IF([test "x$GNUTLS_LIBS" != "x"],
[AC_MSG_NOTICE([GnuTLS: yes])],
@@ -238,6 +283,10 @@ AS_IF([test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xn
[AC_MSG_NOTICE([OpenSSL: no])]
)]
)
+AS_IF([test "x$LIBH2OEVLOOP_LIBS" != "x"],
+ [AC_MSG_NOTICE([h2o-evloop: yes])],
+ [AC_MSG_NOTICE([h2o-evloop: no])]
+)
AS_IF([test "x$NGHTTP2_LIBS" != "x"],
[AC_MSG_NOTICE([nghttp2: yes])],
[AC_MSG_NOTICE([nghttp2: no])]
diff --git a/coverage.cc b/coverage.cc
new file mode 100644
index 0000000..c996207
--- /dev/null
+++ b/coverage.cc
@@ -0,0 +1,50 @@
+/*
+ * 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"
+#include "coverage.hh"
+
+#ifdef COVERAGE
+extern "C"
+{
+#ifdef CLANG_COVERAGE
+ // NOLINTNEXTLINE(bugprone-reserved-identifier): not ours
+ int __llvm_profile_write_file(void);
+#else /* CLANG_COVERAGE */
+ // NOLINTNEXTLINE(bugprone-reserved-identifier): not ours
+ void __gcov_dump(void);
+#endif /* CLANG_COVERAGE */
+}
+#endif /* COVERAGE */
+
+namespace pdns::coverage
+{
+void dumpCoverageData()
+{
+#ifdef COVERAGE
+#ifdef CLANG_COVERAGE
+ __llvm_profile_write_file();
+#else /* CLANG_COVERAGE */
+ __gcov_dump();
+#endif /* CLANG_COVERAGE */
+#endif /* COVERAGE */
+}
+}
diff --git a/coverage.hh b/coverage.hh
new file mode 100644
index 0000000..960f28c
--- /dev/null
+++ b/coverage.hh
@@ -0,0 +1,27 @@
+/*
+ * 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
+
+namespace pdns::coverage
+{
+void dumpCoverageData();
+}
diff --git a/credentials.cc b/credentials.cc
index 137f1b7..ec11732 100644
--- a/credentials.cc
+++ b/credentials.cc
@@ -40,6 +40,7 @@
#include <unistd.h>
#include "base64.hh"
+#include "dns_random.hh"
#include "credentials.hh"
#include "misc.hh"
@@ -68,7 +69,7 @@ SensitiveData::SensitiveData(std::string&& data) :
#endif
}
-SensitiveData& SensitiveData::operator=(SensitiveData&& rhs)
+SensitiveData& SensitiveData::operator=(SensitiveData&& rhs) noexcept
{
d_data = std::move(rhs.d_data);
rhs.clear();
@@ -96,7 +97,7 @@ void SensitiveData::clear()
d_data.clear();
}
-static std::string hashPasswordInternal(const std::string& password, const std::string& salt, uint64_t workFactor, uint64_t parallelFactor, uint64_t blockSize)
+static std::string hashPasswordInternal([[maybe_unused]] const std::string& password, [[maybe_unused]] const std::string& salt, [[maybe_unused]] uint64_t workFactor, [[maybe_unused]] uint64_t parallelFactor, [[maybe_unused]] uint64_t blockSize)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
auto pctx = std::unique_ptr<EVP_PKEY_CTX, void (*)(EVP_PKEY_CTX*)>(EVP_PKEY_CTX_new_id(EVP_PKEY_SCRYPT, nullptr), EVP_PKEY_CTX_free);
@@ -165,7 +166,7 @@ static std::string generateRandomSalt()
#endif
}
-std::string hashPassword(const std::string& password, uint64_t workFactor, uint64_t parallelFactor, uint64_t blockSize)
+std::string hashPassword([[maybe_unused]] const std::string& password, [[maybe_unused]] uint64_t workFactor, [[maybe_unused]] uint64_t parallelFactor, [[maybe_unused]] uint64_t blockSize)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
if (workFactor == 0) {
@@ -197,7 +198,7 @@ std::string hashPassword(const std::string& password, uint64_t workFactor, uint6
#endif
}
-std::string hashPassword(const std::string& password)
+std::string hashPassword([[maybe_unused]] const std::string& password)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
return hashPassword(password, CredentialsHolder::s_defaultWorkFactor, CredentialsHolder::s_defaultParallelFactor, CredentialsHolder::s_defaultBlockSize);
@@ -206,7 +207,7 @@ std::string hashPassword(const std::string& password)
#endif
}
-bool verifyPassword(const std::string& binaryHash, const std::string& salt, uint64_t workFactor, uint64_t parallelFactor, uint64_t blockSize, const std::string& binaryPassword)
+bool verifyPassword([[maybe_unused]] const std::string& binaryHash, [[maybe_unused]] const std::string& salt, [[maybe_unused]] uint64_t workFactor, [[maybe_unused]] uint64_t parallelFactor, [[maybe_unused]] uint64_t blockSize, [[maybe_unused]] const std::string& binaryPassword)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
auto expected = hashPasswordInternal(binaryPassword, salt, workFactor, parallelFactor, blockSize);
@@ -217,7 +218,7 @@ bool verifyPassword(const std::string& binaryHash, const std::string& salt, uint
}
/* parse a hashed password in PHC string format */
-static void parseHashed(const std::string& hash, std::string& salt, std::string& hashedPassword, uint64_t& workFactor, uint64_t& parallelFactor, uint64_t& blockSize)
+static void parseHashed([[maybe_unused]] const std::string& hash, [[maybe_unused]] std::string& salt, [[maybe_unused]] std::string& hashedPassword, [[maybe_unused]] uint64_t& workFactor, [[maybe_unused]] uint64_t& parallelFactor, [[maybe_unused]] uint64_t& blockSize)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
auto parametersEnd = hash.find('$', pwhash_prefix.size());
@@ -282,7 +283,7 @@ static void parseHashed(const std::string& hash, std::string& salt, std::string&
#endif
}
-bool verifyPassword(const std::string& hash, const std::string& password)
+bool verifyPassword(const std::string& hash, [[maybe_unused]] const std::string& password)
{
if (!isPasswordHashed(hash)) {
return false;
@@ -304,7 +305,7 @@ bool verifyPassword(const std::string& hash, const std::string& password)
#endif
}
-bool isPasswordHashed(const std::string& password)
+bool isPasswordHashed([[maybe_unused]] const std::string& password)
{
#if !defined(DISABLE_HASHED_CREDENTIALS) && defined(HAVE_EVP_PKEY_CTX_SET1_SCRYPT_SALT)
if (password.size() < pwhash_prefix_size || password.size() > pwhash_max_size) {
@@ -373,7 +374,7 @@ CredentialsHolder::CredentialsHolder(std::string&& password, bool hashPlaintext)
}
if (!d_isHashed) {
- d_fallbackHashPerturb = random();
+ d_fallbackHashPerturb = dns_random_uint32();
d_fallbackHash = burtle(reinterpret_cast<const unsigned char*>(d_credentials.getString().data()), d_credentials.getString().size(), d_fallbackHashPerturb);
}
}
diff --git a/credentials.hh b/credentials.hh
index 6e59c6b..6762b1a 100644
--- a/credentials.hh
+++ b/credentials.hh
@@ -29,7 +29,7 @@ class SensitiveData
public:
SensitiveData(size_t bytes);
SensitiveData(std::string&& data);
- SensitiveData& operator=(SensitiveData&&);
+ SensitiveData& operator=(SensitiveData&&) noexcept;
~SensitiveData();
void clear();
diff --git a/delaypipe.cc b/delaypipe.cc
index be363d6..ada096c 100644
--- a/delaypipe.cc
+++ b/delaypipe.cc
@@ -28,34 +28,23 @@
template<class T>
ObjectPipe<T>::ObjectPipe()
{
- if(pipe(d_fds))
- unixDie("pipe");
-}
-
-template<class T>
-ObjectPipe<T>::~ObjectPipe()
-{
- ::close(d_fds[0]);
- if(d_fds[1] >= 0)
- ::close(d_fds[1]);
+ auto [sender, receiver] = pdns::channel::createObjectQueue<T>(pdns::channel::SenderBlockingMode::SenderBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0, false);
+ d_sender = std::move(sender);
+ d_receiver = std::move(receiver);
}
template<class T>
void ObjectPipe<T>::close()
{
- if(d_fds[1] < 0)
- return;
- ::close(d_fds[1]); // the writing side
- d_fds[1]=-1;
+ d_sender.close();
}
template<class T>
void ObjectPipe<T>::write(T& t)
{
- auto ptr = new T(t);
- if(::write(d_fds[1], &ptr, sizeof(ptr)) != sizeof(ptr)) {
- delete ptr;
- unixDie("write");
+ auto ptr = std::make_unique<T>(t);
+ if (!d_sender.send(std::move(ptr))) {
+ unixDie("writing to the DelayPipe");
}
}
@@ -63,7 +52,7 @@ template<class T>
int ObjectPipe<T>::readTimeout(T* t, double msec)
{
while (true) {
- int ret = waitForData(d_fds[0], 0, 1000*msec);
+ int ret = waitForData(d_receiver.getDescriptor(), 0, 1000*msec);
if (ret < 0) {
if (errno == EINTR) {
continue;
@@ -74,26 +63,21 @@ int ObjectPipe<T>::readTimeout(T* t, double msec)
return -1;
}
- T* ptr = nullptr;
- ret = ::read(d_fds[0], &ptr, sizeof(ptr)); // this is BLOCKING!
-
- if (ret < 0) {
- if (errno == EINTR) {
+ try {
+ auto tmp = d_receiver.receive();
+ if (!tmp) {
+ if (d_receiver.isClosed()) {
+ return 0;
+ }
continue;
}
- unixDie("read");
- }
- else if (ret == 0) {
- return false;
- }
- if (ret != sizeof(ptr)) {
- throw std::runtime_error("Partial read, should not happen 2");
+ *t = **tmp;
+ return 1;
+ }
+ catch (const std::exception& e) {
+ throw std::runtime_error("reading from the delay pipe: " + std::string(e.what()));
}
-
- *t = *ptr;
- delete ptr;
- return 1;
}
}
@@ -149,7 +133,7 @@ void DelayPipe<T>::worker()
The other special case is that the first we have to do.. is in the past, so we need to do it
immediately. */
-
+
double delay=-1; // infinite
struct timespec now;
if(!d_work.empty()) {
@@ -160,7 +144,7 @@ void DelayPipe<T>::worker()
}
}
if(delay != 0 ) {
- int ret = d_pipe.readTimeout(&c, delay);
+ int ret = d_pipe.readTimeout(&c, delay);
if(ret > 0) { // we got an object
d_work.emplace(c.when, c.what);
}
diff --git a/delaypipe.hh b/delaypipe.hh
index ad1626a..b12fd50 100644
--- a/delaypipe.hh
+++ b/delaypipe.hh
@@ -20,10 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
-#include <map>
#include <time.h>
#include <thread>
+#include "channel.hh"
+
/**
General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
The implementation is that submitter threads create an object that represents the work, and it gets sent over a pipe
@@ -41,12 +42,12 @@ class ObjectPipe
{
public:
ObjectPipe();
- ~ObjectPipe();
void write(T& t);
int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely long. msec==0 = undefined
void close();
private:
- int d_fds[2];
+ pdns::channel::Sender<T> d_sender;
+ pdns::channel::Receiver<T> d_receiver;
};
template<class T>
diff --git a/depcomp b/depcomp
index 65cbf70..715e343 100755
--- a/depcomp
+++ b/depcomp
@@ -3,7 +3,7 @@
scriptversion=2018-03-07.03; # UTC
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 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
diff --git a/dns.cc b/dns.cc
index d9fb509..99bbd72 100644
--- a/dns.cc
+++ b/dns.cc
@@ -71,8 +71,9 @@ static const std::array<std::string, 10> rcodes_short_s = {
};
std::string RCode::to_s(uint8_t rcode) {
- if (rcode > 0xF)
+ if (rcode > 0xF) {
return std::string("ErrOutOfRange");
+ }
return ERCode::to_s(rcode);
}
@@ -83,9 +84,10 @@ std::string RCode::to_short_s(uint8_t rcode) {
return rcodes_short_s.at(rcode);
}
-std::string ERCode::to_s(uint8_t rcode) {
- if (rcode > RCode::rcodes_s.size()-1)
+std::string ERCode::to_s(uint16_t rcode) {
+ if (rcode >= RCode::rcodes_s.size()) {
return std::string("Err#")+std::to_string(rcode);
+ }
return RCode::rcodes_s.at(rcode);
}
diff --git a/dns.hh b/dns.hh
index ef44cf8..c95a62f 100644
--- a/dns.hh
+++ b/dns.hh
@@ -32,7 +32,7 @@ struct DNSRecord;
class RCode
{
public:
- enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10};
+ 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);
const static std::array<std::string, 24> rcodes_s;
@@ -41,14 +41,14 @@ public:
class ERCode
{
public:
- enum rcodes_ { BADVERS=16, BADSIG=16, BADKEY=17, BADTIME=18, BADMODE=19, BADNAME=20, BADALG=21, BADTRUNC=22, BADCOOKIE=23 };
- static std::string to_s(uint8_t rcode);
+ 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);
};
class Opcode
{
public:
- enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
+ enum opcodes_ : uint8_t { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
static std::string to_s(uint8_t opcode);
};
@@ -56,13 +56,18 @@ public:
class DNSResourceRecord
{
public:
- DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(-1), qclass(1), scopeMask(0), auth(1), disabled(0) {};
- static DNSResourceRecord fromWire(const DNSRecord& d);
+ static DNSResourceRecord fromWire(const DNSRecord& wire);
- enum Place : uint8_t {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning within, say, a DNSPacket
+ enum Place : uint8_t
+ {
+ QUESTION = 0,
+ ANSWER = 1,
+ AUTHORITY = 2,
+ ADDITIONAL = 3
+ }; //!< Type describing the positioning within, say, a DNSPacket
void setContent(const string& content);
- string getZoneRepresentation(bool noDot=false) const;
+ [[nodiscard]] string getZoneRepresentation(bool noDot = false) const;
// data
DNSName qname; //!< the name of this record, for example: www.powerdns.com
@@ -72,27 +77,29 @@ public:
// 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{}; //!< For autocalculating SOA serial numbers - the backend needs to fill this in
- uint32_t ttl; //!< Time To Live of this record
- uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG
+ 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; //!< If a backend implements this, the domain_id of the zone this record is in
+ int domain_id{-1}; //!< 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; //!< class of this record
+ uint16_t qclass{1}; //!< class of this record
- uint8_t scopeMask;
- bool auth;
- bool disabled;
+ uint8_t scopeMask{};
+ bool auth{true};
+ bool disabled{};
bool operator==(const DNSResourceRecord& rhs);
- bool operator<(const DNSResourceRecord &b) const
+ bool operator<(const DNSResourceRecord& other) const
{
- if(qname < b.qname)
+ if (qname < other.qname) {
return true;
- if(qname == b.qname)
- return(content < b.content);
+ }
+ if (qname == other.qname) {
+ return (content < other.content);
+ }
return false;
}
};
@@ -120,7 +127,7 @@ static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4");
#elif __linux__ || __GNU__
# include <endian.h>
-#else // with thanks to <arpa/nameser.h>
+#else // with thanks to <arpa/nameser.h>
# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
@@ -151,7 +158,7 @@ static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4");
#endif
struct dnsheader {
- unsigned id :16; /* query identification number */
+ uint16_t id; /* query identification number */
#if BYTE_ORDER == BIG_ENDIAN
/* fields in third byte */
unsigned qr: 1; /* response flag */
@@ -180,10 +187,10 @@ struct dnsheader {
unsigned ra :1; /* recursion available */
#endif
/* remaining bytes */
- unsigned qdcount :16; /* number of question entries */
- unsigned ancount :16; /* number of answer entries */
- unsigned nscount :16; /* number of authority entries */
- unsigned arcount :16; /* number of resource entries */
+ uint16_t qdcount; /* number of question entries */
+ uint16_t ancount; /* number of answer entries */
+ uint16_t nscount; /* number of authority entries */
+ uint16_t arcount; /* number of resource entries */
};
static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12");
@@ -191,10 +198,15 @@ static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12");
class dnsheader_aligned
{
public:
+ static bool isMemoryAligned(const void* mem)
+ {
+ return reinterpret_cast<uintptr_t>(mem) % sizeof(uint32_t) == 0; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+ }
+
dnsheader_aligned(const void* mem)
{
- if (reinterpret_cast<uintptr_t>(mem) % sizeof(uint32_t) == 0) {
- d_p = reinterpret_cast<const dnsheader*>(mem);
+ if (isMemoryAligned(mem)) {
+ d_p = reinterpret_cast<const dnsheader*>(mem); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
}
else {
memcpy(&d_h, mem, sizeof(dnsheader));
@@ -202,19 +214,36 @@ public:
}
}
- const dnsheader* get() const
+ [[nodiscard]] const dnsheader* get() const
+ {
+ return d_p;
+ }
+
+ [[nodiscard]] const dnsheader& operator*() const
+ {
+ return *d_p;
+ }
+
+ [[nodiscard]] const dnsheader* operator->() const
{
return d_p;
}
private:
- dnsheader d_h;
- const dnsheader *d_p;
+ dnsheader d_h{};
+ const dnsheader* d_p{};
};
-inline uint16_t * getFlagsFromDNSHeader(struct dnsheader * dh)
+inline uint16_t* getFlagsFromDNSHeader(dnsheader* dh)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<uint16_t*>(reinterpret_cast<char*>(dh) + sizeof(uint16_t));
+}
+
+inline const uint16_t * getFlagsFromDNSHeader(const dnsheader* dh)
{
- return (uint16_t*) (((char *) dh) + sizeof(uint16_t));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<const uint16_t*>(reinterpret_cast<const char*>(dh) + sizeof(uint16_t));
}
#define DNS_TYPE_SIZE (2)
diff --git a/dns_random.hh b/dns_random.hh
index 5c5e441..c3bd314 100644
--- a/dns_random.hh
+++ b/dns_random.hh
@@ -24,54 +24,69 @@
#include <limits>
#include <string>
-void dns_random_init(const std::string& data = "", bool force_reinit = false);
-uint32_t dns_random(uint32_t n);
-uint16_t dns_random_uint16();
+#include <ext/arc4random/arc4random.hh>
-namespace pdns {
- struct dns_random_engine {
+inline uint32_t dns_random(uint32_t upper_bound)
+{
+ return arc4random_uniform(upper_bound);
+}
+
+inline uint32_t dns_random_uint32()
+{
+ return arc4random();
+}
- typedef uint32_t result_type;
+inline uint16_t dns_random_uint16()
+{
+ return arc4random() & 0xffff;
+}
- static constexpr result_type min()
- {
- return 0;
- }
+namespace pdns
+{
+struct dns_random_engine
+{
- static constexpr result_type max()
- {
- return std::numeric_limits<result_type>::max() - 1;
- }
+ using result_type = uint32_t;
+
+ static constexpr result_type min()
+ {
+ return 0;
+ }
- result_type operator()()
- {
- return dns_random(std::numeric_limits<result_type>::max());
- }
- };
+ static constexpr result_type max()
+ {
+ return std::numeric_limits<result_type>::max();
+ }
- /* minimum value that a PRNG should return for this upper bound to avoid a modulo bias */
- inline unsigned int random_minimum_acceptable_value(uint32_t upper_bound)
+ result_type operator()()
{
- /* Parts of this code come from arc4random_uniform */
- /* To avoid "modulo bias" for some methods, calculate
- minimum acceptable value for random number to improve
- uniformity.
+ return dns_random_uint32();
+ }
+};
+
+/* minimum value that a PRNG should return for this upper bound to avoid a modulo bias */
+inline unsigned int random_minimum_acceptable_value(uint32_t upper_bound)
+{
+ /* Parts of this code come from arc4random_uniform */
+ /* To avoid "modulo bias" for some methods, calculate
+ minimum acceptable value for random number to improve
+ uniformity.
- On applicable rngs, we loop until the rng spews out
- value larger than min, and then take modulo out of that.
- */
- unsigned int min;
+ On applicable rngs, we loop until the rng spews out
+ value larger than min, and then take modulo out of that.
+ */
+ unsigned int min = 0;
#if (ULONG_MAX > 0xffffffffUL)
- min = 0x100000000UL % upper_bound;
+ min = 0x100000000UL % upper_bound;
#else
- /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
- if (upper_bound > 0x80000000)
- min = 1 + ~upper_bound; /* 2**32 - upper_bound */
- else {
- /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
- min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
- }
-#endif
- return min;
+ /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+ if (upper_bound > 0x80000000)
+ min = 1 + ~upper_bound; /* 2**32 - upper_bound */
+ else {
+ /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
}
+#endif
+ return min;
+}
}
diff --git a/dnscrypt.cc b/dnscrypt.cc
index 6db8613..9be46d7 100644
--- a/dnscrypt.cc
+++ b/dnscrypt.cc
@@ -399,9 +399,10 @@ bool DNSCryptQuery::parsePlaintextQuery(const PacketBuffer& packet)
return false;
}
- const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet.data());
- if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
+ const dnsheader_aligned dh(packet.data());
+ if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || static_cast<uint8_t>(dh->opcode) != Opcode::Query) {
return false;
+ }
unsigned int qnameWireLength;
uint16_t qtype, qclass;
@@ -418,7 +419,7 @@ bool DNSCryptQuery::parsePlaintextQuery(const PacketBuffer& packet)
return false;
}
- d_qname = qname;
+ d_qname = std::move(qname);
d_id = dh->id;
d_valid = true;
diff --git a/dnscrypt.hh b/dnscrypt.hh
index 356b4c4..a42be6a 100644
--- a/dnscrypt.hh
+++ b/dnscrypt.hh
@@ -21,6 +21,7 @@
*/
#pragma once
#include "config.h"
+#include <memory>
#ifndef HAVE_DNSCRYPT
@@ -43,7 +44,6 @@ private:
#else /* HAVE_DNSCRYPT */
-#include <memory>
#include <string>
#include <vector>
#include <arpa/inet.h>
diff --git a/dnsdist-async.cc b/dnsdist-async.cc
index e1acef8..9cb96d8 100644
--- a/dnsdist-async.cc
+++ b/dnsdist-async.cc
@@ -27,28 +27,19 @@
namespace dnsdist
{
-AsynchronousHolder::AsynchronousHolder(bool failOpen) :
- d_data(std::make_shared<Data>())
+AsynchronousHolder::Data::Data(bool failOpen) :
+ d_failOpen(failOpen)
{
- d_data->d_failOpen = failOpen;
-
- int fds[2] = {-1, -1};
- if (pipe(fds) < 0) {
- throw std::runtime_error("Error creating the AsynchronousHolder pipe: " + stringerror());
- }
-
- for (size_t idx = 0; idx < (sizeof(fds) / sizeof(*fds)); idx++) {
- if (!setNonBlocking(fds[idx])) {
- int err = errno;
- close(fds[0]);
- close(fds[1]);
- throw std::runtime_error("Error setting the AsynchronousHolder pipe non-blocking: " + stringerror(err));
- }
- }
-
- d_data->d_notifyPipe = FDWrapper(fds[1]);
- d_data->d_watchPipe = FDWrapper(fds[0]);
+ auto [notifier, waiter] = pdns::channel::createNotificationQueue(true);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer): how I am supposed to do that?
+ d_waiter = std::move(waiter);
+ // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer): how I am supposed to do that?
+ d_notifier = std::move(notifier);
+}
+AsynchronousHolder::AsynchronousHolder(bool failOpen) :
+ d_data(std::make_shared<Data>(failOpen))
+{
std::thread main([data = this->d_data] { mainThread(data); });
main.detach();
}
@@ -64,49 +55,19 @@ AsynchronousHolder::~AsynchronousHolder()
bool AsynchronousHolder::notify() const
{
- const char data = 0;
- bool failed = false;
- do {
- auto written = write(d_data->d_notifyPipe.getHandle(), &data, sizeof(data));
- if (written == 0) {
- break;
- }
- if (written > 0 && static_cast<size_t>(written) == sizeof(data)) {
- return true;
- }
- if (errno != EINTR) {
- failed = true;
- }
- } while (!failed);
-
- return false;
+ return d_data->d_notifier.notify();
}
-bool AsynchronousHolder::wait(const AsynchronousHolder::Data& data, FDMultiplexer& mplexer, std::vector<int>& readyFDs, int atMostMs)
+bool AsynchronousHolder::wait(AsynchronousHolder::Data& data, FDMultiplexer& mplexer, std::vector<int>& readyFDs, int atMostMs)
{
readyFDs.clear();
mplexer.getAvailableFDs(readyFDs, atMostMs);
- if (readyFDs.size() == 0) {
+ if (readyFDs.empty()) {
/* timeout */
return true;
}
- while (true) {
- /* we might have been notified several times, let's read
- as much as possible before returning */
- char dummy = 0;
- auto got = read(data.d_watchPipe.getHandle(), &dummy, sizeof(dummy));
- if (got == 0) {
- break;
- }
- if (got > 0 && static_cast<size_t>(got) != sizeof(dummy)) {
- continue;
- }
- if (got == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- break;
- }
- }
-
+ data.d_waiter.clear();
return false;
}
@@ -120,14 +81,17 @@ void AsynchronousHolder::stop()
notify();
}
+// NOLINTNEXTLINE(performance-unnecessary-value-param): this is a long-lived thread, and we want to make sure the reference count of the shared pointer has been increased
void AsynchronousHolder::mainThread(std::shared_ptr<Data> data)
{
setThreadName("dnsdist/async");
- struct timeval now;
+ struct timeval now
+ {
+ };
std::list<std::pair<uint16_t, std::unique_ptr<CrossProtocolQuery>>> expiredEvents;
auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(1));
- mplexer->addReadFD(data->d_watchPipe.getHandle(), [](int, FDMultiplexer::funcparam_t&) {});
+ mplexer->addReadFD(data->d_waiter.getDescriptor(), [](int, FDMultiplexer::funcparam_t&) {});
std::vector<int> readyFDs;
while (true) {
@@ -148,7 +112,7 @@ void AsynchronousHolder::mainThread(std::shared_ptr<Data> data)
}
else {
auto remainingUsec = uSec(next - now);
- timeout = std::round(remainingUsec / 1000.0);
+ timeout = static_cast<int>(std::round(static_cast<double>(remainingUsec) / 1000.0));
if (timeout == 0 && remainingUsec > 0) {
/* if we have less than 1 ms, let's wait at least 1 ms */
timeout = 1;
@@ -173,7 +137,8 @@ void AsynchronousHolder::mainThread(std::shared_ptr<Data> data)
vinfolog("Asynchronous query %d has expired at %d.%d, notifying the sender", queryID, now.tv_sec, now.tv_usec);
auto sender = query->getTCPQuerySender();
if (sender) {
- sender->notifyIOError(std::move(query->query.d_idstate), now);
+ TCPResponse tresponse(std::move(query->query));
+ sender->notifyIOError(now, std::move(tresponse));
}
}
else {
@@ -213,25 +178,27 @@ std::unique_ptr<CrossProtocolQuery> AsynchronousHolder::get(uint16_t asyncID, ui
{
/* no need to notify, worst case the thread wakes up for nothing because this was the next TTD */
auto content = d_data->d_content.lock();
- auto it = content->find(std::tie(queryID, asyncID));
- if (it == content->end()) {
- struct timeval now;
+ auto contentIt = content->find(std::tie(queryID, asyncID));
+ if (contentIt == content->end()) {
+ struct timeval now
+ {
+ };
gettimeofday(&now, nullptr);
vinfolog("Asynchronous object %d not found at %d.%d", queryID, now.tv_sec, now.tv_usec);
return nullptr;
}
- auto result = std::move(it->d_query);
- content->erase(it);
+ auto result = std::move(contentIt->d_query);
+ content->erase(contentIt);
return result;
}
void AsynchronousHolder::pickupExpired(content_t& content, const struct timeval& now, std::list<std::pair<uint16_t, std::unique_ptr<CrossProtocolQuery>>>& events)
{
auto& idx = content.get<TTDTag>();
- for (auto it = idx.begin(); it != idx.end() && it->d_ttd < now;) {
- events.emplace_back(it->d_queryID, std::move(it->d_query));
- it = idx.erase(it);
+ for (auto contentIt = idx.begin(); contentIt != idx.end() && contentIt->d_ttd < now;) {
+ events.emplace_back(contentIt->d_queryID, std::move(contentIt->d_query));
+ contentIt = idx.erase(contentIt);
}
}
@@ -253,10 +220,10 @@ static bool resumeResponse(std::unique_ptr<CrossProtocolQuery>&& response)
{
try {
auto& ids = response->query.d_idstate;
- DNSResponse dr = response->getDR();
+ DNSResponse dnsResponse = response->getDR();
LocalHolders holders;
- auto result = processResponseAfterRules(response->query.d_buffer, *holders.cacheInsertedRespRuleActions, dr, ids.cs->muted);
+ auto result = processResponseAfterRules(response->query.d_buffer, *holders.cacheInsertedRespRuleActions, dnsResponse, ids.cs->muted);
if (!result) {
/* easy */
return true;
@@ -264,7 +231,9 @@ static bool resumeResponse(std::unique_ptr<CrossProtocolQuery>&& response)
auto sender = response->getTCPQuerySender();
if (sender) {
- struct timeval now;
+ struct timeval now
+ {
+ };
gettimeofday(&now, nullptr);
TCPResponse resp(std::move(response->query.d_buffer), std::move(response->query.d_idstate), nullptr, response->downstream);
@@ -314,44 +283,45 @@ bool resumeQuery(std::unique_ptr<CrossProtocolQuery>&& query)
return resumeResponse(std::move(query));
}
- auto& ids = query->query.d_idstate;
- DNSQuestion dq = query->getDQ();
+ DNSQuestion dnsQuestion = query->getDQ();
LocalHolders holders;
- auto result = processQueryAfterRules(dq, holders, query->downstream);
+ auto result = processQueryAfterRules(dnsQuestion, holders, query->downstream);
if (result == ProcessQueryResult::Drop) {
/* easy */
return true;
}
- else if (result == ProcessQueryResult::PassToBackend) {
+ if (result == ProcessQueryResult::PassToBackend) {
if (query->downstream == nullptr) {
return false;
}
#ifdef HAVE_DNS_OVER_HTTPS
- if (dq.ids.du != nullptr) {
- dq.ids.du->downstream = query->downstream;
+ if (dnsQuestion.ids.du != nullptr) {
+ dnsQuestion.ids.du->downstream = query->downstream;
}
#endif
- if (query->downstream->isTCPOnly() || !(dq.getProtocol().isUDP() || dq.getProtocol() == dnsdist::Protocol::DoH)) {
+ if (query->downstream->isTCPOnly() || !(dnsQuestion.getProtocol().isUDP() || dnsQuestion.getProtocol() == dnsdist::Protocol::DoH)) {
query->downstream->passCrossProtocolQuery(std::move(query));
return true;
}
- auto queryID = dq.getHeader()->id;
+ auto queryID = dnsQuestion.getHeader()->id;
/* at this point 'du', if it is not nullptr, is owned by the DoHCrossProtocolQuery
which will stop existing when we return, so we need to increment the reference count
*/
- return assignOutgoingUDPQueryToBackend(query->downstream, queryID, dq, query->query.d_buffer, ids.origDest);
+ return assignOutgoingUDPQueryToBackend(query->downstream, queryID, dnsQuestion, query->query.d_buffer);
}
- else if (result == ProcessQueryResult::SendAnswer) {
+ if (result == ProcessQueryResult::SendAnswer) {
auto sender = query->getTCPQuerySender();
if (!sender) {
return false;
}
- struct timeval now;
+ struct timeval now
+ {
+ };
gettimeofday(&now, nullptr);
TCPResponse response(std::move(query->query.d_buffer), std::move(query->query.d_idstate), nullptr, query->downstream);
@@ -367,7 +337,7 @@ bool resumeQuery(std::unique_ptr<CrossProtocolQuery>&& query)
return false;
}
}
- else if (result == ProcessQueryResult::Asynchronous) {
+ if (result == ProcessQueryResult::Asynchronous) {
/* nope */
errlog("processQueryAfterRules returned 'asynchronous' while trying to resume an already asynchronous query");
return false;
@@ -376,43 +346,47 @@ bool resumeQuery(std::unique_ptr<CrossProtocolQuery>&& query)
return false;
}
-bool suspendQuery(DNSQuestion& dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
+bool suspendQuery(DNSQuestion& dnsQuestion, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
{
if (!g_asyncHolder) {
return false;
}
- struct timeval now;
+ struct timeval now
+ {
+ };
gettimeofday(&now, nullptr);
struct timeval ttd = now;
ttd.tv_sec += timeoutMs / 1000;
- ttd.tv_usec += (timeoutMs % 1000) * 1000;
+ ttd.tv_usec += static_cast<decltype(ttd.tv_usec)>((timeoutMs % 1000) * 1000);
normalizeTV(ttd);
vinfolog("Suspending asynchronous query %d at %d.%d until %d.%d", queryID, now.tv_sec, now.tv_usec, ttd.tv_sec, ttd.tv_usec);
- auto query = getInternalQueryFromDQ(dq, false);
+ auto query = getInternalQueryFromDQ(dnsQuestion, false);
g_asyncHolder->push(asyncID, queryID, ttd, std::move(query));
return true;
}
-bool suspendResponse(DNSResponse& dr, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
+bool suspendResponse(DNSResponse& dnsResponse, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)
{
if (!g_asyncHolder) {
return false;
}
- struct timeval now;
+ struct timeval now
+ {
+ };
gettimeofday(&now, nullptr);
struct timeval ttd = now;
ttd.tv_sec += timeoutMs / 1000;
- ttd.tv_usec += (timeoutMs % 1000) * 1000;
+ ttd.tv_usec += static_cast<decltype(ttd.tv_usec)>((timeoutMs % 1000) * 1000);
normalizeTV(ttd);
vinfolog("Suspending asynchronous response %d at %d.%d until %d.%d", queryID, now.tv_sec, now.tv_usec, ttd.tv_sec, ttd.tv_usec);
- auto query = getInternalQueryFromDQ(dr, true);
+ auto query = getInternalQueryFromDQ(dnsResponse, true);
query->d_isResponse = true;
- query->downstream = dr.d_downstream;
+ query->downstream = dnsResponse.d_downstream;
g_asyncHolder->push(asyncID, queryID, ttd, std::move(query));
return true;
diff --git a/dnsdist-async.hh b/dnsdist-async.hh
index 5a8c090..c0b8453 100644
--- a/dnsdist-async.hh
+++ b/dnsdist-async.hh
@@ -27,6 +27,7 @@
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
+#include "channel.hh"
#include "dnsdist-tcp.hh"
namespace dnsdist
@@ -75,21 +76,28 @@ private:
struct Data
{
+ Data(bool failOpen);
+ Data(const Data&) = delete;
+ Data(Data&&) = delete;
+ Data& operator=(const Data&) = delete;
+ Data& operator=(Data&&) = delete;
+ ~Data() = default;
+
LockGuarded<content_t> d_content;
- FDWrapper d_notifyPipe;
- FDWrapper d_watchPipe;
+ pdns::channel::Notifier d_notifier;
+ pdns::channel::Waiter d_waiter;
bool d_failOpen{true};
bool d_done{false};
};
std::shared_ptr<Data> d_data{nullptr};
static void mainThread(std::shared_ptr<Data> data);
- static bool wait(const Data& data, FDMultiplexer& mplexer, std::vector<int>& readyFDs, int atMostMs);
+ static bool wait(Data& data, FDMultiplexer& mplexer, std::vector<int>& readyFDs, int atMostMs);
bool notify() const;
};
-bool suspendQuery(DNSQuestion& dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs);
-bool suspendResponse(DNSResponse& dr, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs);
+bool suspendQuery(DNSQuestion& dnsQuestion, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs);
+bool suspendResponse(DNSResponse& dnsResponse, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs);
bool queueQueryResumptionEvent(std::unique_ptr<CrossProtocolQuery>&& query);
bool resumeQuery(std::unique_ptr<CrossProtocolQuery>&& query);
void handleQueuedAsynchronousEvents();
diff --git a/dnsdist-backend.cc b/dnsdist-backend.cc
index eca469a..7f56034 100644
--- a/dnsdist-backend.cc
+++ b/dnsdist-backend.cc
@@ -19,25 +19,62 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
+#include "config.h"
#include "dnsdist.hh"
#include "dnsdist-backoff.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-random.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-tcp.hh"
+#include "dnsdist-xsk.hh"
#include "dolog.hh"
+#include "xsk.hh"
bool DownstreamState::passCrossProtocolQuery(std::unique_ptr<CrossProtocolQuery>&& cpq)
{
- if (d_config.d_dohPath.empty()) {
- return g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq));
- }
- else {
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ if (!d_config.d_dohPath.empty()) {
return g_dohClientThreads && g_dohClientThreads->passCrossProtocolQueryToThread(std::move(cpq));
}
+#endif
+ return g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq));
+}
+
+#ifdef HAVE_XSK
+void DownstreamState::addXSKDestination(int fd)
+{
+ auto socklen = d_config.remote.getSocklen();
+ ComboAddress local;
+ if (getsockname(fd, reinterpret_cast<sockaddr*>(&local), &socklen)) {
+ return;
+ }
+
+ {
+ auto addresses = d_socketSourceAddresses.write_lock();
+ addresses->push_back(local);
+ }
+ dnsdist::xsk::addDestinationAddress(local);
+ for (size_t idx = 0; idx < d_xskSockets.size(); idx++) {
+ d_xskSockets.at(idx)->addWorkerRoute(d_xskInfos.at(idx), local);
+ }
}
+void DownstreamState::removeXSKDestination(int fd)
+{
+ auto socklen = d_config.remote.getSocklen();
+ ComboAddress local;
+ if (getsockname(fd, reinterpret_cast<sockaddr*>(&local), &socklen)) {
+ return;
+ }
+
+ dnsdist::xsk::removeDestinationAddress(local);
+ for (auto& xskSocket : d_xskSockets) {
+ xskSocket->removeWorkerRoute(local);
+ }
+}
+#endif /* HAVE_XSK */
+
bool DownstreamState::reconnect(bool initialAttempt)
{
std::unique_lock<std::mutex> tl(connectLock, std::try_to_lock);
@@ -51,11 +88,23 @@ bool DownstreamState::reconnect(bool initialAttempt)
}
connected = false;
+#ifdef HAVE_XSK
+ if (!d_xskInfos.empty()) {
+ auto addresses = d_socketSourceAddresses.write_lock();
+ addresses->clear();
+ }
+#endif /* HAVE_XSK */
+
for (auto& fd : sockets) {
if (fd != -1) {
if (sockets.size() > 1) {
(*mplexer.lock())->removeReadFD(fd);
}
+#ifdef HAVE_XSK
+ if (!d_xskInfos.empty()) {
+ removeXSKDestination(fd);
+ }
+#endif /* HAVE_XSK */
/* shutdown() is needed to wake up recv() in the responderThread */
shutdown(fd, SHUT_RDWR);
close(fd);
@@ -86,6 +135,11 @@ bool DownstreamState::reconnect(bool initialAttempt)
if (sockets.size() > 1) {
(*mplexer.lock())->addReadFD(fd, [](int, boost::any) {});
}
+#ifdef HAVE_XSK
+ if (!d_xskInfos.empty()) {
+ addXSKDestination(fd);
+ }
+#endif /* HAVE_XSK */
connected = true;
}
catch (const std::runtime_error& error) {
@@ -99,8 +153,19 @@ bool DownstreamState::reconnect(bool initialAttempt)
/* if at least one (re-)connection failed, close all sockets */
if (!connected) {
+#ifdef HAVE_XSK
+ if (!d_xskInfos.empty()) {
+ auto addresses = d_socketSourceAddresses.write_lock();
+ addresses->clear();
+ }
+#endif /* HAVE_XSK */
for (auto& fd : sockets) {
if (fd != -1) {
+#ifdef HAVE_XSK
+ if (!d_xskInfos.empty()) {
+ removeXSKDestination(fd);
+ }
+#endif /* HAVE_XSK */
if (sockets.size() > 1) {
try {
(*mplexer.lock())->removeReadFD(fd);
@@ -267,12 +332,20 @@ DownstreamState::DownstreamState(DownstreamState::Config&& config, std::shared_p
void DownstreamState::start()
{
if (connected && !threadStarted.test_and_set()) {
- tid = std::thread(responderThread, shared_from_this());
+#ifdef HAVE_XSK
+ for (auto& xskInfo : d_xskInfos) {
+ auto xskResponderThread = std::thread(dnsdist::xsk::XskResponderThread, shared_from_this(), xskInfo);
+ if (!d_config.d_cpus.empty()) {
+ mapThreadToCPUList(xskResponderThread.native_handle(), d_config.d_cpus);
+ }
+ xskResponderThread.detach();
+ }
+#endif /* HAVE_XSK */
+ auto tid = std::thread(responderThread, shared_from_this());
if (!d_config.d_cpus.empty()) {
mapThreadToCPUList(tid.native_handle(), d_config.d_cpus);
}
-
tid.detach();
}
}
@@ -360,10 +433,10 @@ void DownstreamState::handleUDPTimeout(IDState& ids)
{
ids.age = 0;
ids.inUse = false;
- handleDOHTimeout(std::move(ids.internal.du));
+ DOHUnitInterface::handleTimeout(std::move(ids.internal.du));
++reuseds;
--outstanding;
- ++g_stats.downstreamTimeouts; // this is an 'actively' discovered timeout
+ ++dnsdist::metrics::g_stats.downstreamTimeouts; // this is an 'actively' discovered timeout
vinfolog("Had a downstream timeout from %s (%s) for query for %s|%s from %s",
d_config.remote.toStringWithPort(), getName(),
ids.internal.qname.toLogString(), QType(ids.internal.qtype).toString(), ids.internal.origRemote.toStringWithPort());
@@ -462,8 +535,8 @@ uint16_t DownstreamState::saveState(InternalQueryState&& state)
auto oldDU = std::move(it->second.internal.du);
++reuseds;
- ++g_stats.downstreamTimeouts;
- handleDOHTimeout(std::move(oldDU));
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
+ DOHUnitInterface::handleTimeout(std::move(oldDU));
}
else {
++outstanding;
@@ -489,8 +562,8 @@ uint16_t DownstreamState::saveState(InternalQueryState&& state)
to handle it because it's about to be overwritten. */
auto oldDU = std::move(ids.internal.du);
++reuseds;
- ++g_stats.downstreamTimeouts;
- handleDOHTimeout(std::move(oldDU));
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
+ DOHUnitInterface::handleTimeout(std::move(oldDU));
}
else {
++outstanding;
@@ -512,8 +585,8 @@ void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
if (!inserted) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
- handleDOHTimeout(std::move(state.du));
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
+ DOHUnitInterface::handleTimeout(std::move(state.du));
}
else {
it->second.internal = std::move(state);
@@ -527,15 +600,15 @@ void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
if (!guard) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
- handleDOHTimeout(std::move(state.du));
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
+ DOHUnitInterface::handleTimeout(std::move(state.du));
return;
}
if (ids.isInUse()) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
- handleDOHTimeout(std::move(state.du));
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
+ DOHUnitInterface::handleTimeout(std::move(state.du));
return;
}
ids.internal = std::move(state);
@@ -619,6 +692,7 @@ bool DownstreamState::healthCheckRequired(std::optional<time_t> currentTime)
lastResults.clear();
vinfolog("Backend %s reached the lazy health-check threshold (%f%% out of %f%%, looking at sample of %d items with %d failures), moving to Potential Failure state", getNameWithAddr(), current, maxFailureRate, totalCount, failures);
stats->d_status = LazyHealthCheckStats::LazyStatus::PotentialFailure;
+ consecutiveSuccessfulChecks = 0;
/* we update the next check time here because the check might time out,
and we do not want to send a second check during that time unless
the timer is actually very short */
@@ -678,7 +752,7 @@ void DownstreamState::updateNextLazyHealthCheck(LazyHealthCheckStats& stats, boo
time_t backOff = d_config.d_lazyHealthCheckMaxBackOff;
const ExponentialBackOffTimer backOffTimer(d_config.d_lazyHealthCheckMaxBackOff);
- auto backOffCoeffTmp = backOffTimer.get(failedTests);
+ auto backOffCoeffTmp = backOffTimer.get(failedTests - 1);
/* backOffCoeffTmp cannot be higher than d_config.d_lazyHealthCheckMaxBackOff */
const auto backOffCoeff = static_cast<time_t>(backOffCoeffTmp);
if ((std::numeric_limits<time_t>::max() / d_config.d_lazyHealthCheckFailedInterval) >= backOffCoeff) {
@@ -700,6 +774,10 @@ void DownstreamState::updateNextLazyHealthCheck(LazyHealthCheckStats& stats, boo
void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
{
+ if (!newResult) {
+ ++d_healthCheckMetrics.d_failures;
+ }
+
if (initial) {
/* if this is the initial health-check, at startup, we do not care
about the minimum number of failed/successful health-checks */
@@ -709,9 +787,11 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
setUpStatus(newResult);
if (newResult == false) {
currentCheckFailures++;
- auto stats = d_lazyHealthCheckStats.lock();
- stats->d_status = LazyHealthCheckStats::LazyStatus::Failed;
- updateNextLazyHealthCheck(*stats, false);
+ if (d_config.availability == DownstreamState::Availability::Lazy) {
+ auto stats = d_lazyHealthCheckStats.lock();
+ stats->d_status = LazyHealthCheckStats::LazyStatus::Failed;
+ updateNextLazyHealthCheck(*stats, false);
+ }
}
return;
}
@@ -721,12 +801,12 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
if (newResult) {
/* check succeeded */
currentCheckFailures = 0;
+ consecutiveSuccessfulChecks++;
if (!upStatus) {
/* we were previously marked as "down" and had a successful health-check,
let's see if this is enough to move to the "up" state or if we need
more successful health-checks for that */
- consecutiveSuccessfulChecks++;
if (consecutiveSuccessfulChecks < d_config.minRiseSuccesses) {
/* we need more than one successful check to rise
and we didn't reach the threshold yet, let's stay down */
@@ -767,7 +847,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
auto stats = d_lazyHealthCheckStats.lock();
vinfolog("Backend %s failed its health-check, moving from Potential failure to Failed", getNameWithAddr());
stats->d_status = LazyHealthCheckStats::LazyStatus::Failed;
- currentCheckFailures = 0;
+ currentCheckFailures = 1;
updateNextLazyHealthCheck(*stats, false);
}
}
@@ -790,6 +870,50 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
}
}
+#ifdef HAVE_XSK
+[[nodiscard]] ComboAddress DownstreamState::pickSourceAddressForSending()
+{
+ if (!connected) {
+ waitUntilConnected();
+ }
+
+ auto addresses = d_socketSourceAddresses.read_lock();
+ auto numberOfAddresses = addresses->size();
+ if (numberOfAddresses == 0) {
+ throw std::runtime_error("No source address available for sending XSK data to backend " + getNameWithAddr());
+ }
+ size_t idx = dnsdist::getRandomValue(numberOfAddresses);
+ return (*addresses)[idx % numberOfAddresses];
+}
+
+void DownstreamState::registerXsk(std::vector<std::shared_ptr<XskSocket>>& xsks)
+{
+ d_xskSockets = xsks;
+
+ if (d_config.sourceAddr.sin4.sin_family == 0 || (IsAnyAddress(d_config.sourceAddr))) {
+ const auto& ifName = xsks.at(0)->getInterfaceName();
+ auto addresses = getListOfAddressesOfNetworkInterface(ifName);
+ if (addresses.empty()) {
+ throw std::runtime_error("Unable to get source address from interface " + ifName);
+ }
+
+ if (addresses.size() > 1) {
+ warnlog("More than one address configured on interface %s, picking the first one (%s) for XSK. Set the 'source' parameter on 'newServer' if you want to use a different address.", ifName, addresses.at(0).toString());
+ }
+ d_config.sourceAddr = addresses.at(0);
+ }
+ d_config.sourceMACAddr = d_xskSockets.at(0)->getSourceMACAddress();
+
+ for (auto& xsk : d_xskSockets) {
+ auto xskInfo = XskWorker::create();
+ d_xskInfos.push_back(xskInfo);
+ xsk->addWorker(xskInfo);
+ xskInfo->sharedEmptyFrameOffset = xsk->sharedEmptyFrameOffset;
+ }
+ reconnect(false);
+}
+#endif /* HAVE_XSK */
+
size_t ServerPool::countServers(bool upOnly)
{
std::shared_ptr<const ServerPolicy::NumberedServerVector> servers = nullptr;
diff --git a/dnsdist-cache.cc b/dnsdist-cache.cc
index 7ca9be2..86c900b 100644
--- a/dnsdist-cache.cc
+++ b/dnsdist-cache.cc
@@ -119,9 +119,10 @@ void DNSDistPacketCache::insertLocked(CacheShard& shard, std::unordered_map<uint
void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool receivedOverUDP, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
{
- if (response.size() < sizeof(dnsheader)) {
+ if (response.size() < sizeof(dnsheader) || response.size() > getMaximumEntrySize()) {
return;
}
+
if (qtype == QType::AXFR || qtype == QType::IXFR) {
return;
}
@@ -252,7 +253,7 @@ bool DNSDistPacketCache::get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut
}
/* check for collision */
- if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.getHeader())), dq.ids.qname, dq.ids.qtype, dq.ids.qclass, receivedOverUDP, dnssecOK, subnet)) {
+ if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.getHeader().get())), dq.ids.qname, dq.ids.qtype, dq.ids.qclass, receivedOverUDP, dnssecOK, subnet)) {
++d_lookupCollisions;
return false;
}
@@ -472,12 +473,12 @@ uint64_t DNSDistPacketCache::getEntriesCount()
uint64_t DNSDistPacketCache::dump(int fd)
{
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
- if (fp == nullptr) {
+ auto filePtr = pdns::UniqueFilePtr(fdopen(dup(fd), "w"));
+ if (filePtr == nullptr) {
return 0;
}
- fprintf(fp.get(), "; dnsdist's packet cache dump follows\n;\n");
+ fprintf(filePtr.get(), "; dnsdist's packet cache dump follows\n;\n");
uint64_t count = 0;
time_t now = time(nullptr);
@@ -496,10 +497,10 @@ uint64_t DNSDistPacketCache::dump(int fd)
rcode = dh.rcode;
}
- fprintf(fp.get(), "%s %" PRId64 " %s ; rcode %" PRIu8 ", key %" PRIu32 ", length %" PRIu16 ", received over UDP %d, added %" PRId64 "\n", value.qname.toString().c_str(), static_cast<int64_t>(value.validity - now), QType(value.qtype).toString().c_str(), rcode, entry.first, value.len, value.receivedOverUDP, static_cast<int64_t>(value.added));
+ fprintf(filePtr.get(), "%s %" PRId64 " %s ; rcode %" PRIu8 ", key %" PRIu32 ", length %" PRIu16 ", received over UDP %d, added %" PRId64 "\n", value.qname.toString().c_str(), static_cast<int64_t>(value.validity - now), QType(value.qtype).toString().c_str(), rcode, entry.first, value.len, static_cast<int>(value.receivedOverUDP), static_cast<int64_t>(value.added));
}
catch(...) {
- fprintf(fp.get(), "; error printing '%s'\n", value.qname.empty() ? "EMPTY" : value.qname.toString().c_str());
+ fprintf(filePtr.get(), "; error printing '%s'\n", value.qname.empty() ? "EMPTY" : value.qname.toString().c_str());
}
}
}
@@ -620,3 +621,8 @@ std::set<ComboAddress> DNSDistPacketCache::getRecordsForDomain(const DNSName& do
return addresses;
}
+
+void DNSDistPacketCache::setMaximumEntrySize(size_t maxSize)
+{
+ d_maximumEntrySize = maxSize;
+}
diff --git a/dnsdist-cache.hh b/dnsdist-cache.hh
index d8837be..95667bd 100644
--- a/dnsdist-cache.hh
+++ b/dnsdist-cache.hh
@@ -45,15 +45,15 @@ public:
bool isFull();
string toString();
uint64_t getSize();
- uint64_t getHits() const { return d_hits; }
- uint64_t getMisses() const { return d_misses; }
- uint64_t getDeferredLookups() const { return d_deferredLookups; }
- uint64_t getDeferredInserts() const { return d_deferredInserts; }
- uint64_t getLookupCollisions() const { return d_lookupCollisions; }
- uint64_t getInsertCollisions() const { return d_insertCollisions; }
+ uint64_t getHits() const { return d_hits.load(); }
+ uint64_t getMisses() const { return d_misses.load(); }
+ uint64_t getDeferredLookups() const { return d_deferredLookups.load(); }
+ uint64_t getDeferredInserts() const { return d_deferredInserts.load(); }
+ uint64_t getLookupCollisions() const { return d_lookupCollisions.load(); }
+ uint64_t getInsertCollisions() const { return d_insertCollisions.load(); }
uint64_t getMaxEntries() const { return d_maxEntries; }
- uint64_t getTTLTooShorts() const { return d_ttlTooShorts; }
- uint64_t getCleanupCount() const { return d_cleanupCount; }
+ uint64_t getTTLTooShorts() const { return d_ttlTooShorts.load(); }
+ uint64_t getCleanupCount() const { return d_cleanupCount.load(); }
uint64_t getEntriesCount();
uint64_t dump(int fd);
@@ -75,12 +75,14 @@ public:
d_keepStaleData = keep;
}
-
void setECSParsingEnabled(bool enabled)
{
d_parseECS = enabled;
}
+ void setMaximumEntrySize(size_t maxSize);
+ size_t getMaximumEntrySize() const { return d_maximumEntrySize; }
+
uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const PacketBuffer& packet, bool receivedOverUDP);
static uint32_t getMinTTL(const char* packet, uint16_t length, bool* seenNoDataSOA);
@@ -139,15 +141,16 @@ private:
pdns::stat_t d_ttlTooShorts{0};
pdns::stat_t d_cleanupCount{0};
- size_t d_maxEntries;
- uint32_t d_shardCount;
- uint32_t d_maxTTL;
- uint32_t d_tempFailureTTL;
- uint32_t d_maxNegativeTTL;
- uint32_t d_minTTL;
- uint32_t d_staleTTL;
- bool d_dontAge;
- bool d_deferrableInsertLock;
+ const size_t d_maxEntries;
+ size_t d_maximumEntrySize{4096};
+ const uint32_t d_shardCount;
+ const uint32_t d_maxTTL;
+ const uint32_t d_tempFailureTTL;
+ const uint32_t d_maxNegativeTTL;
+ const uint32_t d_minTTL;
+ const uint32_t d_staleTTL;
+ const bool d_dontAge;
+ const bool d_deferrableInsertLock;
bool d_parseECS;
bool d_keepStaleData{false};
};
diff --git a/dnsdist-carbon.cc b/dnsdist-carbon.cc
index 5a5014d..1b1c0fe 100644
--- a/dnsdist-carbon.cc
+++ b/dnsdist-carbon.cc
@@ -26,6 +26,7 @@
#include "dnsdist-carbon.hh"
#include "dnsdist.hh"
#include "dnsdist-backoff.hh"
+#include "dnsdist-metrics.hh"
#ifndef DISABLE_CARBON
#include "dolog.hh"
@@ -53,19 +54,19 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
const time_t now = time(nullptr);
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
str << namespace_name << "." << hostname << "." << instance_name << "." << entry.d_name << ' ';
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
str << (*val)->load();
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
str << (*adval)->load();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
str << **dval;
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
str << (*func)(entry.d_name);
}
str << ' ' << now << "\r\n";
@@ -98,6 +99,12 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
str << base << "tcpavgqueriesperconnection" << ' ' << state->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
str << base << "tcpavgconnectionduration" << ' ' << state->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
str << base << "tcptoomanyconcurrentconnections" << ' ' << state->tcpTooManyConcurrentConnections.load() << " " << now << "\r\n";
+ str << base << "healthcheckfailures" << ' ' << state->d_healthCheckMetrics.d_failures << " " << now << "\r\n";
+ str << base << "healthcheckfailuresparsing" << ' ' << state->d_healthCheckMetrics.d_parseErrors << " " << now << "\r\n";
+ str << base << "healthcheckfailurestimeout" << ' ' << state->d_healthCheckMetrics.d_timeOuts << " " << now << "\r\n";
+ str << base << "healthcheckfailuresnetwork" << ' ' << state->d_healthCheckMetrics.d_networkErrors << " " << now << "\r\n";
+ str << base << "healthcheckfailuresmismatch" << ' ' << state->d_healthCheckMetrics.d_mismatchErrors << " " << now << "\r\n";
+ str << base << "healthcheckfailuresinvalid" << ' ' << state->d_healthCheckMetrics.d_invalidResponseErrors << " " << now << "\r\n";
}
std::map<std::string, uint64_t> frontendDuplicates;
@@ -120,7 +127,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
str << base << "tcpdiedreadingquery" << ' ' << front->tcpDiedReadingQuery.load() << " " << now << "\r\n";
str << base << "tcpdiedsendingresponse" << ' ' << front->tcpDiedSendingResponse.load() << " " << now << "\r\n";
str << base << "tcpgaveup" << ' ' << front->tcpGaveUp.load() << " " << now << "\r\n";
- str << base << "tcpclientimeouts" << ' ' << front->tcpClientTimeouts.load() << " " << now << "\r\n";
+ str << base << "tcpclienttimeouts" << ' ' << front->tcpClientTimeouts.load() << " " << now << "\r\n";
str << base << "tcpdownstreamtimeouts" << ' ' << front->tcpDownstreamTimeouts.load() << " " << now << "\r\n";
str << base << "tcpcurrentconnections" << ' ' << front->tcpCurrentConnections.load() << " " << now << "\r\n";
str << base << "tcpmaxconcurrentconnections" << ' ' << front->tcpMaxConcurrentConnections.load() << " " << now << "\r\n";
@@ -141,7 +148,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
errorCounters = &front->tlsFrontend->d_tlsCounters;
}
else if (front->dohFrontend != nullptr) {
- errorCounters = &front->dohFrontend->d_tlsCounters;
+ errorCounters = &front->dohFrontend->d_tlsContext.d_tlsCounters;
}
if (errorCounters != nullptr) {
str << base << "tlsdhkeytoosmall" << ' ' << errorCounters->d_dhKeyTooSmall << " " << now << "\r\n";
@@ -198,7 +205,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
std::map<std::string, uint64_t> dohFrontendDuplicates;
const string base = "dnsdist." + hostname + ".main.doh.";
for (const auto& doh : g_dohlocals) {
- string name = doh->d_local.toStringWithPort();
+ string name = doh->d_tlsContext.d_addr.toStringWithPort();
boost::replace_all(name, ".", "_");
boost::replace_all(name, ":", "_");
boost::replace_all(name, "[", "_");
@@ -288,7 +295,7 @@ static void carbonHandler(Carbon::Endpoint&& endpoint)
usleep(toSleepUSec);
}
else {
- vinfolog("Carbon export for %s took longer (%s usec) than the configured interval (%d usec)", endpoint.server.toStringWithPort(), elapsedUSec, intervalUSec);
+ vinfolog("Carbon export for %s took longer (%s us) than the configured interval (%d us)", endpoint.server.toStringWithPort(), elapsedUSec, intervalUSec);
}
consecutiveFailures = 0;
}
diff --git a/dnsdist-console.cc b/dnsdist-console.cc
index f424c97..3e92b56 100644
--- a/dnsdist-console.cc
+++ b/dnsdist-console.cc
@@ -43,7 +43,7 @@
#include "dolog.hh"
#include "dnsdist.hh"
#include "dnsdist-console.hh"
-#include "sodcrypto.hh"
+#include "dnsdist-crypto.hh"
#include "threadname.hh"
GlobalStateHolder<NetmaskGroup> g_consoleACL;
@@ -58,39 +58,40 @@ static ConcurrentConnectionManager s_connManager(100);
class ConsoleConnection
{
public:
- ConsoleConnection(const ComboAddress& client, FDWrapper&& fd): d_client(client), d_fd(std::move(fd))
+ ConsoleConnection(const ComboAddress& client, FDWrapper&& fileDesc): d_client(client), d_fileDesc(std::move(fileDesc))
{
if (!s_connManager.registerConnection()) {
throw std::runtime_error("Too many concurrent console connections");
}
}
- ConsoleConnection(ConsoleConnection&& rhs): d_client(rhs.d_client), d_fd(std::move(rhs.d_fd))
+ ConsoleConnection(ConsoleConnection&& rhs) noexcept: d_client(rhs.d_client), d_fileDesc(std::move(rhs.d_fileDesc))
{
}
ConsoleConnection(const ConsoleConnection&) = delete;
ConsoleConnection& operator=(const ConsoleConnection&) = delete;
+ ConsoleConnection& operator=(ConsoleConnection&&) = delete;
~ConsoleConnection()
{
- if (d_fd.getHandle() != -1) {
+ if (d_fileDesc.getHandle() != -1) {
s_connManager.releaseConnection();
}
}
- int getFD() const
+ [[nodiscard]] int getFD() const
{
- return d_fd.getHandle();
+ return d_fileDesc.getHandle();
}
- const ComboAddress& getClient() const
+ [[nodiscard]] const ComboAddress& getClient() const
{
return d_client;
}
private:
ComboAddress d_client;
- FDWrapper d_fd;
+ FDWrapper d_fileDesc;
};
void setConsoleMaximumConcurrentConnections(size_t max)
@@ -101,10 +102,11 @@ void setConsoleMaximumConcurrentConnections(size_t max)
// MUST BE CALLED UNDER A LOCK - right now the LuaLock
static void feedConfigDelta(const std::string& line)
{
- if(line.empty())
+ if (line.empty()) {
return;
- struct timeval now;
- gettimeofday(&now, 0);
+ }
+ timeval now{};
+ gettimeofday(&now, nullptr);
g_confDelta.emplace_back(now, line);
}
@@ -113,18 +115,22 @@ static string historyFile(const bool &ignoreHOME = false)
{
string ret;
- struct passwd pwd;
- struct passwd *result;
- char buf[16384];
- getpwuid_r(geteuid(), &pwd, buf, sizeof(buf), &result);
+ passwd pwd{};
+ passwd *result{nullptr};
+ std::array<char, 16384> buf{};
+ getpwuid_r(geteuid(), &pwd, buf.data(), buf.size(), &result);
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): we are not modifying the environment
const char *homedir = getenv("HOME");
- if (result)
+ if (result != nullptr) {
ret = string(pwd.pw_dir);
- if (homedir && !ignoreHOME) // $HOME overrides what the OS tells us
+ }
+ if (homedir != nullptr && !ignoreHOME) { // $HOME overrides what the OS tells us
ret = string(homedir);
- if (ret.empty())
+ }
+ if (ret.empty()) {
ret = "."; // CWD if nothing works..
+ }
ret.append("/.dnsdist_history");
return ret;
}
@@ -136,11 +142,11 @@ enum class ConsoleCommandResult : uint8_t {
TooLarge
};
-static ConsoleCommandResult getMsgLen32(int fd, uint32_t* len)
+static ConsoleCommandResult getMsgLen32(int fileDesc, uint32_t* len)
{
try {
- uint32_t raw;
- size_t ret = readn2(fd, &raw, sizeof(raw));
+ uint32_t raw{0};
+ size_t ret = readn2(fileDesc, &raw, sizeof(raw));
if (ret != sizeof raw) {
return ConsoleCommandResult::ConnectionClosed;
@@ -158,12 +164,12 @@ static ConsoleCommandResult getMsgLen32(int fd, uint32_t* len)
}
}
-static bool putMsgLen32(int fd, uint32_t len)
+static bool putMsgLen32(int fileDesc, uint32_t len)
{
try
{
uint32_t raw = htonl(len);
- size_t ret = writen2(fd, &raw, sizeof raw);
+ size_t ret = writen2(fileDesc, &raw, sizeof raw);
return ret == sizeof raw;
}
catch(...) {
@@ -171,28 +177,28 @@ static bool putMsgLen32(int fd, uint32_t len)
}
}
-static ConsoleCommandResult sendMessageToServer(int fd, const std::string& line, SodiumNonce& readingNonce, SodiumNonce& writingNonce, const bool outputEmptyLine)
+static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string& line, dnsdist::crypto::authenticated::Nonce& readingNonce, dnsdist::crypto::authenticated::Nonce& writingNonce, const bool outputEmptyLine)
{
- string msg = sodEncryptSym(line, g_consoleKey, writingNonce);
+ string msg = dnsdist::crypto::authenticated::encryptSym(line, g_consoleKey, writingNonce);
const auto msgLen = msg.length();
if (msgLen > std::numeric_limits<uint32_t>::max()) {
cerr << "Encrypted message is too long to be sent to the server, "<< std::to_string(msgLen) << " > " << std::numeric_limits<uint32_t>::max() << endl;
return ConsoleCommandResult::TooLarge;
}
- putMsgLen32(fd, static_cast<uint32_t>(msgLen));
+ putMsgLen32(fileDesc, static_cast<uint32_t>(msgLen));
if (!msg.empty()) {
- writen2(fd, msg);
+ writen2(fileDesc, msg);
}
- uint32_t len;
- auto commandResult = getMsgLen32(fd, &len);
+ uint32_t len{0};
+ auto commandResult = getMsgLen32(fileDesc, &len);
if (commandResult == ConsoleCommandResult::ConnectionClosed) {
cout << "Connection closed by the server." << endl;
return commandResult;
}
- else if (commandResult == ConsoleCommandResult::TooLarge) {
+ if (commandResult == ConsoleCommandResult::TooLarge) {
cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << g_consoleOutputMsgMaxSize << "), closing that connection" << endl;
return commandResult;
}
@@ -207,8 +213,8 @@ static ConsoleCommandResult sendMessageToServer(int fd, const std::string& line,
msg.clear();
msg.resize(len);
- readn2(fd, msg.data(), len);
- msg = sodDecryptSym(msg, g_consoleKey, readingNonce);
+ readn2(fileDesc, msg.data(), len);
+ msg = dnsdist::crypto::authenticated::decryptSym(msg, g_consoleKey, readingNonce);
cout << msg;
cout.flush();
@@ -217,7 +223,7 @@ static ConsoleCommandResult sendMessageToServer(int fd, const std::string& line,
void doClient(ComboAddress server, const std::string& command)
{
- if (!sodIsValidKey(g_consoleKey)) {
+ if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
cerr << "The currently configured console key is not valid, please configure a valid key using the setKey() directive" << endl;
return;
}
@@ -226,35 +232,38 @@ void doClient(ComboAddress server, const std::string& command)
cout<<"Connecting to "<<server.toStringWithPort()<<endl;
}
- auto fd = FDWrapper(socket(server.sin4.sin_family, SOCK_STREAM, 0));
- if (fd.getHandle() < 0) {
+ auto fileDesc = FDWrapper(socket(server.sin4.sin_family, SOCK_STREAM, 0));
+ if (fileDesc.getHandle() < 0) {
cerr<<"Unable to connect to "<<server.toStringWithPort()<<endl;
return;
}
- SConnect(fd.getHandle(), server);
- setTCPNoDelay(fd.getHandle());
- SodiumNonce theirs, ours, readingNonce, writingNonce;
+ SConnect(fileDesc.getHandle(), server);
+ setTCPNoDelay(fileDesc.getHandle());
+ dnsdist::crypto::authenticated::Nonce theirs;
+ dnsdist::crypto::authenticated::Nonce ours;
+ dnsdist::crypto::authenticated::Nonce readingNonce;
+ dnsdist::crypto::authenticated::Nonce writingNonce;
ours.init();
- writen2(fd.getHandle(), (const char*)ours.value, sizeof(ours.value));
- readn2(fd.getHandle(), (char*)theirs.value, sizeof(theirs.value));
+ writen2(fileDesc.getHandle(), ours.value.data(), ours.value.size());
+ readn2(fileDesc.getHandle(), theirs.value.data(), theirs.value.size());
readingNonce.merge(ours, theirs);
writingNonce.merge(theirs, ours);
/* try sending an empty message, the server should send an empty
one back. If it closes the connection instead, we are probably
having a key mismatch issue. */
- auto commandResult = sendMessageToServer(fd.getHandle(), "", readingNonce, writingNonce, false);
+ auto commandResult = sendMessageToServer(fileDesc.getHandle(), "", readingNonce, writingNonce, false);
if (commandResult == ConsoleCommandResult::ConnectionClosed) {
cerr<<"The server closed the connection right away, likely indicating a key mismatch. Please check your setKey() directive."<<endl;
return;
}
- else if (commandResult == ConsoleCommandResult::TooLarge) {
+ if (commandResult == ConsoleCommandResult::TooLarge) {
return;
}
if (!command.empty()) {
- sendMessageToServer(fd.getHandle(), command, readingNonce, writingNonce, false);
+ sendMessageToServer(fileDesc.getHandle(), command, readingNonce, writingNonce, false);
return;
}
@@ -272,7 +281,7 @@ void doClient(ComboAddress server, const std::string& command)
for (;;) {
char* sline = readline("> ");
rl_bind_key('\t',rl_complete);
- if (!sline) {
+ if (sline == nullptr) {
break;
}
@@ -283,6 +292,7 @@ void doClient(ComboAddress server, const std::string& command)
history.flush();
}
lastline = line;
+ // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory): readline
free(sline);
if (line == "quit") {
@@ -297,7 +307,7 @@ void doClient(ComboAddress server, const std::string& command)
continue;
}
- commandResult = sendMessageToServer(fd.getHandle(), line, readingNonce, writingNonce, true);
+ commandResult = sendMessageToServer(fileDesc.getHandle(), line, readingNonce, writingNonce, true);
if (commandResult != ConsoleCommandResult::Valid) {
break;
}
@@ -312,7 +322,7 @@ static std::optional<std::string> getNextConsoleLine(ofstream& history, std::str
{
char* sline = readline("> ");
rl_bind_key('\t', rl_complete);
- if (!sline) {
+ if (sline == nullptr) {
return std::nullopt;
}
@@ -324,6 +334,7 @@ static std::optional<std::string> getNextConsoleLine(ofstream& history, std::str
}
lastline = line;
+ // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory): readline
free(sline);
return line;
@@ -390,25 +401,26 @@ void doConsole()
>
>(withReturn ? ("return "+*line) : *line);
if (ret) {
- if (const auto dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
+ if (const auto* dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
if (*dsValue) {
cout<<(*dsValue)->getName()<<endl;
}
}
- else if (const auto csValue = boost::get<ClientState*>(&*ret)) {
- if (*csValue) {
+ else if (const auto* csValue = boost::get<ClientState*>(&*ret)) {
+ if (*csValue != nullptr) {
cout<<(*csValue)->local.toStringWithPort()<<endl;
}
}
- else if (const auto strValue = boost::get<string>(&*ret)) {
+ else if (const auto* strValue = boost::get<string>(&*ret)) {
cout<<*strValue<<endl;
}
- else if (const auto um = boost::get<std::unordered_map<string, double> >(&*ret)) {
+ else if (const auto* mapValue = boost::get<std::unordered_map<string, double> >(&*ret)) {
using namespace json11;
- Json::object o;
- for(const auto& v : *um)
- o[v.first]=v.second;
- Json out = o;
+ Json::object obj;
+ for (const auto& value : *mapValue) {
+ obj[value.first] = value.second;
+ }
+ Json out = obj;
cout<<out.dump()<<endl;
}
}
@@ -422,7 +434,8 @@ void doConsole()
}
catch (const LuaContext::SyntaxErrorException&) {
if (withReturn) {
- withReturn=false;
+ withReturn = false;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto)
goto retry;
}
throw;
@@ -433,7 +446,7 @@ void doConsole()
// tried to return something we don't understand
}
catch (const LuaContext::ExecutionErrorException& e) {
- if (!strcmp(e.what(), "invalid key to 'next'")) {
+ if (strcmp(e.what(), "invalid key to 'next'") == 0) {
std::cerr<<"Error parsing parameters, did you forget parameter name?";
}
else {
@@ -464,19 +477,23 @@ void doConsole()
const std::vector<ConsoleKeyword> g_consoleKeywords{
/* keyword, function, parameters, description */
{ "addACL", true, "netmask", "add to the ACL set who can use this server" },
- { "addAction", true, "DNS rule, DNS action [, {uuid=\"UUID\", name=\"name\"}]", "add a rule" },
+ { "addAction", true, R"(DNS rule, DNS action [, {uuid="UUID", name="name"}])", "add a rule" },
{ "addBPFFilterDynBlocks", true, "addresses, dynbpf[[, seconds=10], msg]", "This is the eBPF equivalent of addDynBlocks(), blocking a set of addresses for (optionally) a number of seconds, using an eBPF dynamic filter" },
{ "addCapabilitiesToRetain", true, "capability or list of capabilities", "Linux capabilities to retain after startup, like CAP_BPF" },
{ "addConsoleACL", true, "netmask", "add a netmask to the console ACL" },
- { "addDNSCryptBind", true, "\"127.0.0.1:8443\", \"provider name\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", {reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}", "listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of `provider name`, using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The fifth optional parameter is a table of parameters" },
+ { "addDNSCryptBind", true, R"('127.0.0.1:8443", "provider name", "/path/to/resolver.cert", "/path/to/resolver.key", {reusePort=false, tcpFastOpenQueueSize=0, interface="", cpus={}})", "listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of `provider name`, using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The fifth optional parameter is a table of parameters" },
{ "addDOHLocal", true, "addr, certFile, keyFile [, urls [, vars]]", "listen to incoming DNS over HTTPS queries on the specified address using the specified certificate and key. The last two parameters are tables" },
+ { "addDOH3Local", true, "addr, certFile, keyFile [, vars]", "listen to incoming DNS over HTTP/3 queries on the specified address using the specified certificate and key. The last parameter is a table" },
+ { "addDOQLocal", true, "addr, certFile, keyFile [, vars]", "listen to incoming DNS over QUIC queries on the specified address using the specified certificate and key. The last parameter is a table" },
+ { "addDynamicBlock", true, "address, message[, action [, seconds [, clientIPMask [, clientIPPortMask]]]]", "block the supplied address with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)" },
{ "addDynBlocks", true, "addresses, message[, seconds[, action]]", "block the set of addresses with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)" },
{ "addDynBlockSMT", true, "names, message[, seconds [, action]]", "block the set of names with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)" },
- { "addLocal", true, "addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}]", "add `addr` to the list of addresses we listen on" },
- { "addCacheHitResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a cache hit response rule" },
- { "addCacheInsertedResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a cache inserted response rule" },
- { "addResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a response rule" },
- { "addSelfAnsweredResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a self-answered response rule" },
+ { "addLocal", true, R"(addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface="", cpus={}}])", "add `addr` to the list of addresses we listen on" },
+ { "addCacheHitResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a cache hit response rule" },
+ { "addCacheInsertedResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a cache inserted response rule" },
+ { "addMaintenanceCallback", true, "callback", "register a function to be called as part of the maintenance hook, every second" },
+ { "addResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a response rule" },
+ { "addSelfAnsweredResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a self-answered response rule" },
{ "addTLSLocal", true, "addr, certFile(s), keyFile(s) [,params]", "listen to incoming DNS over TLS queries on the specified address using the specified certificate (or list of) and key (or list of). The last parameter is a table" },
{ "AllowAction", true, "", "let these packets go through" },
{ "AllowResponseAction", true, "", "let these packets go through" },
@@ -514,16 +531,24 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "exceedServFails", true, "rate, seconds", "get set of addresses that exceed `rate` servfails/s over `seconds` seconds" },
{ "firstAvailable", false, "", "picks the server with the lowest `order` that has not exceeded its QPS limit" },
{ "fixupCase", true, "bool", "if set (default to no), rewrite the first qname of the question part of the answer to match the one from the query. It is only useful when you have a downstream server that messes up the case of the question qname in the answer" },
- { "generateDNSCryptCertificate", true, "\"/path/to/providerPrivate.key\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", serial, validFrom, validUntil", "generate a new resolver private key and related certificate, valid from the `validFrom` timestamp until the `validUntil` one, signed with the provider private key" },
- { "generateDNSCryptProviderKeys", true, "\"/path/to/providerPublic.key\", \"/path/to/providerPrivate.key\"", "generate a new provider keypair" },
+ { "generateDNSCryptCertificate", true, R"("/path/to/providerPrivate.key", "/path/to/resolver.cert", "/path/to/resolver.key", serial, validFrom, validUntil)", "generate a new resolver private key and related certificate, valid from the `validFrom` timestamp until the `validUntil` one, signed with the provider private key" },
+ { "generateDNSCryptProviderKeys", true, R"("/path/to/providerPublic.key", "/path/to/providerPrivate.key")", "generate a new provider keypair" },
{ "getAction", true, "n", "Returns the Action associated with rule n" },
{ "getBind", true, "n", "returns the listener at index n" },
{ "getBindCount", true, "", "returns the number of listeners all kinds" },
+ { "getCacheHitResponseRule", true, "selector", "Return the cache-hit response rule corresponding to the selector, if any" },
+ { "getCacheInsertedResponseRule", true, "selector", "Return the cache-inserted response rule corresponding to the selector, if any" },
{ "getCurrentTime", true, "", "returns the current time" },
+ { "getDynamicBlocks", true, "", "returns a table of the current network-based dynamic blocks" },
+ { "getDynamicBlocksSMT", true, "", "returns a table of the current suffix-based dynamic blocks" },
{ "getDNSCryptBind", true, "n", "return the `DNSCryptContext` object corresponding to the bind `n`" },
{ "getDNSCryptBindCount", true, "", "returns the number of DNSCrypt listeners" },
- { "getDOHFrontend", true, "n", "returns the DOH frontend with index n" },
+ { "getDOHFrontend", true, "n", "returns the DoH frontend with index n" },
{ "getDOHFrontendCount", true, "", "returns the number of DoH listeners" },
+ { "getDOH3Frontend", true, "n", "returns the DoH3 frontend with index n" },
+ { "getDOH3FrontendCount", true, "", "returns the number of DoH3 listeners" },
+ { "getDOQFrontend", true, "n", "returns the DoQ frontend with index n" },
+ { "getDOQFrontendCount", true, "", "returns the number of DoQ listeners" },
{ "getListOfAddressesOfNetworkInterface", true, "itf", "returns the list of addresses configured on a given network interface, as strings" },
{ "getListOfNetworkInterfaces", true, "", "returns the list of network interfaces present on the system, as strings" },
{ "getListOfRangesOfNetworkInterface", true, "itf", "returns the list of network ranges configured on a given network interface, as strings" },
@@ -535,7 +560,10 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "getPoolNames", true, "", "returns a table with all the pool names" },
{ "getQueryCounters", true, "[max=10]", "show current buffer of query counters, limited by 'max' if provided" },
{ "getResponseRing", true, "", "return the current content of the response ring" },
+ { "getResponseRule", true, "selector", "Return the response rule corresponding to the selector, if any" },
{ "getRespRing", true, "", "return the qname/rcode content of the response ring" },
+ { "getRule", true, "selector", "Return the rule corresponding to the selector, if any" },
+ { "getSelfAnsweredResponseRule", true, "selector", "Return the self-answered response rule corresponding to the selector, if any" },
{ "getServer", true, "id", "returns server with index 'n' or whose uuid matches if 'id' is an UUID string" },
{ "getServers", true, "", "returns a table with all defined servers" },
{ "getStatisticsCounters", true, "", "returns a map of statistic counters" },
@@ -548,7 +576,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "getTLSFrontend", true, "n", "returns the TLS frontend with index n" },
{ "getTLSFrontendCount", true, "", "returns the number of DoT listeners" },
{ "getVerbose", true, "", "get whether log messages at the verbose level will be logged" },
- { "grepq", true, "Netmask|DNS Name|100ms|{\"::1\", \"powerdns.com\", \"100ms\"} [, n]", "shows the last n queries and responses matching the specified client address or range (Netmask), or the specified DNS Name, or slower than 100ms" },
+ { "grepq", true, R"(Netmask|DNS Name|100ms|{"::1", "powerdns.com", "100ms"} [, n] [,options])", "shows the last n queries and responses matching the specified client address or range (Netmask), or the specified DNS Name, or slower than 100ms" },
{ "hashPassword", true, "password [, workFactor]", "Returns a hashed and salted version of the supplied password, usable with 'setWebserverConfig()'"},
{ "HTTPHeaderRule", true, "name, regex", "matches DoH queries with a HTTP header 'name' whose content matches the regular expression 'regex'"},
{ "HTTPPathRegexRule", true, "regex", "matches DoH queries whose HTTP path matches 'regex'"},
@@ -617,8 +645,8 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "newPacketCache", true, "maxEntries[, maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, options={}]", "return a new Packet Cache" },
{ "newQPSLimiter", true, "rate, burst", "configure a QPS limiter with that rate and that burst capacity" },
{ "newRemoteLogger", true, "address:port [, timeout=2, maxQueuedEntries=100, reconnectWaitTime=1]", "create a Remote Logger object, to use with `RemoteLogAction()` and `RemoteLogResponseAction()`" },
- { "newRuleAction", true, "DNS rule, DNS action [, {uuid=\"UUID\", name=\"name\"}]", "return a pair of DNS Rule and DNS Action, to be used with `setRules()`" },
- { "newServer", true, "{address=\"ip:port\", qps=1000, order=1, weight=10, pool=\"abuse\", retries=5, tcpConnectTimeout=5, tcpSendTimeout=30, tcpRecvTimeout=30, checkName=\"a.root-servers.net.\", checkType=\"A\", maxCheckFailures=1, mustResolve=false, useClientSubnet=true, source=\"address|interface name|address@interface\", sockets=1, reconnectOnUp=false}", "instantiate a server" },
+ { "newRuleAction", true, R"(DNS rule, DNS action [, {uuid="UUID", name="name"}])", "return a pair of DNS Rule and DNS Action, to be used with `setRules()`" },
+ { "newServer", true, R"({address="ip:port", qps=1000, order=1, weight=10, pool="abuse", retries=5, tcpConnectTimeout=5, tcpSendTimeout=30, tcpRecvTimeout=30, checkName="a.root-servers.net.", checkType="A", maxCheckFailures=1, mustResolve=false, useClientSubnet=true, source="address|interface name|address@interface", sockets=1, reconnectOnUp=false})", "instantiate a server" },
{ "newServerPolicy", true, "name, function", "create a policy object from a Lua function" },
{ "newSuffixMatchNode", true, "", "returns a new SuffixMatchNode" },
{ "newSVCRecordParameters", true, "priority, target, mandatoryParams, alpns, noDefaultAlpn [, port [, ech [, ipv4hints [, ipv6hints [, additionalParameters ]]]]]", "return a new SVCRecordParameters object, to use with SpoofSVCAction" },
@@ -630,7 +658,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "PoolAction", true, "poolname [, stop]", "set the packet into the specified pool" },
{ "PoolAvailableRule", true, "poolname", "Check whether a pool has any servers available to handle queries" },
{ "PoolOutstandingRule", true, "poolname, limit", "Check whether a pool has outstanding queries above limit" },
- { "printDNSCryptProviderFingerprint", true, "\"/path/to/providerPublic.key\"", "display the fingerprint of the provided resolver public key" },
+ { "printDNSCryptProviderFingerprint", true, R"("/path/to/providerPublic.key")", "display the fingerprint of the provided resolver public key" },
{ "ProbaRule", true, "probability", "Matches queries with a given probability. 1.0 means always" },
{ "ProxyProtocolValueRule", true, "type [, value]", "matches queries with a specified Proxy Protocol TLV value of that type, optionally matching the content of the option as well" },
{ "QClassRule", true, "qclass", "Matches queries with the specified qclass. class can be specified as an integer or as one of the built-in DNSClass" },
@@ -683,7 +711,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "setECSSourcePrefixV4", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv4 queries" },
{ "setECSSourcePrefixV6", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv6 queries" },
{ "setKey", true, "key", "set access key to that key" },
- { "setLocal", true, "addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}]", "reset the list of addresses we listen on to this address" },
+ { "setLocal", true, R"(addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface="", cpus={}}])", "reset the list of addresses we listen on to this address" },
{ "setMaxCachedDoHConnectionsPerDownstream", true, "max", "Set the maximum number of inactive DoH connections to a backend cached by each worker DoH thread" },
{ "setMaxCachedTCPConnectionsPerDownstream", true, "max", "Set the maximum number of inactive TCP connections to a backend cached by each worker TCP thread" },
{ "setMaxTCPClientThreads", true, "n", "set the maximum of TCP client threads, handling TCP connections" },
@@ -717,6 +745,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "setServerPolicyLuaFFIPerThread", true, "name, code", "set server selection policy to one named 'name' and returned by the Lua FFI code passed in 'code'" },
{ "setServFailWhenNoServer", true, "bool", "if set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query" },
{ "setStaleCacheEntriesTTL", true, "n", "allows using cache entries expired for at most n seconds when there is no backend available to answer for a query" },
+ { "setStructuredLogging", true, "value [, options]", "set whether log messages should be in structured-logging-like format" },
{ "setSyslogFacility", true, "facility", "set the syslog logging facility to 'facility'. Defaults to LOG_DAEMON" },
{ "setTCPDownstreamCleanupInterval", true, "interval", "minimum interval in seconds between two cleanups of the idle TCP downstream connections" },
{ "setTCPFastOpenKey", true, "string", "TCP Fast Open Key" },
@@ -740,7 +769,9 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "showConsoleACL", true, "", "show our current console ACL set" },
{ "showDNSCryptBinds", true, "", "display the currently configured DNSCrypt binds" },
{ "showDOHFrontends", true, "", "list all the available DOH frontends" },
+ { "showDOH3Frontends", true, "", "list all the available DOH3 frontends" },
{ "showDOHResponseCodes", true, "", "show the HTTP response code statistics for the DoH frontends"},
+ { "showDOQFrontends", true, "", "list all the available DOQ frontends" },
{ "showDynBlocks", true, "", "show dynamic blocks in force" },
{ "showPools", true, "", "show the available pools" },
{ "showPoolServerPolicy", true, "pool", "show server selection policy for this pool" },
@@ -766,6 +797,8 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "SetECSPrefixLengthAction", true, "v4, v6", "Set the ECS prefix length. Subsequent rules are processed after this action" },
{ "SetMacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" },
{ "SetEDNSOptionAction", true, "option, data", "Add arbitrary EDNS option and data to the query. Subsequent rules are processed after this action" },
+ { "SetExtendedDNSErrorAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to the response corresponding to the current query. Subsequent rules are processed after this action" },
+ { "SetExtendedDNSErrorResponseAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to this response. Subsequent rules are processed after this action" },
{ "SetNoRecurseAction", true, "", "strip RD bit from the question, let it go through" },
{ "setOutgoingDoHWorkerThreads", true, "n", "Number of outgoing DoH worker threads" },
{ "SetProxyProtocolValuesAction", true, "values", "Set the Proxy-Protocol values for this queries to 'values'" },
@@ -785,6 +818,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
{ "TagRule", true, "name [, value]", "matches if the tag named 'name' is present, with the given 'value' matching if any" },
{ "TCAction", true, "", "create answer to query with TC and RD bits set, to move to TCP" },
{ "TCPRule", true, "[tcp]", "Matches question received over TCP if tcp is true, over UDP otherwise" },
+ { "TCResponseAction", true, "", "truncate a response" },
{ "TeeAction", true, "remote [, addECS [, local]]", "send copy of query to remote, optionally adding ECS info, optionally set local address" },
{ "testCrypto", true, "", "test of the crypto all works" },
{ "TimedIPSetRule", true, "", "Create a rule which matches a set of IP addresses which expire"},
@@ -811,17 +845,17 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
extern "C" {
static char* my_generator(const char* text, int state)
{
- string t(text);
+ string textStr(text);
/* to keep it readable, we try to keep only 4 keywords per line
and to start a new line when the first letter changes */
static int s_counter = 0;
- int counter=0;
- if (!state) {
+ int counter = 0;
+ if (state == 0) {
s_counter = 0;
}
for (const auto& keyword : g_consoleKeywords) {
- if (boost::starts_with(keyword.name, t) && counter++ == s_counter) {
+ if (boost::starts_with(keyword.name, textStr) && counter++ == s_counter) {
std::string value(keyword.name);
s_counter++;
if (keyword.function) {
@@ -833,14 +867,15 @@ static char* my_generator(const char* text, int state)
return strdup(value.c_str());
}
}
- return 0;
+ return nullptr;
}
char** my_completion( const char * text , int start, int end)
{
- char **matches=0;
+ char **matches = nullptr;
if (start == 0) {
- matches = rl_completion_matches ((char*)text, &my_generator);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): readline
+ matches = rl_completion_matches (const_cast<char*>(text), &my_generator);
}
// skip default filename completion.
@@ -859,15 +894,18 @@ static void controlClientThread(ConsoleConnection&& conn)
setTCPNoDelay(conn.getFD());
- SodiumNonce theirs, ours, readingNonce, writingNonce;
+ dnsdist::crypto::authenticated::Nonce theirs;
+ dnsdist::crypto::authenticated::Nonce ours;
+ dnsdist::crypto::authenticated::Nonce readingNonce;
+ dnsdist::crypto::authenticated::Nonce writingNonce;
ours.init();
- readn2(conn.getFD(), (char*)theirs.value, sizeof(theirs.value));
- writen2(conn.getFD(), (char*)ours.value, sizeof(ours.value));
+ readn2(conn.getFD(), theirs.value.data(), theirs.value.size());
+ writen2(conn.getFD(), ours.value.data(), ours.value.size());
readingNonce.merge(ours, theirs);
writingNonce.merge(theirs, ours);
for (;;) {
- uint32_t len;
+ uint32_t len{0};
if (getMsgLen32(conn.getFD(), &len) != ConsoleCommandResult::Valid) {
break;
}
@@ -883,7 +921,7 @@ static void controlClientThread(ConsoleConnection&& conn)
line.resize(len);
readn2(conn.getFD(), line.data(), len);
- line = sodDecryptSym(line, g_consoleKey, readingNonce);
+ line = dnsdist::crypto::authenticated::decryptSym(line, g_consoleKey, readingNonce);
string response;
try {
@@ -906,30 +944,30 @@ static void controlClientThread(ConsoleConnection&& conn)
>(withReturn ? ("return "+line) : line);
if (ret) {
- if (const auto dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
+ if (const auto* dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
if (*dsValue) {
response = (*dsValue)->getName()+"\n";
} else {
response = "";
}
}
- else if (const auto csValue = boost::get<ClientState*>(&*ret)) {
- if (*csValue) {
+ else if (const auto* csValue = boost::get<ClientState*>(&*ret)) {
+ if (*csValue != nullptr) {
response = (*csValue)->local.toStringWithPort()+"\n";
} else {
response = "";
}
}
- else if (const auto strValue = boost::get<string>(&*ret)) {
+ else if (const auto* strValue = boost::get<string>(&*ret)) {
response = *strValue+"\n";
}
- else if (const auto um = boost::get<std::unordered_map<string, double> >(&*ret)) {
+ else if (const auto* mapValue = boost::get<std::unordered_map<string, double> >(&*ret)) {
using namespace json11;
- Json::object o;
- for(const auto& v : *um) {
- o[v.first] = v.second;
+ Json::object obj;
+ for (const auto& value : *mapValue) {
+ obj[value.first] = value.second;
}
- Json out = o;
+ Json out = obj;
response = out.dump()+"\n";
}
}
@@ -941,8 +979,9 @@ static void controlClientThread(ConsoleConnection&& conn)
}
}
catch (const LuaContext::SyntaxErrorException&) {
- if(withReturn) {
- withReturn=false;
+ if (withReturn) {
+ withReturn = false;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto)
goto retry;
}
throw;
@@ -953,7 +992,7 @@ static void controlClientThread(ConsoleConnection&& conn)
// tried to return something we don't understand
}
catch (const LuaContext::ExecutionErrorException& e) {
- if (!strcmp(e.what(),"invalid key to 'next'")) {
+ if (strcmp(e.what(),"invalid key to 'next'") == 0) {
response = "Error: Parsing function parameters, did you forget parameter name?";
}
else {
@@ -974,7 +1013,7 @@ static void controlClientThread(ConsoleConnection&& conn)
catch (const LuaContext::SyntaxErrorException& e) {
response = "Error: " + string(e.what()) + ": ";
}
- response = sodEncryptSym(response, g_consoleKey, writingNonce);
+ response = dnsdist::crypto::authenticated::encryptSym(response, g_consoleKey, writingNonce);
putMsgLen32(conn.getFD(), response.length());
writen2(conn.getFD(), response.c_str(), response.length());
}
@@ -983,25 +1022,30 @@ static void controlClientThread(ConsoleConnection&& conn)
}
}
catch (const std::exception& e) {
- errlog("Got an exception in client connection from %s: %s", conn.getClient().toStringWithPort(), e.what());
+ infolog("Got an exception in client connection from %s: %s", conn.getClient().toStringWithPort(), e.what());
}
}
-void controlThread(int fd, ComboAddress local)
+// NOLINTNEXTLINE(performance-unnecessary-value-param): this is thread
+void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
{
- FDWrapper acceptFD(fd);
try
{
setThreadName("dnsdist/control");
ComboAddress client;
- int sock;
+ // make sure that the family matches the one from the listening IP,
+ // so that getSocklen() returns the correct size later, otherwise
+ // the first IPv6 console connection might get refused
+ client.sin4.sin_family = local.sin4.sin_family;
+
+ int sock{-1};
auto localACL = g_consoleACL.getLocal();
infolog("Accepting control connections on %s", local.toStringWithPort());
- while ((sock = SAccept(acceptFD.getHandle(), client)) >= 0) {
+ while ((sock = SAccept(acceptFD->getHandle(), client)) >= 0) {
FDWrapper socket(sock);
- if (!sodIsValidKey(g_consoleKey)) {
+ if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort());
continue;
}
@@ -1017,11 +1061,11 @@ void controlThread(int fd, ComboAddress local)
warnlog("Got control connection from %s", client.toStringWithPort());
}
- std::thread t(controlClientThread, std::move(conn));
- t.detach();
+ std::thread clientThread(controlClientThread, std::move(conn));
+ clientThread.detach();
}
catch (const std::exception& e) {
- errlog("Control connection died: %s", e.what());
+ infolog("Control connection died: %s", e.what());
}
}
}
diff --git a/dnsdist-console.hh b/dnsdist-console.hh
index 1ef046c..6e227d4 100644
--- a/dnsdist-console.hh
+++ b/dnsdist-console.hh
@@ -22,6 +22,7 @@
#pragma once
#include "config.h"
+#include "sstuff.hh"
#ifndef DISABLE_COMPLETION
struct ConsoleKeyword {
@@ -55,7 +56,7 @@ extern uint32_t g_consoleOutputMsgMaxSize;
void doClient(ComboAddress server, const std::string& command);
void doConsole();
-void controlThread(int fd, ComboAddress local);
+void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local);
void clearConsoleHistory();
void setConsoleMaximumConcurrentConnections(size_t max);
diff --git a/dnsdist-crypto.cc b/dnsdist-crypto.cc
new file mode 100644
index 0000000..df4beeb
--- /dev/null
+++ b/dnsdist-crypto.cc
@@ -0,0 +1,573 @@
+/*
+ * 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 <iostream>
+#include <arpa/inet.h>
+
+#include "dnsdist-crypto.hh"
+
+#include "namespaces.hh"
+#include "noinitvector.hh"
+#include "misc.hh"
+#include "base64.hh"
+
+namespace dnsdist::crypto::authenticated
+{
+#ifdef HAVE_LIBSODIUM
+string newKey(bool base64Encoded)
+{
+ std::string key;
+ key.resize(crypto_secretbox_KEYBYTES);
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ randombytes_buf(reinterpret_cast<unsigned char*>(key.data()), key.size());
+
+ if (!base64Encoded) {
+ return key;
+ }
+ return "\"" + Base64Encode(key) + "\"";
+}
+
+bool isValidKey(const std::string& key)
+{
+ return key.size() == crypto_secretbox_KEYBYTES;
+}
+
+std::string encryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ if (!isValidKey(key)) {
+ throw std::runtime_error("Invalid encryption key of size " + std::to_string(key.size()) + " (" + std::to_string(crypto_secretbox_KEYBYTES) + " expected), use setKey() to set a valid key");
+ }
+
+ std::string ciphertext;
+ ciphertext.resize(msg.length() + crypto_secretbox_MACBYTES);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ crypto_secretbox_easy(reinterpret_cast<unsigned char*>(ciphertext.data()),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const unsigned char*>(msg.data()),
+ msg.length(),
+ nonce.value.data(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const unsigned char*>(key.data()));
+
+ if (incrementNonce) {
+ nonce.increment();
+ }
+
+ return ciphertext;
+}
+
+std::string decryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ std::string decrypted;
+
+ if (msg.length() < crypto_secretbox_MACBYTES) {
+ throw std::runtime_error("Could not decrypt message of size " + std::to_string(msg.length()));
+ }
+
+ if (!isValidKey(key)) {
+ throw std::runtime_error("Invalid decryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key");
+ }
+
+ decrypted.resize(msg.length() - crypto_secretbox_MACBYTES);
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (crypto_secretbox_open_easy(reinterpret_cast<unsigned char*>(decrypted.data()),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const unsigned char*>(msg.data()),
+ msg.length(),
+ nonce.value.data(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const unsigned char*>(key.data()))
+ != 0) {
+ throw std::runtime_error("Could not decrypt message, please check that the key configured with setKey() is correct");
+ }
+
+ if (incrementNonce) {
+ nonce.increment();
+ }
+
+ return decrypted;
+}
+
+void Nonce::init()
+{
+ randombytes_buf(value.data(), value.size());
+}
+
+#elif defined(HAVE_LIBCRYPTO)
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+static constexpr size_t s_CHACHA20_POLY1305_KEY_SIZE = 32U;
+static constexpr size_t s_POLY1305_BLOCK_SIZE = 16U;
+
+string newKey(bool base64Encoded)
+{
+ std::string key;
+ key.resize(s_CHACHA20_POLY1305_KEY_SIZE);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (RAND_priv_bytes(reinterpret_cast<unsigned char*>(key.data()), key.size()) != 1) {
+ throw std::runtime_error("Could not initialize random number generator for cryptographic functions");
+ }
+ if (!base64Encoded) {
+ return key;
+ }
+ return "\"" + Base64Encode(key) + "\"";
+}
+
+bool isValidKey(const std::string& key)
+{
+ return key.size() == s_CHACHA20_POLY1305_KEY_SIZE;
+}
+
+std::string encryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ if (!isValidKey(key)) {
+ throw std::runtime_error("Invalid encryption key of size " + std::to_string(key.size()) + " (" + std::to_string(s_CHACHA20_POLY1305_KEY_SIZE) + " expected), use setKey() to set a valid key");
+ }
+
+ // Each thread gets its own cipher context
+ static thread_local auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(nullptr, EVP_CIPHER_CTX_free);
+
+ if (!ctx) {
+ ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ if (!ctx) {
+ throw std::runtime_error("encryptSym: EVP_CIPHER_CTX_new() could not initialize cipher context");
+ }
+
+ if (EVP_EncryptInit_ex(ctx.get(), EVP_chacha20_poly1305(), nullptr, nullptr, nullptr) != 1) {
+ throw std::runtime_error("encryptSym: EVP_EncryptInit_ex() could not initialize encryption operation");
+ }
+ }
+
+ std::string ciphertext;
+ /* plus one so we can access the last byte in EncryptFinal which does nothing for this algo */
+ ciphertext.resize(s_POLY1305_BLOCK_SIZE + msg.length() + 1);
+ int outLength{0};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, reinterpret_cast<const unsigned char*>(key.c_str()), nonce.value.data()) != 1) {
+ throw std::runtime_error("encryptSym: EVP_EncryptInit_ex() could not initialize encryption key and IV");
+ }
+
+ if (!msg.empty()) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (EVP_EncryptUpdate(ctx.get(),
+ reinterpret_cast<unsigned char*>(&ciphertext.at(s_POLY1305_BLOCK_SIZE)), &outLength,
+ reinterpret_cast<const unsigned char*>(msg.data()), msg.length())
+ != 1) {
+ throw std::runtime_error("encryptSym: EVP_EncryptUpdate() could not encrypt message");
+ }
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (EVP_EncryptFinal_ex(ctx.get(), reinterpret_cast<unsigned char*>(&ciphertext.at(s_POLY1305_BLOCK_SIZE + outLength)), &outLength) != 1) {
+ throw std::runtime_error("encryptSym: EVP_EncryptFinal_ex() could finalize message encryption");
+ ;
+ }
+
+ /* Get the tag */
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_GET_TAG, s_POLY1305_BLOCK_SIZE, ciphertext.data()) != 1) {
+ throw std::runtime_error("encryptSym: EVP_CIPHER_CTX_ctrl() could not get tag");
+ }
+
+ if (incrementNonce) {
+ nonce.increment();
+ }
+
+ ciphertext.resize(ciphertext.size() - 1);
+ return ciphertext;
+}
+
+std::string decryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ if (msg.length() < s_POLY1305_BLOCK_SIZE) {
+ throw std::runtime_error("Could not decrypt message of size " + std::to_string(msg.length()));
+ }
+
+ if (!isValidKey(key)) {
+ throw std::runtime_error("Invalid decryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key");
+ }
+
+ if (msg.length() == s_POLY1305_BLOCK_SIZE) {
+ if (incrementNonce) {
+ nonce.increment();
+ }
+ return std::string();
+ }
+
+ // Each thread gets its own cipher context
+ static thread_local auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(nullptr, EVP_CIPHER_CTX_free);
+ if (!ctx) {
+ ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ if (!ctx) {
+ throw std::runtime_error("decryptSym: EVP_CIPHER_CTX_new() could not initialize cipher context");
+ }
+
+ if (EVP_DecryptInit_ex(ctx.get(), EVP_chacha20_poly1305(), nullptr, nullptr, nullptr) != 1) {
+ throw std::runtime_error("decryptSym: EVP_DecryptInit_ex() could not initialize decryption operation");
+ }
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, reinterpret_cast<const unsigned char*>(key.c_str()), nonce.value.data()) != 1) {
+ throw std::runtime_error("decryptSym: EVP_DecryptInit_ex() could not initialize decryption key and IV");
+ }
+
+ const auto tag = msg.substr(0, s_POLY1305_BLOCK_SIZE);
+ std::string decrypted;
+ /* plus one so we can access the last byte in DecryptFinal, which does nothing */
+ decrypted.resize(msg.length() - s_POLY1305_BLOCK_SIZE + 1);
+ int outLength{0};
+ if (msg.size() > s_POLY1305_BLOCK_SIZE) {
+ if (!EVP_DecryptUpdate(ctx.get(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<unsigned char*>(decrypted.data()), &outLength,
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const unsigned char*>(&msg.at(s_POLY1305_BLOCK_SIZE)), msg.size() - s_POLY1305_BLOCK_SIZE)) {
+ throw std::runtime_error("Could not decrypt message (update failed), please check that the key configured with setKey() is correct");
+ }
+ }
+
+ /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): sorry, OpenSSL's API is terrible
+ if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_TAG, s_POLY1305_BLOCK_SIZE, const_cast<char*>(tag.data()))) {
+ throw std::runtime_error("Could not decrypt message (invalid tag), please check that the key configured with setKey() is correct");
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (!EVP_DecryptFinal_ex(ctx.get(), reinterpret_cast<unsigned char*>(&decrypted.at(outLength)), &outLength)) {
+ throw std::runtime_error("Could not decrypt message (final failed), please check that the key configured with setKey() is correct");
+ }
+
+ if (incrementNonce) {
+ nonce.increment();
+ }
+
+ decrypted.resize(decrypted.size() - 1);
+ return decrypted;
+}
+
+void Nonce::init()
+{
+ if (RAND_priv_bytes(value.data(), value.size()) != 1) {
+ throw std::runtime_error("Could not initialize random number generator for cryptographic functions");
+ }
+}
+#endif
+
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
+void Nonce::merge(const Nonce& lower, const Nonce& higher)
+{
+ constexpr size_t halfSize = std::tuple_size<decltype(value)>{} / 2;
+ memcpy(value.data(), lower.value.data(), halfSize);
+ memcpy(value.data() + halfSize, higher.value.data() + halfSize, halfSize);
+}
+
+void Nonce::increment()
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto* ptr = reinterpret_cast<uint32_t*>(value.data());
+ uint32_t count = htonl(*ptr);
+ *ptr = ntohl(++count);
+}
+
+#else
+void Nonce::init()
+{
+}
+
+void Nonce::merge(const Nonce& lower, const Nonce& higher)
+{
+}
+
+void Nonce::increment()
+{
+}
+
+std::string encryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ return std::string(msg);
+}
+std::string decryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce)
+{
+ return std::string(msg);
+}
+
+string newKey(bool base64Encoded)
+{
+ return "\"plaintext\"";
+}
+
+bool isValidKey(const std::string& key)
+{
+ return true;
+}
+
+#endif
+}
+
+#include <cinttypes>
+
+namespace anonpdns
+{
+static char B64Decode1(char cInChar)
+{
+ // The incoming character will be A-Z, a-z, 0-9, +, /, or =.
+ // The idea is to quickly determine which grouping the
+ // letter belongs to and return the associated value
+ // without having to search the global encoding string
+ // (the value we're looking for would be the resulting
+ // index into that string).
+ //
+ // To do that, we'll play some tricks...
+ unsigned char iIndex = '\0';
+ switch (cInChar) {
+ case '+':
+ iIndex = 62;
+ break;
+
+ case '/':
+ iIndex = 63;
+ break;
+
+ case '=':
+ iIndex = 0;
+ break;
+
+ default:
+ // Must be 'A'-'Z', 'a'-'z', '0'-'9', or an error...
+ //
+ // Numerically, small letters are "greater" in value than
+ // capital letters and numerals (ASCII value), and capital
+ // letters are "greater" than numerals (again, ASCII value),
+ // so we check for numerals first, then capital letters,
+ // and finally small letters.
+ iIndex = '9' - cInChar;
+ if (iIndex > 0x3F) {
+ // Not from '0' to '9'...
+ iIndex = 'Z' - cInChar;
+ if (iIndex > 0x3F) {
+ // Not from 'A' to 'Z'...
+ iIndex = 'z' - cInChar;
+ if (iIndex > 0x3F) {
+ // Invalid character...cannot
+ // decode!
+ iIndex = 0x80; // set the high bit
+ } // if
+ else {
+ // From 'a' to 'z'
+ iIndex = (('z' - iIndex) - 'a') + 26;
+ } // else
+ } // if
+ else {
+ // From 'A' to 'Z'
+ iIndex = ('Z' - iIndex) - 'A';
+ } // else
+ } // if
+ else {
+ // Adjust the index...
+ iIndex = (('9' - iIndex) - '0') + 52;
+ } // else
+ break;
+
+ } // switch
+
+ return static_cast<char>(iIndex);
+}
+
+static inline char B64Encode1(unsigned char input)
+{
+ if (input < 26) {
+ return static_cast<char>('A' + input);
+ }
+ if (input < 52) {
+ return static_cast<char>('a' + (input - 26));
+ }
+ if (input < 62) {
+ return static_cast<char>('0' + (input - 52));
+ }
+ if (input == 62) {
+ return '+';
+ }
+ return '/';
+};
+
+}
+using namespace anonpdns;
+
+template <typename Container>
+int B64Decode(const std::string& strInput, Container& strOutput)
+{
+ // Set up a decoding buffer
+ long cBuf = 0;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ char* pBuf = reinterpret_cast<char*>(&cBuf);
+
+ // Decoding management...
+ int iBitGroup = 0;
+ int iInNum = 0;
+
+ // While there are characters to process...
+ //
+ // We'll decode characters in blocks of 4, as
+ // there are 4 groups of 6 bits in 3 bytes. The
+ // incoming Base64 character is first decoded, and
+ // then it is inserted into the decode buffer
+ // (with any relevant shifting, as required).
+ // Later, after all 3 bytes have been reconstituted,
+ // we assign them to the output string, ultimately
+ // to be returned as the original message.
+ int iInSize = static_cast<int>(strInput.size());
+ unsigned char cChar = '\0';
+ uint8_t pad = 0;
+ while (iInNum < iInSize) {
+ // Fill the decode buffer with 4 groups of 6 bits
+ cBuf = 0; // clear
+ pad = 0;
+ for (iBitGroup = 0; iBitGroup < 4; ++iBitGroup) {
+ if (iInNum < iInSize) {
+ // Decode a character
+ if (strInput.at(iInNum) == '=') {
+ pad++;
+ }
+ while (isspace(strInput.at(iInNum))) {
+ iInNum++;
+ }
+ cChar = B64Decode1(strInput.at(iInNum++));
+
+ } // if
+ else {
+ // Decode a padded zero
+ cChar = '\0';
+ } // else
+
+ // Check for valid decode
+ if (cChar > 0x7F) {
+ return -1;
+ }
+
+ // Adjust the bits
+ switch (iBitGroup) {
+ case 0:
+ // The first group is copied into
+ // the least significant 6 bits of
+ // the decode buffer...these 6 bits
+ // will eventually shift over to be
+ // the most significant bits of the
+ // third byte.
+ cBuf = cBuf | cChar;
+ break;
+
+ default:
+ // For groupings 1-3, simply shift
+ // the bits in the decode buffer over
+ // by 6 and insert the 6 from the
+ // current decode character.
+ cBuf = (cBuf << 6) | cChar;
+ break;
+
+ } // switch
+ } // for
+
+ // Interpret the resulting 3 bytes...note there
+ // may have been padding, so those padded bytes
+ // are actually ignored.
+#if BYTE_ORDER == BIG_ENDIAN
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[sizeof(long) - 3]);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[sizeof(long) - 2]);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[sizeof(long) - 1]);
+#else
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[2]);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[1]);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ strOutput.push_back(pBuf[0]);
+#endif
+ } // while
+ if (pad) {
+ strOutput.resize(strOutput.size() - pad);
+ }
+
+ return 1;
+}
+
+template int B64Decode<std::vector<uint8_t>>(const std::string& strInput, std::vector<uint8_t>& strOutput);
+template int B64Decode<PacketBuffer>(const std::string& strInput, PacketBuffer& strOutput);
+template int B64Decode<std::string>(const std::string& strInput, std::string& strOutput);
+
+/*
+www.kbcafe.com
+Copyright 2001-2002 Randy Charles Morin
+The Encode static method takes an array of 8-bit values and returns a base-64 stream.
+*/
+
+std::string Base64Encode(const std::string& src)
+{
+ std::string retval;
+ if (src.empty()) {
+ return retval;
+ }
+ for (unsigned int i = 0; i < src.size(); i += 3) {
+ unsigned char by1 = 0;
+ unsigned char by2 = 0;
+ unsigned char by3 = 0;
+ by1 = src[i];
+ if (i + 1 < src.size()) {
+ by2 = src[i + 1];
+ };
+ if (i + 2 < src.size()) {
+ by3 = src[i + 2];
+ }
+ unsigned char by4 = 0;
+ unsigned char by5 = 0;
+ unsigned char by6 = 0;
+ unsigned char by7 = 0;
+ by4 = by1 >> 2;
+ by5 = ((by1 & 0x3) << 4) | (by2 >> 4);
+ by6 = ((by2 & 0xf) << 2) | (by3 >> 6);
+ by7 = by3 & 0x3f;
+ retval += B64Encode1(by4);
+ retval += B64Encode1(by5);
+ if (i + 1 < src.size()) {
+ retval += B64Encode1(by6);
+ }
+ else {
+ retval += "=";
+ };
+ if (i + 2 < src.size()) {
+ retval += B64Encode1(by7);
+ }
+ else {
+ retval += "=";
+ };
+ /* if ((i % (76 / 4 * 3)) == 0)
+ {
+ retval += "\r\n";
+ }*/
+ };
+ return retval;
+};
diff --git a/dnsdist-crypto.hh b/dnsdist-crypto.hh
new file mode 100644
index 0000000..74e1c04
--- /dev/null
+++ b/dnsdist-crypto.hh
@@ -0,0 +1,73 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "config.h"
+#include <array>
+#include <string>
+#include <cstdint>
+#include <cstring>
+
+#if defined(HAVE_LIBSODIUM)
+#include <sodium.h>
+#endif
+
+namespace dnsdist::crypto::authenticated
+{
+struct Nonce
+{
+ Nonce() = default;
+ Nonce(const Nonce&) = default;
+ Nonce(Nonce&&) = default;
+ Nonce& operator=(const Nonce&) = default;
+ Nonce& operator=(Nonce&&) = default;
+ ~Nonce() = default;
+
+ void init();
+ void merge(const Nonce& lower, const Nonce& higher);
+ void increment();
+
+#if defined(HAVE_LIBSODIUM)
+ std::array<unsigned char, crypto_secretbox_NONCEBYTES> value{};
+#elif defined(HAVE_LIBCRYPTO)
+ // IV is 96 bits
+ std::array<unsigned char, 12> value{};
+#else
+ std::array<unsigned char, 1> value{};
+#endif
+};
+
+std::string encryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce = true);
+std::string decryptSym(const std::string_view& msg, const std::string& key, Nonce& nonce, bool incrementNonce = true);
+std::string newKey(bool base64Encoded = true);
+bool isValidKey(const std::string& key);
+
+constexpr size_t getEncryptedSize(size_t plainTextSize)
+{
+#if defined(HAVE_LIBSODIUM)
+ return plainTextSize + crypto_secretbox_MACBYTES;
+#elif defined(HAVE_LIBCRYPTO)
+ return plainTextSize + 16;
+#else
+ return plainTextSize;
+#endif
+}
+}
diff --git a/dnsdist-discovery.cc b/dnsdist-discovery.cc
index 76042e3..bba713b 100644
--- a/dnsdist-discovery.cc
+++ b/dnsdist-discovery.cc
@@ -38,7 +38,7 @@ const uint16_t ServiceDiscovery::s_defaultDoHSVCKey{7};
bool ServiceDiscovery::addUpgradeableServer(std::shared_ptr<DownstreamState>& server, uint32_t interval, std::string poolAfterUpgrade, uint16_t dohSVCKey, bool keepAfterUpgrade)
{
- s_upgradeableBackends.lock()->push_back(std::make_shared<UpgradeableBackend>(UpgradeableBackend{server, poolAfterUpgrade, 0, interval, dohSVCKey, keepAfterUpgrade}));
+ s_upgradeableBackends.lock()->push_back(std::make_shared<UpgradeableBackend>(UpgradeableBackend{server, std::move(poolAfterUpgrade), 0, interval, dohSVCKey, keepAfterUpgrade}));
return true;
}
@@ -52,7 +52,7 @@ struct DesignatedResolvers
static bool parseSVCParams(const PacketBuffer& answer, std::map<uint16_t, DesignatedResolvers>& resolvers)
{
std::map<DNSName, std::vector<ComboAddress>> hints;
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(answer.data());
+ const dnsheader_aligned dh(answer.data());
PacketReader pr(std::string_view(reinterpret_cast<const char*>(answer.data()), answer.size()));
uint16_t qdcount = ntohs(dh->qdcount);
uint16_t ancount = ntohs(dh->ancount);
@@ -226,7 +226,7 @@ static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& exis
tempConfig.d_subjectName = resolver.target.toStringNoDot();
tempConfig.d_addr.sin4.sin_port = tempConfig.d_port;
- config = tempConfig;
+ config = std::move(tempConfig);
return true;
}
diff --git a/dnsdist-dnscrypt.cc b/dnsdist-dnscrypt.cc
index 9930144..8f02910 100644
--- a/dnsdist-dnscrypt.cc
+++ b/dnsdist-dnscrypt.cc
@@ -21,6 +21,7 @@
*/
#include "dolog.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#include "dnscrypt.hh"
#ifdef HAVE_DNSCRYPT
@@ -40,7 +41,7 @@ int handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, ti
}
if (packet.size() < static_cast<uint16_t>(sizeof(struct dnsheader))) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
diff --git a/dnsdist-dnsparser.cc b/dnsdist-dnsparser.cc
index 90ce075..a15f2d5 100644
--- a/dnsdist-dnsparser.cc
+++ b/dnsdist-dnsparser.cc
@@ -186,4 +186,32 @@ bool changeNameInDNSPacket(PacketBuffer& initialPacket, const DNSName& from, con
return true;
}
+namespace PacketMangling
+{
+ bool editDNSHeaderFromPacket(PacketBuffer& packet, const std::function<bool(dnsheader& header)>& editFunction)
+ {
+ if (packet.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Trying to edit the DNS header of a too small packet");
+ }
+
+ return editDNSHeaderFromRawPacket(packet.data(), editFunction);
+ }
+
+ bool editDNSHeaderFromRawPacket(void* packet, const std::function<bool(dnsheader& header)>& editFunction)
+ {
+ if (dnsheader_aligned::isMemoryAligned(packet)) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto* header = reinterpret_cast<dnsheader*>(packet);
+ return editFunction(*header);
+ }
+
+ dnsheader header{};
+ memcpy(&header, packet, sizeof(header));
+ if (!editFunction(header)) {
+ return false;
+ }
+ memcpy(packet, &header, sizeof(header));
+ return true;
+ }
+}
}
diff --git a/dnsdist-dnsparser.hh b/dnsdist-dnsparser.hh
index 91de7ac..4f7cdad 100644
--- a/dnsdist-dnsparser.hh
+++ b/dnsdist-dnsparser.hh
@@ -54,4 +54,10 @@ public:
* because it could contain pointers that would not be rewritten.
*/
bool changeNameInDNSPacket(PacketBuffer& initialPacket, const DNSName& from, const DNSName& to);
+
+namespace PacketMangling
+{
+ bool editDNSHeaderFromPacket(PacketBuffer& packet, const std::function<bool(dnsheader& header)>& editFunction);
+ bool editDNSHeaderFromRawPacket(void* packet, const std::function<bool(dnsheader& header)>& editFunction);
+}
}
diff --git a/dnsdist-doh-common.cc b/dnsdist-doh-common.cc
new file mode 100644
index 0000000..71cd87c
--- /dev/null
+++ b/dnsdist-doh-common.cc
@@ -0,0 +1,193 @@
+/*
+ * 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 "base64.hh"
+#include "dnsdist-doh-common.hh"
+#include "dnsdist-rules.hh"
+
+#ifdef HAVE_DNS_OVER_HTTPS
+
+HTTPHeaderRule::HTTPHeaderRule(const std::string& header, const std::string& regex) :
+ d_header(toLower(header)), d_regex(regex), d_visual("http[" + header + "] ~ " + regex)
+{
+}
+
+bool HTTPHeaderRule::matches(const DNSQuestion* dq) const
+{
+ if (!dq->ids.du) {
+ return false;
+ }
+
+ const auto& headers = dq->ids.du->getHTTPHeaders();
+ for (const auto& header : headers) {
+ if (header.first == d_header) {
+ return d_regex.match(header.second);
+ }
+ }
+ return false;
+}
+
+string HTTPHeaderRule::toString() const
+{
+ return d_visual;
+}
+
+HTTPPathRule::HTTPPathRule(std::string path) :
+ d_path(std::move(path))
+{
+}
+
+bool HTTPPathRule::matches(const DNSQuestion* dq) const
+{
+ if (!dq->ids.du) {
+ return false;
+ }
+
+ const auto path = dq->ids.du->getHTTPPath();
+ return d_path == path;
+}
+
+string HTTPPathRule::toString() const
+{
+ return "url path == " + d_path;
+}
+
+HTTPPathRegexRule::HTTPPathRegexRule(const std::string& regex) :
+ d_regex(regex), d_visual("http path ~ " + regex)
+{
+}
+
+bool HTTPPathRegexRule::matches(const DNSQuestion* dq) const
+{
+ if (!dq->ids.du) {
+ return false;
+ }
+
+ return d_regex.match(dq->ids.du->getHTTPPath());
+}
+
+string HTTPPathRegexRule::toString() const
+{
+ return d_visual;
+}
+
+void DOHFrontend::rotateTicketsKey(time_t now)
+{
+ return d_tlsContext.rotateTicketsKey(now);
+}
+
+void DOHFrontend::loadTicketsKeys(const std::string& keyFile)
+{
+ return d_tlsContext.loadTicketsKeys(keyFile);
+}
+
+void DOHFrontend::handleTicketsKeyRotation()
+{
+}
+
+std::string DOHFrontend::getNextTicketsKeyRotation() const
+{
+ return d_tlsContext.getNextTicketsKeyRotation();
+}
+
+size_t DOHFrontend::getTicketsKeysCount()
+{
+ return d_tlsContext.getTicketsKeysCount();
+}
+
+void DOHFrontend::reloadCertificates()
+{
+ d_tlsContext.setupTLS();
+}
+
+void DOHFrontend::setup()
+{
+ if (isHTTPS()) {
+ if (!d_tlsContext.setupTLS()) {
+ throw std::runtime_error("Error setting up TLS context for DoH listener on '" + d_tlsContext.d_addr.toStringWithPort());
+ }
+ }
+}
+
+#endif /* HAVE_DNS_OVER_HTTPS */
+
+namespace dnsdist::doh
+{
+std::optional<PacketBuffer> getPayloadFromPath(const std::string_view& path)
+{
+ std::optional<PacketBuffer> result{std::nullopt};
+
+ if (path.size() <= 5) {
+ return result;
+ }
+
+ auto pos = path.find("?dns=");
+ if (pos == string::npos) {
+ pos = path.find("&dns=");
+ }
+
+ if (pos == string::npos) {
+ return result;
+ }
+
+ // need to base64url decode this
+ string sdns;
+ const size_t payloadSize = path.size() - pos - 5;
+ size_t neededPadding = 0;
+ switch (payloadSize % 4) {
+ case 2:
+ neededPadding = 2;
+ break;
+ case 3:
+ neededPadding = 1;
+ break;
+ }
+ sdns.reserve(payloadSize + neededPadding);
+ sdns = path.substr(pos + 5);
+ for (auto& entry : sdns) {
+ switch (entry) {
+ case '-':
+ entry = '+';
+ break;
+ case '_':
+ entry = '/';
+ break;
+ }
+ }
+
+ if (neededPadding != 0) {
+ // re-add padding that may have been missing
+ sdns.append(neededPadding, '=');
+ }
+
+ PacketBuffer decoded;
+ /* rough estimate so we hopefully don't need a new allocation later */
+ /* We reserve at few additional bytes to be able to add EDNS later */
+ const size_t estimate = ((sdns.size() * 3) / 4);
+ decoded.reserve(estimate);
+ if (B64Decode(sdns, decoded) < 0) {
+ return result;
+ }
+
+ result = std::move(decoded);
+ return result;
+}
+}
diff --git a/dnsdist-doh-common.hh b/dnsdist-doh-common.hh
new file mode 100644
index 0000000..0dc714d
--- /dev/null
+++ b/dnsdist-doh-common.hh
@@ -0,0 +1,248 @@
+/*
+ * 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 <optional>
+#include <unordered_map>
+#include <set>
+#include <string_view>
+
+#include "config.h"
+#include "iputils.hh"
+#include "libssl.hh"
+#include "noinitvector.hh"
+#include "stat_t.hh"
+#include "tcpiohandler.hh"
+
+namespace dnsdist::doh
+{
+std::optional<PacketBuffer> getPayloadFromPath(const std::string_view& path);
+}
+
+struct DOHServerConfig;
+
+class DOHResponseMapEntry
+{
+public:
+ DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional<std::unordered_map<std::string, std::string>>& headers) :
+ d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
+ {
+ if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() - 1) != 0) {
+ // we need to make sure it's null-terminated
+ d_content.push_back(0);
+ }
+ }
+
+ bool matches(const std::string& path) const
+ {
+ return d_regex.match(path);
+ }
+
+ uint16_t getStatusCode() const
+ {
+ return d_status;
+ }
+
+ const PacketBuffer& getContent() const
+ {
+ return d_content;
+ }
+
+ const boost::optional<std::unordered_map<std::string, std::string>>& getHeaders() const
+ {
+ return d_customHeaders;
+ }
+
+private:
+ Regex d_regex;
+ boost::optional<std::unordered_map<std::string, std::string>> d_customHeaders;
+ PacketBuffer d_content;
+ uint16_t d_status;
+};
+
+struct DOHFrontend
+{
+ DOHFrontend()
+ {
+ }
+ DOHFrontend(std::shared_ptr<TLSCtx> tlsCtx) :
+ d_tlsContext(std::move(tlsCtx))
+ {
+ }
+
+ virtual ~DOHFrontend()
+ {
+ }
+
+ std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
+ std::shared_ptr<std::vector<std::shared_ptr<DOHResponseMapEntry>>> d_responsesMap;
+ TLSFrontend d_tlsContext{TLSFrontend::ALPN::DoH};
+ std::string d_serverTokens{"h2o/dnsdist"};
+ std::unordered_map<std::string, std::string> d_customResponseHeaders;
+ std::string d_library;
+
+ uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds
+ std::set<std::string, std::less<>> d_urls;
+
+ pdns::stat_t d_httpconnects{0}; // number of TCP/IP connections established
+ pdns::stat_t d_getqueries{0}; // valid DNS queries received via GET
+ pdns::stat_t d_postqueries{0}; // valid DNS queries received via POST
+ pdns::stat_t d_badrequests{0}; // request could not be converted to dns query
+ pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response
+ pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response
+ pdns::stat_t d_validresponses{0}; // valid responses sent out
+
+ struct HTTPVersionStats
+ {
+ pdns::stat_t d_nbQueries{0}; // valid DNS queries received
+ pdns::stat_t d_nb200Responses{0};
+ pdns::stat_t d_nb400Responses{0};
+ pdns::stat_t d_nb403Responses{0};
+ pdns::stat_t d_nb500Responses{0};
+ pdns::stat_t d_nb502Responses{0};
+ pdns::stat_t d_nbOtherResponses{0};
+ };
+
+ HTTPVersionStats d_http1Stats;
+ HTTPVersionStats d_http2Stats;
+#ifdef __linux__
+ // On Linux this gives us 128k pending queries (default is 8192 queries),
+ // which should be enough to deal with huge spikes
+ uint32_t d_internalPipeBufferSize{1024 * 1024};
+#else
+ uint32_t d_internalPipeBufferSize{0};
+#endif
+ bool d_sendCacheControlHeaders{true};
+ bool d_trustForwardedForHeader{false};
+ bool d_earlyACLDrop{true};
+ /* whether we require tue query path to exactly match one of configured ones,
+ or accept everything below these paths. */
+ bool d_exactPathMatching{true};
+ bool d_keepIncomingHeaders{false};
+
+ time_t getTicketsKeyRotationDelay() const
+ {
+ return d_tlsContext.d_tlsConfig.d_ticketsKeyRotationDelay;
+ }
+
+ bool isHTTPS() const
+ {
+ return !d_tlsContext.d_tlsConfig.d_certKeyPairs.empty();
+ }
+
+#ifndef HAVE_DNS_OVER_HTTPS
+ virtual void setup()
+ {
+ }
+
+ virtual void reloadCertificates()
+ {
+ }
+
+ virtual void rotateTicketsKey(time_t /* now */)
+ {
+ }
+
+ virtual void loadTicketsKeys(const std::string& /* keyFile */)
+ {
+ }
+
+ virtual void handleTicketsKeyRotation()
+ {
+ }
+
+ virtual std::string getNextTicketsKeyRotation()
+ {
+ return std::string();
+ }
+
+ virtual size_t getTicketsKeysCount() const
+ {
+ size_t res = 0;
+ return res;
+ }
+
+#else
+ virtual void setup();
+ virtual void reloadCertificates();
+
+ virtual void rotateTicketsKey(time_t now);
+ virtual void loadTicketsKeys(const std::string& keyFile);
+ virtual void handleTicketsKeyRotation();
+ virtual std::string getNextTicketsKeyRotation() const;
+ virtual size_t getTicketsKeysCount();
+#endif /* HAVE_DNS_OVER_HTTPS */
+};
+
+#include "dnsdist-idstate.hh"
+
+struct DownstreamState;
+
+#ifndef HAVE_DNS_OVER_HTTPS
+struct DOHUnitInterface
+{
+ virtual ~DOHUnitInterface()
+ {
+ }
+ static void handleTimeout(std::unique_ptr<DOHUnitInterface>)
+ {
+ }
+
+ static void handleUDPResponse(std::unique_ptr<DOHUnitInterface>, PacketBuffer&&, InternalQueryState&&, const std::shared_ptr<DownstreamState>&)
+ {
+ }
+};
+#else /* HAVE_DNS_OVER_HTTPS */
+struct DOHUnitInterface
+{
+ virtual ~DOHUnitInterface()
+ {
+ }
+
+ virtual std::string getHTTPPath() const = 0;
+ virtual std::string getHTTPQueryString() const = 0;
+ virtual const std::string& getHTTPHost() const = 0;
+ virtual const std::string& getHTTPScheme() const = 0;
+ virtual const std::unordered_map<std::string, std::string>& getHTTPHeaders() const = 0;
+ virtual void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType = "") = 0;
+ virtual void handleTimeout() = 0;
+ virtual void handleUDPResponse(PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr<DownstreamState>&) = 0;
+
+ static void handleTimeout(std::unique_ptr<DOHUnitInterface> unit)
+ {
+ if (unit) {
+ unit->handleTimeout();
+ unit.release();
+ }
+ }
+
+ static void handleUDPResponse(std::unique_ptr<DOHUnitInterface> unit, PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr<DownstreamState>& ds)
+ {
+ if (unit) {
+ unit->handleUDPResponse(std::move(response), std::move(state), ds);
+ unit.release();
+ }
+ }
+
+ std::shared_ptr<DownstreamState> downstream{nullptr};
+};
+#endif /* HAVE_DNS_OVER_HTTPS */
diff --git a/dnsdist-dynblocks.cc b/dnsdist-dynblocks.cc
index 2f37dfd..b7baca2 100644
--- a/dnsdist-dynblocks.cc
+++ b/dnsdist-dynblocks.cc
@@ -1,13 +1,13 @@
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-metrics.hh"
GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
DNSAction::Action g_dynBlockAction = DNSAction::Action::Drop;
#ifndef DISABLE_DYNBLOCKS
-
void DynBlockRulesGroup::apply(const struct timespec& now)
{
counts_t counts;
@@ -29,7 +29,7 @@ void DynBlockRulesGroup::apply(const struct timespec& now)
return;
}
- boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> > blocks;
+ boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>> blocks;
bool updated = false;
for (const auto& entry : counts) {
@@ -54,6 +54,16 @@ void DynBlockRulesGroup::apply(const struct timespec& now)
continue;
}
+ if (d_respCacheMissRatioRule.warningRatioExceeded(counters.responses, counters.cacheMisses)) {
+ handleWarning(blocks, now, requestor, d_respCacheMissRatioRule, updated);
+ continue;
+ }
+
+ if (d_respCacheMissRatioRule.ratioExceeded(counters.responses, counters.cacheMisses)) {
+ addBlock(blocks, now, requestor, d_respCacheMissRatioRule, updated);
+ continue;
+ }
+
for (const auto& pair : d_qtypeRules) {
const auto qtype = pair.first;
@@ -108,50 +118,64 @@ void DynBlockRulesGroup::apply(const struct timespec& now)
g_dynblockNMG.setState(std::move(*blocks));
}
- if (!statNodeRoot.empty()) {
- StatNode::Stat node;
- std::unordered_map<DNSName, std::optional<std::string>> namesToBlock;
- statNodeRoot.visit([this,&namesToBlock](const StatNode* node_, const StatNode::Stat& self, const StatNode::Stat& children) {
- bool block = false;
- std::optional<std::string> reason;
-
- if (d_smtVisitorFFI) {
- dnsdist_ffi_stat_node_t tmp(*node_, self, children, reason);
- block = d_smtVisitorFFI(&tmp);
- }
- else {
- auto ret = d_smtVisitor(*node_, self, children);
- block = std::get<0>(ret);
- if (block) {
- if (boost::optional<std::string> tmp = std::get<1>(ret)) {
- reason = std::move(*tmp);
- }
- }
- }
-
- if (block) {
- namesToBlock.insert({DNSName(node_->fullname), std::move(reason)});
- }
- },
- node);
-
- if (!namesToBlock.empty()) {
- updated = false;
- SuffixMatchTree<DynBlock> smtBlocks = g_dynblockSMT.getCopy();
- for (auto& [name, reason] : namesToBlock) {
- if (reason) {
- DynBlockRule rule(d_suffixMatchRule);
- rule.d_blockReason = std::move(*reason);
- addOrRefreshBlockSMT(smtBlocks, now, std::move(name), std::move(rule), updated);
+ applySMT(now, statNodeRoot);
+}
+
+void DynBlockRulesGroup::applySMT(const struct timespec& now, StatNode& statNodeRoot)
+{
+ if (statNodeRoot.empty()) {
+ return;
+ }
+
+ bool updated = false;
+ StatNode::Stat node;
+ std::unordered_map<DNSName, SMTBlockParameters> namesToBlock;
+ statNodeRoot.visit([this, &namesToBlock](const StatNode* node_, const StatNode::Stat& self, const StatNode::Stat& children) {
+ bool block = false;
+ SMTBlockParameters blockParameters;
+ if (d_smtVisitorFFI) {
+ dnsdist_ffi_stat_node_t tmp(*node_, self, children, blockParameters);
+ block = d_smtVisitorFFI(&tmp);
+ }
+ else {
+ auto ret = d_smtVisitor(*node_, self, children);
+ block = std::get<0>(ret);
+ if (block) {
+ if (boost::optional<std::string> tmp = std::get<1>(ret)) {
+ blockParameters.d_reason = std::move(*tmp);
}
- else {
- addOrRefreshBlockSMT(smtBlocks, now, std::move(name), d_suffixMatchRule, updated);
+ if (boost::optional<int> tmp = std::get<2>(ret)) {
+ blockParameters.d_action = static_cast<DNSAction::Action>(*tmp);
+ }
+ }
+ }
+ if (block) {
+ namesToBlock.insert({DNSName(node_->fullname), std::move(blockParameters)});
+ }
+ },
+ node);
+
+ if (!namesToBlock.empty()) {
+ updated = false;
+ SuffixMatchTree<DynBlock> smtBlocks = g_dynblockSMT.getCopy();
+ for (auto& [name, parameters] : namesToBlock) {
+ if (parameters.d_reason || parameters.d_action) {
+ DynBlockRule rule(d_suffixMatchRule);
+ if (parameters.d_reason) {
+ rule.d_blockReason = std::move(*parameters.d_reason);
}
+ if (parameters.d_action) {
+ rule.d_action = *parameters.d_action;
+ }
+ addOrRefreshBlockSMT(smtBlocks, now, name, rule, updated);
}
- if (updated) {
- g_dynblockSMT.setState(std::move(smtBlocks));
+ else {
+ addOrRefreshBlockSMT(smtBlocks, now, name, d_suffixMatchRule, updated);
}
}
+ if (updated) {
+ g_dynblockSMT.setState(std::move(smtBlocks));
+ }
}
}
@@ -173,11 +197,7 @@ bool DynBlockRulesGroup::checkIfResponseCodeMatches(const Rings::Response& respo
}
auto ratio = d_rcodeRatioRules.find(response.dh.rcode);
- if (ratio != d_rcodeRatioRules.end() && ratio->second.matches(response.when)) {
- return true;
- }
-
- return false;
+ return ratio != d_rcodeRatioRules.end() && ratio->second.matches(response.when);
}
/* return the actual action that will be taken by that block:
@@ -192,40 +212,36 @@ static DNSAction::Action getActualAction(const DynBlock& block)
return g_dynBlockAction;
}
-void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
+namespace dnsdist::DynamicBlocks
+{
+bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const std::string& reason, unsigned int duration, DNSAction::Action action, bool warning, bool beQuiet)
{
- /* network exclusions are address-based only (no port) */
- if (d_excludedSubnets.match(requestor.getNetwork())) {
- /* do not add a block for excluded subnets */
- return;
- }
-
- if (!blocks) {
- blocks = g_dynblockNMG.getCopy();
- }
- struct timespec until = now;
- until.tv_sec += rule.d_blockDuration;
unsigned int count = 0;
- const auto& got = blocks->lookup(requestor);
bool expired = false;
bool wasWarning = false;
bool bpf = false;
+ struct timespec until = now;
+ until.tv_sec += duration;
- if (got) {
+ DynBlock dblock{reason, until, DNSName(), warning ? DNSAction::Action::NoOp : action};
+ dblock.warning = warning;
+
+ const auto& got = blocks.lookup(requestor);
+ if (got != nullptr) {
bpf = got->second.bpf;
if (warning && !got->second.warning) {
/* we have an existing entry which is not a warning,
don't override it */
- return;
+ return false;
}
- else if (!warning && got->second.warning) {
+ if (!warning && got->second.warning) {
wasWarning = true;
}
else {
if (until < got->second.until) {
// had a longer policy
- return;
+ return false;
}
}
@@ -238,14 +254,11 @@ void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock,
}
}
- DynBlock db{rule.d_blockReason, until, DNSName(), warning ? DNSAction::Action::NoOp : rule.d_action};
- db.blocks = count;
- db.warning = warning;
- if (!got || expired || wasWarning) {
- const auto actualAction = getActualAction(db);
- if (g_defaultBPFFilter &&
- ((requestor.isIPv4() && requestor.getBits() == 32) || (requestor.isIPv6() && requestor.getBits() == 128)) &&
- (actualAction == DNSAction::Action::Drop || actualAction == DNSAction::Action::Truncate)) {
+ dblock.blocks = count;
+
+ if (got == nullptr || expired || wasWarning) {
+ const auto actualAction = getActualAction(dblock);
+ if (g_defaultBPFFilter && ((requestor.isIPv4() && requestor.getBits() == 32) || (requestor.isIPv6() && requestor.getBits() == 128)) && (actualAction == DNSAction::Action::Drop || actualAction == DNSAction::Action::Truncate)) {
try {
BPFFilter::MatchAction bpfAction = actualAction == DNSAction::Action::Drop ? BPFFilter::MatchAction::Drop : BPFFilter::MatchAction::Truncate;
if (g_defaultBPFFilter->supportsMatchAction(bpfAction)) {
@@ -259,41 +272,37 @@ void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock,
}
}
- if (!d_beQuiet) {
- warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", warning ? "(warning) " :"", bpf ? "eBPF " : "", requestor.toString(), rule.d_blockDuration, rule.d_blockReason);
+ if (!beQuiet) {
+ warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", warning ? "(warning) " : "", bpf ? "eBPF " : "", requestor.toString(), duration, reason);
}
}
- db.bpf = bpf;
+ dblock.bpf = bpf;
- blocks->insert(requestor).second = std::move(db);
+ blocks.insert(requestor).second = std::move(dblock);
- updated = true;
+ return true;
}
-void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet)
{
- if (d_excludedDomains.check(name)) {
- /* do not add a block for excluded domains */
- return;
- }
-
struct timespec until = now;
- until.tv_sec += rule.d_blockDuration;
+ until.tv_sec += duration;
unsigned int count = 0;
+ DynBlock dblock{reason, until, name.makeLowerCase(), action};
/* be careful, if you try to insert a longer suffix
lookup() might return a shorter one if it is
already in the tree as a final node */
const DynBlock* got = blocks.lookup(name);
- if (got && got->domain != name) {
+ if (got != nullptr && got->domain != name) {
got = nullptr;
}
bool expired = false;
- if (got) {
+ if (got != nullptr) {
if (until < got->until) {
// had a longer policy
- return;
+ return false;
}
if (now < got->until) {
@@ -305,14 +314,55 @@ void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks,
}
}
- DynBlock db{rule.d_blockReason, until, name.makeLowerCase(), rule.d_action};
- db.blocks = count;
+ dblock.blocks = count;
+
+ if (!beQuiet && (got == nullptr || expired)) {
+ warnlog("Inserting dynamic block for %s for %d seconds: %s", name, duration, reason);
+ }
+ blocks.add(name, std::move(dblock));
+ return true;
+}
+}
+
+void DynBlockRulesGroup::addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning)
+{
+ /* network exclusions are address-based only (no port) */
+ if (d_excludedSubnets.match(requestor.getNetwork())) {
+ /* do not add a block for excluded subnets */
+ return;
+ }
+
+ if (!blocks) {
+ blocks = g_dynblockNMG.getCopy();
+ }
+
+ updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, rule.d_blockReason, rule.d_blockDuration, rule.d_action, warning, d_beQuiet);
+ if (updated && d_newBlockHook) {
+ try {
+ d_newBlockHook(dnsdist_ffi_dynamic_block_type_nmt, requestor.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, warning);
+ }
+ catch (const std::exception& exp) {
+ warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what());
+ }
+ }
+}
+
+void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated)
+{
+ if (d_excludedDomains.check(name)) {
+ /* do not add a block for excluded domains */
+ return;
+ }
- if (!d_beQuiet && (!got || expired)) {
- warnlog("Inserting dynamic block for %s for %d seconds: %s", name, rule.d_blockDuration, rule.d_blockReason);
+ updated = dnsdist::DynamicBlocks::addOrRefreshBlockSMT(blocks, now, name, rule.d_blockReason, rule.d_blockDuration, rule.d_action, d_beQuiet);
+ if (updated && d_newBlockHook) {
+ try {
+ d_newBlockHook(dnsdist_ffi_dynamic_block_type_smt, name.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, false);
+ }
+ catch (const std::exception& exp) {
+ warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what());
+ }
}
- blocks.add(name, std::move(db));
- updated = true;
}
void DynBlockRulesGroup::processQueryRules(counts_t& counts, const struct timespec& now)
@@ -330,22 +380,22 @@ void DynBlockRulesGroup::processQueryRules(counts_t& counts, const struct timesp
}
for (const auto& shard : g_rings.d_shards) {
- auto rl = shard->queryRing.lock();
- for(const auto& c : *rl) {
- if (now < c.when) {
+ auto queryRing = shard->queryRing.lock();
+ for (const auto& ringEntry : *queryRing) {
+ if (now < ringEntry.when) {
continue;
}
- bool qRateMatches = d_queryRateRule.matches(c.when);
- bool typeRuleMatches = checkIfQueryTypeMatches(c);
+ bool qRateMatches = d_queryRateRule.matches(ringEntry.when);
+ bool typeRuleMatches = checkIfQueryTypeMatches(ringEntry);
if (qRateMatches || typeRuleMatches) {
- auto& entry = counts[AddressAndPortRange(c.requestor, c.requestor.isIPv4() ? d_v4Mask : d_v6Mask, d_portMask)];
+ auto& entry = counts[AddressAndPortRange(ringEntry.requestor, ringEntry.requestor.isIPv4() ? d_v4Mask : d_v6Mask, d_portMask)];
if (qRateMatches) {
++entry.queries;
}
if (typeRuleMatches) {
- ++entry.d_qtypeCounts[c.qtype];
+ ++entry.d_qtypeCounts[ringEntry.qtype];
}
}
}
@@ -372,6 +422,12 @@ void DynBlockRulesGroup::processResponseRules(counts_t& counts, StatNode& root,
responseCutOff = d_suffixMatchRule.d_cutOff;
}
+ d_respCacheMissRatioRule.d_cutOff = d_respCacheMissRatioRule.d_minTime = now;
+ d_respCacheMissRatioRule.d_cutOff.tv_sec -= d_respCacheMissRatioRule.d_seconds;
+ if (d_respCacheMissRatioRule.d_cutOff < responseCutOff) {
+ responseCutOff = d_respCacheMissRatioRule.d_cutOff;
+ }
+
for (auto& rule : d_rcodeRules) {
rule.second.d_cutOff = rule.second.d_minTime = now;
rule.second.d_cutOff.tv_sec -= rule.second.d_seconds;
@@ -389,39 +445,37 @@ void DynBlockRulesGroup::processResponseRules(counts_t& counts, StatNode& root,
}
for (const auto& shard : g_rings.d_shards) {
- auto rl = shard->respRing.lock();
- for(const auto& c : *rl) {
- if (now < c.when) {
+ auto responseRing = shard->respRing.lock();
+ for (const auto& ringEntry : *responseRing) {
+ if (now < ringEntry.when) {
continue;
}
- if (c.when < responseCutOff) {
+ if (ringEntry.when < responseCutOff) {
continue;
}
- auto& entry = counts[AddressAndPortRange(c.requestor, c.requestor.isIPv4() ? d_v4Mask : d_v6Mask, d_portMask)];
+ auto& entry = counts[AddressAndPortRange(ringEntry.requestor, ringEntry.requestor.isIPv4() ? d_v4Mask : d_v6Mask, d_portMask)];
++entry.responses;
- bool respRateMatches = d_respRateRule.matches(c.when);
- bool suffixMatchRuleMatches = d_suffixMatchRule.matches(c.when);
- bool rcodeRuleMatches = checkIfResponseCodeMatches(c);
+ bool respRateMatches = d_respRateRule.matches(ringEntry.when);
+ bool suffixMatchRuleMatches = d_suffixMatchRule.matches(ringEntry.when);
+ bool rcodeRuleMatches = checkIfResponseCodeMatches(ringEntry);
+ bool respCacheMissRatioRuleMatches = d_respCacheMissRatioRule.matches(ringEntry.when);
- if (respRateMatches || rcodeRuleMatches) {
- if (respRateMatches) {
- entry.respBytes += c.size;
- }
- if (rcodeRuleMatches) {
- ++entry.d_rcodeCounts[c.dh.rcode];
- }
+ if (respRateMatches) {
+ entry.respBytes += ringEntry.size;
+ }
+ if (rcodeRuleMatches) {
+ ++entry.d_rcodeCounts[ringEntry.dh.rcode];
+ }
+ if (respCacheMissRatioRuleMatches && !ringEntry.isACacheHit()) {
+ ++entry.cacheMisses;
}
if (suffixMatchRuleMatches) {
- bool hit = c.ds.sin4.sin_family == 0;
- if (!hit && c.ds.isIPv4() && c.ds.sin4.sin_addr.s_addr == 0 && c.ds.sin4.sin_port == 0) {
- hit = true;
- }
-
- root.submit(c.name, ((c.dh.rcode == 0 && c.usec == std::numeric_limits<unsigned int>::max()) ? -1 : c.dh.rcode), c.size, hit, boost::none);
+ const bool hit = ringEntry.isACacheHit();
+ root.submit(ringEntry.name, ((ringEntry.dh.rcode == 0 && ringEntry.usec == std::numeric_limits<unsigned int>::max()) ? -1 : ringEntry.dh.rcode), ringEntry.size, hit, boost::none);
}
}
}
@@ -462,7 +516,7 @@ void DynBlockMaintenance::purgeExpired(const struct timespec& now)
updated.erase(entry);
}
g_dynblockNMG.setState(std::move(updated));
- g_stats.dynBlocked += bpfBlocked;
+ dnsdist::metrics::g_stats.dynBlocked += bpfBlocked;
}
}
@@ -507,10 +561,10 @@ std::map<std::string, std::list<std::pair<AddressAndPortRange, unsigned int>>> D
topsForReason.pop_front();
}
- topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<AddressAndPortRange, unsigned int>& a, const std::pair<AddressAndPortRange, unsigned int>& b) {
- return a.second < b.second;
- }),
- newEntry);
+ topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<AddressAndPortRange, unsigned int>& rhs, const std::pair<AddressAndPortRange, unsigned int>& lhs) {
+ return rhs.second < lhs.second;
+ }),
+ newEntry);
}
}
@@ -534,10 +588,10 @@ std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaint
topsForReason.pop_front();
}
- topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<DNSName, unsigned int>& a, const std::pair<DNSName, unsigned int>& b) {
- return a.second < b.second;
- }),
- newEntry);
+ topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<DNSName, unsigned int>& rhs, const std::pair<DNSName, unsigned int>& lhs) {
+ return rhs.second < lhs.second;
+ }),
+ newEntry);
}
});
@@ -546,7 +600,7 @@ std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaint
struct DynBlockEntryStat
{
- size_t sum;
+ size_t sum{0};
unsigned int lastSeenValue{0};
};
@@ -577,9 +631,9 @@ void DynBlockMaintenance::generateMetrics()
}
/* do NMG */
- std::map<std::string, std::map<AddressAndPortRange, DynBlockEntryStat>> nm;
+ std::map<std::string, std::map<AddressAndPortRange, DynBlockEntryStat>> netmasks;
for (const auto& reason : s_metricsData.front().nmgData) {
- auto& reasonStat = nm[reason.first];
+ auto& reasonStat = netmasks[reason.first];
/* prepare the counters by scanning the oldest entry (N+1) */
for (const auto& entry : reason.second) {
@@ -597,9 +651,9 @@ void DynBlockMaintenance::generateMetrics()
continue;
}
- auto& nmgData = snap.nmgData;
+ const auto& nmgData = snap.nmgData;
for (const auto& reason : nmgData) {
- auto& reasonStat = nm[reason.first];
+ auto& reasonStat = netmasks[reason.first];
for (const auto& entry : reason.second) {
auto& stat = reasonStat[entry.first];
if (entry.second < stat.lastSeenValue) {
@@ -617,20 +671,20 @@ void DynBlockMaintenance::generateMetrics()
/* now we need to get the top N entries (for each "reason") based on our counters (sum of the last N entries) */
std::map<std::string, std::list<std::pair<AddressAndPortRange, unsigned int>>> topNMGs;
{
- for (const auto& reason : nm) {
+ for (const auto& reason : netmasks) {
auto& topsForReason = topNMGs[reason.first];
for (const auto& entry : reason.second) {
if (topsForReason.size() < s_topN || topsForReason.front().second < entry.second.sum) {
/* Note that this is a gauge, so we need to divide by the number of elapsed seconds */
- auto newEntry = std::pair<AddressAndPortRange, unsigned int>(entry.first, std::round(entry.second.sum / 60.0));
+ auto newEntry = std::pair<AddressAndPortRange, unsigned int>(entry.first, std::round(static_cast<double>(entry.second.sum) / 60.0));
if (topsForReason.size() >= s_topN) {
topsForReason.pop_front();
}
- topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<AddressAndPortRange, unsigned int>& a, const std::pair<AddressAndPortRange, unsigned int>& b) {
- return a.second < b.second;
- }),
- newEntry);
+ topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<AddressAndPortRange, unsigned int>& rhs, const std::pair<AddressAndPortRange, unsigned int>& lhs) {
+ return rhs.second < lhs.second;
+ }),
+ newEntry);
}
}
}
@@ -657,7 +711,7 @@ void DynBlockMaintenance::generateMetrics()
continue;
}
- auto& smtData = snap.smtData;
+ const auto& smtData = snap.smtData;
for (const auto& reason : smtData) {
auto& reasonStat = smt[reason.first];
for (const auto& entry : reason.second) {
@@ -682,15 +736,15 @@ void DynBlockMaintenance::generateMetrics()
for (const auto& entry : reason.second) {
if (topsForReason.size() < s_topN || topsForReason.front().second < entry.second.sum) {
/* Note that this is a gauge, so we need to divide by the number of elapsed seconds */
- auto newEntry = std::pair<DNSName, unsigned int>(entry.first, std::round(entry.second.sum / 60.0));
+ auto newEntry = std::pair<DNSName, unsigned int>(entry.first, std::round(static_cast<double>(entry.second.sum) / 60.0));
if (topsForReason.size() >= s_topN) {
topsForReason.pop_front();
}
- topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<DNSName, unsigned int>& a, const std::pair<DNSName, unsigned int>& b) {
- return a.second < b.second;
- }),
- newEntry);
+ topsForReason.insert(std::lower_bound(topsForReason.begin(), topsForReason.end(), newEntry, [](const std::pair<DNSName, unsigned int>& lhs, const std::pair<DNSName, unsigned int>& rhs) {
+ return lhs.second < rhs.second;
+ }),
+ newEntry);
}
}
}
@@ -727,7 +781,7 @@ void DynBlockMaintenance::run()
sleepDelay = std::min(sleepDelay, (nextMetricsGeneration - now));
// coverity[store_truncates_time_t]
- sleep(sleepDelay);
+ std::this_thread::sleep_for(std::chrono::seconds(sleepDelay));
try {
now = time(nullptr);
@@ -749,7 +803,9 @@ void DynBlockMaintenance::run()
}
if (s_expiredDynBlocksPurgeInterval > 0 && now >= nextExpiredPurge) {
- struct timespec tspec;
+ struct timespec tspec
+ {
+ };
gettime(&tspec);
purgeExpired(tspec);
@@ -774,4 +830,163 @@ std::map<std::string, std::list<std::pair<DNSName, unsigned int>>> DynBlockMaint
{
return s_tops.lock()->topSMTsByReason;
}
+
+std::string DynBlockRulesGroup::DynBlockRule::toString() const
+{
+ if (!isEnabled()) {
+ return "";
+ }
+
+ std::stringstream result;
+ if (d_action != DNSAction::Action::None) {
+ result << DNSAction::typeToString(d_action) << " ";
+ }
+ else {
+ result << "Apply the global DynBlock action ";
+ }
+ result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_rate) << " during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
+
+ return result.str();
+}
+
+bool DynBlockRulesGroup::DynBlockRule::matches(const struct timespec& when)
+{
+ if (!d_enabled) {
+ return false;
+ }
+
+ if (d_seconds > 0 && when < d_cutOff) {
+ return false;
+ }
+
+ if (when < d_minTime) {
+ d_minTime = when;
+ }
+
+ return true;
+}
+
+bool DynBlockRulesGroup::DynBlockRule::rateExceeded(unsigned int count, const struct timespec& now) const
+{
+ if (!d_enabled) {
+ return false;
+ }
+
+ double delta = d_seconds > 0 ? d_seconds : DiffTime(now, d_minTime);
+ double limit = delta * d_rate;
+ return (count > limit);
+}
+
+bool DynBlockRulesGroup::DynBlockRule::warningRateExceeded(unsigned int count, const struct timespec& now) const
+{
+ if (!d_enabled) {
+ return false;
+ }
+
+ if (d_warningRate == 0) {
+ return false;
+ }
+
+ double delta = d_seconds > 0 ? d_seconds : DiffTime(now, d_minTime);
+ double limit = delta * d_warningRate;
+ return (count > limit);
+}
+
+bool DynBlockRulesGroup::DynBlockRatioRule::ratioExceeded(unsigned int total, unsigned int count) const
+{
+ if (!d_enabled) {
+ return false;
+ }
+
+ if (total < d_minimumNumberOfResponses) {
+ return false;
+ }
+
+ double allowed = d_ratio * static_cast<double>(total);
+ return (count > allowed);
+}
+
+bool DynBlockRulesGroup::DynBlockRatioRule::warningRatioExceeded(unsigned int total, unsigned int count) const
+{
+ if (!d_enabled) {
+ return false;
+ }
+
+ if (d_warningRatio == 0.0) {
+ return false;
+ }
+
+ if (total < d_minimumNumberOfResponses) {
+ return false;
+ }
+
+ double allowed = d_warningRatio * static_cast<double>(total);
+ return (count > allowed);
+}
+
+std::string DynBlockRulesGroup::DynBlockRatioRule::toString() const
+{
+ if (!isEnabled()) {
+ return "";
+ }
+
+ std::stringstream result;
+ if (d_action != DNSAction::Action::None) {
+ result << DNSAction::typeToString(d_action) << " ";
+ }
+ else {
+ result << "Apply the global DynBlock action ";
+ }
+ result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_ratio) << " ratio during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
+
+ return result.str();
+}
+
+bool DynBlockRulesGroup::DynBlockCacheMissRatioRule::checkGlobalCacheHitRatio() const
+{
+ auto globalMisses = dnsdist::metrics::g_stats.cacheMisses.load();
+ auto globalHits = dnsdist::metrics::g_stats.cacheHits.load();
+ if (globalMisses == 0 || globalHits == 0) {
+ return false;
+ }
+ double globalCacheHitRatio = static_cast<double>(globalHits) / static_cast<double>(globalHits + globalMisses);
+ return globalCacheHitRatio >= d_minimumGlobalCacheHitRatio;
+}
+
+bool DynBlockRulesGroup::DynBlockCacheMissRatioRule::ratioExceeded(unsigned int total, unsigned int count) const
+{
+ if (!DynBlockRulesGroup::DynBlockRatioRule::ratioExceeded(total, count)) {
+ return false;
+ }
+
+ return checkGlobalCacheHitRatio();
+}
+
+bool DynBlockRulesGroup::DynBlockCacheMissRatioRule::warningRatioExceeded(unsigned int total, unsigned int count) const
+{
+ if (!DynBlockRulesGroup::DynBlockRatioRule::warningRatioExceeded(total, count)) {
+ return false;
+ }
+
+ return checkGlobalCacheHitRatio();
+}
+
+std::string DynBlockRulesGroup::DynBlockCacheMissRatioRule::toString() const
+{
+ if (!isEnabled()) {
+ return "";
+ }
+
+ std::stringstream result;
+ if (d_action != DNSAction::Action::None) {
+ result << DNSAction::typeToString(d_action) << " ";
+ }
+ else {
+ result << "Apply the global DynBlock action ";
+ }
+ result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_ratio) << " ratio during the last " << d_seconds << " seconds, with a global cache-hit ratio of at least " << d_minimumGlobalCacheHitRatio << ", reason: '" << d_blockReason << "'";
+
+ return result.str();
+}
+
#endif /* DISABLE_DYNBLOCKS */
diff --git a/dnsdist-dynblocks.hh b/dnsdist-dynblocks.hh
index c9b1e4a..1a8b3a6 100644
--- a/dnsdist-dynblocks.hh
+++ b/dnsdist-dynblocks.hh
@@ -28,40 +28,51 @@
#include "dnsdist-rings.hh"
#include "statnode.hh"
-extern "C" {
+extern "C"
+{
#include "dnsdist-lua-inspection-ffi.h"
}
// dnsdist_ffi_stat_node_t is a lightuserdata
-template<>
-struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*> {
- static const int minSize = 1;
- static const int maxSize = 1;
-
- static PushedObject push(lua_State* state, dnsdist_ffi_stat_node_t* ptr) noexcept {
- lua_pushlightuserdata(state, ptr);
- return PushedObject{state, 1};
- }
+template <>
+struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*>
+{
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, dnsdist_ffi_stat_node_t* ptr) noexcept
+ {
+ lua_pushlightuserdata(state, ptr);
+ return PushedObject{state, 1};
+ }
};
-typedef std::function<bool(dnsdist_ffi_stat_node_t*)> dnsdist_ffi_stat_node_visitor_t;
+using dnsdist_ffi_stat_node_visitor_t = std::function<bool(dnsdist_ffi_stat_node_t*)>;
+
+struct SMTBlockParameters
+{
+ std::optional<std::string> d_reason;
+ std::optional<DNSAction::Action> d_action;
+};
struct dnsdist_ffi_stat_node_t
{
- dnsdist_ffi_stat_node_t(const StatNode& node_, const StatNode::Stat& self_, const StatNode::Stat& children_, std::optional<std::string>& reason_): node(node_), self(self_), children(children_), reason(reason_)
+ dnsdist_ffi_stat_node_t(const StatNode& node_, const StatNode::Stat& self_, const StatNode::Stat& children_, SMTBlockParameters& blockParameters) :
+ node(node_), self(self_), children(children_), d_blockParameters(blockParameters)
{
}
const StatNode& node;
const StatNode::Stat& self;
const StatNode::Stat& children;
- std::optional<std::string>& reason;
+ SMTBlockParameters& d_blockParameters;
};
+using dnsdist_ffi_dynamic_block_inserted_hook = std::function<void(uint8_t type, const char* key, const char* reason, uint8_t action, uint64_t duration, bool warning)>;
+
class DynBlockRulesGroup
{
private:
-
struct Counts
{
std::map<uint8_t, uint64_t> d_rcodeCounts;
@@ -69,83 +80,27 @@ private:
uint64_t queries{0};
uint64_t responses{0};
uint64_t respBytes{0};
+ uint64_t cacheMisses{0};
};
struct DynBlockRule
{
- DynBlockRule(): d_enabled(false)
+ DynBlockRule() = default;
+ DynBlockRule(const std::string& blockReason, unsigned int blockDuration, unsigned int rate, unsigned int warningRate, unsigned int seconds, DNSAction::Action action) :
+ d_blockReason(blockReason), d_blockDuration(blockDuration), d_rate(rate), d_warningRate(warningRate), d_seconds(seconds), d_action(action), d_enabled(true)
{
}
- DynBlockRule(const std::string& blockReason, unsigned int blockDuration, unsigned int rate, unsigned int warningRate, unsigned int seconds, DNSAction::Action action): d_blockReason(blockReason), d_blockDuration(blockDuration), d_rate(rate), d_warningRate(warningRate), d_seconds(seconds), d_action(action), d_enabled(true)
- {
- }
-
- bool matches(const struct timespec& when)
- {
- if (!d_enabled) {
- return false;
- }
-
- if (d_seconds && when < d_cutOff) {
- return false;
- }
-
- if (when < d_minTime) {
- d_minTime = when;
- }
-
- return true;
- }
-
- bool rateExceeded(unsigned int count, const struct timespec& now) const
- {
- if (!d_enabled) {
- return false;
- }
-
- double delta = d_seconds ? d_seconds : DiffTime(now, d_minTime);
- double limit = delta * d_rate;
- return (count > limit);
- }
-
- bool warningRateExceeded(unsigned int count, const struct timespec& now) const
- {
- if (!d_enabled) {
- return false;
- }
-
- if (d_warningRate == 0) {
- return false;
- }
-
- double delta = d_seconds ? d_seconds : DiffTime(now, d_minTime);
- double limit = delta * d_warningRate;
- return (count > limit);
- }
+ bool matches(const struct timespec& when);
+ bool rateExceeded(unsigned int count, const struct timespec& now) const;
+ bool warningRateExceeded(unsigned int count, const struct timespec& now) const;
bool isEnabled() const
{
return d_enabled;
}
- std::string toString() const
- {
- if (!isEnabled()) {
- return "";
- }
-
- std::stringstream result;
- if (d_action != DNSAction::Action::None) {
- result << DNSAction::typeToString(d_action) << " ";
- }
- else {
- result << "Apply the global DynBlock action ";
- }
- result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_rate) << " during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
-
- return result.str();
- }
+ std::string toString() const;
std::string d_blockReason;
struct timespec d_cutOff;
@@ -158,72 +113,40 @@ private:
bool d_enabled{false};
};
- struct DynBlockRatioRule: DynBlockRule
+ struct DynBlockRatioRule : DynBlockRule
{
- DynBlockRatioRule(): DynBlockRule()
- {
- }
-
- DynBlockRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses): DynBlockRule(blockReason, blockDuration, 0, 0, seconds, action), d_minimumNumberOfResponses(minimumNumberOfResponses), d_ratio(ratio), d_warningRatio(warningRatio)
+ DynBlockRatioRule() = default;
+ DynBlockRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses) :
+ DynBlockRule(blockReason, blockDuration, 0, 0, seconds, action), d_minimumNumberOfResponses(minimumNumberOfResponses), d_ratio(ratio), d_warningRatio(warningRatio)
{
}
- bool ratioExceeded(unsigned int total, unsigned int count) const
- {
- if (!d_enabled) {
- return false;
- }
-
- if (total < d_minimumNumberOfResponses) {
- return false;
- }
+ bool ratioExceeded(unsigned int total, unsigned int count) const;
+ bool warningRatioExceeded(unsigned int total, unsigned int count) const;
+ std::string toString() const;
- double allowed = d_ratio * static_cast<double>(total);
- return (count > allowed);
- }
+ size_t d_minimumNumberOfResponses{0};
+ double d_ratio{0.0};
+ double d_warningRatio{0.0};
+ };
- bool warningRatioExceeded(unsigned int total, unsigned int count) const
+ struct DynBlockCacheMissRatioRule : public DynBlockRatioRule
+ {
+ DynBlockCacheMissRatioRule() = default;
+ DynBlockCacheMissRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio) :
+ DynBlockRatioRule(blockReason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses), d_minimumGlobalCacheHitRatio(minimumGlobalCacheHitRatio)
{
- if (!d_enabled) {
- return false;
- }
-
- if (d_warningRatio == 0.0) {
- return false;
- }
-
- if (total < d_minimumNumberOfResponses) {
- return false;
- }
-
- double allowed = d_warningRatio * static_cast<double>(total);
- return (count > allowed);
}
- std::string toString() const
- {
- if (!isEnabled()) {
- return "";
- }
-
- std::stringstream result;
- if (d_action != DNSAction::Action::None) {
- result << DNSAction::typeToString(d_action) << " ";
- }
- else {
- result << "Apply the global DynBlock action ";
- }
- result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_ratio) << " ratio during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
-
- return result.str();
- }
+ bool checkGlobalCacheHitRatio() const;
+ bool ratioExceeded(unsigned int total, unsigned int count) const;
+ bool warningRatioExceeded(unsigned int total, unsigned int count) const;
+ std::string toString() const;
- size_t d_minimumNumberOfResponses{0};
- double d_ratio{0.0};
- double d_warningRatio{0.0};
+ double d_minimumGlobalCacheHitRatio{0.0};
};
- typedef std::unordered_map<AddressAndPortRange, Counts, AddressAndPortRange::hash> counts_t;
+ using counts_t = std::unordered_map<AddressAndPortRange, Counts, AddressAndPortRange::hash>;
public:
DynBlockRulesGroup()
@@ -259,18 +182,28 @@ public:
entry = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
}
- typedef std::function<std::tuple<bool, boost::optional<std::string>>(const StatNode&, const StatNode::Stat&, const StatNode::Stat&)> smtVisitor_t;
+ void setCacheMissRatio(double ratio, double warningRatio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio)
+ {
+ d_respCacheMissRatioRule = DynBlockCacheMissRatioRule(reason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ }
+
+ using smtVisitor_t = std::function<std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(const StatNode&, const StatNode::Stat&, const StatNode::Stat&)>;
void setSuffixMatchRule(unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, smtVisitor_t visitor)
{
d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
- d_smtVisitor = visitor;
+ d_smtVisitor = std::move(visitor);
}
void setSuffixMatchRuleFFI(unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, dnsdist_ffi_stat_node_visitor_t visitor)
{
d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
- d_smtVisitorFFI = visitor;
+ d_smtVisitorFFI = std::move(visitor);
+ }
+
+ void setNewBlockHook(const dnsdist_ffi_dynamic_block_inserted_hook& callback)
+ {
+ d_newBlockHook = callback;
}
void setMasks(uint8_t v4, uint8_t v6, uint8_t port)
@@ -332,6 +265,7 @@ public:
result << "Query rate rule: " << d_queryRateRule.toString() << std::endl;
result << "Response rate rule: " << d_respRateRule.toString() << std::endl;
result << "SuffixMatch rule: " << d_suffixMatchRule.toString() << std::endl;
+ result << "Response cache-miss ratio rule: " << d_respCacheMissRatioRule.toString() << std::endl;
result << "RCode rules: " << std::endl;
for (const auto& rule : d_rcodeRules) {
result << "- " << RCode::to_s(rule.first) << ": " << rule.second.toString() << std::endl;
@@ -355,18 +289,18 @@ public:
}
private:
-
+ void applySMT(const struct timespec& now, StatNode& statNodeRoot);
bool checkIfQueryTypeMatches(const Rings::Query& query);
bool checkIfResponseCodeMatches(const Rings::Response& response);
- void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
+ void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
void addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
- void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, false);
}
- void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, true);
}
@@ -378,7 +312,7 @@ private:
bool hasResponseRules() const
{
- return d_respRateRule.isEnabled() || !d_rcodeRules.empty() || !d_rcodeRatioRules.empty();
+ return d_respRateRule.isEnabled() || !d_rcodeRules.empty() || !d_rcodeRatioRules.empty() || d_respCacheMissRatioRule.isEnabled();
}
bool hasSuffixMatchRules() const
@@ -400,10 +334,12 @@ private:
DynBlockRule d_queryRateRule;
DynBlockRule d_respRateRule;
DynBlockRule d_suffixMatchRule;
+ DynBlockCacheMissRatioRule d_respCacheMissRatioRule;
NetmaskGroup d_excludedSubnets;
SuffixMatchNode d_excludedDomains;
smtVisitor_t d_smtVisitor;
dnsdist_ffi_stat_node_visitor_t d_smtVisitorFFI;
+ dnsdist_ffi_dynamic_block_inserted_hook d_newBlockHook;
uint8_t d_v6Mask{128};
uint8_t d_v4Mask{32};
uint8_t d_portMask{0};
@@ -449,4 +385,9 @@ private:
static size_t s_topN;
};
+namespace dnsdist::DynamicBlocks
+{
+bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const std::string& reason, unsigned int duration, DNSAction::Action action, bool warning, bool beQuiet);
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet);
+}
#endif /* DISABLE_DYNBLOCKS */
diff --git a/dnsdist-dynbpf.cc b/dnsdist-dynbpf.cc
index c19844d..9ede03f 100644
--- a/dnsdist-dynbpf.cc
+++ b/dnsdist-dynbpf.cc
@@ -78,7 +78,7 @@ std::vector<std::tuple<ComboAddress, uint64_t, struct timespec> > DynBPFFilter::
for (const auto& stat : stats) {
const container_t::iterator it = data->d_entries.find(stat.first);
if (it != data->d_entries.end()) {
- result.push_back(std::make_tuple(stat.first, stat.second, it->d_until));
+ result.emplace_back(stat.first, stat.second, it->d_until);
}
}
return result;
diff --git a/dnsdist-ecs.cc b/dnsdist-ecs.cc
index 9e9d9c3..2cad194 100644
--- a/dnsdist-ecs.cc
+++ b/dnsdist-ecs.cc
@@ -21,6 +21,7 @@
*/
#include "dolog.hh"
#include "dnsdist.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
@@ -44,13 +45,15 @@ bool g_addEDNSToSelfGeneratedResponses{true};
int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
- if (ntohs(dh->arcount) == 0)
+ if (ntohs(dh->arcount) == 0) {
return ENOENT;
+ }
- if (ntohs(dh->qdcount) == 0)
+ if (ntohs(dh->qdcount) == 0) {
return ENOENT;
+ }
PacketReader pr(std::string_view(reinterpret_cast<const char*>(initialPacket.data()), initialPacket.size()));
@@ -152,7 +155,7 @@ static bool addOrReplaceEDNSOption(std::vector<std::pair<uint16_t, std::string>>
bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->qdcount) == 0) {
return false;
@@ -269,7 +272,7 @@ static bool slowParseEDNSOptions(const PacketBuffer& packet, EDNSOptionViewMap&
return false;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (ntohs(dh->qdcount) == 0) {
return false;
@@ -324,10 +327,11 @@ int locateEDNSOptRR(const PacketBuffer& packet, uint16_t * optStart, size_t * op
assert(optStart != NULL);
assert(optLen != NULL);
assert(last != NULL);
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
- if (ntohs(dh->arcount) == 0)
+ if (ntohs(dh->arcount) == 0) {
return ENOENT;
+ }
PacketReader pr(std::string_view(reinterpret_cast<const char*>(packet.data()), packet.size()));
@@ -390,14 +394,15 @@ int getEDNSOptionsStart(const PacketBuffer& packet, const size_t offset, uint16_
{
assert(optRDPosition != nullptr);
assert(remaining != nullptr);
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (offset >= packet.size()) {
return ENOENT;
}
- if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->arcount) != 1 || ntohs(dh->nscount) != 0)
+ if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->arcount) != 1 || ntohs(dh->nscount) != 0) {
return ENOENT;
+ }
size_t pos = sizeof(dnsheader) + offset;
pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
@@ -571,10 +576,12 @@ static bool addEDNSWithECS(PacketBuffer& packet, size_t maximumSize, const strin
return false;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
- uint16_t arcount = ntohs(dh->arcount);
- arcount++;
- dh->arcount = htons(arcount);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ uint16_t arcount = ntohs(header.arcount);
+ arcount++;
+ header.arcount = htons(arcount);
+ return true;
+ });
ednsAdded = true;
ecsAdded = true;
@@ -585,7 +592,7 @@ bool handleEDNSClientSubnet(PacketBuffer& packet, const size_t maximumSize, cons
{
assert(qnameWireLength <= packet.size());
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
if (ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || (ntohs(dh->arcount) != 0 && ntohs(dh->arcount) != 1)) {
PacketBuffer newContent;
@@ -752,7 +759,7 @@ bool isEDNSOptionInOpt(const PacketBuffer& packet, const size_t optStart, const
int rewriteResponseWithoutEDNSOption(const PacketBuffer& initialPacket, const uint16_t optionCodeToSkip, PacketBuffer& newContent)
{
assert(initialPacket.size() >= sizeof(dnsheader));
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->arcount) == 0)
return ENOENT;
@@ -852,8 +859,10 @@ bool addEDNS(PacketBuffer& packet, size_t maximumSize, bool dnssecOK, uint16_t p
return false;
}
- auto dh = reinterpret_cast<dnsheader*>(packet.data());
- dh->arcount = htons(ntohs(dh->arcount) + 1);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.arcount = htons(ntohs(header.arcount) + 1);
+ return true;
+ });
return true;
}
@@ -894,17 +903,19 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone,
/* chop off everything after the question */
packet.resize(queryPartSize);
- dh = dq.getHeader();
- if (nxd) {
- dh->rcode = RCode::NXDomain;
- }
- else {
- dh->rcode = RCode::NoError;
- }
- dh->qr = true;
- dh->ancount = 0;
- dh->nscount = 0;
- dh->arcount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [nxd](dnsheader& header) {
+ if (nxd) {
+ header.rcode = RCode::NXDomain;
+ }
+ else {
+ header.rcode = RCode::NoError;
+ }
+ header.qr = true;
+ header.ancount = 0;
+ header.nscount = 0;
+ header.arcount = 0;
+ return true;
+ });
rdLength = htons(rdLength);
ttl = htonl(ttl);
@@ -934,16 +945,18 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone,
}
packet.insert(packet.end(), soa.begin(), soa.end());
- dh = dq.getHeader();
/* We are populating a response with only the query in place, order of sections is QD,AN,NS,AR
NS (authority) is before AR (additional) so we can just decide which section the SOA record is in here
and have EDNS added to AR afterwards */
- if (soaInAuthoritySection) {
- dh->nscount = htons(1);
- } else {
- dh->arcount = htons(1);
- }
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [soaInAuthoritySection](dnsheader& header) {
+ if (soaInAuthoritySection) {
+ header.nscount = htons(1);
+ } else {
+ header.arcount = htons(1);
+ }
+ return true;
+ });
if (hadEDNS) {
/* now we need to add a new OPT record */
@@ -982,7 +995,10 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dq)
/* remove the existing OPT record, and everything else that follows (any SIG or TSIG would be useless anyway) */
packet.resize(packet.size() - existingOptLen);
- dq.getHeader()->arcount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.arcount = 0;
+ return true;
+ });
if (g_addEDNSToSelfGeneratedResponses) {
/* now we need to add a new OPT record */
@@ -1107,7 +1123,10 @@ bool setEDNSOption(DNSQuestion& dq, uint16_t ednsCode, const std::string& ednsDa
auto& data = dq.getMutableData();
if (generateOptRR(optRData, data, dq.getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
- dq.getHeader()->arcount = htons(1);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(1);
+ return true;
+ });
// make sure that any EDNS sent by the backend is removed before forwarding the response to the client
dq.ids.ednsAdded = true;
}
@@ -1129,17 +1148,22 @@ bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uin
hadEDNS = getEDNS0Record(buffer, edns0);
}
- auto dh = reinterpret_cast<dnsheader*>(buffer.data());
- dh->rcode = rcode;
- dh->ad = false;
- dh->aa = false;
- dh->ra = dh->rd;
- dh->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [rcode,clearAnswers](dnsheader& header) {
+ header.rcode = rcode;
+ header.ad = false;
+ header.aa = false;
+ header.ra = header.rd;
+ header.qr = true;
+
+ if (clearAnswers) {
+ header.ancount = 0;
+ header.nscount = 0;
+ header.arcount = 0;
+ }
+ return true;
+ });
if (clearAnswers) {
- dh->ancount = 0;
- dh->nscount = 0;
- dh->arcount = 0;
buffer.resize(sizeof(dnsheader) + qnameLength + sizeof(uint16_t) + sizeof(uint16_t));
if (hadEDNS) {
DNSQuestion dq(state, buffer);
diff --git a/dnsdist-ecs.hh b/dnsdist-ecs.hh
index 653052d..f5d215f 100644
--- a/dnsdist-ecs.hh
+++ b/dnsdist-ecs.hh
@@ -58,6 +58,7 @@ bool getEDNS0Record(const PacketBuffer& packet, EDNS0Record& edns0);
bool setEDNSOption(DNSQuestion& dq, uint16_t ednsCode, const std::string& data);
+struct InternalQueryState;
namespace dnsdist {
bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uint8_t rcode, bool clearAnswers);
}
diff --git a/dnsdist-edns.cc b/dnsdist-edns.cc
new file mode 100644
index 0000000..0aa8539
--- /dev/null
+++ b/dnsdist-edns.cc
@@ -0,0 +1,94 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist-ecs.hh"
+#include "dnsdist-edns.hh"
+#include "ednsoptions.hh"
+#include "ednsextendederror.hh"
+
+namespace dnsdist::edns
+{
+std::pair<std::optional<uint16_t>, std::optional<std::string>> getExtendedDNSError(const PacketBuffer& packet)
+{
+ uint16_t optStart = 0;
+ size_t optLen = 0;
+ bool last = false;
+
+ int res = locateEDNSOptRR(packet, &optStart, &optLen, &last);
+
+ if (res != 0) {
+ return {std::nullopt, std::nullopt};
+ }
+
+ size_t optContentStart = 0;
+ uint16_t optContentLen = 0;
+ uint16_t infoCode{0};
+ std::optional<std::string> extraText{std::nullopt};
+ /* we need at least 2 bytes after the option length (info-code) */
+ if (!isEDNSOptionInOpt(packet, optStart, optLen, EDNSOptionCode::EXTENDEDERROR, &optContentStart, &optContentLen) || optContentLen < sizeof(infoCode)) {
+ return {std::nullopt, std::nullopt};
+ }
+ memcpy(&infoCode, &packet.at(optContentStart), sizeof(infoCode));
+ infoCode = ntohs(infoCode);
+
+ if (optContentLen > sizeof(infoCode)) {
+ extraText = std::string();
+ extraText->resize(optContentLen - sizeof(infoCode));
+ memcpy(extraText->data(), &packet.at(optContentStart + sizeof(infoCode)), optContentLen - sizeof(infoCode));
+ }
+ return {infoCode, std::move(extraText)};
+}
+
+bool addExtendedDNSError(PacketBuffer& packet, size_t maximumPacketSize, uint16_t code, const std::string& extraStatus)
+{
+ uint16_t optStart = 0;
+ size_t optLen = 0;
+ bool last = false;
+
+ int res = locateEDNSOptRR(packet, &optStart, &optLen, &last);
+
+ if (res != 0) {
+ /* no EDNS OPT record in the response, something is not right */
+ return false;
+ }
+
+ EDNSExtendedError ede{.infoCode = code, .extraText = extraStatus};
+ auto edeOptionPayload = makeEDNSExtendedErrorOptString(ede);
+ std::string edeOption;
+ generateEDNSOption(EDNSOptionCode::EXTENDEDERROR, edeOptionPayload, edeOption);
+
+ /* we might have one record after the OPT one, we need to rewrite
+ the whole packet because of compression */
+ PacketBuffer newContent;
+ bool ednsAdded = false;
+ bool edeAdded = false;
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, true, edeOption)) {
+ return false;
+ }
+
+ if (newContent.size() > maximumPacketSize) {
+ return false;
+ }
+
+ packet = std::move(newContent);
+ return true;
+}
+}
diff --git a/dnsdist-edns.hh b/dnsdist-edns.hh
new file mode 100644
index 0000000..8e60e5b
--- /dev/null
+++ b/dnsdist-edns.hh
@@ -0,0 +1,34 @@
+/*
+ * 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 <optional>
+#include <string>
+#include <utility>
+
+#include "noinitvector.hh"
+
+namespace dnsdist::edns
+{
+std::pair<std::optional<uint16_t>, std::optional<std::string>> getExtendedDNSError(const PacketBuffer& packet);
+bool addExtendedDNSError(PacketBuffer& packet, size_t maximumPacketSize, uint16_t code, const std::string& extraStatus);
+}
diff --git a/dnsdist-healthchecks.cc b/dnsdist-healthchecks.cc
index dc77022..3680557 100644
--- a/dnsdist-healthchecks.cc
+++ b/dnsdist-healthchecks.cc
@@ -33,9 +33,15 @@ bool g_verboseHealthChecks{false};
struct HealthCheckData
{
- enum class TCPState : uint8_t { WritingQuery, ReadingResponseSize, ReadingResponse };
+ enum class TCPState : uint8_t
+ {
+ WritingQuery,
+ ReadingResponseSize,
+ ReadingResponse
+ };
- HealthCheckData(FDMultiplexer& mplexer, const std::shared_ptr<DownstreamState>& ds, DNSName&& checkName, uint16_t checkType, uint16_t checkClass, uint16_t queryID): d_ds(ds), d_mplexer(mplexer), d_udpSocket(-1), d_checkName(std::move(checkName)), d_checkType(checkType), d_checkClass(checkClass), d_queryID(queryID)
+ HealthCheckData(FDMultiplexer& mplexer, std::shared_ptr<DownstreamState> downstream, DNSName&& checkName, uint16_t checkType, uint16_t checkClass, uint16_t queryID) :
+ d_ds(std::move(downstream)), d_mplexer(mplexer), d_udpSocket(-1), d_checkName(std::move(checkName)), d_checkType(checkType), d_checkClass(checkClass), d_queryID(queryID)
{
}
@@ -46,7 +52,10 @@ struct HealthCheckData
PacketBuffer d_buffer;
Socket d_udpSocket;
DNSName d_checkName;
- struct timeval d_ttd{0, 0};
+ struct timeval d_ttd
+ {
+ 0, 0
+ };
size_t d_bufferPos{0};
uint16_t d_checkType;
uint16_t d_checkClass;
@@ -57,64 +66,72 @@ struct HealthCheckData
static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
{
- auto& ds = data->d_ds;
+ const auto& downstream = data->d_ds;
try {
if (data->d_buffer.size() < sizeof(dnsheader)) {
+ ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
if (g_verboseHealthChecks) {
- infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), ds->getNameWithAddr(), sizeof(dnsheader));
+ infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader));
}
return false;
}
- const dnsheader * responseHeader = reinterpret_cast<const dnsheader*>(data->d_buffer.data());
- if (responseHeader->id != data->d_queryID) {
+ dnsheader_aligned responseHeader(data->d_buffer.data());
+ if (responseHeader.get()->id != data->d_queryID) {
+ ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
if (g_verboseHealthChecks) {
- infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader->id, ds->getNameWithAddr(), data->d_queryID);
+ infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID);
}
return false;
}
- if (!responseHeader->qr) {
+ if (!responseHeader.get()->qr) {
+ ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
if (g_verboseHealthChecks) {
- infolog("Invalid health check response from backend %s, expecting QR to be set", ds->getNameWithAddr());
+ infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr());
}
return false;
}
- if (responseHeader->rcode == RCode::ServFail) {
+ if (responseHeader.get()->rcode == RCode::ServFail) {
+ ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
if (g_verboseHealthChecks) {
- infolog("Backend %s responded to health check with ServFail", ds->getNameWithAddr());
+ infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr());
}
return false;
}
- if (ds->d_config.mustResolve && (responseHeader->rcode == RCode::NXDomain || responseHeader->rcode == RCode::Refused)) {
+ if (downstream->d_config.mustResolve && (responseHeader.get()->rcode == RCode::NXDomain || responseHeader.get()->rcode == RCode::Refused)) {
+ ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
if (g_verboseHealthChecks) {
- infolog("Backend %s responded to health check with %s while mustResolve is set", ds->getNameWithAddr(), responseHeader->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
+ infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
}
return false;
}
- uint16_t receivedType;
- uint16_t receivedClass;
- DNSName receivedName(reinterpret_cast<const char*>(data->d_buffer.data()), data->d_buffer.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
+ uint16_t receivedType{0};
+ uint16_t receivedClass{0};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ DNSName receivedName(reinterpret_cast<const char*>(data->d_buffer.data()), static_cast<int>(data->d_buffer.size()), sizeof(dnsheader), false, &receivedType, &receivedClass);
if (receivedName != data->d_checkName || receivedType != data->d_checkType || receivedClass != data->d_checkClass) {
+ ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
if (g_verboseHealthChecks) {
- infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", ds->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
+ infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
}
return false;
}
}
- catch(const std::exception& e) {
+ catch (const std::exception& e) {
+ ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
if (g_verboseHealthChecks) {
- infolog("Error checking the health of backend %s: %s", ds->getNameWithAddr(), e.what());
+ infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
}
return false;
}
catch (...) {
if (g_verboseHealthChecks) {
- infolog("Unknown exception while checking the health of backend %s", ds->getNameWithAddr());
+ infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
}
return false;
}
@@ -125,15 +142,17 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
class HealthCheckQuerySender : public TCPQuerySender
{
public:
- HealthCheckQuerySender(std::shared_ptr<HealthCheckData>& data): d_data(data)
- {
- }
-
- ~HealthCheckQuerySender()
+ HealthCheckQuerySender(std::shared_ptr<HealthCheckData>& data) :
+ d_data(data)
{
}
+ HealthCheckQuerySender(const HealthCheckQuerySender&) = default;
+ HealthCheckQuerySender(HealthCheckQuerySender&&) = default;
+ HealthCheckQuerySender& operator=(const HealthCheckQuerySender&) = default;
+ HealthCheckQuerySender& operator=(HealthCheckQuerySender&&) = default;
+ ~HealthCheckQuerySender() override = default;
- bool active() const override
+ [[nodiscard]] bool active() const override
{
return true;
}
@@ -149,8 +168,9 @@ public:
throw std::runtime_error("Unexpected XFR reponse to a health check query");
}
- void notifyIOError(InternalQueryState&& query, const struct timeval& now) override
+ void notifyIOError(const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
+ ++d_data->d_ds->d_healthCheckMetrics.d_networkErrors;
d_data->d_ds->submitHealthCheckResult(d_data->d_initial, false);
}
@@ -158,24 +178,40 @@ private:
std::shared_ptr<HealthCheckData> d_data;
};
-static void healthCheckUDPCallback(int fd, FDMultiplexer::funcparam_t& param)
+static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
{
auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
- data->d_mplexer.removeReadFD(fd);
+ ssize_t got = 0;
ComboAddress from;
- from.sin4.sin_family = data->d_ds->d_config.remote.sin4.sin_family;
- auto fromlen = from.getSocklen();
- data->d_buffer.resize(512);
- auto got = recvfrom(data->d_udpSocket.getHandle(), &data->d_buffer.at(0), data->d_buffer.size(), 0, reinterpret_cast<sockaddr *>(&from), &fromlen);
- if (got < 0) {
- int savederrno = errno;
- if (g_verboseHealthChecks) {
- infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
+ do {
+ from.sin4.sin_family = data->d_ds->d_config.remote.sin4.sin_family;
+ auto fromlen = from.getSocklen();
+ data->d_buffer.resize(512);
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ got = recvfrom(data->d_udpSocket.getHandle(), data->d_buffer.data(), data->d_buffer.size(), 0, reinterpret_cast<sockaddr*>(&from), &fromlen);
+ if (got < 0) {
+ int savederrno = errno;
+ if (savederrno == EINTR) {
+ /* interrupted before any data was available, let's try again */
+ continue;
+ }
+ if (savederrno == EWOULDBLOCK || savederrno == EAGAIN) {
+ /* spurious wake-up, let's return to sleep */
+ return;
+ }
+
+ if (g_verboseHealthChecks) {
+ infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
+ }
+ ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
+ data->d_ds->submitHealthCheckResult(data->d_initial, false);
+ data->d_mplexer.removeReadFD(descriptor);
+ return;
}
- data->d_ds->submitHealthCheckResult(data->d_initial, false);
- return;
- }
+ } while (got < 0);
+
data->d_buffer.resize(static_cast<size_t>(got));
/* we are using a connected socket but hey.. */
@@ -183,14 +219,16 @@ static void healthCheckUDPCallback(int fd, FDMultiplexer::funcparam_t& param)
if (g_verboseHealthChecks) {
infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort());
}
+ ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
data->d_ds->submitHealthCheckResult(data->d_initial, false);
return;
}
+ data->d_mplexer.removeReadFD(descriptor);
data->d_ds->submitHealthCheckResult(data->d_initial, handleResponse(data));
}
-static void healthCheckTCPCallback(int fd, FDMultiplexer::funcparam_t& param)
+static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
{
auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
@@ -211,8 +249,8 @@ static void healthCheckTCPCallback(int fd, FDMultiplexer::funcparam_t& param)
ioState = data->d_tcpHandler->tryRead(data->d_buffer, data->d_bufferPos, data->d_buffer.size());
if (ioState == IOState::Done) {
data->d_bufferPos = 0;
- uint16_t responseSize;
- memcpy(&responseSize, &data->d_buffer.at(0), sizeof(responseSize));
+ uint16_t responseSize{0};
+ memcpy(&responseSize, data->d_buffer.data(), sizeof(responseSize));
data->d_buffer.resize(ntohs(responseSize));
data->d_tcpState = HealthCheckData::TCPState::ReadingResponse;
}
@@ -248,6 +286,7 @@ static void healthCheckTCPCallback(int fd, FDMultiplexer::funcparam_t& param)
ioGuard.release();
}
catch (const std::exception& e) {
+ ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
data->d_ds->submitHealthCheckResult(data->d_initial, false);
if (g_verboseHealthChecks) {
infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what());
@@ -261,27 +300,27 @@ static void healthCheckTCPCallback(int fd, FDMultiplexer::funcparam_t& param)
}
}
-bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& ds, bool initialCheck)
+bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initialCheck)
{
try {
uint16_t queryID = dnsdist::getRandomDNSID();
- DNSName checkName = ds->d_config.checkName;
- uint16_t checkType = ds->d_config.checkType.getCode();
- uint16_t checkClass = ds->d_config.checkClass;
- dnsheader checkHeader;
+ DNSName checkName = downstream->d_config.checkName;
+ uint16_t checkType = downstream->d_config.checkType.getCode();
+ uint16_t checkClass = downstream->d_config.checkClass;
+ dnsheader checkHeader{};
memset(&checkHeader, 0, sizeof(checkHeader));
checkHeader.qdcount = htons(1);
checkHeader.id = queryID;
checkHeader.rd = true;
- if (ds->d_config.setCD) {
+ if (downstream->d_config.setCD) {
checkHeader.cd = true;
}
- if (ds->d_config.checkFunction) {
+ if (downstream->d_config.checkFunction) {
auto lock = g_lua.lock();
- auto ret = ds->d_config.checkFunction(checkName, checkType, checkClass, &checkHeader);
+ auto ret = downstream->d_config.checkFunction(checkName, checkType, checkClass, &checkHeader);
checkName = std::get<0>(ret);
checkType = std::get<1>(ret);
checkClass = std::get<2>(ret);
@@ -296,88 +335,90 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
uint16_t packetSize = packet.size();
std::string proxyProtocolPayload;
size_t proxyProtocolPayloadSize = 0;
- if (ds->d_config.useProxyProtocol) {
+ if (downstream->d_config.useProxyProtocol) {
proxyProtocolPayload = makeLocalProxyHeader();
proxyProtocolPayloadSize = proxyProtocolPayload.size();
- if (!ds->isDoH()) {
+ if (!downstream->isDoH()) {
packet.insert(packet.begin(), proxyProtocolPayload.begin(), proxyProtocolPayload.end());
}
}
- Socket sock(ds->d_config.remote.sin4.sin_family, ds->doHealthcheckOverTCP() ? SOCK_STREAM : SOCK_DGRAM);
+ Socket sock(downstream->d_config.remote.sin4.sin_family, downstream->doHealthcheckOverTCP() ? SOCK_STREAM : SOCK_DGRAM);
sock.setNonBlocking();
#ifdef SO_BINDTODEVICE
- if (!ds->d_config.sourceItfName.empty()) {
- int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, ds->d_config.sourceItfName.c_str(), ds->d_config.sourceItfName.length());
+ if (!downstream->d_config.sourceItfName.empty()) {
+ int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, downstream->d_config.sourceItfName.c_str(), downstream->d_config.sourceItfName.length());
if (res != 0 && g_verboseHealthChecks) {
- infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", ds->getNameWithAddr(), stringerror());
+ infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror());
}
}
#endif
- if (!IsAnyAddress(ds->d_config.sourceAddr)) {
- if (ds->doHealthcheckOverTCP()) {
+ if (!IsAnyAddress(downstream->d_config.sourceAddr)) {
+ if (downstream->doHealthcheckOverTCP()) {
sock.setReuseAddr();
}
#ifdef IP_BIND_ADDRESS_NO_PORT
- if (ds->d_config.ipBindAddrNoPort) {
+ if (downstream->d_config.ipBindAddrNoPort) {
SSetsockopt(sock.getHandle(), SOL_IP, IP_BIND_ADDRESS_NO_PORT, 1);
}
#endif
- sock.bind(ds->d_config.sourceAddr, false);
+ sock.bind(downstream->d_config.sourceAddr, false);
}
- auto data = std::make_shared<HealthCheckData>(*mplexer, ds, std::move(checkName), checkType, checkClass, queryID);
+ auto data = std::make_shared<HealthCheckData>(*mplexer, downstream, std::move(checkName), checkType, checkClass, queryID);
data->d_initial = initialCheck;
gettimeofday(&data->d_ttd, nullptr);
- data->d_ttd.tv_sec += ds->d_config.checkTimeout / 1000; /* ms to seconds */
- data->d_ttd.tv_usec += (ds->d_config.checkTimeout % 1000) * 1000; /* remaining ms to us */
+ data->d_ttd.tv_sec += static_cast<decltype(data->d_ttd.tv_sec)>(downstream->d_config.checkTimeout / 1000); /* ms to seconds */
+ data->d_ttd.tv_usec += static_cast<decltype(data->d_ttd.tv_usec)>((downstream->d_config.checkTimeout % 1000) * 1000); /* remaining ms to us */
normalizeTV(data->d_ttd);
- if (!ds->doHealthcheckOverTCP()) {
- sock.connect(ds->d_config.remote);
+ if (!downstream->doHealthcheckOverTCP()) {
+ sock.connect(downstream->d_config.remote);
data->d_udpSocket = std::move(sock);
- ssize_t sent = udpClientSendRequestToBackend(ds, data->d_udpSocket.getHandle(), packet, true);
+ ssize_t sent = udpClientSendRequestToBackend(downstream, data->d_udpSocket.getHandle(), packet, true);
if (sent < 0) {
int ret = errno;
if (g_verboseHealthChecks) {
- infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, ds->getNameWithAddr(), ret);
+ infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret);
}
return false;
}
mplexer->addReadFD(data->d_udpSocket.getHandle(), &healthCheckUDPCallback, data, &data->d_ttd);
}
- else if (ds->isDoH()) {
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ else if (downstream->isDoH()) {
InternalQuery query(std::move(packet), InternalQueryState());
query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
auto sender = std::shared_ptr<TCPQuerySender>(new HealthCheckQuerySender(data));
- if (!sendH2Query(ds, mplexer, sender, std::move(query), true)) {
+ if (!sendH2Query(downstream, mplexer, sender, std::move(query), true)) {
data->d_ds->submitHealthCheckResult(data->d_initial, false);
}
}
+#endif
else {
- data->d_tcpHandler = std::make_unique<TCPIOHandler>(ds->d_config.d_tlsSubjectName, ds->d_config.d_tlsSubjectIsAddr, sock.releaseHandle(), timeval{ds->d_config.checkTimeout,0}, ds->d_tlsCtx);
+ data->d_tcpHandler = std::make_unique<TCPIOHandler>(downstream->d_config.d_tlsSubjectName, downstream->d_config.d_tlsSubjectIsAddr, sock.releaseHandle(), timeval{downstream->d_config.checkTimeout, 0}, downstream->d_tlsCtx);
data->d_ioState = std::make_unique<IOStateHandler>(*mplexer, data->d_tcpHandler->getDescriptor());
- if (ds->d_tlsCtx) {
+ if (downstream->d_tlsCtx) {
try {
time_t now = time(nullptr);
- auto tlsSession = g_sessionCache.getSession(ds->getID(), now);
+ auto tlsSession = g_sessionCache.getSession(downstream->getID(), now);
if (tlsSession) {
data->d_tcpHandler->setTLSSession(tlsSession);
}
}
catch (const std::exception& e) {
- vinfolog("Unable to restore a TLS session for the DoT healthcheck for backend %s: %s", ds->getNameWithAddr(), e.what());
+ vinfolog("Unable to restore a TLS session for the DoT healthcheck for backend %s: %s", downstream->getNameWithAddr(), e.what());
}
}
- data->d_tcpHandler->tryConnect(ds->d_config.tcpFastOpen, ds->d_config.remote);
+ data->d_tcpHandler->tryConnect(downstream->d_config.tcpFastOpen, downstream->d_config.remote);
- const uint8_t sizeBytes[] = { static_cast<uint8_t>(packetSize / 256), static_cast<uint8_t>(packetSize % 256) };
- packet.insert(packet.begin() + proxyProtocolPayloadSize, sizeBytes, sizeBytes + 2);
+ const std::array<uint8_t, 2> sizeBytes = {static_cast<uint8_t>(packetSize / 256), static_cast<uint8_t>(packetSize % 256)};
+ packet.insert(packet.begin() + static_cast<ssize_t>(proxyProtocolPayloadSize), sizeBytes.begin(), sizeBytes.end());
data->d_buffer = std::move(packet);
auto ioState = data->d_tcpHandler->tryWrite(data->d_buffer, data->d_bufferPos, data->d_buffer.size());
@@ -395,13 +436,13 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
}
catch (const std::exception& e) {
if (g_verboseHealthChecks) {
- infolog("Error checking the health of backend %s: %s", ds->getNameWithAddr(), e.what());
+ infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
}
return false;
}
catch (...) {
if (g_verboseHealthChecks) {
- infolog("Unknown exception while checking the health of backend %s", ds->getNameWithAddr());
+ infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
}
return false;
}
@@ -410,7 +451,9 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
{
while (mplexer.getWatchedFDCount(false) > 0 || mplexer.getWatchedFDCount(true) > 0) {
- struct timeval now;
+ struct timeval now
+ {
+ };
int ret = mplexer.run(&now, 100);
if (ret == -1) {
if (g_verboseHealthChecks) {
@@ -423,7 +466,9 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
continue;
}
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
handleH2Timeouts(mplexer, now);
+#endif
auto timeouts = mplexer.getTimeouts(now);
for (const auto& timeout : timeouts) {
@@ -444,14 +489,19 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
+ ++data->d_ds->d_healthCheckMetrics.d_timeOuts;
data->d_ds->submitHealthCheckResult(initial, false);
}
catch (const std::exception& e) {
+ /* this is not supposed to happen as the file descriptor has to be
+ there for us to reach that code, and the submission code should not throw,
+ but let's provide a nice error message if it ever does. */
if (g_verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
}
}
catch (...) {
+ /* this is even less likely to happen */
if (g_verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
@@ -471,14 +521,18 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
+ ++data->d_ds->d_healthCheckMetrics.d_timeOuts;
data->d_ds->submitHealthCheckResult(initial, false);
}
catch (const std::exception& e) {
+ /* this is not supposed to happen as the submission code should not throw,
+ but let's provide a nice error message if it ever does. */
if (g_verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
}
}
catch (...) {
+ /* this is even less likely to happen */
if (g_verboseHealthChecks) {
infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
}
diff --git a/dnsdist-healthchecks.hh b/dnsdist-healthchecks.hh
index 825961e..e9da6c6 100644
--- a/dnsdist-healthchecks.hh
+++ b/dnsdist-healthchecks.hh
@@ -27,6 +27,5 @@
extern bool g_verboseHealthChecks;
-bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& ds, bool initial=false);
-void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial=false);
-
+bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initial = false);
+void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial = false);
diff --git a/dnsdist-idstate.hh b/dnsdist-idstate.hh
index b619842..d22d274 100644
--- a/dnsdist-idstate.hh
+++ b/dnsdist-idstate.hh
@@ -21,19 +21,27 @@
*/
#pragma once
+#include <unordered_map>
+
#include "config.h"
+#include "dnscrypt.hh"
#include "dnsname.hh"
#include "dnsdist-protocols.hh"
+#include "ednsextendederror.hh"
#include "gettime.hh"
#include "iputils.hh"
+#include "noinitvector.hh"
#include "uuid-utils.hh"
struct ClientState;
-struct DOHUnit;
+struct DOHUnitInterface;
+struct DOQUnit;
+struct DOH3Unit;
class DNSCryptQuery;
class DNSDistPacketCache;
using QTag = std::unordered_map<string, string>;
+using HeadersMap = std::unordered_map<std::string, std::string>;
struct StopWatch
{
@@ -89,6 +97,8 @@ private:
bool d_needRealTime;
};
+class CrossProtocolContext;
+
struct InternalQueryState
{
struct ProtoBufData
@@ -99,12 +109,7 @@ struct InternalQueryState
std::string d_requestorID;
};
- static void DeleterPlaceHolder(DOHUnit*)
- {
- }
-
- InternalQueryState() :
- du(std::unique_ptr<DOHUnit, void (*)(DOHUnit*)>(nullptr, DeleterPlaceHolder))
+ InternalQueryState()
{
origDest.sin4.sin_family = 0;
}
@@ -115,22 +120,39 @@ struct InternalQueryState
InternalQueryState(const InternalQueryState& orig) = delete;
InternalQueryState& operator=(const InternalQueryState& orig) = delete;
+ bool isXSK() const noexcept
+ {
+#ifdef HAVE_XSK
+ return !xskPacketHeader.empty();
+#else
+ return false;
+#endif /* HAVE_XSK */
+ }
+
boost::optional<Netmask> subnet{boost::none}; // 40
+ std::string poolName; // 32
ComboAddress origRemote; // 28
ComboAddress origDest; // 28
ComboAddress hopRemote;
ComboAddress hopLocal;
DNSName qname; // 24
- std::string poolName; // 24
+#ifdef HAVE_XSK
+ PacketBuffer xskPacketHeader; // 24
+#endif /* HAVE_XSK */
StopWatch queryRealTime{true}; // 24
std::shared_ptr<DNSDistPacketCache> packetCache{nullptr}; // 16
std::unique_ptr<DNSCryptQuery> dnsCryptQuery{nullptr}; // 8
std::unique_ptr<QTag> qTag{nullptr}; // 8
std::unique_ptr<PacketBuffer> d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8
std::unique_ptr<ProtoBufData> d_protoBufData{nullptr};
+ std::unique_ptr<EDNSExtendedError> d_extendedError{nullptr};
boost::optional<uint32_t> tempFailureTTL{boost::none}; // 8
ClientState* cs{nullptr}; // 8
- std::unique_ptr<DOHUnit, void (*)(DOHUnit*)> du; // 8
+ std::unique_ptr<DOHUnitInterface> du; // 8
+ size_t d_proxyProtocolPayloadSize{0}; // 8
+ std::unique_ptr<DOQUnit> doqu{nullptr}; // 8
+ std::unique_ptr<DOH3Unit> doh3u{nullptr}; // 8
+ int32_t d_streamID{-1}; // 4
uint32_t cacheKey{0}; // 4
uint32_t cacheKeyNoECS{0}; // 4
// DoH-only */
diff --git a/dnsdist-internal-queries.cc b/dnsdist-internal-queries.cc
index 49f95e4..b707fef 100644
--- a/dnsdist-internal-queries.cc
+++ b/dnsdist-internal-queries.cc
@@ -20,8 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dnsdist-internal-queries.hh"
+#include "dnsdist-nghttp2-in.hh"
#include "dnsdist-tcp.hh"
#include "doh.hh"
+#include "doq.hh"
std::unique_ptr<CrossProtocolQuery> getUDPCrossProtocolQueryFromDQ(DNSQuestion& dq);
@@ -35,7 +37,22 @@ std::unique_ptr<CrossProtocolQuery> getInternalQueryFromDQ(DNSQuestion& dq, bool
}
#ifdef HAVE_DNS_OVER_HTTPS
else if (protocol == dnsdist::Protocol::DoH) {
- return getDoHCrossProtocolQueryFromDQ(dq, isResponse);
+#ifdef HAVE_LIBH2OEVLOOP
+ if (dq.ids.cs->dohFrontend->d_library == "h2o") {
+ return getDoHCrossProtocolQueryFromDQ(dq, isResponse);
+ }
+#endif /* HAVE_LIBH2OEVLOOP */
+ return getTCPCrossProtocolQueryFromDQ(dq);
+ }
+#endif
+#ifdef HAVE_DNS_OVER_QUIC
+ else if (protocol == dnsdist::Protocol::DoQ) {
+ return getDOQCrossProtocolQueryFromDQ(dq, isResponse);
+ }
+#endif
+#ifdef HAVE_DNS_OVER_HTTP3
+ else if (protocol == dnsdist::Protocol::DoH3) {
+ return getDOH3CrossProtocolQueryFromDQ(dq, isResponse);
}
#endif
else {
diff --git a/dnsdist-kvs.cc b/dnsdist-kvs.cc
index c2b6272..d20aa1e 100644
--- a/dnsdist-kvs.cc
+++ b/dnsdist-kvs.cc
@@ -96,8 +96,8 @@ bool LMDBKVStore::getValue(const std::string& key, std::string& value)
return false;
}
}
- catch(const std::exception& e) {
- warnlog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
+ catch (const std::exception& e) {
+ vinfolog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
}
return false;
}
@@ -115,8 +115,8 @@ bool LMDBKVStore::keyExists(const std::string& key)
return false;
}
}
- catch(const std::exception& e) {
- warnlog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
+ catch (const std::exception& e) {
+ vinfolog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName, e.what());
}
return false;
}
@@ -163,7 +163,7 @@ bool LMDBKVStore::getRangeValue(const std::string& key, std::string& value)
return false;
}
}
- catch(const std::exception& e) {
+ catch (const std::exception& e) {
vinfolog("Error while looking up a range from LMDB file '%s', database '%s': %s", d_fname, d_dbName, e.what());
}
return false;
@@ -230,7 +230,7 @@ void CDBKVStore::refreshDBIfNeeded(time_t now)
d_nextCheck = now + d_refreshDelay;
d_refreshing.clear();
}
- catch(...) {
+ catch (...) {
d_refreshing.clear();
throw;
}
@@ -252,8 +252,8 @@ bool CDBKVStore::getValue(const std::string& key, std::string& value)
}
}
}
- catch(const std::exception& e) {
- warnlog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
+ catch (const std::exception& e) {
+ vinfolog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
}
return false;
}
@@ -276,8 +276,8 @@ bool CDBKVStore::keyExists(const std::string& key)
return (*cdb)->keyExists(key);
}
}
- catch(const std::exception& e) {
- warnlog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
+ catch (const std::exception& e) {
+ vinfolog("Error while looking up key '%s' from CDB file '%s': %s", key, d_fname, e.what());
}
return false;
}
diff --git a/dnsdist-lbpolicies.cc b/dnsdist-lbpolicies.cc
index 70fec89..b4e3532 100644
--- a/dnsdist-lbpolicies.cc
+++ b/dnsdist-lbpolicies.cc
@@ -25,6 +25,7 @@
#include "dnsdist-lua.hh"
#include "dnsdist-lua-ffi.hh"
#include "dolog.hh"
+#include "dns_random.hh"
GlobalStateHolder<ServerPolicy> g_policy;
bool g_roundrobinFailOnNoServer{false};
@@ -40,7 +41,7 @@ template <class T> static std::shared_ptr<DownstreamState> getLeastOutstanding(c
size_t usableServers = 0;
for (const auto& d : servers) {
if (d.second->isUp()) {
- poss[usableServers] = std::make_pair(std::make_tuple(d.second->outstanding.load(), d.second->d_config.order, d.second->getRelevantLatencyUsec()), d.first);
+ poss.at(usableServers) = std::pair(std::tuple(d.second->outstanding.load(), d.second->d_config.order, d.second->getRelevantLatencyUsec()), d.first);
usableServers++;
}
}
@@ -100,7 +101,7 @@ template <class T> static std::shared_ptr<DownstreamState> getValRandom(const Se
sum += d.second->d_config.d_weight;
}
- poss[usableServers] = std::make_pair(sum, d.first);
+ poss.at(usableServers) = std::pair(sum, d.first);
usableServers++;
}
}
@@ -153,7 +154,7 @@ static shared_ptr<DownstreamState> valrandom(const unsigned int val, const Serve
shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
- return valrandom(random(), servers);
+ return valrandom(dns_random_uint32(), servers);
}
uint32_t g_hashperturb;
@@ -289,7 +290,7 @@ void setPoolPolicy(pools_t& pools, const string& poolName, std::shared_ptr<Serve
} else {
vinfolog("Setting default pool server selection policy to %s", policy->getName());
}
- pool->policy = policy;
+ pool->policy = std::move(policy);
}
void addServerToPool(pools_t& pools, const string& poolName, std::shared_ptr<DownstreamState> server)
@@ -378,6 +379,11 @@ std::shared_ptr<DownstreamState> ServerPolicy::getSelectedBackend(const ServerPo
selected = policy(&serversList, &dnsq);
}
+ if (selected >= servers.size()) {
+ /* invalid offset, meaning that there is no server available */
+ return {};
+ }
+
selectedBackend = servers.at(selected).second;
}
}
diff --git a/dnsdist-lbpolicies.hh b/dnsdist-lbpolicies.hh
index a1332c7..7244340 100644
--- a/dnsdist-lbpolicies.hh
+++ b/dnsdist-lbpolicies.hh
@@ -37,11 +37,11 @@ public:
typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
typedef std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)> ffipolicyfunc_t;
- ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_): d_name(name_), d_policy(policy_), d_isLua(isLua_)
+ ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_): d_name(name_), d_policy(std::move(policy_)), d_isLua(isLua_)
{
}
- ServerPolicy(const std::string& name_, ffipolicyfunc_t policy_): d_name(name_), d_ffipolicy(policy_), d_isLua(true), d_isFFI(true)
+ ServerPolicy(const std::string& name_, ffipolicyfunc_t policy_): d_name(name_), d_ffipolicy(std::move(policy_)), d_isLua(true), d_isFFI(true)
{
}
diff --git a/dnsdist-lua-actions.cc b/dnsdist-lua-actions.cc
index 5d3271a..e643007 100644
--- a/dnsdist-lua-actions.cc
+++ b/dnsdist-lua-actions.cc
@@ -23,11 +23,14 @@
#include "threadname.hh"
#include "dnsdist.hh"
#include "dnsdist-async.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-edns.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-lua-ffi.hh"
#include "dnsdist-mac-address.hh"
#include "dnsdist-protobuf.hh"
+#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-kvs.hh"
#include "dnsdist-svc.hh"
@@ -45,11 +48,11 @@
class DropAction : public DNSAction
{
public:
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
return Action::Drop;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "drop";
}
@@ -58,11 +61,11 @@ public:
class AllowAction : public DNSAction
{
public:
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
return Action::Allow;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "allow";
}
@@ -72,11 +75,11 @@ class NoneAction : public DNSAction
{
public:
// this action does not stop the processing
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "no op";
}
@@ -85,22 +88,22 @@ public:
class QPSAction : public DNSAction
{
public:
- QPSAction(int limit) : d_qps(QPSLimiter(limit, limit))
+ QPSAction(int limit) :
+ d_qps(QPSLimiter(limit, limit))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
if (d_qps.lock()->check()) {
return Action::None;
}
- else {
- return Action::Drop;
- }
+ return Action::Drop;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
- return "qps limit to "+std::to_string(d_qps.lock()->getRate());
+ return "qps limit to " + std::to_string(d_qps.lock()->getRate());
}
+
private:
mutable LockGuarded<QPSLimiter> d_qps;
};
@@ -108,18 +111,20 @@ private:
class DelayAction : public DNSAction
{
public:
- DelayAction(int msec) : d_msec(msec)
+ DelayAction(int msec) :
+ d_msec(msec)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
*ruleresult = std::to_string(d_msec);
return Action::Delay;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
- return "delay by "+std::to_string(d_msec)+ " msec";
+ return "delay by " + std::to_string(d_msec) + " ms";
}
+
private:
int d_msec;
};
@@ -128,18 +133,22 @@ class TeeAction : public DNSAction
{
public:
// this action does not stop the processing
- TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS=false);
+ TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS = false, bool addProxyProtocol = false);
+ TeeAction(TeeAction& other) = delete;
+ TeeAction(TeeAction&& other) = delete;
+ TeeAction& operator=(TeeAction& other) = delete;
+ TeeAction& operator=(TeeAction&& other) = delete;
~TeeAction() override;
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override;
- std::string toString() const override;
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override;
+ [[nodiscard]] std::string toString() const override;
std::map<std::string, double> getStats() const override;
private:
- ComboAddress d_remote;
- std::thread d_worker;
void worker();
- int d_fd{-1};
+ ComboAddress d_remote;
+ std::thread d_worker;
+ Socket d_socket;
mutable std::atomic<unsigned long> d_senderrors{0};
unsigned long d_recverrors{0};
mutable std::atomic<unsigned long> d_queries{0};
@@ -154,61 +163,65 @@ private:
stat_t d_otherrcode{0};
std::atomic<bool> d_pleaseQuit{false};
bool d_addECS{false};
+ bool d_addProxyProtocol{false};
};
-TeeAction::TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS)
- : d_remote(rca), d_addECS(addECS)
+TeeAction::TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS, bool addProxyProtocol) :
+ d_remote(rca), d_socket(d_remote.sin4.sin_family, SOCK_DGRAM, 0), d_addECS(addECS), d_addProxyProtocol(addProxyProtocol)
{
- d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0);
- try {
- if (lca) {
- SBind(d_fd, *lca);
- }
- SConnect(d_fd, d_remote);
- setNonBlocking(d_fd);
- d_worker=std::thread([this](){worker();});
- }
- catch (...) {
- if (d_fd != -1) {
- close(d_fd);
- }
- throw;
+ if (lca) {
+ d_socket.bind(*lca, false);
}
+ d_socket.connect(d_remote);
+ d_socket.setNonBlocking();
+ d_worker = std::thread([this]() {
+ worker();
+ });
}
TeeAction::~TeeAction()
{
- d_pleaseQuit=true;
- close(d_fd);
+ d_pleaseQuit = true;
+ close(d_socket.releaseHandle());
d_worker.join();
}
-DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
+DNSAction::Action TeeAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const
{
- if (dq->overTCP()) {
+ if (dnsquestion->overTCP()) {
d_tcpdrops++;
+ return DNSAction::Action::None;
}
- else {
- ssize_t res;
- d_queries++;
- if(d_addECS) {
- PacketBuffer query(dq->getData());
- bool ednsAdded = false;
- bool ecsAdded = false;
+ d_queries++;
- std::string newECSOption;
- generateECSOption(dq->ecs ? dq->ecs->getNetwork() : dq->ids.origRemote, newECSOption, dq->ecs ? dq->ecs->getBits() : dq->ecsPrefixLength);
+ PacketBuffer query;
+ if (d_addECS) {
+ query = dnsquestion->getData();
+ bool ednsAdded = false;
+ bool ecsAdded = false;
- if (!handleEDNSClientSubnet(query, dq->getMaximumSize(), dq->ids.qname.wirelength(), ednsAdded, ecsAdded, dq->ecsOverride, newECSOption)) {
- return DNSAction::Action::None;
- }
+ std::string newECSOption;
+ generateECSOption(dnsquestion->ecs ? dnsquestion->ecs->getNetwork() : dnsquestion->ids.origRemote, newECSOption, dnsquestion->ecs ? dnsquestion->ecs->getBits() : dnsquestion->ecsPrefixLength);
- res = send(d_fd, query.data(), query.size(), 0);
+ if (!handleEDNSClientSubnet(query, dnsquestion->getMaximumSize(), dnsquestion->ids.qname.wirelength(), ednsAdded, ecsAdded, dnsquestion->ecsOverride, newECSOption)) {
+ return DNSAction::Action::None;
}
- else {
- res = send(d_fd, dq->getData().data(), dq->getData().size(), 0);
+ }
+
+ if (d_addProxyProtocol) {
+ auto proxyPayload = getProxyProtocolPayload(*dnsquestion);
+ if (query.empty()) {
+ query = dnsquestion->getData();
+ }
+ if (!addProxyProtocol(query, proxyPayload)) {
+ return DNSAction::Action::None;
}
+ }
+
+ {
+ const PacketBuffer& payload = query.empty() ? dnsquestion->getData() : query;
+ auto res = send(d_socket.getHandle(), payload.data(), payload.size(), 0);
if (res <= 0) {
d_senderrors++;
@@ -220,10 +233,10 @@ DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult
std::string TeeAction::toString() const
{
- return "tee to "+d_remote.toStringWithPort();
+ return "tee to " + d_remote.toStringWithPort();
}
-std::map<std::string,double> TeeAction::getStats() const
+std::map<std::string, double> TeeAction::getStats() const
{
return {{"queries", d_queries},
{"responses", d_responses},
@@ -234,81 +247,98 @@ std::map<std::string,double> TeeAction::getStats() const
{"refuseds", d_refuseds},
{"servfails", d_servfails},
{"other-rcode", d_otherrcode},
- {"tcp-drops", d_tcpdrops}
- };
+ {"tcp-drops", d_tcpdrops}};
}
void TeeAction::worker()
{
setThreadName("dnsdist/TeeWork");
- char packet[1500];
- int res=0;
- struct dnsheader* dh=(struct dnsheader*)packet;
- for(;;) {
- res=waitForData(d_fd, 0, 250000);
- if(d_pleaseQuit)
+ std::array<char, s_udpIncomingBufferSize> packet{};
+ ssize_t res = 0;
+ const dnsheader_aligned dnsheader(packet.data());
+ for (;;) {
+ res = waitForData(d_socket.getHandle(), 0, 250000);
+ if (d_pleaseQuit) {
break;
- if(res < 0) {
+ }
+
+ if (res < 0) {
usleep(250000);
continue;
}
- if(res==0)
+ if (res == 0) {
continue;
- res=recv(d_fd, packet, sizeof(packet), 0);
- if(res <= (int)sizeof(struct dnsheader))
+ }
+ res = recv(d_socket.getHandle(), packet.data(), packet.size(), 0);
+ if (static_cast<size_t>(res) <= sizeof(struct dnsheader)) {
d_recverrors++;
- else
+ }
+ else {
d_responses++;
+ }
- if(dh->rcode == RCode::NoError)
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ if (dnsheader->rcode == RCode::NoError) {
d_noerrors++;
- else if(dh->rcode == RCode::ServFail)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dnsheader->rcode == RCode::ServFail) {
d_servfails++;
- else if(dh->rcode == RCode::NXDomain)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dnsheader->rcode == RCode::NXDomain) {
d_nxdomains++;
- else if(dh->rcode == RCode::Refused)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dnsheader->rcode == RCode::Refused) {
d_refuseds++;
- else if(dh->rcode == RCode::FormErr)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dnsheader->rcode == RCode::FormErr) {
d_formerrs++;
- else if(dh->rcode == RCode::NotImp)
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well
+ else if (dnsheader->rcode == RCode::NotImp) {
d_notimps++;
+ }
}
}
class PoolAction : public DNSAction
{
public:
- PoolAction(const std::string& pool, bool stopProcessing) : d_pool(pool), d_stopProcessing(stopProcessing) {}
+ PoolAction(std::string pool, bool stopProcessing) :
+ d_pool(std::move(pool)), d_stopProcessing(stopProcessing) {}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
if (d_stopProcessing) {
/* we need to do it that way to keep compatiblity with custom Lua actions returning DNSAction.Pool, 'poolname' */
*ruleresult = d_pool;
return Action::Pool;
}
- else {
- dq->ids.poolName = d_pool;
- return Action::None;
- }
+ dnsquestion->ids.poolName = d_pool;
+ return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "to pool " + d_pool;
}
private:
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::string d_pool;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const bool d_stopProcessing;
};
-
class QPSPoolAction : public DNSAction
{
public:
- QPSPoolAction(unsigned int limit, const std::string& pool, bool stopProcessing) : d_qps(QPSLimiter(limit, limit)), d_pool(pool), d_stopProcessing(stopProcessing) {}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ QPSPoolAction(unsigned int limit, std::string pool, bool stopProcessing) :
+ d_qps(QPSLimiter(limit, limit)), d_pool(std::move(pool)), d_stopProcessing(stopProcessing) {}
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
if (d_qps.lock()->check()) {
if (d_stopProcessing) {
@@ -316,66 +346,79 @@ public:
*ruleresult = d_pool;
return Action::Pool;
}
- else {
- dq->ids.poolName = d_pool;
- return Action::None;
- }
- }
- else {
- return Action::None;
+ dnsquestion->ids.poolName = d_pool;
}
+ return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "max " + std::to_string(d_qps.lock()->getRate()) + " to pool " + d_pool;
}
private:
mutable LockGuarded<QPSLimiter> d_qps;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::string d_pool;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const bool d_stopProcessing;
};
class RCodeAction : public DNSAction
{
public:
- RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ RCodeAction(uint8_t rcode) :
+ d_rcode(rcode) {}
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->getHeader()->rcode = d_rcode;
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
+ header.rcode = d_rcode;
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::HeaderModify;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set rcode " + std::to_string(d_rcode);
+ }
+ [[nodiscard]] ResponseConfig& getResponseConfig()
{
- return "set rcode "+std::to_string(d_rcode);
+ return d_responseConfig;
}
- ResponseConfig d_responseConfig;
private:
+ ResponseConfig d_responseConfig;
uint8_t d_rcode;
};
class ERCodeAction : public DNSAction
{
public:
- ERCodeAction(uint8_t rcode) : d_rcode(rcode) {}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ ERCodeAction(uint8_t rcode) :
+ d_rcode(rcode) {}
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->getHeader()->rcode = (d_rcode & 0xF);
- dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
+ header.rcode = (d_rcode & 0xF);
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
+ dnsquestion->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
return Action::HeaderModify;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set ercode " + ERCode::to_s(d_rcode);
+ }
+ [[nodiscard]] ResponseConfig& getResponseConfig()
{
- return "set ercode "+ERCode::to_s(d_rcode);
+ return d_responseConfig;
}
- ResponseConfig d_responseConfig;
private:
+ ResponseConfig d_responseConfig;
uint8_t d_rcode;
};
@@ -396,88 +439,106 @@ public:
d_payloads.push_back(std::move(payload));
for (const auto& hint : param.second.ipv4hints) {
- d_additionals4.insert({ param.second.target, ComboAddress(hint) });
+ d_additionals4.insert({param.second.target, ComboAddress(hint)});
}
for (const auto& hint : param.second.ipv6hints) {
- d_additionals6.insert({ param.second.target, ComboAddress(hint) });
+ d_additionals6.insert({param.second.target, ComboAddress(hint)});
}
}
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
/* it will likely be a bit bigger than that because of additionals */
- uint16_t numberOfRecords = d_payloads.size();
- const auto qnameWireLength = dq->ids.qname.wirelength();
- if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + d_totalPayloadsSize)) {
+ auto numberOfRecords = d_payloads.size();
+ const auto qnameWireLength = dnsquestion->ids.qname.wirelength();
+ if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize)) {
return Action::None;
}
PacketBuffer newPacket;
- newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + d_totalPayloadsSize);
- GenericDNSPacketWriter<PacketBuffer> pw(newPacket, dq->ids.qname, dq->ids.qtype);
+ newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize);
+ GenericDNSPacketWriter<PacketBuffer> packetWriter(newPacket, dnsquestion->ids.qname, dnsquestion->ids.qtype);
for (const auto& payload : d_payloads) {
- pw.startRecord(dq->ids.qname, dq->ids.qtype, d_responseConfig.ttl);
- pw.xfrBlob(payload);
- pw.commit();
+ packetWriter.startRecord(dnsquestion->ids.qname, dnsquestion->ids.qtype, d_responseConfig.ttl);
+ packetWriter.xfrBlob(payload);
+ packetWriter.commit();
}
- if (newPacket.size() < dq->getMaximumSize()) {
+ if (newPacket.size() < dnsquestion->getMaximumSize()) {
for (const auto& additional : d_additionals4) {
- pw.startRecord(additional.first.isRoot() ? dq->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
- pw.xfrCAWithoutPort(4, additional.second);
- pw.commit();
+ packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ packetWriter.xfrCAWithoutPort(4, additional.second);
+ packetWriter.commit();
}
}
- if (newPacket.size() < dq->getMaximumSize()) {
+ if (newPacket.size() < dnsquestion->getMaximumSize()) {
for (const auto& additional : d_additionals6) {
- pw.startRecord(additional.first.isRoot() ? dq->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
- pw.xfrCAWithoutPort(6, additional.second);
- pw.commit();
+ packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL);
+ packetWriter.xfrCAWithoutPort(6, additional.second);
+ packetWriter.commit();
}
}
- if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
- bool dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
- pw.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
- pw.commit();
+ if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
+ bool dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
+ packetWriter.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
+ packetWriter.commit();
}
- if (newPacket.size() >= dq->getMaximumSize()) {
+ if (newPacket.size() >= dnsquestion->getMaximumSize()) {
/* sorry! */
return Action::None;
}
- pw.getHeader()->id = dq->getHeader()->id;
- pw.getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*pw.getHeader(), d_responseConfig);
- dq->getMutableData() = std::move(newPacket);
+ packetWriter.getHeader()->id = dnsquestion->getHeader()->id;
+ packetWriter.getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*packetWriter.getHeader(), d_responseConfig);
+ dnsquestion->getMutableData() = std::move(newPacket);
return Action::HeaderModify;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "spoof SVC record ";
}
- ResponseConfig d_responseConfig;
+ [[nodiscard]] ResponseConfig& getResponseConfig()
+ {
+ return d_responseConfig;
+ }
+
private:
- std::vector<std::vector<uint8_t>> d_payloads;
- std::set<std::pair<DNSName, ComboAddress>> d_additionals4;
- std::set<std::pair<DNSName, ComboAddress>> d_additionals6;
+ ResponseConfig d_responseConfig;
+ std::vector<std::vector<uint8_t>> d_payloads{};
+ std::set<std::pair<DNSName, ComboAddress>> d_additionals4{};
+ std::set<std::pair<DNSName, ComboAddress>> d_additionals6{};
size_t d_totalPayloadsSize{0};
};
class TCAction : public DNSAction
{
public:
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
+ {
+ return Action::Truncate;
+ }
+ [[nodiscard]] std::string toString() const override
+ {
+ return "tc=1 answer";
+ }
+};
+
+class TCResponseAction : public DNSResponseAction
+{
+public:
+ DNSResponseAction::Action operator()(DNSResponse* dnsResponse, std::string* ruleresult) const override
{
return Action::Truncate;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "tc=1 answer";
}
@@ -486,18 +547,19 @@ public:
class LuaAction : public DNSAction
{
public:
- typedef std::function<std::tuple<int, boost::optional<string> >(DNSQuestion* dq)> func_t;
- LuaAction(const LuaAction::func_t& func) : d_func(func)
+ using func_t = std::function<std::tuple<int, boost::optional<string>>(DNSQuestion* dnsquestion)>;
+ LuaAction(LuaAction::func_t func) :
+ d_func(std::move(func))
{}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
try {
- DNSAction::Action result;
+ DNSAction::Action result{};
{
auto lock = g_lua.lock();
- auto ret = d_func(dq);
- if (ruleresult) {
+ auto ret = d_func(dnsquestion);
+ if (ruleresult != nullptr) {
if (boost::optional<std::string> rule = std::get<1>(ret)) {
*ruleresult = *rule;
}
@@ -510,18 +572,21 @@ public:
}
dnsdist::handleQueuedAsynchronousEvents();
return result;
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception& e) {
warnlog("LuaAction failed inside Lua, returning ServFail: %s", e.what());
- } catch (...) {
+ }
+ catch (...) {
warnlog("LuaAction failed inside Lua, returning ServFail: [unknown exception]");
}
return DNSAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua script";
}
+
private:
func_t d_func;
};
@@ -529,17 +594,18 @@ private:
class LuaResponseAction : public DNSResponseAction
{
public:
- typedef std::function<std::tuple<int, boost::optional<string> >(DNSResponse* dr)> func_t;
- LuaResponseAction(const LuaResponseAction::func_t& func) : d_func(func)
+ using func_t = std::function<std::tuple<int, boost::optional<string>>(DNSResponse* response)>;
+ LuaResponseAction(LuaResponseAction::func_t func) :
+ d_func(std::move(func))
{}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
try {
- DNSResponseAction::Action result;
+ DNSResponseAction::Action result{};
{
auto lock = g_lua.lock();
- auto ret = d_func(dr);
- if (ruleresult) {
+ auto ret = d_func(response);
+ if (ruleresult != nullptr) {
if (boost::optional<std::string> rule = std::get<1>(ret)) {
*ruleresult = *rule;
}
@@ -552,40 +618,44 @@ public:
}
dnsdist::handleQueuedAsynchronousEvents();
return result;
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception& e) {
warnlog("LuaResponseAction failed inside Lua, returning ServFail: %s", e.what());
- } catch (...) {
+ }
+ catch (...) {
warnlog("LuaResponseAction failed inside Lua, returning ServFail: [unknown exception]");
}
return DNSResponseAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua response script";
}
+
private:
func_t d_func;
};
-class LuaFFIAction: public DNSAction
+class LuaFFIAction : public DNSAction
{
public:
- typedef std::function<int(dnsdist_ffi_dnsquestion_t* dq)> func_t;
+ using func_t = std::function<int(dnsdist_ffi_dnsquestion_t* dnsquestion)>;
- LuaFFIAction(const LuaFFIAction::func_t& func): d_func(func)
+ LuaFFIAction(LuaFFIAction::func_t func) :
+ d_func(std::move(func))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dnsdist_ffi_dnsquestion_t dqffi(dq);
+ dnsdist_ffi_dnsquestion_t dqffi(dnsquestion);
try {
- DNSAction::Action result;
+ DNSAction::Action result{};
{
auto lock = g_lua.lock();
auto ret = d_func(&dqffi);
- if (ruleresult) {
+ if (ruleresult != nullptr) {
if (dqffi.result) {
*ruleresult = *dqffi.result;
}
@@ -598,32 +668,36 @@ public:
}
dnsdist::handleQueuedAsynchronousEvents();
return result;
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception& e) {
warnlog("LuaFFIAction failed inside Lua, returning ServFail: %s", e.what());
- } catch (...) {
+ }
+ catch (...) {
warnlog("LuaFFIAction failed inside Lua, returning ServFail: [unknown exception]");
}
return DNSAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua FFI script";
}
+
private:
func_t d_func;
};
-class LuaFFIPerThreadAction: public DNSAction
+class LuaFFIPerThreadAction : public DNSAction
{
public:
- typedef std::function<int(dnsdist_ffi_dnsquestion_t* dq)> func_t;
+ using func_t = std::function<int(dnsdist_ffi_dnsquestion_t* dnsquestion)>;
- LuaFFIPerThreadAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++)
+ LuaFFIPerThreadAction(std::string code) :
+ d_functionCode(std::move(code)), d_functionID(s_functionsCounter++)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
try {
auto& state = t_perThreadStates[d_functionID];
@@ -640,9 +714,9 @@ public:
return DNSAction::Action::None;
}
- dnsdist_ffi_dnsquestion_t dqffi(dq);
+ dnsdist_ffi_dnsquestion_t dqffi(dnsquestion);
auto ret = state.d_func(&dqffi);
- if (ruleresult) {
+ if (ruleresult != nullptr) {
if (dqffi.result) {
*ruleresult = *dqffi.result;
}
@@ -654,7 +728,7 @@ public:
dnsdist::handleQueuedAsynchronousEvents();
return static_cast<DNSAction::Action>(ret);
}
- catch (const std::exception &e) {
+ catch (const std::exception& e) {
warnlog("LuaFFIPerThreadAction failed inside Lua, returning ServFail: %s", e.what());
}
catch (...) {
@@ -663,7 +737,7 @@ public:
return DNSAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua FFI per-thread script";
}
@@ -677,33 +751,36 @@ private:
};
static std::atomic<uint64_t> s_functionsCounter;
static thread_local std::map<uint64_t, PerThreadState> t_perThreadStates;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::string d_functionCode;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const uint64_t d_functionID;
};
std::atomic<uint64_t> LuaFFIPerThreadAction::s_functionsCounter = 0;
thread_local std::map<uint64_t, LuaFFIPerThreadAction::PerThreadState> LuaFFIPerThreadAction::t_perThreadStates;
-class LuaFFIResponseAction: public DNSResponseAction
+class LuaFFIResponseAction : public DNSResponseAction
{
public:
- typedef std::function<int(dnsdist_ffi_dnsresponse_t* dq)> func_t;
+ using func_t = std::function<int(dnsdist_ffi_dnsresponse_t* dnsquestion)>;
- LuaFFIResponseAction(const LuaFFIResponseAction::func_t& func): d_func(func)
+ LuaFFIResponseAction(LuaFFIResponseAction::func_t func) :
+ d_func(std::move(func))
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- dnsdist_ffi_dnsresponse_t drffi(dr);
+ dnsdist_ffi_dnsresponse_t ffiResponse(response);
try {
- DNSResponseAction::Action result;
+ DNSResponseAction::Action result{};
{
auto lock = g_lua.lock();
- auto ret = d_func(&drffi);
- if (ruleresult) {
- if (drffi.result) {
- *ruleresult = *drffi.result;
+ auto ret = d_func(&ffiResponse);
+ if (ruleresult != nullptr) {
+ if (ffiResponse.result) {
+ *ruleresult = *ffiResponse.result;
}
else {
// default to empty string
@@ -714,32 +791,36 @@ public:
}
dnsdist::handleQueuedAsynchronousEvents();
return result;
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception& e) {
warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: %s", e.what());
- } catch (...) {
+ }
+ catch (...) {
warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: [unknown exception]");
}
return DNSResponseAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua FFI script";
}
+
private:
func_t d_func;
};
-class LuaFFIPerThreadResponseAction: public DNSResponseAction
+class LuaFFIPerThreadResponseAction : public DNSResponseAction
{
public:
- typedef std::function<int(dnsdist_ffi_dnsresponse_t* dr)> func_t;
+ using func_t = std::function<int(dnsdist_ffi_dnsresponse_t* response)>;
- LuaFFIPerThreadResponseAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++)
+ LuaFFIPerThreadResponseAction(std::string code) :
+ d_functionCode(std::move(code)), d_functionID(s_functionsCounter++)
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
try {
auto& state = t_perThreadStates[d_functionID];
@@ -756,11 +837,11 @@ public:
return DNSResponseAction::Action::None;
}
- dnsdist_ffi_dnsresponse_t drffi(dr);
- auto ret = state.d_func(&drffi);
- if (ruleresult) {
- if (drffi.result) {
- *ruleresult = *drffi.result;
+ dnsdist_ffi_dnsresponse_t ffiResponse(response);
+ auto ret = state.d_func(&ffiResponse);
+ if (ruleresult != nullptr) {
+ if (ffiResponse.result) {
+ *ruleresult = *ffiResponse.result;
}
else {
// default to empty string
@@ -770,7 +851,7 @@ public:
dnsdist::handleQueuedAsynchronousEvents();
return static_cast<DNSResponseAction::Action>(ret);
}
- catch (const std::exception &e) {
+ catch (const std::exception& e) {
warnlog("LuaFFIPerThreadResponseAction failed inside Lua, returning ServFail: %s", e.what());
}
catch (...) {
@@ -779,7 +860,7 @@ public:
return DNSResponseAction::Action::ServFail;
}
- string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "Lua FFI per-thread script";
}
@@ -794,7 +875,9 @@ private:
static std::atomic<uint64_t> s_functionsCounter;
static thread_local std::map<uint64_t, PerThreadState> t_perThreadStates;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::string d_functionCode;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const uint64_t d_functionID;
};
@@ -803,35 +886,37 @@ thread_local std::map<uint64_t, LuaFFIPerThreadResponseAction::PerThreadState> L
thread_local std::default_random_engine SpoofAction::t_randomEngine;
-DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
+DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const
{
- uint16_t qtype = dq->ids.qtype;
+ uint16_t qtype = dnsquestion->ids.qtype;
// do we even have a response?
- if (d_cname.empty() &&
- d_rawResponses.empty() &&
+ if (d_cname.empty() && d_rawResponses.empty() &&
// make sure pre-forged response is greater than sizeof(dnsheader)
- (d_raw.size() < sizeof(dnsheader)) &&
- d_types.count(qtype) == 0) {
+ (d_raw.size() < sizeof(dnsheader)) && d_types.count(qtype) == 0) {
return Action::None;
}
if (d_raw.size() >= sizeof(dnsheader)) {
- auto id = dq->getHeader()->id;
- dq->getMutableData() = d_raw;
- dq->getHeader()->id = id;
+ auto questionId = dnsquestion->getHeader()->id;
+ dnsquestion->getMutableData() = d_raw;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [questionId](dnsheader& header) {
+ header.id = questionId;
+ return true;
+ });
return Action::HeaderModify;
}
- vector<ComboAddress> addrs;
- vector<std::string> rawResponses;
+ std::vector<ComboAddress> addrs = {};
+ std::vector<std::string> rawResponses = {};
unsigned int totrdatalen = 0;
- uint16_t numberOfRecords = 0;
+ size_t numberOfRecords = 0;
if (!d_cname.empty()) {
qtype = QType::CNAME;
totrdatalen += d_cname.getStorage().size();
numberOfRecords = 1;
- } else if (!d_rawResponses.empty()) {
+ }
+ else if (!d_rawResponses.empty()) {
rawResponses.reserve(d_rawResponses.size());
- for(const auto& rawResponse : d_rawResponses){
+ for (const auto& rawResponse : d_rawResponses) {
totrdatalen += rawResponse.size();
rawResponses.push_back(rawResponse);
++numberOfRecords;
@@ -841,9 +926,8 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu
}
}
else {
- for(const auto& addr : d_addrs) {
- if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
- (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
+ for (const auto& addr : d_addrs) {
+ if (qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) || (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
continue;
}
totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
@@ -856,37 +940,43 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu
shuffle(addrs.begin(), addrs.end(), t_randomEngine);
}
- unsigned int qnameWireLength=0;
- DNSName ignore(reinterpret_cast<const char*>(dq->getData().data()), dq->getData().size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
+ unsigned int qnameWireLength = 0;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ DNSName ignore(reinterpret_cast<const char*>(dnsquestion->getData().data()), dnsquestion->getData().size(), sizeof(dnsheader), false, nullptr, nullptr, &qnameWireLength);
- if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) {
+ if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) {
return Action::None;
}
bool dnssecOK = false;
bool hadEDNS = false;
- if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
+ if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
hadEDNS = true;
- dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
+ dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
}
- auto& data = dq->getMutableData();
- data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen); // there goes your EDNS
+ auto& data = dnsquestion->getMutableData();
+ data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen); // there goes your EDNS
uint8_t* dest = &(data.at(sizeof(dnsheader) + qnameWireLength + 4));
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
- dq->getHeader()->ancount = 0;
- dq->getHeader()->arcount = 0; // for now, forget about your EDNS, we're marching over it
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ header.ancount = 0;
+ header.arcount = 0; // for now, forget about your EDNS, we're marching over it
+ return true;
+ });
uint32_t ttl = htonl(d_responseConfig.ttl);
- uint16_t qclass = htons(dq->ids.qclass);
- unsigned char recordstart[] = {0xc0, 0x0c, // compressed name
- 0, 0, // QTYPE
- 0, 0, // QCLASS
- 0, 0, 0, 0, // TTL
- 0, 0 }; // rdata length
- static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
+ uint16_t qclass = htons(dnsquestion->ids.qclass);
+ std::array<unsigned char, 12> recordstart = {
+ 0xc0, 0x0c, // compressed name
+ 0, 0, // QTYPE
+ 0, 0, // QCLASS
+ 0, 0, 0, 0, // TTL
+ 0, 0 // rdata length
+ };
+ static_assert(recordstart.size() == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
memcpy(&recordstart[4], &qclass, sizeof(qclass));
memcpy(&recordstart[6], &ttl, sizeof(ttl));
bool raw = false;
@@ -898,50 +988,72 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu
memcpy(&recordstart[2], &qtype, sizeof(qtype));
memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
- memcpy(dest, recordstart, sizeof(recordstart));
- dest += sizeof(recordstart);
+ memcpy(dest, recordstart.data(), recordstart.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ dest += recordstart.size();
memcpy(dest, wireData.c_str(), wireData.length());
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
else if (!rawResponses.empty()) {
+ if (qtype == QType::ANY && d_rawTypeForAny) {
+ qtype = *d_rawTypeForAny;
+ }
qtype = htons(qtype);
- for(const auto& rawResponse : rawResponses){
+ for (const auto& rawResponse : rawResponses) {
uint16_t rdataLen = htons(rawResponse.size());
memcpy(&recordstart[2], &qtype, sizeof(qtype));
memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
- memcpy(dest, recordstart, sizeof(recordstart));
- dest += sizeof(recordstart);
+ memcpy(dest, recordstart.data(), sizeof(recordstart));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ dest += recordstart.size();
memcpy(dest, rawResponse.c_str(), rawResponse.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
dest += rawResponse.size();
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
raw = true;
}
else {
- for(const auto& addr : addrs) {
+ for (const auto& addr : addrs) {
uint16_t rdataLen = htons(addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
qtype = htons(addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA);
memcpy(&recordstart[2], &qtype, sizeof(qtype));
memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
- memcpy(dest, recordstart, sizeof(recordstart));
+ memcpy(dest, recordstart.data(), recordstart.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
dest += sizeof(recordstart);
memcpy(dest,
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
addr.sin4.sin_family == AF_INET ? reinterpret_cast<const void*>(&addr.sin4.sin_addr.s_addr) : reinterpret_cast<const void*>(&addr.sin6.sin6_addr.s6_addr),
addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- dq->getHeader()->ancount++;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.ancount++;
+ return true;
+ });
}
}
- dq->getHeader()->ancount = htons(dq->getHeader()->ancount);
+ auto finalANCount = dnsquestion->getHeader()->ancount;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [finalANCount](dnsheader& header) {
+ header.ancount = htons(finalANCount);
+ return true;
+ });
- if (hadEDNS && raw == false) {
- addEDNS(dq->getMutableData(), dq->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
+ if (hadEDNS && !raw) {
+ addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
}
return Action::HeaderModify;
@@ -951,56 +1063,62 @@ class SetMacAddrAction : public DNSAction
{
public:
// this action does not stop the processing
- SetMacAddrAction(uint16_t code) : d_code(code)
+ SetMacAddrAction(uint16_t code) :
+ d_code(code)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dnsdist::MacAddress mac;
- int res = dnsdist::MacAddressesCache::get(dq->ids.origRemote, mac.data(), mac.size());
+ dnsdist::MacAddress mac{};
+ int res = dnsdist::MacAddressesCache::get(dnsquestion->ids.origRemote, mac.data(), mac.size());
if (res != 0) {
return Action::None;
}
std::string optRData;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
generateEDNSOption(d_code, reinterpret_cast<const char*>(mac.data()), optRData);
- if (dq->getHeader()->arcount) {
+ if (dnsquestion->getHeader()->arcount > 0) {
bool ednsAdded = false;
bool optionAdded = false;
PacketBuffer newContent;
- newContent.reserve(dq->getData().size());
+ newContent.reserve(dnsquestion->getData().size());
- if (!slowRewriteEDNSOptionInQueryWithRecords(dq->getData(), newContent, ednsAdded, d_code, optionAdded, true, optRData)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(dnsquestion->getData(), newContent, ednsAdded, d_code, optionAdded, true, optRData)) {
return Action::None;
}
- if (newContent.size() > dq->getMaximumSize()) {
+ if (newContent.size() > dnsquestion->getMaximumSize()) {
return Action::None;
}
- dq->getMutableData() = std::move(newContent);
- if (!dq->ids.ednsAdded && ednsAdded) {
- dq->ids.ednsAdded = true;
+ dnsquestion->getMutableData() = std::move(newContent);
+ if (!dnsquestion->ids.ednsAdded && ednsAdded) {
+ dnsquestion->ids.ednsAdded = true;
}
return Action::None;
}
- auto& data = dq->getMutableData();
- if (generateOptRR(optRData, data, dq->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
- dq->getHeader()->arcount = htons(1);
+ auto& data = dnsquestion->getMutableData();
+ if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(1);
+ return true;
+ });
// make sure that any EDNS sent by the backend is removed before forwarding the response to the client
- dq->ids.ednsAdded = true;
+ dnsquestion->ids.ednsAdded = true;
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "add EDNS MAC (code=" + std::to_string(d_code) + ")";
}
+
private:
uint16_t d_code{3};
};
@@ -1009,17 +1127,18 @@ class SetEDNSOptionAction : public DNSAction
{
public:
// this action does not stop the processing
- SetEDNSOptionAction(uint16_t code, const std::string& data) : d_code(code), d_data(data)
+ SetEDNSOptionAction(uint16_t code, std::string data) :
+ d_code(code), d_data(std::move(data))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- setEDNSOption(*dq, d_code, d_data);
+ setEDNSOption(*dnsquestion, d_code, d_data);
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "add EDNS Option (code=" + std::to_string(d_code) + ")";
}
@@ -1033,12 +1152,15 @@ class SetNoRecurseAction : public DNSAction
{
public:
// this action does not stop the processing
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set rd=0";
}
@@ -1048,69 +1170,68 @@ class LogAction : public DNSAction, public boost::noncopyable
{
public:
// this action does not stop the processing
- LogAction()
- {
- }
+ LogAction() = default;
- LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered)
+ LogAction(const std::string& str, bool binary = true, bool append = false, bool buffered = true, bool verboseOnly = true, bool includeTimestamp = false) :
+ d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered)
{
if (str.empty()) {
return;
}
- if (!reopenLogFile()) {
+ if (!reopenLogFile()) {
throw std::runtime_error("Unable to open file '" + str + "' for logging: " + stringerror());
}
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
- if (!fp) {
+ auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
+ if (!filepointer) {
if (!d_verboseOnly || g_verbose) {
if (d_includeTimestamp) {
- infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq->getQueryRealTime().tv_sec), static_cast<unsigned long>(dq->getQueryRealTime().tv_nsec), dq->ids.origRemote.toStringWithPort(), dq->ids.qname.toString(), QType(dq->ids.qtype).toString(), dq->getHeader()->id);
+ infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dnsquestion->getQueryRealTime().tv_sec), static_cast<unsigned long>(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id);
}
else {
- infolog("Packet from %s for %s %s with id %d", dq->ids.origRemote.toStringWithPort(), dq->ids.qname.toString(), QType(dq->ids.qtype).toString(), dq->getHeader()->id);
+ infolog("Packet from %s for %s %s with id %d", dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id);
}
}
}
else {
if (d_binary) {
- const auto& out = dq->ids.qname.getStorage();
+ const auto& out = dnsquestion->ids.qname.getStorage();
if (d_includeTimestamp) {
- uint64_t tv_sec = static_cast<uint64_t>(dq->getQueryRealTime().tv_sec);
- uint32_t tv_nsec = static_cast<uint32_t>(dq->getQueryRealTime().tv_nsec);
- fwrite(&tv_sec, sizeof(tv_sec), 1, fp.get());
- fwrite(&tv_nsec, sizeof(tv_nsec), 1, fp.get());
+ auto tv_sec = static_cast<uint64_t>(dnsquestion->getQueryRealTime().tv_sec);
+ auto tv_nsec = static_cast<uint32_t>(dnsquestion->getQueryRealTime().tv_nsec);
+ fwrite(&tv_sec, sizeof(tv_sec), 1, filepointer.get());
+ fwrite(&tv_nsec, sizeof(tv_nsec), 1, filepointer.get());
}
- uint16_t id = dq->getHeader()->id;
- fwrite(&id, sizeof(id), 1, fp.get());
- fwrite(out.c_str(), 1, out.size(), fp.get());
- fwrite(&dq->ids.qtype, sizeof(dq->ids.qtype), 1, fp.get());
- fwrite(&dq->ids.origRemote.sin4.sin_family, sizeof(dq->ids.origRemote.sin4.sin_family), 1, fp.get());
- if (dq->ids.origRemote.sin4.sin_family == AF_INET) {
- fwrite(&dq->ids.origRemote.sin4.sin_addr.s_addr, sizeof(dq->ids.origRemote.sin4.sin_addr.s_addr), 1, fp.get());
+ uint16_t queryId = dnsquestion->getHeader()->id;
+ fwrite(&queryId, sizeof(queryId), 1, filepointer.get());
+ fwrite(out.c_str(), 1, out.size(), filepointer.get());
+ fwrite(&dnsquestion->ids.qtype, sizeof(dnsquestion->ids.qtype), 1, filepointer.get());
+ fwrite(&dnsquestion->ids.origRemote.sin4.sin_family, sizeof(dnsquestion->ids.origRemote.sin4.sin_family), 1, filepointer.get());
+ if (dnsquestion->ids.origRemote.sin4.sin_family == AF_INET) {
+ fwrite(&dnsquestion->ids.origRemote.sin4.sin_addr.s_addr, sizeof(dnsquestion->ids.origRemote.sin4.sin_addr.s_addr), 1, filepointer.get());
}
- else if (dq->ids.origRemote.sin4.sin_family == AF_INET6) {
- fwrite(&dq->ids.origRemote.sin6.sin6_addr.s6_addr, sizeof(dq->ids.origRemote.sin6.sin6_addr.s6_addr), 1, fp.get());
+ else if (dnsquestion->ids.origRemote.sin4.sin_family == AF_INET6) {
+ fwrite(&dnsquestion->ids.origRemote.sin6.sin6_addr.s6_addr, sizeof(dnsquestion->ids.origRemote.sin6.sin6_addr.s6_addr), 1, filepointer.get());
}
- fwrite(&dq->ids.origRemote.sin4.sin_port, sizeof(dq->ids.origRemote.sin4.sin_port), 1, fp.get());
+ fwrite(&dnsquestion->ids.origRemote.sin4.sin_port, sizeof(dnsquestion->ids.origRemote.sin4.sin_port), 1, filepointer.get());
}
else {
if (d_includeTimestamp) {
- fprintf(fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %u\n", static_cast<unsigned long long>(dq->getQueryRealTime().tv_sec), static_cast<unsigned long>(dq->getQueryRealTime().tv_nsec), dq->ids.origRemote.toStringWithPort().c_str(), dq->ids.qname.toString().c_str(), QType(dq->ids.qtype).toString().c_str(), dq->getHeader()->id);
+ fprintf(filepointer.get(), "[%llu.%lu] Packet from %s for %s %s with id %u\n", static_cast<unsigned long long>(dnsquestion->getQueryRealTime().tv_sec), static_cast<unsigned long>(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort().c_str(), dnsquestion->ids.qname.toString().c_str(), QType(dnsquestion->ids.qtype).toString().c_str(), dnsquestion->getHeader()->id);
}
else {
- fprintf(fp.get(), "Packet from %s for %s %s with id %u\n", dq->ids.origRemote.toStringWithPort().c_str(), dq->ids.qname.toString().c_str(), QType(dq->ids.qtype).toString().c_str(), dq->getHeader()->id);
+ fprintf(filepointer.get(), "Packet from %s for %s %s with id %u\n", dnsquestion->ids.origRemote.toStringWithPort().c_str(), dnsquestion->ids.qname.toString().c_str(), QType(dnsquestion->ids.qtype).toString().c_str(), dnsquestion->getHeader()->id);
}
}
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
if (!d_fname.empty()) {
return "log to " + d_fname;
@@ -1131,20 +1252,21 @@ private:
// we are using a naked pointer here because we don't want fclose to be called
// with a nullptr, which would happen if we constructor a shared_ptr with fclose
// as a custom deleter and nullptr as a FILE*
- auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
- if (!nfp) {
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ auto* nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
+ if (nfp == nullptr) {
/* don't fall on our sword when reopening */
return false;
}
- auto fp = std::shared_ptr<FILE>(nfp, fclose);
+ auto filepointer = std::shared_ptr<FILE>(nfp, fclose);
nfp = nullptr;
if (!d_buffered) {
- setbuf(fp.get(), 0);
+ setbuf(filepointer.get(), nullptr);
}
- std::atomic_store_explicit(&d_fp, fp, std::memory_order_release);
+ std::atomic_store_explicit(&d_fp, std::move(filepointer), std::memory_order_release);
return true;
}
@@ -1160,11 +1282,10 @@ private:
class LogResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
- LogResponseAction()
- {
- }
+ LogResponseAction() = default;
- LogResponseAction(const std::string& str, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered)
+ LogResponseAction(const std::string& str, bool append = false, bool buffered = true, bool verboseOnly = true, bool includeTimestamp = false) :
+ d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered)
{
if (str.empty()) {
return;
@@ -1175,31 +1296,31 @@ public:
}
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
- if (!fp) {
+ auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
+ if (!filepointer) {
if (!d_verboseOnly || g_verbose) {
if (d_includeTimestamp) {
- infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast<unsigned long long>(dr->getQueryRealTime().tv_sec), static_cast<unsigned long>(dr->getQueryRealTime().tv_nsec), dr->ids.origRemote.toStringWithPort(), dr->ids.qname.toString(), QType(dr->ids.qtype).toString(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id);
+ infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast<unsigned long long>(response->getQueryRealTime().tv_sec), static_cast<unsigned long>(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id);
}
else {
- infolog("Answer to %s for %s %s (%s) with id %u", dr->ids.origRemote.toStringWithPort(), dr->ids.qname.toString(), QType(dr->ids.qtype).toString(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id);
+ infolog("Answer to %s for %s %s (%s) with id %u", response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id);
}
}
}
else {
if (d_includeTimestamp) {
- fprintf(fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %u\n", static_cast<unsigned long long>(dr->getQueryRealTime().tv_sec), static_cast<unsigned long>(dr->getQueryRealTime().tv_nsec), dr->ids.origRemote.toStringWithPort().c_str(), dr->ids.qname.toString().c_str(), QType(dr->ids.qtype).toString().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id);
+ fprintf(filepointer.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %u\n", static_cast<unsigned long long>(response->getQueryRealTime().tv_sec), static_cast<unsigned long>(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort().c_str(), response->ids.qname.toString().c_str(), QType(response->ids.qtype).toString().c_str(), RCode::to_s(response->getHeader()->rcode).c_str(), response->getHeader()->id);
}
else {
- fprintf(fp.get(), "Answer to %s for %s %s (%s) with id %u\n", dr->ids.origRemote.toStringWithPort().c_str(), dr->ids.qname.toString().c_str(), QType(dr->ids.qtype).toString().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id);
+ fprintf(filepointer.get(), "Answer to %s for %s %s (%s) with id %u\n", response->ids.origRemote.toStringWithPort().c_str(), response->ids.qname.toString().c_str(), QType(response->ids.qtype).toString().c_str(), RCode::to_s(response->getHeader()->rcode).c_str(), response->getHeader()->id);
}
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
if (!d_fname.empty()) {
return "log to " + d_fname;
@@ -1220,20 +1341,21 @@ private:
// we are using a naked pointer here because we don't want fclose to be called
// with a nullptr, which would happen if we constructor a shared_ptr with fclose
// as a custom deleter and nullptr as a FILE*
- auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
- if (!nfp) {
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ auto* nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w");
+ if (nfp == nullptr) {
/* don't fall on our sword when reopening */
return false;
}
- auto fp = std::shared_ptr<FILE>(nfp, fclose);
+ auto filepointer = std::shared_ptr<FILE>(nfp, fclose);
nfp = nullptr;
if (!d_buffered) {
- setbuf(fp.get(), 0);
+ setbuf(filepointer.get(), nullptr);
}
- std::atomic_store_explicit(&d_fp, fp, std::memory_order_release);
+ std::atomic_store_explicit(&d_fp, std::move(filepointer), std::memory_order_release);
return true;
}
@@ -1249,12 +1371,15 @@ class SetDisableValidationAction : public DNSAction
{
public:
// this action does not stop the processing
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->getHeader()->cd = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
+ header.cd = true;
+ return true;
+ });
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set cd=1";
}
@@ -1264,12 +1389,12 @@ class SetSkipCacheAction : public DNSAction
{
public:
// this action does not stop the processing
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->ids.skipCache = true;
+ dnsquestion->ids.skipCache = true;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "skip cache";
}
@@ -1278,12 +1403,12 @@ public:
class SetSkipCacheResponseAction : public DNSResponseAction
{
public:
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- dr->ids.skipCache = true;
+ response->ids.skipCache = true;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "skip cache";
}
@@ -1293,18 +1418,20 @@ class SetTempFailureCacheTTLAction : public DNSAction
{
public:
// this action does not stop the processing
- SetTempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
+ SetTempFailureCacheTTLAction(uint32_t ttl) :
+ d_ttl(ttl)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->ids.tempFailureTTL = d_ttl;
+ dnsquestion->ids.tempFailureTTL = d_ttl;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
- return "set tempfailure cache ttl to "+std::to_string(d_ttl);
+ return "set tempfailure cache ttl to " + std::to_string(d_ttl);
}
+
private:
uint32_t d_ttl;
};
@@ -1313,18 +1440,20 @@ class SetECSPrefixLengthAction : public DNSAction
{
public:
// this action does not stop the processing
- SetECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
+ SetECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) :
+ d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->ecsPrefixLength = dq->ids.origRemote.sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
+ dnsquestion->ecsPrefixLength = dnsquestion->ids.origRemote.sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
}
+
private:
uint16_t d_v4PrefixLength;
uint16_t d_v6PrefixLength;
@@ -1334,33 +1463,34 @@ class SetECSOverrideAction : public DNSAction
{
public:
// this action does not stop the processing
- SetECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
+ SetECSOverrideAction(bool ecsOverride) :
+ d_ecsOverride(ecsOverride)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->ecsOverride = d_ecsOverride;
+ dnsquestion->ecsOverride = d_ecsOverride;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
- return "set ECS override to " + std::to_string(d_ecsOverride);
+ return "set ECS override to " + std::to_string(static_cast<int>(d_ecsOverride));
}
+
private:
bool d_ecsOverride;
};
-
class SetDisableECSAction : public DNSAction
{
public:
// this action does not stop the processing
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->useECS = false;
+ dnsquestion->useECS = false;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "disable ECS";
}
@@ -1370,27 +1500,29 @@ class SetECSAction : public DNSAction
{
public:
// this action does not stop the processing
- SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
+ SetECSAction(const Netmask& v4Netmask) :
+ d_v4(v4Netmask), d_hasV6(false)
{
}
- SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
+ SetECSAction(const Netmask& v4Netmask, const Netmask& v6Netmask) :
+ d_v4(v4Netmask), d_v6(v6Netmask), d_hasV6(true)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
if (d_hasV6) {
- dq->ecs = std::make_unique<Netmask>(dq->ids.origRemote.isIPv4() ? d_v4 : d_v6);
+ dnsquestion->ecs = std::make_unique<Netmask>(dnsquestion->ids.origRemote.isIPv4() ? d_v4 : d_v6);
}
else {
- dq->ecs = std::make_unique<Netmask>(d_v4);
+ dnsquestion->ecs = std::make_unique<Netmask>(d_v4);
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
std::string result = "set ECS to " + d_v4.toString();
if (d_hasV6) {
@@ -1411,41 +1543,44 @@ static DnstapMessage::ProtocolType ProtocolToDNSTap(dnsdist::Protocol protocol)
if (protocol == dnsdist::Protocol::DoUDP) {
return DnstapMessage::ProtocolType::DoUDP;
}
- else if (protocol == dnsdist::Protocol::DoTCP) {
+ if (protocol == dnsdist::Protocol::DoTCP) {
return DnstapMessage::ProtocolType::DoTCP;
}
- else if (protocol == dnsdist::Protocol::DoT) {
+ if (protocol == dnsdist::Protocol::DoT) {
return DnstapMessage::ProtocolType::DoT;
}
- else if (protocol == dnsdist::Protocol::DoH) {
+ if (protocol == dnsdist::Protocol::DoH || protocol == dnsdist::Protocol::DoH3) {
return DnstapMessage::ProtocolType::DoH;
}
- else if (protocol == dnsdist::Protocol::DNSCryptUDP) {
+ if (protocol == dnsdist::Protocol::DNSCryptUDP) {
return DnstapMessage::ProtocolType::DNSCryptUDP;
}
- else if (protocol == dnsdist::Protocol::DNSCryptTCP) {
+ if (protocol == dnsdist::Protocol::DNSCryptTCP) {
return DnstapMessage::ProtocolType::DNSCryptTCP;
}
+ if (protocol == dnsdist::Protocol::DoQ) {
+ return DnstapMessage::ProtocolType::DoQ;
+ }
throw std::runtime_error("Unhandled protocol for dnstap: " + protocol.toPrettyString());
}
-static void remoteLoggerQueueData(RemoteLoggerInterface& r, const std::string& data)
+static void remoteLoggerQueueData(RemoteLoggerInterface& remoteLogger, const std::string& data)
{
- auto ret = r.queueData(data);
+ auto ret = remoteLogger.queueData(data);
switch (ret) {
case RemoteLoggerInterface::Result::Queued:
break;
case RemoteLoggerInterface::Result::PipeFull: {
- vinfolog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret));
+ vinfolog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret));
break;
}
case RemoteLoggerInterface::Result::TooLarge: {
- warnlog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret));
+ warnlog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret));
break;
}
case RemoteLoggerInterface::Result::OtherError:
- warnlog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret));
+ warnlog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret));
}
}
@@ -1453,51 +1588,57 @@ class DnstapLogAction : public DNSAction, public boost::noncopyable
{
public:
// this action does not stop the processing
- DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
+ DnstapLogAction(std::string identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)>> alterFunc) :
+ d_identity(std::move(identity)), d_logger(logger), d_alterFunc(std::move(alterFunc))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
static thread_local std::string data;
data.clear();
- DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dq->getProtocol());
- DnstapMessage message(data, !dq->getHeader()->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, &dq->ids.origRemote, &dq->ids.origDest, protocol, reinterpret_cast<const char*>(dq->getData().data()), dq->getData().size(), &dq->getQueryRealTime(), nullptr);
+ DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dnsquestion->getProtocol());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ DnstapMessage message(std::move(data), !dnsquestion->getHeader()->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, &dnsquestion->ids.origRemote, &dnsquestion->ids.origDest, protocol, reinterpret_cast<const char*>(dnsquestion->getData().data()), dnsquestion->getData().size(), &dnsquestion->getQueryRealTime(), nullptr);
{
if (d_alterFunc) {
auto lock = g_lua.lock();
- (*d_alterFunc)(dq, &message);
+ (*d_alterFunc)(dnsquestion, &message);
}
}
+ data = message.getBuffer();
remoteLoggerQueueData(*d_logger, data);
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
}
+
private:
std::string d_identity;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)>> d_alterFunc;
};
-static void addMetaDataToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, const std::vector<std::pair<std::string, ProtoBufMetaKey>>& metas)
+namespace
+{
+void addMetaDataToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dnsquestion, const std::vector<std::pair<std::string, ProtoBufMetaKey>>& metas)
{
for (const auto& [name, meta] : metas) {
- message.addMeta(name, meta.getValues(dq));
+ message.addMeta(name, meta.getValues(dnsquestion), {});
}
}
-static void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, const std::unordered_set<std::string>& allowed)
+void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dnsquestion, const std::unordered_set<std::string>& allowed)
{
- if (!dq.ids.qTag) {
+ if (!dnsquestion.ids.qTag) {
return;
}
- for (const auto& [key, value] : *dq.ids.qTag) {
+ for (const auto& [key, value] : *dnsquestion.ids.qTag) {
if (!allowed.empty() && allowed.count(key) == 0) {
continue;
}
@@ -1506,49 +1647,81 @@ static void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion
message.addTag(key);
}
else {
- message.addTag(key + ":" + value);
+ auto tag = key;
+ tag.append(":");
+ tag.append(value);
+ message.addTag(tag);
}
}
}
+void addExtendedDNSErrorToProtobuf(DNSDistProtoBufMessage& message, const DNSResponse& response, const std::string& metaKey)
+{
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(response.getData());
+ if (!infoCode) {
+ return;
+ }
+
+ if (extraText) {
+ message.addMeta(metaKey, {*extraText}, {*infoCode});
+ }
+ else {
+ message.addMeta(metaKey, {}, {*infoCode});
+ }
+}
+}
+
+struct RemoteLogActionConfiguration
+{
+ std::vector<std::pair<std::string, ProtoBufMetaKey>> metas;
+ std::optional<std::unordered_set<std::string>> tagsToExport{std::nullopt};
+ boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)>> alterQueryFunc{boost::none};
+ boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)>> alterResponseFunc{boost::none};
+ std::shared_ptr<RemoteLoggerInterface> logger;
+ std::string serverID;
+ std::string ipEncryptKey;
+ std::optional<std::string> exportExtendedErrorsToMeta{std::nullopt};
+ bool includeCNAME{false};
+};
+
class RemoteLogAction : public DNSAction, public boost::noncopyable
{
public:
// this action does not stop the processing
- RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, std::vector<std::pair<std::string, ProtoBufMetaKey>>&& metas, std::optional<std::unordered_set<std::string>>&& tagsToExport): d_tagsToExport(std::move(tagsToExport)), d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
+ RemoteLogAction(RemoteLogActionConfiguration& config) :
+ d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (!dq->ids.d_protoBufData) {
- dq->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
+ if (!dnsquestion->ids.d_protoBufData) {
+ dnsquestion->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
}
- if (!dq->ids.d_protoBufData->uniqueId) {
- dq->ids.d_protoBufData->uniqueId = getUniqueID();
+ if (!dnsquestion->ids.d_protoBufData->uniqueId) {
+ dnsquestion->ids.d_protoBufData->uniqueId = getUniqueID();
}
- DNSDistProtoBufMessage message(*dq);
+ DNSDistProtoBufMessage message(*dnsquestion);
if (!d_serverID.empty()) {
message.setServerIdentity(d_serverID);
}
#if HAVE_IPCIPHER
- if (!d_ipEncryptKey.empty())
- {
- message.setRequestor(encryptCA(dq->ids.origRemote, d_ipEncryptKey));
+ if (!d_ipEncryptKey.empty()) {
+ message.setRequestor(encryptCA(dnsquestion->ids.origRemote, d_ipEncryptKey));
}
#endif /* HAVE_IPCIPHER */
if (d_tagsToExport) {
- addTagsToProtobuf(message, *dq, *d_tagsToExport);
+ addTagsToProtobuf(message, *dnsquestion, *d_tagsToExport);
}
- addMetaDataToProtobuf(message, *dq, d_metas);
+ addMetaDataToProtobuf(message, *dnsquestion, d_metas);
if (d_alterFunc) {
auto lock = g_lua.lock();
- (*d_alterFunc)(dq, &message);
+ (*d_alterFunc)(dnsquestion, &message);
}
static thread_local std::string data;
@@ -1558,15 +1731,16 @@ public:
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "remote log to " + (d_logger ? d_logger->toString() : "");
}
+
private:
std::optional<std::unordered_set<std::string>> d_tagsToExport;
std::vector<std::pair<std::string, ProtoBufMetaKey>> d_metas;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)>> d_alterFunc;
std::string d_serverID;
std::string d_ipEncryptKey;
};
@@ -1577,21 +1751,23 @@ class SNMPTrapAction : public DNSAction
{
public:
// this action does not stop the processing
- SNMPTrapAction(const std::string& reason): d_reason(reason)
+ SNMPTrapAction(std::string reason) :
+ d_reason(std::move(reason))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (g_snmpAgent && g_snmpTrapsEnabled) {
- g_snmpAgent->sendDNSTrap(*dq, d_reason);
+ if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+ g_snmpAgent->sendDNSTrap(*dnsquestion, d_reason);
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "send SNMP trap";
}
+
private:
std::string d_reason;
};
@@ -1600,19 +1776,21 @@ class SetTagAction : public DNSAction
{
public:
// this action does not stop the processing
- SetTagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
+ SetTagAction(std::string tag, std::string value) :
+ d_tag(std::move(tag)), d_value(std::move(value))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->setTag(d_tag, d_value);
+ dnsquestion->setTag(d_tag, d_value);
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set tag '" + d_tag + "' to value '" + d_value + "'";
}
+
private:
std::string d_tag;
std::string d_value;
@@ -1623,76 +1801,84 @@ class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopya
{
public:
// this action does not stop the processing
- DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
+ DnstapLogResponseAction(std::string identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)>> alterFunc) :
+ d_identity(std::move(identity)), d_logger(logger), d_alterFunc(std::move(alterFunc))
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
static thread_local std::string data;
- struct timespec now;
+ struct timespec now = {};
gettime(&now, true);
data.clear();
- DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dr->getProtocol());
- DnstapMessage message(data, DnstapMessage::MessageType::client_response, d_identity, &dr->ids.origRemote, &dr->ids.origDest, protocol, reinterpret_cast<const char*>(dr->getData().data()), dr->getData().size(), &dr->getQueryRealTime(), &now);
+ DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(response->getProtocol());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ DnstapMessage message(std::move(data), DnstapMessage::MessageType::client_response, d_identity, &response->ids.origRemote, &response->ids.origDest, protocol, reinterpret_cast<const char*>(response->getData().data()), response->getData().size(), &response->getQueryRealTime(), &now);
{
if (d_alterFunc) {
auto lock = g_lua.lock();
- (*d_alterFunc)(dr, &message);
+ (*d_alterFunc)(response, &message);
}
}
+ data = message.getBuffer();
remoteLoggerQueueData(*d_logger, data);
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
}
+
private:
std::string d_identity;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSResponse*, DnstapMessage*)>> d_alterFunc;
};
class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
// this action does not stop the processing
- RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME, std::vector<std::pair<std::string, ProtoBufMetaKey>>&& metas, std::optional<std::unordered_set<std::string>>&& tagsToExport): d_tagsToExport(std::move(tagsToExport)), d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
+ RemoteLogResponseAction(RemoteLogActionConfiguration& config) :
+ d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME)
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- if (!dr->ids.d_protoBufData) {
- dr->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
+ if (!response->ids.d_protoBufData) {
+ response->ids.d_protoBufData = std::make_unique<InternalQueryState::ProtoBufData>();
}
- if (!dr->ids.d_protoBufData->uniqueId) {
- dr->ids.d_protoBufData->uniqueId = getUniqueID();
+ if (!response->ids.d_protoBufData->uniqueId) {
+ response->ids.d_protoBufData->uniqueId = getUniqueID();
}
- DNSDistProtoBufMessage message(*dr, d_includeCNAME);
+ DNSDistProtoBufMessage message(*response, d_includeCNAME);
if (!d_serverID.empty()) {
message.setServerIdentity(d_serverID);
}
#if HAVE_IPCIPHER
- if (!d_ipEncryptKey.empty())
- {
- message.setRequestor(encryptCA(dr->ids.origRemote, d_ipEncryptKey));
+ if (!d_ipEncryptKey.empty()) {
+ message.setRequestor(encryptCA(response->ids.origRemote, d_ipEncryptKey));
}
#endif /* HAVE_IPCIPHER */
if (d_tagsToExport) {
- addTagsToProtobuf(message, *dr, *d_tagsToExport);
+ addTagsToProtobuf(message, *response, *d_tagsToExport);
}
- addMetaDataToProtobuf(message, *dr, d_metas);
+ addMetaDataToProtobuf(message, *response, d_metas);
+
+ if (d_exportExtendedErrorsToMeta) {
+ addExtendedDNSErrorToProtobuf(message, *response, *d_exportExtendedErrorsToMeta);
+ }
if (d_alterFunc) {
auto lock = g_lua.lock();
- (*d_alterFunc)(dr, &message);
+ (*d_alterFunc)(response, &message);
}
static thread_local std::string data;
@@ -1702,17 +1888,19 @@ public:
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "remote log response to " + (d_logger ? d_logger->toString() : "");
}
+
private:
std::optional<std::unordered_set<std::string>> d_tagsToExport;
std::vector<std::pair<std::string, ProtoBufMetaKey>> d_metas;
std::shared_ptr<RemoteLoggerInterface> d_logger;
- boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
+ boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)>> d_alterFunc;
std::string d_serverID;
std::string d_ipEncryptKey;
+ std::optional<std::string> d_exportExtendedErrorsToMeta{std::nullopt};
bool d_includeCNAME;
};
@@ -1721,11 +1909,11 @@ private:
class DropResponseAction : public DNSResponseAction
{
public:
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
return Action::Drop;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "drop";
}
@@ -1734,11 +1922,11 @@ public:
class AllowResponseAction : public DNSResponseAction
{
public:
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
return Action::Allow;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "allow";
}
@@ -1747,18 +1935,20 @@ public:
class DelayResponseAction : public DNSResponseAction
{
public:
- DelayResponseAction(int msec) : d_msec(msec)
+ DelayResponseAction(int msec) :
+ d_msec(msec)
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
*ruleresult = std::to_string(d_msec);
return Action::Delay;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
- return "delay by "+std::to_string(d_msec)+ " msec";
+ return "delay by " + std::to_string(d_msec) + " ms";
}
+
private:
int d_msec;
};
@@ -1768,21 +1958,23 @@ class SNMPTrapResponseAction : public DNSResponseAction
{
public:
// this action does not stop the processing
- SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
+ SNMPTrapResponseAction(std::string reason) :
+ d_reason(std::move(reason))
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
if (g_snmpAgent && g_snmpTrapsEnabled) {
- g_snmpAgent->sendDNSTrap(*dr, d_reason);
+ g_snmpAgent->sendDNSTrap(*response, d_reason);
}
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "send SNMP trap";
}
+
private:
std::string d_reason;
};
@@ -1792,19 +1984,21 @@ class SetTagResponseAction : public DNSResponseAction
{
public:
// this action does not stop the processing
- SetTagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
+ SetTagResponseAction(std::string tag, std::string value) :
+ d_tag(std::move(tag)), d_value(std::move(value))
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- dr->setTag(d_tag, d_value);
+ response->setTag(d_tag, d_value);
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set tag '" + d_tag + "' to value '" + d_value + "'";
}
+
private:
std::string d_tag;
std::string d_value;
@@ -1813,19 +2007,20 @@ private:
class ClearRecordTypesResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
- ClearRecordTypesResponseAction(const std::unordered_set<QType>& qtypes) : d_qtypes(qtypes)
+ ClearRecordTypesResponseAction(std::unordered_set<QType> qtypes) :
+ d_qtypes(std::move(qtypes))
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- if (d_qtypes.size() > 0) {
- clearDNSPacketRecordTypes(dr->getMutableData(), d_qtypes);
+ if (!d_qtypes.empty()) {
+ clearDNSPacketRecordTypes(response->getMutableData(), d_qtypes);
}
return DNSResponseAction::Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "clear record types";
}
@@ -1838,32 +2033,31 @@ class ContinueAction : public DNSAction
{
public:
// this action does not stop the processing
- ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action)
+ ContinueAction(std::shared_ptr<DNSAction>& action) :
+ d_action(action)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
if (d_action) {
/* call the action */
- auto action = (*d_action)(dq, ruleresult);
+ auto action = (*d_action)(dnsquestion, ruleresult);
bool drop = false;
/* apply the changes if needed (pool selection, flags, etc */
- processRulesResult(action, *dq, *ruleresult, drop);
+ processRulesResult(action, *dnsquestion, *ruleresult, drop);
}
/* but ignore the resulting action no matter what */
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
if (d_action) {
return "continue after: " + (d_action ? d_action->toString() : "");
}
- else {
- return "no op";
- }
+ return "no op";
}
private:
@@ -1871,32 +2065,41 @@ private:
};
#ifdef HAVE_DNS_OVER_HTTPS
-class HTTPStatusAction: public DNSAction
+class HTTPStatusAction : public DNSAction
{
public:
- HTTPStatusAction(int code, const PacketBuffer& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
+ HTTPStatusAction(int code, PacketBuffer body, std::string contentType) :
+ d_body(std::move(body)), d_contentType(std::move(contentType)), d_code(code)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (!dq->ids.du) {
+ if (!dnsquestion->ids.du) {
return Action::None;
}
- dq->ids.du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType);
- dq->getHeader()->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsquestion->ids.du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::HeaderModify;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "return an HTTP status of " + std::to_string(d_code);
}
- ResponseConfig d_responseConfig;
+ [[nodiscard]] ResponseConfig& getResponseConfig()
+ {
+ return d_responseConfig;
+ }
+
private:
+ ResponseConfig d_responseConfig;
PacketBuffer d_body;
std::string d_contentType;
int d_code;
@@ -1908,26 +2111,27 @@ class KeyValueStoreLookupAction : public DNSAction
{
public:
// this action does not stop the processing
- KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
+ KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, std::string destinationTag) :
+ d_kvs(kvs), d_key(lookupKey), d_tag(std::move(destinationTag))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- std::vector<std::string> keys = d_key->getKeys(*dq);
+ std::vector<std::string> keys = d_key->getKeys(*dnsquestion);
std::string result;
for (const auto& key : keys) {
- if (d_kvs->getValue(key, result) == true) {
+ if (d_kvs->getValue(key, result)) {
break;
}
}
- dq->setTag(d_tag, std::move(result));
+ dnsquestion->setTag(d_tag, std::move(result));
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
}
@@ -1942,26 +2146,27 @@ class KeyValueStoreRangeLookupAction : public DNSAction
{
public:
// this action does not stop the processing
- KeyValueStoreRangeLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
+ KeyValueStoreRangeLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, std::string destinationTag) :
+ d_kvs(kvs), d_key(lookupKey), d_tag(std::move(destinationTag))
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- std::vector<std::string> keys = d_key->getKeys(*dq);
+ std::vector<std::string> keys = d_key->getKeys(*dnsquestion);
std::string result;
for (const auto& key : keys) {
- if (d_kvs->getRangeValue(key, result) == true) {
+ if (d_kvs->getRangeValue(key, result)) {
break;
}
}
- dq->setTag(d_tag, std::move(result));
+ dnsquestion->setTag(d_tag, std::move(result));
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "do a range-based lookup in key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
}
@@ -1976,17 +2181,18 @@ private:
class MaxReturnedTTLAction : public DNSAction
{
public:
- MaxReturnedTTLAction(uint32_t cap) : d_cap(cap)
+ MaxReturnedTTLAction(uint32_t cap) :
+ d_cap(cap)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- dq->ids.ttlCap = d_cap;
+ dnsquestion->ids.ttlCap = d_cap;
return DNSAction::Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "cap the TTL of the returned response to " + std::to_string(d_cap);
}
@@ -1998,17 +2204,18 @@ private:
class MaxReturnedTTLResponseAction : public DNSResponseAction
{
public:
- MaxReturnedTTLResponseAction(uint32_t cap) : d_cap(cap)
+ MaxReturnedTTLResponseAction(uint32_t cap) :
+ d_cap(cap)
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
- dr->ids.ttlCap = d_cap;
+ response->ids.ttlCap = d_cap;
return DNSResponseAction::Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "cap the TTL of the returned response to " + std::to_string(d_cap);
}
@@ -2017,41 +2224,54 @@ private:
uint32_t d_cap;
};
-class NegativeAndSOAAction: public DNSAction
+class NegativeAndSOAAction : public DNSAction
{
public:
- NegativeAndSOAAction(bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, bool soaInAuthoritySection): d_zone(zone), d_mname(mname), d_rname(rname), d_ttl(ttl), d_serial(serial), d_refresh(refresh), d_retry(retry), d_expire(expire), d_minimum(minimum), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection)
+ struct SOAParams
+ {
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+ };
+
+ NegativeAndSOAAction(bool nxd, DNSName zone, uint32_t ttl, DNSName mname, DNSName rname, SOAParams params, bool soaInAuthoritySection) :
+ d_zone(std::move(zone)), d_mname(std::move(mname)), d_rname(std::move(rname)), d_ttl(ttl), d_params(params), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum, d_soaInAuthoritySection)) {
+ if (!setNegativeAndAdditionalSOA(*dnsquestion, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_params.serial, d_params.refresh, d_params.retry, d_params.expire, d_params.minimum, d_soaInAuthoritySection)) {
return Action::None;
}
- setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
+ setResponseHeadersFromConfig(header, d_responseConfig);
+ return true;
+ });
return Action::Allow;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA";
}
+ [[nodiscard]] ResponseConfig& getResponseConfig()
+ {
+ return d_responseConfig;
+ }
+private:
ResponseConfig d_responseConfig;
-private:
DNSName d_zone;
DNSName d_mname;
DNSName d_rname;
uint32_t d_ttl;
- uint32_t d_serial;
- uint32_t d_refresh;
- uint32_t d_retry;
- uint32_t d_expire;
- uint32_t d_minimum;
+ SOAParams d_params;
bool d_nxd;
bool d_soaInAuthoritySection;
};
@@ -2068,18 +2288,18 @@ public:
}
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (!dq->proxyProtocolValues) {
- dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
+ if (!dnsquestion->proxyProtocolValues) {
+ dnsquestion->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
}
- *(dq->proxyProtocolValues) = d_values;
+ *(dnsquestion->proxyProtocolValues) = d_values;
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "set Proxy-Protocol values";
}
@@ -2092,22 +2312,23 @@ class SetAdditionalProxyProtocolValueAction : public DNSAction
{
public:
// this action does not stop the processing
- SetAdditionalProxyProtocolValueAction(uint8_t type, const std::string& value): d_value(value), d_type(type)
+ SetAdditionalProxyProtocolValueAction(uint8_t type, std::string value) :
+ d_value(std::move(value)), d_type(type)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
- if (!dq->proxyProtocolValues) {
- dq->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
+ if (!dnsquestion->proxyProtocolValues) {
+ dnsquestion->proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
}
- dq->proxyProtocolValues->push_back({ d_value, d_type });
+ dnsquestion->proxyProtocolValues->push_back({d_value, d_type});
return Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "add a Proxy-Protocol value of type " + std::to_string(d_type);
}
@@ -2121,20 +2342,23 @@ class SetReducedTTLResponseAction : public DNSResponseAction, public boost::nonc
{
public:
// this action does not stop the processing
- SetReducedTTLResponseAction(uint8_t percentage) : d_ratio(percentage / 100.0)
+ SetReducedTTLResponseAction(uint8_t percentage) :
+ d_ratio(percentage / 100.0)
{
}
- DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+ DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
{
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
auto visitor = [&](uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl) {
return ttl * d_ratio;
};
- editDNSPacketTTL(reinterpret_cast<char *>(dr->getMutableData().data()), dr->getData().size(), visitor);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ editDNSPacketTTL(reinterpret_cast<char*>(response->getMutableData().data()), response->getData().size(), visitor);
return DNSResponseAction::Action::None;
}
- std::string toString() const override
+ [[nodiscard]] std::string toString() const override
{
return "reduce ttl to " + std::to_string(d_ratio * 100) + " percent of its value";
}
@@ -2143,23 +2367,76 @@ private:
double d_ratio{1.0};
};
-template<typename T, typename ActionT>
-static void addAction(GlobalStateHolder<vector<T> > *someRuleActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params) {
+class SetExtendedDNSErrorAction : public DNSAction
+{
+public:
+ // this action does not stop the processing
+ SetExtendedDNSErrorAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSAction::Action operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const override
+ {
+ dnsQuestion->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+
+ return DNSAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ EDNSExtendedError d_ede;
+};
+
+class SetExtendedDNSErrorResponseAction : public DNSResponseAction
+{
+public:
+ // this action does not stop the processing
+ SetExtendedDNSErrorResponseAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSResponseAction::Action operator()(DNSResponse* dnsResponse, std::string* ruleresult) const override
+ {
+ dnsResponse->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+
+ return DNSResponseAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "set EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ EDNSExtendedError d_ede;
+};
+
+template <typename T, typename ActionT>
+static void addAction(GlobalStateHolder<vector<T>>* someRuleActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
+{
setLuaSideEffect();
std::string name;
- boost::uuids::uuid uuid;
- uint64_t creationOrder;
+ boost::uuids::uuid uuid{};
+ uint64_t creationOrder = 0;
parseRuleParams(params, uuid, name, creationOrder);
checkAllParametersConsumed("addAction", params);
- auto rule = makeRule(var);
- someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions){
- ruleactions.push_back({std::move(rule), std::move(action), std::move(name), std::move(uuid), creationOrder});
- });
+ auto rule = makeRule(var, "addAction");
+ someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector<T>& ruleactions) {
+ ruleactions.push_back({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
+ });
}
-typedef std::unordered_map<std::string, boost::variant<bool, uint32_t> > responseParams_t;
+using responseParams_t = std::unordered_map<std::string, boost::variant<bool, uint32_t>>;
static void parseResponseConfig(boost::optional<responseParams_t>& vars, ResponseConfig& config)
{
@@ -2169,193 +2446,208 @@ static void parseResponseConfig(boost::optional<responseParams_t>& vars, Respons
getOptionalValue<bool>(vars, "ra", config.setRA);
}
-void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config)
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config)
{
if (config.setAA) {
- dh.aa = *config.setAA;
+ dnsheader.aa = *config.setAA;
}
if (config.setAD) {
- dh.ad = *config.setAD;
+ dnsheader.ad = *config.setAD;
}
else {
- dh.ad = false;
+ dnsheader.ad = false;
}
if (config.setRA) {
- dh.ra = *config.setRA;
+ dnsheader.ra = *config.setRA;
}
else {
- dh.ra = dh.rd; // for good measure
+ dnsheader.ra = dnsheader.rd; // for good measure
}
}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaActions(LuaContext& luaCtx)
{
- luaCtx.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
- boost::uuids::uuid uuid;
- uint64_t creationOrder;
- std::string name;
- parseRuleParams(params, uuid, name, creationOrder);
- checkAllParametersConsumed("newRuleAction", params);
+ luaCtx.writeFunction("newRuleAction", [](const luadnsrule_t& dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
+ boost::uuids::uuid uuid{};
+ uint64_t creationOrder = 0;
+ std::string name;
+ parseRuleParams(params, uuid, name, creationOrder);
+ checkAllParametersConsumed("newRuleAction", params);
- auto rule = makeRule(dnsrule);
- DNSDistRuleAction ra({std::move(rule), action, std::move(name), uuid, creationOrder});
- return std::make_shared<DNSDistRuleAction>(ra);
- });
+ auto rule = makeRule(dnsrule, "newRuleAction");
+ DNSDistRuleAction ruleaction({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
+ return std::make_shared<DNSDistRuleAction>(ruleaction);
+ });
- luaCtx.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
- if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
- throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
- }
+ luaCtx.writeFunction("addAction", [](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+ if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
+ throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
+ }
- addAction(&g_ruleactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
- });
+ addAction(&g_ruleactions, var, boost::get<std::shared_ptr<DNSAction>>(era), params);
+ });
- luaCtx.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
- if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
- throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
- }
+ luaCtx.writeFunction("addResponseAction", [](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+ if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
+ throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
+ }
- addAction(&g_respruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
- });
+ addAction(&g_respruleactions, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
+ });
- luaCtx.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
- if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
- throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
- }
+ luaCtx.writeFunction("addCacheHitResponseAction", [](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+ if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
+ throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
+ }
- addAction(&g_cachehitrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
- });
+ addAction(&g_cachehitrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
+ });
- luaCtx.writeFunction("addCacheInsertedResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+ luaCtx.writeFunction("addCacheInsertedResponseAction", [](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
throw std::runtime_error("addCacheInsertedResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
}
- addAction(&g_cacheInsertedRespRuleActions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
+ addAction(&g_cacheInsertedRespRuleActions, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
});
- luaCtx.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
- if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
- throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
- }
+ luaCtx.writeFunction("addSelfAnsweredResponseAction", [](const luadnsrule_t& var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
+ if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
+ throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
+ }
- addAction(&g_selfansweredrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
- });
+ addAction(&g_selfansweredrespruleactions, var, boost::get<std::shared_ptr<DNSResponseAction>>(era), params);
+ });
- luaCtx.registerFunction<void(DNSAction::*)()const>("printStats", [](const DNSAction& ta) {
- setLuaNoSideEffect();
- auto stats = ta.getStats();
- for(const auto& s : stats) {
- g_outputBuffer+=s.first+"\t";
- if((uint64_t)s.second == s.second)
- g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
- else
- g_outputBuffer += std::to_string(s.second)+"\n";
+ luaCtx.registerFunction<void (DNSAction::*)() const>("printStats", [](const DNSAction& action) {
+ setLuaNoSideEffect();
+ auto stats = action.getStats();
+ for (const auto& stat : stats) {
+ g_outputBuffer += stat.first + "\t";
+ double integral = 0;
+ if (std::modf(stat.second, &integral) == 0.0 && stat.second < static_cast<double>(std::numeric_limits<uint64_t>::max())) {
+ g_outputBuffer += std::to_string(static_cast<uint64_t>(stat.second)) + "\n";
}
- });
+ else {
+ g_outputBuffer += std::to_string(stat.second) + "\n";
+ }
+ }
+ });
luaCtx.writeFunction("getAction", [](unsigned int num) {
- setLuaNoSideEffect();
- boost::optional<std::shared_ptr<DNSAction>> ret;
- auto ruleactions = g_ruleactions.getCopy();
- if(num < ruleactions.size())
- ret=ruleactions[num].d_action;
- return ret;
- });
+ setLuaNoSideEffect();
+ boost::optional<std::shared_ptr<DNSAction>> ret;
+ auto ruleactions = g_ruleactions.getCopy();
+ if (num < ruleactions.size()) {
+ ret = ruleactions[num].d_action;
+ }
+ return ret;
+ });
luaCtx.registerFunction("getStats", &DNSAction::getStats);
luaCtx.registerFunction("reload", &DNSAction::reload);
luaCtx.registerFunction("reload", &DNSResponseAction::reload);
luaCtx.writeFunction("LuaAction", [](LuaAction::func_t func) {
- setLuaSideEffect();
- return std::shared_ptr<DNSAction>(new LuaAction(func));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSAction>(new LuaAction(std::move(func)));
+ });
luaCtx.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func) {
- setLuaSideEffect();
- return std::shared_ptr<DNSAction>(new LuaFFIAction(func));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSAction>(new LuaFFIAction(std::move(func)));
+ });
luaCtx.writeFunction("LuaFFIPerThreadAction", [](const std::string& code) {
- setLuaSideEffect();
- return std::shared_ptr<DNSAction>(new LuaFFIPerThreadAction(code));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSAction>(new LuaFFIPerThreadAction(code));
+ });
luaCtx.writeFunction("SetNoRecurseAction", []() {
- return std::shared_ptr<DNSAction>(new SetNoRecurseAction);
- });
+ return std::shared_ptr<DNSAction>(new SetNoRecurseAction);
+ });
luaCtx.writeFunction("SetMacAddrAction", [](int code) {
- return std::shared_ptr<DNSAction>(new SetMacAddrAction(code));
- });
+ return std::shared_ptr<DNSAction>(new SetMacAddrAction(code));
+ });
luaCtx.writeFunction("SetEDNSOptionAction", [](int code, const std::string& data) {
- return std::shared_ptr<DNSAction>(new SetEDNSOptionAction(code, data));
- });
+ return std::shared_ptr<DNSAction>(new SetEDNSOptionAction(code, data));
+ });
- luaCtx.writeFunction("PoolAction", [](const std::string& a, boost::optional<bool> stopProcessing) {
- return std::shared_ptr<DNSAction>(new PoolAction(a, stopProcessing ? *stopProcessing : true));
- });
+ luaCtx.writeFunction("PoolAction", [](const std::string& poolname, boost::optional<bool> stopProcessing) {
+ return std::shared_ptr<DNSAction>(new PoolAction(poolname, stopProcessing ? *stopProcessing : true));
+ });
luaCtx.writeFunction("QPSAction", [](int limit) {
- return std::shared_ptr<DNSAction>(new QPSAction(limit));
- });
+ return std::shared_ptr<DNSAction>(new QPSAction(limit));
+ });
- luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& a, boost::optional<bool> stopProcessing) {
- return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a, stopProcessing ? *stopProcessing : true));
- });
+ luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& poolname, boost::optional<bool> stopProcessing) {
+ return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, poolname, stopProcessing ? *stopProcessing : true));
+ });
luaCtx.writeFunction("SpoofAction", [](LuaTypeOrArrayOf<std::string> inp, boost::optional<responseParams_t> vars) {
- vector<ComboAddress> addrs;
- if(auto s = boost::get<std::string>(&inp)) {
- addrs.push_back(ComboAddress(*s));
- } else {
- const auto& v = boost::get<LuaArray<std::string>>(inp);
- for(const auto& a: v) {
- addrs.push_back(ComboAddress(a.second));
- }
+ vector<ComboAddress> addrs;
+ if (auto* ipaddr = boost::get<std::string>(&inp)) {
+ addrs.emplace_back(*ipaddr);
+ }
+ else {
+ const auto& ipsArray = boost::get<LuaArray<std::string>>(inp);
+ for (const auto& ipAddr : ipsArray) {
+ addrs.emplace_back(ipAddr.second);
}
+ }
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
- auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, sa->d_responseConfig);
- checkAllParametersConsumed("SpoofAction", vars);
- return ret;
- });
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
+ auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
+ parseResponseConfig(vars, spoofaction->getResponseConfig());
+ checkAllParametersConsumed("SpoofAction", vars);
+ return ret;
+ });
luaCtx.writeFunction("SpoofSVCAction", [](const LuaArray<SVCRecordParameters>& parameters, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new SpoofSVCAction(parameters));
- auto sa = std::dynamic_pointer_cast<SpoofSVCAction>(ret);
- parseResponseConfig(vars, sa->d_responseConfig);
- return ret;
- });
+ auto ret = std::shared_ptr<DNSAction>(new SpoofSVCAction(parameters));
+ auto spoofaction = std::dynamic_pointer_cast<SpoofSVCAction>(ret);
+ parseResponseConfig(vars, spoofaction->getResponseConfig());
+ return ret;
+ });
- luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(a)));
- auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, sa->d_responseConfig);
- checkAllParametersConsumed("SpoofCNAMEAction", vars);
- return ret;
- });
+ luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& cname, boost::optional<responseParams_t> vars) {
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(cname)));
+ auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
+ parseResponseConfig(vars, spoofaction->getResponseConfig());
+ checkAllParametersConsumed("SpoofCNAMEAction", vars);
+ return ret;
+ });
luaCtx.writeFunction("SpoofRawAction", [](LuaTypeOrArrayOf<std::string> inp, boost::optional<responseParams_t> vars) {
- vector<string> raws;
- if(auto s = boost::get<std::string>(&inp)) {
- raws.push_back(*s);
- } else {
- const auto& v = boost::get<LuaArray<std::string>>(inp);
- for(const auto& raw: v) {
- raws.push_back(raw.second);
- }
+ vector<string> raws;
+ if (const auto* str = boost::get<std::string>(&inp)) {
+ raws.push_back(*str);
+ }
+ else {
+ const auto& vect = boost::get<LuaArray<std::string>>(inp);
+ for (const auto& raw : vect) {
+ raws.push_back(raw.second);
}
-
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raws));
- auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, sa->d_responseConfig);
- checkAllParametersConsumed("SpoofRawAction", vars);
- return ret;
- });
+ }
+ uint32_t qtypeForAny{0};
+ getOptionalValue<uint32_t>(vars, "typeForAny", qtypeForAny);
+ if (qtypeForAny > std::numeric_limits<uint16_t>::max()) {
+ qtypeForAny = 0;
+ }
+ std::optional<uint16_t> qtypeForAnyParam;
+ if (qtypeForAny > 0) {
+ qtypeForAnyParam = static_cast<uint16_t>(qtypeForAny);
+ }
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raws, qtypeForAnyParam));
+ auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
+ parseResponseConfig(vars, spoofaction->getResponseConfig());
+ checkAllParametersConsumed("SpoofRawAction", vars);
+ return ret;
+ });
luaCtx.writeFunction("SpoofPacketAction", [](const std::string& response, size_t len) {
if (len < sizeof(dnsheader)) {
@@ -2363,58 +2655,62 @@ void setupLuaActions(LuaContext& luaCtx)
}
auto ret = std::shared_ptr<DNSAction>(new SpoofAction(response.c_str(), len));
return ret;
- });
+ });
luaCtx.writeFunction("DropAction", []() {
- return std::shared_ptr<DNSAction>(new DropAction);
- });
+ return std::shared_ptr<DNSAction>(new DropAction);
+ });
luaCtx.writeFunction("AllowAction", []() {
- return std::shared_ptr<DNSAction>(new AllowAction);
- });
+ return std::shared_ptr<DNSAction>(new AllowAction);
+ });
luaCtx.writeFunction("NoneAction", []() {
- return std::shared_ptr<DNSAction>(new NoneAction);
- });
+ return std::shared_ptr<DNSAction>(new NoneAction);
+ });
luaCtx.writeFunction("DelayAction", [](int msec) {
- return std::shared_ptr<DNSAction>(new DelayAction(msec));
- });
+ return std::shared_ptr<DNSAction>(new DelayAction(msec));
+ });
luaCtx.writeFunction("TCAction", []() {
- return std::shared_ptr<DNSAction>(new TCAction);
- });
+ return std::shared_ptr<DNSAction>(new TCAction);
+ });
+
+ luaCtx.writeFunction("TCResponseAction", []() {
+ return std::shared_ptr<DNSResponseAction>(new TCResponseAction);
+ });
luaCtx.writeFunction("SetDisableValidationAction", []() {
- return std::shared_ptr<DNSAction>(new SetDisableValidationAction);
- });
+ return std::shared_ptr<DNSAction>(new SetDisableValidationAction);
+ });
luaCtx.writeFunction("LogAction", [](boost::optional<std::string> fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
- return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
- });
+ return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
+ });
luaCtx.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
- return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
- });
+ return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
+ });
luaCtx.writeFunction("LimitTTLResponseAction", [](uint32_t min, uint32_t max, boost::optional<LuaArray<uint16_t>> types) {
- std::unordered_set<QType> capTypes;
- if (types) {
- capTypes.reserve(types->size());
- for (const auto& [idx, type] : *types) {
- capTypes.insert(QType(type));
- }
+ std::unordered_set<QType> capTypes;
+ if (types) {
+ capTypes.reserve(types->size());
+ for (const auto& [idx, type] : *types) {
+ capTypes.insert(QType(type));
}
- return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min, max, capTypes));
- });
+ }
+ return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min, max, capTypes));
+ });
luaCtx.writeFunction("SetMinTTLResponseAction", [](uint32_t min) {
- return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min));
- });
+ return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min));
+ });
luaCtx.writeFunction("SetMaxTTLResponseAction", [](uint32_t max) {
- return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(0, max));
- });
+ return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(0, max));
+ });
luaCtx.writeFunction("SetMaxReturnedTTLAction", [](uint32_t max) {
return std::shared_ptr<DNSAction>(new MaxReturnedTTLAction(max));
@@ -2425,257 +2721,272 @@ void setupLuaActions(LuaContext& luaCtx)
});
luaCtx.writeFunction("SetReducedTTLResponseAction", [](uint8_t percentage) {
- if (percentage > 100) {
- throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100."));
- }
- return std::shared_ptr<DNSResponseAction>(new SetReducedTTLResponseAction(percentage));
- });
+ if (percentage > 100) {
+ throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100."));
+ }
+ return std::shared_ptr<DNSResponseAction>(new SetReducedTTLResponseAction(percentage));
+ });
luaCtx.writeFunction("ClearRecordTypesResponseAction", [](LuaTypeOrArrayOf<int> types) {
- std::unordered_set<QType> qtypes{};
- if (types.type() == typeid(int)) {
- qtypes.insert(boost::get<int>(types));
- } else if (types.type() == typeid(LuaArray<int>)) {
- const auto& v = boost::get<LuaArray<int>>(types);
- for (const auto& tpair: v) {
- qtypes.insert(tpair.second);
- }
+ std::unordered_set<QType> qtypes{};
+ if (types.type() == typeid(int)) {
+ qtypes.insert(boost::get<int>(types));
+ }
+ else if (types.type() == typeid(LuaArray<int>)) {
+ const auto& typesArray = boost::get<LuaArray<int>>(types);
+ for (const auto& tpair : typesArray) {
+ qtypes.insert(tpair.second);
}
- return std::shared_ptr<DNSResponseAction>(new ClearRecordTypesResponseAction(qtypes));
- });
+ }
+ return std::shared_ptr<DNSResponseAction>(new ClearRecordTypesResponseAction(std::move(qtypes)));
+ });
luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
- auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
- parseResponseConfig(vars, rca->d_responseConfig);
- checkAllParametersConsumed("RCodeAction", vars);
- return ret;
- });
+ auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
+ auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
+ parseResponseConfig(vars, rca->getResponseConfig());
+ checkAllParametersConsumed("RCodeAction", vars);
+ return ret;
+ });
luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
- auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
- parseResponseConfig(vars, erca->d_responseConfig);
- checkAllParametersConsumed("ERCodeAction", vars);
- return ret;
- });
+ auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
+ auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
+ parseResponseConfig(vars, erca->getResponseConfig());
+ checkAllParametersConsumed("ERCodeAction", vars);
+ return ret;
+ });
luaCtx.writeFunction("SetSkipCacheAction", []() {
- return std::shared_ptr<DNSAction>(new SetSkipCacheAction);
- });
+ return std::shared_ptr<DNSAction>(new SetSkipCacheAction);
+ });
luaCtx.writeFunction("SetSkipCacheResponseAction", []() {
- return std::shared_ptr<DNSResponseAction>(new SetSkipCacheResponseAction);
- });
+ return std::shared_ptr<DNSResponseAction>(new SetSkipCacheResponseAction);
+ });
luaCtx.writeFunction("SetTempFailureCacheTTLAction", [](int maxTTL) {
- return std::shared_ptr<DNSAction>(new SetTempFailureCacheTTLAction(maxTTL));
- });
+ return std::shared_ptr<DNSAction>(new SetTempFailureCacheTTLAction(maxTTL));
+ });
luaCtx.writeFunction("DropResponseAction", []() {
- return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
- });
+ return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
+ });
luaCtx.writeFunction("AllowResponseAction", []() {
- return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
- });
+ return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
+ });
luaCtx.writeFunction("DelayResponseAction", [](int msec) {
- return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
- });
+ return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
+ });
luaCtx.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
- setLuaSideEffect();
- return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(std::move(func)));
+ });
luaCtx.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func) {
- setLuaSideEffect();
- return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(func));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSResponseAction>(new LuaFFIResponseAction(std::move(func)));
+ });
luaCtx.writeFunction("LuaFFIPerThreadResponseAction", [](const std::string& code) {
- setLuaSideEffect();
- return std::shared_ptr<DNSResponseAction>(new LuaFFIPerThreadResponseAction(code));
- });
+ setLuaSideEffect();
+ return std::shared_ptr<DNSResponseAction>(new LuaFFIPerThreadResponseAction(code));
+ });
#ifndef DISABLE_PROTOBUF
- luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
- if (logger) {
- // avoids potentially-evaluated-expression warning with clang.
- RemoteLoggerInterface& rl = *logger.get();
- if (typeid(rl) != typeid(RemoteLogger)) {
- // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
- throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
- }
+ luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)>> alterFunc, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
+ if (logger) {
+ // avoids potentially-evaluated-expression warning with clang.
+ RemoteLoggerInterface& remoteLoggerRef = *logger;
+ if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) {
+ // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
+ throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
}
+ }
- std::string serverID;
- std::string ipEncryptKey;
- std::string tags;
- getOptionalValue<std::string>(vars, "serverID", serverID);
- getOptionalValue<std::string>(vars, "ipEncryptKey", ipEncryptKey);
- getOptionalValue<std::string>(vars, "exportTags", tags);
-
- std::vector<std::pair<std::string, ProtoBufMetaKey>> metaOptions;
- if (metas) {
- for (const auto& [key, value] : *metas) {
- metaOptions.push_back({key, ProtoBufMetaKey(value)});
- }
+ std::string tags;
+ RemoteLogActionConfiguration config;
+ config.logger = std::move(logger);
+ config.alterQueryFunc = std::move(alterFunc);
+ getOptionalValue<std::string>(vars, "serverID", config.serverID);
+ getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey);
+ getOptionalValue<std::string>(vars, "exportTags", tags);
+
+ if (metas) {
+ for (const auto& [key, value] : *metas) {
+ config.metas.emplace_back(key, ProtoBufMetaKey(value));
}
+ }
- std::optional<std::unordered_set<std::string>> tagsToExport{std::nullopt};
- if (!tags.empty()) {
- tagsToExport = std::unordered_set<std::string>();
- if (tags != "*") {
- std::vector<std::string> tokens;
- stringtok(tokens, tags, ",");
- for (auto& token : tokens) {
- tagsToExport->insert(std::move(token));
- }
+ if (!tags.empty()) {
+ config.tagsToExport = std::unordered_set<std::string>();
+ if (tags != "*") {
+ std::vector<std::string> tokens;
+ stringtok(tokens, tags, ",");
+ for (auto& token : tokens) {
+ config.tagsToExport->insert(std::move(token));
}
}
+ }
- checkAllParametersConsumed("RemoteLogAction", vars);
+ checkAllParametersConsumed("RemoteLogAction", vars);
- return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey, std::move(metaOptions), std::move(tagsToExport)));
- });
+ return std::shared_ptr<DNSAction>(new RemoteLogAction(config));
+ });
- luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
- if (logger) {
- // avoids potentially-evaluated-expression warning with clang.
- RemoteLoggerInterface& rl = *logger.get();
- if (typeid(rl) != typeid(RemoteLogger)) {
- // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
- throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
- }
+ luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)>> alterFunc, boost::optional<bool> includeCNAME, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
+ if (logger) {
+ // avoids potentially-evaluated-expression warning with clang.
+ RemoteLoggerInterface& remoteLoggerRef = *logger;
+ if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) {
+ // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
+ throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
}
+ }
- std::string serverID;
- std::string ipEncryptKey;
- std::string tags;
- getOptionalValue<std::string>(vars, "serverID", serverID);
- getOptionalValue<std::string>(vars, "ipEncryptKey", ipEncryptKey);
- getOptionalValue<std::string>(vars, "exportTags", tags);
-
- std::vector<std::pair<std::string, ProtoBufMetaKey>> metaOptions;
- if (metas) {
- for (const auto& [key, value] : *metas) {
- metaOptions.push_back({key, ProtoBufMetaKey(value)});
- }
+ std::string tags;
+ RemoteLogActionConfiguration config;
+ config.logger = std::move(logger);
+ config.alterResponseFunc = std::move(alterFunc);
+ config.includeCNAME = includeCNAME ? *includeCNAME : false;
+ getOptionalValue<std::string>(vars, "serverID", config.serverID);
+ getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey);
+ getOptionalValue<std::string>(vars, "exportTags", tags);
+ getOptionalValue<std::string>(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta);
+
+ if (metas) {
+ for (const auto& [key, value] : *metas) {
+ config.metas.emplace_back(key, ProtoBufMetaKey(value));
}
+ }
- std::optional<std::unordered_set<std::string>> tagsToExport{std::nullopt};
- if (!tags.empty()) {
- tagsToExport = std::unordered_set<std::string>();
- if (tags != "*") {
- std::vector<std::string> tokens;
- stringtok(tokens, tags, ",");
- for (auto& token : tokens) {
- tagsToExport->insert(std::move(token));
- }
+ if (!tags.empty()) {
+ config.tagsToExport = std::unordered_set<std::string>();
+ if (tags != "*") {
+ std::vector<std::string> tokens;
+ stringtok(tokens, tags, ",");
+ for (auto& token : tokens) {
+ config.tagsToExport->insert(std::move(token));
}
}
+ }
- checkAllParametersConsumed("RemoteLogResponseAction", vars);
+ checkAllParametersConsumed("RemoteLogResponseAction", vars);
- return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false, std::move(metaOptions), std::move(tagsToExport)));
- });
+ return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(config));
+ });
- luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
- return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
- });
+ luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)>> alterFunc) {
+ return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, std::move(alterFunc)));
+ });
- luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
- return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
- });
+ luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)>> alterFunc) {
+ return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, std::move(alterFunc)));
+ });
#endif /* DISABLE_PROTOBUF */
- luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS, boost::optional<std::string> local) {
- boost::optional<ComboAddress> localAddr{boost::none};
- if (local) {
- localAddr = ComboAddress(*local, 0);
- }
+ luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS, boost::optional<std::string> local, boost::optional<bool> addProxyProtocol) {
+ boost::optional<ComboAddress> localAddr{boost::none};
+ if (local) {
+ localAddr = ComboAddress(*local, 0);
+ }
- return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), localAddr, addECS ? *addECS : false));
- });
+ return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), localAddr, addECS ? *addECS : false, addProxyProtocol ? *addProxyProtocol : false));
+ });
luaCtx.writeFunction("SetECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
- return std::shared_ptr<DNSAction>(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
- });
+ return std::shared_ptr<DNSAction>(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
+ });
luaCtx.writeFunction("SetECSOverrideAction", [](bool ecsOverride) {
- return std::shared_ptr<DNSAction>(new SetECSOverrideAction(ecsOverride));
- });
+ return std::shared_ptr<DNSAction>(new SetECSOverrideAction(ecsOverride));
+ });
luaCtx.writeFunction("SetDisableECSAction", []() {
- return std::shared_ptr<DNSAction>(new SetDisableECSAction());
- });
+ return std::shared_ptr<DNSAction>(new SetDisableECSAction());
+ });
- luaCtx.writeFunction("SetECSAction", [](const std::string& v4, boost::optional<std::string> v6) {
- if (v6) {
- return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
- }
- return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
- });
+ luaCtx.writeFunction("SetECSAction", [](const std::string& v4Netmask, boost::optional<std::string> v6Netmask) {
+ if (v6Netmask) {
+ return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4Netmask), Netmask(*v6Netmask)));
+ }
+ return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4Netmask)));
+ });
#ifdef HAVE_NET_SNMP
luaCtx.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
- return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
- });
+ return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
+ });
luaCtx.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
- return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
- });
+ return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
+ });
#endif /* HAVE_NET_SNMP */
luaCtx.writeFunction("SetTagAction", [](const std::string& tag, const std::string& value) {
- return std::shared_ptr<DNSAction>(new SetTagAction(tag, value));
- });
+ return std::shared_ptr<DNSAction>(new SetTagAction(tag, value));
+ });
luaCtx.writeFunction("SetTagResponseAction", [](const std::string& tag, const std::string& value) {
- return std::shared_ptr<DNSResponseAction>(new SetTagResponseAction(tag, value));
- });
+ return std::shared_ptr<DNSResponseAction>(new SetTagResponseAction(tag, value));
+ });
luaCtx.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
- return std::shared_ptr<DNSAction>(new ContinueAction(action));
- });
+ return std::shared_ptr<DNSAction>(new ContinueAction(action));
+ });
#ifdef HAVE_DNS_OVER_HTTPS
luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : ""));
- auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
- parseResponseConfig(vars, hsa->d_responseConfig);
- checkAllParametersConsumed("HTTPStatusAction", vars);
- return ret;
- });
+ auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : ""));
+ auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
+ parseResponseConfig(vars, hsa->getResponseConfig());
+ checkAllParametersConsumed("HTTPStatusAction", vars);
+ return ret;
+ });
#endif /* HAVE_DNS_OVER_HTTPS */
#if defined(HAVE_LMDB) || defined(HAVE_CDB)
luaCtx.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
- return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
- });
+ return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
+ });
luaCtx.writeFunction("KeyValueStoreRangeLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
- return std::shared_ptr<DNSAction>(new KeyValueStoreRangeLookupAction(kvs, lookupKey, destinationTag));
- });
+ return std::shared_ptr<DNSAction>(new KeyValueStoreRangeLookupAction(kvs, lookupKey, destinationTag));
+ });
#endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */
luaCtx.writeFunction("NegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, boost::optional<responseParams_t> vars) {
- bool soaInAuthoritySection = false;
- getOptionalValue<bool>(vars, "soaInAuthoritySection", soaInAuthoritySection);
- auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, soaInAuthoritySection));
- auto action = std::dynamic_pointer_cast<NegativeAndSOAAction>(ret);
- parseResponseConfig(vars, action->d_responseConfig);
- checkAllParametersConsumed("NegativeAndSOAAction", vars);
- return ret;
+ bool soaInAuthoritySection = false;
+ getOptionalValue<bool>(vars, "soaInAuthoritySection", soaInAuthoritySection);
+ NegativeAndSOAAction::SOAParams params{
+ .serial = serial,
+ .refresh = refresh,
+ .retry = retry,
+ .expire = expire,
+ .minimum = minimum};
+ auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), params, soaInAuthoritySection));
+ auto action = std::dynamic_pointer_cast<NegativeAndSOAAction>(ret);
+ parseResponseConfig(vars, action->getResponseConfig());
+ checkAllParametersConsumed("NegativeAndSOAAction", vars);
+ return ret;
});
luaCtx.writeFunction("SetProxyProtocolValuesAction", [](const std::vector<std::pair<uint8_t, std::string>>& values) {
- return std::shared_ptr<DNSAction>(new SetProxyProtocolValuesAction(values));
- });
+ return std::shared_ptr<DNSAction>(new SetProxyProtocolValuesAction(values));
+ });
luaCtx.writeFunction("SetAdditionalProxyProtocolValueAction", [](uint8_t type, const std::string& value) {
return std::shared_ptr<DNSAction>(new SetAdditionalProxyProtocolValueAction(type, value));
});
+
+ luaCtx.writeFunction("SetExtendedDNSErrorAction", [](uint16_t infoCode, boost::optional<std::string> extraText) {
+ return std::shared_ptr<DNSAction>(new SetExtendedDNSErrorAction(infoCode, extraText ? *extraText : ""));
+ });
+
+ luaCtx.writeFunction("SetExtendedDNSErrorResponseAction", [](uint16_t infoCode, boost::optional<std::string> extraText) {
+ return std::shared_ptr<DNSResponseAction>(new SetExtendedDNSErrorResponseAction(infoCode, extraText ? *extraText : ""));
+ });
}
diff --git a/dnsdist-lua-bindings-dnscrypt.cc b/dnsdist-lua-bindings-dnscrypt.cc
index 72936ca..114eead 100644
--- a/dnsdist-lua-bindings-dnscrypt.cc
+++ b/dnsdist-lua-bindings-dnscrypt.cc
@@ -102,7 +102,7 @@ void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client)
ret << (fmt % "#" % "Serial" % "Version" % "From" % "To" ) << endl;
for (const auto& pair : ctx->getCertificates()) {
- const auto cert = pair->cert;
+ const auto& cert = pair->cert;
const DNSCryptExchangeVersion version = DNSCryptContext::getExchangeVersion(cert);
ret << (fmt % idx % cert.getSerial() % (version == DNSCryptExchangeVersion::VERSION1 ? 1 : 2) % DNSCryptContext::certificateDateToStr(cert.getTSStart()) % DNSCryptContext::certificateDateToStr(cert.getTSEnd())) << endl;
@@ -121,9 +121,9 @@ void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client)
ctx.addNewCertificate(cert, privateKey);
}
}
- catch(const std::exception& e) {
- errlog(e.what());
- g_outputBuffer="Error: "+string(e.what())+"\n";
+ catch (const std::exception& e) {
+ errlog("Error generating a DNSCrypt certificate: %s", e.what());
+ g_outputBuffer = "Error generating a DNSCrypt certificate: " + string(e.what()) + "\n";
}
});
@@ -167,8 +167,8 @@ void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client)
}
}
catch (const std::exception& e) {
- errlog(e.what());
- g_outputBuffer = "Error: " + string(e.what()) + "\n";
+ errlog("Error generating a DNSCrypt certificate: %s", e.what());
+ g_outputBuffer = "Error generating a DNSCrypt certificate: " + string(e.what()) + "\n";
}
});
@@ -195,8 +195,8 @@ void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client)
g_outputBuffer = "Provider fingerprint is: " + DNSCryptContext::getProviderFingerprint(publicKey) + "\n";
}
catch (const std::exception& e) {
- errlog(e.what());
- g_outputBuffer = "Error: " + string(e.what()) + "\n";
+ errlog("Error generating a DNSCrypt provider key: %s", e.what());
+ g_outputBuffer = "Error generating a DNSCrypt provider key: " + string(e.what()) + "\n";
}
sodium_memzero(privateKey, sizeof(privateKey));
@@ -219,8 +219,8 @@ void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client)
g_outputBuffer = "Provider fingerprint is: " + DNSCryptContext::getProviderFingerprint(publicKey) + "\n";
}
catch (const std::exception& e) {
- errlog(e.what());
- g_outputBuffer = "Error: " + string(e.what()) + "\n";
+ errlog("Error getting a DNSCrypt provider fingerprint: %s", e.what());
+ g_outputBuffer = "Error getting a DNSCrypt provider fingerprint: " + string(e.what()) + "\n";
}
});
#endif
diff --git a/dnsdist-lua-bindings-dnsparser.cc b/dnsdist-lua-bindings-dnsparser.cc
index 606220e..9605314 100644
--- a/dnsdist-lua-bindings-dnsparser.cc
+++ b/dnsdist-lua-bindings-dnsparser.cc
@@ -31,7 +31,7 @@ void setupLuaBindingsDNSParser(LuaContext& luaCtx)
return dpo;
});
- luaCtx.registerMember<DNSName(dnsdist::DNSPacketOverlay::*)>(std::string("qname"), [](const dnsdist::DNSPacketOverlay& overlay) { return overlay.d_qname; });
+ luaCtx.registerMember<DNSName(dnsdist::DNSPacketOverlay::*)>(std::string("qname"), [](const dnsdist::DNSPacketOverlay& overlay) -> const DNSName& { return overlay.d_qname; });
luaCtx.registerMember<uint16_t(dnsdist::DNSPacketOverlay::*)>(std::string("qtype"), [](const dnsdist::DNSPacketOverlay& overlay) { return overlay.d_qtype; });
luaCtx.registerMember<uint16_t(dnsdist::DNSPacketOverlay::*)>(std::string("qclass"), [](const dnsdist::DNSPacketOverlay& overlay) { return overlay.d_qclass; });
luaCtx.registerMember<dnsheader(dnsdist::DNSPacketOverlay::*)>(std::string("dh"), [](const dnsdist::DNSPacketOverlay& overlay) { return overlay.d_header; });
diff --git a/dnsdist-lua-bindings-dnsquestion.cc b/dnsdist-lua-bindings-dnsquestion.cc
index 9d5da2c..4512fc5 100644
--- a/dnsdist-lua-bindings-dnsquestion.cc
+++ b/dnsdist-lua-bindings-dnsquestion.cc
@@ -27,6 +27,7 @@
#include "dnsdist-lua.hh"
#include "dnsparser.hh"
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
{
#ifndef DISABLE_NON_FFI_DQ_BINDINGS
@@ -36,10 +37,20 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
luaCtx.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return dq.ids.qname; }, [](DNSQuestion& dq, const DNSName& newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.ids.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.ids.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.getHeader()->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return static_cast<int>(dq.getHeader()->rcode); }, [](DNSQuestion& dq, int newRCode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [newRCode](dnsheader& header) {
+ header.rcode = static_cast<decltype(header.rcode)>(newRCode);
+ return true;
+ });
+ });
luaCtx.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return dq.ids.origRemote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
/* DNSDist DNSQuestion */
- luaCtx.registerMember<dnsheader* (DNSQuestion::*)>("dh", [](const DNSQuestion& dq) -> dnsheader* { return const_cast<DNSQuestion&>(dq).getHeader(); }, [](DNSQuestion& dq, const dnsheader* dh) { *(dq.getHeader()) = *dh; });
+ luaCtx.registerMember<dnsheader* (DNSQuestion::*)>("dh", [](const DNSQuestion& dq) -> dnsheader* { return dq.getMutableHeader(); }, [](DNSQuestion& dq, const dnsheader* dh) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [&dh](dnsheader& header) {
+ header = *dh;
+ return true;
+ });
+ });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.getData().size(); }, [](DNSQuestion& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
luaCtx.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
luaCtx.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.overTCP(); }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
@@ -90,7 +101,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
dq.ids.d_protoBufData->d_requestorID = newValue;
});
luaCtx.registerFunction<bool(DNSQuestion::*)()const>("getDO", [](const DNSQuestion& dq) {
- return getEDNSZ(dq) & EDNS_HEADER_FLAG_DO;
+ return getEDNSZ(dq) & EDNS_HEADER_FLAG_DO;
});
luaCtx.registerFunction<std::string(DNSQuestion::*)()const>("getContent", [](const DNSQuestion& dq) {
return std::string(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size());
@@ -100,7 +111,11 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
auto& buffer = dq.getMutableData();
buffer.clear();
buffer.insert(buffer.begin(), raw.begin(), raw.end());
- reinterpret_cast<dnsheader*>(buffer.data())->id = oldID;
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
});
luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSQuestion::*)()const>("getEDNSOptions", [](const DNSQuestion& dq) {
if (dq.ednsOptions == nullptr) {
@@ -187,7 +202,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
dq.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
}
- dq.proxyProtocolValues->push_back({value, static_cast<uint8_t>(type)});
+ dq.proxyProtocolValues->push_back({std::move(value), static_cast<uint8_t>(type)});
});
luaCtx.registerFunction<LuaArray<std::string>(DNSQuestion::*)()>("getProxyProtocolValues", [](const DNSQuestion& dq) {
@@ -212,7 +227,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
return true;
});
- luaCtx.registerFunction<void(DNSQuestion::*)(const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>& response)>("spoof", [](DNSQuestion& dq, const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>& response) {
+ luaCtx.registerFunction<void(DNSQuestion::*)(const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>&, boost::optional<uint16_t>)>("spoof", [](DNSQuestion& dnsQuestion, const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>& response, boost::optional<uint16_t> typeForAny) {
if (response.type() == typeid(LuaArray<ComboAddress>)) {
std::vector<ComboAddress> data;
auto responses = boost::get<LuaArray<ComboAddress>>(response);
@@ -221,8 +236,8 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
data.push_back(resp.second);
}
std::string result;
- SpoofAction sa(data);
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(data);
+ tempSpoofAction(&dnsQuestion, &result);
return;
}
if (response.type() == typeid(LuaArray<std::string>)) {
@@ -233,8 +248,8 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
data.push_back(resp.second);
}
std::string result;
- SpoofAction sa(data);
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(data, typeForAny ? *typeForAny : std::optional<uint16_t>());
+ tempSpoofAction(&dnsQuestion, &result);
return;
}
});
@@ -243,6 +258,15 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
setEDNSOption(dq, code, data);
});
+ luaCtx.registerFunction<void(DNSQuestion::*)(uint16_t infoCode, const boost::optional<std::string>& extraText)>("setExtendedDNSError", [](DNSQuestion& dnsQuestion, uint16_t infoCode, const boost::optional<std::string>& extraText) {
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText) {
+ ede.extraText = *extraText;
+ }
+ dnsQuestion.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ });
+
luaCtx.registerFunction<bool(DNSQuestion::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSQuestion& dq, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
dq.asynchronous = true;
return dnsdist::suspendQuery(dq, asyncID, queryID, timeoutMs);
@@ -284,7 +308,7 @@ public:
struct timeval now;
gettimeofday(&now, nullptr);
- sender->notifyIOError(std::move(object->query.d_idstate), now);
+ sender->notifyIOError(now, TCPResponse(std::move(object->query)));
return true;
}
@@ -333,9 +357,19 @@ private:
luaCtx.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return dq.ids.qname; }, [](DNSResponse& dq, const DNSName& newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.ids.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.ids.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.getHeader()->rcode; }, [](DNSResponse& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return static_cast<int>(dq.getHeader()->rcode); }, [](DNSResponse& dq, int newRCode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [newRCode](dnsheader& header) {
+ header.rcode = static_cast<decltype(header.rcode)>(newRCode);
+ return true;
+ });
+ });
luaCtx.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return dq.ids.origRemote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; });
- luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return const_cast<DNSResponse&>(dr).getHeader(); }, [](DNSResponse& dr, const dnsheader* dh) { *(dr.getHeader()) = *dh; });
+ luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return dr.getMutableHeader(); }, [](DNSResponse& dr, const dnsheader* dh) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [&dh](dnsheader& header) {
+ header = *dh;
+ return true;
+ });
+ });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.getData().size(); }, [](DNSResponse& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
luaCtx.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
luaCtx.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.overTCP(); }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; });
@@ -355,7 +389,10 @@ private:
auto& buffer = dr.getMutableData();
buffer.clear();
buffer.insert(buffer.begin(), raw.begin(), raw.end());
- reinterpret_cast<dnsheader*>(buffer.data())->id = oldID;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
});
luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView>(DNSResponse::*)()const>("getEDNSOptions", [](const DNSResponse& dq) {
@@ -478,6 +515,15 @@ private:
return setNegativeAndAdditionalSOA(dq, nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, false);
});
+ luaCtx.registerFunction<void(DNSResponse::*)(uint16_t infoCode, const boost::optional<std::string>& extraText)>("setExtendedDNSError", [](DNSResponse& dnsResponse, uint16_t infoCode, const boost::optional<std::string>& extraText) {
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText) {
+ ede.extraText = *extraText;
+ }
+ dnsResponse.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ });
+
luaCtx.registerFunction<bool(DNSResponse::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSResponse& dr, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
dr.asynchronous = true;
return dnsdist::suspendResponse(dr, asyncID, queryID, timeoutMs);
@@ -500,5 +546,9 @@ private:
auto query = dnsdist::getInternalQueryFromDQ(dr, false);
return dnsdist::queueQueryResumptionEvent(std::move(query));
});
+
+ luaCtx.registerFunction<std::shared_ptr<DownstreamState>(DNSResponse::*)(void)const>("getSelectedBackend", [](const DNSResponse& dr) {
+ return dr.d_downstream;
+ });
#endif /* DISABLE_NON_FFI_DQ_BINDINGS */
}
diff --git a/dnsdist-lua-bindings-network.cc b/dnsdist-lua-bindings-network.cc
index 62dce3b..75d8447 100644
--- a/dnsdist-lua-bindings-network.cc
+++ b/dnsdist-lua-bindings-network.cc
@@ -67,7 +67,7 @@ void setupLuaBindingsNetwork(LuaContext& luaCtx, bool client)
return false;
}
- return listener->addUnixListeningEndpoint(path, endpointID, [cb](dnsdist::NetworkListener::EndpointID endpoint, std::string&& dgram, const std::string& from) {
+ return listener->addUnixListeningEndpoint(path, endpointID, [cb = std::move(cb)](dnsdist::NetworkListener::EndpointID endpoint, std::string&& dgram, const std::string& from) {
{
auto lock = g_lua.lock();
cb(endpoint, dgram, from);
diff --git a/dnsdist-lua-bindings-packetcache.cc b/dnsdist-lua-bindings-packetcache.cc
index fd62eb5..f71bf37 100644
--- a/dnsdist-lua-bindings-packetcache.cc
+++ b/dnsdist-lua-bindings-packetcache.cc
@@ -41,6 +41,7 @@ void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client)
size_t maxNegativeTTL = 3600;
size_t staleTTL = 60;
size_t numberOfShards = 20;
+ size_t maxEntrySize{0};
bool dontAge = false;
bool deferrableInsertLock = true;
bool ecsParsing = false;
@@ -59,6 +60,7 @@ void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client)
getOptionalValue<size_t>(vars, "staleTTL", staleTTL);
getOptionalValue<size_t>(vars, "temporaryFailureTTL", tempFailTTL);
getOptionalValue<bool>(vars, "cookieHashing", cookieHashing);
+ getOptionalValue<size_t>(vars, "maximumEntrySize", maxEntrySize);
if (getOptionalValue<decltype(skipOptions)>(vars, "skipOptions", skipOptions) > 0) {
for (const auto& option : skipOptions) {
@@ -87,6 +89,9 @@ void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client)
res->setKeepStaleData(keepStaleData);
res->setSkippedOptions(optionsToSkip);
+ if (maxEntrySize >= sizeof(dnsheader)) {
+ res->setMaximumEntrySize(maxEntrySize);
+ }
return res;
});
diff --git a/dnsdist-lua-bindings-rings.cc b/dnsdist-lua-bindings-rings.cc
index 4bf83a5..059bce7 100644
--- a/dnsdist-lua-bindings-rings.cc
+++ b/dnsdist-lua-bindings-rings.cc
@@ -85,15 +85,15 @@ void setupLuaBindingsRings(LuaContext& luaCtx, bool client)
return results;
});
- luaCtx.registerMember<DNSName(LuaRingEntry::*)>(std::string("qname"), [](const LuaRingEntry& entry) {
+ luaCtx.registerMember<DNSName(LuaRingEntry::*)>(std::string("qname"), [](const LuaRingEntry& entry) -> const DNSName& {
return entry.qname;
});
- luaCtx.registerMember<ComboAddress(LuaRingEntry::*)>(std::string("requestor"), [](const LuaRingEntry& entry) {
+ luaCtx.registerMember<ComboAddress(LuaRingEntry::*)>(std::string("requestor"), [](const LuaRingEntry& entry) -> const ComboAddress& {
return entry.requestor;
});
- luaCtx.registerMember<ComboAddress(LuaRingEntry::*)>(std::string("backend"), [](const LuaRingEntry& entry) {
+ luaCtx.registerMember<ComboAddress(LuaRingEntry::*)>(std::string("backend"), [](const LuaRingEntry& entry) -> const ComboAddress& {
return entry.ds;
});
@@ -101,7 +101,7 @@ void setupLuaBindingsRings(LuaContext& luaCtx, bool client)
return entry.when;
});
- luaCtx.registerMember<std::string(LuaRingEntry::*)>(std::string("macAddress"), [](const LuaRingEntry& entry) {
+ luaCtx.registerMember<std::string(LuaRingEntry::*)>(std::string("macAddress"), [](const LuaRingEntry& entry) -> const std::string& {
return entry.macAddr;
});
diff --git a/dnsdist-lua-bindings.cc b/dnsdist-lua-bindings.cc
index ef5f29f..3f5d6e2 100644
--- a/dnsdist-lua-bindings.cc
+++ b/dnsdist-lua-bindings.cc
@@ -22,12 +22,17 @@
#include "bpf-filter.hh"
#include "config.h"
#include "dnsdist.hh"
+#include "dnsdist-async.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-resolver.hh"
#include "dnsdist-svc.hh"
+#include "dnsdist-xsk.hh"
#include "dolog.hh"
+#include "xsk.hh"
-void setupLuaBindings(LuaContext& luaCtx, bool client)
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
+void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
{
luaCtx.writeFunction("vinfolog", [](const string& arg) {
vinfolog("%s", arg);
@@ -47,7 +52,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
});
/* Exceptions */
- luaCtx.registerFunction<string(std::exception_ptr::*)()const>("__tostring", [](const std::exception_ptr& eptr) {
+ luaCtx.registerFunction<string(std::exception_ptr::*)()const>("__tostring", [](const std::exception_ptr& eptr) -> std::string {
try {
if (eptr) {
std::rethrow_exception(eptr);
@@ -73,16 +78,16 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
luaCtx.registerFunction("toString", &ServerPolicy::toString);
luaCtx.registerFunction("__tostring", &ServerPolicy::toString);
- ServerPolicy policies[] = {
- ServerPolicy{"firstAvailable", firstAvailable, false},
- ServerPolicy{"roundrobin", roundrobin, false},
- ServerPolicy{"wrandom", wrandom, false},
- ServerPolicy{"whashed", whashed, false},
- ServerPolicy{"chashed", chashed, false},
- ServerPolicy{"leastOutstanding", leastOutstanding, false}
+ const std::array<std::shared_ptr<ServerPolicy>, 6> policies = {
+ std::make_shared<ServerPolicy>("firstAvailable", firstAvailable, false),
+ std::make_shared<ServerPolicy>("roundrobin", roundrobin, false),
+ std::make_shared<ServerPolicy>("wrandom", wrandom, false),
+ std::make_shared<ServerPolicy>("whashed", whashed, false),
+ std::make_shared<ServerPolicy>("chashed", chashed, false),
+ std::make_shared<ServerPolicy>("leastOutstanding", leastOutstanding, false)
};
- for (auto& policy : policies) {
- luaCtx.writeVariable(policy.d_name, policy);
+ for (const auto& policy : policies) {
+ luaCtx.writeVariable(policy->d_name, policy);
}
#endif /* DISABLE_POLICIES_BINDINGS */
@@ -90,7 +95,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
/* ServerPool */
luaCtx.registerFunction<void(std::shared_ptr<ServerPool>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](std::shared_ptr<ServerPool> pool, std::shared_ptr<DNSDistPacketCache> cache) {
if (pool) {
- pool->packetCache = cache;
+ pool->packetCache = std::move(cache);
}
});
luaCtx.registerFunction("getCache", &ServerPool::getCache);
@@ -104,50 +109,50 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
#ifndef DISABLE_DOWNSTREAM_BINDINGS
/* DownstreamState */
- luaCtx.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& s, int lim) { s.qps = lim ? QPSLimiter(lim, lim) : QPSLimiter(); });
- luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](std::shared_ptr<DownstreamState> s, string pool) {
+ luaCtx.registerFunction<void(DownstreamState::*)(int)>("setQPS", [](DownstreamState& state, int lim) { state.qps = lim > 0 ? QPSLimiter(lim, lim) : QPSLimiter(); });
+ luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
auto localPools = g_pools.getCopy();
- addServerToPool(localPools, pool, s);
+ addServerToPool(localPools, pool, state);
g_pools.setState(localPools);
- s->d_config.pools.insert(pool);
+ state->d_config.pools.insert(pool);
});
- luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](std::shared_ptr<DownstreamState> s, string pool) {
+ luaCtx.registerFunction<void(std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
auto localPools = g_pools.getCopy();
- removeServerFromPool(localPools, pool, s);
+ removeServerFromPool(localPools, pool, state);
g_pools.setState(localPools);
- s->d_config.pools.erase(pool);
+ state->d_config.pools.erase(pool);
});
- luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getOutstanding", [](const DownstreamState& s) { return s.outstanding.load(); });
- luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getDrops", [](const DownstreamState& s) { return s.reuseds.load(); });
- luaCtx.registerFunction<double(DownstreamState::*)()const>("getLatency", [](const DownstreamState& s) { return s.getRelevantLatencyUsec(); });
+ luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getOutstanding", [](const DownstreamState& state) { return state.outstanding.load(); });
+ luaCtx.registerFunction<uint64_t(DownstreamState::*)()const>("getDrops", [](const DownstreamState& state) { return state.reuseds.load(); });
+ luaCtx.registerFunction<double(DownstreamState::*)()const>("getLatency", [](const DownstreamState& state) { return state.getRelevantLatencyUsec(); });
luaCtx.registerFunction("isUp", &DownstreamState::isUp);
luaCtx.registerFunction("setDown", &DownstreamState::setDown);
luaCtx.registerFunction("setUp", &DownstreamState::setUp);
- luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& s, boost::optional<bool> newStatus) {
+ luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setAuto", [](DownstreamState& state, boost::optional<bool> newStatus) {
if (newStatus) {
- s.setUpStatus(*newStatus);
+ state.setUpStatus(*newStatus);
}
- s.setAuto();
+ state.setAuto();
});
- luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setLazyAuto", [](DownstreamState& s, boost::optional<bool> newStatus) {
+ luaCtx.registerFunction<void(DownstreamState::*)(boost::optional<bool> newStatus)>("setLazyAuto", [](DownstreamState& state, boost::optional<bool> newStatus) {
if (newStatus) {
- s.setUpStatus(*newStatus);
+ state.setUpStatus(*newStatus);
}
- s.setLazyAuto();
+ state.setLazyAuto();
});
- luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getName", [](const DownstreamState& s) { return s.getName(); });
- luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getNameWithAddr", [](const DownstreamState& s) { return s.getNameWithAddr(); });
+ luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getName", [](const DownstreamState& state) -> const std::string& { return state.getName(); });
+ luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getNameWithAddr", [](const DownstreamState& state) -> const std::string& { return state.getNameWithAddr(); });
luaCtx.registerMember("upStatus", &DownstreamState::upStatus);
luaCtx.registerMember<int (DownstreamState::*)>("weight",
- [](const DownstreamState& s) -> int {return s.d_config.d_weight;},
- [](DownstreamState& s, int newWeight) { s.setWeight(newWeight); }
+ [](const DownstreamState& state) -> int {return state.d_config.d_weight;},
+ [](DownstreamState& state, int newWeight) { state.setWeight(newWeight); }
);
luaCtx.registerMember<int (DownstreamState::*)>("order",
- [](const DownstreamState& s) -> int {return s.d_config.order; },
- [](DownstreamState& s, int newOrder) { s.d_config.order = newOrder; }
+ [](const DownstreamState& state) -> int {return state.d_config.order; },
+ [](DownstreamState& state, int newOrder) { state.d_config.order = newOrder; }
);
luaCtx.registerMember<const std::string(DownstreamState::*)>("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); });
- luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getID", [](const DownstreamState& s) { return boost::uuids::to_string(*s.d_config.id); });
+ luaCtx.registerFunction<std::string(DownstreamState::*)()const>("getID", [](const DownstreamState& state) { return boost::uuids::to_string(*state.d_config.id); });
#endif /* DISABLE_DOWNSTREAM_BINDINGS */
#ifndef DISABLE_DNSHEADER_BINDINGS
@@ -283,54 +288,54 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
/* SuffixMatchNode */
luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, std::string, LuaArray<DNSName>, LuaArray<std::string>> &name)>("add", [](SuffixMatchNode &smn, const boost::variant<DNSName, std::string, LuaArray<DNSName>, LuaArray<std::string>> &name) {
if (name.type() == typeid(DNSName)) {
- auto n = boost::get<DNSName>(name);
- smn.add(n);
+ const auto& actualName = boost::get<DNSName>(name);
+ smn.add(actualName);
return;
}
if (name.type() == typeid(std::string)) {
- auto n = boost::get<std::string>(name);
- smn.add(n);
+ const auto& actualName = boost::get<std::string>(name);
+ smn.add(actualName);
return;
}
if (name.type() == typeid(LuaArray<DNSName>)) {
- auto names = boost::get<LuaArray<DNSName>>(name);
- for (const auto& n : names) {
- smn.add(n.second);
+ const auto& names = boost::get<LuaArray<DNSName>>(name);
+ for (const auto& actualName : names) {
+ smn.add(actualName.second);
}
return;
}
if (name.type() == typeid(LuaArray<std::string>)) {
- auto names = boost::get<LuaArray<string>>(name);
- for (const auto& n : names) {
- smn.add(n.second);
+ const auto& names = boost::get<LuaArray<string>>(name);
+ for (const auto& actualName : names) {
+ smn.add(actualName.second);
}
return;
}
});
luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, LuaArray<DNSName>, LuaArray<std::string>> &name)>("remove", [](SuffixMatchNode &smn, const boost::variant<DNSName, string, LuaArray<DNSName>, LuaArray<std::string>> &name) {
if (name.type() == typeid(DNSName)) {
- auto n = boost::get<DNSName>(name);
- smn.remove(n);
+ const auto& actualName = boost::get<DNSName>(name);
+ smn.remove(actualName);
return;
}
if (name.type() == typeid(string)) {
- auto n = boost::get<string>(name);
- DNSName d(n);
- smn.remove(d);
+ const auto& actualName = boost::get<string>(name);
+ DNSName dnsName(actualName);
+ smn.remove(dnsName);
return;
}
if (name.type() == typeid(LuaArray<DNSName>)) {
- auto names = boost::get<LuaArray<DNSName>>(name);
- for (const auto& n : names) {
- smn.remove(n.second);
+ const auto& names = boost::get<LuaArray<DNSName>>(name);
+ for (const auto& actualName : names) {
+ smn.remove(actualName.second);
}
return;
}
if (name.type() == typeid(LuaArray<std::string>)) {
- auto names = boost::get<LuaArray<std::string>>(name);
- for (const auto& n : names) {
- DNSName d(n.second);
- smn.remove(d);
+ const auto& names = boost::get<LuaArray<std::string>>(name);
+ for (const auto& actualName : names) {
+ DNSName dnsName(actualName.second);
+ smn.remove(dnsName);
}
return;
}
@@ -349,16 +354,16 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
#ifndef DISABLE_NETMASK_BINDINGS
/* Netmask */
- luaCtx.writeFunction("newNetmask", [](boost::variant<std::string,ComboAddress> s, boost::optional<uint8_t> bits) {
- if (s.type() == typeid(ComboAddress)) {
- auto ca = boost::get<ComboAddress>(s);
+ luaCtx.writeFunction("newNetmask", [](boost::variant<std::string,ComboAddress> addrOrStr, boost::optional<uint8_t> bits) {
+ if (addrOrStr.type() == typeid(ComboAddress)) {
+ const auto& comboAddr = boost::get<ComboAddress>(addrOrStr);
if (bits) {
- return Netmask(ca, *bits);
+ return Netmask(comboAddr, *bits);
}
- return Netmask(ca);
+ return Netmask(comboAddr);
}
- else if (s.type() == typeid(std::string)) {
- auto str = boost::get<std::string>(s);
+ if (addrOrStr.type() == typeid(std::string)) {
+ const auto& str = boost::get<std::string>(addrOrStr);
return Netmask(str);
}
throw std::runtime_error("Invalid parameter passed to 'newNetmask()'");
@@ -379,10 +384,17 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
/* NetmaskGroup */
luaCtx.writeFunction("newNMG", []() { return NetmaskGroup(); });
- luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
+ luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string& mask)>("addMask", [](NetmaskGroup& nmg, const std::string& mask)
{
nmg.addMask(mask);
});
+ luaCtx.registerFunction<void(NetmaskGroup::*)(const NetmaskGroup& otherNMG)>("addNMG", [](NetmaskGroup& nmg, const NetmaskGroup& otherNMG) {
+ /* this is not going to be very efficient, sorry */
+ auto entries = otherNMG.toStringVector();
+ for (const auto& entry : entries) {
+ nmg.addMask(entry);
+ }
+ });
luaCtx.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map)
{
for (const auto& entry : map) {
@@ -479,7 +491,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
auto& params = boost::get<string>(tmp);
config.d_pinnedPath = std::move(params);
}
- mapsConfig[name] = config;
+ mapsConfig[name] = std::move(config);
};
convertParamsToConfig("ipv4", BPFFilter::MapType::IPv4);
@@ -705,7 +717,48 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
}
});
#endif /* HAVE_EBPF */
-
+#ifdef HAVE_XSK
+ using xskopt_t = LuaAssociativeTable<boost::variant<uint32_t, std::string>>;
+ luaCtx.writeFunction("newXsk", [client](xskopt_t opts) {
+ if (g_configurationDone) {
+ throw std::runtime_error("newXsk() only can be used at configuration time!");
+ }
+ if (client) {
+ return std::shared_ptr<XskSocket>(nullptr);
+ }
+ uint32_t queue_id;
+ uint32_t frameNums{65536};
+ std::string ifName;
+ std::string path("/sys/fs/bpf/dnsdist/xskmap");
+ if (opts.count("ifName") == 1) {
+ ifName = boost::get<std::string>(opts.at("ifName"));
+ }
+ else {
+ throw std::runtime_error("ifName field is required!");
+ }
+ if (opts.count("NIC_queue_id") == 1) {
+ queue_id = boost::get<uint32_t>(opts.at("NIC_queue_id"));
+ }
+ else {
+ throw std::runtime_error("NIC_queue_id field is required!");
+ }
+ if (opts.count("frameNums") == 1) {
+ frameNums = boost::get<uint32_t>(opts.at("frameNums"));
+ }
+ if (opts.count("xskMapPath") == 1) {
+ path = boost::get<std::string>(opts.at("xskMapPath"));
+ }
+ auto socket = std::make_shared<XskSocket>(frameNums, ifName, queue_id, path);
+ dnsdist::xsk::g_xsk.push_back(socket);
+ return socket;
+ });
+ luaCtx.registerFunction<std::string(std::shared_ptr<XskSocket>::*)()const>("getMetrics", [](const std::shared_ptr<XskSocket>& xsk) -> std::string {
+ if (!xsk) {
+ return {};
+ }
+ return xsk->getMetrics();
+ });
+#endif /* HAVE_XSK */
/* EDNSOptionView */
luaCtx.registerFunction<size_t(EDNSOptionView::*)()const>("count", [](const EDNSOptionView& option) {
return option.values.size();
@@ -784,4 +837,23 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
}
return now;
});
+
+ luaCtx.writeFunction("getAddressInfo", [client, configCheck](std::string hostname, std::function<void(const std::string& hostname, const LuaArray<ComboAddress>& ips)> callback) {
+ if (client || configCheck) {
+ return;
+ }
+ std::thread newThread(dnsdist::resolver::asynchronousResolver, std::move(hostname), [callback=std::move(callback)](const std::string& resolvedHostname, std::vector<ComboAddress>& ips) {
+ LuaArray<ComboAddress> result;
+ result.reserve(ips.size());
+ for (const auto& entry : ips) {
+ result.emplace_back(result.size() + 1, entry);
+ }
+ {
+ auto lua = g_lua.lock();
+ callback(resolvedHostname, result);
+ dnsdist::handleQueuedAsynchronousEvents();
+ }
+ });
+ newThread.detach();
+ });
}
diff --git a/dnsdist-lua-ffi-interface.h b/dnsdist-lua-ffi-interface.h
index e7cc8fe..14d6fab 100644
--- a/dnsdist-lua-ffi-interface.h
+++ b/dnsdist-lua-ffi-interface.h
@@ -60,6 +60,7 @@ typedef enum {
void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_is_remote_v6(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
@@ -117,6 +118,8 @@ void dnsdist_ffi_dnsquestion_set_device_name(dnsdist_ffi_dnsquestion_t* dq, cons
void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, size_t bodyLen, const char* contentType) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize) __attribute__ ((visibility ("default")));
+
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen) __attribute__ ((visibility ("default")));
@@ -191,11 +194,22 @@ size_t dnsdist_ffi_packetcache_get_address_list_by_domain(const char* poolName,
typedef struct dnsdist_ffi_ring_entry_list_t dnsdist_ffi_ring_entry_list_t;
bool dnsdist_ffi_ring_entry_is_response(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+double dnsdist_ffi_ring_entry_get_age(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_name(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_ring_entry_get_type(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+const char* dnsdist_ffi_ring_entry_get_backend(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint8_t dnsdist_ffi_ring_entry_get_protocol(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_ring_entry_get_size(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_latency(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_id(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_ring_entry_get_rcode(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_aa(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_rd(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_tc(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_ancount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_nscount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_arcount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_ring_entry_has_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
@@ -241,3 +255,32 @@ const char* dnsdist_ffi_network_message_get_payload(const dnsdist_ffi_network_me
size_t dnsdist_ffi_network_message_get_payload_size(const dnsdist_ffi_network_message_t* msg) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_message_t* msg) __attribute__ ((visibility ("default")));
+/* Add a dynamic block:
+ - address should be an IPv4 or IPv6 address, as a string (192.0.2.1). A port might be included (192.0.2.1:).
+ - reason is a description of why the block was inserted
+ - action should be a DNSAction
+ - duration is the duration of the block, in seconds
+ - clientIPMask indicates whether the exact IP address should be blocked (32 for IPv4, 128 for IPv6) or if a range should be used instead, by indicating the number of bits of the address to consider
+ - clientIPPort indicates It is also possible to take the IPv4 UDP and TCP ports into account, for CGNAT deployments, by setting the number of bits of the port to consider. For example passing 2 as the last parameter, which only makes sense if the previous parameters are respectively 32 and 128, will split a given IP address into four port ranges: 0-16383, 16384-32767, 32768-49151 and 49152-65535.
+*/
+bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, uint8_t action, unsigned int duration, uint8_t clientIPMask, uint8_t clientIPPortMask) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration) __attribute__ ((visibility ("default")));
+
+typedef struct dnsdist_ffi_dynamic_block_entry {
+ char* key; /* Client IP for NMT blocks, domain name for SMT ones */
+ char* reason;
+ uint64_t blockedQueries;
+ uint64_t remainingTime;
+ uint8_t action;
+ bool ebpf;
+ bool warning;
+} dnsdist_ffi_dynamic_block_entry_t;
+
+typedef struct dnsdist_ffi_dynamic_blocks_list_t dnsdist_ffi_dynamic_blocks_list_t;
+
+size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
+size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
+const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t*) __attribute__ ((visibility ("default")));
+
+uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive) __attribute__ ((visibility ("default")));
diff --git a/dnsdist-lua-ffi-interface.inc b/dnsdist-lua-ffi-interface.inc
index 851c75a..c4954b9 100644
--- a/dnsdist-lua-ffi-interface.inc
+++ b/dnsdist-lua-ffi-interface.inc
@@ -61,6 +61,7 @@ typedef enum {
void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dnsquestion_is_remote_v6(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
@@ -118,6 +119,8 @@ void dnsdist_ffi_dnsquestion_set_device_name(dnsdist_ffi_dnsquestion_t* dq, cons
void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, size_t bodyLen, const char* contentType) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize) __attribute__ ((visibility ("default")));
+
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen) __attribute__ ((visibility ("default")));
@@ -192,11 +195,22 @@ size_t dnsdist_ffi_packetcache_get_address_list_by_domain(const char* poolName,
typedef struct dnsdist_ffi_ring_entry_list_t dnsdist_ffi_ring_entry_list_t;
bool dnsdist_ffi_ring_entry_is_response(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+double dnsdist_ffi_ring_entry_get_age(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_name(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_ring_entry_get_type(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+const char* dnsdist_ffi_ring_entry_get_backend(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint8_t dnsdist_ffi_ring_entry_get_protocol(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_ring_entry_get_size(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_latency(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_id(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint8_t dnsdist_ffi_ring_entry_get_rcode(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_aa(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_rd(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_ring_entry_get_tc(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_ancount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_nscount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+uint16_t dnsdist_ffi_ring_entry_get_arcount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_ring_entry_has_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
const char* dnsdist_ffi_ring_entry_get_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
@@ -242,6 +256,35 @@ const char* dnsdist_ffi_network_message_get_payload(const dnsdist_ffi_network_me
size_t dnsdist_ffi_network_message_get_payload_size(const dnsdist_ffi_network_message_t* msg) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_message_t* msg) __attribute__ ((visibility ("default")));
+/* Add a dynamic block:
+ - address should be an IPv4 or IPv6 address, as a string (192.0.2.1). A port might be included (192.0.2.1:).
+ - reason is a description of why the block was inserted
+ - action should be a DNSAction
+ - duration is the duration of the block, in seconds
+ - clientIPMask indicates whether the exact IP address should be blocked (32 for IPv4, 128 for IPv6) or if a range should be used instead, by indicating the number of bits of the address to consider
+ - clientIPPort indicates It is also possible to take the IPv4 UDP and TCP ports into account, for CGNAT deployments, by setting the number of bits of the port to consider. For example passing 2 as the last parameter, which only makes sense if the previous parameters are respectively 32 and 128, will split a given IP address into four port ranges: 0-16383, 16384-32767, 32768-49151 and 49152-65535.
+*/
+bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, uint8_t action, unsigned int duration, uint8_t clientIPMask, uint8_t clientIPPortMask) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration) __attribute__ ((visibility ("default")));
+
+typedef struct dnsdist_ffi_dynamic_block_entry {
+ char* key; /* Client IP for NMT blocks, domain name for SMT ones */
+ char* reason;
+ uint64_t blockedQueries;
+ uint64_t remainingTime;
+ uint8_t action;
+ bool ebpf;
+ bool warning;
+} dnsdist_ffi_dynamic_block_entry_t;
+
+typedef struct dnsdist_ffi_dynamic_blocks_list_t dnsdist_ffi_dynamic_blocks_list_t;
+
+size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
+size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
+const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t*) __attribute__ ((visibility ("default")));
+
+uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive) __attribute__ ((visibility ("default")));
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
@@ -266,26 +309,32 @@ uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_m
typedef struct dnsdist_ffi_stat_node_t dnsdist_ffi_stat_node_t;
-uint64_t dnsdist_ffi_stat_node_get_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_bytes(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_hits(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-unsigned int dnsdist_ffi_stat_node_get_labels_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-void dnsdist_ffi_stat_node_get_full_name_raw(const dnsdist_ffi_stat_node_t* node, const char** name, size_t* nameSize) __attribute__ ((visibility ("default")));
-
-unsigned int dnsdist_ffi_stat_node_get_children_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-
-uint64_t dnsdist_ffi_stat_node_get_children_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_bytes_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_hits(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-
-void dnsdist_ffi_state_node_set_reason(dnsdist_ffi_stat_node_t* node, const char* reason, size_t reasonSize) __attribute__ ((visibility ("default")));
-
+uint64_t dnsdist_ffi_stat_node_get_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_bytes(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_hits(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+unsigned int dnsdist_ffi_stat_node_get_labels_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+void dnsdist_ffi_stat_node_get_full_name_raw(const dnsdist_ffi_stat_node_t* node, const char** name, size_t* nameSize) __attribute__((visibility("default")));
+
+unsigned int dnsdist_ffi_stat_node_get_children_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+
+uint64_t dnsdist_ffi_stat_node_get_children_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_bytes_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_hits(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+
+void dnsdist_ffi_state_node_set_reason(dnsdist_ffi_stat_node_t* node, const char* reason, size_t reasonSize) __attribute__((visibility("default")));
+void dnsdist_ffi_state_node_set_action(dnsdist_ffi_stat_node_t* node, int blockAction) __attribute__((visibility("default")));
+
+typedef enum
+{
+ dnsdist_ffi_dynamic_block_type_nmt = 0,
+ dnsdist_ffi_dynamic_block_type_smt = 1,
+} dnsdist_ffi_dynamic_block_type;
)FFIContent"
diff --git a/dnsdist-lua-ffi.cc b/dnsdist-lua-ffi.cc
index bf46aad..6c08cfc 100644
--- a/dnsdist-lua-ffi.cc
+++ b/dnsdist-lua-ffi.cc
@@ -22,6 +22,7 @@
#include "dnsdist-async.hh"
#include "dnsdist-dnsparser.hh"
+#include "dnsdist-dynblocks.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-lua-ffi.hh"
#include "dnsdist-mac-address.hh"
@@ -67,6 +68,15 @@ void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq,
dnsdist_ffi_comboaddress_to_raw(dq->dq->ids.origDest, addr, addrSize);
}
+bool dnsdist_ffi_dnsquestion_is_remote_v6(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+ if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr) {
+ return false;
+ }
+
+ return dnsQuestion->dq->ids.origRemote.isIPv6();
+}
+
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize)
{
dnsdist_ffi_comboaddress_to_raw(dq->dq->ids.origRemote, addr, addrSize);
@@ -129,7 +139,7 @@ int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->getHeader();
+ return dq->dq->getMutableHeader();
}
uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
@@ -458,14 +468,30 @@ void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, ui
#ifdef HAVE_DNS_OVER_HTTPS
PacketBuffer bodyVect(body, body + bodyLen);
dq->dq->ids.du->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
- dq->dq->getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [](dnsheader& header) {
+ header.qr = true;
+ return true;
+ });
#endif
}
+void dnsdist_ffi_dnsquestion_set_extended_dns_error(dnsdist_ffi_dnsquestion_t* dnsQuestion, uint16_t infoCode, const char* extraText, size_t extraTextSize)
+{
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText != nullptr && extraTextSize > 0) {
+ ede.extraText = std::string(extraText, extraTextSize);
+ }
+ dnsQuestion->dq->ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+}
+
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
{
- dq->dq->getHeader()->rcode = rcode;
- dq->dq->getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->dq->getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
}
void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
@@ -571,8 +597,8 @@ void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char
void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* raw, size_t len)
{
std::string result;
- SpoofAction sa(raw, len);
- sa(dq->dq, &result);
+ SpoofAction tempSpoofAction(raw, len);
+ tempSpoofAction(dq->dq, &result);
}
void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
@@ -585,8 +611,8 @@ void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsd
}
std::string result;
- SpoofAction sa(data);
- sa(dq->dq, &result);
+ SpoofAction tempSpoofAction(data, std::nullopt);
+ tempSpoofAction(dq->dq, &result);
}
void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
@@ -614,8 +640,8 @@ void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dn
}
std::string result;
- SpoofAction sa(data);
- sa(dq->dq, &result);
+ SpoofAction tempSpoofAction(data);
+ tempSpoofAction(dq->dq, &result);
}
void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max)
@@ -749,7 +775,7 @@ bool dnsdist_ffi_dnsresponse_rebase(dnsdist_ffi_dnsresponse_t* dr, const char* i
}
// set qname to new one
- dr->dr->ids.qname = parsed;
+ dr->dr->ids.qname = std::move(parsed);
dr->dr->ids.skipCache = true;
}
catch (const std::exception& e) {
@@ -929,7 +955,8 @@ bool dnsdist_ffi_drop_from_async(uint16_t asyncID, uint16_t queryID)
struct timeval now;
gettimeofday(&now, nullptr);
- sender->notifyIOError(std::move(query->query.d_idstate), now);
+ TCPResponse tresponse(std::move(query->query));
+ sender->notifyIOError(now, std::move(tresponse));
return true;
}
@@ -949,11 +976,15 @@ bool dnsdist_ffi_set_answer_from_async(uint16_t asyncID, uint16_t queryID, const
return false;
}
- auto oldId = reinterpret_cast<const dnsheader*>(query->query.d_buffer.data())->id;
+ dnsheader_aligned alignedHeader(query->query.d_buffer.data());
+ auto oldID = alignedHeader->id;
query->query.d_buffer.clear();
query->query.d_buffer.insert(query->query.d_buffer.begin(), raw, raw + rawSize);
- reinterpret_cast<dnsheader*>(query->query.d_buffer.data())->id = oldId;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query->query.d_buffer, [oldID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
query->query.d_idstate.skipCache = true;
return dnsdist::queueQueryResumptionEvent(std::move(query));
@@ -978,7 +1009,7 @@ const char* getLuaFFIWrappers()
void setupLuaLoadBalancingContext(LuaContext& luaCtx)
{
- setupLuaBindings(luaCtx, true);
+ setupLuaBindings(luaCtx, true, false);
setupLuaBindingsDNSQuestion(luaCtx);
setupLuaBindingsKVS(luaCtx, true);
setupLuaVars(luaCtx);
@@ -1202,7 +1233,11 @@ struct dnsdist_ffi_ring_entry_list_t
std::string qname;
std::string requestor;
std::string macAddr;
- size_t size;
+ std::string ds;
+ dnsheader dh;
+ double age;
+ unsigned int latency;
+ uint16_t size;
uint16_t qtype;
dnsdist::Protocol protocol;
bool isResponse;
@@ -1220,6 +1255,15 @@ bool dnsdist_ffi_ring_entry_is_response(const dnsdist_ffi_ring_entry_list_t* lis
return list->d_entries.at(idx).isResponse;
}
+double dnsdist_ffi_ring_entry_get_age(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return list->d_entries.at(idx).age;
+}
+
const char* dnsdist_ffi_ring_entry_get_name(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
{
if (list == nullptr || idx >= list->d_entries.size()) {
@@ -1236,7 +1280,6 @@ uint16_t dnsdist_ffi_ring_entry_get_type(const dnsdist_ffi_ring_entry_list_t* li
}
return list->d_entries.at(idx).qtype;
-
}
const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
@@ -1248,6 +1291,15 @@ const char* dnsdist_ffi_ring_entry_get_requestor(const dnsdist_ffi_ring_entry_li
return list->d_entries.at(idx).requestor.c_str();
}
+const char* dnsdist_ffi_ring_entry_get_backend(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return nullptr;
+ }
+
+ return list->d_entries.at(idx).ds.c_str();
+}
+
uint8_t dnsdist_ffi_ring_entry_get_protocol(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
{
if (list == nullptr || idx >= list->d_entries.size()) {
@@ -1264,7 +1316,87 @@ uint16_t dnsdist_ffi_ring_entry_get_size(const dnsdist_ffi_ring_entry_list_t* li
}
return list->d_entries.at(idx).size;
+}
+
+uint16_t dnsdist_ffi_ring_entry_get_latency(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return list->d_entries.at(idx).latency;
+}
+
+uint16_t dnsdist_ffi_ring_entry_get_id(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+ return ntohs(list->d_entries.at(idx).dh.id);
+}
+
+uint8_t dnsdist_ffi_ring_entry_get_rcode(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return list->d_entries.at(idx).dh.rcode;
+}
+
+bool dnsdist_ffi_ring_entry_get_aa(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return false;
+ }
+
+ return list->d_entries.at(idx).dh.aa == 1;
+}
+
+bool dnsdist_ffi_ring_entry_get_rd(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return false;
+ }
+
+ return list->d_entries.at(idx).dh.rd == 1;
+}
+
+bool dnsdist_ffi_ring_entry_get_tc(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return false;
+ }
+
+ return list->d_entries.at(idx).dh.tc == 1;
+}
+
+uint16_t dnsdist_ffi_ring_entry_get_ancount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return ntohs(list->d_entries.at(idx).dh.ancount);
+}
+
+uint16_t dnsdist_ffi_ring_entry_get_nscount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return ntohs(list->d_entries.at(idx).dh.nscount);
+}
+
+uint16_t dnsdist_ffi_ring_entry_get_arcount(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
+{
+ if (list == nullptr || idx >= list->d_entries.size()) {
+ return 0;
+ }
+
+ return ntohs(list->d_entries.at(idx).dh.arcount);
}
bool dnsdist_ffi_ring_entry_has_mac_address(const dnsdist_ffi_ring_entry_list_t* list, size_t idx)
@@ -1283,7 +1415,6 @@ const char* dnsdist_ffi_ring_entry_get_mac_address(const dnsdist_ffi_ring_entry_
}
return list->d_entries.at(idx).macAddr.data();
-
}
void dnsdist_ffi_ring_entry_list_free(dnsdist_ffi_ring_entry_list_t* list)
@@ -1291,22 +1422,23 @@ void dnsdist_ffi_ring_entry_list_free(dnsdist_ffi_ring_entry_list_t* list)
delete list;
}
-template<typename T> static void addRingEntryToList(std::unique_ptr<dnsdist_ffi_ring_entry_list_t>& list, const T& entry)
+template<typename T> static void addRingEntryToList(std::unique_ptr<dnsdist_ffi_ring_entry_list_t>& list, const struct timespec& now, const T& entry)
{
+ auto age = DiffTime(entry.when, now);
+
constexpr bool response = std::is_same_v<T, Rings::Response>;
-#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
if constexpr (!response) {
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string(), entry.size, entry.qtype, entry.protocol, response};
+#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string(), std::string(), entry.dh, age, 0, entry.size, entry.qtype, entry.protocol, response};
+#else
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), std::string(), entry.dh, age, 0, entry.size, entry.qtype, entry.protocol, response};
+#endif
list->d_entries.push_back(std::move(tmp));
}
else {
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), std::string(), entry.size, entry.qtype, entry.protocol, response};
+ dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toStringWithPort(), std::string(), entry.ds.toStringWithPort(), entry.dh, age, entry.usec, entry.size, entry.qtype, entry.protocol, response};
list->d_entries.push_back(std::move(tmp));
}
-#else
- dnsdist_ffi_ring_entry_list_t::entry tmp{entry.name.toString(), entry.requestor.toString(), std::string(), entry.size, entry.qtype, entry.protocol, response};
- list->d_entries.push_back(std::move(tmp));
-#endif
}
size_t dnsdist_ffi_ring_get_entries(dnsdist_ffi_ring_entry_list_t** out)
@@ -1315,18 +1447,22 @@ size_t dnsdist_ffi_ring_get_entries(dnsdist_ffi_ring_entry_list_t** out)
return 0;
}
auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
+ struct timespec now
+ {
+ };
+ gettime(&now);
for (const auto& shard : g_rings.d_shards) {
{
auto ql = shard->queryRing.lock();
for (const auto& entry : *ql) {
- addRingEntryToList(list, entry);
+ addRingEntryToList(list, now, entry);
}
}
{
auto rl = shard->respRing.lock();
for (const auto& entry : *rl) {
- addRingEntryToList(list, entry);
+ addRingEntryToList(list, now, entry);
}
}
}
@@ -1357,6 +1493,10 @@ size_t dnsdist_ffi_ring_get_entries_by_addr(const char* addr, dnsdist_ffi_ring_e
}
auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
+ struct timespec now
+ {
+ };
+ gettime(&now);
auto compare = ComboAddress::addressOnlyEqual();
for (const auto& shard : g_rings.d_shards) {
@@ -1367,7 +1507,7 @@ size_t dnsdist_ffi_ring_get_entries_by_addr(const char* addr, dnsdist_ffi_ring_e
continue;
}
- addRingEntryToList(list, entry);
+ addRingEntryToList(list, now, entry);
}
}
{
@@ -1377,7 +1517,7 @@ size_t dnsdist_ffi_ring_get_entries_by_addr(const char* addr, dnsdist_ffi_ring_e
continue;
}
- addRingEntryToList(list, entry);
+ addRingEntryToList(list, now, entry);
}
}
}
@@ -1399,6 +1539,10 @@ size_t dnsdist_ffi_ring_get_entries_by_mac(const char* addr, dnsdist_ffi_ring_en
return 0;
#else
auto list = std::make_unique<dnsdist_ffi_ring_entry_list_t>();
+ struct timespec now
+ {
+ };
+ gettime(&now);
for (const auto& shard : g_rings.d_shards) {
auto ql = shard->queryRing.lock();
@@ -1407,7 +1551,7 @@ size_t dnsdist_ffi_ring_get_entries_by_mac(const char* addr, dnsdist_ffi_ring_en
continue;
}
- addRingEntryToList(list, entry);
+ addRingEntryToList(list, now, entry);
}
}
@@ -1607,17 +1751,14 @@ bool dnsdist_ffi_metric_declare(const char* name, size_t nameLen, const char* ty
if (name == nullptr || nameLen == 0 || type == nullptr || description == nullptr) {
return false;
}
- auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName ? std::optional<std::string>(customName) : std::nullopt);
- if (result) {
- return false;
- }
- return true;
+ auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName != nullptr ? std::optional<std::string>(customName) : std::nullopt);
+ return !result;
}
void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen)
{
auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), 1U);
- if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
return;
}
}
@@ -1625,7 +1766,7 @@ void dnsdist_ffi_metric_inc(const char* metricName, size_t metricNameLen)
void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uint64_t value)
{
auto result = dnsdist::metrics::incrementCustomCounter(std::string_view(metricName, metricNameLen), value);
- if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
return;
}
}
@@ -1633,7 +1774,7 @@ void dnsdist_ffi_metric_inc_by(const char* metricName, size_t metricNameLen, uin
void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen)
{
auto result = dnsdist::metrics::decrementCustomCounter(std::string_view(metricName, metricNameLen), 1U);
- if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
return;
}
}
@@ -1641,7 +1782,7 @@ void dnsdist_ffi_metric_dec(const char* metricName, size_t metricNameLen)
void dnsdist_ffi_metric_set(const char* metricName, size_t metricNameLen, double value)
{
auto result = dnsdist::metrics::setCustomGauge(std::string_view(metricName, metricNameLen), value);
- if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
return;
}
}
@@ -1649,7 +1790,7 @@ void dnsdist_ffi_metric_set(const char* metricName, size_t metricNameLen, double
double dnsdist_ffi_metric_get(const char* metricName, size_t metricNameLen, bool isCounter)
{
auto result = dnsdist::metrics::getCustomMetric(std::string_view(metricName, metricNameLen));
- if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
+ if (std::get_if<dnsdist::metrics::Error>(&result) != nullptr) {
return 0.;
}
return std::get<double>(result);
@@ -1678,3 +1819,200 @@ uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_m
}
return 0;
}
+
+#ifndef DISABLE_DYNBLOCKS
+bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, uint8_t action, unsigned int duration, uint8_t clientIPMask, uint8_t clientIPPortMask)
+{
+ try {
+ ComboAddress clientIPCA;
+ try {
+ clientIPCA = ComboAddress(address);
+ }
+ catch (const std::exception& exp) {
+ errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.what());
+ return false;
+ }
+ catch (const PDNSException& exp) {
+ errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.reason);
+ return false;
+ }
+
+ AddressAndPortRange target(clientIPCA, clientIPMask, clientIPPortMask);
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+ auto slow = g_dynblockNMG.getCopy();
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, message, duration, static_cast<DNSAction::Action>(action), false, false)) {
+ g_dynblockNMG.setState(slow);
+ return true;
+ }
+ }
+ catch (const std::exception& exp) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.what());
+ }
+ catch (const PDNSException& exp) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_add: %s", exp.reason);
+ }
+ catch (...) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_add");
+ }
+ return false;
+}
+
+bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration)
+{
+ try {
+ DNSName domain;
+ try {
+ domain = DNSName(suffix);
+ domain.makeUsLowerCase();
+ }
+ catch (const std::exception& exp) {
+ errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.what());
+ return false;
+ }
+ catch (const PDNSException& exp) {
+ errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.reason);
+ return false;
+ }
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+ auto slow = g_dynblockSMT.getCopy();
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, message, duration, static_cast<DNSAction::Action>(action), false)) {
+ g_dynblockSMT.setState(slow);
+ return true;
+ }
+ }
+ catch (const std::exception& exp) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.what());
+ }
+ catch (const PDNSException& exp) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.reason);
+ }
+ catch (...) {
+ errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add");
+ }
+ return false;
+}
+
+struct dnsdist_ffi_dynamic_blocks_list_t
+{
+ std::vector<dnsdist_ffi_dynamic_block_entry_t> d_entries;
+};
+
+size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
+{
+ if (out == nullptr) {
+ return 0;
+ }
+
+ auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ auto fullCopy = g_dynblockNMG.getCopy();
+ for (const auto& entry : fullCopy) {
+ const auto& client = entry.first;
+ const auto& details = entry.second;
+ if (!(now < details.until)) {
+ continue;
+ }
+
+ uint64_t counter = details.blocks;
+ if (g_defaultBPFFilter && details.bpf) {
+ counter += g_defaultBPFFilter->getHits(client.getNetwork());
+ }
+ list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : g_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
+ }
+
+ auto count = list->d_entries.size();
+ *out = list.release();
+ return count;
+}
+
+size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
+{
+ if (out == nullptr) {
+ return 0;
+ }
+
+ auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ auto fullCopy = g_dynblockSMT.getCopy();
+ fullCopy.visit([&now, &list](const SuffixMatchTree<DynBlock>& node) {
+ if (!(now < node.d_value.until)) {
+ return;
+ }
+ auto entry = node.d_value;
+ string key("empty");
+ if (!entry.domain.empty()) {
+ key = entry.domain.toString();
+ }
+ if (entry.action == DNSAction::Action::None) {
+ entry.action = g_dynBlockAction;
+ }
+ list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
+ });
+
+ auto count = list->d_entries.size();
+ *out = list.release();
+ return count;
+}
+
+const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx)
+{
+ if (list == nullptr) {
+ return nullptr;
+ }
+
+ if (idx >= list->d_entries.size()) {
+ return nullptr;
+ }
+
+ return &list->d_entries.at(idx);
+}
+
+void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t* list)
+{
+ if (list == nullptr) {
+ return;
+ }
+
+ for (auto& entry : list->d_entries) {
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
+ free(entry.key);
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc): this is a C API, RAII is not an option
+ free(entry.reason);
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): this is a C API, RAII is not an option
+ delete list;
+}
+
+#endif /* DISABLE_DYNBLOCKS */
+
+uint32_t dnsdist_ffi_hash(uint32_t seed, const unsigned char* data, size_t dataSize, bool caseInsensitive)
+{
+ if (data == nullptr || dataSize == 0) {
+ return seed;
+ }
+
+ if (caseInsensitive) {
+ return burtleCI(data, dataSize, seed);
+ }
+
+ return burtle(data, dataSize, seed);
+}
diff --git a/dnsdist-lua-ffi.hh b/dnsdist-lua-ffi.hh
index d0ed833..a91003b 100644
--- a/dnsdist-lua-ffi.hh
+++ b/dnsdist-lua-ffi.hh
@@ -48,11 +48,11 @@ struct dnsdist_ffi_dnsquestion_t
DNSQuestion* dq{nullptr};
ComboAddress maskedRemote;
std::string trailingData;
- boost::optional<std::string> result{boost::none};
- boost::optional<std::string> httpPath{boost::none};
- boost::optional<std::string> httpQueryString{boost::none};
- boost::optional<std::string> httpHost{boost::none};
- boost::optional<std::string> httpScheme{boost::none};
+ std::optional<std::string> result{std::nullopt};
+ std::optional<std::string> httpPath{std::nullopt};
+ std::optional<std::string> httpQueryString{std::nullopt};
+ std::optional<std::string> httpHost{std::nullopt};
+ std::optional<std::string> httpScheme{std::nullopt};
std::unique_ptr<std::vector<dnsdist_ffi_ednsoption_t>> ednsOptionsVect;
std::unique_ptr<std::vector<dnsdist_ffi_http_header_t>> httpHeadersVect;
std::unique_ptr<std::vector<dnsdist_ffi_tag_t>> tagsVect;
@@ -78,7 +78,7 @@ struct dnsdist_ffi_dnsresponse_t
}
DNSResponse* dr{nullptr};
- boost::optional<std::string> result{boost::none};
+ std::optional<std::string> result{std::nullopt};
};
// dnsdist_ffi_server_t is a lightuserdata
diff --git a/dnsdist-lua-hooks.cc b/dnsdist-lua-hooks.cc
new file mode 100644
index 0000000..c5ccb48
--- /dev/null
+++ b/dnsdist-lua-hooks.cc
@@ -0,0 +1,37 @@
+
+#include "dnsdist-lua-hooks.hh"
+#include "dnsdist-lua.hh"
+#include "lock.hh"
+
+namespace dnsdist::lua::hooks
+{
+static LockGuarded<std::vector<MaintenanceCallback>> s_maintenanceHooks;
+
+void runMaintenanceHooks(const LuaContext& context)
+{
+ (void)context;
+ for (const auto& callback : *(s_maintenanceHooks.lock())) {
+ callback();
+ }
+}
+
+void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback)
+{
+ (void)context;
+ s_maintenanceHooks.lock()->push_back(std::move(callback));
+}
+
+void clearMaintenanceHooks()
+{
+ s_maintenanceHooks.lock()->clear();
+}
+
+void setupLuaHooks(LuaContext& luaCtx)
+{
+ luaCtx.writeFunction("addMaintenanceCallback", [&luaCtx](const MaintenanceCallback& callback) {
+ setLuaSideEffect();
+ addMaintenanceCallback(luaCtx, callback);
+ });
+}
+
+}
diff --git a/dnsdist-lua-hooks.hh b/dnsdist-lua-hooks.hh
new file mode 100644
index 0000000..11a9084
--- /dev/null
+++ b/dnsdist-lua-hooks.hh
@@ -0,0 +1,35 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <functional>
+
+class LuaContext;
+
+namespace dnsdist::lua::hooks
+{
+using MaintenanceCallback = std::function<void()>;
+void runMaintenanceHooks(const LuaContext& context);
+void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback);
+void clearMaintenanceHooks();
+void setupLuaHooks(LuaContext& luaCtx);
+}
diff --git a/dnsdist-lua-inspection-ffi.cc b/dnsdist-lua-inspection-ffi.cc
index 0187ebc..232d5f9 100644
--- a/dnsdist-lua-inspection-ffi.cc
+++ b/dnsdist-lua-inspection-ffi.cc
@@ -113,6 +113,11 @@ uint64_t dnsdist_ffi_stat_node_get_children_hits(const dnsdist_ffi_stat_node_t*
void dnsdist_ffi_state_node_set_reason(dnsdist_ffi_stat_node_t* node, const char* reason, size_t reasonSize)
{
- node->reason = std::string(reason, reasonSize);
+ node->d_blockParameters.d_reason = std::string(reason, reasonSize);
+}
+
+void dnsdist_ffi_state_node_set_action(dnsdist_ffi_stat_node_t* node, int blockAction)
+{
+ node->d_blockParameters.d_action = static_cast<DNSAction::Action>(blockAction);
}
#endif /* DISABLE_DYNBLOCKS */
diff --git a/dnsdist-lua-inspection-ffi.h b/dnsdist-lua-inspection-ffi.h
index ca70eed..d681c87 100644
--- a/dnsdist-lua-inspection-ffi.h
+++ b/dnsdist-lua-inspection-ffi.h
@@ -22,25 +22,31 @@
typedef struct dnsdist_ffi_stat_node_t dnsdist_ffi_stat_node_t;
-uint64_t dnsdist_ffi_stat_node_get_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_bytes(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_hits(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-unsigned int dnsdist_ffi_stat_node_get_labels_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-void dnsdist_ffi_stat_node_get_full_name_raw(const dnsdist_ffi_stat_node_t* node, const char** name, size_t* nameSize) __attribute__ ((visibility ("default")));
+uint64_t dnsdist_ffi_stat_node_get_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_bytes(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_hits(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+unsigned int dnsdist_ffi_stat_node_get_labels_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+void dnsdist_ffi_stat_node_get_full_name_raw(const dnsdist_ffi_stat_node_t* node, const char** name, size_t* nameSize) __attribute__((visibility("default")));
-unsigned int dnsdist_ffi_stat_node_get_children_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
+unsigned int dnsdist_ffi_stat_node_get_children_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_bytes_count(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
-uint64_t dnsdist_ffi_stat_node_get_children_hits(const dnsdist_ffi_stat_node_t* node) __attribute__ ((visibility ("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_queries_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_noerrors_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_nxdomains_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_servfails_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_drops_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_bytes_count(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
+uint64_t dnsdist_ffi_stat_node_get_children_hits(const dnsdist_ffi_stat_node_t* node) __attribute__((visibility("default")));
-void dnsdist_ffi_state_node_set_reason(dnsdist_ffi_stat_node_t* node, const char* reason, size_t reasonSize) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_state_node_set_reason(dnsdist_ffi_stat_node_t* node, const char* reason, size_t reasonSize) __attribute__((visibility("default")));
+void dnsdist_ffi_state_node_set_action(dnsdist_ffi_stat_node_t* node, int blockAction) __attribute__((visibility("default")));
+typedef enum
+{
+ dnsdist_ffi_dynamic_block_type_nmt = 0,
+ dnsdist_ffi_dynamic_block_type_smt = 1,
+} dnsdist_ffi_dynamic_block_type;
diff --git a/dnsdist-lua-inspection.cc b/dnsdist-lua-inspection.cc
index 4fac0e3..ba7dfdb 100644
--- a/dnsdist-lua-inspection.cc
+++ b/dnsdist-lua-inspection.cc
@@ -19,6 +19,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <fcntl.h>
+
#include "dnsdist.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-dynblocks.hh"
@@ -136,17 +138,13 @@ static void statNodeRespRing(statvisitor_t visitor, uint64_t seconds)
continue;
}
- bool hit = c.ds.sin4.sin_family == 0;
- if (!hit && c.ds.isIPv4() && c.ds.sin4.sin_addr.s_addr == 0 && c.ds.sin4.sin_port == 0) {
- hit = true;
- }
-
+ const bool hit = c.isACacheHit();
root.submit(c.name, ((c.dh.rcode == 0 && c.usec == std::numeric_limits<unsigned int>::max()) ? -1 : c.dh.rcode), c.size, hit, boost::none);
}
}
StatNode::Stat node;
- root.visit([visitor](const StatNode* node_, const StatNode::Stat& self, const StatNode::Stat& children) {
+ root.visit([visitor = std::move(visitor)](const StatNode* node_, const StatNode::Stat& self, const StatNode::Stat& children) {
visitor(*node_, self, children);}, node);
}
@@ -408,38 +406,59 @@ void setupLuaInspection(LuaContext& luaCtx)
}
});
- luaCtx.writeFunction("grepq", [](LuaTypeOrArrayOf<std::string> inp, boost::optional<unsigned int> limit) {
+ luaCtx.writeFunction("grepq", [](LuaTypeOrArrayOf<std::string> inp, boost::optional<unsigned int> limit, boost::optional<LuaAssociativeTable<std::string>> options) {
setLuaNoSideEffect();
boost::optional<Netmask> nm;
boost::optional<DNSName> dn;
- int msec=-1;
+ int msec = -1;
+ pdns::UniqueFilePtr outputFile{nullptr};
+
+ if (options) {
+ std::string outputFileName;
+ if (getOptionalValue<std::string>(options, "outputFile", outputFileName) > 0) {
+ int fd = open(outputFileName.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0600);
+ if (fd < 0) {
+ g_outputBuffer = "Error opening dump file for writing: " + stringerror() + "\n";
+ return;
+ }
+ outputFile = pdns::UniqueFilePtr(fdopen(fd, "w"));
+ if (outputFile == nullptr) {
+ g_outputBuffer = "Error opening dump file for writing: " + stringerror() + "\n";
+ close(fd);
+ return;
+ }
+ }
+ checkAllParametersConsumed("grepq", options);
+ }
vector<string> vec;
- auto str=boost::get<string>(&inp);
- if(str)
+ auto str = boost::get<string>(&inp);
+ if (str) {
vec.push_back(*str);
+ }
else {
auto v = boost::get<LuaArray<std::string>>(inp);
- for(const auto& a: v)
+ for (const auto& a: v) {
vec.push_back(a.second);
+ }
}
- for(const auto& s : vec) {
- try
- {
+ for (const auto& s : vec) {
+ try {
nm = Netmask(s);
- }
- catch(...) {
- if(boost::ends_with(s,"ms") && sscanf(s.c_str(), "%ums", &msec)) {
+ }
+ catch (...) {
+ if (boost::ends_with(s,"ms") && sscanf(s.c_str(), "%ums", &msec)) {
;
}
else {
- try { dn=DNSName(s); }
- catch(...)
- {
- g_outputBuffer = "Could not parse '"+s+"' as domain name or netmask";
- return;
- }
+ try {
+ dn = DNSName(s);
+ }
+ catch (...) {
+ g_outputBuffer = "Could not parse '"+s+"' as domain name or netmask";
+ return;
+ }
}
}
}
@@ -477,12 +496,19 @@ void setupLuaInspection(LuaContext& luaCtx)
std::multimap<struct timespec, string> out;
- boost::format fmt("%-7.1f %-47s %-12s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %-s\n");
- g_outputBuffer+= (fmt % "Time" % "Client" % "Protocol" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str();
+ boost::format fmt("%-7.1f %-47s %-12s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %-s\n");
+ const auto headLine = (fmt % "Time" % "Client" % "Protocol" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str();
+ if (!outputFile) {
+ g_outputBuffer += headLine;
+ }
+ else {
+ fprintf(outputFile.get(), "%s", headLine.c_str());
+ }
- if(msec==-1) {
- for(const auto& c : qr) {
- bool nmmatch=true, dnmatch=true;
+ if (msec == -1) {
+ for (const auto& c : qr) {
+ bool nmmatch = true;
+ bool dnmatch = true;
if (nm) {
nmmatch = nm->match(c.requestor);
}
@@ -502,17 +528,19 @@ void setupLuaInspection(LuaContext& luaCtx)
}
out.emplace(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % dnsdist::Protocol(c.protocol).toString() % "" % htons(c.dh.id) % c.name.toString() % qt.toString() % "" % (c.dh.tc ? "TC" : "") % (c.dh.rd ? "RD" : "") % (c.dh.aa ? "AA" : "") % ("Question" + extra)).str());
- if(limit && *limit==++num)
+ if (limit && *limit == ++num) {
break;
+ }
}
}
}
- num=0;
-
+ num = 0;
string extra;
- for(const auto& c : rr) {
- bool nmmatch=true, dnmatch=true, msecmatch=true;
+ for (const auto& c : rr) {
+ bool nmmatch = true;
+ bool dnmatch = true;
+ bool msecmatch = true;
if (nm) {
nmmatch = nm->match(c.requestor);
}
@@ -525,13 +553,13 @@ void setupLuaInspection(LuaContext& luaCtx)
}
}
if (msec != -1) {
- msecmatch=(c.usec/1000 > (unsigned int)msec);
+ msecmatch = (c.usec/1000 > (unsigned int)msec);
}
if (nmmatch && dnmatch && msecmatch) {
QType qt(c.qtype);
if (!c.dh.rcode) {
- extra=". " +std::to_string(htons(c.dh.ancount))+ " answers";
+ extra = ". " +std::to_string(htons(c.dh.ancount)) + " answers";
}
else {
extra.clear();
@@ -556,8 +584,13 @@ void setupLuaInspection(LuaContext& luaCtx)
}
}
- for(const auto& p : out) {
- g_outputBuffer+=p.second;
+ for (const auto& p : out) {
+ if (!outputFile) {
+ g_outputBuffer += p.second;
+ }
+ else {
+ fprintf(outputFile.get(), "%s", p.second.c_str());
+ }
}
});
@@ -596,14 +629,14 @@ void setupLuaInspection(LuaContext& luaCtx)
return;
}
- g_outputBuffer = (boost::format("Average response latency: %.02f msec\n") % (0.001*totlat/size)).str();
+ g_outputBuffer = (boost::format("Average response latency: %.02f ms\n") % (0.001*totlat/size)).str();
double highest=0;
for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
highest=std::max(highest, iter->second*1.0);
}
boost::format fmt("%7.2f\t%s\n");
- g_outputBuffer += (fmt % "msec" % "").str();
+ g_outputBuffer += (fmt % "ms" % "").str();
for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
int stars = (70.0 * iter->second/highest);
@@ -669,7 +702,7 @@ void setupLuaInspection(LuaContext& luaCtx)
errorCounters = &f->tlsFrontend->d_tlsCounters;
}
else if (f->dohFrontend != nullptr) {
- errorCounters = &f->dohFrontend->d_tlsCounters;
+ errorCounters = &f->dohFrontend->d_tlsContext.d_tlsCounters;
}
if (errorCounters == nullptr) {
continue;
@@ -691,7 +724,9 @@ void setupLuaInspection(LuaContext& luaCtx)
luaCtx.writeFunction("requestDoHStatesDump", [] {
setLuaNoSideEffect();
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
g_dohStatesDumpRequested += g_dohClientThreads->getThreadsCount();
+#endif
});
luaCtx.writeFunction("dumpStats", [] {
@@ -700,7 +735,7 @@ void setupLuaInspection(LuaContext& luaCtx)
boost::format fmt("%-35s\t%+11s");
g_outputBuffer.clear();
- auto entries = *g_stats.entries.read_lock();
+ auto entries = *dnsdist::metrics::g_stats.entries.read_lock();
sort(entries.begin(), entries.end(),
[](const decltype(entries)::value_type& a, const decltype(entries)::value_type& b) {
return a.d_name < b.d_name;
@@ -708,16 +743,16 @@ void setupLuaInspection(LuaContext& luaCtx)
boost::format flt(" %9.1f");
for (const auto& entry : entries) {
string second;
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
second = std::to_string((*val)->load());
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
second = (flt % (*adval)->load()).str();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
second = (flt % (**dval)).str();
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
second = std::to_string((*func)(entry.d_name));
}
@@ -780,10 +815,10 @@ void setupLuaInspection(LuaContext& luaCtx)
luaCtx.writeFunction("getRespRing", getRespRing);
/* StatNode */
- luaCtx.registerFunction<StatNode, unsigned int()>("numChildren",
- [](StatNode& sn) -> unsigned int {
- return sn.children.size();
- } );
+ luaCtx.registerFunction<unsigned int(StatNode::*)()const>("numChildren",
+ [](const StatNode& sn) -> unsigned int {
+ return sn.children.size();
+ } );
luaCtx.registerMember("fullname", &StatNode::fullname);
luaCtx.registerMember("labelsCount", &StatNode::labelsCount);
luaCtx.registerMember("servfails", &StatNode::Stat::servfails);
@@ -795,7 +830,7 @@ void setupLuaInspection(LuaContext& luaCtx)
luaCtx.registerMember("hits", &StatNode::Stat::hits);
luaCtx.writeFunction("statNodeRespRing", [](statvisitor_t visitor, boost::optional<uint64_t> seconds) {
- statNodeRespRing(visitor, seconds ? *seconds : 0U);
+ statNodeRespRing(std::move(visitor), seconds ? *seconds : 0U);
});
#endif /* DISABLE_DEPRECATED_DYNBLOCK */
@@ -813,12 +848,17 @@ void setupLuaInspection(LuaContext& luaCtx)
});
luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, DynBlockRulesGroup::smtVisitor_t)>("setSuffixMatchRule", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, DynBlockRulesGroup::smtVisitor_t visitor) {
if (group) {
- group->setSuffixMatchRule(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, visitor);
+ group->setSuffixMatchRule(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, std::move(visitor));
}
});
luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, dnsdist_ffi_stat_node_visitor_t)>("setSuffixMatchRuleFFI", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, dnsdist_ffi_stat_node_visitor_t visitor) {
if (group) {
- group->setSuffixMatchRuleFFI(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, visitor);
+ group->setSuffixMatchRuleFFI(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, std::move(visitor));
+ }
+ });
+ luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(const dnsdist_ffi_dynamic_block_inserted_hook&)>("setNewBlockInsertedHook", [](std::shared_ptr<DynBlockRulesGroup>& group, const dnsdist_ffi_dynamic_block_inserted_hook& hook) {
+ if (group) {
+ group->setNewBlockHook(hook);
}
});
luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setRCodeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
@@ -836,6 +876,11 @@ void setupLuaInspection(LuaContext& luaCtx)
group->setQTypeRate(qtype, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
}
});
+ luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(double, unsigned int, const std::string&, unsigned int, size_t, double, boost::optional<DNSAction::Action>, boost::optional<double>)>("setCacheMissRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio) {
+ if (group) {
+ group->setCacheMissRatio(ratio, warningRatio ? *warningRatio : 0.0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ }
+ });
luaCtx.registerFunction<void(std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, uint8_t, uint8_t)>("setMasks", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t v4, uint8_t v6, uint8_t port) {
if (group) {
if (v4 > 32) {
@@ -907,5 +952,14 @@ void setupLuaInspection(LuaContext& luaCtx)
});
luaCtx.registerFunction("setQuiet", &DynBlockRulesGroup::setQuiet);
luaCtx.registerFunction("toString", &DynBlockRulesGroup::toString);
+
+ /* DynBlock object accessors */
+ luaCtx.registerMember("reason", &DynBlock::reason);
+ luaCtx.registerMember("domain", &DynBlock::domain);
+ luaCtx.registerMember("until", &DynBlock::until);
+ luaCtx.registerMember<DynBlock, unsigned int>("blocks", [](const DynBlock& block) { return block.blocks.load(); }, [](DynBlock& block, [[maybe_unused]] unsigned int blocks) { });
+ luaCtx.registerMember("action", &DynBlock::action);
+ luaCtx.registerMember("warning", &DynBlock::warning);
+ luaCtx.registerMember("bpf", &DynBlock::bpf);
#endif /* DISABLE_DYNBLOCKS */
}
diff --git a/dnsdist-lua-network.cc b/dnsdist-lua-network.cc
index 6892888..56a58cd 100644
--- a/dnsdist-lua-network.cc
+++ b/dnsdist-lua-network.cc
@@ -28,11 +28,21 @@
namespace dnsdist
{
-NetworkListener::NetworkListener() :
+NetworkListener::ListenerData::ListenerData() :
d_mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(10)))
{
}
+NetworkListener::NetworkListener() :
+ d_data(std::make_shared<ListenerData>())
+{
+}
+
+NetworkListener::~NetworkListener()
+{
+ d_data->d_exiting = true;
+}
+
void NetworkListener::readCB(int desc, FDMultiplexer::funcparam_t& param)
{
auto cbData = boost::any_cast<std::shared_ptr<NetworkListener::CBData>>(param);
@@ -40,24 +50,26 @@ void NetworkListener::readCB(int desc, FDMultiplexer::funcparam_t& param)
#ifdef MSG_TRUNC
/* first we peek to avoid allocating a very large buffer. "MSG_TRUNC [...] return the real length of the datagram, even when it was longer than the passed buffer" */
- auto peeked = recvfrom(desc, nullptr, 0, MSG_PEEK | MSG_TRUNC, nullptr, 0);
+ auto peeked = recvfrom(desc, nullptr, 0, MSG_PEEK | MSG_TRUNC, nullptr, nullptr);
if (peeked > 0) {
packet.resize(static_cast<size_t>(peeked));
}
#endif
- if (packet.size() == 0) {
+ if (packet.empty()) {
packet.resize(65535);
}
- struct sockaddr_un from;
+ sockaddr_un from{};
memset(&from, 0, sizeof(from));
socklen_t fromLen = sizeof(from);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto got = recvfrom(desc, &packet.at(0), packet.size(), 0, reinterpret_cast<sockaddr*>(&from), &fromLen);
if (got > 0) {
packet.resize(static_cast<size_t>(got));
std::string fromAddr;
if (fromLen <= sizeof(from)) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
fromAddr = std::string(from.sun_path, strlen(from.sun_path));
}
try {
@@ -72,13 +84,13 @@ void NetworkListener::readCB(int desc, FDMultiplexer::funcparam_t& param)
}
}
-bool NetworkListener::addUnixListeningEndpoint(const std::string& path, NetworkListener::EndpointID id, NetworkListener::NetworkDatagramCB cb)
+bool NetworkListener::addUnixListeningEndpoint(const std::string& path, NetworkListener::EndpointID endpointID, NetworkListener::NetworkDatagramCB callback)
{
- if (d_running == true) {
+ if (d_data->d_running) {
throw std::runtime_error("NetworkListener should not be altered at runtime");
}
- struct sockaddr_un sun;
+ sockaddr_un sun{};
if (makeUNsockaddr(path, &sun) != 0) {
throw std::runtime_error("Invalid Unix socket path '" + path + "'");
}
@@ -101,6 +113,7 @@ bool NetworkListener::addUnixListeningEndpoint(const std::string& path, NetworkL
sunLength = sizeof(sa_family_t) + path.size();
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
if (bind(sock.getHandle(), reinterpret_cast<const struct sockaddr*>(&sun), sunLength) != 0) {
std::string sanitizedPath(path);
if (abstractPath) {
@@ -112,38 +125,51 @@ bool NetworkListener::addUnixListeningEndpoint(const std::string& path, NetworkL
sock.setNonBlocking();
auto cbData = std::make_shared<CBData>();
- cbData->d_endpoint = id;
- cbData->d_cb = cb;
- d_mplexer->addReadFD(sock.getHandle(), readCB, cbData);
+ cbData->d_endpoint = endpointID;
+ cbData->d_cb = std::move(callback);
+ d_data->d_mplexer->addReadFD(sock.getHandle(), readCB, cbData);
- d_sockets.insert({path, std::move(sock)});
+ d_data->d_sockets.insert({path, std::move(sock)});
return true;
}
-void NetworkListener::runOnce(struct timeval& now, uint32_t timeout)
+void NetworkListener::runOnce(ListenerData& data, timeval& now, uint32_t timeout)
{
- d_running = true;
- if (d_sockets.empty()) {
+ if (data.d_exiting) {
+ return;
+ }
+
+ data.d_running = true;
+ if (data.d_sockets.empty()) {
throw runtime_error("NetworkListener started with no sockets");
}
- d_mplexer->run(&now, timeout);
+ data.d_mplexer->run(&now, static_cast<int>(timeout));
+}
+
+void NetworkListener::runOnce(timeval& now, uint32_t timeout)
+{
+ runOnce(*d_data, now, timeout);
}
-void NetworkListener::mainThread()
+void NetworkListener::mainThread(std::shared_ptr<ListenerData>& dataArg)
{
+ /* take our own copy of the shared_ptr so it's still alive if the NetworkListener object
+ gets destroyed while we are still running */
+ // NOLINTNEXTLINE(performance-unnecessary-copy-initialization): we really need a copy here, or we end up with use-after-free as explained above
+ auto data = dataArg;
setThreadName("dnsdist/lua-net");
- struct timeval now;
+ timeval now{};
- while (true) {
- runOnce(now, -1);
+ while (!data->d_exiting) {
+ runOnce(*data, now, -1);
}
}
void NetworkListener::start()
{
std::thread main = std::thread([this] {
- mainThread();
+ mainThread(d_data);
});
main.detach();
}
@@ -151,7 +177,7 @@ void NetworkListener::start()
NetworkEndpoint::NetworkEndpoint(const std::string& path) :
d_socket(AF_UNIX, SOCK_DGRAM, 0)
{
- struct sockaddr_un sun;
+ sockaddr_un sun{};
if (makeUNsockaddr(path, &sun) != 0) {
throw std::runtime_error("Invalid Unix socket path '" + path + "'");
}
@@ -163,6 +189,7 @@ NetworkEndpoint::NetworkEndpoint(const std::string& path) :
/* abstract paths can contain null bytes so we need to set the actual size */
sunLength = sizeof(sa_family_t) + path.size();
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
if (connect(d_socket.getHandle(), reinterpret_cast<const struct sockaddr*>(&sun), sunLength) != 0) {
std::string sanitizedPath(path);
if (abstractPath) {
diff --git a/dnsdist-lua-network.hh b/dnsdist-lua-network.hh
index a63efd4..3cd2f08 100644
--- a/dnsdist-lua-network.hh
+++ b/dnsdist-lua-network.hh
@@ -34,16 +34,32 @@ class NetworkListener
{
public:
NetworkListener();
+ NetworkListener(const NetworkListener&) = delete;
+ NetworkListener(NetworkListener&&) = delete;
+ NetworkListener& operator=(const NetworkListener&) = delete;
+ NetworkListener& operator=(NetworkListener&&) = delete;
+ ~NetworkListener();
using EndpointID = uint16_t;
using NetworkDatagramCB = std::function<void(EndpointID endpoint, std::string&& dgram, const std::string& from)>;
- bool addUnixListeningEndpoint(const std::string& path, EndpointID id, NetworkDatagramCB cb);
+ bool addUnixListeningEndpoint(const std::string& path, EndpointID endpointID, NetworkDatagramCB callback);
void start();
- void runOnce(struct timeval& now, uint32_t timeout);
+ void runOnce(timeval& now, uint32_t timeout);
private:
+ struct ListenerData
+ {
+ ListenerData();
+
+ std::unique_ptr<FDMultiplexer> d_mplexer;
+ std::unordered_map<std::string, Socket> d_sockets;
+ std::atomic<bool> d_running{false};
+ std::atomic<bool> d_exiting{false};
+ };
+
static void readCB(int desc, FDMultiplexer::funcparam_t& param);
- void mainThread();
+ static void mainThread(std::shared_ptr<ListenerData>& data);
+ static void runOnce(ListenerData& data, timeval& now, uint32_t timeout);
struct CBData
{
@@ -51,9 +67,7 @@ private:
EndpointID d_endpoint;
};
- std::unique_ptr<FDMultiplexer> d_mplexer;
- std::unordered_map<std::string, Socket> d_sockets;
- std::atomic<bool> d_running{false};
+ std::shared_ptr<ListenerData> d_data;
};
class NetworkEndpoint
diff --git a/dnsdist-lua-rules.cc b/dnsdist-lua-rules.cc
index da309e5..f53b98b 100644
--- a/dnsdist-lua-rules.cc
+++ b/dnsdist-lua-rules.cc
@@ -22,40 +22,51 @@
#include "dnsdist.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-rules.hh"
+#include "dns_random.hh"
-std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var)
+std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom)
{
- if (var.type() == typeid(std::shared_ptr<DNSRule>))
+ if (var.type() == typeid(std::shared_ptr<DNSRule>)) {
return *boost::get<std::shared_ptr<DNSRule>>(&var);
+ }
+ bool suffixSeen = false;
SuffixMatchNode smn;
NetmaskGroup nmg;
- auto add=[&](string src) {
+ auto add = [&nmg, &smn, &suffixSeen](const string& src) {
try {
nmg.addMask(src); // need to try mask first, all masks are domain names!
- } catch(...) {
+ } catch (...) {
+ suffixSeen = true;
smn.add(DNSName(src));
}
};
- if (var.type() == typeid(string))
+ if (var.type() == typeid(string)) {
add(*boost::get<string>(&var));
-
- else if (var.type() == typeid(LuaArray<std::string>))
- for(const auto& a : *boost::get<LuaArray<std::string>>(&var))
- add(a.second);
-
- else if (var.type() == typeid(DNSName))
+ }
+ else if (var.type() == typeid(LuaArray<std::string>)) {
+ for (const auto& str : *boost::get<LuaArray<std::string>>(&var)) {
+ add(str.second);
+ }
+ }
+ else if (var.type() == typeid(DNSName)) {
smn.add(*boost::get<DNSName>(&var));
+ }
+ else if (var.type() == typeid(LuaArray<DNSName>)) {
+ smn = SuffixMatchNode();
+ for (const auto& name : *boost::get<LuaArray<DNSName>>(&var)) {
+ smn.add(name.second);
+ }
+ }
- else if (var.type() == typeid(LuaArray<DNSName>))
- for(const auto& a : *boost::get<LuaArray<DNSName>>(&var))
- smn.add(a.second);
-
- if(nmg.empty())
+ if (nmg.empty()) {
return std::make_shared<SuffixMatchNodeRule>(smn);
- else
- return std::make_shared<NetmaskGroupRule>(nmg, true);
+ }
+ if (suffixSeen) {
+ warnlog("At least one parameter to %s has been parsed as a domain name amongst network masks, and will be ignored!", calledFrom);
+ }
+ return std::make_shared<NetmaskGroupRule>(nmg, true);
}
static boost::uuids::uuid makeRuleID(std::string& id)
@@ -83,7 +94,7 @@ void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uui
typedef LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int> > > ruleparams_t;
template<typename T>
-static std::string rulesToString(const std::vector<T>& rules, boost::optional<ruleparams_t> vars)
+static std::string rulesToString(const std::vector<T>& rules, boost::optional<ruleparams_t>& vars)
{
int num = 0;
bool showUUIDs = false;
@@ -116,7 +127,7 @@ static std::string rulesToString(const std::vector<T>& rules, boost::optional<ru
}
template<typename T>
-static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::optional<ruleparams_t> vars) {
+static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::optional<ruleparams_t>& vars) {
setLuaNoSideEffect();
auto rules = someRuleActions->getLocal();
@@ -124,7 +135,7 @@ static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::opt
}
template<typename T>
-static void rmRule(GlobalStateHolder<vector<T> > *someRuleActions, boost::variant<unsigned int, std::string> id) {
+static void rmRule(GlobalStateHolder<vector<T> > *someRuleActions, const boost::variant<unsigned int, std::string>& id) {
setLuaSideEffect();
auto rules = someRuleActions->getCopy();
if (auto str = boost::get<std::string>(&id)) {
@@ -227,12 +238,93 @@ static std::vector<T> getTopRules(const std::vector<T>& rules, unsigned int top)
return results;
}
+template<typename T>
+static LuaArray<T> toLuaArray(std::vector<T>&& rules)
+{
+ LuaArray<T> results;
+ results.reserve(rules.size());
+
+ size_t pos = 1;
+ for (auto& rule : rules) {
+ results.emplace_back(pos, std::move(rule));
+ pos++;
+ }
+
+ return results;
+}
+
+template <typename T>
+static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<int, std::string>& selector)
+{
+ if (auto str = boost::get<std::string>(&selector)) {
+ /* let's see if this a UUID */
+ try {
+ const auto uuid = getUniqueID(*str);
+ for (const auto& rule : rules) {
+ if (rule.d_id == uuid) {
+ return rule;
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ /* a name, then */
+ for (const auto& rule : rules) {
+ if (rule.d_name == *str) {
+ return rule;
+ }
+ }
+ }
+ }
+ else if (auto pos = boost::get<int>(&selector)) {
+ /* this will throw a std::out_of_range exception if the
+ supplied position is out of bounds, this is fine */
+ return rules.at(*pos);
+ }
+ return boost::none;
+}
+
+namespace
+{
+std::shared_ptr<DNSRule> qnameSuffixRule(const boost::variant<const SuffixMatchNode&, std::string, const LuaArray<std::string>> names, boost::optional<bool> quiet)
+{
+ if (names.type() == typeid(string)) {
+ SuffixMatchNode smn;
+ smn.add(DNSName(*boost::get<std::string>(&names)));
+ return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+ }
+
+ if (names.type() == typeid(LuaArray<std::string>)) {
+ SuffixMatchNode smn;
+ for (const auto& str : *boost::get<const LuaArray<std::string>>(&names)) {
+ smn.add(DNSName(str.second));
+ }
+ return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+ }
+
+ const auto& smn = *boost::get<const SuffixMatchNode&>(&names);
+ return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
+}
+}
+
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaRules(LuaContext& luaCtx)
{
- luaCtx.writeFunction("makeRule", makeRule);
+ luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr<DNSRule> {
+ return makeRule(var, "makeRule");
+ });
luaCtx.registerFunction<string(std::shared_ptr<DNSRule>::*)()const>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); });
+ luaCtx.registerFunction<uint64_t(std::shared_ptr<DNSRule>::*)()const>("getMatches", [](const std::shared_ptr<DNSRule>& rule) { return rule->d_matches.load(); });
+
+ luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistRuleAction::*)()const>("getSelector", [](const DNSDistRuleAction& rule) { return rule.d_rule; });
+
+ luaCtx.registerFunction<std::shared_ptr<DNSAction>(DNSDistRuleAction::*)()const>("getAction", [](const DNSDistRuleAction& rule) { return rule.d_action; });
+
+ luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistResponseRuleAction::*)()const>("getSelector", [](const DNSDistResponseRuleAction& rule) { return rule.d_rule; });
+
+ luaCtx.registerFunction<std::shared_ptr<DNSResponseAction>(DNSDistResponseRuleAction::*)()const>("getAction", [](const DNSDistResponseRuleAction& rule) { return rule.d_action; });
+
luaCtx.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) {
showRules(&g_respruleactions, vars);
});
@@ -323,17 +415,22 @@ void setupLuaRules(LuaContext& luaCtx)
for (const auto& pair : newruleactions) {
const auto& newruleaction = pair.second;
if (newruleaction->d_action) {
- auto rule = makeRule(newruleaction->d_rule);
+ auto rule = newruleaction->d_rule;
gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder});
}
}
});
});
+ luaCtx.writeFunction("getRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistRuleAction> {
+ auto rules = g_ruleactions.getLocal();
+ return getRuleFromSelector(*rules, selector);
+ });
+
luaCtx.writeFunction("getTopRules", [](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
auto rules = g_ruleactions.getLocal();
- return getTopRules(*rules, (top ? *top : 10));
+ return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
});
luaCtx.writeFunction("topRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -342,10 +439,15 @@ void setupLuaRules(LuaContext& luaCtx)
return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
});
+ luaCtx.writeFunction("getCacheHitResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+ auto rules = g_cachehitrespruleactions.getLocal();
+ return getRuleFromSelector(*rules, selector);
+ });
+
luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
auto rules = g_cachehitrespruleactions.getLocal();
- return getTopRules(*rules, (top ? *top : 10));
+ return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
});
luaCtx.writeFunction("topCacheHitResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -354,10 +456,15 @@ void setupLuaRules(LuaContext& luaCtx)
return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
});
+ luaCtx.writeFunction("getCacheInsertedResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+ auto rules = g_cacheInsertedRespRuleActions.getLocal();
+ return getRuleFromSelector(*rules, selector);
+ });
+
luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
auto rules = g_cacheInsertedRespRuleActions.getLocal();
- return getTopRules(*rules, (top ? *top : 10));
+ return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
});
luaCtx.writeFunction("topCacheInsertedResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -366,10 +473,15 @@ void setupLuaRules(LuaContext& luaCtx)
return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
});
+ luaCtx.writeFunction("getResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+ auto rules = g_respruleactions.getLocal();
+ return getRuleFromSelector(*rules, selector);
+ });
+
luaCtx.writeFunction("getTopResponseRules", [](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
auto rules = g_respruleactions.getLocal();
- return getTopRules(*rules, (top ? *top : 10));
+ return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
});
luaCtx.writeFunction("topResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -378,10 +490,15 @@ void setupLuaRules(LuaContext& luaCtx)
return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars);
});
+ luaCtx.writeFunction("getSelfAnsweredResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> {
+ auto rules = g_selfansweredrespruleactions.getLocal();
+ return getRuleFromSelector(*rules, selector);
+ });
+
luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional<unsigned int> top) {
setLuaNoSideEffect();
auto rules = g_selfansweredrespruleactions.getLocal();
- return getTopRules(*rules, (top ? *top : 10));
+ return toLuaArray(getTopRules(*rules, (top ? *top : 10)));
});
luaCtx.writeFunction("topSelfAnsweredResponseRules", [](boost::optional<unsigned int> top, boost::optional<ruleparams_t> vars) {
@@ -427,13 +544,26 @@ void setupLuaRules(LuaContext& luaCtx)
return std::shared_ptr<DNSRule>(new SNIRule(name));
});
- luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) {
- return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false));
- });
+ luaCtx.writeFunction("SuffixMatchNodeRule", qnameSuffixRule);
- luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) {
+ luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant<const NetmaskGroup&, std::string, const LuaArray<std::string>> netmasks, boost::optional<bool> src, boost::optional<bool> quiet) {
+ if (netmasks.type() == typeid(string)) {
+ NetmaskGroup nmg;
+ nmg.addMask(*boost::get<std::string>(&netmasks));
return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
- });
+ }
+
+ if (netmasks.type() == typeid(LuaArray<std::string>)) {
+ NetmaskGroup nmg;
+ for (const auto& str : *boost::get<const LuaArray<std::string>>(&netmasks)) {
+ nmg.addMask(str.second);
+ }
+ return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
+ }
+
+ const auto& nmg = *boost::get<const NetmaskGroup&>(&netmasks);
+ return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false));
+ });
luaCtx.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<unsigned int> times_, boost::optional<string> suffix_) {
setLuaNoSideEffect();
@@ -447,9 +577,9 @@ void setupLuaRules(LuaContext& luaCtx)
items.reserve(1000);
for (int n = 0; n < 1000; ++n) {
struct item i;
- i.ids.qname = DNSName(std::to_string(random()));
+ i.ids.qname = DNSName(std::to_string(dns_random_uint32()));
i.ids.qname += suffix;
- i.ids.qtype = random() % 0xff;
+ i.ids.qtype = dns_random(0xff);
i.ids.qclass = QClass::IN;
i.ids.protocol = dnsdist::Protocol::DoUDP;
i.ids.origRemote = ComboAddress("127.0.0.1");
@@ -472,7 +602,7 @@ void setupLuaRules(LuaContext& luaCtx)
}
}
double udiff = sw.udiff();
- g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str();
+ g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f us\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str();
});
@@ -488,6 +618,8 @@ void setupLuaRules(LuaContext& luaCtx)
return std::shared_ptr<DNSRule>(new QNameRule(DNSName(qname)));
});
+ luaCtx.writeFunction("QNameSuffixRule", qnameSuffixRule);
+
luaCtx.writeFunction("QTypeRule", [](boost::variant<unsigned int, std::string> str) {
uint16_t qtype;
if (auto dir = boost::get<unsigned int>(&str)) {
@@ -596,7 +728,7 @@ void setupLuaRules(LuaContext& luaCtx)
});
luaCtx.writeFunction("TagRule", [](const std::string& tag, boost::optional<std::string> value) {
- return std::shared_ptr<DNSRule>(new TagRule(tag, value));
+ return std::shared_ptr<DNSRule>(new TagRule(tag, std::move(value)));
});
luaCtx.writeFunction("TimedIPSetRule", []() {
@@ -653,10 +785,14 @@ void setupLuaRules(LuaContext& luaCtx)
});
luaCtx.writeFunction("LuaFFIPerThreadRule", [](const std::string& code) {
- return std::shared_ptr<DNSRule>(new LuaFFIPerThreadRule(code));
- });
+ return std::shared_ptr<DNSRule>(new LuaFFIPerThreadRule(code));
+ });
luaCtx.writeFunction("ProxyProtocolValueRule", [](uint8_t type, boost::optional<std::string> value) {
- return std::shared_ptr<DNSRule>(new ProxyProtocolValueRule(type, value));
+ return std::shared_ptr<DNSRule>(new ProxyProtocolValueRule(type, std::move(value)));
+ });
+
+ luaCtx.writeFunction("PayloadSizeRule", [](const std::string& comparison, uint16_t size) {
+ return std::shared_ptr<DNSRule>(new PayloadSizeRule(comparison, size));
});
}
diff --git a/dnsdist-lua-vars.cc b/dnsdist-lua-vars.cc
index 265568f..89927b7 100644
--- a/dnsdist-lua-vars.cc
+++ b/dnsdist-lua-vars.cc
@@ -51,6 +51,7 @@ void setupLuaVars(LuaContext& luaCtx)
{"Drop", (int)DNSResponseAction::Action::Drop },
{"HeaderModify", (int)DNSResponseAction::Action::HeaderModify },
{"ServFail", (int)DNSResponseAction::Action::ServFail },
+ {"Truncate", (int)DNSResponseAction::Action::Truncate },
{"None", (int)DNSResponseAction::Action::None }
});
diff --git a/dnsdist-lua.cc b/dnsdist-lua.cc
index fa1b8b6..73a8567 100644
--- a/dnsdist-lua.cc
+++ b/dnsdist-lua.cc
@@ -21,6 +21,7 @@
*/
#include <cstdint>
+#include <cstdio>
#include <dirent.h>
#include <fstream>
#include <cinttypes>
@@ -39,11 +40,14 @@
#include "dnsdist-carbon.hh"
#include "dnsdist-concurrent-connections.hh"
#include "dnsdist-console.hh"
+#include "dnsdist-crypto.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-discovery.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-lua-hooks.hh"
+#include "xsk.hh"
#ifdef LUAJIT_VERSION
#include "dnsdist-lua-ffi.hh"
#endif /* LUAJIT_VERSION */
@@ -57,8 +61,10 @@
#include "dnsdist-web.hh"
#include "base64.hh"
+#include "coverage.hh"
+#include "doh.hh"
+#include "doq-common.hh"
#include "dolog.hh"
-#include "sodcrypto.hh"
#include "threadname.hh"
#ifdef HAVE_LIBSSL
@@ -107,14 +113,15 @@ void resetLuaSideEffect()
g_noLuaSideEffect = boost::logic::indeterminate;
}
-using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>>>;
+using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>, std::shared_ptr<XskSocket>>>;
-static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections)
+static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections, bool& enableProxyProtocol)
{
if (vars) {
LuaArray<int> setCpus;
getOptionalValue<bool>(vars, "reusePort", reusePort);
+ getOptionalValue<bool>(vars, "enableProxyProtocol", enableProxyProtocol);
getOptionalValue<int>(vars, "tcpFastOpenQueueSize", tcpFastOpenQueueSize);
getOptionalValue<int>(vars, "tcpListenQueueSize", tcpListenQueueSize);
getOptionalValue<int>(vars, "maxConcurrentTCPConnections", tcpMaxConcurrentConnections);
@@ -127,9 +134,19 @@ static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePo
}
}
}
+#ifdef HAVE_XSK
+static void parseXskVars(boost::optional<localbind_t>& vars, std::shared_ptr<XskSocket>& socket)
+{
+ if (!vars) {
+ return;
+ }
-#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
-static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<TLSCertKeyPair>& pairs, boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, LuaTypeOrArrayOf<std::string> keyFiles)
+ getOptionalValue<std::shared_ptr<XskSocket>>(vars, "xskSocket", socket);
+}
+#endif /* HAVE_XSK */
+
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) || defined(HAVE_DNS_OVER_QUIC)
+static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<TLSCertKeyPair>& pairs, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles)
{
if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
auto certFile = boost::get<std::string>(certFiles);
@@ -225,6 +242,7 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
getOptionalValue<bool>(vars, "enableRenegotiation", config.d_enableRenegotiation);
getOptionalValue<bool>(vars, "tlsAsyncMode", config.d_asyncMode);
getOptionalValue<bool>(vars, "ktls", config.d_ktls);
+ getOptionalValue<bool>(vars, "readAhead", config.d_readAhead);
}
#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
@@ -256,7 +274,7 @@ static void LuaThread(const std::string& code)
// maybe offer more than `void`
auto func = lua->readVariable<boost::optional<std::function<void(std::string cmd, LuaAssociativeTable<std::string> data)>>>("threadmessage");
if (func) {
- func.get()(cmd, data);
+ func.get()(std::move(cmd), std::move(data));
}
else {
errlog("Lua thread called submitToMainThread but no threadmessage receiver is defined");
@@ -280,13 +298,6 @@ static void LuaThread(const std::string& code)
}
}
-#ifdef COVERAGE
-extern "C"
-{
- void __gcov_dump(void);
-}
-#endif
-
static bool checkConfigurationTime(const std::string& name)
{
if (!g_configurationDone) {
@@ -297,9 +308,101 @@ static bool checkConfigurationTime(const std::string& name)
return false;
}
+using newserver_t = LuaAssociativeTable<boost::variant<bool, std::string, LuaArray<std::string>, LuaArray<std::shared_ptr<XskSocket>>, DownstreamState::checkfunc_t>>;
+
+static void handleNewServerHealthCheckParameters(boost::optional<newserver_t>& vars, DownstreamState::Config& config)
+{
+ std::string valueStr;
+
+ if (getOptionalValue<std::string>(vars, "checkInterval", valueStr) > 0) {
+ config.checkInterval = static_cast<unsigned int>(std::stoul(valueStr));
+ }
+
+ if (getOptionalValue<std::string>(vars, "healthCheckMode", valueStr) > 0) {
+ const auto& mode = valueStr;
+ if (pdns_iequals(mode, "auto")) {
+ config.availability = DownstreamState::Availability::Auto;
+ }
+ else if (pdns_iequals(mode, "lazy")) {
+ config.availability = DownstreamState::Availability::Lazy;
+ }
+ else if (pdns_iequals(mode, "up")) {
+ config.availability = DownstreamState::Availability::Up;
+ }
+ else if (pdns_iequals(mode, "down")) {
+ config.availability = DownstreamState::Availability::Down;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'healthCheckMode' on 'newServer'", mode);
+ }
+ }
+
+ if (getOptionalValue<std::string>(vars, "checkName", valueStr) > 0) {
+ config.checkName = DNSName(valueStr);
+ }
+
+ getOptionalValue<std::string>(vars, "checkType", config.checkType);
+ getOptionalIntegerValue("newServer", vars, "checkClass", config.checkClass);
+ getOptionalValue<DownstreamState::checkfunc_t>(vars, "checkFunction", config.checkFunction);
+ getOptionalIntegerValue("newServer", vars, "checkTimeout", config.checkTimeout);
+ getOptionalValue<bool>(vars, "checkTCP", config.d_tcpCheck);
+ getOptionalValue<bool>(vars, "setCD", config.setCD);
+ getOptionalValue<bool>(vars, "mustResolve", config.mustResolve);
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckSampleSize", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckSampleSize", value);
+ config.d_lazyHealthCheckSampleSize = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMinSampleCount", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckMinSampleCount", value);
+ config.d_lazyHealthCheckMinSampleCount = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckThreshold", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckThreshold", value, std::numeric_limits<uint8_t>::max());
+ config.d_lazyHealthCheckThreshold = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckFailedInterval", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckFailedInterval", value);
+ config.d_lazyHealthCheckFailedInterval = value;
+ }
+
+ getOptionalValue<bool>(vars, "lazyHealthCheckUseExponentialBackOff", config.d_lazyHealthCheckUseExponentialBackOff);
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMaxBackOff", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckMaxBackOff", value);
+ config.d_lazyHealthCheckMaxBackOff = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMode", valueStr) > 0) {
+ const auto& mode = valueStr;
+ if (pdns_iequals(mode, "TimeoutOnly")) {
+ config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOnly;
+ }
+ else if (pdns_iequals(mode, "TimeoutOrServFail")) {
+ config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOrServFail;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'lazyHealthCheckMode' on 'newServer'", mode);
+ }
+ }
+
+ getOptionalValue<bool>(vars, "lazyHealthCheckWhenUpgraded", config.d_upgradeToLazyHealthChecks);
+
+ getOptionalIntegerValue("newServer", vars, "maxCheckFailures", config.maxCheckFailures);
+ getOptionalIntegerValue("newServer", vars, "rise", config.minRiseSuccesses);
+}
+
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
{
- typedef LuaAssociativeTable<boost::variant<bool, std::string, LuaArray<std::string>, DownstreamState::checkfunc_t>> newserver_t;
luaCtx.writeFunction("inClientStartup", [client]() {
return client && !g_configurationDone;
});
@@ -395,9 +498,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
getOptionalIntegerValue("newServer", vars, "tcpSendTimeout", config.tcpSendTimeout);
getOptionalIntegerValue("newServer", vars, "tcpRecvTimeout", config.tcpRecvTimeout);
- if (getOptionalValue<std::string>(vars, "checkInterval", valueStr) > 0) {
- config.checkInterval = static_cast<unsigned int>(std::stoul(valueStr));
- }
+ handleNewServerHealthCheckParameters(vars, config);
bool fastOpen{false};
if (getOptionalValue<bool>(vars, "tcpFastOpen", fastOpen) > 0) {
@@ -419,92 +520,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
config.id = boost::uuids::string_generator()(valueStr);
}
- if (getOptionalValue<std::string>(vars, "healthCheckMode", valueStr) > 0) {
- const auto& mode = valueStr;
- if (pdns_iequals(mode, "auto")) {
- config.availability = DownstreamState::Availability::Auto;
- }
- else if (pdns_iequals(mode, "lazy")) {
- config.availability = DownstreamState::Availability::Lazy;
- }
- else if (pdns_iequals(mode, "up")) {
- config.availability = DownstreamState::Availability::Up;
- }
- else if (pdns_iequals(mode, "down")) {
- config.availability = DownstreamState::Availability::Down;
- }
- else {
- warnlog("Ignoring unknown value '%s' for 'healthCheckMode' on 'newServer'", mode);
- }
- }
-
- if (getOptionalValue<std::string>(vars, "checkName", valueStr) > 0) {
- config.checkName = DNSName(valueStr);
- }
-
- getOptionalValue<std::string>(vars, "checkType", config.checkType);
- getOptionalIntegerValue("newServer", vars, "checkClass", config.checkClass);
- getOptionalValue<DownstreamState::checkfunc_t>(vars, "checkFunction", config.checkFunction);
- getOptionalIntegerValue("newServer", vars, "checkTimeout", config.checkTimeout);
- getOptionalValue<bool>(vars, "checkTCP", config.d_tcpCheck);
- getOptionalValue<bool>(vars, "setCD", config.setCD);
- getOptionalValue<bool>(vars, "mustResolve", config.mustResolve);
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckSampleSize", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckSampleSize", value);
- config.d_lazyHealthCheckSampleSize = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMinSampleCount", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckMinSampleCount", value);
- config.d_lazyHealthCheckMinSampleCount = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckThreshold", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckThreshold", value, std::numeric_limits<uint8_t>::max());
- config.d_lazyHealthCheckThreshold = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckFailedInterval", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckFailedInterval", value);
- config.d_lazyHealthCheckFailedInterval = value;
- }
-
- getOptionalValue<bool>(vars, "lazyHealthCheckUseExponentialBackOff", config.d_lazyHealthCheckUseExponentialBackOff);
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMaxBackOff", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckMaxBackOff", value);
- config.d_lazyHealthCheckMaxBackOff = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMode", valueStr) > 0) {
- const auto& mode = valueStr;
- if (pdns_iequals(mode, "TimeoutOnly")) {
- config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOnly;
- }
- else if (pdns_iequals(mode, "TimeoutOrServFail")) {
- config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOrServFail;
- }
- else {
- warnlog("Ignoring unknown value '%s' for 'lazyHealthCheckMode' on 'newServer'", mode);
- }
- }
-
- getOptionalValue<bool>(vars, "lazyHealthCheckWhenUpgraded", config.d_upgradeToLazyHealthChecks);
-
getOptionalValue<bool>(vars, "useClientSubnet", config.useECS);
getOptionalValue<bool>(vars, "useProxyProtocol", config.useProxyProtocol);
+ getOptionalValue<bool>(vars, "proxyProtocolAdvertiseTLS", config.d_proxyProtocolAdvertiseTLS);
getOptionalValue<bool>(vars, "disableZeroScope", config.disableZeroScope);
getOptionalValue<bool>(vars, "ipBindAddrNoPort", config.ipBindAddrNoPort);
getOptionalIntegerValue("newServer", vars, "addXPF", config.xpfRRCode);
- getOptionalIntegerValue("newServer", vars, "maxCheckFailures", config.maxCheckFailures);
- getOptionalIntegerValue("newServer", vars, "rise", config.minRiseSuccesses);
getOptionalValue<bool>(vars, "reconnectOnUp", config.reconnectOnUp);
@@ -547,8 +569,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
tlsCtx = getTLSContext(config.d_tlsParams);
if (getOptionalValue<std::string>(vars, "dohPath", valueStr) > 0) {
-#ifndef HAVE_NGHTTP2
- throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but nghttp2 support is not available");
+#if !defined(HAVE_DNS_OVER_HTTPS) || !defined(HAVE_NGHTTP2)
+ throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but it is not available");
#endif
serverPort = 443;
@@ -618,10 +640,39 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
// create but don't connect the socket in client or check-config modes
auto ret = std::make_shared<DownstreamState>(std::move(config), std::move(tlsCtx), !(client || configCheck));
- if (!(client || configCheck)) {
+#ifdef HAVE_XSK
+ LuaArray<std::shared_ptr<XskSocket>> luaXskSockets;
+ if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
+ if (g_configurationDone) {
+ throw std::runtime_error("Adding a server with xsk at runtime is not supported");
+ }
+ std::vector<std::shared_ptr<XskSocket>> xskSockets;
+ for (auto& socket : luaXskSockets) {
+ xskSockets.push_back(socket.second);
+ }
+ ret->registerXsk(xskSockets);
+ std::string mac;
+ if (getOptionalValue<std::string>(vars, "MACAddr", mac) > 0) {
+ auto* addr = &ret->d_config.destMACAddr[0];
+ sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr + 1, addr + 2, addr + 3, addr + 4, addr + 5);
+ }
+ else {
+ mac = getMACAddress(ret->d_config.remote);
+ if (mac.size() != ret->d_config.destMACAddr.size()) {
+ throw runtime_error("Field 'MACAddr' is not set on 'newServer' directive for '" + ret->d_config.remote.toStringWithPort() + "' and cannot be retrieved from the system either!");
+ }
+ memcpy(ret->d_config.destMACAddr.data(), mac.data(), ret->d_config.destMACAddr.size());
+ }
+ infolog("Added downstream server %s via XSK in %s mode", ret->d_config.remote.toStringWithPort(), xskSockets.at(0)->getXDPMode());
+ }
+ else if (!(client || configCheck)) {
infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
}
-
+#else /* HAVE_XSK */
+ if (!(client || configCheck)) {
+ infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
if (autoUpgrade && ret->getProtocol() != dnsdist::Protocol::DoT && ret->getProtocol() != dnsdist::Protocol::DoH) {
dnsdist::ServiceDiscovery::addUpgradeableServer(ret, upgradeInterval, upgradePool, upgradeDoHKey, keepAfterUpgrade);
}
@@ -725,10 +776,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> cpus;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
-
- checkAllParametersConsumed("setLocal", vars);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
try {
ComboAddress loc(addr, 53);
@@ -743,8 +793,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
// only works pre-startup, so no sync necessary
- g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
@@ -755,7 +805,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
tcpCS->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
+#ifdef HAVE_XSK
+ std::shared_ptr<XskSocket> socket;
+ parseXskVars(vars, socket);
+ if (socket) {
+ udpCS->xskInfo = XskWorker::create();
+ udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ socket->addWorker(udpCS->xskInfo);
+ socket->addWorkerRoute(udpCS->xskInfo, loc);
+ vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
+ g_frontends.push_back(std::move(udpCS));
g_frontends.push_back(std::move(tcpCS));
+
+ checkAllParametersConsumed("setLocal", vars);
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -777,15 +841,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> cpus;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
- checkAllParametersConsumed("addLocal", vars);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
try {
ComboAddress loc(addr, 53);
// only works pre-startup, so no sync necessary
- g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
@@ -795,7 +859,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (tcpMaxConcurrentConnections > 0) {
tcpCS->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
+#ifdef HAVE_XSK
+ std::shared_ptr<XskSocket> socket;
+ parseXskVars(vars, socket);
+ if (socket) {
+ udpCS->xskInfo = XskWorker::create();
+ udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ socket->addWorker(udpCS->xskInfo);
+ socket->addWorkerRoute(udpCS->xskInfo, loc);
+ vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
+ g_frontends.push_back(std::move(udpCS));
g_frontends.push_back(std::move(tcpCS));
+
+ checkAllParametersConsumed("addLocal", vars);
}
catch (std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -843,12 +921,11 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("showACL", []() {
setLuaNoSideEffect();
- vector<string> vec;
-
- g_ACL.getLocal()->toStringVector(&vec);
+ auto aclEntries = g_ACL.getLocal()->toStringVector();
- for (const auto& s : vec)
- g_outputBuffer += s + "\n";
+ for (const auto& entry : aclEntries) {
+ g_outputBuffer += entry + "\n";
+ }
});
luaCtx.writeFunction("shutdown", []() {
@@ -864,9 +941,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
g_tlslocals.clear();
g_rings.clear();
#endif /* 0 */
-#ifdef COVERAGE
- __gcov_dump();
-#endif
+ pdns::coverage::dumpCoverageData();
_exit(0);
});
@@ -942,7 +1017,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
LuaArray<std::shared_ptr<DownstreamState>> ret;
int count = 1;
for (const auto& s : g_dstates.getCopy()) {
- ret.push_back(make_pair(count++, s));
+ ret.emplace_back(count++, s);
}
return ret;
});
@@ -1107,23 +1182,22 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
g_consoleEnabled = true;
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
if (g_configurationDone && g_consoleKey.empty()) {
warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
}
#endif
try {
- int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
- SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
- SBind(sock, local);
- SListen(sock, 5);
- auto launch = [sock, local]() {
- thread t(controlThread, sock, local);
- t.detach();
+ auto sock = std::make_shared<Socket>(local.sin4.sin_family, SOCK_STREAM, 0);
+ sock->bind(local, true);
+ sock->listen(5);
+ auto launch = [sock = std::move(sock), local]() {
+ std::thread consoleControlThread(controlThread, sock, local);
+ consoleControlThread.detach();
};
if (g_launchWork) {
- g_launchWork->push_back(launch);
+ g_launchWork->emplace_back(std::move(launch));
}
else {
launch();
@@ -1137,8 +1211,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("addConsoleACL", [](const std::string& netmask) {
setLuaSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium not libcrypto support has been enabled is not secure, and will result in cleartext communications");
#endif
g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
@@ -1147,8 +1221,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("setConsoleACL", [](LuaTypeOrArrayOf<std::string> inp) {
setLuaSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
#endif
NetmaskGroup nmg;
@@ -1165,15 +1239,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("showConsoleACL", []() {
setLuaNoSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
#endif
- vector<string> vec;
- g_consoleACL.getLocal()->toStringVector(&vec);
+ auto aclEntries = g_consoleACL.getLocal()->toStringVector();
- for (const auto& s : vec) {
- g_outputBuffer += s + "\n";
+ for (const auto& entry : aclEntries) {
+ g_outputBuffer += entry + "\n";
}
});
@@ -1212,20 +1285,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled = enabled; });
luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
- g_qcount.filter = func;
+ g_qcount.filter = std::move(func);
});
luaCtx.writeFunction("makeKey", []() {
setLuaNoSideEffect();
- g_outputBuffer = "setKey(" + newKey() + ")\n";
+ g_outputBuffer = "setKey(" + dnsdist::crypto::authenticated::newKey() + ")\n";
});
luaCtx.writeFunction("setKey", [](const std::string& key) {
if (!g_configurationDone && !g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
return; // but later setKeys() trump the -k value again
}
-#ifndef HAVE_LIBSODIUM
- warnlog("Calling setKey() while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Calling setKey() while neither libsodium nor libcrypto support has been enabled is not secure, and will result in cleartext communications");
#endif
setLuaSideEffect();
@@ -1235,7 +1308,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
errlog("%s", g_outputBuffer);
}
else
- g_consoleKey = newkey;
+ g_consoleKey = std::move(newkey);
});
luaCtx.writeFunction("clearConsoleHistory", []() {
@@ -1244,7 +1317,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("testCrypto", [](boost::optional<string> optTestMsg) {
setLuaNoSideEffect();
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
try {
string testmsg;
@@ -1255,22 +1328,25 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
testmsg = "testStringForCryptoTests";
}
- SodiumNonce sn, sn2;
- sn.init();
- sn2 = sn;
- string encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
- string decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
+ dnsdist::crypto::authenticated::Nonce nonce1;
+ dnsdist::crypto::authenticated::Nonce nonce2;
+ nonce1.init();
+ nonce2 = nonce1;
+ string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
+ string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
- sn.increment();
- sn2.increment();
+ nonce1.increment();
+ nonce2.increment();
- encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
- decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
+ encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
+ decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
- if (testmsg == decrypted)
+ if (testmsg == decrypted) {
g_outputBuffer = "Everything is ok!\n";
- else
+ }
+ else {
g_outputBuffer = "Crypto failed.. (the decoded value does not match the cleartext one)\n";
+ }
}
catch (const std::exception& e) {
g_outputBuffer = "Crypto failed: " + std::string(e.what()) + "\n";
@@ -1337,6 +1413,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamMaxIdleConnectionsPerBackend(max);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setMaxIdleDoHConnectionsPerDownstream", [](uint64_t max) {
setDoHDownstreamMaxIdleConnectionsPerBackend(max);
});
@@ -1347,6 +1424,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
g_outgoingDoHWorkerThreads = workers;
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
@@ -1421,6 +1499,58 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
});
});
+ luaCtx.writeFunction("getDynamicBlocks", []() {
+ setLuaNoSideEffect();
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ LuaAssociativeTable<DynBlock> entries;
+ auto fullCopy = g_dynblockNMG.getCopy();
+ for (const auto& blockPair : fullCopy) {
+ const auto& requestor = blockPair.first;
+ if (!(now < blockPair.second.until)) {
+ continue;
+ }
+ auto entry = blockPair.second;
+ if (g_defaultBPFFilter && entry.bpf) {
+ entry.blocks += g_defaultBPFFilter->getHits(requestor.getNetwork());
+ }
+ if (entry.action == DNSAction::Action::None) {
+ entry.action = g_dynBlockAction;
+ }
+ entries.emplace(requestor.toString(), std::move(entry));
+ }
+ return entries;
+ });
+
+ luaCtx.writeFunction("getDynamicBlocksSMT", []() {
+ setLuaNoSideEffect();
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ LuaAssociativeTable<DynBlock> entries;
+ auto fullCopy = g_dynblockSMT.getCopy();
+ fullCopy.visit([&now, &entries](const SuffixMatchTree<DynBlock>& node) {
+ if (!(now < node.d_value.until)) {
+ return;
+ }
+ auto entry = node.d_value;
+ string key("empty");
+ if (!entry.domain.empty()) {
+ key = entry.domain.toString();
+ }
+ if (entry.action == DNSAction::Action::None) {
+ entry.action = g_dynBlockAction;
+ }
+ entries.emplace(std::move(key), std::move(entry));
+ });
+ return entries;
+ });
+
luaCtx.writeFunction("clearDynBlocks", []() {
setLuaSideEffect();
nmts_t nmg;
@@ -1466,61 +1596,87 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (!got || expired) {
warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg);
}
- slow.insert(requestor).second = db;
+ slow.insert(requestor).second = std::move(db);
}
g_dynblockNMG.setState(slow);
});
+ luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
+ if (!checkConfigurationTime("setDynBlocksAction")) {
+ return;
+ }
+ if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
+ g_dynBlockAction = action;
+ }
+ else {
+ errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
+ g_outputBuffer = "Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!\n";
+ }
+ });
+#endif /* DISABLE_DEPRECATED_DYNBLOCK */
+
luaCtx.writeFunction("addDynBlockSMT",
[](const LuaArray<std::string>& names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
if (names.empty()) {
return;
}
setLuaSideEffect();
- auto slow = g_dynblockSMT.getCopy();
- struct timespec until, now;
+ struct timespec now
+ {
+ };
gettime(&now);
- until = now;
- int actualSeconds = seconds ? *seconds : 10;
- until.tv_sec += actualSeconds;
+ unsigned int actualSeconds = seconds ? *seconds : 10;
+ bool needUpdate = false;
+ auto slow = g_dynblockSMT.getCopy();
for (const auto& capair : names) {
- unsigned int count = 0;
DNSName domain(capair.second);
domain.makeUsLowerCase();
- auto got = slow.lookup(domain);
- bool expired = false;
- if (got) {
- if (until < got->until) // had a longer policy
- continue;
- if (now < got->until) // only inherit count on fresh query we are extending
- count = got->blocks;
- else
- expired = true;
+
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, msg, actualSeconds, action ? *action : DNSAction::Action::None, false)) {
+ needUpdate = true;
}
+ }
- DynBlock db{msg, until, domain, (action ? *action : DNSAction::Action::None)};
- db.blocks = count;
- if (!got || expired)
- warnlog("Inserting dynamic block for %s for %d seconds: %s", domain, actualSeconds, msg);
- slow.add(domain, std::move(db));
+ if (needUpdate) {
+ g_dynblockSMT.setState(slow);
}
- g_dynblockSMT.setState(slow);
});
- luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
- if (!checkConfigurationTime("setDynBlocksAction")) {
- return;
- }
- if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
- g_dynBlockAction = action;
- }
- else {
- errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
- g_outputBuffer = "Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!\n";
- }
- });
-#endif /* DISABLE_DEPRECATED_DYNBLOCK */
+ luaCtx.writeFunction("addDynamicBlock",
+ [](const boost::variant<ComboAddress, std::string>& clientIP, const std::string& msg, const boost::optional<DNSAction::Action> action, const boost::optional<int> seconds, boost::optional<uint8_t> clientIPMask, boost::optional<uint8_t> clientIPPortMask) {
+ setLuaSideEffect();
+
+ ComboAddress clientIPCA;
+ if (clientIP.type() == typeid(ComboAddress)) {
+ clientIPCA = boost::get<ComboAddress>(clientIP);
+ }
+ else {
+ const auto& clientIPStr = boost::get<std::string>(clientIP);
+ try {
+ clientIPCA = ComboAddress(clientIPStr);
+ }
+ catch (const std::exception& exp) {
+ errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.what());
+ return;
+ }
+ catch (const PDNSException& exp) {
+ errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.reason);
+ return;
+ }
+ }
+ AddressAndPortRange target(clientIPCA, clientIPMask ? *clientIPMask : (clientIPCA.isIPv4() ? 32 : 128), clientIPPortMask ? *clientIPPortMask : 0);
+ unsigned int actualSeconds = seconds ? *seconds : 10;
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+ auto slow = g_dynblockNMG.getCopy();
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, false)) {
+ g_dynblockNMG.setState(slow);
+ }
+ });
luaCtx.writeFunction("setDynBlocksPurgeInterval", [](uint64_t interval) {
DynBlockMaintenance::s_expiredDynBlocksPurgeInterval = interval;
@@ -1540,14 +1696,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<DNSCryptContext::CertKeyPaths> certKeys;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
checkAllParametersConsumed("addDNSCryptBind", vars);
if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
auto certFile = boost::get<std::string>(certFiles);
auto keyFile = boost::get<std::string>(keyFiles);
- certKeys.push_back({certFile, keyFile});
+ certKeys.push_back({std::move(certFile), std::move(keyFile)});
}
else if (certFiles.type() == typeid(LuaArray<std::string>) && keyFiles.type() == typeid(LuaArray<std::string>)) {
auto certFilesVect = boost::get<LuaArray<std::string>>(certFiles);
@@ -1573,29 +1730,29 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
- auto cs = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dnscryptCtx = ctx;
+ auto clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dnscryptCtx = ctx;
g_dnsCryptLocals.push_back(ctx);
- g_frontends.push_back(std::move(cs));
+ g_frontends.push_back(std::move(clientState));
/* TCP */
- cs = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dnscryptCtx = ctx;
+ clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dnscryptCtx = std::move(ctx);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (maxInFlightQueriesPerConn > 0) {
- cs->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
+ clientState->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
}
if (tcpMaxConcurrentConnections > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(cs));
+ g_frontends.push_back(std::move(clientState));
}
- catch (std::exception& e) {
- errlog(e.what());
- g_outputBuffer = "Error: " + string(e.what()) + "\n";
+ catch (const std::exception& e) {
+ errlog("Error during addDNSCryptBind() processing: %s", e.what());
+ g_outputBuffer = "Error during addDNSCryptBind() processing: " + string(e.what()) + "\n";
}
});
@@ -1683,7 +1840,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
const auto localPools = g_pools.getCopy();
for (const auto& entry : localPools) {
const string& name = entry.first;
- ret.push_back(make_pair(count++, name));
+ ret.emplace_back(count++, name);
}
return ret;
});
@@ -1707,12 +1864,33 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
try {
auto stream = std::ofstream(dest.c_str());
- g_verboseStream = std::move(stream);
+ dnsdist::logging::LoggingConfiguration::setVerboseStream(std::move(stream));
}
catch (const std::exception& e) {
errlog("Error while opening the verbose logging destination file %s: %s", dest, e.what());
}
});
+ luaCtx.writeFunction("setStructuredLogging", [](bool enable, boost::optional<LuaAssociativeTable<std::string>> options) {
+ std::string levelPrefix;
+ std::string timeFormat;
+ if (options) {
+ getOptionalValue<std::string>(options, "levelPrefix", levelPrefix);
+ if (getOptionalValue<std::string>(options, "timeFormat", timeFormat) == 1) {
+ if (timeFormat == "numeric") {
+ dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::Numeric);
+ }
+ else if (timeFormat == "ISO8601") {
+ dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601);
+ }
+ else {
+ warnlog("Unknown value '%s' to setStructuredLogging's 'timeFormat' parameter", timeFormat);
+ }
+ }
+ checkAllParametersConsumed("setStructuredLogging", options);
+ }
+
+ dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, levelPrefix);
+ });
luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint64_t ttl) {
checkParameterBound("setStaleCacheEntriesTTL", ttl, std::numeric_limits<uint32_t>::max());
@@ -1783,12 +1961,12 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (!checkConfigurationTime("setDefaultBPFFilter")) {
return;
}
- g_defaultBPFFilter = bpf;
+ g_defaultBPFFilter = std::move(bpf);
});
luaCtx.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
if (dbpf) {
- g_dynBPFFilters.push_back(dbpf);
+ g_dynBPFFilters.push_back(std::move(dbpf));
}
});
@@ -1830,10 +2008,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setLuaNoSideEffect();
std::unordered_map<string, uint64_t> res;
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
res.reserve(entries->size());
for (const auto& entry : *entries) {
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
res[entry.d_name] = (*val)->load();
}
}
@@ -1864,33 +2042,30 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
return;
}
- DIR* dirp;
- struct dirent* ent;
std::vector<std::string> files;
- if (!(dirp = opendir(dirname.c_str()))) {
- errlog("Error opening the included directory %s!", dirname.c_str());
- g_outputBuffer = "Error opening the included directory " + dirname + "!";
- return;
- }
-
- while ((ent = readdir(dirp)) != NULL) {
- if (ent->d_name[0] == '.') {
- continue;
+ auto directoryError = pdns::visit_directory(dirname, [&dirname, &files]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ if (boost::starts_with(name, ".")) {
+ return true;
}
-
- if (boost::ends_with(ent->d_name, ".conf")) {
+ if (boost::ends_with(name, ".conf")) {
std::ostringstream namebuf;
- namebuf << dirname << "/" << ent->d_name;
-
- if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) {
- continue;
+ namebuf << dirname << "/" << name;
+ struct stat fileStat
+ {
+ };
+ if (stat(namebuf.str().c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
+ files.push_back(namebuf.str());
}
-
- files.push_back(namebuf.str());
}
+ return true;
+ });
+
+ if (directoryError) {
+ errlog("Error opening included directory: %s!", *directoryError);
+ g_outputBuffer = "Error opening included directory: " + *directoryError + "!";
+ return;
}
- closedir(dirp);
std::sort(files.begin(), files.end());
g_included = true;
@@ -2051,9 +2226,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#endif /* HAVE_NET_SNMP */
#ifndef DISABLE_POLICIES_BINDINGS
- luaCtx.writeFunction("setServerPolicy", [](const ServerPolicy& policy) {
+ luaCtx.writeFunction("setServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy) {
setLuaSideEffect();
- g_policy.setState(policy);
+ g_policy.setState(*policy);
});
luaCtx.writeFunction("setServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy) {
@@ -2078,24 +2253,24 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
g_outputBuffer = g_policy.getLocal()->getName() + "\n";
});
- luaCtx.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, const string& pool) {
+ luaCtx.writeFunction("setPoolServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(policy));
+ setPoolPolicy(localPools, pool, policy);
g_pools.setState(localPools);
});
luaCtx.writeFunction("setPoolServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy, true}));
+ setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
g_pools.setState(localPools);
});
luaCtx.writeFunction("setPoolServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy}));
+ setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
g_pools.setState(localPools);
});
@@ -2125,11 +2300,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamCleanupInterval(interval);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setDoHDownstreamCleanupInterval", [](uint64_t interval) {
setLuaSideEffect();
checkParameterBound("setDoHDownstreamCleanupInterval", interval);
setDoHDownstreamCleanupInterval(interval);
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setTCPDownstreamMaxIdleTime", [](uint64_t max) {
setLuaSideEffect();
@@ -2137,11 +2314,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamMaxIdleTime(max);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setDoHDownstreamMaxIdleTime", [](uint64_t max) {
setLuaSideEffect();
checkParameterBound("setDoHDownstreamMaxIdleTime", max);
setDoHDownstreamMaxIdleTime(max);
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
g_logConsoleConnections = enabled;
@@ -2221,7 +2400,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#ifndef DISABLE_SECPOLL
luaCtx.writeFunction("showSecurityStatus", []() {
setLuaNoSideEffect();
- g_outputBuffer = std::to_string(g_stats.securityStatus) + "\n";
+ g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
});
luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
@@ -2320,7 +2499,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
password = boost::get<const string>((*opts)["password"]);
}
}
- result = std::make_shared<TLSCertKeyPair>(TLSCertKeyPair{cert, key, password});
+ result = std::make_shared<TLSCertKeyPair>(cert, std::move(key), std::move(password));
#endif
return result;
});
@@ -2336,31 +2515,61 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setLuaSideEffect();
auto frontend = std::make_shared<DOHFrontend>();
+ if (getOptionalValue<std::string>(vars, "library", frontend->d_library) == 0) {
+#ifdef HAVE_NGHTTP2
+ frontend->d_library = "nghttp2";
+#else /* HAVE_NGHTTP2 */
+ frontend->d_library = "h2o";
+#endif /* HAVE_NGHTTP2 */
+ }
+ if (frontend->d_library == "h2o") {
+#ifdef HAVE_LIBH2OEVLOOP
+ frontend = std::make_shared<H2ODOHFrontend>();
+ // we _really_ need to set it again, as we just replaced the generic frontend by a new one
+ frontend->d_library = "h2o";
+#else /* HAVE_LIBH2OEVLOOP */
+ errlog("DOH bind %s is configured to use libh2o but the library is not available", addr);
+ return;
+#endif /* HAVE_LIBH2OEVLOOP */
+ }
+ else if (frontend->d_library == "nghttp2") {
+#ifndef HAVE_NGHTTP2
+ errlog("DOH bind %s is configured to use nghttp2 but the library is not available", addr);
+ return;
+#endif /* HAVE_NGHTTP2 */
+ }
+ else {
+ errlog("DOH bind %s is configured to use an unknown library ('%s')", addr, frontend->d_library);
+ return;
+ }
+
+ bool useTLS = true;
if (certFiles && !certFiles->empty()) {
- if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_tlsConfig.d_certKeyPairs, *certFiles, *keyFiles)) {
+ if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, *certFiles, *keyFiles)) {
return;
}
- frontend->d_local = ComboAddress(addr, 443);
+ frontend->d_tlsContext.d_addr = ComboAddress(addr, 443);
}
else {
- frontend->d_local = ComboAddress(addr, 80);
- infolog("No certificate provided for DoH endpoint %s, running in DNS over HTTP mode instead of DNS over HTTPS", frontend->d_local.toStringWithPort());
+ frontend->d_tlsContext.d_addr = ComboAddress(addr, 80);
+ infolog("No certificate provided for DoH endpoint %s, running in DNS over HTTP mode instead of DNS over HTTPS", frontend->d_tlsContext.d_addr.toStringWithPort());
+ useTLS = false;
}
if (urls) {
if (urls->type() == typeid(std::string)) {
- frontend->d_urls.push_back(boost::get<std::string>(*urls));
+ frontend->d_urls.insert(boost::get<std::string>(*urls));
}
else if (urls->type() == typeid(LuaArray<std::string>)) {
auto urlsVect = boost::get<LuaArray<std::string>>(*urls);
for (const auto& p : urlsVect) {
- frontend->d_urls.push_back(p.second);
+ frontend->d_urls.insert(p.second);
}
}
}
else {
- frontend->d_urls = {"/dns-query"};
+ frontend->d_urls.insert("/dns-query");
}
bool reusePort = false;
@@ -2371,16 +2580,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
if (vars) {
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
getOptionalValue<int>(vars, "idleTimeout", frontend->d_idleTimeout);
getOptionalValue<std::string>(vars, "serverTokens", frontend->d_serverTokens);
+ getOptionalValue<std::string>(vars, "provider", frontend->d_tlsContext.d_provider);
+ boost::algorithm::to_lower(frontend->d_tlsContext.d_provider);
+ getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_tlsContext.d_proxyProtocolOutsideTLS);
LuaAssociativeTable<std::string> customResponseHeaders;
if (getOptionalValue<decltype(customResponseHeaders)>(vars, "customResponseHeaders", customResponseHeaders) > 0) {
for (auto const& headerMap : customResponseHeaders) {
- std::pair<std::string, std::string> headerResponse = std::make_pair(boost::to_lower_copy(headerMap.first), headerMap.second);
+ auto headerResponse = std::pair(boost::to_lower_copy(headerMap.first), headerMap.second);
frontend->d_customResponseHeaders.insert(headerResponse);
}
}
@@ -2388,6 +2601,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
getOptionalValue<bool>(vars, "sendCacheControlHeaders", frontend->d_sendCacheControlHeaders);
getOptionalValue<bool>(vars, "keepIncomingHeaders", frontend->d_keepIncomingHeaders);
getOptionalValue<bool>(vars, "trustForwardedForHeader", frontend->d_trustForwardedForHeader);
+ getOptionalValue<bool>(vars, "earlyACLDrop", frontend->d_earlyACLDrop);
getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
getOptionalValue<bool>(vars, "exactPathMatching", frontend->d_exactPathMatching);
@@ -2405,7 +2619,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
}
- parseTLSConfig(frontend->d_tlsConfig, "addDOHLocal", vars);
+ parseTLSConfig(frontend->d_tlsContext.d_tlsConfig, "addDOHLocal", vars);
bool ignoreTLSConfigurationErrors = false;
if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
@@ -2413,7 +2627,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
// and properly ignore the frontend before actually launching it
try {
std::map<int, std::string> ocspResponses = {};
- auto ctx = libssl_init_server_context(frontend->d_tlsConfig, ocspResponses);
+ auto ctx = libssl_init_server_context(frontend->d_tlsContext.d_tlsConfig, ocspResponses);
}
catch (const std::runtime_error& e) {
errlog("Ignoring DoH frontend: '%s'", e.what());
@@ -2423,23 +2637,246 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
checkAllParametersConsumed("addDOHLocal", vars);
}
+
+ if (useTLS && frontend->d_library == "nghttp2") {
+ if (!frontend->d_tlsContext.d_provider.empty()) {
+ vinfolog("Loading TLS provider '%s'", frontend->d_tlsContext.d_provider);
+ }
+ else {
+#ifdef HAVE_LIBSSL
+ const std::string provider("openssl");
+#else
+ const std::string provider("gnutls");
+#endif
+ vinfolog("Loading default TLS provider '%s'", provider);
+ }
+ }
+
g_dohlocals.push_back(frontend);
- auto cs = std::make_unique<ClientState>(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dohFrontend = frontend;
- cs->d_additionalAddresses = std::move(additionalAddresses);
+ auto clientState = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dohFrontend = std::move(frontend);
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (tcpMaxConcurrentConnections > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(cs));
-#else
+ g_frontends.push_back(std::move(clientState));
+#else /* HAVE_DNS_OVER_HTTPS */
throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
+#endif /* HAVE_DNS_OVER_HTTPS */
+ });
+
+ // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
+ luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ if (client) {
+ return;
+ }
+#ifdef HAVE_DNS_OVER_HTTP3
+ if (!checkConfigurationTime("addDOH3Local")) {
+ return;
+ }
+ setLuaSideEffect();
+
+ auto frontend = std::make_shared<DOH3Frontend>();
+ if (!loadTLSCertificateAndKeys("addDOH3Local", frontend->d_quicheParams.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ return;
+ }
+ frontend->d_local = ComboAddress(addr, 443);
+
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ int tcpListenQueueSize = 0;
+ uint64_t maxInFlightQueriesPerConn = 0;
+ uint64_t tcpMaxConcurrentConnections = 0;
+ std::string interface;
+ std::set<int> cpus;
+ std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
+
+ if (vars) {
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
+ if (maxInFlightQueriesPerConn > 0) {
+ frontend->d_quicheParams.d_maxInFlight = maxInFlightQueriesPerConn;
+ }
+ getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
+ getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
+ getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ {
+ std::string valueStr;
+ if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
+ if (dnsdist::doq::s_available_cc_algorithms.count(valueStr) > 0) {
+ frontend->d_quicheParams.d_ccAlgo = valueStr;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'congestionControlAlgo' on 'addDOH3Local'", valueStr);
+ }
+ }
+ }
+ parseTLSConfig(frontend->d_quicheParams.d_tlsConfig, "addDOH3Local", vars);
+
+ bool ignoreTLSConfigurationErrors = false;
+ if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
+ // we are asked to try to load the certificates so we can return a potential error
+ // and properly ignore the frontend before actually launching it
+ try {
+ std::map<int, std::string> ocspResponses = {};
+ auto ctx = libssl_init_server_context(frontend->d_quicheParams.d_tlsConfig, ocspResponses);
+ }
+ catch (const std::runtime_error& e) {
+ errlog("Ignoring DoH3 frontend: '%s'", e.what());
+ return;
+ }
+ }
+
+ checkAllParametersConsumed("addDOH3Local", vars);
+ }
+ g_doh3locals.push_back(frontend);
+ auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->doh3Frontend = frontend;
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
+
+ g_frontends.push_back(std::move(clientState));
+#else
+ throw std::runtime_error("addDOH3Local() called but DNS over HTTP/3 support is not present!");
#endif
});
+ // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
+ luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ if (client) {
+ return;
+ }
+#ifdef HAVE_DNS_OVER_QUIC
+ if (!checkConfigurationTime("addDOQLocal")) {
+ return;
+ }
+ setLuaSideEffect();
+
+ auto frontend = std::make_shared<DOQFrontend>();
+ if (!loadTLSCertificateAndKeys("addDOQLocal", frontend->d_quicheParams.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ return;
+ }
+ frontend->d_local = ComboAddress(addr, 853);
+
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ int tcpListenQueueSize = 0;
+ uint64_t maxInFlightQueriesPerConn = 0;
+ uint64_t tcpMaxConcurrentConnections = 0;
+ std::string interface;
+ std::set<int> cpus;
+ std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
+
+ if (vars) {
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
+ if (maxInFlightQueriesPerConn > 0) {
+ frontend->d_quicheParams.d_maxInFlight = maxInFlightQueriesPerConn;
+ }
+ getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
+ getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
+ getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ {
+ std::string valueStr;
+ if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
+ if (dnsdist::doq::s_available_cc_algorithms.count(valueStr) > 0) {
+ frontend->d_quicheParams.d_ccAlgo = std::move(valueStr);
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'congestionControlAlgo' on 'addDOQLocal'", valueStr);
+ }
+ }
+ }
+ parseTLSConfig(frontend->d_quicheParams.d_tlsConfig, "addDOQLocal", vars);
+
+ bool ignoreTLSConfigurationErrors = false;
+ if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
+ // we are asked to try to load the certificates so we can return a potential error
+ // and properly ignore the frontend before actually launching it
+ try {
+ std::map<int, std::string> ocspResponses = {};
+ auto ctx = libssl_init_server_context(frontend->d_quicheParams.d_tlsConfig, ocspResponses);
+ }
+ catch (const std::runtime_error& e) {
+ errlog("Ignoring DoQ frontend: '%s'", e.what());
+ return;
+ }
+ }
+
+ checkAllParametersConsumed("addDOQLocal", vars);
+ }
+ g_doqlocals.push_back(frontend);
+ auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->doqFrontend = std::move(frontend);
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
+
+ g_frontends.push_back(std::move(clientState));
+#else
+ throw std::runtime_error("addDOQLocal() called but DNS over QUIC support is not present!");
+#endif
+ });
+
+ luaCtx.writeFunction("showDOQFrontends", []() {
+#ifdef HAVE_DNS_OVER_QUIC
+ setLuaNoSideEffect();
+ try {
+ ostringstream ret;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
+ size_t counter = 0;
+ for (const auto& ctx : g_doqlocals) {
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doqUnsupportedVersionErrors % ctx->d_doqInvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
+ counter++;
+ }
+ g_outputBuffer = ret.str();
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = e.what();
+ throw;
+ }
+#else
+ g_outputBuffer = "DNS over QUIC support is not present!\n";
+#endif
+ });
+
+#ifdef HAVE_DNS_OVER_QUIC
+ luaCtx.writeFunction("getDOQFrontend", [client](uint64_t index) {
+ std::shared_ptr<DOQFrontend> result = nullptr;
+ if (client) {
+ return result;
+ }
+ setLuaNoSideEffect();
+ try {
+ if (index < g_doqlocals.size()) {
+ result = g_doqlocals.at(index);
+ }
+ else {
+ errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, g_doqlocals.size());
+ g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doqlocals.size()) + " frontend(s)\n";
+ }
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = "Error while trying to get DOQ frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+ errlog("Error while trying to get DOQ frontend with index %d: %s\n", index, string(e.what()));
+ }
+ return result;
+ });
+
+ luaCtx.writeFunction("getDOQFrontendCount", []() {
+ setLuaNoSideEffect();
+ return g_doqlocals.size();
+ });
+
+ luaCtx.registerFunction<void (std::shared_ptr<DOQFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOQFrontend>& frontend) {
+ if (frontend != nullptr) {
+ frontend->reloadCertificates();
+ }
+ });
+#endif
+
luaCtx.writeFunction("showDOHFrontends", []() {
#ifdef HAVE_DNS_OVER_HTTPS
setLuaNoSideEffect();
@@ -2449,7 +2886,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
size_t counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http2Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http2Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
counter++;
}
g_outputBuffer = ret.str();
@@ -2463,6 +2900,64 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#endif
});
+ luaCtx.writeFunction("showDOH3Frontends", []() {
+#ifdef HAVE_DNS_OVER_HTTP3
+ setLuaNoSideEffect();
+ try {
+ ostringstream ret;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
+ size_t counter = 0;
+ for (const auto& ctx : g_doh3locals) {
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doh3UnsupportedVersionErrors % ctx->d_doh3InvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
+ counter++;
+ }
+ g_outputBuffer = ret.str();
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = e.what();
+ throw;
+ }
+#else
+ g_outputBuffer = "DNS over HTTP3 support is not present!\n";
+#endif
+ });
+
+#ifdef HAVE_DNS_OVER_HTTP3
+ luaCtx.writeFunction("getDOH3Frontend", [client](uint64_t index) {
+ std::shared_ptr<DOH3Frontend> result = nullptr;
+ if (client) {
+ return result;
+ }
+ setLuaNoSideEffect();
+ try {
+ if (index < g_doh3locals.size()) {
+ result = g_doh3locals.at(index);
+ }
+ else {
+ errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, g_doh3locals.size());
+ g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doh3locals.size()) + " frontend(s)\n";
+ }
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = "Error while trying to get DOH3 frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+ errlog("Error while trying to get DOH3 frontend with index %d: %s\n", index, string(e.what()));
+ }
+ return result;
+ });
+
+ luaCtx.writeFunction("getDOH3FrontendCount", []() {
+ setLuaNoSideEffect();
+ return g_doh3locals.size();
+ });
+
+ luaCtx.registerFunction<void (std::shared_ptr<DOH3Frontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOH3Frontend>& frontend) {
+ if (frontend != nullptr) {
+ frontend->reloadCertificates();
+ }
+ });
+#endif
+
luaCtx.writeFunction("showDOHResponseCodes", []() {
#ifdef HAVE_DNS_OVER_HTTPS
setLuaNoSideEffect();
@@ -2473,7 +2968,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
size_t counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
counter++;
}
g_outputBuffer += ret.str();
@@ -2483,7 +2978,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
counter++;
}
g_outputBuffer += ret.str();
@@ -2509,13 +3004,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_dohlocals.at(index);
}
else {
- errlog("Error: trying to get DOH frontend with index %zu but we only have %zu frontend(s)\n", index, g_dohlocals.size());
+ errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, g_dohlocals.size());
g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get DOH frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get DOH frontend with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over HTTPS support is not present!\n";
@@ -2528,7 +3023,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
return g_dohlocals.size();
});
- luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
+ luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOHFrontend>& frontend) {
if (frontend != nullptr) {
frontend->reloadCertificates();
}
@@ -2537,7 +3032,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<DOHFrontend> frontend, boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles) {
#ifdef HAVE_DNS_OVER_HTTPS
if (frontend != nullptr) {
- if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
frontend->reloadCertificates();
}
}
@@ -2579,7 +3074,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
setLuaSideEffect();
- shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
+ auto frontend = std::make_shared<TLSFrontend>(TLSFrontend::ALPN::DoT);
if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
return;
}
@@ -2592,12 +3087,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
if (vars) {
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns, enableProxyProtocol);
getOptionalValue<std::string>(vars, "provider", frontend->d_provider);
boost::algorithm::to_lower(frontend->d_provider);
+ getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_proxyProtocolOutsideTLS);
LuaArray<std::string> addresses;
if (getOptionalValue<decltype(addresses)>(vars, "additionalAddresses", addresses) > 0) {
@@ -2639,27 +3136,28 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
else {
#ifdef HAVE_LIBSSL
- vinfolog("Loading default TLS provider 'openssl'");
+ const std::string provider("openssl");
#else
- vinfolog("Loading default TLS provider 'gnutls'");
+ const std::string provider("gnutls");
#endif
+ vinfolog("Loading default TLS provider '%s'", provider);
}
// only works pre-startup, so no sync necessary
- auto cs = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->tlsFrontend = frontend;
- cs->d_additionalAddresses = std::move(additionalAddresses);
+ auto clientState = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->tlsFrontend = frontend;
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (maxInFlightQueriesPerConn > 0) {
- cs->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
+ clientState->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
}
if (tcpMaxConcurrentConns > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
}
- g_tlslocals.push_back(cs->tlsFrontend);
- g_frontends.push_back(std::move(cs));
+ g_tlslocals.push_back(clientState->tlsFrontend);
+ g_frontends.push_back(std::move(clientState));
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -2702,13 +3200,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_tlslocals.at(index)->getContext();
}
else {
- errlog("Error: trying to get TLS context with index %zu but we only have %zu context(s)\n", index, g_tlslocals.size());
+ errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, g_tlslocals.size());
g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get TLS context with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get TLS context with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get TLS context with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
@@ -2725,13 +3223,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_tlslocals.at(index);
}
else {
- errlog("Error: trying to get TLS frontend with index %zu but we only have %zu frontends\n", index, g_tlslocals.size());
+ errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, g_tlslocals.size());
g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get TLS frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get TLS frontend with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get TLS frontend with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
@@ -2783,7 +3281,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
});
- luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<TLSFrontend>& frontend) {
+ luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<TLSFrontend>& frontend) {
if (frontend == nullptr) {
return;
}
@@ -2819,6 +3317,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
frontend->dohFrontend->reloadCertificates();
}
#endif /* HAVE_DNS_OVER_HTTPS */
+#ifdef HAVE_DNS_OVER_QUIC
+ if (frontend->doqFrontend) {
+ frontend->doqFrontend->reloadCertificates();
+ }
+#endif /* HAVE_DNS_OVER_QUIC */
+#ifdef HAVE_DNS_OVER_HTTP3
+ if (frontend->doh3Frontend) {
+ frontend->doh3Frontend->reloadCertificates();
+ }
+#endif /* HAVE_DNS_OVER_HTTP3 */
}
catch (const std::exception& e) {
errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
@@ -2918,7 +3426,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName ? std::optional<std::string>(*customName) : std::nullopt);
if (result) {
g_outputBuffer += *result + "\n";
- errlog("%s", *result);
+ errlog("Error in declareMetric: %s", *result);
return false;
}
return true;
@@ -2927,7 +3435,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::incrementCustomCounter(name, step ? *step : 1);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in incMetric: %s", *errorStr);
return static_cast<uint64_t>(0);
}
return std::get<uint64_t>(result);
@@ -2936,7 +3444,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::decrementCustomCounter(name, step ? *step : 1);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in decMetric: %s", *errorStr);
return static_cast<uint64_t>(0);
}
return std::get<uint64_t>(result);
@@ -2945,7 +3453,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::setCustomGauge(name, value);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in setMetric: %s", *errorStr);
return 0.;
}
return std::get<double>(result);
@@ -2954,7 +3462,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::getCustomMetric(name);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in getMetric: %s", *errorStr);
return 0.;
}
return std::get<double>(result);
@@ -2969,7 +3477,7 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
setupLuaActions(luaCtx);
setupLuaConfig(luaCtx, client, configCheck);
- setupLuaBindings(luaCtx, client);
+ setupLuaBindings(luaCtx, client, configCheck);
setupLuaBindingsDNSCrypt(luaCtx, client);
setupLuaBindingsDNSParser(luaCtx);
setupLuaBindingsDNSQuestion(luaCtx);
@@ -2978,6 +3486,7 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
setupLuaBindingsPacketCache(luaCtx, client);
setupLuaBindingsProtoBuf(luaCtx, client, configCheck);
setupLuaBindingsRings(luaCtx, client);
+ dnsdist::lua::hooks::setupLuaHooks(luaCtx);
setupLuaInspection(luaCtx);
setupLuaRules(luaCtx);
setupLuaVars(luaCtx);
diff --git a/dnsdist-lua.hh b/dnsdist-lua.hh
index 61a021f..5c35c3f 100644
--- a/dnsdist-lua.hh
+++ b/dnsdist-lua.hh
@@ -33,7 +33,7 @@ struct ResponseConfig
boost::optional<bool> setRA{boost::none};
uint32_t ttl{60};
};
-void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config);
+void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config);
class SpoofAction : public DNSAction
{
@@ -62,11 +62,11 @@ public:
{
}
- SpoofAction(const vector<std::string>& raws): d_rawResponses(raws)
+ SpoofAction(const vector<std::string>& raws, std::optional<uint16_t> typeForAny): d_rawResponses(raws), d_rawTypeForAny(typeForAny)
{
}
- DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override;
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, string* ruleresult) const override;
string toString() const override
{
@@ -84,15 +84,20 @@ public:
return ret;
}
+ [[nodiscard]] ResponseConfig& getResponseConfig()
+ {
+ return d_responseConfig;
+ }
- ResponseConfig d_responseConfig;
private:
+ ResponseConfig d_responseConfig;
static thread_local std::default_random_engine t_randomEngine;
std::vector<ComboAddress> d_addrs;
std::unordered_set<uint16_t> d_types;
std::vector<std::string> d_rawResponses;
PacketBuffer d_raw;
DNSName d_cname;
+ std::optional<uint16_t> d_rawTypeForAny{};
};
class LimitTTLResponseAction : public DNSResponseAction, public boost::noncopyable
@@ -156,17 +161,18 @@ template <class T> using LuaArray = std::vector<std::pair<int, T>>;
template <class T> using LuaAssociativeTable = std::unordered_map<std::string, T>;
template <class T> using LuaTypeOrArrayOf = boost::variant<T, LuaArray<T>>;
-using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
using luaruleparams_t = LuaAssociativeTable<std::string>;
using nmts_t = NetmaskTree<DynBlock, AddressAndPortRange>;
-std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var);
+using luadnsrule_t = boost::variant<string, LuaArray<std::string>, std::shared_ptr<DNSRule>, DNSName, LuaArray<DNSName>>;
+std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom);
+
void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uuid& uuid, std::string& name, uint64_t& creationOrder);
void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max());
vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
void setupLuaActions(LuaContext& luaCtx);
-void setupLuaBindings(LuaContext& luaCtx, bool client);
+void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck);
void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client);
void setupLuaBindingsDNSParser(LuaContext& luaCtx);
void setupLuaBindingsDNSQuestion(LuaContext& luaCtx);
diff --git a/dnsdist-metrics.cc b/dnsdist-metrics.cc
index 5de4bfc..d47236e 100644
--- a/dnsdist-metrics.cc
+++ b/dnsdist-metrics.cc
@@ -28,26 +28,165 @@
namespace dnsdist::metrics
{
+struct MutableCounter
+{
+ MutableCounter() = default;
+ MutableCounter(const MutableCounter&) = delete;
+ MutableCounter(MutableCounter&& rhs) noexcept :
+ d_value(rhs.d_value.load())
+ {
+ }
+ MutableCounter& operator=(const MutableCounter&) = delete;
+ MutableCounter& operator=(MutableCounter&& rhs) noexcept
+ {
+ d_value = rhs.d_value.load();
+ return *this;
+ }
+ ~MutableCounter() = default;
+
+ mutable stat_t d_value{0};
+};
+
+struct MutableGauge
+{
+ MutableGauge() = default;
+ MutableGauge(const MutableGauge&) = delete;
+ MutableGauge(MutableGauge&& rhs) noexcept :
+ d_value(rhs.d_value.load())
+ {
+ }
+ MutableGauge& operator=(const MutableGauge&) = delete;
+ MutableGauge& operator=(MutableGauge&& rhs) noexcept
+ {
+ d_value = rhs.d_value.load();
+ return *this;
+ }
+ ~MutableGauge() = default;
+
+ mutable pdns::stat_t_trait<double> d_value{0};
+};
+
+static SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> s_customCounters;
+static SharedLockGuarded<std::map<std::string, MutableGauge, std::less<>>> s_customGauges;
+
+Stats::Stats() :
+ entries{std::vector<EntryPair>{
+ {"responses", &responses},
+ {"servfail-responses", &servfailResponses},
+ {"queries", &queries},
+ {"frontend-nxdomain", &frontendNXDomain},
+ {"frontend-servfail", &frontendServFail},
+ {"frontend-noerror", &frontendNoError},
+ {"acl-drops", &aclDrops},
+ {"rule-drop", &ruleDrop},
+ {"rule-nxdomain", &ruleNXDomain},
+ {"rule-refused", &ruleRefused},
+ {"rule-servfail", &ruleServFail},
+ {"rule-truncated", &ruleTruncated},
+ {"self-answered", &selfAnswered},
+ {"downstream-timeouts", &downstreamTimeouts},
+ {"downstream-send-errors", &downstreamSendErrors},
+ {"trunc-failures", &truncFail},
+ {"no-policy", &noPolicy},
+ {"latency0-1", &latency0_1},
+ {"latency1-10", &latency1_10},
+ {"latency10-50", &latency10_50},
+ {"latency50-100", &latency50_100},
+ {"latency100-1000", &latency100_1000},
+ {"latency-slow", &latencySlow},
+ {"latency-avg100", &latencyAvg100},
+ {"latency-avg1000", &latencyAvg1000},
+ {"latency-avg10000", &latencyAvg10000},
+ {"latency-avg1000000", &latencyAvg1000000},
+ {"latency-tcp-avg100", &latencyTCPAvg100},
+ {"latency-tcp-avg1000", &latencyTCPAvg1000},
+ {"latency-tcp-avg10000", &latencyTCPAvg10000},
+ {"latency-tcp-avg1000000", &latencyTCPAvg1000000},
+ {"latency-dot-avg100", &latencyDoTAvg100},
+ {"latency-dot-avg1000", &latencyDoTAvg1000},
+ {"latency-dot-avg10000", &latencyDoTAvg10000},
+ {"latency-dot-avg1000000", &latencyDoTAvg1000000},
+ {"latency-doh-avg100", &latencyDoHAvg100},
+ {"latency-doh-avg1000", &latencyDoHAvg1000},
+ {"latency-doh-avg10000", &latencyDoHAvg10000},
+ {"latency-doh-avg1000000", &latencyDoHAvg1000000},
+ {"latency-doq-avg100", &latencyDoQAvg100},
+ {"latency-doq-avg1000", &latencyDoQAvg1000},
+ {"latency-doq-avg10000", &latencyDoQAvg10000},
+ {"latency-doq-avg1000000", &latencyDoQAvg1000000},
+ {"latency-doh3-avg100", &latencyDoH3Avg100},
+ {"latency-doh3-avg1000", &latencyDoH3Avg1000},
+ {"latency-doh3-avg10000", &latencyDoH3Avg10000},
+ {"latency-doh3-avg1000000", &latencyDoH3Avg1000000},
+ {"uptime", uptimeOfProcess},
+ {"real-memory-usage", getRealMemoryUsage},
+ {"special-memory-usage", getSpecialMemoryUsage},
+ {"udp-in-errors", [](const std::string&) { return udpErrorStats("udp-in-errors"); }},
+ {"udp-noport-errors", [](const std::string&) { return udpErrorStats("udp-noport-errors"); }},
+ {"udp-recvbuf-errors", [](const std::string&) { return udpErrorStats("udp-recvbuf-errors"); }},
+ {"udp-sndbuf-errors", [](const std::string&) { return udpErrorStats("udp-sndbuf-errors"); }},
+ {"udp-in-csum-errors", [](const std::string&) { return udpErrorStats("udp-in-csum-errors"); }},
+ {"udp6-in-errors", [](const std::string&) { return udp6ErrorStats("udp6-in-errors"); }},
+ {"udp6-recvbuf-errors", [](const std::string&) { return udp6ErrorStats("udp6-recvbuf-errors"); }},
+ {"udp6-sndbuf-errors", [](const std::string&) { return udp6ErrorStats("udp6-sndbuf-errors"); }},
+ {"udp6-noport-errors", [](const std::string&) { return udp6ErrorStats("udp6-noport-errors"); }},
+ {"udp6-in-csum-errors", [](const std::string&) { return udp6ErrorStats("udp6-in-csum-errors"); }},
+ {"tcp-listen-overflows", [](const std::string&) { return tcpErrorStats("ListenOverflows"); }},
+ {"noncompliant-queries", &nonCompliantQueries},
+ {"noncompliant-responses", &nonCompliantResponses},
+ {"proxy-protocol-invalid", &proxyProtocolInvalid},
+ {"rdqueries", &rdQueries},
+ {"empty-queries", &emptyQueries},
+ {"cache-hits", &cacheHits},
+ {"cache-misses", &cacheMisses},
+ {"cpu-iowait", getCPUIOWait},
+ {"cpu-steal", getCPUSteal},
+ {"cpu-sys-msec", getCPUTimeSystem},
+ {"cpu-user-msec", getCPUTimeUser},
+ {"fd-usage", getOpenFileDescriptors},
+ {"dyn-blocked", &dynBlocked},
+ {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
+ {"security-status", &securityStatus},
+ {"doh-query-pipe-full", &dohQueryPipeFull},
+ {"doh-response-pipe-full", &dohResponsePipeFull},
+ {"doq-response-pipe-full", &doqResponsePipeFull},
+ {"doh3-response-pipe-full", &doh3ResponsePipeFull},
+ {"outgoing-doh-query-pipe-full", &outgoingDoHQueryPipeFull},
+ {"tcp-query-pipe-full", &tcpQueryPipeFull},
+ {"tcp-cross-protocol-query-pipe-full", &tcpCrossProtocolQueryPipeFull},
+ {"tcp-cross-protocol-response-pipe-full", &tcpCrossProtocolResponsePipeFull},
+ // Latency histogram
+ {"latency-sum", &latencySum},
+ {"latency-count", &latencyCount},
+ }}
+{
+}
+
+struct Stats g_stats;
+
std::optional<std::string> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName)
{
if (!std::regex_match(name, std::regex("^[a-z0-9-]+$"))) {
return std::string("Unable to declare metric '") + std::string(name) + std::string("': invalid name\n");
}
+ const std::string finalCustomName(customName ? *customName : "");
if (type == "counter") {
- auto customCounters = g_stats.customCounters.write_lock();
- auto itp = customCounters->insert({name, DNSDistStats::MutableCounter()});
+ auto customCounters = s_customCounters.write_lock();
+ auto itp = customCounters->insert({name, MutableCounter()});
if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customCounters)[name].d_value});
- addMetricDefinition(name, "counter", description, customName ? *customName : "");
+ g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customCounters)[name].d_value});
+ dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
+ addMetricDefinition(def);
}
}
else if (type == "gauge") {
- auto customGauges = g_stats.customGauges.write_lock();
- auto itp = customGauges->insert({name, DNSDistStats::MutableGauge()});
+ auto customGauges = s_customGauges.write_lock();
+ auto itp = customGauges->insert({name, MutableGauge()});
if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customGauges)[name].d_value});
- addMetricDefinition(name, "gauge", description, customName ? *customName : "");
+ g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customGauges)[name].d_value});
+ dnsdist::prometheus::PrometheusMetricDefinition def{name, type, description, finalCustomName};
+ addMetricDefinition(def);
}
}
else {
@@ -58,35 +197,29 @@ std::optional<std::string> declareCustomMetric(const std::string& name, const st
std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step)
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto metric = customCounters->find(name);
if (metric != customCounters->end()) {
- if (step) {
- metric->second.d_value += step;
- return metric->second.d_value.load();
- }
- return ++(metric->second.d_value);
+ metric->second.d_value += step;
+ return metric->second.d_value.load();
}
return std::string("Unable to increment custom metric '") + std::string(name) + "': no such metric";
}
std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step)
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto metric = customCounters->find(name);
if (metric != customCounters->end()) {
- if (step) {
- metric->second.d_value -= step;
- return metric->second.d_value.load();
- }
- return --(metric->second.d_value);
+ metric->second.d_value -= step;
+ return metric->second.d_value.load();
}
return std::string("Unable to decrement custom metric '") + std::string(name) + "': no such metric";
}
std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value)
{
- auto customGauges = g_stats.customGauges.read_lock();
+ auto customGauges = s_customGauges.read_lock();
auto metric = customGauges->find(name);
if (metric != customGauges->end()) {
metric->second.d_value = value;
@@ -99,14 +232,14 @@ std::variant<double, Error> setCustomGauge(const std::string_view& name, const d
std::variant<double, Error> getCustomMetric(const std::string_view& name)
{
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto counter = customCounters->find(name);
if (counter != customCounters->end()) {
return static_cast<double>(counter->second.d_value.load());
}
}
{
- auto customGauges = g_stats.customGauges.read_lock();
+ auto customGauges = s_customGauges.read_lock();
auto gauge = customGauges->find(name);
if (gauge != customGauges->end()) {
return gauge->second.d_value.load();
@@ -114,4 +247,5 @@ std::variant<double, Error> getCustomMetric(const std::string_view& name)
}
return std::string("Unable to get metric '") + std::string(name) + "': no such metric";
}
+
}
diff --git a/dnsdist-metrics.hh b/dnsdist-metrics.hh
index 753c9b9..8e899ce 100644
--- a/dnsdist-metrics.hh
+++ b/dnsdist-metrics.hh
@@ -27,6 +27,9 @@
#include <string_view>
#include <variant>
+#include "lock.hh"
+#include "stat_t.hh"
+
namespace dnsdist::metrics
{
using Error = std::string;
@@ -36,4 +39,64 @@ using Error = std::string;
[[nodiscard]] std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step);
[[nodiscard]] std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value);
[[nodiscard]] std::variant<double, Error> getCustomMetric(const std::string_view& name);
+
+using pdns::stat_t;
+
+struct Stats
+{
+ Stats();
+
+ stat_t responses{0};
+ stat_t servfailResponses{0};
+ stat_t queries{0};
+ stat_t frontendNXDomain{0};
+ stat_t frontendServFail{0};
+ stat_t frontendNoError{0};
+ stat_t nonCompliantQueries{0};
+ stat_t nonCompliantResponses{0};
+ stat_t rdQueries{0};
+ stat_t emptyQueries{0};
+ stat_t aclDrops{0};
+ stat_t dynBlocked{0};
+ stat_t ruleDrop{0};
+ stat_t ruleNXDomain{0};
+ stat_t ruleRefused{0};
+ stat_t ruleServFail{0};
+ stat_t ruleTruncated{0};
+ stat_t selfAnswered{0};
+ stat_t downstreamTimeouts{0};
+ stat_t downstreamSendErrors{0};
+ stat_t truncFail{0};
+ stat_t noPolicy{0};
+ stat_t cacheHits{0};
+ stat_t cacheMisses{0};
+ stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0}, latencySum{0}, latencyCount{0};
+ stat_t securityStatus{0};
+ stat_t dohQueryPipeFull{0};
+ stat_t dohResponsePipeFull{0};
+ stat_t doqResponsePipeFull{0};
+ stat_t doh3ResponsePipeFull{0};
+ stat_t outgoingDoHQueryPipeFull{0};
+ stat_t proxyProtocolInvalid{0};
+ stat_t tcpQueryPipeFull{0};
+ stat_t tcpCrossProtocolQueryPipeFull{0};
+ stat_t tcpCrossProtocolResponsePipeFull{0};
+ double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
+ double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
+ double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
+ double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
+ double latencyDoQAvg100{0}, latencyDoQAvg1000{0}, latencyDoQAvg10000{0}, latencyDoQAvg1000000{0};
+ double latencyDoH3Avg100{0}, latencyDoH3Avg1000{0}, latencyDoH3Avg10000{0}, latencyDoH3Avg1000000{0};
+ using statfunction_t = std::function<uint64_t(const std::string&)>;
+ using entry_t = std::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
+ struct EntryPair
+ {
+ std::string d_name;
+ entry_t d_value;
+ };
+
+ SharedLockGuarded<std::vector<EntryPair>> entries;
+};
+
+extern struct Stats g_stats;
}
diff --git a/dnsdist-nghttp2-in.cc b/dnsdist-nghttp2-in.cc
new file mode 100644
index 0000000..32dc254
--- /dev/null
+++ b/dnsdist-nghttp2-in.cc
@@ -0,0 +1,1187 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-dnsparser.hh"
+#include "dnsdist-doh-common.hh"
+#include "dnsdist-nghttp2-in.hh"
+#include "dnsdist-proxy-protocol.hh"
+#include "dnsparser.hh"
+
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+
+#if 0
+class IncomingDoHCrossProtocolContext : public CrossProtocolContext
+{
+public:
+ IncomingDoHCrossProtocolContext(IncomingHTTP2Connection::PendingQuery&& query, std::shared_ptr<IncomingHTTP2Connection> connection, IncomingHTTP2Connection::StreamID streamID): CrossProtocolContext(std::move(query.d_buffer)), d_connection(connection), d_query(std::move(query))
+ {
+ }
+
+ std::optional<std::string> getHTTPPath() const override
+ {
+ return d_query.d_path;
+ }
+
+ std::optional<std::string> getHTTPScheme() const override
+ {
+ return d_query.d_scheme;
+ }
+
+ std::optional<std::string> getHTTPHost() const override
+ {
+ return d_query.d_host;
+ }
+
+ std::optional<std::string> getHTTPQueryString() const override
+ {
+ return d_query.d_queryString;
+ }
+
+ std::optional<HeadersMap> getHTTPHeaders() const override
+ {
+ if (!d_query.d_headers) {
+ return std::nullopt;
+ }
+ return *d_query.d_headers;
+ }
+
+ void handleResponse(PacketBuffer&& response, InternalQueryState&& state) override
+ {
+ auto conn = d_connection.lock();
+ if (!conn) {
+ /* the connection has been closed in the meantime */
+ return;
+ }
+ }
+
+ void handleTimeout() override
+ {
+ auto conn = d_connection.lock();
+ if (!conn) {
+ /* the connection has been closed in the meantime */
+ return;
+ }
+ }
+
+ ~IncomingDoHCrossProtocolContext() override
+ {
+ }
+
+private:
+ std::weak_ptr<IncomingHTTP2Connection> d_connection;
+ IncomingHTTP2Connection::PendingQuery d_query;
+ IncomingHTTP2Connection::StreamID d_streamID{-1};
+};
+#endif
+
+class IncomingDoHCrossProtocolContext : public DOHUnitInterface
+{
+public:
+ IncomingDoHCrossProtocolContext(IncomingHTTP2Connection::PendingQuery&& query, const std::shared_ptr<IncomingHTTP2Connection>& connection, IncomingHTTP2Connection::StreamID streamID) :
+ d_connection(connection), d_query(std::move(query)), d_streamID(streamID)
+ {
+ }
+ IncomingDoHCrossProtocolContext(const IncomingDoHCrossProtocolContext&) = delete;
+ IncomingDoHCrossProtocolContext(IncomingDoHCrossProtocolContext&&) = delete;
+ IncomingDoHCrossProtocolContext& operator=(const IncomingDoHCrossProtocolContext&) = delete;
+ IncomingDoHCrossProtocolContext& operator=(IncomingDoHCrossProtocolContext&&) = delete;
+
+ ~IncomingDoHCrossProtocolContext() override = default;
+
+ [[nodiscard]] std::string getHTTPPath() const override
+ {
+ return d_query.d_path;
+ }
+
+ [[nodiscard]] const std::string& getHTTPScheme() const override
+ {
+ return d_query.d_scheme;
+ }
+
+ [[nodiscard]] const std::string& getHTTPHost() const override
+ {
+ return d_query.d_host;
+ }
+
+ [[nodiscard]] std::string getHTTPQueryString() const override
+ {
+ return d_query.d_queryString;
+ }
+
+ [[nodiscard]] const HeadersMap& getHTTPHeaders() const override
+ {
+ if (!d_query.d_headers) {
+ static const HeadersMap empty{};
+ return empty;
+ }
+ return *d_query.d_headers;
+ }
+
+ void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType = "") override
+ {
+ d_query.d_statusCode = statusCode;
+ d_query.d_response = std::move(body);
+ d_query.d_contentTypeOut = contentType;
+ }
+
+ void handleUDPResponse(PacketBuffer&& response, InternalQueryState&& state, const std::shared_ptr<DownstreamState>& downstream_) override
+ {
+ std::unique_ptr<DOHUnitInterface> unit(this);
+ auto conn = d_connection.lock();
+ if (!conn) {
+ /* the connection has been closed in the meantime */
+ return;
+ }
+
+ state.du = std::move(unit);
+ TCPResponse resp(std::move(response), std::move(state), nullptr, nullptr);
+ resp.d_ds = downstream_;
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+ conn->handleResponse(now, std::move(resp));
+ }
+
+ void handleTimeout() override
+ {
+ std::unique_ptr<DOHUnitInterface> unit(this);
+ auto conn = d_connection.lock();
+ if (!conn) {
+ /* the connection has been closed in the meantime */
+ return;
+ }
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+ TCPResponse resp;
+ resp.d_idstate.d_streamID = d_streamID;
+ conn->notifyIOError(now, std::move(resp));
+ }
+
+ std::weak_ptr<IncomingHTTP2Connection> d_connection;
+ IncomingHTTP2Connection::PendingQuery d_query;
+ IncomingHTTP2Connection::StreamID d_streamID{-1};
+};
+
+void IncomingHTTP2Connection::handleResponse(const struct timeval& now, TCPResponse&& response)
+{
+ if (std::this_thread::get_id() != d_creatorThreadID) {
+ handleCrossProtocolResponse(now, std::move(response));
+ return;
+ }
+
+ auto& state = response.d_idstate;
+ if (state.forwardedOverUDP) {
+ dnsheader_aligned responseDH(response.d_buffer.data());
+
+ if (responseDH.get()->tc && state.d_packet && state.d_packet->size() > state.d_proxyProtocolPayloadSize && state.d_packet->size() - state.d_proxyProtocolPayloadSize > sizeof(dnsheader)) {
+ vinfolog("Response received from backend %s via UDP, for query %d received from %s via DoH, is truncated, retrying over TCP", response.d_ds->getNameWithAddr(), state.d_streamID, state.origRemote.toStringWithPort());
+ auto& query = *state.d_packet;
+ dnsdist::PacketMangling::editDNSHeaderFromRawPacket(&query.at(state.d_proxyProtocolPayloadSize), [origID = state.origID](dnsheader& header) {
+ /* restoring the original ID */
+ header.id = origID;
+ return true;
+ });
+
+ state.forwardedOverUDP = false;
+ bool proxyProtocolPayloadAdded = state.d_proxyProtocolPayloadSize > 0;
+ auto cpq = getCrossProtocolQuery(std::move(query), std::move(state), response.d_ds);
+ cpq->query.d_proxyProtocolPayloadAdded = proxyProtocolPayloadAdded;
+ if (g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq))) {
+ return;
+ }
+ vinfolog("Unable to pass DoH query to a TCP worker thread after getting a TC response over UDP");
+ notifyIOError(now, std::move(response));
+ return;
+ }
+ }
+
+ IncomingTCPConnectionState::handleResponse(now, std::move(response));
+}
+
+std::unique_ptr<DOHUnitInterface> IncomingHTTP2Connection::getDOHUnit(uint32_t streamID)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): clang-tidy is getting confused by assert()
+ assert(streamID <= std::numeric_limits<IncomingHTTP2Connection::StreamID>::max());
+ // NOLINTNEXTLINE(*-narrowing-conversions): generic interface between DNS and DoH with different types
+ auto query = std::move(d_currentStreams.at(static_cast<IncomingHTTP2Connection::StreamID>(streamID)));
+ return std::make_unique<IncomingDoHCrossProtocolContext>(std::move(query), std::dynamic_pointer_cast<IncomingHTTP2Connection>(shared_from_this()), streamID);
+}
+
+void IncomingHTTP2Connection::restoreDOHUnit(std::unique_ptr<DOHUnitInterface>&& unit)
+{
+ auto context = std::unique_ptr<IncomingDoHCrossProtocolContext>(dynamic_cast<IncomingDoHCrossProtocolContext*>(unit.release()));
+ if (context) {
+ d_currentStreams.at(context->d_streamID) = std::move(context->d_query);
+ }
+}
+
+IncomingHTTP2Connection::IncomingHTTP2Connection(ConnectionInfo&& connectionInfo, TCPClientThreadData& threadData, const struct timeval& now) :
+ IncomingTCPConnectionState(std::move(connectionInfo), threadData, now)
+{
+ nghttp2_session_callbacks* cbs = nullptr;
+ if (nghttp2_session_callbacks_new(&cbs) != 0) {
+ throw std::runtime_error("Unable to create a callback object for a new incoming HTTP/2 session");
+ }
+ std::unique_ptr<nghttp2_session_callbacks, void (*)(nghttp2_session_callbacks*)> callbacks(cbs, nghttp2_session_callbacks_del);
+ cbs = nullptr;
+
+ nghttp2_session_callbacks_set_send_callback(callbacks.get(), send_callback);
+ nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks.get(), on_frame_recv_callback);
+ nghttp2_session_callbacks_set_on_stream_close_callback(callbacks.get(), on_stream_close_callback);
+ nghttp2_session_callbacks_set_on_begin_headers_callback(callbacks.get(), on_begin_headers_callback);
+ nghttp2_session_callbacks_set_on_header_callback(callbacks.get(), on_header_callback);
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks.get(), on_data_chunk_recv_callback);
+ nghttp2_session_callbacks_set_error_callback2(callbacks.get(), on_error_callback);
+
+ nghttp2_session* sess = nullptr;
+ if (nghttp2_session_server_new(&sess, callbacks.get(), this) != 0) {
+ throw std::runtime_error("Coult not allocate a new incoming HTTP/2 session");
+ }
+
+ d_session = std::unique_ptr<nghttp2_session, decltype(&nghttp2_session_del)>(sess, nghttp2_session_del);
+ sess = nullptr;
+}
+
+bool IncomingHTTP2Connection::checkALPN()
+{
+ constexpr std::array<uint8_t, 2> h2ALPN{'h', '2'};
+ const auto protocols = d_handler.getNextProtocol();
+ if (protocols.size() == h2ALPN.size() && memcmp(protocols.data(), h2ALPN.data(), h2ALPN.size()) == 0) {
+ return true;
+ }
+
+ constexpr std::array<uint8_t, 8> http11ALPN{'h', 't', 't', 'p', '/', '1', '.', '1'};
+ if (protocols.size() == http11ALPN.size() && memcmp(protocols.data(), http11ALPN.data(), http11ALPN.size()) == 0) {
+ ++d_ci.cs->dohFrontend->d_http1Stats.d_nbQueries;
+ }
+
+ const std::string data("HTTP/1.1 400 Bad Request\r\nConnection: Close\r\n\r\n<html><body>This server implements RFC 8484 - DNS Queries over HTTP, and requires HTTP/2 in accordance with section 5.2 of the RFC.</body></html>\r\n");
+ d_out.insert(d_out.end(), data.begin(), data.end());
+ writeToSocket(false);
+
+ vinfolog("DoH connection from %s expected ALPN value 'h2', got '%s'", d_ci.remote.toStringWithPort(), std::string(protocols.begin(), protocols.end()));
+ return false;
+}
+
+void IncomingHTTP2Connection::handleConnectionReady()
+{
+ constexpr std::array<nghttp2_settings_entry, 1> settings{{{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100U}}};
+ auto ret = nghttp2_submit_settings(d_session.get(), NGHTTP2_FLAG_NONE, settings.data(), settings.size());
+ if (ret != 0) {
+ throw std::runtime_error("Fatal error: " + std::string(nghttp2_strerror(ret)));
+ }
+ d_needFlush = true;
+ ret = nghttp2_session_send(d_session.get());
+ if (ret != 0) {
+ throw std::runtime_error("Fatal error: " + std::string(nghttp2_strerror(ret)));
+ }
+}
+
+bool IncomingHTTP2Connection::hasPendingWrite() const
+{
+ return d_pendingWrite;
+}
+
+IOState IncomingHTTP2Connection::handleHandshake(const struct timeval& now)
+{
+ auto iostate = d_handler.tryHandshake();
+ if (iostate == IOState::Done) {
+ handleHandshakeDone(now);
+ if (d_handler.isTLS()) {
+ if (!checkALPN()) {
+ d_connectionDied = true;
+ stopIO();
+ return iostate;
+ }
+ }
+
+ if (d_ci.cs != nullptr && d_ci.cs->d_enableProxyProtocol && !isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) {
+ d_state = State::readingProxyProtocolHeader;
+ d_buffer.resize(s_proxyProtocolMinimumHeaderSize);
+ d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
+ }
+ else {
+ d_state = State::waitingForQuery;
+ handleConnectionReady();
+ }
+ }
+ return iostate;
+}
+
+void IncomingHTTP2Connection::handleIO()
+{
+ IOState iostate = IOState::Done;
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+
+ try {
+ if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+ vinfolog("Terminating DoH connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
+ stopIO();
+ d_connectionClosing = true;
+ return;
+ }
+
+ if (d_state == State::starting) {
+ if (d_ci.cs != nullptr && d_ci.cs->dohFrontend != nullptr) {
+ ++d_ci.cs->dohFrontend->d_httpconnects;
+ }
+ if (d_ci.cs != nullptr && d_ci.cs->d_enableProxyProtocol && isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) {
+ d_state = State::readingProxyProtocolHeader;
+ d_buffer.resize(s_proxyProtocolMinimumHeaderSize);
+ d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
+ }
+ else {
+ d_state = State::doingHandshake;
+ }
+ }
+
+ if (d_state == State::doingHandshake) {
+ iostate = handleHandshake(now);
+ if (d_connectionDied) {
+ return;
+ }
+ }
+
+ if (d_state == State::readingProxyProtocolHeader) {
+ auto status = handleProxyProtocolPayload();
+ if (status == ProxyProtocolResult::Done) {
+ if (isProxyPayloadOutsideTLS()) {
+ d_state = State::doingHandshake;
+ iostate = handleHandshake(now);
+ if (d_connectionDied) {
+ return;
+ }
+ }
+ else {
+ d_currentPos = 0;
+ d_proxyProtocolNeed = 0;
+ d_buffer.clear();
+ d_state = State::waitingForQuery;
+ handleConnectionReady();
+ }
+ }
+ else if (status == ProxyProtocolResult::Error) {
+ d_connectionDied = true;
+ stopIO();
+ return;
+ }
+ }
+
+ if (active() && !d_connectionClosing && (d_state == State::waitingForQuery || d_state == State::idle)) {
+ do {
+ iostate = readHTTPData();
+ } while (active() && !d_connectionClosing && iostate == IOState::Done);
+ }
+
+ if (!active()) {
+ stopIO();
+ return;
+ }
+ /*
+ So:
+ - if we have a pending write, we need to wait until the socket becomes writable
+ and then call handleWritableCallback
+ - if we have NeedWrite but no pending write, we need to wait until the socket
+ becomes writable but for handleReadableIOCallback
+ - if we have NeedRead, or nghttp2_session_want_read, wait until the socket
+ becomes readable and call handleReadableIOCallback
+ */
+ if (hasPendingWrite()) {
+ updateIO(IOState::NeedWrite, handleWritableIOCallback);
+ }
+ else if (iostate == IOState::NeedWrite) {
+ updateIO(IOState::NeedWrite, handleReadableIOCallback);
+ }
+ else if (!d_connectionClosing) {
+ if (nghttp2_session_want_read(d_session.get()) != 0) {
+ updateIO(IOState::NeedRead, handleReadableIOCallback);
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Exception when processing IO for incoming DoH connection from %s: %s", d_ci.remote.toStringWithPort(), e.what());
+ d_connectionDied = true;
+ stopIO();
+ }
+}
+
+void IncomingHTTP2Connection::writeToSocket(bool socketReady)
+{
+ try {
+ d_needFlush = false;
+ IOState newState = d_handler.tryWrite(d_out, d_outPos, d_out.size());
+
+ if (newState == IOState::Done) {
+ d_pendingWrite = false;
+ d_out.clear();
+ d_outPos = 0;
+ if (active() && !d_connectionClosing) {
+ updateIO(IOState::NeedRead, handleReadableIOCallback);
+ }
+ else {
+ stopIO();
+ }
+ }
+ else {
+ updateIO(newState, handleWritableIOCallback);
+ d_pendingWrite = true;
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Exception while trying to write (%s) to HTTP client connection to %s: %s", (socketReady ? "ready" : "send"), d_ci.remote.toStringWithPort(), e.what());
+ handleIOError();
+ }
+}
+
+ssize_t IncomingHTTP2Connection::send_callback(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+ if (conn->d_connectionDied) {
+ return static_cast<ssize_t>(length);
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): nghttp2 API
+ conn->d_out.insert(conn->d_out.end(), data, data + length);
+
+ if (conn->d_connectionClosing || conn->d_needFlush) {
+ conn->writeToSocket(false);
+ }
+
+ return static_cast<ssize_t>(length);
+}
+
+static const std::array<const std::string, static_cast<size_t>(NGHTTP2Headers::HeaderConstantIndexes::COUNT)> s_headerConstants{
+ "200",
+ ":method",
+ "POST",
+ ":scheme",
+ "https",
+ ":authority",
+ "x-forwarded-for",
+ ":path",
+ "content-length",
+ ":status",
+ "location",
+ "accept",
+ "application/dns-message",
+ "cache-control",
+ "content-type",
+ "application/dns-message",
+ "user-agent",
+ "nghttp2-" NGHTTP2_VERSION "/dnsdist",
+ "x-forwarded-port",
+ "x-forwarded-proto",
+ "dns-over-udp",
+ "dns-over-tcp",
+ "dns-over-tls",
+ "dns-over-http",
+ "dns-over-https"};
+
+static const std::string s_authorityHeaderName(":authority");
+static const std::string s_pathHeaderName(":path");
+static const std::string s_methodHeaderName(":method");
+static const std::string s_schemeHeaderName(":scheme");
+static const std::string s_xForwardedForHeaderName("x-forwarded-for");
+
+void NGHTTP2Headers::addStaticHeader(std::vector<nghttp2_nv>& headers, NGHTTP2Headers::HeaderConstantIndexes nameKey, NGHTTP2Headers::HeaderConstantIndexes valueKey)
+{
+ const auto& name = s_headerConstants.at(static_cast<size_t>(nameKey));
+ const auto& value = s_headerConstants.at(static_cast<size_t>(valueKey));
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast,cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API
+ headers.push_back({const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(name.c_str())), const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.c_str())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE});
+}
+
+void NGHTTP2Headers::addCustomDynamicHeader(std::vector<nghttp2_nv>& headers, const std::string& name, const std::string_view& value)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast,cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API
+ headers.push_back({const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(name.data())), const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE});
+}
+
+void NGHTTP2Headers::addDynamicHeader(std::vector<nghttp2_nv>& headers, NGHTTP2Headers::HeaderConstantIndexes nameKey, const std::string_view& value)
+{
+ const auto& name = s_headerConstants.at(static_cast<size_t>(nameKey));
+ NGHTTP2Headers::addCustomDynamicHeader(headers, name, value);
+}
+
+IOState IncomingHTTP2Connection::sendResponse(const struct timeval& now, TCPResponse&& response)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): clang-tidy is getting confused by assert()
+ assert(response.d_idstate.d_streamID != -1);
+ auto& context = d_currentStreams.at(response.d_idstate.d_streamID);
+
+ uint32_t statusCode = 200U;
+ std::string contentType;
+ bool sendContentType = true;
+ auto& responseBuffer = context.d_buffer;
+ if (context.d_statusCode != 0) {
+ responseBuffer = std::move(context.d_response);
+ statusCode = context.d_statusCode;
+ contentType = std::move(context.d_contentTypeOut);
+ }
+ else {
+ responseBuffer = std::move(response.d_buffer);
+ }
+
+ sendResponse(response.d_idstate.d_streamID, context, statusCode, d_ci.cs->dohFrontend->d_customResponseHeaders, contentType, sendContentType);
+ handleResponseSent(response);
+
+ return hasPendingWrite() ? IOState::NeedWrite : IOState::Done;
+}
+
+void IncomingHTTP2Connection::notifyIOError(const struct timeval& now, TCPResponse&& response)
+{
+ if (std::this_thread::get_id() != d_creatorThreadID) {
+ /* empty buffer will signal an IO error */
+ response.d_buffer.clear();
+ handleCrossProtocolResponse(now, std::move(response));
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): clang-tidy is getting confused by assert()
+ assert(response.d_idstate.d_streamID != -1);
+ auto& context = d_currentStreams.at(response.d_idstate.d_streamID);
+ context.d_buffer = std::move(response.d_buffer);
+ sendResponse(response.d_idstate.d_streamID, context, 502, d_ci.cs->dohFrontend->d_customResponseHeaders);
+}
+
+bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID streamID, IncomingHTTP2Connection::PendingQuery& context, uint16_t responseCode, const HeadersMap& customResponseHeaders, const std::string& contentType, bool addContentType)
+{
+ /* if data_prd is not NULL, it provides data which will be sent in subsequent DATA frames. In this case, a method that allows request message bodies (https://tools.ietf.org/html/rfc7231#section-4) must be specified with :method key (e.g. POST). This function does not take ownership of the data_prd. The function copies the members of the data_prd. If data_prd is NULL, HEADERS have END_STREAM set.
+ */
+ nghttp2_data_provider data_provider;
+
+ data_provider.source.ptr = this;
+ data_provider.read_callback = [](nghttp2_session*, IncomingHTTP2Connection::StreamID stream_id, uint8_t* buf, size_t length, uint32_t* data_flags, nghttp2_data_source* source, void* cb_data) -> ssize_t {
+ auto* connection = static_cast<IncomingHTTP2Connection*>(cb_data);
+ auto& obj = connection->d_currentStreams.at(stream_id);
+ size_t toCopy = 0;
+ if (obj.d_queryPos < obj.d_buffer.size()) {
+ size_t remaining = obj.d_buffer.size() - obj.d_queryPos;
+ toCopy = length > remaining ? remaining : length;
+ memcpy(buf, &obj.d_buffer.at(obj.d_queryPos), toCopy);
+ obj.d_queryPos += toCopy;
+ }
+
+ if (obj.d_queryPos >= obj.d_buffer.size()) {
+ *data_flags |= NGHTTP2_DATA_FLAG_EOF;
+ obj.d_buffer.clear();
+ connection->d_needFlush = true;
+ }
+ return static_cast<ssize_t>(toCopy);
+ };
+
+ const auto& dohFrontend = d_ci.cs->dohFrontend;
+ auto& responseBody = context.d_buffer;
+
+ std::vector<nghttp2_nv> headers;
+ std::string responseCodeStr;
+ std::string cacheControlValue;
+ std::string location;
+ /* remember that dynamic header values should be kept alive
+ until we have called nghttp2_submit_response(), at least */
+ /* status, content-type, cache-control, content-length */
+ headers.reserve(4);
+
+ if (responseCode == 200) {
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::STATUS_NAME, NGHTTP2Headers::HeaderConstantIndexes::OK_200_VALUE);
+ ++dohFrontend->d_validresponses;
+ ++dohFrontend->d_http2Stats.d_nb200Responses;
+
+ if (addContentType) {
+ if (contentType.empty()) {
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_VALUE);
+ }
+ else {
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, contentType);
+ }
+ }
+
+ if (dohFrontend->d_sendCacheControlHeaders && responseBody.size() > sizeof(dnsheader)) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): API
+ uint32_t minTTL = getDNSPacketMinTTL(reinterpret_cast<const char*>(responseBody.data()), responseBody.size());
+ if (minTTL != std::numeric_limits<uint32_t>::max()) {
+ cacheControlValue = "max-age=" + std::to_string(minTTL);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CACHE_CONTROL_NAME, cacheControlValue);
+ }
+ }
+ }
+ else {
+ responseCodeStr = std::to_string(responseCode);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::STATUS_NAME, responseCodeStr);
+
+ if (responseCode >= 300 && responseCode < 400) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ location = std::string(reinterpret_cast<const char*>(responseBody.data()), responseBody.size());
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, "text/html; charset=utf-8");
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::LOCATION_NAME, location);
+ static const std::string s_redirectStart{"<!DOCTYPE html><TITLE>Moved</TITLE><P>The document has moved <A HREF=\""};
+ static const std::string s_redirectEnd{"\">here</A>"};
+ responseBody.reserve(s_redirectStart.size() + responseBody.size() + s_redirectEnd.size());
+ responseBody.insert(responseBody.begin(), s_redirectStart.begin(), s_redirectStart.end());
+ responseBody.insert(responseBody.end(), s_redirectEnd.begin(), s_redirectEnd.end());
+ ++dohFrontend->d_redirectresponses;
+ }
+ else {
+ ++dohFrontend->d_errorresponses;
+ switch (responseCode) {
+ case 400:
+ ++dohFrontend->d_http2Stats.d_nb400Responses;
+ break;
+ case 403:
+ ++dohFrontend->d_http2Stats.d_nb403Responses;
+ break;
+ case 500:
+ ++dohFrontend->d_http2Stats.d_nb500Responses;
+ break;
+ case 502:
+ ++dohFrontend->d_http2Stats.d_nb502Responses;
+ break;
+ default:
+ ++dohFrontend->d_http2Stats.d_nbOtherResponses;
+ break;
+ }
+
+ if (!responseBody.empty()) {
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, "text/plain; charset=utf-8");
+ }
+ else {
+ static const std::string invalid{"invalid DNS query"};
+ static const std::string notAllowed{"dns query not allowed"};
+ static const std::string noDownstream{"no downstream server available"};
+ static const std::string internalServerError{"Internal Server Error"};
+
+ switch (responseCode) {
+ case 400:
+ responseBody.insert(responseBody.begin(), invalid.begin(), invalid.end());
+ break;
+ case 403:
+ responseBody.insert(responseBody.begin(), notAllowed.begin(), notAllowed.end());
+ break;
+ case 502:
+ responseBody.insert(responseBody.begin(), noDownstream.begin(), noDownstream.end());
+ break;
+ case 500:
+ /* fall-through */
+ default:
+ responseBody.insert(responseBody.begin(), internalServerError.begin(), internalServerError.end());
+ break;
+ }
+ }
+ }
+ }
+
+ const std::string contentLength = std::to_string(responseBody.size());
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_LENGTH_NAME, contentLength);
+
+ for (const auto& [key, value] : customResponseHeaders) {
+ NGHTTP2Headers::addCustomDynamicHeader(headers, key, value);
+ }
+
+ auto ret = nghttp2_submit_response(d_session.get(), streamID, headers.data(), headers.size(), &data_provider);
+ if (ret != 0) {
+ d_currentStreams.erase(streamID);
+ vinfolog("Error submitting HTTP response for stream %d: %s", streamID, nghttp2_strerror(ret));
+ return false;
+ }
+
+ ret = nghttp2_session_send(d_session.get());
+ if (ret != 0) {
+ d_currentStreams.erase(streamID);
+ vinfolog("Error flushing HTTP response for stream %d: %s", streamID, nghttp2_strerror(ret));
+ return false;
+ }
+
+ return true;
+}
+
+static void processForwardedForHeader(const std::unique_ptr<HeadersMap>& headers, ComboAddress& remote)
+{
+ if (!headers) {
+ return;
+ }
+
+ auto headerIt = headers->find(s_xForwardedForHeaderName);
+ if (headerIt == headers->end()) {
+ return;
+ }
+
+ std::string_view value = headerIt->second;
+ try {
+ auto pos = value.rfind(',');
+ if (pos != std::string_view::npos) {
+ ++pos;
+ for (; pos < value.size() && value[pos] == ' '; ++pos) {
+ }
+
+ if (pos < value.size()) {
+ value = value.substr(pos);
+ }
+ }
+ auto newRemote = ComboAddress(std::string(value));
+ remote = newRemote;
+ }
+ catch (const std::exception& e) {
+ vinfolog("Invalid X-Forwarded-For header ('%s') received from %s : %s", std::string(value), remote.toStringWithPort(), e.what());
+ }
+ catch (const PDNSException& e) {
+ vinfolog("Invalid X-Forwarded-For header ('%s') received from %s : %s", std::string(value), remote.toStringWithPort(), e.reason);
+ }
+}
+
+void IncomingHTTP2Connection::handleIncomingQuery(IncomingHTTP2Connection::PendingQuery&& query, IncomingHTTP2Connection::StreamID streamID)
+{
+ const auto handleImmediateResponse = [this, &query, streamID](uint16_t code, const std::string& reason, PacketBuffer&& response = PacketBuffer()) {
+ if (response.empty()) {
+ query.d_buffer.clear();
+ query.d_buffer.insert(query.d_buffer.begin(), reason.begin(), reason.end());
+ }
+ else {
+ query.d_buffer = std::move(response);
+ }
+ vinfolog("Sending an immediate %d response to incoming DoH query: %s", code, reason);
+ sendResponse(streamID, query, code, d_ci.cs->dohFrontend->d_customResponseHeaders);
+ };
+
+ if (query.d_method == PendingQuery::Method::Unknown || query.d_method == PendingQuery::Method::Unsupported) {
+ handleImmediateResponse(400, "DoH query not allowed because of unsupported HTTP method");
+ return;
+ }
+
+ ++d_ci.cs->dohFrontend->d_http2Stats.d_nbQueries;
+
+ if (d_ci.cs->dohFrontend->d_trustForwardedForHeader) {
+ processForwardedForHeader(query.d_headers, d_proxiedRemote);
+
+ /* second ACL lookup based on the updated address */
+ auto& holders = d_threadData.holders;
+ if (!holders.acl->match(d_proxiedRemote)) {
+ ++dnsdist::metrics::g_stats.aclDrops;
+ vinfolog("Query from %s (%s) (DoH) dropped because of ACL", d_ci.remote.toStringWithPort(), d_proxiedRemote.toStringWithPort());
+ handleImmediateResponse(403, "DoH query not allowed because of ACL");
+ return;
+ }
+
+ if (!d_ci.cs->dohFrontend->d_keepIncomingHeaders) {
+ query.d_headers.reset();
+ }
+ }
+
+ if (d_ci.cs->dohFrontend->d_exactPathMatching) {
+ if (d_ci.cs->dohFrontend->d_urls.count(query.d_path) == 0) {
+ handleImmediateResponse(404, "there is no endpoint configured for this path");
+ return;
+ }
+ }
+ else {
+ bool found = false;
+ for (const auto& path : d_ci.cs->dohFrontend->d_urls) {
+ if (boost::starts_with(query.d_path, path)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ handleImmediateResponse(404, "there is no endpoint configured for this path");
+ return;
+ }
+ }
+
+ /* the responses map can be updated at runtime, so we need to take a copy of
+ the shared pointer, increasing the reference counter */
+ auto responsesMap = d_ci.cs->dohFrontend->d_responsesMap;
+ if (responsesMap) {
+ for (const auto& entry : *responsesMap) {
+ if (entry->matches(query.d_path)) {
+ const auto& customHeaders = entry->getHeaders();
+ query.d_buffer = entry->getContent();
+ if (entry->getStatusCode() >= 400 && !query.d_buffer.empty()) {
+ // legacy trailing 0 from the h2o era
+ query.d_buffer.pop_back();
+ }
+
+ sendResponse(streamID, query, entry->getStatusCode(), customHeaders ? *customHeaders : d_ci.cs->dohFrontend->d_customResponseHeaders, std::string(), false);
+ return;
+ }
+ }
+ }
+
+ if (query.d_buffer.empty() && query.d_method == PendingQuery::Method::Get && !query.d_queryString.empty()) {
+ auto payload = dnsdist::doh::getPayloadFromPath(query.d_queryString);
+ if (payload) {
+ query.d_buffer = std::move(*payload);
+ }
+ else {
+ ++d_ci.cs->dohFrontend->d_badrequests;
+ handleImmediateResponse(400, "DoH unable to decode BASE64-URL");
+ return;
+ }
+ }
+
+ if (query.d_method == PendingQuery::Method::Get) {
+ ++d_ci.cs->dohFrontend->d_getqueries;
+ }
+ else if (query.d_method == PendingQuery::Method::Post) {
+ ++d_ci.cs->dohFrontend->d_postqueries;
+ }
+
+ try {
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+ auto processingResult = handleQuery(std::move(query.d_buffer), now, streamID);
+
+ switch (processingResult) {
+ case QueryProcessingResult::TooSmall:
+ handleImmediateResponse(400, "DoH non-compliant query");
+ break;
+ case QueryProcessingResult::InvalidHeaders:
+ handleImmediateResponse(400, "DoH invalid headers");
+ break;
+ case QueryProcessingResult::Dropped:
+ handleImmediateResponse(403, "DoH dropped query");
+ break;
+ case QueryProcessingResult::NoBackend:
+ handleImmediateResponse(502, "DoH no backend available");
+ return;
+ case QueryProcessingResult::Forwarded:
+ case QueryProcessingResult::Asynchronous:
+ case QueryProcessingResult::SelfAnswered:
+ break;
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Exception while processing DoH query: %s", e.what());
+ handleImmediateResponse(400, "DoH non-compliant query");
+ return;
+ }
+}
+
+int IncomingHTTP2Connection::on_frame_recv_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+ /* is this the last frame for this stream? */
+ if ((frame->hd.type == NGHTTP2_HEADERS || frame->hd.type == NGHTTP2_DATA) && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) != 0) {
+ auto streamID = frame->hd.stream_id;
+ auto stream = conn->d_currentStreams.find(streamID);
+ if (stream != conn->d_currentStreams.end()) {
+ conn->handleIncomingQuery(std::move(stream->second), streamID);
+ }
+ else {
+ vinfolog("Stream %d NOT FOUND", streamID);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ }
+
+ return 0;
+}
+
+int IncomingHTTP2Connection::on_stream_close_callback(nghttp2_session* session, IncomingHTTP2Connection::StreamID stream_id, uint32_t error_code, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+
+ conn->d_currentStreams.erase(stream_id);
+ return 0;
+}
+
+int IncomingHTTP2Connection::on_begin_headers_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data)
+{
+ if (frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
+ return 0;
+ }
+
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+ auto insertPair = conn->d_currentStreams.emplace(frame->hd.stream_id, PendingQuery());
+ if (!insertPair.second) {
+ /* there is a stream ID collision, something is very wrong! */
+ vinfolog("Stream ID collision (%d) on connection from %d", frame->hd.stream_id, conn->d_ci.remote.toStringWithPort());
+ conn->d_connectionClosing = true;
+ conn->d_needFlush = true;
+ nghttp2_session_terminate_session(conn->d_session.get(), NGHTTP2_NO_ERROR);
+ auto ret = nghttp2_session_send(conn->d_session.get());
+ if (ret != 0) {
+ vinfolog("Error flushing HTTP response for stream %d from %s: %s", frame->hd.stream_id, conn->d_ci.remote.toStringWithPort(), nghttp2_strerror(ret));
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static std::string::size_type getLengthOfPathWithoutParameters(const std::string_view& path)
+{
+ auto pos = path.find('?');
+ if (pos == string::npos) {
+ return path.size();
+ }
+
+ return pos;
+}
+
+int IncomingHTTP2Connection::on_header_callback(nghttp2_session* session, const nghttp2_frame* frame, const uint8_t* name, size_t nameLen, const uint8_t* value, size_t valuelen, uint8_t flags, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+
+ if (frame->hd.type == NGHTTP2_HEADERS && frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
+ if (nghttp2_check_header_name(name, nameLen) == 0) {
+ vinfolog("Invalid header name");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+#if HAVE_NGHTTP2_CHECK_HEADER_VALUE_RFC9113
+ if (nghttp2_check_header_value_rfc9113(value, valuelen) == 0) {
+ vinfolog("Invalid header value");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+#endif /* HAVE_NGHTTP2_CHECK_HEADER_VALUE_RFC9113 */
+
+ auto headerMatches = [name, nameLen](const std::string& expected) -> bool {
+ return nameLen == expected.size() && memcmp(name, expected.data(), expected.size()) == 0;
+ };
+
+ auto stream = conn->d_currentStreams.find(frame->hd.stream_id);
+ if (stream == conn->d_currentStreams.end()) {
+ vinfolog("Unable to match the stream ID %d to a known one!", frame->hd.stream_id);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ auto& query = stream->second;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API
+ auto valueView = std::string_view(reinterpret_cast<const char*>(value), valuelen);
+ if (headerMatches(s_pathHeaderName)) {
+#if HAVE_NGHTTP2_CHECK_PATH
+ if (nghttp2_check_path(value, valuelen) == 0) {
+ vinfolog("Invalid path value");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+#endif /* HAVE_NGHTTP2_CHECK_PATH */
+
+ auto pathLen = getLengthOfPathWithoutParameters(valueView);
+ query.d_path = valueView.substr(0, pathLen);
+ if (pathLen < valueView.size()) {
+ query.d_queryString = valueView.substr(pathLen);
+ }
+ }
+ else if (headerMatches(s_authorityHeaderName)) {
+ query.d_host = valueView;
+ }
+ else if (headerMatches(s_schemeHeaderName)) {
+ query.d_scheme = valueView;
+ }
+ else if (headerMatches(s_methodHeaderName)) {
+#if HAVE_NGHTTP2_CHECK_METHOD
+ if (nghttp2_check_method(value, valuelen) == 0) {
+ vinfolog("Invalid method value");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+#endif /* HAVE_NGHTTP2_CHECK_METHOD */
+
+ if (valueView == "GET") {
+ query.d_method = PendingQuery::Method::Get;
+ }
+ else if (valueView == "POST") {
+ query.d_method = PendingQuery::Method::Post;
+ }
+ else {
+ query.d_method = PendingQuery::Method::Unsupported;
+ vinfolog("Unsupported method value");
+ return 0;
+ }
+ }
+
+ if (conn->d_ci.cs->dohFrontend->d_keepIncomingHeaders || (conn->d_ci.cs->dohFrontend->d_trustForwardedForHeader && headerMatches(s_xForwardedForHeaderName))) {
+ if (!query.d_headers) {
+ query.d_headers = std::make_unique<HeadersMap>();
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API
+ query.d_headers->insert({std::string(reinterpret_cast<const char*>(name), nameLen), std::string(valueView)});
+ }
+ }
+ return 0;
+}
+
+int IncomingHTTP2Connection::on_data_chunk_recv_callback(nghttp2_session* session, uint8_t flags, IncomingHTTP2Connection::StreamID stream_id, const uint8_t* data, size_t len, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+ auto stream = conn->d_currentStreams.find(stream_id);
+ if (stream == conn->d_currentStreams.end()) {
+ vinfolog("Unable to match the stream ID %d to a known one!", stream_id);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ if (len > std::numeric_limits<uint16_t>::max() || (std::numeric_limits<uint16_t>::max() - stream->second.d_buffer.size()) < len) {
+ vinfolog("Data frame of size %d is too large for a DNS query (we already have %d)", len, stream->second.d_buffer.size());
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): nghttp2 API
+ stream->second.d_buffer.insert(stream->second.d_buffer.end(), data, data + len);
+
+ return 0;
+}
+
+int IncomingHTTP2Connection::on_error_callback(nghttp2_session* session, int lib_error_code, const char* msg, size_t len, void* user_data)
+{
+ auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
+
+ vinfolog("Error in HTTP/2 connection from %d: %s", conn->d_ci.remote.toStringWithPort(), std::string(msg, len));
+ conn->d_connectionClosing = true;
+ conn->d_needFlush = true;
+ nghttp2_session_terminate_session(conn->d_session.get(), NGHTTP2_NO_ERROR);
+ auto ret = nghttp2_session_send(conn->d_session.get());
+ if (ret != 0) {
+ vinfolog("Error flushing HTTP response on connection from %s: %s", conn->d_ci.remote.toStringWithPort(), nghttp2_strerror(ret));
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ return 0;
+}
+
+IOState IncomingHTTP2Connection::readHTTPData()
+{
+ IOState newState = IOState::Done;
+ size_t got = 0;
+ if (d_in.size() < s_initialReceiveBufferSize) {
+ d_in.resize(std::max(s_initialReceiveBufferSize, d_in.capacity()));
+ }
+ try {
+ newState = d_handler.tryRead(d_in, got, d_in.size(), true);
+ d_in.resize(got);
+
+ if (got > 0) {
+ /* we got something */
+ auto readlen = nghttp2_session_mem_recv(d_session.get(), d_in.data(), d_in.size());
+ /* as long as we don't require a pause by returning nghttp2_error.NGHTTP2_ERR_PAUSE from a CB,
+ all data should be consumed before returning */
+ if (readlen < 0 || static_cast<size_t>(readlen) < d_in.size()) {
+ throw std::runtime_error("Fatal error while passing received data to nghttp2: " + std::string(nghttp2_strerror((int)readlen)));
+ }
+
+ nghttp2_session_send(d_session.get());
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Exception while trying to read from HTTP client connection to %s: %s", d_ci.remote.toStringWithPort(), e.what());
+ handleIOError();
+ return IOState::Done;
+ }
+ return newState;
+}
+
+void IncomingHTTP2Connection::handleReadableIOCallback([[maybe_unused]] int descriptor, FDMultiplexer::funcparam_t& param)
+{
+ auto conn = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(param);
+ conn->handleIO();
+}
+
+void IncomingHTTP2Connection::handleWritableIOCallback([[maybe_unused]] int descriptor, FDMultiplexer::funcparam_t& param)
+{
+ auto conn = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(param);
+ conn->writeToSocket(true);
+}
+
+void IncomingHTTP2Connection::stopIO()
+{
+ if (d_ioState) {
+ d_ioState->reset();
+ }
+}
+
+uint32_t IncomingHTTP2Connection::getConcurrentStreamsCount() const
+{
+ return d_currentStreams.size();
+}
+
+boost::optional<struct timeval> IncomingHTTP2Connection::getIdleClientReadTTD(struct timeval now) const
+{
+ auto idleTimeout = d_ci.cs->dohFrontend->d_idleTimeout;
+ if (g_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
+ return boost::none;
+ }
+
+ if (g_maxTCPConnectionDuration > 0) {
+ auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
+ if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+ return now;
+ }
+ auto remaining = g_maxTCPConnectionDuration - elapsed;
+ if (idleTimeout == 0 || remaining <= static_cast<size_t>(idleTimeout)) {
+ now.tv_sec += static_cast<time_t>(remaining);
+ return now;
+ }
+ }
+
+ now.tv_sec += idleTimeout;
+ return now;
+}
+
+void IncomingHTTP2Connection::updateIO(IOState newState, const FDMultiplexer::callbackfunc_t& callback)
+{
+ boost::optional<struct timeval> ttd{boost::none};
+
+ auto shared = std::dynamic_pointer_cast<IncomingHTTP2Connection>(shared_from_this());
+ if (!shared || !d_ioState) {
+ return;
+ }
+
+ timeval now{};
+ gettimeofday(&now, nullptr);
+
+ if (newState == IOState::NeedRead) {
+ /* use the idle TTL if the handshake has been completed (and proxy protocol payload received, if any),
+ and we have processed at least one query, otherwise we use the shorter read TTL */
+ if ((d_state == State::waitingForQuery || d_state == State::idle) && (d_queriesCount > 0 || d_currentQueriesCount > 0)) {
+ ttd = getIdleClientReadTTD(now);
+ }
+ else {
+ ttd = getClientReadTTD(now);
+ }
+ d_ioState->update(newState, callback, shared, ttd);
+ }
+ else if (newState == IOState::NeedWrite) {
+ ttd = getClientWriteTTD(now);
+ d_ioState->update(newState, callback, shared, ttd);
+ }
+}
+
+void IncomingHTTP2Connection::handleIOError()
+{
+ d_connectionDied = true;
+ d_out.clear();
+ d_outPos = 0;
+ nghttp2_session_terminate_session(d_session.get(), NGHTTP2_PROTOCOL_ERROR);
+ d_currentStreams.clear();
+ stopIO();
+}
+
+bool IncomingHTTP2Connection::active() const
+{
+ return !d_connectionDied && d_ioState != nullptr;
+}
+
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
diff --git a/dnsdist-nghttp2-in.hh b/dnsdist-nghttp2-in.hh
new file mode 100644
index 0000000..a2e58a4
--- /dev/null
+++ b/dnsdist-nghttp2-in.hh
@@ -0,0 +1,159 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "config.h"
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+#include <nghttp2/nghttp2.h>
+
+#include "dnsdist-tcp-upstream.hh"
+
+class IncomingHTTP2Connection : public IncomingTCPConnectionState
+{
+public:
+ using StreamID = int32_t;
+
+ class PendingQuery
+ {
+ public:
+ enum class Method : uint8_t
+ {
+ Unknown,
+ Get,
+ Post,
+ Unsupported
+ };
+
+ PacketBuffer d_buffer;
+ PacketBuffer d_response;
+ std::string d_path;
+ std::string d_scheme;
+ std::string d_host;
+ std::string d_queryString;
+ std::string d_sni;
+ std::string d_contentTypeOut;
+ std::unique_ptr<HeadersMap> d_headers;
+ size_t d_queryPos{0};
+ uint32_t d_statusCode{0};
+ Method d_method{Method::Unknown};
+ };
+
+ IncomingHTTP2Connection(ConnectionInfo&& connectionInfo, TCPClientThreadData& threadData, const struct timeval& now);
+ ~IncomingHTTP2Connection() = default;
+ void handleIO() override;
+ void handleResponse(const struct timeval& now, TCPResponse&& response) override;
+ void notifyIOError(const struct timeval& now, TCPResponse&& response) override;
+ bool active() const override;
+
+private:
+ static ssize_t send_callback(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data);
+ static int on_frame_recv_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data);
+ static int on_data_chunk_recv_callback(nghttp2_session* session, uint8_t flags, StreamID stream_id, const uint8_t* data, size_t len, void* user_data);
+ static int on_stream_close_callback(nghttp2_session* session, StreamID stream_id, uint32_t error_code, void* user_data);
+ static int on_header_callback(nghttp2_session* session, const nghttp2_frame* frame, const uint8_t* name, size_t namelen, const uint8_t* value, size_t valuelen, uint8_t flags, void* user_data);
+ static int on_begin_headers_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data);
+ static int on_error_callback(nghttp2_session* session, int lib_error_code, const char* msg, size_t len, void* user_data);
+ static void handleReadableIOCallback(int descriptor, FDMultiplexer::funcparam_t& param);
+ static void handleWritableIOCallback(int descriptor, FDMultiplexer::funcparam_t& param);
+
+ static constexpr size_t s_initialReceiveBufferSize{256U};
+
+ IOState sendResponse(const struct timeval& now, TCPResponse&& response) override;
+ bool forwardViaUDPFirst() const override
+ {
+ return true;
+ }
+ void restoreDOHUnit(std::unique_ptr<DOHUnitInterface>&&) override;
+ std::unique_ptr<DOHUnitInterface> getDOHUnit(uint32_t streamID) override;
+
+ void stopIO();
+ uint32_t getConcurrentStreamsCount() const;
+ void updateIO(IOState newState, const FDMultiplexer::callbackfunc_t& callback);
+ void handleIOError();
+ bool sendResponse(StreamID streamID, PendingQuery& context, uint16_t responseCode, const HeadersMap& customResponseHeaders, const std::string& contentType = "", bool addContentType = true);
+ void handleIncomingQuery(PendingQuery&& query, StreamID streamID);
+ bool checkALPN();
+ IOState readHTTPData();
+ void handleConnectionReady();
+ IOState handleHandshake(const struct timeval& now) override;
+ bool hasPendingWrite() const;
+ void writeToSocket(bool socketReady);
+ boost::optional<struct timeval> getIdleClientReadTTD(struct timeval now) const;
+
+ std::unique_ptr<nghttp2_session, decltype(&nghttp2_session_del)> d_session{nullptr, nghttp2_session_del};
+ std::unordered_map<StreamID, PendingQuery> d_currentStreams;
+ PacketBuffer d_out;
+ PacketBuffer d_in;
+ size_t d_outPos{0};
+ /* this connection is done, the remote end has closed the connection
+ or something like that. We do not want to try to write to it. */
+ bool d_connectionDied{false};
+ /* we are done reading from this connection, but we might still want to
+ write to it to close it properly */
+ bool d_connectionClosing{false};
+ /* Whether we are still waiting for more data to be buffered
+ before writing to the socket (false) or not. */
+ bool d_needFlush{false};
+ /* Whether we have data that we want to write to the socket,
+ but the socket is full. */
+ bool d_pendingWrite{false};
+};
+
+class NGHTTP2Headers
+{
+public:
+ enum class HeaderConstantIndexes
+ {
+ OK_200_VALUE = 0,
+ METHOD_NAME,
+ METHOD_VALUE,
+ SCHEME_NAME,
+ SCHEME_VALUE,
+ AUTHORITY_NAME,
+ X_FORWARDED_FOR_NAME,
+ PATH_NAME,
+ CONTENT_LENGTH_NAME,
+ STATUS_NAME,
+ LOCATION_NAME,
+ ACCEPT_NAME,
+ ACCEPT_VALUE,
+ CACHE_CONTROL_NAME,
+ CONTENT_TYPE_NAME,
+ CONTENT_TYPE_VALUE,
+ USER_AGENT_NAME,
+ USER_AGENT_VALUE,
+ X_FORWARDED_PORT_NAME,
+ X_FORWARDED_PROTO_NAME,
+ X_FORWARDED_PROTO_VALUE_DNS_OVER_UDP,
+ X_FORWARDED_PROTO_VALUE_DNS_OVER_TCP,
+ X_FORWARDED_PROTO_VALUE_DNS_OVER_TLS,
+ X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTP,
+ X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTPS,
+ COUNT
+ };
+
+ static void addStaticHeader(std::vector<nghttp2_nv>& headers, HeaderConstantIndexes nameKey, HeaderConstantIndexes valueKey);
+ static void addDynamicHeader(std::vector<nghttp2_nv>& headers, HeaderConstantIndexes nameKey, const std::string_view& value);
+ static void addCustomDynamicHeader(std::vector<nghttp2_nv>& headers, const std::string& name, const std::string_view& value);
+};
+
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
diff --git a/dnsdist-nghttp2.cc b/dnsdist-nghttp2.cc
index 5c745ea..bf1666f 100644
--- a/dnsdist-nghttp2.cc
+++ b/dnsdist-nghttp2.cc
@@ -22,16 +22,18 @@
#include "config.h"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
#include "dnsdist-nghttp2.hh"
+#include "dnsdist-nghttp2-in.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-downstream-connection.hh"
#include "dolog.hh"
+#include "channel.hh"
#include "iputils.hh"
#include "libssl.hh"
#include "noinitvector.hh"
@@ -43,7 +45,7 @@ std::atomic<uint64_t> g_dohStatesDumpRequested{0};
std::unique_ptr<DoHClientCollection> g_dohClientThreads{nullptr};
std::optional<uint16_t> g_outgoingDoHWorkerThreads{std::nullopt};
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
class DoHConnectionToBackend : public ConnectionToBackend
{
public:
@@ -82,9 +84,6 @@ private:
static void handleReadableIOCallback(int fd, FDMultiplexer::funcparam_t& param);
static void handleWritableIOCallback(int fd, FDMultiplexer::funcparam_t& param);
- static void addStaticHeader(std::vector<nghttp2_nv>& headers, const std::string& nameKey, const std::string& valueKey);
- static void addDynamicHeader(std::vector<nghttp2_nv>& headers, const std::string& nameKey, const std::string& value);
-
class PendingRequest
{
public:
@@ -95,8 +94,7 @@ private:
uint16_t d_responseCode{0};
bool d_finished{false};
};
- void addToIOState(IOState state, FDMultiplexer::callbackfunc_t callback);
- void updateIO(IOState newState, FDMultiplexer::callbackfunc_t callback, bool noTTD = false);
+ void updateIO(IOState newState, const FDMultiplexer::callbackfunc_t& callback, bool noTTD = false);
void watchForRemoteHostClosingConnection();
void handleResponse(PendingRequest&& request);
void handleResponseError(PendingRequest&& request, const struct timeval& now);
@@ -132,7 +130,11 @@ uint32_t DoHConnectionToBackend::getConcurrentStreamsCount() const
void DoHConnectionToBackend::handleResponse(PendingRequest&& request)
{
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
try {
if (!d_healthCheckQuery) {
@@ -148,7 +150,11 @@ void DoHConnectionToBackend::handleResponse(PendingRequest&& request)
}
}
- request.d_sender->handleResponse(now, TCPResponse(std::move(request.d_buffer), std::move(request.d_query.d_idstate), shared_from_this(), d_ds));
+ TCPResponse response(std::move(request.d_query));
+ response.d_buffer = std::move(request.d_buffer);
+ response.d_connection = shared_from_this();
+ response.d_ds = d_ds;
+ request.d_sender->handleResponse(now, std::move(response));
}
catch (const std::exception& e) {
vinfolog("Got exception while handling response for cross-protocol DoH: %s", e.what());
@@ -162,7 +168,8 @@ void DoHConnectionToBackend::handleResponseError(PendingRequest&& request, const
d_ds->reportTimeoutOrError();
}
- request.d_sender->notifyIOError(std::move(request.d_query.d_idstate), now);
+ TCPResponse response(PacketBuffer(), std::move(request.d_query.d_idstate), nullptr, nullptr);
+ request.d_sender->notifyIOError(now, std::move(response));
}
catch (const std::exception& e) {
vinfolog("Got exception while handling response for cross-protocol DoH: %s", e.what());
@@ -174,7 +181,11 @@ void DoHConnectionToBackend::handleIOError()
d_connectionDied = true;
nghttp2_session_terminate_session(d_session.get(), NGHTTP2_PROTOCOL_ERROR);
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
for (auto& request : d_currentStreams) {
handleResponseError(std::move(request.second), now);
@@ -221,45 +232,6 @@ bool DoHConnectionToBackend::isIdle() const
return getConcurrentStreamsCount() == 0;
}
-const std::unordered_map<std::string, std::string> DoHConnectionToBackend::s_constants = {
- {"method-name", ":method"},
- {"method-value", "POST"},
- {"scheme-name", ":scheme"},
- {"scheme-value", "https"},
- {"accept-name", "accept"},
- {"accept-value", "application/dns-message"},
- {"content-type-name", "content-type"},
- {"content-type-value", "application/dns-message"},
- {"user-agent-name", "user-agent"},
- {"user-agent-value", "nghttp2-" NGHTTP2_VERSION "/dnsdist"},
- {"authority-name", ":authority"},
- {"path-name", ":path"},
- {"content-length-name", "content-length"},
- {"x-forwarded-for-name", "x-forwarded-for"},
- {"x-forwarded-port-name", "x-forwarded-port"},
- {"x-forwarded-proto-name", "x-forwarded-proto"},
- {"x-forwarded-proto-value-dns-over-udp", "dns-over-udp"},
- {"x-forwarded-proto-value-dns-over-tcp", "dns-over-tcp"},
- {"x-forwarded-proto-value-dns-over-tls", "dns-over-tls"},
- {"x-forwarded-proto-value-dns-over-http", "dns-over-http"},
- {"x-forwarded-proto-value-dns-over-https", "dns-over-https"},
-};
-
-void DoHConnectionToBackend::addStaticHeader(std::vector<nghttp2_nv>& headers, const std::string& nameKey, const std::string& valueKey)
-{
- const auto& name = s_constants.at(nameKey);
- const auto& value = s_constants.at(valueKey);
-
- headers.push_back({const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(name.c_str())), const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.c_str())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE});
-}
-
-void DoHConnectionToBackend::addDynamicHeader(std::vector<nghttp2_nv>& headers, const std::string& nameKey, const std::string& value)
-{
- const auto& name = s_constants.at(nameKey);
-
- headers.push_back({const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(name.c_str())), const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.c_str())), name.size(), value.size(), NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE});
-}
-
void DoHConnectionToBackend::queueQuery(std::shared_ptr<TCPQuerySender>& sender, TCPQuery&& query)
{
auto payloadSize = std::to_string(query.d_buffer.size());
@@ -275,37 +247,37 @@ void DoHConnectionToBackend::queueQuery(std::shared_ptr<TCPQuerySender>& sender,
headers.reserve(8 + (addXForwarded ? 3 : 0));
/* Pseudo-headers need to come first (rfc7540 8.1.2.1) */
- addStaticHeader(headers, "method-name", "method-value");
- addStaticHeader(headers, "scheme-name", "scheme-value");
- addDynamicHeader(headers, "authority-name", d_ds->d_config.d_tlsSubjectName);
- addDynamicHeader(headers, "path-name", d_ds->d_config.d_dohPath);
- addStaticHeader(headers, "accept-name", "accept-value");
- addStaticHeader(headers, "content-type-name", "content-type-value");
- addStaticHeader(headers, "user-agent-name", "user-agent-value");
- addDynamicHeader(headers, "content-length-name", payloadSize);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::METHOD_NAME, NGHTTP2Headers::HeaderConstantIndexes::METHOD_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_NAME, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_VALUE);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::AUTHORITY_NAME, d_ds->d_config.d_tlsSubjectName);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::PATH_NAME, d_ds->d_config.d_dohPath);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_NAME, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_NAME, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_VALUE);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_LENGTH_NAME, payloadSize);
/* no need to add these headers for health-check queries */
if (addXForwarded && query.d_idstate.origRemote.getPort() != 0) {
remote = query.d_idstate.origRemote.toString();
remotePort = std::to_string(query.d_idstate.origRemote.getPort());
- addDynamicHeader(headers, "x-forwarded-for-name", remote);
- addDynamicHeader(headers, "x-forwarded-port-name", remotePort);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_FOR_NAME, remote);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PORT_NAME, remotePort);
if (query.d_idstate.cs != nullptr) {
if (query.d_idstate.cs->isUDP()) {
- addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-udp");
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_UDP);
}
else if (query.d_idstate.cs->isDoH()) {
if (query.d_idstate.cs->hasTLS()) {
- addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-https");
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTPS);
}
else {
- addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-http");
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_HTTP);
}
}
else if (query.d_idstate.cs->hasTLS()) {
- addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-tls");
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_TLS);
}
else {
- addStaticHeader(headers, "x-forwarded-proto-name", "x-forwarded-proto-value-dns-over-tcp");
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_NAME, NGHTTP2Headers::HeaderConstantIndexes::X_FORWARDED_PROTO_VALUE_DNS_OVER_TCP);
}
}
}
@@ -327,10 +299,9 @@ void DoHConnectionToBackend::queueQuery(std::shared_ptr<TCPQuerySender>& sender,
*/
nghttp2_data_provider data_provider;
- /* we will not use this pointer */
data_provider.source.ptr = this;
data_provider.read_callback = [](nghttp2_session* session, int32_t stream_id, uint8_t* buf, size_t length, uint32_t* data_flags, nghttp2_data_source* source, void* user_data) -> ssize_t {
- auto conn = reinterpret_cast<DoHConnectionToBackend*>(user_data);
+ auto* conn = static_cast<DoHConnectionToBackend*>(user_data);
auto& request = conn->d_currentStreams.at(stream_id);
size_t toCopy = 0;
if (request.d_queryPos < request.d_query.d_buffer.size()) {
@@ -368,12 +339,14 @@ void DoHConnectionToBackend::queueQuery(std::shared_ptr<TCPQuerySender>& sender,
class DoHClientThreadData
{
public:
- DoHClientThreadData() :
- mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent()))
+ DoHClientThreadData(pdns::channel::Receiver<CrossProtocolQuery>&& receiver) :
+ mplexer(std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent())),
+ d_receiver(std::move(receiver))
{
}
std::unique_ptr<FDMultiplexer> mplexer{nullptr};
+ pdns::channel::Receiver<CrossProtocolQuery> d_receiver;
};
void DoHConnectionToBackend::handleReadableIOCallback(int fd, FDMultiplexer::funcparam_t& param)
@@ -403,7 +376,11 @@ void DoHConnectionToBackend::handleReadableIOCallback(int fd, FDMultiplexer::fun
throw std::runtime_error("Fatal error while passing received data to nghttp2: " + std::string(nghttp2_strerror((int)readlen)));
}
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
conn->d_lastDataReceivedTime = now;
@@ -491,9 +468,13 @@ void DoHConnectionToBackend::stopIO()
}
}
-void DoHConnectionToBackend::updateIO(IOState newState, FDMultiplexer::callbackfunc_t callback, bool noTTD)
+void DoHConnectionToBackend::updateIO(IOState newState, const FDMultiplexer::callbackfunc_t& callback, bool noTTD)
{
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
boost::optional<struct timeval> ttd{boost::none};
if (!noTTD) {
@@ -515,10 +496,10 @@ void DoHConnectionToBackend::updateIO(IOState newState, FDMultiplexer::callbackf
auto shared = std::dynamic_pointer_cast<DoHConnectionToBackend>(shared_from_this());
if (shared) {
if (newState == IOState::NeedRead) {
- d_ioState->update(newState, callback, shared, ttd);
+ d_ioState->update(newState, callback, std::move(shared), ttd);
}
else if (newState == IOState::NeedWrite) {
- d_ioState->update(newState, callback, shared, ttd);
+ d_ioState->update(newState, callback, std::move(shared), ttd);
}
}
}
@@ -530,33 +511,6 @@ void DoHConnectionToBackend::watchForRemoteHostClosingConnection()
}
}
-void DoHConnectionToBackend::addToIOState(IOState state, FDMultiplexer::callbackfunc_t callback)
-{
- struct timeval now;
- gettimeofday(&now, nullptr);
- boost::optional<struct timeval> ttd{boost::none};
- if (state == IOState::NeedRead) {
- ttd = getBackendReadTTD(now);
- }
- else if (isFresh() && d_firstWrite == 0) {
- /* first write just after the non-blocking connect */
- ttd = getBackendConnectTTD(now);
- }
- else {
- ttd = getBackendWriteTTD(now);
- }
-
- auto shared = std::dynamic_pointer_cast<DoHConnectionToBackend>(shared_from_this());
- if (shared) {
- if (state == IOState::NeedRead) {
- d_ioState->add(state, callback, shared, ttd);
- }
- else if (state == IOState::NeedWrite) {
- d_ioState->add(state, callback, shared, ttd);
- }
- }
-}
-
ssize_t DoHConnectionToBackend::send_callback(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data)
{
DoHConnectionToBackend* conn = reinterpret_cast<DoHConnectionToBackend*>(user_data);
@@ -646,7 +600,11 @@ int DoHConnectionToBackend::on_frame_recv_callback(nghttp2_session* session, con
}
else {
vinfolog("HTTP response has a non-200 status code: %d", request.d_responseCode);
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
conn->handleResponseError(std::move(request), now);
@@ -698,7 +656,11 @@ int DoHConnectionToBackend::on_data_chunk_recv_callback(nghttp2_session* session
}
else {
vinfolog("HTTP response has a non-200 status code: %d", request.d_responseCode);
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
conn->handleResponseError(std::move(request), now);
@@ -730,7 +692,11 @@ int DoHConnectionToBackend::on_stream_close_callback(nghttp2_session* session, i
return 0;
}
- struct timeval now;
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+
gettimeofday(&now, nullptr);
auto request = std::move(stream->second);
conn->d_currentStreams.erase(stream->first);
@@ -856,55 +822,53 @@ DoHConnectionToBackend::DoHConnectionToBackend(const std::shared_ptr<DownstreamS
static void handleCrossProtocolQuery(int pipefd, FDMultiplexer::funcparam_t& param)
{
auto threadData = boost::any_cast<DoHClientThreadData*>(param);
- CrossProtocolQuery* tmp{nullptr};
- ssize_t got = read(pipefd, &tmp, sizeof(tmp));
- if (got == 0) {
- throw std::runtime_error("EOF while reading from the DoH cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
- }
- else if (got == -1) {
- if (errno == EAGAIN || errno == EINTR) {
+ std::unique_ptr<CrossProtocolQuery> cpq{nullptr};
+ try {
+ auto tmp = threadData->d_receiver.receive();
+ if (!tmp) {
return;
}
- throw std::runtime_error("Error while reading from the DoH cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode:" + stringerror());
+ cpq = std::move(*tmp);
}
- else if (got != sizeof(tmp)) {
- throw std::runtime_error("Partial read while reading from the DoH cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error while reading from the DoH cross-protocol channel:" + std::string(e.what()));
}
- try {
- struct timeval now;
- gettimeofday(&now, nullptr);
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
+ gettimeofday(&now, nullptr);
- std::shared_ptr<TCPQuerySender> tqs = tmp->getTCPQuerySender();
- auto query = std::move(tmp->query);
- auto downstreamServer = std::move(tmp->downstream);
- delete tmp;
- tmp = nullptr;
+ std::shared_ptr<TCPQuerySender> tqs = cpq->getTCPQuerySender();
+ auto query = std::move(cpq->query);
+ auto downstreamServer = std::move(cpq->downstream);
+ cpq.reset();
- try {
- auto downstream = t_downstreamDoHConnectionsManager.getConnectionToDownstream(threadData->mplexer, downstreamServer, now, std::move(query.d_proxyProtocolPayload));
- downstream->queueQuery(tqs, std::move(query));
- }
- catch (...) {
- tqs->notifyIOError(std::move(query.d_idstate), now);
- }
+ try {
+ auto downstream = t_downstreamDoHConnectionsManager.getConnectionToDownstream(threadData->mplexer, downstreamServer, now, std::move(query.d_proxyProtocolPayload));
+ downstream->queueQuery(tqs, std::move(query));
}
catch (...) {
- delete tmp;
- tmp = nullptr;
+ TCPResponse response(std::move(query));
+ tqs->notifyIOError(now, std::move(response));
}
}
-static void dohClientThread(int crossProtocolPipeFD)
+static void dohClientThread(pdns::channel::Receiver<CrossProtocolQuery>&& receiver)
{
setThreadName("dnsdist/dohClie");
try {
- DoHClientThreadData data;
- data.mplexer->addReadFD(crossProtocolPipeFD, handleCrossProtocolQuery, &data);
+ DoHClientThreadData data(std::move(receiver));
+ data.mplexer->addReadFD(data.d_receiver.getDescriptor(), handleCrossProtocolQuery, &data);
+
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
- struct timeval now;
gettimeofday(&now, nullptr);
time_t lastTimeoutScan = now.tv_sec;
@@ -925,31 +889,31 @@ static void dohClientThread(int crossProtocolPipeFD)
if (g_dohStatesDumpRequested > 0) {
/* no race here, we took the lock so it can only be increased in the meantime */
--g_dohStatesDumpRequested;
- errlog("Dumping the DoH client states, as requested:");
+ infolog("Dumping the DoH client states, as requested:");
data.mplexer->runForAllWatchedFDs([](bool isRead, int fd, const FDMultiplexer::funcparam_t& param, struct timeval ttd) {
struct timeval lnow;
gettimeofday(&lnow, nullptr);
if (ttd.tv_sec > 0) {
- errlog("- Descriptor %d is in %s state, TTD in %d", fd, (isRead ? "read" : "write"), (ttd.tv_sec - lnow.tv_sec));
+ infolog("- Descriptor %d is in %s state, TTD in %d", fd, (isRead ? "read" : "write"), (ttd.tv_sec - lnow.tv_sec));
}
else {
- errlog("- Descriptor %d is in %s state, no TTD set", fd, (isRead ? "read" : "write"));
+ infolog("- Descriptor %d is in %s state, no TTD set", fd, (isRead ? "read" : "write"));
}
if (param.type() == typeid(std::shared_ptr<DoHConnectionToBackend>)) {
auto conn = boost::any_cast<std::shared_ptr<DoHConnectionToBackend>>(param);
- errlog(" - %s", conn->toString());
+ infolog(" - %s", conn->toString());
}
else if (param.type() == typeid(DoHClientThreadData*)) {
- errlog(" - Worker thread pipe");
+ infolog(" - Worker thread pipe");
}
});
- errlog("The DoH client cache has %d active and %d idle outgoing connections cached", t_downstreamDoHConnectionsManager.getActiveCount(), t_downstreamDoHConnectionsManager.getIdleCount());
+ infolog("The DoH client cache has %d active and %d idle outgoing connections cached", t_downstreamDoHConnectionsManager.getActiveCount(), t_downstreamDoHConnectionsManager.getIdleCount());
}
}
}
catch (const std::exception& e) {
- errlog("Error in outgoing DoH thread: %s", e.what());
+ warnlog("Error in outgoing DoH thread: %s", e.what());
}
}
}
@@ -968,7 +932,7 @@ static bool select_next_proto_callback(unsigned char** out, unsigned char* outle
return true;
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
struct DoHClientCollection::DoHWorkerThread
{
@@ -976,40 +940,26 @@ struct DoHClientCollection::DoHWorkerThread
{
}
- DoHWorkerThread(int crossProtocolPipe) :
- d_crossProtocolQueryPipe(crossProtocolPipe)
+ DoHWorkerThread(pdns::channel::Sender<CrossProtocolQuery>&& sender) :
+ d_sender(std::move(sender))
{
}
DoHWorkerThread(DoHWorkerThread&& rhs) :
- d_crossProtocolQueryPipe(rhs.d_crossProtocolQueryPipe)
+ d_sender(std::move(rhs.d_sender))
{
- rhs.d_crossProtocolQueryPipe = -1;
}
DoHWorkerThread& operator=(DoHWorkerThread&& rhs)
{
- if (d_crossProtocolQueryPipe != -1) {
- close(d_crossProtocolQueryPipe);
- }
-
- d_crossProtocolQueryPipe = rhs.d_crossProtocolQueryPipe;
- rhs.d_crossProtocolQueryPipe = -1;
-
+ d_sender = std::move(rhs.d_sender);
return *this;
}
DoHWorkerThread(const DoHWorkerThread& rhs) = delete;
DoHWorkerThread& operator=(const DoHWorkerThread&) = delete;
- ~DoHWorkerThread()
- {
- if (d_crossProtocolQueryPipe != -1) {
- close(d_crossProtocolQueryPipe);
- }
- }
-
- int d_crossProtocolQueryPipe{-1};
+ pdns::channel::Sender<CrossProtocolQuery> d_sender;
};
DoHClientCollection::DoHClientCollection(size_t numberOfThreads) :
@@ -1024,13 +974,8 @@ bool DoHClientCollection::passCrossProtocolQueryToThread(std::unique_ptr<CrossPr
}
uint64_t pos = d_pos++;
- auto pipe = d_clientThreads.at(pos % d_numberOfThreads).d_crossProtocolQueryPipe;
- auto tmp = cpq.release();
-
- if (write(pipe, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- delete tmp;
- ++g_stats.outgoingDoHQueryPipeFull;
- tmp = nullptr;
+ if (!d_clientThreads.at(pos % d_numberOfThreads).d_sender.send(std::move(cpq))) {
+ ++dnsdist::metrics::g_stats.outgoingDoHQueryPipeFull;
return false;
}
@@ -1039,78 +984,44 @@ bool DoHClientCollection::passCrossProtocolQueryToThread(std::unique_ptr<CrossPr
void DoHClientCollection::addThread()
{
-#ifdef HAVE_NGHTTP2
- auto preparePipe = [](int fds[2], const std::string& type) -> bool {
- if (pipe(fds) < 0) {
- errlog("Error creating the DoH thread %s pipe: %s", type, stringerror());
- return false;
- }
-
- if (!setNonBlocking(fds[0])) {
- int err = errno;
- close(fds[0]);
- close(fds[1]);
- errlog("Error setting the DoH thread %s pipe non-blocking: %s", type, stringerror(err));
- return false;
- }
-
- if (!setNonBlocking(fds[1])) {
- int err = errno;
- close(fds[0]);
- close(fds[1]);
- errlog("Error setting the DoH thread %s pipe non-blocking: %s", type, stringerror(err));
- return false;
- }
-
- if (g_tcpInternalPipeBufferSize > 0 && getPipeBufferSize(fds[0]) < g_tcpInternalPipeBufferSize) {
- setPipeBufferSize(fds[0], g_tcpInternalPipeBufferSize);
- }
-
- return true;
- };
-
- int crossProtocolFDs[2] = {-1, -1};
- if (!preparePipe(crossProtocolFDs, "cross-protocol")) {
- return;
- }
-
- vinfolog("Adding DoH Client thread");
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ try {
+ auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
- {
+ vinfolog("Adding DoH Client thread");
std::lock_guard<std::mutex> lock(d_mutex);
if (d_numberOfThreads >= d_clientThreads.size()) {
vinfolog("Adding a new DoH client thread would exceed the vector size (%d/%d), skipping. Consider increasing the maximum amount of DoH client threads with setMaxDoHClientThreads() in the configuration.", d_numberOfThreads, d_clientThreads.size());
- close(crossProtocolFDs[0]);
- close(crossProtocolFDs[1]);
return;
}
- /* from now on this side of the pipe will be managed by that object,
- no need to worry about it */
- DoHWorkerThread worker(crossProtocolFDs[1]);
+ DoHWorkerThread worker(std::move(sender));
try {
- std::thread t1(dohClientThread, crossProtocolFDs[0]);
+ std::thread t1(dohClientThread, std::move(receiver));
t1.detach();
}
catch (const std::runtime_error& e) {
- /* the thread creation failed, don't leak */
+ /* the thread creation failed */
errlog("Error creating a DoH thread: %s", e.what());
- close(crossProtocolFDs[0]);
return;
}
d_clientThreads.at(d_numberOfThreads) = std::move(worker);
++d_numberOfThreads;
}
-#else /* HAVE_NGHTTP2 */
+ catch (const std::exception& e) {
+ errlog("Error creating the DoH channel: %s", e.what());
+ return;
+ }
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
throw std::runtime_error("DoHClientCollection::addThread() called but nghttp2 support is not available");
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
bool initDoHWorkers()
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
if (!g_outgoingDoHWorkerThreads) {
/* Unless the value has been set to 0 explicitly, always start at least one outgoing DoH worker thread, in case a DoH backend
is added at a later time. */
@@ -1126,7 +1037,7 @@ bool initDoHWorkers()
return true;
#else
return false;
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
@@ -1134,21 +1045,24 @@ bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
if (ctx == nullptr) {
return false;
}
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
/* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */
const std::vector<std::vector<uint8_t>> h2Alpns = {{'h', '2'}};
ctx->setALPNProtos(h2Alpns);
ctx->setNextProtocolSelectCallback(select_next_proto_callback);
return true;
-#else /* HAVE_NGHTTP2 */
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return false;
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
bool sendH2Query(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, std::shared_ptr<TCPQuerySender>& sender, InternalQuery&& query, bool healthCheck)
{
-#ifdef HAVE_NGHTTP2
- struct timeval now;
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ struct timeval now
+ {
+ .tv_sec = 0, .tv_usec = 0
+ };
gettimeofday(&now, nullptr);
if (healthCheck) {
@@ -1163,24 +1077,24 @@ bool sendH2Query(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDM
}
return true;
-#else /* HAVE_NGHTTP2 */
+#else /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return false;
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
size_t clearH2Connections()
{
size_t cleared = 0;
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
cleared = t_downstreamDoHConnectionsManager.clear();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return cleared;
}
size_t handleH2Timeouts(FDMultiplexer& mplexer, const struct timeval& now)
{
size_t got = 0;
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
auto expiredReadConns = mplexer.getTimeouts(now, false);
for (const auto& cbData : expiredReadConns) {
if (cbData.second.type() == typeid(std::shared_ptr<DoHConnectionToBackend>)) {
@@ -1200,27 +1114,27 @@ size_t handleH2Timeouts(FDMultiplexer& mplexer, const struct timeval& now)
++got;
}
}
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
return got;
}
void setDoHDownstreamCleanupInterval(uint16_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setCleanupInterval(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
void setDoHDownstreamMaxIdleTime(uint16_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setMaxIdleTime(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
void setDoHDownstreamMaxIdleConnectionsPerBackend(size_t max)
{
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
DownstreamDoHConnectionsManager::setMaxIdleConnectionsPerDownstream(max);
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
diff --git a/dnsdist-prometheus.hh b/dnsdist-prometheus.hh
index 15567bf..011053d 100644
--- a/dnsdist-prometheus.hh
+++ b/dnsdist-prometheus.hh
@@ -21,6 +21,17 @@
*/
#pragma once
+namespace dnsdist::prometheus
+{
+struct PrometheusMetricDefinition
+{
+ const std::string& name;
+ const std::string& type;
+ const std::string& description;
+ const std::string& customName;
+};
+}
+
#ifndef DISABLE_PROMETHEUS
// Metric types for Prometheus
enum class PrometheusMetricType: uint8_t {
@@ -56,16 +67,16 @@ struct MetricDefinitionStorage {
return true;
};
- static bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customName) {
+ static bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def) {
static const std::map<std::string, PrometheusMetricType> namesToTypes = {
{"counter", PrometheusMetricType::counter},
{"gauge", PrometheusMetricType::gauge},
};
- auto realtype = namesToTypes.find(type);
+ auto realtype = namesToTypes.find(def.type);
if (realtype == namesToTypes.end()) {
return false;
}
- metrics.emplace(name, MetricDefinition{realtype->second, description, customName});
+ metrics.emplace(def.name, MetricDefinition{realtype->second, def.description, def.customName});
return true;
}
diff --git a/dnsdist-protobuf.cc b/dnsdist-protobuf.cc
index c38529c..30445ed 100644
--- a/dnsdist-protobuf.cc
+++ b/dnsdist-protobuf.cc
@@ -27,11 +27,13 @@
#include "dnsdist-protobuf.hh"
#include "protozero.hh"
-DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dq): d_dq(dq), d_type(pdns::ProtoZero::Message::MessageType::DNSQueryType)
+DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dnsquestion) :
+ d_dq(dnsquestion)
{
}
-DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME): d_dq(dr), d_dr(&dr), d_type(pdns::ProtoZero::Message::MessageType::DNSResponseType), d_includeCNAME(includeCNAME)
+DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dnsresponse, bool includeCNAME) :
+ d_dq(dnsresponse), d_dr(&dnsresponse), d_type(pdns::ProtoZero::Message::MessageType::DNSResponseType), d_includeCNAME(includeCNAME)
{
}
@@ -104,11 +106,14 @@ void DNSDistProtoBufMessage::addTag(const std::string& strValue)
d_additionalTags.push_back(strValue);
}
-void DNSDistProtoBufMessage::addMeta(const std::string& key, std::vector<std::string>&& values)
+void DNSDistProtoBufMessage::addMeta(const std::string& key, std::vector<std::string>&& strValues, const std::vector<int64_t>& intValues)
{
auto& entry = d_metaTags[key];
- for (auto& value : values) {
- entry.insert(std::move(value));
+ for (auto& value : strValues) {
+ entry.d_strings.insert(std::move(value));
+ }
+ for (const auto& value : intValues) {
+ entry.d_integers.insert(value);
}
}
@@ -146,6 +151,11 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const
}
else if (distProto == dnsdist::Protocol::DoH) {
protocol = pdns::ProtoZero::Message::TransportProtocol::DoH;
+ m.setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion::HTTP2);
+ }
+ else if (distProto == dnsdist::Protocol::DoH3) {
+ protocol = pdns::ProtoZero::Message::TransportProtocol::DoH;
+ m.setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion::HTTP3);
}
else if (distProto == dnsdist::Protocol::DNSCryptUDP) {
protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptUDP;
@@ -153,6 +163,9 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const
else if (distProto == dnsdist::Protocol::DNSCryptTCP) {
protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptTCP;
}
+ else if (distProto == dnsdist::Protocol::DoQ) {
+ protocol = pdns::ProtoZero::Message::TransportProtocol::DoQ;
+ }
m.setRequest(d_dq.ids.d_protoBufData && d_dq.ids.d_protoBufData->uniqueId ? *d_dq.ids.d_protoBufData->uniqueId : getUniqueID(), d_requestor ? *d_requestor : d_dq.ids.origRemote, d_responder ? *d_responder : d_dq.ids.origDest, d_question ? d_question->d_name : d_dq.ids.qname, d_question ? d_question->d_type : d_dq.ids.qtype, d_question ? d_question->d_class : d_dq.ids.qclass, d_dq.getHeader()->id, protocol, d_bytes ? *d_bytes : d_dq.getData().size());
@@ -210,8 +223,8 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const
}
for (const auto& [key, values] : d_metaTags) {
- if (!values.empty()) {
- m.setMeta(key, values, {});
+ if (!values.d_strings.empty() || !values.d_integers.empty()) {
+ m.setMeta(key, values.d_strings, values.d_integers);
}
else {
/* the MetaValue field is _required_ to exist, even if we have no value */
@@ -255,14 +268,14 @@ ProtoBufMetaKey::ProtoBufMetaKey(const std::string& key)
throw std::runtime_error("Invalid ProtoBuf key '" + key + "'");
}
-std::vector<std::string> ProtoBufMetaKey::getValues(const DNSQuestion& dq) const
+std::vector<std::string> ProtoBufMetaKey::getValues(const DNSQuestion& dnsquestion) const
{
auto& idx = s_types.get<TypeTag>();
auto it = idx.find(d_type);
if (it == idx.end()) {
throw std::runtime_error("Trying to get the values of an unsupported type: " + std::to_string(static_cast<uint8_t>(d_type)));
}
- return (it->d_func)(dq, d_subKey, d_numericSubKey);
+ return (it->d_func)(dnsquestion, d_subKey, d_numericSubKey);
}
const std::string& ProtoBufMetaKey::getName() const
@@ -276,94 +289,104 @@ const std::string& ProtoBufMetaKey::getName() const
}
const ProtoBufMetaKey::TypeContainer ProtoBufMetaKey::s_types = {
- ProtoBufMetaKey::KeyTypeDescription{ "sni", Type::SNI, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> { return {dq.sni}; }, false },
- ProtoBufMetaKey::KeyTypeDescription{ "pool", Type::Pool, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> { return {dq.ids.poolName}; }, false },
- ProtoBufMetaKey::KeyTypeDescription{ "b64-content", Type::B64Content, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> { const auto& data = dq.getData(); return {Base64Encode(std::string(data.begin(), data.end()))}; }, false },
+ ProtoBufMetaKey::KeyTypeDescription{"sni", Type::SNI, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> { return {dnsquestion.sni}; }, false},
+ ProtoBufMetaKey::KeyTypeDescription{"pool", Type::Pool, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> { return {dnsquestion.ids.poolName}; }, false},
+ ProtoBufMetaKey::KeyTypeDescription{"b64-content", Type::B64Content, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> { const auto& data = dnsquestion.getData(); return {Base64Encode(std::string(data.begin(), data.end()))}; }, false},
#ifdef HAVE_DNS_OVER_HTTPS
- ProtoBufMetaKey::KeyTypeDescription{ "doh-header", Type::DoHHeader, [](const DNSQuestion& dq , const std::string& name, uint8_t) -> std::vector<std::string> {
- if (!dq.ids.du) {
- return {};
- }
- auto headers = dq.ids.du->getHTTPHeaders();
- auto it = headers.find(name);
- if (it != headers.end()) {
- return {it->second};
- }
- return {};
- }, true, false },
- ProtoBufMetaKey::KeyTypeDescription{ "doh-host", Type::DoHHost, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- if (dq.ids.du) {
- return {dq.ids.du->getHTTPHost()};
- }
- return {};
- }, true, false },
- ProtoBufMetaKey::KeyTypeDescription{ "doh-path", Type::DoHPath, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- if (dq.ids.du) {
- return {dq.ids.du->getHTTPPath()};
- }
- return {};
- }, false },
- ProtoBufMetaKey::KeyTypeDescription{ "doh-query-string", Type::DoHQueryString, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- if (dq.ids.du) {
- return {dq.ids.du->getHTTPQueryString()};
- }
- return {};
- }, false },
- ProtoBufMetaKey::KeyTypeDescription{ "doh-scheme", Type::DoHScheme, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- if (dq.ids.du) {
- return {dq.ids.du->getHTTPScheme()};
- }
- return {};
- }, false, false },
+ ProtoBufMetaKey::KeyTypeDescription{"doh-header", Type::DoHHeader, [](const DNSQuestion& dnsquestion, const std::string& name, uint8_t) -> std::vector<std::string> {
+ if (!dnsquestion.ids.du) {
+ return {};
+ }
+ auto headers = dnsquestion.ids.du->getHTTPHeaders();
+ auto iter = headers.find(name);
+ if (iter != headers.end()) {
+ return {iter->second};
+ }
+ return {};
+ },
+ true, false},
+ ProtoBufMetaKey::KeyTypeDescription{"doh-host", Type::DoHHost, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ if (dnsquestion.ids.du) {
+ return {dnsquestion.ids.du->getHTTPHost()};
+ }
+ return {};
+ },
+ true, false},
+ ProtoBufMetaKey::KeyTypeDescription{"doh-path", Type::DoHPath, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ if (dnsquestion.ids.du) {
+ return {dnsquestion.ids.du->getHTTPPath()};
+ }
+ return {};
+ },
+ false},
+ ProtoBufMetaKey::KeyTypeDescription{"doh-query-string", Type::DoHQueryString, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ if (dnsquestion.ids.du) {
+ return {dnsquestion.ids.du->getHTTPQueryString()};
+ }
+ return {};
+ },
+ false},
+ ProtoBufMetaKey::KeyTypeDescription{"doh-scheme", Type::DoHScheme, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ if (dnsquestion.ids.du) {
+ return {dnsquestion.ids.du->getHTTPScheme()};
+ }
+ return {};
+ },
+ false, false},
#endif // HAVE_DNS_OVER_HTTPS
- ProtoBufMetaKey::KeyTypeDescription{ "proxy-protocol-value", Type::ProxyProtocolValue, [](const DNSQuestion& dq, const std::string&, uint8_t numericSubKey) -> std::vector<std::string> {
- if (!dq.proxyProtocolValues) {
- return {};
- }
- for (const auto& value : *dq.proxyProtocolValues) {
- if (value.type == numericSubKey) {
- return {value.content};
- }
- }
- return {};
- }, true, false, true },
- ProtoBufMetaKey::KeyTypeDescription{ "proxy-protocol-values", Type::ProxyProtocolValues, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- std::vector<std::string> result;
- if (!dq.proxyProtocolValues) {
- return result;
- }
- for (const auto& value : *dq.proxyProtocolValues) {
- result.push_back(std::to_string(value.type) + ":" + value.content);
- }
- return result;
- } },
- ProtoBufMetaKey::KeyTypeDescription{ "tag", Type::Tag, [](const DNSQuestion& dq, const std::string& subKey, uint8_t) -> std::vector<std::string> {
- if (!dq.ids.qTag) {
- return {};
- }
- for (const auto& [key, value] : *dq.ids.qTag) {
- if (key == subKey) {
- return {value};
- }
- }
- return {};
- }, true, true },
- ProtoBufMetaKey::KeyTypeDescription{ "tags", Type::Tags, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector<std::string> {
- std::vector<std::string> result;
- if (!dq.ids.qTag) {
- return result;
- }
- for (const auto& [key, value] : *dq.ids.qTag) {
- if (value.empty()) {
- /* avoids a spurious ':' when the value is empty */
- result.push_back(key);
- }
- else {
- result.push_back(key + ":" + value);
- }
- }
- return result;
- } },
+ ProtoBufMetaKey::KeyTypeDescription{"proxy-protocol-value", Type::ProxyProtocolValue, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t numericSubKey) -> std::vector<std::string> {
+ if (!dnsquestion.proxyProtocolValues) {
+ return {};
+ }
+ for (const auto& value : *dnsquestion.proxyProtocolValues) {
+ if (value.type == numericSubKey) {
+ return {value.content};
+ }
+ }
+ return {};
+ },
+ true, false, true},
+ ProtoBufMetaKey::KeyTypeDescription{"proxy-protocol-values", Type::ProxyProtocolValues, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ std::vector<std::string> result;
+ if (!dnsquestion.proxyProtocolValues) {
+ return result;
+ }
+ for (const auto& value : *dnsquestion.proxyProtocolValues) {
+ result.push_back(std::to_string(value.type) + ":" + value.content);
+ }
+ return result;
+ }},
+ ProtoBufMetaKey::KeyTypeDescription{"tag", Type::Tag, [](const DNSQuestion& dnsquestion, const std::string& subKey, uint8_t) -> std::vector<std::string> {
+ if (!dnsquestion.ids.qTag) {
+ return {};
+ }
+ for (const auto& [key, value] : *dnsquestion.ids.qTag) {
+ if (key == subKey) {
+ return {value};
+ }
+ }
+ return {};
+ },
+ true, true},
+ ProtoBufMetaKey::KeyTypeDescription{"tags", Type::Tags, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector<std::string> {
+ std::vector<std::string> result;
+ if (!dnsquestion.ids.qTag) {
+ return result;
+ }
+ for (const auto& [key, value] : *dnsquestion.ids.qTag) {
+ if (value.empty()) {
+ /* avoids a spurious ':' when the value is empty */
+ result.push_back(key);
+ }
+ else {
+ auto tag = key;
+ tag.append(":");
+ tag.append(value);
+ result.push_back(tag);
+ }
+ }
+ return result;
+ }},
};
#endif /* DISABLE_PROTOBUF */
diff --git a/dnsdist-protobuf.hh b/dnsdist-protobuf.hh
index 3930538..c2dee81 100644
--- a/dnsdist-protobuf.hh
+++ b/dnsdist-protobuf.hh
@@ -30,8 +30,10 @@
class DNSDistProtoBufMessage
{
public:
- DNSDistProtoBufMessage(const DNSQuestion& dq);
- DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME);
+ DNSDistProtoBufMessage(const DNSQuestion& dnsquestion);
+ DNSDistProtoBufMessage(const DNSResponse& dnsresponse, bool includeCNAME);
+ DNSDistProtoBufMessage(const DNSQuestion&&) = delete;
+ DNSDistProtoBufMessage(const DNSResponse&&, bool) = delete;
void setServerIdentity(const std::string& serverId);
void setRequestor(const ComboAddress& requestor);
@@ -40,19 +42,20 @@ public:
void setResponderPort(uint16_t port);
void setResponseCode(uint8_t rcode);
void setType(pdns::ProtoZero::Message::MessageType type);
+ void setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion version);
void setBytes(size_t bytes);
void setTime(time_t sec, uint32_t usec);
void setQueryTime(time_t sec, uint32_t usec);
void setQuestion(const DNSName& name, uint16_t qtype, uint16_t qclass);
- void setEDNSSubnet(const Netmask& nm);
+ void setEDNSSubnet(const Netmask& netmask);
void addTag(const std::string& strValue);
- void addMeta(const std::string& key, std::vector<std::string>&& values);
+ void addMeta(const std::string& key, std::vector<std::string>&& strValues, const std::vector<int64_t>& intValues);
void addRR(DNSName&& qname, uint16_t uType, uint16_t uClass, uint32_t uTTL, const std::string& data);
void serialize(std::string& data) const;
- std::string toDebugString() const;
+ [[nodiscard]] std::string toDebugString() const;
private:
struct PBRecord
@@ -65,7 +68,8 @@ private:
};
struct PBQuestion
{
- PBQuestion(const DNSName& name, uint16_t type, uint16_t class_): d_name(name), d_type(type), d_class(class_)
+ PBQuestion(DNSName name, uint16_t type, uint16_t class_) :
+ d_name(std::move(name)), d_type(type), d_class(class_)
{
}
@@ -76,8 +80,14 @@ private:
std::vector<PBRecord> d_additionalRRs;
std::vector<std::string> d_additionalTags;
- std::unordered_map<std::string, std::unordered_set<std::string>> d_metaTags;
+ struct MetaValue
+ {
+ std::unordered_set<std::string> d_strings;
+ std::unordered_set<int64_t> d_integers;
+ };
+ std::unordered_map<std::string, MetaValue> d_metaTags;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const DNSQuestion& d_dq;
const DNSResponse* d_dr{nullptr};
const std::string* d_ServerIdentityRef{nullptr};
@@ -98,36 +108,56 @@ private:
class ProtoBufMetaKey
{
- enum class Type : uint8_t { SNI, Pool, B64Content, DoHHeader, DoHHost, DoHPath, DoHQueryString, DoHScheme, ProxyProtocolValue, ProxyProtocolValues, Tag, Tags };
+ enum class Type : uint8_t
+ {
+ SNI,
+ Pool,
+ B64Content,
+ DoHHeader,
+ DoHHost,
+ DoHPath,
+ DoHQueryString,
+ DoHScheme,
+ ProxyProtocolValue,
+ ProxyProtocolValues,
+ Tag,
+ Tags
+ };
struct KeyTypeDescription
{
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::string d_name;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const Type d_type;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
const std::function<std::vector<std::string>(const DNSQuestion&, const std::string&, uint8_t)> d_func;
bool d_prefix{false};
bool d_caseSensitive{true};
bool d_numeric{false};
};
- struct NameTag {};
- struct TypeTag {};
+ struct NameTag
+ {
+ };
+ struct TypeTag
+ {
+ };
- typedef boost::multi_index_container<
+ using TypeContainer = boost::multi_index_container<
KeyTypeDescription,
- indexed_by <
+ indexed_by<
hashed_unique<tag<NameTag>, member<KeyTypeDescription, const std::string, &KeyTypeDescription::d_name>>,
- hashed_unique<tag<TypeTag>, member<KeyTypeDescription, const Type, &KeyTypeDescription::d_type>>
- >
- > TypeContainer;
+ hashed_unique<tag<TypeTag>, member<KeyTypeDescription, const Type, &KeyTypeDescription::d_type>>>>;
static const TypeContainer s_types;
public:
ProtoBufMetaKey(const std::string& key);
- const std::string& getName() const;
- std::vector<std::string> getValues(const DNSQuestion& dq) const;
+ [[nodiscard]] const std::string& getName() const;
+ [[nodiscard]] std::vector<std::string> getValues(const DNSQuestion& dnsquestion) const;
+
private:
std::string d_subKey;
uint8_t d_numericSubKey{0};
diff --git a/dnsdist-protocols.cc b/dnsdist-protocols.cc
index aee63f2..886e7ee 100644
--- a/dnsdist-protocols.cc
+++ b/dnsdist-protocols.cc
@@ -33,7 +33,9 @@ const std::array<std::string, Protocol::s_numberOfProtocols> Protocol::s_names =
"DNSCryptUDP",
"DNSCryptTCP",
"DoT",
- "DoH"};
+ "DoH",
+ "DoQ",
+ "DoH3"};
const std::array<std::string, Protocol::s_numberOfProtocols> Protocol::s_prettyNames = {
"Do53 UDP",
@@ -41,7 +43,9 @@ const std::array<std::string, Protocol::s_numberOfProtocols> Protocol::s_prettyN
"DNSCrypt UDP",
"DNSCrypt TCP",
"DNS over TLS",
- "DNS over HTTPS"};
+ "DNS over HTTPS",
+ "DNS over QUIC",
+ "DNS over HTTP/3"};
Protocol::Protocol(const std::string& s)
{
@@ -79,6 +83,11 @@ bool Protocol::isUDP() const
return d_protocol == DoUDP || d_protocol == DNSCryptUDP;
}
+bool Protocol::isEncrypted() const
+{
+ return d_protocol != DoUDP && d_protocol != DoTCP;
+}
+
uint8_t Protocol::toNumber() const
{
return static_cast<uint8_t>(d_protocol);
diff --git a/dnsdist-protocols.hh b/dnsdist-protocols.hh
index bd2a4bb..beb43ed 100644
--- a/dnsdist-protocols.hh
+++ b/dnsdist-protocols.hh
@@ -37,7 +37,9 @@ public:
DNSCryptUDP,
DNSCryptTCP,
DoT,
- DoH
+ DoH,
+ DoQ,
+ DoH3
};
Protocol(typeenum protocol = DoUDP) :
@@ -56,12 +58,13 @@ public:
const std::string& toString() const;
const std::string& toPrettyString() const;
bool isUDP() const;
+ bool isEncrypted() const;
uint8_t toNumber() const;
private:
typeenum d_protocol;
- static constexpr size_t s_numberOfProtocols = 6;
+ static constexpr size_t s_numberOfProtocols = 8;
static const std::array<std::string, s_numberOfProtocols> s_names;
static const std::array<std::string, s_numberOfProtocols> s_prettyNames;
};
diff --git a/dnsdist-proxy-protocol.cc b/dnsdist-proxy-protocol.cc
index aefcafb..d19e872 100644
--- a/dnsdist-proxy-protocol.cc
+++ b/dnsdist-proxy-protocol.cc
@@ -21,6 +21,7 @@
*/
#include "dnsdist-proxy-protocol.hh"
+#include "dnsdist-metrics.hh"
#include "dolog.hh"
NetmaskGroup g_proxyProtocolACL;
@@ -81,13 +82,13 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
ssize_t used = parseProxyHeader(query, proxyProto, realRemote, realDestination, tcp, values);
if (used <= 0) {
- ++g_stats.proxyProtocolInvalid;
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
vinfolog("Ignoring invalid proxy protocol (%d, %d) query over %s from %s", query.size(), used, (isTCP ? "TCP" : "UDP"), remote.toStringWithPort());
return false;
}
else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
vinfolog("Proxy protocol header in %s packet from %s is larger than proxy-protocol-maximum-size (%d), dropping", (isTCP ? "TCP" : "UDP"), remote.toStringWithPort(), used);
- ++g_stats.proxyProtocolInvalid;
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
return false;
}
@@ -95,14 +96,14 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
/* on TCP we have not read the actual query yet */
if (!isTCP && query.size() < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
if (proxyProto && g_applyACLToProxiedClients) {
if (!acl.match(realRemote)) {
vinfolog("Query from %s dropped because of ACL", realRemote.toStringWithPort());
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
return false;
}
}
diff --git a/dnsdist-resolver.cc b/dnsdist-resolver.cc
new file mode 100644
index 0000000..8e3417d
--- /dev/null
+++ b/dnsdist-resolver.cc
@@ -0,0 +1,52 @@
+/*
+ * 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 <vector>
+
+#include "dnsdist-resolver.hh"
+#include "iputils.hh"
+
+namespace dnsdist::resolver
+{
+void asynchronousResolver(const std::string& hostname, const std::function<void(const std::string& hostname, std::vector<ComboAddress>& ips)>& callback)
+{
+ addrinfo hints{};
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_DGRAM;
+ addrinfo* infosRaw{nullptr};
+ std::vector<ComboAddress> addresses;
+ auto ret = getaddrinfo(hostname.c_str(), nullptr, &hints, &infosRaw);
+ if (ret != 0) {
+ callback(hostname, addresses);
+ return;
+ }
+ auto infos = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>(infosRaw, &freeaddrinfo);
+ for (const auto* addr = infos.get(); addr != nullptr; addr = addr->ai_next) {
+ try {
+ addresses.emplace_back(addr->ai_addr, addr->ai_addrlen);
+ }
+ catch (...) {
+ }
+ }
+ callback(hostname, addresses);
+}
+}
diff --git a/dnsdist-resolver.hh b/dnsdist-resolver.hh
new file mode 100644
index 0000000..44b1616
--- /dev/null
+++ b/dnsdist-resolver.hh
@@ -0,0 +1,28 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "iputils.hh"
+
+namespace dnsdist::resolver
+{
+void asynchronousResolver(const std::string& hostname, const std::function<void(const std::string& hostname, std::vector<ComboAddress>& ips)>& callback);
+}
diff --git a/dnsdist-rings.cc b/dnsdist-rings.cc
index 5485b33..b97b44e 100644
--- a/dnsdist-rings.cc
+++ b/dnsdist-rings.cc
@@ -214,3 +214,12 @@ size_t Rings::loadFromFile(const std::string& filepath, const struct timespec& n
return inserted;
}
+
+bool Rings::Response::isACacheHit() const
+{
+ bool hit = ds.sin4.sin_family == 0;
+ if (!hit && ds.isIPv4() && ds.sin4.sin_addr.s_addr == 0 && ds.sin4.sin_port == 0) {
+ hit = true;
+ }
+ return hit;
+}
diff --git a/dnsdist-rings.hh b/dnsdist-rings.hh
index 6bd93af..084044f 100644
--- a/dnsdist-rings.hh
+++ b/dnsdist-rings.hh
@@ -58,10 +58,12 @@ struct Rings {
struct timespec when;
struct dnsheader dh;
unsigned int usec;
- unsigned int size;
+ uint16_t size;
uint16_t qtype;
// outgoing protocol
dnsdist::Protocol protocol;
+
+ bool isACacheHit() const;
};
struct Shard
@@ -236,7 +238,7 @@ private:
#endif
}
- void insertResponseLocked(boost::circular_buffer<Response>& ring, const struct timespec& when, const ComboAddress& requestor, const DNSName& name, uint16_t qtype, unsigned int usec, unsigned int size, const struct dnsheader& dh, const ComboAddress& backend, dnsdist::Protocol protocol)
+ void insertResponseLocked(boost::circular_buffer<Response>& ring, const struct timespec& when, const ComboAddress& requestor, const DNSName& name, uint16_t qtype, unsigned int usec, uint16_t size, const struct dnsheader& dh, const ComboAddress& backend, dnsdist::Protocol protocol)
{
if (!ring.full()) {
d_nbResponseEntries++;
diff --git a/dnsdist-rules.hh b/dnsdist-rules.hh
index 2457b2b..d0f2fcb 100644
--- a/dnsdist-rules.hh
+++ b/dnsdist-rules.hh
@@ -33,6 +33,7 @@
#include "dnsdist-lua-ffi.hh"
#include "dolog.hh"
#include "dnsparser.hh"
+#include "dns_random.hh"
class MaxQPSIPRule : public DNSRule
{
@@ -556,7 +557,7 @@ private:
class HTTPPathRule : public DNSRule
{
public:
- HTTPPathRule(const std::string& path);
+ HTTPPathRule(std::string path);
bool matches(const DNSQuestion* dq) const override;
string toString() const override;
private:
@@ -1055,7 +1056,7 @@ public:
{
if(d_proba == 1.0)
return true;
- double rnd = 1.0*random() / RAND_MAX;
+ double rnd = 1.0*dns_random_uint32() / UINT32_MAX;
return rnd > (1.0 - d_proba);
}
string toString() const override
@@ -1069,7 +1070,7 @@ private:
class TagRule : public DNSRule
{
public:
- TagRule(const std::string& tag, boost::optional<std::string> value) : d_value(value), d_tag(tag)
+ TagRule(const std::string& tag, boost::optional<std::string> value) : d_value(std::move(value)), d_tag(tag)
{
}
bool matches(const DNSQuestion* dq) const override
@@ -1318,7 +1319,7 @@ private:
class ProxyProtocolValueRule : public DNSRule
{
public:
- ProxyProtocolValueRule(uint8_t type, boost::optional<std::string> value): d_value(value), d_type(type)
+ ProxyProtocolValueRule(uint8_t type, boost::optional<std::string> value): d_value(std::move(value)), d_type(type)
{
}
@@ -1349,3 +1350,66 @@ private:
boost::optional<std::string> d_value;
uint8_t d_type;
};
+
+class PayloadSizeRule : public DNSRule
+{
+ enum class Comparisons : uint8_t { equal, greater, greaterOrEqual, smaller, smallerOrEqual };
+public:
+ PayloadSizeRule(const std::string& comparison, uint16_t size): d_size(size)
+ {
+ if (comparison == "equal") {
+ d_comparison = Comparisons::equal;
+ }
+ else if (comparison == "greater") {
+ d_comparison = Comparisons::greater;
+ }
+ else if (comparison == "greaterOrEqual") {
+ d_comparison = Comparisons::greaterOrEqual;
+ }
+ else if (comparison == "smaller") {
+ d_comparison = Comparisons::smaller;
+ }
+ else if (comparison == "smallerOrEqual") {
+ d_comparison = Comparisons::smallerOrEqual;
+ }
+ else {
+ throw std::runtime_error("Unsupported comparison '" + comparison + "'");
+ }
+ }
+
+ bool matches(const DNSQuestion* dq) const override
+ {
+ const auto size = dq->getData().size();
+
+ switch (d_comparison) {
+ case Comparisons::equal:
+ return size == d_size;
+ case Comparisons::greater:
+ return size > d_size;
+ case Comparisons::greaterOrEqual:
+ return size >= d_size;
+ case Comparisons::smaller:
+ return size < d_size;
+ case Comparisons::smallerOrEqual:
+ return size <= d_size;
+ default:
+ return false;
+ }
+ }
+
+ string toString() const override
+ {
+ static const std::array<const std::string, 5> comparisonStr{
+ "equal to" ,
+ "greater than",
+ "equal to or greater than",
+ "smaller than",
+ "equal to or smaller than"
+ };
+ return "payload size is " + comparisonStr.at(static_cast<size_t>(d_comparison)) + " " + std::to_string(d_size);
+ }
+
+private:
+ uint16_t d_size;
+ Comparisons d_comparison;
+};
diff --git a/dnsdist-secpoll.cc b/dnsdist-secpoll.cc
index eb38d35..26c48ba 100644
--- a/dnsdist-secpoll.cc
+++ b/dnsdist-secpoll.cc
@@ -36,6 +36,7 @@
#include "sstuff.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-random.hh"
#ifndef PACKAGEVERSION
@@ -48,7 +49,7 @@ static std::string getFirstTXTAnswer(const std::string& answer)
throw std::runtime_error("Looking for a TXT record in an answer smaller than the DNS header");
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(answer.data());
+ const dnsheader_aligned dh(answer.data());
PacketReader pr(answer);
uint16_t qdcount = ntohs(dh->qdcount);
uint16_t ancount = ntohs(dh->ancount);
@@ -210,21 +211,21 @@ void doSecPoll(const std::string& suffix)
int securityStatus = std::stoi(split.first);
std::string securityMessage = split.second;
- if(securityStatus == 1 && !g_secPollDone) {
- warnlog("Polled security status of version %s at startup, no known issues reported: %s", std::string(VERSION), securityMessage);
+ if (securityStatus == 1 && !g_secPollDone) {
+ infolog("Polled security status of version %s at startup, no known issues reported: %s", std::string(VERSION), securityMessage);
}
- if(securityStatus == 2) {
+ if (securityStatus == 2) {
errlog("PowerDNS DNSDist Security Update Recommended: %s", securityMessage);
}
else if(securityStatus == 3) {
errlog("PowerDNS DNSDist Security Update Mandatory: %s", securityMessage);
}
- g_stats.securityStatus = securityStatus;
+ dnsdist::metrics::g_stats.securityStatus = securityStatus;
g_secPollDone = true;
return;
}
- catch(const std::exception& e) {
+ catch (const std::exception& e) {
if (releaseVersion) {
warnlog("Error while retrieving the security update for version %s: %s", version, e.what());
}
diff --git a/dnsdist-snmp.cc b/dnsdist-snmp.cc
index d853a32..856fccb 100644
--- a/dnsdist-snmp.cc
+++ b/dnsdist-snmp.cc
@@ -1,5 +1,6 @@
#include "dnsdist-snmp.hh"
+#include "dnsdist-metrics.hh"
#include "dolog.hh"
bool g_snmpEnabled{false};
@@ -55,7 +56,7 @@ static const oid securityStatusOID[] = { DNSDIST_STATS_OID, 38 };
static const oid specialMemoryUsageOID[] = { DNSDIST_STATS_OID, 39 };
static const oid ruleTruncatedOID[] = { DNSDIST_STATS_OID, 40 };
-static std::unordered_map<oid, DNSDistStats::entry_t> s_statsMap;
+static std::unordered_map<oid, dnsdist::metrics::Stats::entry_t> s_statsMap;
/* We are never called for a GETNEXT if it's registered as a
"instance", as it's "magically" handled for us. */
@@ -80,7 +81,7 @@ static int handleCounter64Stats(netsnmp_mib_handler* handler,
return SNMP_ERR_GENERR;
}
- if (const auto& val = boost::get<pdns::stat_t*>(&it->second)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&it->second)) {
return DNSDistSNMPAgent::setCounter64Value(requests, (*val)->load());
}
@@ -125,7 +126,7 @@ static int handleFloatStats(netsnmp_mib_handler* handler,
return SNMP_ERR_GENERR;
}
- if (const auto& val = boost::get<double*>(&it->second)) {
+ if (const auto& val = std::get_if<double*>(&it->second)) {
std::string str(std::to_string(**val));
snmp_set_var_typed_value(requests->requestvb,
ASN_OCTET_STR,
@@ -176,11 +177,11 @@ static int handleGauge64Stats(netsnmp_mib_handler* handler,
}
std::string str;
- uint64_t value = (*boost::get<DNSDistStats::statfunction_t>(&it->second))(str);
+ uint64_t value = (*std::get_if<dnsdist::metrics::Stats::statfunction_t>(&it->second))(str);
return DNSDistSNMPAgent::setCounter64Value(requests, value);
}
-static void registerGauge64Stat(const char* name, const oid statOID[], size_t statOIDLength, DNSDistStats::statfunction_t ptr)
+static void registerGauge64Stat(const char* name, const oid statOID[], size_t statOIDLength, dnsdist::metrics::Stats::statfunction_t ptr)
{
if (statOIDLength != OID_LENGTH(queriesOID)) {
errlog("Invalid OID for SNMP Gauge64 statistic %s", name);
@@ -383,8 +384,8 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap(const DownstreamState& dss)
netsnmp_variable_list* varList = nullptr;
snmp_varlist_add_variable(&varList,
- snmpTrapOID,
- snmpTrapOIDLen,
+ snmpTrapOID.data(),
+ snmpTrapOID.size(),
ASN_OBJECT_ID,
backendStatusChangeTrapOID,
OID_LENGTH(backendStatusChangeTrapOID) * sizeof(oid));
@@ -411,7 +412,7 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap(const DownstreamState& dss)
backendStatus.c_str(),
backendStatus.size());
- return sendTrap(d_trapPipe[1], varList);
+ return sendTrap(d_sender, varList);
#else
return true;
#endif /* HAVE_NET_SNMP */
@@ -423,8 +424,8 @@ bool DNSDistSNMPAgent::sendCustomTrap(const std::string& reason)
netsnmp_variable_list* varList = nullptr;
snmp_varlist_add_variable(&varList,
- snmpTrapOID,
- snmpTrapOIDLen,
+ snmpTrapOID.data(),
+ snmpTrapOID.size(),
ASN_OBJECT_ID,
customTrapOID,
OID_LENGTH(customTrapOID) * sizeof(oid));
@@ -436,7 +437,7 @@ bool DNSDistSNMPAgent::sendCustomTrap(const std::string& reason)
reason.c_str(),
reason.size());
- return sendTrap(d_trapPipe[1], varList);
+ return sendTrap(d_sender, varList);
#else
return true;
#endif /* HAVE_NET_SNMP */
@@ -459,8 +460,8 @@ bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& rea
netsnmp_variable_list* varList = nullptr;
snmp_varlist_add_variable(&varList,
- snmpTrapOID,
- snmpTrapOIDLen,
+ snmpTrapOID.data(),
+ snmpTrapOID.size(),
ASN_OBJECT_ID,
actionTrapOID,
OID_LENGTH(actionTrapOID) * sizeof(oid));
@@ -542,7 +543,7 @@ bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& rea
reason.c_str(),
reason.size());
- return sendTrap(d_trapPipe[1], varList);
+ return sendTrap(d_sender, varList);
#else
return true;
#endif /* HAVE_NET_SNMP */
@@ -552,44 +553,44 @@ DNSDistSNMPAgent::DNSDistSNMPAgent(const std::string& name, const std::string& d
{
#ifdef HAVE_NET_SNMP
- registerCounter64Stat("queries", queriesOID, OID_LENGTH(queriesOID), &g_stats.queries);
- registerCounter64Stat("responses", responsesOID, OID_LENGTH(responsesOID), &g_stats.responses);
- registerCounter64Stat("servfailResponses", servfailResponsesOID, OID_LENGTH(servfailResponsesOID), &g_stats.servfailResponses);
- registerCounter64Stat("aclDrops", aclDropsOID, OID_LENGTH(aclDropsOID), &g_stats.aclDrops);
- registerCounter64Stat("ruleDrop", ruleDropOID, OID_LENGTH(ruleDropOID), &g_stats.ruleDrop);
- registerCounter64Stat("ruleNXDomain", ruleNXDomainOID, OID_LENGTH(ruleNXDomainOID), &g_stats.ruleNXDomain);
- registerCounter64Stat("ruleRefused", ruleRefusedOID, OID_LENGTH(ruleRefusedOID), &g_stats.ruleRefused);
- registerCounter64Stat("ruleServFail", ruleServFailOID, OID_LENGTH(ruleServFailOID), &g_stats.ruleServFail);
- registerCounter64Stat("ruleTruncated", ruleTruncatedOID, OID_LENGTH(ruleTruncatedOID), &g_stats.ruleTruncated);
- registerCounter64Stat("selfAnswered", selfAnsweredOID, OID_LENGTH(selfAnsweredOID), &g_stats.selfAnswered);
- registerCounter64Stat("downstreamTimeouts", downstreamTimeoutsOID, OID_LENGTH(downstreamTimeoutsOID), &g_stats.downstreamTimeouts);
- registerCounter64Stat("downstreamSendErrors", downstreamSendErrorsOID, OID_LENGTH(downstreamSendErrorsOID), &g_stats.downstreamSendErrors);
- registerCounter64Stat("truncFail", truncFailOID, OID_LENGTH(truncFailOID), &g_stats.truncFail);
- registerCounter64Stat("noPolicy", noPolicyOID, OID_LENGTH(noPolicyOID), &g_stats.noPolicy);
- registerCounter64Stat("latency0_1", latency0_1OID, OID_LENGTH(latency0_1OID), &g_stats.latency0_1);
- registerCounter64Stat("latency1_10", latency1_10OID, OID_LENGTH(latency1_10OID), &g_stats.latency1_10);
- registerCounter64Stat("latency10_50", latency10_50OID, OID_LENGTH(latency10_50OID), &g_stats.latency10_50);
- registerCounter64Stat("latency50_100", latency50_100OID, OID_LENGTH(latency50_100OID), &g_stats.latency50_100);
- registerCounter64Stat("latency100_1000", latency100_1000OID, OID_LENGTH(latency100_1000OID), &g_stats.latency100_1000);
- registerCounter64Stat("latencySlow", latencySlowOID, OID_LENGTH(latencySlowOID), &g_stats.latencySlow);
- registerCounter64Stat("nonCompliantQueries", nonCompliantQueriesOID, OID_LENGTH(nonCompliantQueriesOID), &g_stats.nonCompliantQueries);
- registerCounter64Stat("nonCompliantResponses", nonCompliantResponsesOID, OID_LENGTH(nonCompliantResponsesOID), &g_stats.nonCompliantResponses);
- registerCounter64Stat("rdQueries", rdQueriesOID, OID_LENGTH(rdQueriesOID), &g_stats.rdQueries);
- registerCounter64Stat("emptyQueries", emptyQueriesOID, OID_LENGTH(emptyQueriesOID), &g_stats.emptyQueries);
- registerCounter64Stat("cacheHits", cacheHitsOID, OID_LENGTH(cacheHitsOID), &g_stats.cacheHits);
- registerCounter64Stat("cacheMisses", cacheMissesOID, OID_LENGTH(cacheMissesOID), &g_stats.cacheMisses);
- registerCounter64Stat("dynBlocked", dynBlockedOID, OID_LENGTH(dynBlockedOID), &g_stats.dynBlocked);
- registerFloatStat("latencyAvg100", latencyAvg100OID, OID_LENGTH(latencyAvg100OID), &g_stats.latencyAvg100);
- registerFloatStat("latencyAvg1000", latencyAvg1000OID, OID_LENGTH(latencyAvg1000OID), &g_stats.latencyAvg1000);
- registerFloatStat("latencyAvg10000", latencyAvg10000OID, OID_LENGTH(latencyAvg10000OID), &g_stats.latencyAvg10000);
- registerFloatStat("latencyAvg1000000", latencyAvg1000000OID, OID_LENGTH(latencyAvg1000000OID), &g_stats.latencyAvg1000000);
+ registerCounter64Stat("queries", queriesOID, OID_LENGTH(queriesOID), &dnsdist::metrics::g_stats.queries);
+ registerCounter64Stat("responses", responsesOID, OID_LENGTH(responsesOID), &dnsdist::metrics::g_stats.responses);
+ registerCounter64Stat("servfailResponses", servfailResponsesOID, OID_LENGTH(servfailResponsesOID), &dnsdist::metrics::g_stats.servfailResponses);
+ registerCounter64Stat("aclDrops", aclDropsOID, OID_LENGTH(aclDropsOID), &dnsdist::metrics::g_stats.aclDrops);
+ registerCounter64Stat("ruleDrop", ruleDropOID, OID_LENGTH(ruleDropOID), &dnsdist::metrics::g_stats.ruleDrop);
+ registerCounter64Stat("ruleNXDomain", ruleNXDomainOID, OID_LENGTH(ruleNXDomainOID), &dnsdist::metrics::g_stats.ruleNXDomain);
+ registerCounter64Stat("ruleRefused", ruleRefusedOID, OID_LENGTH(ruleRefusedOID), &dnsdist::metrics::g_stats.ruleRefused);
+ registerCounter64Stat("ruleServFail", ruleServFailOID, OID_LENGTH(ruleServFailOID), &dnsdist::metrics::g_stats.ruleServFail);
+ registerCounter64Stat("ruleTruncated", ruleTruncatedOID, OID_LENGTH(ruleTruncatedOID), &dnsdist::metrics::g_stats.ruleTruncated);
+ registerCounter64Stat("selfAnswered", selfAnsweredOID, OID_LENGTH(selfAnsweredOID), &dnsdist::metrics::g_stats.selfAnswered);
+ registerCounter64Stat("downstreamTimeouts", downstreamTimeoutsOID, OID_LENGTH(downstreamTimeoutsOID), &dnsdist::metrics::g_stats.downstreamTimeouts);
+ registerCounter64Stat("downstreamSendErrors", downstreamSendErrorsOID, OID_LENGTH(downstreamSendErrorsOID), &dnsdist::metrics::g_stats.downstreamSendErrors);
+ registerCounter64Stat("truncFail", truncFailOID, OID_LENGTH(truncFailOID), &dnsdist::metrics::g_stats.truncFail);
+ registerCounter64Stat("noPolicy", noPolicyOID, OID_LENGTH(noPolicyOID), &dnsdist::metrics::g_stats.noPolicy);
+ registerCounter64Stat("latency0_1", latency0_1OID, OID_LENGTH(latency0_1OID), &dnsdist::metrics::g_stats.latency0_1);
+ registerCounter64Stat("latency1_10", latency1_10OID, OID_LENGTH(latency1_10OID), &dnsdist::metrics::g_stats.latency1_10);
+ registerCounter64Stat("latency10_50", latency10_50OID, OID_LENGTH(latency10_50OID), &dnsdist::metrics::g_stats.latency10_50);
+ registerCounter64Stat("latency50_100", latency50_100OID, OID_LENGTH(latency50_100OID), &dnsdist::metrics::g_stats.latency50_100);
+ registerCounter64Stat("latency100_1000", latency100_1000OID, OID_LENGTH(latency100_1000OID), &dnsdist::metrics::g_stats.latency100_1000);
+ registerCounter64Stat("latencySlow", latencySlowOID, OID_LENGTH(latencySlowOID), &dnsdist::metrics::g_stats.latencySlow);
+ registerCounter64Stat("nonCompliantQueries", nonCompliantQueriesOID, OID_LENGTH(nonCompliantQueriesOID), &dnsdist::metrics::g_stats.nonCompliantQueries);
+ registerCounter64Stat("nonCompliantResponses", nonCompliantResponsesOID, OID_LENGTH(nonCompliantResponsesOID), &dnsdist::metrics::g_stats.nonCompliantResponses);
+ registerCounter64Stat("rdQueries", rdQueriesOID, OID_LENGTH(rdQueriesOID), &dnsdist::metrics::g_stats.rdQueries);
+ registerCounter64Stat("emptyQueries", emptyQueriesOID, OID_LENGTH(emptyQueriesOID), &dnsdist::metrics::g_stats.emptyQueries);
+ registerCounter64Stat("cacheHits", cacheHitsOID, OID_LENGTH(cacheHitsOID), &dnsdist::metrics::g_stats.cacheHits);
+ registerCounter64Stat("cacheMisses", cacheMissesOID, OID_LENGTH(cacheMissesOID), &dnsdist::metrics::g_stats.cacheMisses);
+ registerCounter64Stat("dynBlocked", dynBlockedOID, OID_LENGTH(dynBlockedOID), &dnsdist::metrics::g_stats.dynBlocked);
+ registerFloatStat("latencyAvg100", latencyAvg100OID, OID_LENGTH(latencyAvg100OID), &dnsdist::metrics::g_stats.latencyAvg100);
+ registerFloatStat("latencyAvg1000", latencyAvg1000OID, OID_LENGTH(latencyAvg1000OID), &dnsdist::metrics::g_stats.latencyAvg1000);
+ registerFloatStat("latencyAvg10000", latencyAvg10000OID, OID_LENGTH(latencyAvg10000OID), &dnsdist::metrics::g_stats.latencyAvg10000);
+ registerFloatStat("latencyAvg1000000", latencyAvg1000000OID, OID_LENGTH(latencyAvg1000000OID), &dnsdist::metrics::g_stats.latencyAvg1000000);
registerGauge64Stat("uptime", uptimeOID, OID_LENGTH(uptimeOID), &uptimeOfProcess);
registerGauge64Stat("specialMemoryUsage", specialMemoryUsageOID, OID_LENGTH(specialMemoryUsageOID), &getSpecialMemoryUsage);
registerGauge64Stat("cpuUserMSec", cpuUserMSecOID, OID_LENGTH(cpuUserMSecOID), &getCPUTimeUser);
registerGauge64Stat("cpuSysMSec", cpuSysMSecOID, OID_LENGTH(cpuSysMSecOID), &getCPUTimeSystem);
registerGauge64Stat("fdUsage", fdUsageOID, OID_LENGTH(fdUsageOID), &getOpenFileDescriptors);
registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, OID_LENGTH(dynBlockedNMGSizeOID), [](const std::string&) { return g_dynblockNMG.getLocal()->size(); });
- registerGauge64Stat("securityStatus", securityStatusOID, OID_LENGTH(securityStatusOID), [](const std::string&) { return g_stats.securityStatus.load(); });
+ registerGauge64Stat("securityStatus", securityStatusOID, OID_LENGTH(securityStatusOID), [](const std::string&) { return dnsdist::metrics::g_stats.securityStatus.load(); });
registerGauge64Stat("realMemoryUsage", realMemoryUsageOID, OID_LENGTH(realMemoryUsageOID), &getRealMemoryUsage);
diff --git a/dnsdist-tcp-downstream.cc b/dnsdist-tcp-downstream.cc
index 6c6fcf2..904913e 100644
--- a/dnsdist-tcp-downstream.cc
+++ b/dnsdist-tcp-downstream.cc
@@ -118,7 +118,7 @@ bool ConnectionToBackend::reconnect()
return true;
}
catch (const std::runtime_error& e) {
- vinfolog("Connection to downstream server %s failed: %s", d_ds->getName(), e.what());
+ vinfolog("Connection to downstream server %s failed: %s", d_ds->getNameWithAddr(), e.what());
d_downstreamFailures++;
if (d_downstreamFailures >= d_ds->d_config.d_retries) {
throw;
@@ -173,7 +173,7 @@ static uint32_t getSerialFromRawSOAContent(const std::vector<uint8_t>& raw)
static bool getSerialFromIXFRQuery(TCPQuery& query)
{
try {
- size_t proxyPayloadSize = query.d_proxyProtocolPayloadAdded ? query.d_proxyProtocolPayloadAddedSize : 0;
+ size_t proxyPayloadSize = query.d_proxyProtocolPayloadAdded ? query.d_idstate.d_proxyProtocolPayloadSize : 0;
if (query.d_buffer.size() <= (proxyPayloadSize + sizeof(uint16_t))) {
return false;
}
@@ -191,7 +191,7 @@ static bool getSerialFromIXFRQuery(TCPQuery& query)
if (!unknownContent) {
return false;
}
- auto raw = unknownContent->getRawContent();
+ const auto& raw = unknownContent->getRawContent();
query.d_ixfrQuerySerial = getSerialFromRawSOAContent(raw);
return true;
}
@@ -232,24 +232,25 @@ static void prepareQueryForSending(TCPQuery& query, uint16_t id, QueryState quer
if (query.d_proxyProtocolPayload.size() > 0 && !query.d_proxyProtocolPayloadAdded) {
query.d_buffer.insert(query.d_buffer.begin(), query.d_proxyProtocolPayload.begin(), query.d_proxyProtocolPayload.end());
query.d_proxyProtocolPayloadAdded = true;
- query.d_proxyProtocolPayloadAddedSize = query.d_proxyProtocolPayload.size();
+ query.d_idstate.d_proxyProtocolPayloadSize = query.d_proxyProtocolPayload.size();
}
}
else if (connectionState == ConnectionState::proxySent) {
if (query.d_proxyProtocolPayloadAdded) {
- if (query.d_buffer.size() < query.d_proxyProtocolPayloadAddedSize) {
+ if (query.d_buffer.size() < query.d_idstate.d_proxyProtocolPayloadSize) {
throw std::runtime_error("Trying to remove a proxy protocol payload of size " + std::to_string(query.d_proxyProtocolPayload.size()) + " from a buffer of size " + std::to_string(query.d_buffer.size()));
}
- query.d_buffer.erase(query.d_buffer.begin(), query.d_buffer.begin() + query.d_proxyProtocolPayloadAddedSize);
+ // NOLINTNEXTLINE(*-narrowing-conversions): the size of the payload is limited to 2^16-1
+ query.d_buffer.erase(query.d_buffer.begin(), query.d_buffer.begin() + static_cast<ssize_t>(query.d_idstate.d_proxyProtocolPayloadSize));
query.d_proxyProtocolPayloadAdded = false;
- query.d_proxyProtocolPayloadAddedSize = 0;
+ query.d_idstate.d_proxyProtocolPayloadSize = 0;
}
}
if (query.d_idstate.qclass == QClass::IN && query.d_idstate.qtype == QType::IXFR) {
getSerialFromIXFRQuery(query);
}
- editPayloadID(query.d_buffer, id, query.d_proxyProtocolPayloadAdded ? query.d_proxyProtocolPayloadAddedSize : 0, true);
+ editPayloadID(query.d_buffer, id, query.d_proxyProtocolPayloadAdded ? query.d_idstate.d_proxyProtocolPayloadSize : 0, true);
}
IOState TCPConnectionToBackend::queueNextQuery(std::shared_ptr<TCPConnectionToBackend>& conn)
@@ -268,7 +269,7 @@ IOState TCPConnectionToBackend::queueNextQuery(std::shared_ptr<TCPConnectionToBa
IOState TCPConnectionToBackend::sendQuery(std::shared_ptr<TCPConnectionToBackend>& conn, const struct timeval& now)
{
- DEBUGLOG("sending query to backend "<<conn->getDS()->getName()<<" over FD "<<conn->d_handler->getDescriptor());
+ DEBUGLOG("sending query to backend "<<conn->getDS()->getNameWithAddr()<<" over FD "<<conn->d_handler->getDescriptor());
IOState state = conn->d_handler->tryWrite(conn->d_currentQuery.d_query.d_buffer, conn->d_currentPos, conn->d_currentQuery.d_query.d_buffer.size());
@@ -361,7 +362,7 @@ void TCPConnectionToBackend::handleIO(std::shared_ptr<TCPConnectionToBackend>& c
iostate = conn->handleResponse(conn, now);
}
catch (const std::exception& e) {
- vinfolog("Got an exception while handling TCP response from %s (client is %s): %s", conn->d_ds ? conn->d_ds->getName() : "unknown", conn->d_currentQuery.d_query.d_idstate.origRemote.toStringWithPort(), e.what());
+ vinfolog("Got an exception while handling TCP response from %s (client is %s): %s", conn->d_ds ? conn->d_ds->getNameWithAddr() : "unknown", conn->d_currentQuery.d_query.d_idstate.origRemote.toStringWithPort(), e.what());
ioGuard.release();
conn->release();
return;
@@ -433,7 +434,8 @@ void TCPConnectionToBackend::handleIO(std::shared_ptr<TCPConnectionToBackend>& c
/* this one can't be restarted, sorry */
DEBUGLOG("A XFR for which a response has already been sent cannot be restarted");
try {
- pending.second.d_sender->notifyIOError(std::move(pending.second.d_query.d_idstate), now);
+ TCPResponse response(std::move(pending.second.d_query));
+ pending.second.d_sender->notifyIOError(now, std::move(response));
}
catch (const std::exception& e) {
vinfolog("Got an exception while notifying: %s", e.what());
@@ -553,16 +555,16 @@ void TCPConnectionToBackend::handleTimeout(const struct timeval& now, bool write
if (write) {
if (isFresh() && d_queries == 0) {
++d_ds->tcpConnectTimeouts;
- vinfolog("Timeout while connecting to TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while connecting to TCP backend %s", d_ds->getNameWithAddr());
}
else {
++d_ds->tcpWriteTimeouts;
- vinfolog("Timeout while writing to TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while writing to TCP backend %s", d_ds->getNameWithAddr());
}
}
else {
++d_ds->tcpReadTimeouts;
- vinfolog("Timeout while reading from TCP backend %s", d_ds->getName());
+ vinfolog("Timeout while reading from TCP backend %s", d_ds->getNameWithAddr());
}
try {
@@ -606,25 +608,28 @@ void TCPConnectionToBackend::notifyAllQueriesFailed(const struct timeval& now, F
try {
if (d_state == State::sendingQueryToBackend) {
increaseCounters(d_currentQuery.d_query.d_idstate.cs);
- auto sender = d_currentQuery.d_sender;
+ auto sender = std::move(d_currentQuery.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(d_currentQuery.d_query.d_idstate), now);
+ TCPResponse response(std::move(d_currentQuery.d_query));
+ sender->notifyIOError(now, std::move(response));
}
}
for (auto& query : pendingQueries) {
increaseCounters(query.d_query.d_idstate.cs);
- auto sender = query.d_sender;
+ auto sender = std::move(query.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(query.d_query.d_idstate), now);
+ TCPResponse response(std::move(query.d_query));
+ sender->notifyIOError(now, std::move(response));
}
}
for (auto& response : pendingResponses) {
increaseCounters(response.second.d_query.d_idstate.cs);
- auto sender = response.second.d_sender;
+ auto sender = std::move(response.second.d_sender);
if (sender->active()) {
- sender->notifyIOError(std::move(response.second.d_query.d_idstate), now);
+ TCPResponse tresp(std::move(response.second.d_query));
+ sender->notifyIOError(now, std::move(tresp));
}
}
}
@@ -721,12 +726,20 @@ IOState TCPConnectionToBackend::handleResponse(std::shared_ptr<TCPConnectionToBa
d_state = State::idle;
t_downstreamTCPConnectionsManager.moveToIdle(conn);
}
+ else if (!d_pendingResponses.empty()) {
+ d_currentPos = 0;
+ d_state = State::waitingForResponseFromBackend;
+ }
+ // be very careful that handleResponse() might trigger new queries being assigned to us,
+ // which may reset our d_currentPos, d_state and/or d_responseBuffer, so we cannot assume
+ // anything without checking first
auto shared = conn;
if (sender->active()) {
DEBUGLOG("passing response to client connection for "<<ids.qname);
// make sure that we still exist after calling handleResponse()
- sender->handleResponse(now, TCPResponse(std::move(d_responseBuffer), std::move(ids), conn, conn->d_ds));
+ TCPResponse response(std::move(d_responseBuffer), std::move(ids), conn, conn->d_ds);
+ sender->handleResponse(now, std::move(response));
}
if (!d_pendingQueries.empty()) {
@@ -735,9 +748,6 @@ IOState TCPConnectionToBackend::handleResponse(std::shared_ptr<TCPConnectionToBa
}
else if (!d_pendingResponses.empty()) {
DEBUGLOG("still have some responses to read");
- d_state = State::waitingForResponseFromBackend;
- d_currentPos = 0;
- d_responseBuffer.resize(sizeof(uint16_t));
return IOState::NeedRead;
}
else {
@@ -805,13 +815,13 @@ bool TCPConnectionToBackend::isXFRFinished(const TCPResponse& response, TCPQuery
if (!unknownContent) {
continue;
}
- auto raw = unknownContent->getRawContent();
+ const auto& raw = unknownContent->getRawContent();
auto serial = getSerialFromRawSOAContent(raw);
- if (query.d_xfrMasterSerial == 0) {
+ if (query.d_xfrPrimarySerial == 0) {
// store the first SOA in our client's connection metadata
- query.d_xfrMasterSerial = serial;
- if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrMasterSerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrMasterSerial, query.d_ixfrQuerySerial))) {
- /* This is the first message with a master SOA:
+ query.d_xfrPrimarySerial = serial;
+ if (query.d_idstate.qtype == QType::IXFR && (query.d_xfrPrimarySerial == query.d_ixfrQuerySerial || rfc1982LessThan(query.d_xfrPrimarySerial, query.d_ixfrQuerySerial))) {
+ /* This is the first message with a primary SOA:
RFC 1995 Section 2:
If an IXFR query with the same or newer version number
than that of the server is received, it is replied to
@@ -823,16 +833,16 @@ bool TCPConnectionToBackend::isXFRFinished(const TCPResponse& response, TCPQuery
}
++query.d_xfrSerialCount;
- if (serial == query.d_xfrMasterSerial) {
- ++query.d_xfrMasterSerialCount;
- // figure out if it's end when receiving master's SOA again
+ if (serial == query.d_xfrPrimarySerial) {
+ ++query.d_xfrPrimarySerialCount;
+ // figure out if it's end when receiving primary's SOA again
if (query.d_xfrSerialCount == 2) {
// if there are only two SOA records marks a finished AXFR
done = true;
break;
}
- if (query.d_xfrMasterSerialCount == 3) {
- // receiving master's SOA 3 times marks a finished IXFR
+ if (query.d_xfrPrimarySerialCount == 3) {
+ // receiving primary's SOA 3 times marks a finished IXFR
done = true;
break;
}
diff --git a/dnsdist-tcp-downstream.hh b/dnsdist-tcp-downstream.hh
index 81c8757..a165dc1 100644
--- a/dnsdist-tcp-downstream.hh
+++ b/dnsdist-tcp-downstream.hh
@@ -226,7 +226,7 @@ protected:
class TCPConnectionToBackend : public ConnectionToBackend
{
public:
- TCPConnectionToBackend(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, const struct timeval& now, std::string&& /* proxyProtocolPayload*, unused but there to match the HTTP2 connections, so we can use the same templated connections manager class */): ConnectionToBackend(ds, mplexer, now), d_responseBuffer(s_maxPacketCacheEntrySize)
+ TCPConnectionToBackend(const std::shared_ptr<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, const struct timeval& now, std::string&& /* proxyProtocolPayload*, unused but there to match the HTTP2 connections, so we can use the same templated connections manager class */): ConnectionToBackend(ds, mplexer, now), d_responseBuffer(512)
{
}
diff --git a/dnsdist-tcp-upstream.hh b/dnsdist-tcp-upstream.hh
index 59c4df4..c6410df 100644
--- a/dnsdist-tcp-upstream.hh
+++ b/dnsdist-tcp-upstream.hh
@@ -2,6 +2,9 @@
#include "dolog.hh"
#include "dnsdist-tcp.hh"
+#include "dnsdist-tcp-downstream.hh"
+
+struct TCPCrossProtocolResponse;
class TCPClientThreadData
{
@@ -15,13 +18,19 @@ public:
LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions;
LocalStateHolder<vector<DNSDistResponseRuleAction>> localCacheInsertedRespRuleActions;
std::unique_ptr<FDMultiplexer> mplexer{nullptr};
- int crossProtocolResponsesPipe{-1};
+ pdns::channel::Receiver<ConnectionInfo> queryReceiver;
+ pdns::channel::Receiver<CrossProtocolQuery> crossProtocolQueryReceiver;
+ pdns::channel::Receiver<TCPCrossProtocolResponse> crossProtocolResponseReceiver;
+ pdns::channel::Sender<TCPCrossProtocolResponse> crossProtocolResponseSender;
};
class IncomingTCPConnectionState : public TCPQuerySender, public std::enable_shared_from_this<IncomingTCPConnectionState>
{
public:
- IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(s_maxPacketCacheEntrySize), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{g_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : nullptr, now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
+ enum class QueryProcessingResult : uint8_t { Forwarded, TooSmall, InvalidHeaders, Dropped, SelfAnswered, NoBackend, Asynchronous };
+ enum class ProxyProtocolResult : uint8_t { Reading, Done, Error };
+
+ IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{g_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
{
d_origDest.reset();
d_origDest.sin4.sin_family = d_ci.remote.sin4.sin_family;
@@ -41,7 +50,7 @@ public:
IncomingTCPConnectionState(const IncomingTCPConnectionState& rhs) = delete;
IncomingTCPConnectionState& operator=(const IncomingTCPConnectionState& rhs) = delete;
- ~IncomingTCPConnectionState();
+ virtual ~IncomingTCPConnectionState();
void resetForNewQuery();
@@ -107,30 +116,34 @@ public:
return false;
}
- std::shared_ptr<TCPConnectionToBackend> getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& ds, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs);
- std::shared_ptr<TCPConnectionToBackend> getDownstreamConnection(std::shared_ptr<DownstreamState>& ds, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now);
+ std::shared_ptr<TCPConnectionToBackend> getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs);
+ std::shared_ptr<TCPConnectionToBackend> getDownstreamConnection(std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now);
void registerOwnedDownstreamConnection(std::shared_ptr<TCPConnectionToBackend>& conn);
static size_t clearAllDownstreamConnections();
- static void handleIO(std::shared_ptr<IncomingTCPConnectionState>& conn, const struct timeval& now);
- static void handleIOCallback(int fd, FDMultiplexer::funcparam_t& param);
- static void handleAsyncReady(int fd, FDMultiplexer::funcparam_t& param);
+ static void handleIOCallback(int desc, FDMultiplexer::funcparam_t& param);
+ static void handleAsyncReady(int desc, FDMultiplexer::funcparam_t& param);
static void updateIO(std::shared_ptr<IncomingTCPConnectionState>& state, IOState newState, const struct timeval& now);
- static IOState sendResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response);
- static void queueResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response);
-static void handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bool write);
+ static void queueResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response, bool fromBackend);
+ static void handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bool write);
- /* we take a copy of a shared pointer, not a reference, because the initial shared pointer might be released during the handling of the response */
- void handleResponse(const struct timeval& now, TCPResponse&& response) override;
+ virtual void handleIO();
+
+ QueryProcessingResult handleQuery(PacketBuffer&& query, const struct timeval& now, std::optional<int32_t> streamID);
+ virtual void handleResponse(const struct timeval& now, TCPResponse&& response) override;
+ virtual void notifyIOError(const struct timeval& now, TCPResponse&& response) override;
void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override;
- void notifyIOError(InternalQueryState&& query, const struct timeval& now) override;
+ virtual IOState sendResponse(const struct timeval& now, TCPResponse&& response);
+ void handleResponseSent(TCPResponse& currentResponse);
+ virtual IOState handleHandshake(const struct timeval& now);
+ void handleHandshakeDone(const struct timeval& now);
+ ProxyProtocolResult handleProxyProtocolPayload();
void handleCrossProtocolResponse(const struct timeval& now, TCPResponse&& response);
void terminateClientConnection();
- void queueQuery(TCPQuery&& query);
bool canAcceptNewQueries(const struct timeval& now);
@@ -138,6 +151,28 @@ static void handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bo
{
return d_ioState != nullptr;
}
+ bool isProxyPayloadOutsideTLS() const
+ {
+ if (!d_ci.cs->hasTLS()) {
+ return false;
+ }
+ return d_ci.cs->getTLSFrontend().d_proxyProtocolOutsideTLS;
+ }
+
+ virtual bool forwardViaUDPFirst() const
+ {
+ return false;
+ }
+ virtual std::unique_ptr<DOHUnitInterface> getDOHUnit(uint32_t streamID)
+ {
+ throw std::runtime_error("Getting a DOHUnit state from a generic TCP/DoT connection is not supported");
+ }
+ virtual void restoreDOHUnit(std::unique_ptr<DOHUnitInterface>&&)
+ {
+ throw std::runtime_error("Restoring a DOHUnit state to a generic TCP/DoT connection is not supported");
+ }
+
+ std::unique_ptr<CrossProtocolQuery> getCrossProtocolQuery(PacketBuffer&& query, InternalQueryState&& state, const std::shared_ptr<DownstreamState>& backend);
std::string toString() const
{
@@ -146,7 +181,12 @@ static void handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bo
return o.str();
}
- enum class State : uint8_t { doingHandshake, readingProxyProtocolHeader, waitingForQuery, readingQuerySize, readingQuery, sendingResponse, idle /* in case of XFR, we stop processing queries */ };
+ dnsdist::Protocol getProtocol() const;
+ IOState handleIncomingQueryReceived(const struct timeval& now);
+ void handleExceptionDuringIO(const std::exception& exp);
+ bool readIncomingQuery(const timeval& now, IOState& iostate);
+
+ enum class State : uint8_t { starting, doingHandshake, readingProxyProtocolHeader, waitingForQuery, readingQuerySize, readingQuery, sendingResponse, idle /* in case of XFR, we stop processing queries */ };
TCPResponse d_currentResponse;
std::map<std::shared_ptr<DownstreamState>, std::deque<std::shared_ptr<TCPConnectionToBackend>>> d_ownedConnectionsToBackend;
@@ -171,7 +211,7 @@ static void handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bo
size_t d_currentQueriesCount{0};
std::thread::id d_creatorThreadID;
uint16_t d_querySize{0};
- State d_state{State::doingHandshake};
+ State d_state{State::starting};
bool d_isXFR{false};
bool d_proxyProtocolPayloadHasTLV{false};
bool d_lastIOBlocked{false};
diff --git a/dnsdist-tcp.cc b/dnsdist-tcp.cc
index b927cbe..e3eb68e 100644
--- a/dnsdist-tcp.cc
+++ b/dnsdist-tcp.cc
@@ -26,7 +26,9 @@
#include "dnsdist.hh"
#include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-nghttp2-in.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-tcp.hh"
@@ -64,7 +66,7 @@ size_t g_maxTCPConnectionDuration{0};
#ifdef __linux__
// On Linux this gives us 128k pending queries (default is 8192 queries),
// which should be enough to deal with huge spikes
-size_t g_tcpInternalPipeBufferSize{1024*1024};
+size_t g_tcpInternalPipeBufferSize{1048576U};
uint64_t g_maxTCPQueuedConnections{10000};
#else
size_t g_tcpInternalPipeBufferSize{0};
@@ -83,11 +85,11 @@ IncomingTCPConnectionState::~IncomingTCPConnectionState()
dnsdist::IncomingConcurrentTCPConnectionsManager::accountClosedTCPConnection(d_ci.remote);
if (d_ci.cs != nullptr) {
- struct timeval now;
+ timeval now{};
gettimeofday(&now, nullptr);
auto diff = now - d_connectionStartTime;
- d_ci.cs->updateTCPMetrics(d_queriesCount, diff.tv_sec * 1000.0 + diff.tv_usec / 1000.0);
+ d_ci.cs->updateTCPMetrics(d_queriesCount, diff.tv_sec * 1000 + diff.tv_usec / 1000);
}
// would have been done when the object is destroyed anyway,
@@ -96,21 +98,30 @@ IncomingTCPConnectionState::~IncomingTCPConnectionState()
d_handler.close();
}
+dnsdist::Protocol IncomingTCPConnectionState::getProtocol() const
+{
+ if (d_ci.cs->dohFrontend) {
+ return dnsdist::Protocol::DoH;
+ }
+ if (d_handler.isTLS()) {
+ return dnsdist::Protocol::DoT;
+ }
+ return dnsdist::Protocol::DoTCP;
+}
+
size_t IncomingTCPConnectionState::clearAllDownstreamConnections()
{
return t_downstreamTCPConnectionsManager.clear();
}
-std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getDownstreamConnection(std::shared_ptr<DownstreamState>& ds, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now)
+std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getDownstreamConnection(std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now)
{
- std::shared_ptr<TCPConnectionToBackend> downstream{nullptr};
-
- downstream = getOwnedDownstreamConnection(ds, tlvs);
+ auto downstream = getOwnedDownstreamConnection(backend, tlvs);
if (!downstream) {
/* we don't have a connection to this backend owned yet, let's get one (it might not be a fresh one, though) */
- downstream = t_downstreamTCPConnectionsManager.getConnectionToDownstream(d_threadData.mplexer, ds, now, std::string());
- if (ds->d_config.useProxyProtocol) {
+ downstream = t_downstreamTCPConnectionsManager.getConnectionToDownstream(d_threadData.mplexer, backend, now, std::string());
+ if (backend->d_config.useProxyProtocol) {
registerOwnedDownstreamConnection(downstream);
}
}
@@ -118,9 +129,10 @@ std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getDownstrea
return downstream;
}
-static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int crossProtocolResponsesListenPipeFD, int crossProtocolResponsesWritePipeFD, std::vector<ClientState*> tcpAcceptStates);
+static void tcpClientThread(pdns::channel::Receiver<ConnectionInfo>&& queryReceiver, pdns::channel::Receiver<CrossProtocolQuery>&& crossProtocolQueryReceiver, pdns::channel::Receiver<TCPCrossProtocolResponse>&& crossProtocolResponseReceiver, pdns::channel::Sender<TCPCrossProtocolResponse>&& crossProtocolResponseSender, std::vector<ClientState*> tcpAcceptStates);
-TCPClientCollection::TCPClientCollection(size_t maxThreads, std::vector<ClientState*> tcpAcceptStates): d_tcpclientthreads(maxThreads), d_maxthreads(maxThreads)
+TCPClientCollection::TCPClientCollection(size_t maxThreads, std::vector<ClientState*> tcpAcceptStates) :
+ d_tcpclientthreads(maxThreads), d_maxthreads(maxThreads)
{
for (size_t idx = 0; idx < maxThreads; idx++) {
addTCPClientThread(tcpAcceptStates);
@@ -129,83 +141,37 @@ TCPClientCollection::TCPClientCollection(size_t maxThreads, std::vector<ClientSt
void TCPClientCollection::addTCPClientThread(std::vector<ClientState*>& tcpAcceptStates)
{
- auto preparePipe = [](int fds[2], const std::string& type) -> bool {
- if (pipe(fds) < 0) {
- errlog("Error creating the TCP thread %s pipe: %s", type, stringerror());
- return false;
- }
-
- if (!setNonBlocking(fds[0])) {
- int err = errno;
- close(fds[0]);
- close(fds[1]);
- errlog("Error setting the TCP thread %s pipe non-blocking: %s", type, stringerror(err));
- return false;
- }
-
- if (!setNonBlocking(fds[1])) {
- int err = errno;
- close(fds[0]);
- close(fds[1]);
- errlog("Error setting the TCP thread %s pipe non-blocking: %s", type, stringerror(err));
- return false;
- }
-
- if (g_tcpInternalPipeBufferSize > 0 && getPipeBufferSize(fds[0]) < g_tcpInternalPipeBufferSize) {
- setPipeBufferSize(fds[0], g_tcpInternalPipeBufferSize);
- }
-
- return true;
- };
-
- int pipefds[2] = { -1, -1};
- if (!preparePipe(pipefds, "communication")) {
- return;
- }
+ try {
+ auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
- int crossProtocolQueriesFDs[2] = { -1, -1};
- if (!preparePipe(crossProtocolQueriesFDs, "cross-protocol queries")) {
- return;
- }
+ auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
- int crossProtocolResponsesFDs[2] = { -1, -1};
- if (!preparePipe(crossProtocolResponsesFDs, "cross-protocol responses")) {
- return;
- }
+ auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
- vinfolog("Adding TCP Client thread");
+ vinfolog("Adding TCP Client thread");
- {
if (d_numthreads >= d_tcpclientthreads.size()) {
vinfolog("Adding a new TCP client thread would exceed the vector size (%d/%d), skipping. Consider increasing the maximum amount of TCP client threads with setMaxTCPClientThreads() in the configuration.", d_numthreads.load(), d_tcpclientthreads.size());
- close(crossProtocolQueriesFDs[0]);
- close(crossProtocolQueriesFDs[1]);
- close(crossProtocolResponsesFDs[0]);
- close(crossProtocolResponsesFDs[1]);
- close(pipefds[0]);
- close(pipefds[1]);
return;
}
- /* from now on this side of the pipe will be managed by that object,
- no need to worry about it */
- TCPWorkerThread worker(pipefds[1], crossProtocolQueriesFDs[1], crossProtocolResponsesFDs[1]);
+ TCPWorkerThread worker(std::move(queryChannelSender), std::move(crossProtocolQueryChannelSender));
+
try {
- std::thread t1(tcpClientThread, pipefds[0], crossProtocolQueriesFDs[0], crossProtocolResponsesFDs[0], crossProtocolResponsesFDs[1], tcpAcceptStates);
- t1.detach();
+ std::thread clientThread(tcpClientThread, std::move(queryChannelReceiver), std::move(crossProtocolQueryChannelReceiver), std::move(crossProtocolResponseChannelReceiver), std::move(crossProtocolResponseChannelSender), tcpAcceptStates);
+ clientThread.detach();
}
catch (const std::runtime_error& e) {
- /* the thread creation failed, don't leak */
errlog("Error creating a TCP thread: %s", e.what());
- close(pipefds[0]);
- close(crossProtocolQueriesFDs[0]);
- close(crossProtocolResponsesFDs[0]);
return;
}
d_tcpclientthreads.at(d_numthreads) = std::move(worker);
++d_numthreads;
}
+ catch (const std::exception& e) {
+ errlog("Error creating TCP worker: %", e.what());
+ }
}
std::unique_ptr<TCPClientCollection> g_tcpclientthreads;
@@ -215,11 +181,11 @@ static IOState sendQueuedResponses(std::shared_ptr<IncomingTCPConnectionState>&
IOState result = IOState::Done;
while (state->active() && !state->d_queuedResponses.empty()) {
- DEBUGLOG("queue size is "<<state->d_queuedResponses.size()<<", sending the next one");
+ DEBUGLOG("queue size is " << state->d_queuedResponses.size() << ", sending the next one");
TCPResponse resp = std::move(state->d_queuedResponses.front());
state->d_queuedResponses.pop_front();
state->d_state = IncomingTCPConnectionState::State::idle;
- result = state->sendResponse(state, now, std::move(resp));
+ result = state->sendResponse(now, std::move(resp));
if (result != IOState::Done) {
return result;
}
@@ -229,28 +195,29 @@ static IOState sendQueuedResponses(std::shared_ptr<IncomingTCPConnectionState>&
return IOState::Done;
}
-static void handleResponseSent(std::shared_ptr<IncomingTCPConnectionState>& state, TCPResponse& currentResponse)
+void IncomingTCPConnectionState::handleResponseSent(TCPResponse& currentResponse)
{
if (currentResponse.d_idstate.qtype == QType::AXFR || currentResponse.d_idstate.qtype == QType::IXFR) {
return;
}
- --state->d_currentQueriesCount;
+ --d_currentQueriesCount;
- const auto& ds = currentResponse.d_connection ? currentResponse.d_connection->getDS() : currentResponse.d_ds;
- if (currentResponse.d_idstate.selfGenerated == false && ds) {
+ const auto& backend = currentResponse.d_connection ? currentResponse.d_connection->getDS() : currentResponse.d_ds;
+ if (!currentResponse.d_idstate.selfGenerated && backend) {
const auto& ids = currentResponse.d_idstate;
double udiff = ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (%s, %d bytes), took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), (state->d_handler.isTLS() ? "DoT" : "TCP"), currentResponse.d_buffer.size(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (%s, %d bytes), took %f us", backend->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), getProtocol().toString(), currentResponse.d_buffer.size(), udiff);
- auto backendProtocol = ds->getProtocol();
- if (backendProtocol == dnsdist::Protocol::DoUDP) {
+ auto backendProtocol = backend->getProtocol();
+ if (backendProtocol == dnsdist::Protocol::DoUDP && !currentResponse.d_idstate.forwardedOverUDP) {
backendProtocol = dnsdist::Protocol::DoTCP;
}
- ::handleResponseSent(ids, udiff, state->d_ci.remote, ds->d_config.remote, static_cast<unsigned int>(currentResponse.d_buffer.size()), currentResponse.d_cleartextDH, backendProtocol, true);
- } else {
+ ::handleResponseSent(ids, udiff, d_ci.remote, backend->d_config.remote, static_cast<unsigned int>(currentResponse.d_buffer.size()), currentResponse.d_cleartextDH, backendProtocol, true);
+ }
+ else {
const auto& ids = currentResponse.d_idstate;
- ::handleResponseSent(ids, 0., state->d_ci.remote, ComboAddress(), static_cast<unsigned int>(currentResponse.d_buffer.size()), currentResponse.d_cleartextDH, ids.protocol, false);
+ ::handleResponseSent(ids, 0., d_ci.remote, ComboAddress(), static_cast<unsigned int>(currentResponse.d_buffer.size()), currentResponse.d_cleartextDH, ids.protocol, false);
}
currentResponse.d_buffer.clear();
@@ -264,11 +231,11 @@ static void prependSizeToTCPQuery(PacketBuffer& buffer, size_t proxyProtocolPayl
}
uint16_t queryLen = proxyProtocolPayloadSize > 0 ? (buffer.size() - proxyProtocolPayloadSize) : buffer.size();
- const uint8_t sizeBytes[] = { static_cast<uint8_t>(queryLen / 256), static_cast<uint8_t>(queryLen % 256) };
+ const std::array<uint8_t, 2> sizeBytes{static_cast<uint8_t>(queryLen / 256), static_cast<uint8_t>(queryLen % 256)};
/* prepend the size. Yes, this is not the most efficient way but it prevents mistakes
that could occur if we had to deal with the size during the processing,
especially alignment issues */
- buffer.insert(buffer.begin() + proxyProtocolPayloadSize, sizeBytes, sizeBytes + 2);
+ buffer.insert(buffer.begin() + static_cast<PacketBuffer::iterator::difference_type>(proxyProtocolPayloadSize), sizeBytes.begin(), sizeBytes.end());
}
bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now)
@@ -278,12 +245,13 @@ bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now)
return false;
}
- if (d_currentQueriesCount >= d_ci.cs->d_maxInFlightQueriesPerConn) {
- DEBUGLOG("not accepting new queries because we already have "<<d_currentQueriesCount<<" out of "<<d_ci.cs->d_maxInFlightQueriesPerConn);
+ // for DoH, this is already handled by the underlying library
+ if (!d_ci.cs->dohFrontend && d_currentQueriesCount >= d_ci.cs->d_maxInFlightQueriesPerConn) {
+ DEBUGLOG("not accepting new queries because we already have " << d_currentQueriesCount << " out of " << d_ci.cs->d_maxInFlightQueriesPerConn);
return false;
}
- if (g_maxTCPQueriesPerConn && d_queriesCount > g_maxTCPQueriesPerConn) {
+ if (g_maxTCPQueriesPerConn != 0 && d_queriesCount > g_maxTCPQueriesPerConn) {
vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, g_maxTCPQueriesPerConn);
return false;
}
@@ -298,27 +266,27 @@ bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now)
void IncomingTCPConnectionState::resetForNewQuery()
{
- d_buffer.resize(sizeof(uint16_t));
+ d_buffer.clear();
d_currentPos = 0;
d_querySize = 0;
d_state = State::waitingForQuery;
}
-std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& ds, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs)
+std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs)
{
- auto it = d_ownedConnectionsToBackend.find(ds);
- if (it == d_ownedConnectionsToBackend.end()) {
- DEBUGLOG("no owned connection found for "<<ds->getName());
+ auto connIt = d_ownedConnectionsToBackend.find(backend);
+ if (connIt == d_ownedConnectionsToBackend.end()) {
+ DEBUGLOG("no owned connection found for " << backend->getName());
return nullptr;
}
- for (auto& conn : it->second) {
+ for (auto& conn : connIt->second) {
if (conn->canBeReused(true) && conn->matchesTLVs(tlvs)) {
- DEBUGLOG("Got one owned connection accepting more for "<<ds->getName());
+ DEBUGLOG("Got one owned connection accepting more for " << backend->getName());
conn->setReused();
return conn;
}
- DEBUGLOG("not accepting more for "<<ds->getName());
+ DEBUGLOG("not accepting more for " << backend->getName());
}
return nullptr;
@@ -330,37 +298,36 @@ void IncomingTCPConnectionState::registerOwnedDownstreamConnection(std::shared_p
}
/* called when the buffer has been set and the rules have been processed, and only from handleIO (sometimes indirectly via handleQuery) */
-IOState IncomingTCPConnectionState::sendResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response)
+IOState IncomingTCPConnectionState::sendResponse(const struct timeval& now, TCPResponse&& response)
{
- state->d_state = IncomingTCPConnectionState::State::sendingResponse;
+ d_state = State::sendingResponse;
- uint16_t responseSize = static_cast<uint16_t>(response.d_buffer.size());
- const uint8_t sizeBytes[] = { static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256) };
+ const auto responseSize = static_cast<uint16_t>(response.d_buffer.size());
+ const std::array<uint8_t, 2> sizeBytes{static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256)};
/* prepend the size. Yes, this is not the most efficient way but it prevents mistakes
that could occur if we had to deal with the size during the processing,
especially alignment issues */
- response.d_buffer.insert(response.d_buffer.begin(), sizeBytes, sizeBytes + 2);
- state->d_currentPos = 0;
- state->d_currentResponse = std::move(response);
+ response.d_buffer.insert(response.d_buffer.begin(), sizeBytes.begin(), sizeBytes.end());
+ d_currentPos = 0;
+ d_currentResponse = std::move(response);
try {
- auto iostate = state->d_handler.tryWrite(state->d_currentResponse.d_buffer, state->d_currentPos, state->d_currentResponse.d_buffer.size());
+ auto iostate = d_handler.tryWrite(d_currentResponse.d_buffer, d_currentPos, d_currentResponse.d_buffer.size());
if (iostate == IOState::Done) {
- DEBUGLOG("response sent from "<<__PRETTY_FUNCTION__);
- handleResponseSent(state, state->d_currentResponse);
- return iostate;
- } else {
- state->d_lastIOBlocked = true;
- DEBUGLOG("partial write");
+ DEBUGLOG("response sent from " << __PRETTY_FUNCTION__);
+ handleResponseSent(d_currentResponse);
return iostate;
}
+ d_lastIOBlocked = true;
+ DEBUGLOG("partial write");
+ return iostate;
}
catch (const std::exception& e) {
- vinfolog("Closing TCP client connection with %s: %s", state->d_ci.remote.toStringWithPort(), e.what());
- DEBUGLOG("Closing TCP client connection: "<<e.what());
- ++state->d_ci.cs->tcpDiedSendingResponse;
+ vinfolog("Closing TCP client connection with %s: %s", d_ci.remote.toStringWithPort(), e.what());
+ DEBUGLOG("Closing TCP client connection: " << e.what());
+ ++d_ci.cs->tcpDiedSendingResponse;
- state->terminateClientConnection();
+ terminateClientConnection();
return IOState::Done;
}
@@ -394,50 +361,59 @@ void IncomingTCPConnectionState::terminateClientConnection()
/* we might already be waiting, but we might also not because sometimes we have already been
notified via the descriptor, not received Async again, but the async job still exists.. */
auto state = shared_from_this();
- for (const auto fd : afds) {
+ for (const auto desc : afds) {
try {
- state->d_threadData.mplexer->addReadFD(fd, handleAsyncReady, state);
+ state->d_threadData.mplexer->addReadFD(desc, handleAsyncReady, state);
}
catch (...) {
}
}
-
}
}
-void IncomingTCPConnectionState::queueResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response)
+void IncomingTCPConnectionState::queueResponse(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now, TCPResponse&& response, bool fromBackend)
{
// queue response
- state->d_queuedResponses.push_back(std::move(response));
- DEBUGLOG("queueing response, state is "<<(int)state->d_state<<", queue size is now "<<state->d_queuedResponses.size());
+ state->d_queuedResponses.emplace_back(std::move(response));
+ DEBUGLOG("queueing response, state is " << (int)state->d_state << ", queue size is now " << state->d_queuedResponses.size());
// when the response comes from a backend, there is a real possibility that we are currently
// idle, and thus not trying to send the response right away would make our ref count go to 0.
// Even if we are waiting for a query, we will not wake up before the new query arrives or a
// timeout occurs
- if (state->d_state == IncomingTCPConnectionState::State::idle ||
- state->d_state == IncomingTCPConnectionState::State::waitingForQuery) {
+ if (state->d_state == State::idle || state->d_state == State::waitingForQuery) {
auto iostate = sendQueuedResponses(state, now);
if (iostate == IOState::Done && state->active()) {
if (state->canAcceptNewQueries(now)) {
state->resetForNewQuery();
- state->d_state = IncomingTCPConnectionState::State::waitingForQuery;
+ state->d_state = State::waitingForQuery;
iostate = IOState::NeedRead;
}
else {
- state->d_state = IncomingTCPConnectionState::State::idle;
+ state->d_state = State::idle;
}
}
// for the same reason we need to update the state right away, nobody will do that for us
if (state->active()) {
updateIO(state, iostate, now);
+ // if we have not finished reading every available byte, we _need_ to do an actual read
+ // attempt before waiting for the socket to become readable again, because if there is
+ // buffered data available the socket might never become readable again.
+ // This is true as soon as we deal with TLS because TLS records are processed one by
+ // one and might not match what we see at the application layer, so data might already
+ // be available in the TLS library's buffers. This is especially true when OpenSSL's
+ // read-ahead mode is enabled because then it buffers even more than one SSL record
+ // for performance reasons.
+ if (fromBackend && !state->d_lastIOBlocked) {
+ state->handleIO();
+ }
}
}
}
-void IncomingTCPConnectionState::handleAsyncReady(int fd, FDMultiplexer::funcparam_t& param)
+void IncomingTCPConnectionState::handleAsyncReady([[maybe_unused]] int desc, FDMultiplexer::funcparam_t& param)
{
auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(param);
@@ -454,9 +430,7 @@ void IncomingTCPConnectionState::handleAsyncReady(int fd, FDMultiplexer::funcpar
if (state->active()) {
/* and now we restart our own I/O state machine */
- struct timeval now;
- gettimeofday(&now, nullptr);
- handleIO(state, now);
+ state->handleIO();
}
else {
/* we were only waiting for the engine to come back,
@@ -469,8 +443,8 @@ void IncomingTCPConnectionState::updateIO(std::shared_ptr<IncomingTCPConnectionS
{
if (newState == IOState::Async) {
auto fds = state->d_handler.getAsyncFDs();
- for (const auto fd : fds) {
- state->d_threadData.mplexer->addReadFD(fd, handleAsyncReady, state);
+ for (const auto desc : fds) {
+ state->d_threadData.mplexer->addReadFD(desc, handleAsyncReady, state);
}
state->d_ioState->update(IOState::Done, handleIOCallback, state);
}
@@ -521,27 +495,27 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe
if (!response.isAsync()) {
try {
auto& ids = response.d_idstate;
- unsigned int qnameWireLength;
- if (!response.d_connection || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, response.d_connection->getDS(), qnameWireLength)) {
+ std::shared_ptr<DownstreamState> backend = response.d_ds ? response.d_ds : (response.d_connection ? response.d_connection->getDS() : nullptr);
+ if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend)) {
state->terminateClientConnection();
return;
}
- if (response.d_connection->getDS()) {
- ++response.d_connection->getDS()->responses;
+ if (backend != nullptr) {
+ ++backend->responses;
}
- DNSResponse dr(ids, response.d_buffer, response.d_connection->getDS());
- dr.d_incomingTCPState = state;
+ DNSResponse dnsResponse(ids, response.d_buffer, backend);
+ dnsResponse.d_incomingTCPState = state;
- memcpy(&response.d_cleartextDH, dr.getHeader(), sizeof(response.d_cleartextDH));
+ memcpy(&response.d_cleartextDH, dnsResponse.getHeader().get(), sizeof(response.d_cleartextDH));
- if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dr, false)) {
+ if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dnsResponse, false)) {
state->terminateClientConnection();
return;
}
- if (dr.isAsynchronous()) {
+ if (dnsResponse.isAsynchronous()) {
/* we are done for now */
return;
}
@@ -553,17 +527,23 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe
}
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++state->d_ci.cs->responses;
- queueResponse(state, now, std::move(response));
+ queueResponse(state, now, std::move(response), true);
}
struct TCPCrossProtocolResponse
{
- TCPCrossProtocolResponse(TCPResponse&& response, std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now): d_response(std::move(response)), d_state(state), d_now(now)
+ TCPCrossProtocolResponse(TCPResponse&& response, std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now) :
+ d_response(std::move(response)), d_state(state), d_now(now)
{
}
+ TCPCrossProtocolResponse(const TCPCrossProtocolResponse&) = delete;
+ TCPCrossProtocolResponse& operator=(const TCPCrossProtocolResponse&) = delete;
+ TCPCrossProtocolResponse(TCPCrossProtocolResponse&&) = delete;
+ TCPCrossProtocolResponse& operator=(TCPCrossProtocolResponse&&) = delete;
+ ~TCPCrossProtocolResponse() = default;
TCPResponse d_response;
std::shared_ptr<IncomingTCPConnectionState> d_state;
@@ -573,14 +553,15 @@ struct TCPCrossProtocolResponse
class TCPCrossProtocolQuery : public CrossProtocolQuery
{
public:
- TCPCrossProtocolQuery(PacketBuffer&& buffer, InternalQueryState&& ids, std::shared_ptr<DownstreamState> ds, std::shared_ptr<IncomingTCPConnectionState> sender): CrossProtocolQuery(InternalQuery(std::move(buffer), std::move(ids)), ds), d_sender(std::move(sender))
- {
- proxyProtocolPayloadSize = 0;
- }
-
- ~TCPCrossProtocolQuery()
+ TCPCrossProtocolQuery(PacketBuffer&& buffer, InternalQueryState&& ids, std::shared_ptr<DownstreamState> backend, std::shared_ptr<IncomingTCPConnectionState> sender) :
+ CrossProtocolQuery(InternalQuery(std::move(buffer), std::move(ids)), backend), d_sender(std::move(sender))
{
}
+ TCPCrossProtocolQuery(const TCPCrossProtocolQuery&) = delete;
+ TCPCrossProtocolQuery& operator=(const TCPCrossProtocolQuery&) = delete;
+ TCPCrossProtocolQuery(TCPCrossProtocolQuery&&) = delete;
+ TCPCrossProtocolQuery& operator=(TCPCrossProtocolQuery&&) = delete;
+ ~TCPCrossProtocolQuery() override = default;
std::shared_ptr<TCPQuerySender> getTCPQuerySender() override
{
@@ -590,503 +571,616 @@ public:
DNSQuestion getDQ() override
{
auto& ids = query.d_idstate;
- DNSQuestion dq(ids, query.d_buffer);
- dq.d_incomingTCPState = d_sender;
- return dq;
+ DNSQuestion dnsQuestion(ids, query.d_buffer);
+ dnsQuestion.d_incomingTCPState = d_sender;
+ return dnsQuestion;
}
DNSResponse getDR() override
{
auto& ids = query.d_idstate;
- DNSResponse dr(ids, query.d_buffer, downstream);
- dr.d_incomingTCPState = d_sender;
- return dr;
+ DNSResponse dnsResponse(ids, query.d_buffer, downstream);
+ dnsResponse.d_incomingTCPState = d_sender;
+ return dnsResponse;
}
private:
std::shared_ptr<IncomingTCPConnectionState> d_sender;
};
-std::unique_ptr<CrossProtocolQuery> getTCPCrossProtocolQueryFromDQ(DNSQuestion& dq)
+std::unique_ptr<CrossProtocolQuery> IncomingTCPConnectionState::getCrossProtocolQuery(PacketBuffer&& query, InternalQueryState&& state, const std::shared_ptr<DownstreamState>& backend)
{
- auto state = dq.getIncomingTCPState();
+ return std::make_unique<TCPCrossProtocolQuery>(std::move(query), std::move(state), backend, shared_from_this());
+}
+
+std::unique_ptr<CrossProtocolQuery> getTCPCrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion)
+{
+ auto state = dnsQuestion.getIncomingTCPState();
if (!state) {
throw std::runtime_error("Trying to create a TCP cross protocol query without a valid TCP state");
}
- dq.ids.origID = dq.getHeader()->id;
- return std::make_unique<TCPCrossProtocolQuery>(std::move(dq.getMutableData()), std::move(dq.ids), nullptr, std::move(state));
+ dnsQuestion.ids.origID = dnsQuestion.getHeader()->id;
+ return std::make_unique<TCPCrossProtocolQuery>(std::move(dnsQuestion.getMutableData()), std::move(dnsQuestion.ids), nullptr, std::move(state));
}
void IncomingTCPConnectionState::handleCrossProtocolResponse(const struct timeval& now, TCPResponse&& response)
{
- if (d_threadData.crossProtocolResponsesPipe == -1) {
- throw std::runtime_error("Invalid pipe descriptor in TCP Cross Protocol Query Sender");
- }
-
std::shared_ptr<IncomingTCPConnectionState> state = shared_from_this();
- auto ptr = new TCPCrossProtocolResponse(std::move(response), state, now);
- static_assert(sizeof(ptr) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
- ssize_t sent = write(d_threadData.crossProtocolResponsesPipe, &ptr, sizeof(ptr));
- if (sent != sizeof(ptr)) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- ++g_stats.tcpCrossProtocolResponsePipeFull;
+ try {
+ auto ptr = std::make_unique<TCPCrossProtocolResponse>(std::move(response), state, now);
+ if (!state->d_threadData.crossProtocolResponseSender.send(std::move(ptr))) {
+ ++dnsdist::metrics::g_stats.tcpCrossProtocolResponsePipeFull;
vinfolog("Unable to pass a cross-protocol response to the TCP worker thread because the pipe is full");
}
- else {
- vinfolog("Unable to pass a cross-protocol response to the TCP worker thread because we couldn't write to the pipe: %s", stringerror());
- }
- delete ptr;
+ }
+ catch (const std::exception& e) {
+ vinfolog("Unable to pass a cross-protocol response to the TCP worker thread because we couldn't write to the pipe: %s", stringerror());
}
}
-static void handleQuery(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now)
+IncomingTCPConnectionState::QueryProcessingResult IncomingTCPConnectionState::handleQuery(PacketBuffer&& queryIn, const struct timeval& now, std::optional<int32_t> streamID)
{
- if (state->d_querySize < sizeof(dnsheader)) {
- ++g_stats.nonCompliantQueries;
- ++state->d_ci.cs->nonCompliantQueries;
- state->terminateClientConnection();
- return;
+ auto query = std::move(queryIn);
+ if (query.size() < sizeof(dnsheader)) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++d_ci.cs->nonCompliantQueries;
+ return QueryProcessingResult::TooSmall;
}
- ++state->d_queriesCount;
- ++state->d_ci.cs->queries;
- ++g_stats.queries;
+ ++d_queriesCount;
+ ++d_ci.cs->queries;
+ ++dnsdist::metrics::g_stats.queries;
- if (state->d_handler.isTLS()) {
- auto tlsVersion = state->d_handler.getTLSVersion();
+ if (d_handler.isTLS()) {
+ auto tlsVersion = d_handler.getTLSVersion();
switch (tlsVersion) {
case LibsslTLSVersion::TLS10:
- ++state->d_ci.cs->tls10queries;
+ ++d_ci.cs->tls10queries;
break;
case LibsslTLSVersion::TLS11:
- ++state->d_ci.cs->tls11queries;
+ ++d_ci.cs->tls11queries;
break;
case LibsslTLSVersion::TLS12:
- ++state->d_ci.cs->tls12queries;
+ ++d_ci.cs->tls12queries;
break;
case LibsslTLSVersion::TLS13:
- ++state->d_ci.cs->tls13queries;
+ ++d_ci.cs->tls13queries;
break;
default:
- ++state->d_ci.cs->tlsUnknownqueries;
+ ++d_ci.cs->tlsUnknownqueries;
}
}
+ auto state = shared_from_this();
InternalQueryState ids;
- ids.origDest = state->d_proxiedDestination;
- ids.origRemote = state->d_proxiedRemote;
- ids.cs = state->d_ci.cs;
+ ids.origDest = d_proxiedDestination;
+ ids.origRemote = d_proxiedRemote;
+ ids.cs = d_ci.cs;
ids.queryRealTime.start();
+ if (streamID) {
+ ids.d_streamID = *streamID;
+ }
- auto dnsCryptResponse = checkDNSCryptQuery(*state->d_ci.cs, state->d_buffer, ids.dnsCryptQuery, ids.queryRealTime.d_start.tv_sec, true);
+ auto dnsCryptResponse = checkDNSCryptQuery(*d_ci.cs, query, ids.dnsCryptQuery, ids.queryRealTime.d_start.tv_sec, true);
if (dnsCryptResponse) {
TCPResponse response;
- state->d_state = IncomingTCPConnectionState::State::idle;
- ++state->d_currentQueriesCount;
- state->queueResponse(state, now, std::move(response));
- return;
+ d_state = State::idle;
+ ++d_currentQueriesCount;
+ queueResponse(state, now, std::move(response), false);
+ return QueryProcessingResult::SelfAnswered;
}
{
/* this pointer will be invalidated the second the buffer is resized, don't hold onto it! */
- auto* dh = reinterpret_cast<dnsheader*>(state->d_buffer.data());
- if (!checkQueryHeaders(dh, *state->d_ci.cs)) {
- state->terminateClientConnection();
- return;
+ const dnsheader_aligned dnsHeader(query.data());
+ if (!checkQueryHeaders(*dnsHeader, *d_ci.cs)) {
+ return QueryProcessingResult::InvalidHeaders;
}
- if (dh->qdcount == 0) {
+ if (dnsHeader->qdcount == 0) {
TCPResponse response;
- dh->rcode = RCode::NotImp;
- dh->qr = true;
+ auto queryID = dnsHeader->id;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+ response.d_idstate = std::move(ids);
+ response.d_idstate.origID = queryID;
response.d_idstate.selfGenerated = true;
- response.d_buffer = std::move(state->d_buffer);
- state->d_state = IncomingTCPConnectionState::State::idle;
- ++state->d_currentQueriesCount;
- state->queueResponse(state, now, std::move(response));
- return;
+ response.d_buffer = std::move(query);
+ d_state = State::idle;
+ ++d_currentQueriesCount;
+ queueResponse(state, now, std::move(response), false);
+ return QueryProcessingResult::SelfAnswered;
}
}
- ids.qname = DNSName(reinterpret_cast<const char*>(state->d_buffer.data()), state->d_buffer.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
- ids.protocol = dnsdist::Protocol::DoTCP;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast
+ ids.qname = DNSName(reinterpret_cast<const char*>(query.data()), static_cast<int>(query.size()), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
+ ids.protocol = getProtocol();
if (ids.dnsCryptQuery) {
ids.protocol = dnsdist::Protocol::DNSCryptTCP;
}
- else if (state->d_handler.isTLS()) {
- ids.protocol = dnsdist::Protocol::DoT;
- }
- DNSQuestion dq(ids, state->d_buffer);
- const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader());
- ids.origFlags = *flags;
- dq.d_incomingTCPState = state;
- dq.sni = state->d_handler.getServerNameIndication();
+ DNSQuestion dnsQuestion(ids, query);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [&ids](dnsheader& header) {
+ const uint16_t* flags = getFlagsFromDNSHeader(&header);
+ ids.origFlags = *flags;
+ return true;
+ });
+ dnsQuestion.d_incomingTCPState = state;
+ dnsQuestion.sni = d_handler.getServerNameIndication();
- if (state->d_proxyProtocolValues) {
+ if (d_proxyProtocolValues) {
/* we need to copy them, because the next queries received on that connection will
need to get the _unaltered_ values */
- dq.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(*state->d_proxyProtocolValues);
+ dnsQuestion.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(*d_proxyProtocolValues);
}
- if (dq.ids.qtype == QType::AXFR || dq.ids.qtype == QType::IXFR) {
- dq.ids.skipCache = true;
+ if (dnsQuestion.ids.qtype == QType::AXFR || dnsQuestion.ids.qtype == QType::IXFR) {
+ dnsQuestion.ids.skipCache = true;
}
- std::shared_ptr<DownstreamState> ds;
- auto result = processQuery(dq, state->d_threadData.holders, ds);
+ if (forwardViaUDPFirst()) {
+ // if there was no EDNS, we add it with a large buffer size
+ // so we can use UDP to talk to the backend.
+ const dnsheader_aligned dnsHeader(query.data());
+ if (dnsHeader->arcount == 0U) {
+ if (addEDNS(query, 4096, false, 4096, 0)) {
+ dnsQuestion.ids.ednsAdded = true;
+ }
+ }
+ }
- if (result == ProcessQueryResult::Drop) {
- state->terminateClientConnection();
- return;
+ if (streamID) {
+ auto unit = getDOHUnit(*streamID);
+ if (unit) {
+ dnsQuestion.ids.du = std::move(unit);
+ }
}
- else if (result == ProcessQueryResult::Asynchronous) {
+
+ std::shared_ptr<DownstreamState> backend;
+ auto result = processQuery(dnsQuestion, d_threadData.holders, backend);
+
+ if (result == ProcessQueryResult::Asynchronous) {
/* we are done for now */
- ++state->d_currentQueriesCount;
- return;
+ ++d_currentQueriesCount;
+ return QueryProcessingResult::Asynchronous;
+ }
+
+ if (streamID) {
+ restoreDOHUnit(std::move(dnsQuestion.ids.du));
+ }
+
+ if (result == ProcessQueryResult::Drop) {
+ return QueryProcessingResult::Dropped;
}
// the buffer might have been invalidated by now
- const dnsheader* dh = dq.getHeader();
+ uint16_t queryID{0};
+ {
+ const auto dnsHeader = dnsQuestion.getHeader();
+ queryID = dnsHeader->id;
+ }
+
if (result == ProcessQueryResult::SendAnswer) {
TCPResponse response;
- memcpy(&response.d_cleartextDH, dh, sizeof(response.d_cleartextDH));
+ {
+ const auto dnsHeader = dnsQuestion.getHeader();
+ memcpy(&response.d_cleartextDH, dnsHeader.get(), sizeof(response.d_cleartextDH));
+ }
response.d_idstate = std::move(ids);
- response.d_idstate.origID = dh->id;
+ response.d_idstate.origID = queryID;
response.d_idstate.selfGenerated = true;
- response.d_idstate.cs = state->d_ci.cs;
- response.d_buffer = std::move(state->d_buffer);
+ response.d_idstate.cs = d_ci.cs;
+ response.d_buffer = std::move(query);
- state->d_state = IncomingTCPConnectionState::State::idle;
- ++state->d_currentQueriesCount;
- state->queueResponse(state, now, std::move(response));
- return;
+ d_state = State::idle;
+ ++d_currentQueriesCount;
+ queueResponse(state, now, std::move(response), false);
+ return QueryProcessingResult::SelfAnswered;
}
- if (result != ProcessQueryResult::PassToBackend || ds == nullptr) {
- state->terminateClientConnection();
- return;
+ if (result != ProcessQueryResult::PassToBackend || backend == nullptr) {
+ return QueryProcessingResult::NoBackend;
}
- dq.ids.origID = dh->id;
+ dnsQuestion.ids.origID = queryID;
- ++state->d_currentQueriesCount;
+ ++d_currentQueriesCount;
std::string proxyProtocolPayload;
- if (ds->isDoH()) {
- vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", ids.qname.toLogString(), QType(ids.qtype).toString(), state->d_proxiedRemote.toStringWithPort(), (state->d_handler.isTLS() ? "DoT" : "TCP"), state->d_buffer.size(), ds->getNameWithAddr());
+ if (backend->isDoH()) {
+ vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", ids.qname.toLogString(), QType(ids.qtype).toString(), d_proxiedRemote.toStringWithPort(), getProtocol().toString(), query.size(), backend->getNameWithAddr());
/* we need to do this _before_ creating the cross protocol query because
after that the buffer will have been moved */
- if (ds->d_config.useProxyProtocol) {
- proxyProtocolPayload = getProxyProtocolPayload(dq);
+ if (backend->d_config.useProxyProtocol) {
+ proxyProtocolPayload = getProxyProtocolPayload(dnsQuestion);
}
- auto cpq = std::make_unique<TCPCrossProtocolQuery>(std::move(state->d_buffer), std::move(ids), ds, state);
+ auto cpq = std::make_unique<TCPCrossProtocolQuery>(std::move(query), std::move(ids), backend, state);
cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
- ds->passCrossProtocolQuery(std::move(cpq));
- return;
+ backend->passCrossProtocolQuery(std::move(cpq));
+ return QueryProcessingResult::Forwarded;
+ }
+ if (!backend->isTCPOnly() && forwardViaUDPFirst()) {
+ if (streamID) {
+ auto unit = getDOHUnit(*streamID);
+ if (unit) {
+ dnsQuestion.ids.du = std::move(unit);
+ }
+ }
+ if (assignOutgoingUDPQueryToBackend(backend, queryID, dnsQuestion, query)) {
+ return QueryProcessingResult::Forwarded;
+ }
+ restoreDOHUnit(std::move(dnsQuestion.ids.du));
+ // fallback to the normal flow
}
- prependSizeToTCPQuery(state->d_buffer, 0);
+ prependSizeToTCPQuery(query, 0);
- auto downstreamConnection = state->getDownstreamConnection(ds, dq.proxyProtocolValues, now);
+ auto downstreamConnection = getDownstreamConnection(backend, dnsQuestion.proxyProtocolValues, now);
- if (ds->d_config.useProxyProtocol) {
+ if (backend->d_config.useProxyProtocol) {
/* if we ever sent a TLV over a connection, we can never go back */
- if (!state->d_proxyProtocolPayloadHasTLV) {
- state->d_proxyProtocolPayloadHasTLV = dq.proxyProtocolValues && !dq.proxyProtocolValues->empty();
+ if (!d_proxyProtocolPayloadHasTLV) {
+ d_proxyProtocolPayloadHasTLV = dnsQuestion.proxyProtocolValues && !dnsQuestion.proxyProtocolValues->empty();
}
- proxyProtocolPayload = getProxyProtocolPayload(dq);
+ proxyProtocolPayload = getProxyProtocolPayload(dnsQuestion);
}
- if (dq.proxyProtocolValues) {
- downstreamConnection->setProxyProtocolValuesSent(std::move(dq.proxyProtocolValues));
+ if (dnsQuestion.proxyProtocolValues) {
+ downstreamConnection->setProxyProtocolValuesSent(std::move(dnsQuestion.proxyProtocolValues));
}
- TCPQuery query(std::move(state->d_buffer), std::move(ids));
- query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
+ TCPQuery tcpquery(std::move(query), std::move(ids));
+ tcpquery.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
- vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", query.d_idstate.qname.toLogString(), QType(query.d_idstate.qtype).toString(), state->d_proxiedRemote.toStringWithPort(), (state->d_handler.isTLS() ? "DoT" : "TCP"), query.d_buffer.size(), ds->getNameWithAddr());
+ vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", tcpquery.d_idstate.qname.toLogString(), QType(tcpquery.d_idstate.qtype).toString(), d_proxiedRemote.toStringWithPort(), getProtocol().toString(), tcpquery.d_buffer.size(), backend->getNameWithAddr());
std::shared_ptr<TCPQuerySender> incoming = state;
- downstreamConnection->queueQuery(incoming, std::move(query));
+ downstreamConnection->queueQuery(incoming, std::move(tcpquery));
+ return QueryProcessingResult::Forwarded;
}
-void IncomingTCPConnectionState::handleIOCallback(int fd, FDMultiplexer::funcparam_t& param)
+void IncomingTCPConnectionState::handleIOCallback(int desc, FDMultiplexer::funcparam_t& param)
{
auto conn = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(param);
- if (fd != conn->d_handler.getDescriptor()) {
- throw std::runtime_error("Unexpected socket descriptor " + std::to_string(fd) + " received in " + std::string(__PRETTY_FUNCTION__) + ", expected " + std::to_string(conn->d_handler.getDescriptor()));
+ if (desc != conn->d_handler.getDescriptor()) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay): __PRETTY_FUNCTION__ is fine
+ throw std::runtime_error("Unexpected socket descriptor " + std::to_string(desc) + " received in " + std::string(__PRETTY_FUNCTION__) + ", expected " + std::to_string(conn->d_handler.getDescriptor()));
}
- struct timeval now;
- gettimeofday(&now, nullptr);
- handleIO(conn, now);
+ conn->handleIO();
+}
+
+void IncomingTCPConnectionState::handleHandshakeDone(const struct timeval& now)
+{
+ if (d_handler.isTLS()) {
+ if (!d_handler.hasTLSSessionBeenResumed()) {
+ ++d_ci.cs->tlsNewSessions;
+ }
+ else {
+ ++d_ci.cs->tlsResumptions;
+ }
+ if (d_handler.getResumedFromInactiveTicketKey()) {
+ ++d_ci.cs->tlsInactiveTicketKey;
+ }
+ if (d_handler.getUnknownTicketKey()) {
+ ++d_ci.cs->tlsUnknownTicketKey;
+ }
+ }
+
+ d_handshakeDoneTime = now;
+}
+
+IncomingTCPConnectionState::ProxyProtocolResult IncomingTCPConnectionState::handleProxyProtocolPayload()
+{
+ do {
+ DEBUGLOG("reading proxy protocol header");
+ auto iostate = d_handler.tryRead(d_buffer, d_currentPos, d_proxyProtocolNeed, false, isProxyPayloadOutsideTLS());
+ if (iostate == IOState::Done) {
+ d_buffer.resize(d_currentPos);
+ ssize_t remaining = isProxyHeaderComplete(d_buffer);
+ if (remaining == 0) {
+ vinfolog("Unable to consume proxy protocol header in packet from TCP client %s", d_ci.remote.toStringWithPort());
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
+ return ProxyProtocolResult::Error;
+ }
+ if (remaining < 0) {
+ d_proxyProtocolNeed += -remaining;
+ d_buffer.resize(d_currentPos + d_proxyProtocolNeed);
+ /* we need to keep reading, since we might have buffered data */
+ }
+ else {
+ /* proxy header received */
+ std::vector<ProxyProtocolValue> proxyProtocolValues;
+ if (!handleProxyProtocol(d_ci.remote, true, *d_threadData.holders.acl, d_buffer, d_proxiedRemote, d_proxiedDestination, proxyProtocolValues)) {
+ vinfolog("Error handling the Proxy Protocol received from TCP client %s", d_ci.remote.toStringWithPort());
+ return ProxyProtocolResult::Error;
+ }
+
+ if (!proxyProtocolValues.empty()) {
+ d_proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
+ }
+
+ return ProxyProtocolResult::Done;
+ }
+ }
+ else {
+ d_lastIOBlocked = true;
+ }
+ } while (active() && !d_lastIOBlocked);
+
+ return ProxyProtocolResult::Reading;
+}
+
+IOState IncomingTCPConnectionState::handleHandshake(const struct timeval& now)
+{
+ DEBUGLOG("doing handshake");
+ auto iostate = d_handler.tryHandshake();
+ if (iostate == IOState::Done) {
+ DEBUGLOG("handshake done");
+ handleHandshakeDone(now);
+
+ if (d_ci.cs != nullptr && d_ci.cs->d_enableProxyProtocol && !isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) {
+ d_state = State::readingProxyProtocolHeader;
+ d_buffer.resize(s_proxyProtocolMinimumHeaderSize);
+ d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
+ }
+ else {
+ d_state = State::readingQuerySize;
+ }
+ }
+ else {
+ d_lastIOBlocked = true;
+ }
+
+ return iostate;
+}
+
+IOState IncomingTCPConnectionState::handleIncomingQueryReceived(const struct timeval& now)
+{
+ DEBUGLOG("query received");
+ d_buffer.resize(d_querySize);
+
+ d_state = State::idle;
+ auto processingResult = handleQuery(std::move(d_buffer), now, std::nullopt);
+ switch (processingResult) {
+ case QueryProcessingResult::TooSmall:
+ /* fall-through */
+ case QueryProcessingResult::InvalidHeaders:
+ /* fall-through */
+ case QueryProcessingResult::Dropped:
+ /* fall-through */
+ case QueryProcessingResult::NoBackend:
+ terminateClientConnection();
+ ;
+ default:
+ break;
+ }
+
+ /* the state might have been updated in the meantime, we don't want to override it
+ in that case */
+ if (active() && d_state != State::idle) {
+ if (d_ioState->isWaitingForRead()) {
+ return IOState::NeedRead;
+ }
+ if (d_ioState->isWaitingForWrite()) {
+ return IOState::NeedWrite;
+ }
+ return IOState::Done;
+ }
+ return IOState::Done;
+};
+
+void IncomingTCPConnectionState::handleExceptionDuringIO(const std::exception& exp)
+{
+ if (d_state == State::idle || d_state == State::waitingForQuery) {
+ /* no need to increase any counters in that case, the client is simply done with us */
+ }
+ else if (d_state == State::doingHandshake || d_state == State::readingProxyProtocolHeader || d_state == State::waitingForQuery || d_state == State::readingQuerySize || d_state == State::readingQuery) {
+ ++d_ci.cs->tcpDiedReadingQuery;
+ }
+ else if (d_state == State::sendingResponse) {
+ /* unlikely to happen here, the exception should be handled in sendResponse() */
+ ++d_ci.cs->tcpDiedSendingResponse;
+ }
+
+ if (d_ioState->isWaitingForWrite() || d_queriesCount == 0) {
+ DEBUGLOG("Got an exception while handling TCP query: " << exp.what());
+ vinfolog("Got an exception while handling (%s) TCP query from %s: %s", (d_ioState->isWaitingForRead() ? "reading" : "writing"), d_ci.remote.toStringWithPort(), exp.what());
+ }
+ else {
+ vinfolog("Closing TCP client connection with %s: %s", d_ci.remote.toStringWithPort(), exp.what());
+ DEBUGLOG("Closing TCP client connection: " << exp.what());
+ }
+ /* remove this FD from the IO multiplexer */
+ terminateClientConnection();
}
-void IncomingTCPConnectionState::handleIO(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now)
+bool IncomingTCPConnectionState::readIncomingQuery(const timeval& now, IOState& iostate)
+{
+ if (!d_lastIOBlocked && (d_state == State::waitingForQuery || d_state == State::readingQuerySize)) {
+ DEBUGLOG("reading query size");
+ d_buffer.resize(sizeof(uint16_t));
+ iostate = d_handler.tryRead(d_buffer, d_currentPos, sizeof(uint16_t));
+ if (d_currentPos > 0) {
+ /* if we got at least one byte, we can't go around sending responses */
+ d_state = State::readingQuerySize;
+ }
+
+ if (iostate == IOState::Done) {
+ DEBUGLOG("query size received");
+ d_state = State::readingQuery;
+ d_querySizeReadTime = now;
+ if (d_queriesCount == 0) {
+ d_firstQuerySizeReadTime = now;
+ }
+ d_querySize = d_buffer.at(0) * 256 + d_buffer.at(1);
+ if (d_querySize < sizeof(dnsheader)) {
+ /* go away */
+ terminateClientConnection();
+ return true;
+ }
+
+ d_buffer.resize(d_querySize);
+ d_currentPos = 0;
+ }
+ else {
+ d_lastIOBlocked = true;
+ }
+ }
+
+ if (!d_lastIOBlocked && d_state == State::readingQuery) {
+ DEBUGLOG("reading query");
+ iostate = d_handler.tryRead(d_buffer, d_currentPos, d_querySize);
+ if (iostate == IOState::Done) {
+ iostate = handleIncomingQueryReceived(now);
+ }
+ else {
+ d_lastIOBlocked = true;
+ }
+ }
+
+ return false;
+}
+
+void IncomingTCPConnectionState::handleIO()
{
// why do we loop? Because the TLS layer does buffering, and thus can have data ready to read
// even though the underlying socket is not ready, so we need to actually ask for the data first
IOState iostate = IOState::Done;
+ timeval now{};
+ gettimeofday(&now, nullptr);
+
do {
iostate = IOState::Done;
- IOStateGuard ioGuard(state->d_ioState);
+ IOStateGuard ioGuard(d_ioState);
- if (state->maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
- vinfolog("Terminating TCP connection from %s because it reached the maximum TCP connection duration", state->d_ci.remote.toStringWithPort());
+ if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+ vinfolog("Terminating TCP connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
// will be handled by the ioGuard
- //handleNewIOState(state, IOState::Done, fd, handleIOCallback);
+ // handleNewIOState(state, IOState::Done, fd, handleIOCallback);
return;
}
- state->d_lastIOBlocked = false;
+ d_lastIOBlocked = false;
try {
- if (state->d_state == IncomingTCPConnectionState::State::doingHandshake) {
- DEBUGLOG("doing handshake");
- iostate = state->d_handler.tryHandshake();
- if (iostate == IOState::Done) {
- DEBUGLOG("handshake done");
- if (state->d_handler.isTLS()) {
- if (!state->d_handler.hasTLSSessionBeenResumed()) {
- ++state->d_ci.cs->tlsNewSessions;
- }
- else {
- ++state->d_ci.cs->tlsResumptions;
- }
- if (state->d_handler.getResumedFromInactiveTicketKey()) {
- ++state->d_ci.cs->tlsInactiveTicketKey;
- }
- if (state->d_handler.getUnknownTicketKey()) {
- ++state->d_ci.cs->tlsUnknownTicketKey;
- }
- }
-
- state->d_handshakeDoneTime = now;
- if (expectProxyProtocolFrom(state->d_ci.remote)) {
- state->d_state = IncomingTCPConnectionState::State::readingProxyProtocolHeader;
- state->d_buffer.resize(s_proxyProtocolMinimumHeaderSize);
- state->d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
- }
- else {
- state->d_state = IncomingTCPConnectionState::State::readingQuerySize;
- }
+ if (d_state == State::starting) {
+ if (d_ci.cs != nullptr && d_ci.cs->d_enableProxyProtocol && isProxyPayloadOutsideTLS() && expectProxyProtocolFrom(d_ci.remote)) {
+ d_state = State::readingProxyProtocolHeader;
+ d_buffer.resize(s_proxyProtocolMinimumHeaderSize);
+ d_proxyProtocolNeed = s_proxyProtocolMinimumHeaderSize;
}
else {
- state->d_lastIOBlocked = true;
+ d_state = State::doingHandshake;
}
}
- if (!state->d_lastIOBlocked && state->d_state == IncomingTCPConnectionState::State::readingProxyProtocolHeader) {
- do {
- DEBUGLOG("reading proxy protocol header");
- iostate = state->d_handler.tryRead(state->d_buffer, state->d_currentPos, state->d_proxyProtocolNeed);
- if (iostate == IOState::Done) {
- state->d_buffer.resize(state->d_currentPos);
- ssize_t remaining = isProxyHeaderComplete(state->d_buffer);
- if (remaining == 0) {
- vinfolog("Unable to consume proxy protocol header in packet from TCP client %s", state->d_ci.remote.toStringWithPort());
- ++g_stats.proxyProtocolInvalid;
- break;
- }
- else if (remaining < 0) {
- state->d_proxyProtocolNeed += -remaining;
- state->d_buffer.resize(state->d_currentPos + state->d_proxyProtocolNeed);
- /* we need to keep reading, since we might have buffered data */
- iostate = IOState::NeedRead;
- }
- else {
- /* proxy header received */
- std::vector<ProxyProtocolValue> proxyProtocolValues;
- if (!handleProxyProtocol(state->d_ci.remote, true, *state->d_threadData.holders.acl, state->d_buffer, state->d_proxiedRemote, state->d_proxiedDestination, proxyProtocolValues)) {
- vinfolog("Error handling the Proxy Protocol received from TCP client %s", state->d_ci.remote.toStringWithPort());
- break;
- }
-
- if (!proxyProtocolValues.empty()) {
- state->d_proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
- }
-
- state->d_state = IncomingTCPConnectionState::State::readingQuerySize;
- state->d_buffer.resize(sizeof(uint16_t));
- state->d_currentPos = 0;
- state->d_proxyProtocolNeed = 0;
- break;
- }
- }
- else {
- state->d_lastIOBlocked = true;
- }
- }
- while (state->active() && !state->d_lastIOBlocked);
+ if (d_state == State::doingHandshake) {
+ iostate = handleHandshake(now);
}
- if (!state->d_lastIOBlocked && (state->d_state == IncomingTCPConnectionState::State::waitingForQuery ||
- state->d_state == IncomingTCPConnectionState::State::readingQuerySize)) {
- DEBUGLOG("reading query size");
- iostate = state->d_handler.tryRead(state->d_buffer, state->d_currentPos, sizeof(uint16_t));
- if (state->d_currentPos > 0) {
- /* if we got at least one byte, we can't go around sending responses */
- state->d_state = IncomingTCPConnectionState::State::readingQuerySize;
- }
-
- if (iostate == IOState::Done) {
- DEBUGLOG("query size received");
- state->d_state = IncomingTCPConnectionState::State::readingQuery;
- state->d_querySizeReadTime = now;
- if (state->d_queriesCount == 0) {
- state->d_firstQuerySizeReadTime = now;
+ if (!d_lastIOBlocked && d_state == State::readingProxyProtocolHeader) {
+ auto status = handleProxyProtocolPayload();
+ if (status == ProxyProtocolResult::Done) {
+ if (isProxyPayloadOutsideTLS()) {
+ d_state = State::doingHandshake;
+ iostate = handleHandshake(now);
}
- state->d_querySize = state->d_buffer.at(0) * 256 + state->d_buffer.at(1);
- if (state->d_querySize < sizeof(dnsheader)) {
- /* go away */
- state->terminateClientConnection();
- return;
+ else {
+ d_state = State::readingQuerySize;
+ d_buffer.resize(sizeof(uint16_t));
+ d_currentPos = 0;
+ d_proxyProtocolNeed = 0;
}
-
- /* allocate a bit more memory to be able to spoof the content, get an answer from the cache
- or to add ECS without allocating a new buffer */
- state->d_buffer.resize(std::max(state->d_querySize + static_cast<size_t>(512), s_maxPacketCacheEntrySize));
- state->d_currentPos = 0;
+ }
+ else if (status == ProxyProtocolResult::Error) {
+ iostate = IOState::Done;
}
else {
- state->d_lastIOBlocked = true;
+ iostate = IOState::NeedRead;
}
}
- if (!state->d_lastIOBlocked && state->d_state == IncomingTCPConnectionState::State::readingQuery) {
- DEBUGLOG("reading query");
- iostate = state->d_handler.tryRead(state->d_buffer, state->d_currentPos, state->d_querySize);
- if (iostate == IOState::Done) {
- DEBUGLOG("query received");
- state->d_buffer.resize(state->d_querySize);
-
- state->d_state = IncomingTCPConnectionState::State::idle;
- handleQuery(state, now);
- /* the state might have been updated in the meantime, we don't want to override it
- in that case */
- if (state->active() && state->d_state != IncomingTCPConnectionState::State::idle) {
- if (state->d_ioState->isWaitingForRead()) {
- iostate = IOState::NeedRead;
- }
- else if (state->d_ioState->isWaitingForWrite()) {
- iostate = IOState::NeedWrite;
- }
- else {
- iostate = IOState::Done;
- }
- }
- }
- else {
- state->d_lastIOBlocked = true;
+ if (!d_lastIOBlocked && (d_state == State::waitingForQuery || d_state == State::readingQuerySize || d_state == State::readingQuery)) {
+ if (readIncomingQuery(now, iostate)) {
+ return;
}
}
- if (!state->d_lastIOBlocked && state->d_state == IncomingTCPConnectionState::State::sendingResponse) {
+ if (!d_lastIOBlocked && d_state == State::sendingResponse) {
DEBUGLOG("sending response");
- iostate = state->d_handler.tryWrite(state->d_currentResponse.d_buffer, state->d_currentPos, state->d_currentResponse.d_buffer.size());
+ iostate = d_handler.tryWrite(d_currentResponse.d_buffer, d_currentPos, d_currentResponse.d_buffer.size());
if (iostate == IOState::Done) {
- DEBUGLOG("response sent from "<<__PRETTY_FUNCTION__);
- handleResponseSent(state, state->d_currentResponse);
- state->d_state = IncomingTCPConnectionState::State::idle;
+ DEBUGLOG("response sent from " << __PRETTY_FUNCTION__);
+ handleResponseSent(d_currentResponse);
+ d_state = State::idle;
}
else {
- state->d_lastIOBlocked = true;
+ d_lastIOBlocked = true;
}
}
- if (state->active() &&
- !state->d_lastIOBlocked &&
- iostate == IOState::Done &&
- (state->d_state == IncomingTCPConnectionState::State::idle ||
- state->d_state == IncomingTCPConnectionState::State::waitingForQuery))
- {
+ if (active() && !d_lastIOBlocked && iostate == IOState::Done && (d_state == State::idle || d_state == State::waitingForQuery)) {
// try sending queued responses
DEBUGLOG("send responses, if any");
+ auto state = shared_from_this();
iostate = sendQueuedResponses(state, now);
- if (!state->d_lastIOBlocked && state->active() && iostate == IOState::Done) {
+ if (!d_lastIOBlocked && active() && iostate == IOState::Done) {
// if the query has been passed to a backend, or dropped, and the responses have been sent,
// we can start reading again
- if (state->canAcceptNewQueries(now)) {
- state->resetForNewQuery();
+ if (canAcceptNewQueries(now)) {
+ resetForNewQuery();
iostate = IOState::NeedRead;
}
else {
- state->d_state = IncomingTCPConnectionState::State::idle;
+ d_state = State::idle;
iostate = IOState::Done;
}
}
}
- if (state->d_state != IncomingTCPConnectionState::State::idle &&
- state->d_state != IncomingTCPConnectionState::State::doingHandshake &&
- state->d_state != IncomingTCPConnectionState::State::readingProxyProtocolHeader &&
- state->d_state != IncomingTCPConnectionState::State::waitingForQuery &&
- state->d_state != IncomingTCPConnectionState::State::readingQuerySize &&
- state->d_state != IncomingTCPConnectionState::State::readingQuery &&
- state->d_state != IncomingTCPConnectionState::State::sendingResponse) {
- vinfolog("Unexpected state %d in handleIOCallback", static_cast<int>(state->d_state));
+ if (d_state != State::idle && d_state != State::doingHandshake && d_state != State::readingProxyProtocolHeader && d_state != State::waitingForQuery && d_state != State::readingQuerySize && d_state != State::readingQuery && d_state != State::sendingResponse) {
+ vinfolog("Unexpected state %d in handleIOCallback", static_cast<int>(d_state));
}
}
- catch (const std::exception& e) {
+ catch (const std::exception& exp) {
/* most likely an EOF because the other end closed the connection,
but it might also be a real IO error or something else.
Let's just drop the connection
*/
- if (state->d_state == IncomingTCPConnectionState::State::idle ||
- state->d_state == IncomingTCPConnectionState::State::waitingForQuery) {
- /* no need to increase any counters in that case, the client is simply done with us */
- }
- else if (state->d_state == IncomingTCPConnectionState::State::doingHandshake ||
- state->d_state != IncomingTCPConnectionState::State::readingProxyProtocolHeader ||
- state->d_state == IncomingTCPConnectionState::State::waitingForQuery ||
- state->d_state == IncomingTCPConnectionState::State::readingQuerySize ||
- state->d_state == IncomingTCPConnectionState::State::readingQuery) {
- ++state->d_ci.cs->tcpDiedReadingQuery;
- }
- else if (state->d_state == IncomingTCPConnectionState::State::sendingResponse) {
- /* unlikely to happen here, the exception should be handled in sendResponse() */
- ++state->d_ci.cs->tcpDiedSendingResponse;
- }
-
- if (state->d_ioState->isWaitingForWrite() || state->d_queriesCount == 0) {
- DEBUGLOG("Got an exception while handling TCP query: "<<e.what());
- vinfolog("Got an exception while handling (%s) TCP query from %s: %s", (state->d_ioState->isWaitingForRead() ? "reading" : "writing"), state->d_ci.remote.toStringWithPort(), e.what());
- }
- else {
- vinfolog("Closing TCP client connection with %s: %s", state->d_ci.remote.toStringWithPort(), e.what());
- DEBUGLOG("Closing TCP client connection: "<<e.what());
- }
- /* remove this FD from the IO multiplexer */
- state->terminateClientConnection();
+ handleExceptionDuringIO(exp);
}
- if (!state->active()) {
+ if (!active()) {
DEBUGLOG("state is no longer active");
return;
}
+ auto state = shared_from_this();
if (iostate == IOState::Done) {
- state->d_ioState->update(iostate, handleIOCallback, state);
+ d_ioState->update(iostate, handleIOCallback, state);
}
else {
updateIO(state, iostate, now);
}
ioGuard.release();
- }
- while ((iostate == IOState::NeedRead || iostate == IOState::NeedWrite) && !state->d_lastIOBlocked);
+ } while ((iostate == IOState::NeedRead || iostate == IOState::NeedWrite) && !d_lastIOBlocked);
}
-void IncomingTCPConnectionState::notifyIOError(InternalQueryState&& query, const struct timeval& now)
+void IncomingTCPConnectionState::notifyIOError(const struct timeval& now, TCPResponse&& response)
{
if (std::this_thread::get_id() != d_creatorThreadID) {
/* empty buffer will signal an IO error */
- TCPResponse response(PacketBuffer(), std::move(query), nullptr, nullptr);
+ response.d_buffer.clear();
handleCrossProtocolResponse(now, std::move(response));
return;
}
@@ -1105,7 +1199,7 @@ void IncomingTCPConnectionState::notifyIOError(InternalQueryState&& query, const
if (state->active() && iostate != IOState::Done) {
// we need to update the state right away, nobody will do that for us
- updateIO(state, iostate, now);
+ updateIO(state, iostate, now);
}
}
catch (const std::exception& e) {
@@ -1126,14 +1220,14 @@ void IncomingTCPConnectionState::handleXFRResponse(const struct timeval& now, TC
}
std::shared_ptr<IncomingTCPConnectionState> state = shared_from_this();
- queueResponse(state, now, std::move(response));
+ queueResponse(state, now, std::move(response), true);
}
void IncomingTCPConnectionState::handleTimeout(std::shared_ptr<IncomingTCPConnectionState>& state, bool write)
{
vinfolog("Timeout while %s TCP client %s", (write ? "writing to" : "reading from"), state->d_ci.remote.toStringWithPort());
DEBUGLOG("client timeout");
- DEBUGLOG("Processed "<<state->d_queriesCount<<" queries, current count is "<<state->d_currentQueriesCount<<", "<<state->d_ownedConnectionsToBackend.size()<<" owned connections, "<<state->d_queuedResponses.size()<<" response queued");
+ DEBUGLOG("Processed " << state->d_queriesCount << " queries, current count is " << state->d_currentQueriesCount << ", " << state->d_ownedConnectionsToBackend.size() << " owned connections, " << state->d_queuedResponses.size() << " response queued");
if (write || state->d_currentQueriesCount == 0) {
++state->d_ci.cs->tcpClientTimeouts;
@@ -1142,124 +1236,102 @@ void IncomingTCPConnectionState::handleTimeout(std::shared_ptr<IncomingTCPConnec
else {
DEBUGLOG("Going idle");
/* we still have some queries in flight, let's just stop reading for now */
- state->d_state = IncomingTCPConnectionState::State::idle;
+ state->d_state = State::idle;
state->d_ioState->update(IOState::Done, handleIOCallback, state);
}
}
static void handleIncomingTCPQuery(int pipefd, FDMultiplexer::funcparam_t& param)
{
- auto threadData = boost::any_cast<TCPClientThreadData*>(param);
+ auto* threadData = boost::any_cast<TCPClientThreadData*>(param);
- ConnectionInfo* citmp{nullptr};
-
- ssize_t got = read(pipefd, &citmp, sizeof(citmp));
- if (got == 0) {
- throw std::runtime_error("EOF while reading from the TCP acceptor pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
- }
- else if (got == -1) {
- if (errno == EAGAIN || errno == EINTR) {
+ std::unique_ptr<ConnectionInfo> citmp{nullptr};
+ try {
+ auto tmp = threadData->queryReceiver.receive();
+ if (!tmp) {
return;
}
- throw std::runtime_error("Error while reading from the TCP acceptor pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode:" + stringerror());
+ citmp = std::move(*tmp);
}
- else if (got != sizeof(citmp)) {
- throw std::runtime_error("Partial read while reading from the TCP acceptor pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error while reading from the TCP query channel: " + std::string(e.what()));
}
- try {
- g_tcpclientthreads->decrementQueuedCount();
+ g_tcpclientthreads->decrementQueuedCount();
- struct timeval now;
- gettimeofday(&now, nullptr);
- auto state = std::make_shared<IncomingTCPConnectionState>(std::move(*citmp), *threadData, now);
- delete citmp;
- citmp = nullptr;
+ timeval now{};
+ gettimeofday(&now, nullptr);
- IncomingTCPConnectionState::handleIO(state, now);
+ if (citmp->cs->dohFrontend) {
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ auto state = std::make_shared<IncomingHTTP2Connection>(std::move(*citmp), *threadData, now);
+ state->handleIO();
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
}
- catch (...) {
- delete citmp;
- citmp = nullptr;
- throw;
+ else {
+ auto state = std::make_shared<IncomingTCPConnectionState>(std::move(*citmp), *threadData, now);
+ state->handleIO();
}
}
static void handleCrossProtocolQuery(int pipefd, FDMultiplexer::funcparam_t& param)
{
- auto threadData = boost::any_cast<TCPClientThreadData*>(param);
- CrossProtocolQuery* tmp{nullptr};
+ auto* threadData = boost::any_cast<TCPClientThreadData*>(param);
- ssize_t got = read(pipefd, &tmp, sizeof(tmp));
- if (got == 0) {
- throw std::runtime_error("EOF while reading from the TCP cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
- }
- else if (got == -1) {
- if (errno == EAGAIN || errno == EINTR) {
+ std::unique_ptr<CrossProtocolQuery> cpq{nullptr};
+ try {
+ auto tmp = threadData->crossProtocolQueryReceiver.receive();
+ if (!tmp) {
return;
}
- throw std::runtime_error("Error while reading from the TCP cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode:" + stringerror());
+ cpq = std::move(*tmp);
}
- else if (got != sizeof(tmp)) {
- throw std::runtime_error("Partial read while reading from the TCP cross-protocol pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error while reading from the TCP cross-protocol channel: " + std::string(e.what()));
}
- try {
- struct timeval now;
- gettimeofday(&now, nullptr);
+ timeval now{};
+ gettimeofday(&now, nullptr);
- std::shared_ptr<TCPQuerySender> tqs = tmp->getTCPQuerySender();
- auto query = std::move(tmp->query);
- auto downstreamServer = std::move(tmp->downstream);
- auto proxyProtocolPayloadSize = tmp->proxyProtocolPayloadSize;
- delete tmp;
- tmp = nullptr;
+ std::shared_ptr<TCPQuerySender> tqs = cpq->getTCPQuerySender();
+ auto query = std::move(cpq->query);
+ auto downstreamServer = std::move(cpq->downstream);
- try {
- auto downstream = t_downstreamTCPConnectionsManager.getConnectionToDownstream(threadData->mplexer, downstreamServer, now, std::string());
+ try {
+ auto downstream = t_downstreamTCPConnectionsManager.getConnectionToDownstream(threadData->mplexer, downstreamServer, now, std::string());
- prependSizeToTCPQuery(query.d_buffer, proxyProtocolPayloadSize);
- query.d_proxyProtocolPayloadAddedSize = proxyProtocolPayloadSize;
+ prependSizeToTCPQuery(query.d_buffer, query.d_idstate.d_proxyProtocolPayloadSize);
- vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", query.d_idstate.qname.toLogString(), QType(query.d_idstate.qtype).toString(), query.d_idstate.origRemote.toStringWithPort(), query.d_idstate.protocol.toString(), query.d_buffer.size(), downstreamServer->getNameWithAddr());
+ vinfolog("Got query for %s|%s from %s (%s, %d bytes), relayed to %s", query.d_idstate.qname.toLogString(), QType(query.d_idstate.qtype).toString(), query.d_idstate.origRemote.toStringWithPort(), query.d_idstate.protocol.toString(), query.d_buffer.size(), downstreamServer->getNameWithAddr());
- downstream->queueQuery(tqs, std::move(query));
- }
- catch (...) {
- tqs->notifyIOError(std::move(query.d_idstate), now);
- }
+ downstream->queueQuery(tqs, std::move(query));
}
catch (...) {
- delete tmp;
- tmp = nullptr;
+ tqs->notifyIOError(now, std::move(query));
}
}
static void handleCrossProtocolResponse(int pipefd, FDMultiplexer::funcparam_t& param)
{
- TCPCrossProtocolResponse* tmp{nullptr};
+ auto* threadData = boost::any_cast<TCPClientThreadData*>(param);
- ssize_t got = read(pipefd, &tmp, sizeof(tmp));
- if (got == 0) {
- throw std::runtime_error("EOF while reading from the TCP cross-protocol response pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
- }
- else if (got == -1) {
- if (errno == EAGAIN || errno == EINTR) {
+ std::unique_ptr<TCPCrossProtocolResponse> cpr{nullptr};
+ try {
+ auto tmp = threadData->crossProtocolResponseReceiver.receive();
+ if (!tmp) {
return;
}
- throw std::runtime_error("Error while reading from the TCP cross-protocol response pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode:" + stringerror());
+ cpr = std::move(*tmp);
}
- else if (got != sizeof(tmp)) {
- throw std::runtime_error("Partial read while reading from the TCP cross-protocol response pipe (" + std::to_string(pipefd) + ") in " + std::string(isNonBlocking(pipefd) ? "non-blocking" : "blocking") + " mode");
+ catch (const std::exception& e) {
+ throw std::runtime_error("Error while reading from the TCP cross-protocol response: " + std::string(e.what()));
}
- auto response = std::move(*tmp);
- delete tmp;
- tmp = nullptr;
+ auto& response = *cpr;
try {
if (response.d_response.d_buffer.empty()) {
- response.d_state->notifyIOError(std::move(response.d_response.d_idstate), response.d_now);
+ response.d_state->notifyIOError(response.d_now, std::move(response.d_response));
}
else if (response.d_response.d_idstate.qtype == QType::AXFR || response.d_response.d_idstate.qtype == QType::IXFR) {
response.d_state->handleXFRResponse(response.d_now, std::move(response.d_response));
@@ -1275,15 +1347,114 @@ static void handleCrossProtocolResponse(int pipefd, FDMultiplexer::funcparam_t&
struct TCPAcceptorParam
{
- ClientState& cs;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
+ ClientState& clientState;
ComboAddress local;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
LocalStateHolder<NetmaskGroup>& acl;
int socket{-1};
};
static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadData* threadData);
-static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int crossProtocolResponsesListenPipeFD, int crossProtocolResponsesWritePipeFD, std::vector<ClientState*> tcpAcceptStates)
+static void scanForTimeouts(const TCPClientThreadData& data, const timeval& now)
+{
+ auto expiredReadConns = data.mplexer->getTimeouts(now, false);
+ for (const auto& cbData : expiredReadConns) {
+ if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
+ if (cbData.first == state->d_handler.getDescriptor()) {
+ vinfolog("Timeout (read) from remote TCP client %s", state->d_ci.remote.toStringWithPort());
+ state->handleTimeout(state, false);
+ }
+ }
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ else if (cbData.second.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(cbData.second);
+ if (cbData.first == state->d_handler.getDescriptor()) {
+ vinfolog("Timeout (read) from remote H2 client %s", state->d_ci.remote.toStringWithPort());
+ std::shared_ptr<IncomingTCPConnectionState> parentState = state;
+ state->handleTimeout(parentState, false);
+ }
+ }
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
+ auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
+ vinfolog("Timeout (read) from remote backend %s", conn->getBackendName());
+ conn->handleTimeout(now, false);
+ }
+ }
+
+ auto expiredWriteConns = data.mplexer->getTimeouts(now, true);
+ for (const auto& cbData : expiredWriteConns) {
+ if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
+ if (cbData.first == state->d_handler.getDescriptor()) {
+ vinfolog("Timeout (write) from remote TCP client %s", state->d_ci.remote.toStringWithPort());
+ state->handleTimeout(state, true);
+ }
+ }
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ else if (cbData.second.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(cbData.second);
+ if (cbData.first == state->d_handler.getDescriptor()) {
+ vinfolog("Timeout (write) from remote H2 client %s", state->d_ci.remote.toStringWithPort());
+ std::shared_ptr<IncomingTCPConnectionState> parentState = state;
+ state->handleTimeout(parentState, true);
+ }
+ }
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
+ auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
+ vinfolog("Timeout (write) from remote backend %s", conn->getBackendName());
+ conn->handleTimeout(now, true);
+ }
+ }
+}
+
+static void dumpTCPStates(const TCPClientThreadData& data)
+{
+ /* just to keep things clean in the output, debug only */
+ static std::mutex s_lock;
+ std::lock_guard<decltype(s_lock)> lck(s_lock);
+ if (g_tcpStatesDumpRequested > 0) {
+ /* no race here, we took the lock so it can only be increased in the meantime */
+ --g_tcpStatesDumpRequested;
+ infolog("Dumping the TCP states, as requested:");
+ data.mplexer->runForAllWatchedFDs([](bool isRead, int desc, const FDMultiplexer::funcparam_t& param, struct timeval ttd) {
+ timeval lnow{};
+ gettimeofday(&lnow, nullptr);
+ if (ttd.tv_sec > 0) {
+ infolog("- Descriptor %d is in %s state, TTD in %d", desc, (isRead ? "read" : "write"), (ttd.tv_sec - lnow.tv_sec));
+ }
+ else {
+ infolog("- Descriptor %d is in %s state, no TTD set", desc, (isRead ? "read" : "write"));
+ }
+
+ if (param.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(param);
+ infolog(" - %s", state->toString());
+ }
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ else if (param.type() == typeid(std::shared_ptr<IncomingHTTP2Connection>)) {
+ auto state = boost::any_cast<std::shared_ptr<IncomingHTTP2Connection>>(param);
+ infolog(" - %s", state->toString());
+ }
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ else if (param.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
+ auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(param);
+ infolog(" - %s", conn->toString());
+ }
+ else if (param.type() == typeid(TCPClientThreadData*)) {
+ infolog(" - Worker thread pipe");
+ }
+ });
+ infolog("The TCP/DoT client cache has %d active and %d idle outgoing connections cached", t_downstreamTCPConnectionsManager.getActiveCount(), t_downstreamTCPConnectionsManager.getIdleCount());
+ }
+}
+
+// NOLINTNEXTLINE(performance-unnecessary-value-param): you are wrong, clang-tidy, go home
+static void tcpClientThread(pdns::channel::Receiver<ConnectionInfo>&& queryReceiver, pdns::channel::Receiver<CrossProtocolQuery>&& crossProtocolQueryReceiver, pdns::channel::Receiver<TCPCrossProtocolResponse>&& crossProtocolResponseReceiver, pdns::channel::Sender<TCPCrossProtocolResponse>&& crossProtocolResponseSender, std::vector<ClientState*> tcpAcceptStates)
{
/* we get launched with a pipe on which we receive file descriptors from clients that we own
from that point on */
@@ -1292,11 +1463,14 @@ static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int cros
try {
TCPClientThreadData data;
- /* this is the writing end! */
- data.crossProtocolResponsesPipe = crossProtocolResponsesWritePipeFD;
- data.mplexer->addReadFD(pipefd, handleIncomingTCPQuery, &data);
- data.mplexer->addReadFD(crossProtocolQueriesPipeFD, handleCrossProtocolQuery, &data);
- data.mplexer->addReadFD(crossProtocolResponsesListenPipeFD, handleCrossProtocolResponse, &data);
+ data.crossProtocolResponseSender = std::move(crossProtocolResponseSender);
+ data.queryReceiver = std::move(queryReceiver);
+ data.crossProtocolQueryReceiver = std::move(crossProtocolQueryReceiver);
+ data.crossProtocolResponseReceiver = std::move(crossProtocolResponseReceiver);
+
+ data.mplexer->addReadFD(data.queryReceiver.getDescriptor(), handleIncomingTCPQuery, &data);
+ data.mplexer->addReadFD(data.crossProtocolQueryReceiver.getDescriptor(), handleCrossProtocolQuery, &data);
+ data.mplexer->addReadFD(data.crossProtocolResponseReceiver.getDescriptor(), handleCrossProtocolResponse, &data);
/* only used in single acceptor mode for now */
auto acl = g_ACL.getLocal();
@@ -1311,17 +1485,16 @@ static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int cros
}
auto acceptCallback = [&data](int socket, FDMultiplexer::funcparam_t& funcparam) {
- auto acceptorParam = boost::any_cast<const TCPAcceptorParam*>(funcparam);
+ const auto* acceptorParam = boost::any_cast<const TCPAcceptorParam*>(funcparam);
acceptNewConnection(*acceptorParam, &data);
};
- for (size_t idx = 0; idx < acceptParams.size(); idx++) {
- const auto& param = acceptParams.at(idx);
+ for (const auto& param : acceptParams) {
setNonBlocking(param.socket);
data.mplexer->addReadFD(param.socket, acceptCallback, &param);
}
- struct timeval now;
+ timeval now{};
gettimeofday(&now, nullptr);
time_t lastTimeoutScan = now.tv_sec;
@@ -1333,76 +1506,15 @@ static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int cros
if (now.tv_sec > lastTimeoutScan) {
lastTimeoutScan = now.tv_sec;
- auto expiredReadConns = data.mplexer->getTimeouts(now, false);
- for (const auto& cbData : expiredReadConns) {
- if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
- auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
- if (cbData.first == state->d_handler.getDescriptor()) {
- vinfolog("Timeout (read) from remote TCP client %s", state->d_ci.remote.toStringWithPort());
- state->handleTimeout(state, false);
- }
- }
- else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
- auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
- vinfolog("Timeout (read) from remote backend %s", conn->getBackendName());
- conn->handleTimeout(now, false);
- }
- }
-
- auto expiredWriteConns = data.mplexer->getTimeouts(now, true);
- for (const auto& cbData : expiredWriteConns) {
- if (cbData.second.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
- auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(cbData.second);
- if (cbData.first == state->d_handler.getDescriptor()) {
- vinfolog("Timeout (write) from remote TCP client %s", state->d_ci.remote.toStringWithPort());
- state->handleTimeout(state, true);
- }
- }
- else if (cbData.second.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
- auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(cbData.second);
- vinfolog("Timeout (write) from remote backend %s", conn->getBackendName());
- conn->handleTimeout(now, true);
- }
- }
+ scanForTimeouts(data, now);
if (g_tcpStatesDumpRequested > 0) {
- /* just to keep things clean in the output, debug only */
- static std::mutex s_lock;
- std::lock_guard<decltype(s_lock)> lck(s_lock);
- if (g_tcpStatesDumpRequested > 0) {
- /* no race here, we took the lock so it can only be increased in the meantime */
- --g_tcpStatesDumpRequested;
- errlog("Dumping the TCP states, as requested:");
- data.mplexer->runForAllWatchedFDs([](bool isRead, int fd, const FDMultiplexer::funcparam_t& param, struct timeval ttd)
- {
- struct timeval lnow;
- gettimeofday(&lnow, nullptr);
- if (ttd.tv_sec > 0) {
- errlog("- Descriptor %d is in %s state, TTD in %d", fd, (isRead ? "read" : "write"), (ttd.tv_sec-lnow.tv_sec));
- }
- else {
- errlog("- Descriptor %d is in %s state, no TTD set", fd, (isRead ? "read" : "write"));
- }
-
- if (param.type() == typeid(std::shared_ptr<IncomingTCPConnectionState>)) {
- auto state = boost::any_cast<std::shared_ptr<IncomingTCPConnectionState>>(param);
- errlog(" - %s", state->toString());
- }
- else if (param.type() == typeid(std::shared_ptr<TCPConnectionToBackend>)) {
- auto conn = boost::any_cast<std::shared_ptr<TCPConnectionToBackend>>(param);
- errlog(" - %s", conn->toString());
- }
- else if (param.type() == typeid(TCPClientThreadData*)) {
- errlog(" - Worker thread pipe");
- }
- });
- errlog("The TCP/DoT client cache has %d active and %d idle outgoing connections cached", t_downstreamTCPConnectionsManager.getActiveCount(), t_downstreamTCPConnectionsManager.getIdleCount());
- }
+ dumpTCPStates(data);
}
}
}
catch (const std::exception& e) {
- errlog("Error in TCP worker thread: %s", e.what());
+ warnlog("Error in TCP worker thread: %s", e.what());
}
}
}
@@ -1413,9 +1525,10 @@ static void tcpClientThread(int pipefd, int crossProtocolQueriesPipeFD, int cros
static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadData* threadData)
{
- auto& cs = param.cs;
+ auto& clientState = param.clientState;
auto& acl = param.acl;
- int socket = param.socket;
+ const bool checkACL = clientState.dohFrontend == nullptr || (!clientState.dohFrontend->d_trustForwardedForHeader && clientState.dohFrontend->d_earlyACLDrop);
+ const int socket = param.socket;
bool tcpClientCountIncremented = false;
ComboAddress remote;
remote.sin4.sin_family = param.local.sin4.sin_family;
@@ -1423,41 +1536,43 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
tcpClientCountIncremented = false;
try {
socklen_t remlen = remote.getSocklen();
- ConnectionInfo ci(&cs);
+ ConnectionInfo connInfo(&clientState);
#ifdef HAVE_ACCEPT4
- ci.fd = accept4(socket, reinterpret_cast<struct sockaddr*>(&remote), &remlen, SOCK_NONBLOCK);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ connInfo.fd = accept4(socket, reinterpret_cast<struct sockaddr*>(&remote), &remlen, SOCK_NONBLOCK);
#else
- ci.fd = accept(socket, reinterpret_cast<struct sockaddr*>(&remote), &remlen);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ connInfo.fd = accept(socket, reinterpret_cast<struct sockaddr*>(&remote), &remlen);
#endif
// will be decremented when the ConnectionInfo object is destroyed, no matter the reason
- auto concurrentConnections = ++cs.tcpCurrentConnections;
+ auto concurrentConnections = ++clientState.tcpCurrentConnections;
- if (ci.fd < 0) {
+ if (connInfo.fd < 0) {
throw std::runtime_error((boost::format("accepting new connection on socket: %s") % stringerror()).str());
}
- if (!acl->match(remote)) {
- ++g_stats.aclDrops;
+ if (checkACL && !acl->match(remote)) {
+ ++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Dropped TCP connection from %s because of ACL", remote.toStringWithPort());
return;
}
- if (cs.d_tcpConcurrentConnectionsLimit > 0 && concurrentConnections > cs.d_tcpConcurrentConnectionsLimit) {
+ if (clientState.d_tcpConcurrentConnectionsLimit > 0 && concurrentConnections > clientState.d_tcpConcurrentConnectionsLimit) {
vinfolog("Dropped TCP connection from %s because of concurrent connections limit", remote.toStringWithPort());
return;
}
- if (concurrentConnections > cs.tcpMaxConcurrentConnections.load()) {
- cs.tcpMaxConcurrentConnections.store(concurrentConnections);
+ if (concurrentConnections > clientState.tcpMaxConcurrentConnections.load()) {
+ clientState.tcpMaxConcurrentConnections.store(concurrentConnections);
}
#ifndef HAVE_ACCEPT4
- if (!setNonBlocking(ci.fd)) {
+ if (!setNonBlocking(connInfo.fd)) {
return;
}
#endif
- setTCPNoDelay(ci.fd); // disable NAGLE
+ setTCPNoDelay(connInfo.fd); // disable NAGLE
if (g_maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= g_maxTCPQueuedConnections) {
vinfolog("Dropping TCP connection from %s because we have too many queued already", remote.toStringWithPort());
@@ -1472,19 +1587,29 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
vinfolog("Got TCP connection from %s", remote.toStringWithPort());
- ci.remote = remote;
+ connInfo.remote = remote;
+
if (threadData == nullptr) {
- if (!g_tcpclientthreads->passConnectionToThread(std::make_unique<ConnectionInfo>(std::move(ci)))) {
+ if (!g_tcpclientthreads->passConnectionToThread(std::make_unique<ConnectionInfo>(std::move(connInfo)))) {
if (tcpClientCountIncremented) {
dnsdist::IncomingConcurrentTCPConnectionsManager::accountClosedTCPConnection(remote);
}
}
}
else {
- struct timeval now;
+ timeval now{};
gettimeofday(&now, nullptr);
- auto state = std::make_shared<IncomingTCPConnectionState>(std::move(ci), *threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+
+ if (connInfo.cs->dohFrontend) {
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+ auto state = std::make_shared<IncomingHTTP2Connection>(std::move(connInfo), *threadData, now);
+ state->handleIO();
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
+ }
+ else {
+ auto state = std::make_shared<IncomingTCPConnectionState>(std::move(connInfo), *threadData, now);
+ state->handleIO();
+ }
}
}
catch (const std::exception& e) {
@@ -1493,14 +1618,15 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
dnsdist::IncomingConcurrentTCPConnectionsManager::accountClosedTCPConnection(remote);
}
}
- catch (...){}
+ catch (...) {
+ }
}
/* spawn as many of these as required, they call Accept on a socket on which they will accept queries, and
they will hand off to worker threads & spawn more of them if required
*/
#ifndef USE_SINGLE_ACCEPTOR_THREAD
-void tcpAcceptorThread(std::vector<ClientState*> states)
+void tcpAcceptorThread(const std::vector<ClientState*>& states)
{
setThreadName("dnsdist/tcpAcce");
@@ -1508,7 +1634,7 @@ void tcpAcceptorThread(std::vector<ClientState*> states)
std::vector<TCPAcceptorParam> params;
params.reserve(states.size());
- for (auto& state : states) {
+ for (const auto& state : states) {
params.emplace_back(TCPAcceptorParam{*state, state->local, acl, state->tcpFD});
for (const auto& [addr, socket] : state->d_additionalAddresses) {
params.emplace_back(TCPAcceptorParam{*state, addr, acl, socket});
@@ -1522,19 +1648,18 @@ void tcpAcceptorThread(std::vector<ClientState*> states)
}
else {
auto acceptCallback = [](int socket, FDMultiplexer::funcparam_t& funcparam) {
- auto acceptorParam = boost::any_cast<const TCPAcceptorParam*>(funcparam);
+ const auto* acceptorParam = boost::any_cast<const TCPAcceptorParam*>(funcparam);
acceptNewConnection(*acceptorParam, nullptr);
};
auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(params.size()));
- for (size_t idx = 0; idx < params.size(); idx++) {
- const auto& param = params.at(idx);
+ for (const auto& param : params) {
mplexer->addReadFD(param.socket, acceptCallback, &param);
}
- struct timeval tv;
+ timeval now{};
while (true) {
- mplexer->run(&tv, -1);
+ mplexer->run(&now, -1);
}
}
}
diff --git a/dnsdist-tcp.hh b/dnsdist-tcp.hh
index 3d11f1a..f3d827e 100644
--- a/dnsdist-tcp.hh
+++ b/dnsdist-tcp.hh
@@ -21,9 +21,12 @@
*/
#pragma once
+#include <optional>
#include <unistd.h>
+#include "channel.hh"
#include "iputils.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
struct ConnectionInfo
{
@@ -98,12 +101,11 @@ public:
InternalQueryState d_idstate;
std::string d_proxyProtocolPayload;
PacketBuffer d_buffer;
- uint32_t d_proxyProtocolPayloadAddedSize{0};
uint32_t d_ixfrQuerySerial{0};
- uint32_t d_xfrMasterSerial{0};
+ uint32_t d_xfrPrimarySerial{0};
uint32_t d_xfrSerialCount{0};
uint32_t d_downstreamFailures{0};
- uint8_t d_xfrMasterSerialCount{0};
+ uint8_t d_xfrPrimarySerialCount{0};
bool d_xfrStarted{false};
bool d_proxyProtocolPayloadAdded{false};
};
@@ -121,10 +123,23 @@ struct TCPResponse : public TCPQuery
}
TCPResponse(PacketBuffer&& buffer, InternalQueryState&& state, std::shared_ptr<ConnectionToBackend> conn, std::shared_ptr<DownstreamState> ds) :
- TCPQuery(std::move(buffer), std::move(state)), d_connection(conn), d_ds(ds)
+ TCPQuery(std::move(buffer), std::move(state)), d_connection(std::move(conn)), d_ds(std::move(ds))
{
if (d_buffer.size() >= sizeof(dnsheader)) {
- memcpy(&d_cleartextDH, reinterpret_cast<const dnsheader*>(d_buffer.data()), sizeof(d_cleartextDH));
+ dnsheader_aligned header(d_buffer.data());
+ memcpy(&d_cleartextDH, header.get(), sizeof(d_cleartextDH));
+ }
+ else {
+ memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
+ }
+ }
+
+ TCPResponse(TCPQuery&& query) :
+ TCPQuery(std::move(query))
+ {
+ if (d_buffer.size() >= sizeof(dnsheader)) {
+ dnsheader_aligned header(d_buffer.data());
+ memcpy(&d_cleartextDH, header.get(), sizeof(d_cleartextDH));
}
else {
memset(&d_cleartextDH, 0, sizeof(d_cleartextDH));
@@ -152,7 +167,7 @@ public:
virtual bool active() const = 0;
virtual void handleResponse(const struct timeval& now, TCPResponse&& response) = 0;
virtual void handleXFRResponse(const struct timeval& now, TCPResponse&& response) = 0;
- virtual void notifyIOError(InternalQueryState&& query, const struct timeval& now) = 0;
+ virtual void notifyIOError(const struct timeval& now, TCPResponse&& response) = 0;
/* whether the connection should be automatically released to the pool after handleResponse()
has been called */
@@ -197,14 +212,13 @@ struct CrossProtocolQuery
InternalQuery query;
std::shared_ptr<DownstreamState> downstream{nullptr};
- size_t proxyProtocolPayloadSize{0};
bool d_isResponse{false};
};
class TCPClientCollection
{
public:
- TCPClientCollection(size_t maxThreads, std::vector<ClientState*> tcpStates);
+ TCPClientCollection(size_t maxThreads, std::vector<ClientState*> tcpAcceptStates);
bool passConnectionToThread(std::unique_ptr<ConnectionInfo>&& conn)
{
@@ -213,20 +227,16 @@ public:
}
uint64_t pos = d_pos++;
- auto pipe = d_tcpclientthreads.at(pos % d_numthreads).d_newConnectionPipe.getHandle();
- auto tmp = conn.release();
-
/* we need to increment this counter _before_ writing to the pipe,
otherwise there is a very real possiblity that the other end
decrement the counter before we can increment it, leading to an underflow */
++d_queued;
- if (write(pipe, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ if (!d_tcpclientthreads.at(pos % d_numthreads).d_querySender.send(std::move(conn))) {
--d_queued;
- ++g_stats.tcpQueryPipeFull;
- delete tmp;
- tmp = nullptr;
+ ++dnsdist::metrics::g_stats.tcpQueryPipeFull;
return false;
}
+
return true;
}
@@ -237,13 +247,8 @@ public:
}
uint64_t pos = d_pos++;
- auto pipe = d_tcpclientthreads.at(pos % d_numthreads).d_crossProtocolQueriesPipe.getHandle();
- auto tmp = cpq.release();
-
- if (write(pipe, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- ++g_stats.tcpCrossProtocolQueryPipeFull;
- delete tmp;
- tmp = nullptr;
+ if (!d_tcpclientthreads.at(pos % d_numthreads).d_crossProtocolQuerySender.send(std::move(cpq))) {
+ ++dnsdist::metrics::g_stats.tcpCrossProtocolQueryPipeFull;
return false;
}
@@ -279,8 +284,8 @@ private:
{
}
- TCPWorkerThread(int newConnPipe, int crossProtocolQueriesPipe, int crossProtocolResponsesPipe) :
- d_newConnectionPipe(newConnPipe), d_crossProtocolQueriesPipe(crossProtocolQueriesPipe), d_crossProtocolResponsesPipe(crossProtocolResponsesPipe)
+ TCPWorkerThread(pdns::channel::Sender<ConnectionInfo>&& querySender, pdns::channel::Sender<CrossProtocolQuery>&& crossProtocolQuerySender) :
+ d_querySender(std::move(querySender)), d_crossProtocolQuerySender(std::move(crossProtocolQuerySender))
{
}
@@ -289,9 +294,8 @@ private:
TCPWorkerThread(const TCPWorkerThread& rhs) = delete;
TCPWorkerThread& operator=(const TCPWorkerThread&) = delete;
- FDWrapper d_newConnectionPipe;
- FDWrapper d_crossProtocolQueriesPipe;
- FDWrapper d_crossProtocolResponsesPipe;
+ pdns::channel::Sender<ConnectionInfo> d_querySender;
+ pdns::channel::Sender<CrossProtocolQuery> d_crossProtocolQuerySender;
};
std::vector<TCPWorkerThread> d_tcpclientthreads;
@@ -303,4 +307,4 @@ private:
extern std::unique_ptr<TCPClientCollection> g_tcpclientthreads;
-std::unique_ptr<CrossProtocolQuery> getTCPCrossProtocolQueryFromDQ(DNSQuestion& dq);
+std::unique_ptr<CrossProtocolQuery> getTCPCrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion);
diff --git a/dnsdist-web.cc b/dnsdist-web.cc
index 16e1164..066b5c1 100644
--- a/dnsdist-web.cc
+++ b/dnsdist-web.cc
@@ -34,7 +34,9 @@
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-healthchecks.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-prometheus.hh"
+#include "dnsdist-rings.hh"
#include "dnsdist-web.hh"
#include "dolog.hh"
#include "gettime.hh"
@@ -175,6 +177,10 @@ std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{
{ "latency-doh-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoH")},
{ "latency-doh-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoH")},
{ "latency-doh-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoH")},
+ { "latency-doq-avg100", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 100 packets received over DoQ")},
+ { "latency-doq-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoQ")},
+ { "latency-doq-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoQ")},
+ { "latency-doq-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoQ")},
{ "uptime", MetricDefinition(PrometheusMetricType::gauge, "Uptime of the dnsdist process in seconds")},
{ "real-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Current memory usage in bytes")},
{ "noncompliant-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped as non-compliant")},
@@ -212,9 +218,9 @@ std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{
};
#endif /* DISABLE_PROMETHEUS */
-bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customName) {
+bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def) {
#ifndef DISABLE_PROMETHEUS
- return MetricDefinitionStorage::addMetricDefinition(name, type, description, customName);
+ return MetricDefinitionStorage::addMetricDefinition(def);
#else
return true;
#endif /* DISABLE_PROMETHEUS */
@@ -224,7 +230,7 @@ bool addMetricDefinition(const std::string& name, const std::string& type, const
static bool apiWriteConfigFile(const string& filebasename, const string& content)
{
if (!g_apiReadWrite) {
- errlog("Not writing content to %s since the API is read-only", filebasename);
+ warnlog("Not writing content to %s since the API is read-only", filebasename);
return false;
}
@@ -247,15 +253,14 @@ static bool apiWriteConfigFile(const string& filebasename, const string& content
static void apiSaveACL(const NetmaskGroup& nmg)
{
- vector<string> vec;
- nmg.toStringVector(&vec);
+ auto aclEntries = nmg.toStringVector();
string acl;
- for(const auto& s : vec) {
+ for (const auto& entry : aclEntries) {
if (!acl.empty()) {
acl += ", ";
}
- acl += "\"" + s + "\"";
+ acl += "\"" + entry + "\"";
}
string content = "setACL({" + acl + "})";
@@ -468,7 +473,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
std::ostringstream output;
static const std::set<std::string> metricBlacklist = { "special-memory-usage", "latency-count", "latency-sum" };
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
const auto& metricName = entry.d_name;
@@ -504,16 +509,16 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
output << prometheusMetricName << " ";
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
output << (*val)->load();
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
output << (*adval)->load();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
output << **dval;
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
output << (*func)(entry.d_name);
}
@@ -524,20 +529,20 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
// Latency histogram buckets
output << "# HELP dnsdist_latency Histogram of responses by latency (in milliseconds)\n";
output << "# TYPE dnsdist_latency histogram\n";
- uint64_t latency_amounts = g_stats.latency0_1;
+ uint64_t latency_amounts = dnsdist::metrics::g_stats.latency0_1;
output << "dnsdist_latency_bucket{le=\"1\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency1_10;
+ latency_amounts += dnsdist::metrics::g_stats.latency1_10;
output << "dnsdist_latency_bucket{le=\"10\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency10_50;
+ latency_amounts += dnsdist::metrics::g_stats.latency10_50;
output << "dnsdist_latency_bucket{le=\"50\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency50_100;
+ latency_amounts += dnsdist::metrics::g_stats.latency50_100;
output << "dnsdist_latency_bucket{le=\"100\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency100_1000;
+ latency_amounts += dnsdist::metrics::g_stats.latency100_1000;
output << "dnsdist_latency_bucket{le=\"1000\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latencySlow; // Should be the same as latency_count
+ latency_amounts += dnsdist::metrics::g_stats.latencySlow; // Should be the same as latency_count
output << "dnsdist_latency_bucket{le=\"+Inf\"} " << latency_amounts << "\n";
- output << "dnsdist_latency_sum " << g_stats.latencySum << "\n";
- output << "dnsdist_latency_count " << g_stats.latencyCount << "\n";
+ output << "dnsdist_latency_sum " << dnsdist::metrics::g_stats.latencySum << "\n";
+ output << "dnsdist_latency_count " << dnsdist::metrics::g_stats.latencyCount << "\n";
auto states = g_dstates.getLocal();
const string statesbase = "dnsdist_server_";
@@ -592,6 +597,18 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << "# TYPE " << statesbase << "tlsresumptions " << "counter" << "\n";
output << "# HELP " << statesbase << "tcplatency " << "Server's latency when answering TCP questions in milliseconds" << "\n";
output << "# TYPE " << statesbase << "tcplatency " << "gauge" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailures " << "Number of health check attempts that failed (total)" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailures " << "counter" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailuresparsing " << "Number of health check attempts where the response could not be parsed" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailuresparsing " << "counter" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailurestimeout " << "Number of health check attempts where the response did not arrive in time" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailurestimeout " << "counter" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailuresnetwork " << "Number of health check attempts that experienced a network issue" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailuresnetwork " << "counter" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailuresmismatch " << "Number of health check attempts where the response did not match the query" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailuresmismatch " << "counter" << "\n";
+ output << "# HELP " << statesbase << "healthcheckfailuresinvalid " << "Number of health check attempts where the DNS response was invalid" << "\n";
+ output << "# TYPE " << statesbase << "healthcheckfailuresinvalid " << "counter" << "\n";
for (const auto& state : *states) {
string serverName;
@@ -635,6 +652,12 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << statesbase << "tcpavgqueriesperconn" << label << " " << state->tcpAvgQueriesPerConnection << "\n";
output << statesbase << "tcpavgconnduration" << label << " " << state->tcpAvgConnectionDuration << "\n";
output << statesbase << "tlsresumptions" << label << " " << state->tlsResumptions << "\n";
+ output << statesbase << "healthcheckfailures" << label << " " << state->d_healthCheckMetrics.d_failures << "\n";
+ output << statesbase << "healthcheckfailuresparsing" << label << " " << state->d_healthCheckMetrics.d_parseErrors << "\n";
+ output << statesbase << "healthcheckfailurestimeout" << label << " " << state->d_healthCheckMetrics.d_timeOuts << "\n";
+ output << statesbase << "healthcheckfailuresnetwork" << label << " " << state->d_healthCheckMetrics.d_networkErrors << "\n";
+ output << statesbase << "healthcheckfailuresmismatch" << label << " " << state->d_healthCheckMetrics.d_mismatchErrors << "\n";
+ output << statesbase << "healthcheckfailuresinvalid" << label << " " << state->d_healthCheckMetrics.d_invalidResponseErrors << "\n";
}
const string frontsbase = "dnsdist_frontend_";
@@ -650,8 +673,8 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << "# TYPE " << frontsbase << "tcpdiedsendingresponse " << "counter" << "\n";
output << "# HELP " << frontsbase << "tcpgaveup " << "Amount of TCP connections terminated after too many attempts to get a connection to the backend" << "\n";
output << "# TYPE " << frontsbase << "tcpgaveup " << "counter" << "\n";
- output << "# HELP " << frontsbase << "tcpclientimeouts " << "Amount of TCP connections terminated by a timeout while reading from the client" << "\n";
- output << "# TYPE " << frontsbase << "tcpclientimeouts " << "counter" << "\n";
+ output << "# HELP " << frontsbase << "tcpclienttimeouts " << "Amount of TCP connections terminated by a timeout while reading from the client" << "\n";
+ output << "# TYPE " << frontsbase << "tcpclienttimeouts " << "counter" << "\n";
output << "# HELP " << frontsbase << "tcpdownstreamtimeouts " << "Amount of TCP connections terminated by a timeout while reading from the backend" << "\n";
output << "# TYPE " << frontsbase << "tcpdownstreamtimeouts " << "counter" << "\n";
output << "# HELP " << frontsbase << "tcpcurrentconnections " << "Amount of current incoming TCP connections from clients" << "\n";
@@ -672,7 +695,6 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << "# TYPE " << frontsbase << "tlsunknownticketkeys " << "counter" << "\n";
output << "# HELP " << frontsbase << "tlsinactiveticketkeys " << "Amount of TLS sessions resumed from an inactive key" << "\n";
output << "# TYPE " << frontsbase << "tlsinactiveticketkeys " << "counter" << "\n";
-
output << "# HELP " << frontsbase << "tlshandshakefailures " << "Amount of TLS handshake failures" << "\n";
output << "# TYPE " << frontsbase << "tlshandshakefailures " << "counter" << "\n";
@@ -700,7 +722,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
output << frontsbase << "tcpdiedreadingquery" << label << front->tcpDiedReadingQuery.load() << "\n";
output << frontsbase << "tcpdiedsendingresponse" << label << front->tcpDiedSendingResponse.load() << "\n";
output << frontsbase << "tcpgaveup" << label << front->tcpGaveUp.load() << "\n";
- output << frontsbase << "tcpclientimeouts" << label << front->tcpClientTimeouts.load() << "\n";
+ output << frontsbase << "tcpclienttimeouts" << label << front->tcpClientTimeouts.load() << "\n";
output << frontsbase << "tcpdownstreamtimeouts" << label << front->tcpDownstreamTimeouts.load() << "\n";
output << frontsbase << "tcpcurrentconnections" << label << front->tcpCurrentConnections.load() << "\n";
output << frontsbase << "tcpmaxconcurrentconnections" << label << front->tcpMaxConcurrentConnections.load() << "\n";
@@ -723,7 +745,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
errorCounters = &front->tlsFrontend->d_tlsCounters;
}
else if (front->dohFrontend != nullptr) {
- errorCounters = &front->dohFrontend->d_tlsCounters;
+ errorCounters = &front->dohFrontend->d_tlsContext.d_tlsCounters;
}
if (errorCounters != nullptr) {
@@ -761,7 +783,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
#ifdef HAVE_DNS_OVER_HTTPS
std::map<std::string,uint64_t> dohFrontendDuplicates;
for(const auto& doh : g_dohlocals) {
- const string frontName = doh->d_local.toStringWithPort();
+ const string frontName = doh->d_tlsContext.d_addr.toStringWithPort();
uint64_t threadNumber = 0;
auto dupPair = frontendDuplicates.emplace(frontName, 1);
if (!dupPair.second) {
@@ -895,18 +917,18 @@ using namespace json11;
static void addStatsToJSONObject(Json::object& obj)
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
if (entry.d_name == "special-memory-usage") {
continue; // Too expensive for get-all
}
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*val)->load());
- } else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ } else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
obj.emplace(entry.d_name, (*adval)->load());
- } else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ } else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
obj.emplace(entry.d_name, (**dval));
- } else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ } else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*func)(entry.d_name));
}
}
@@ -1084,6 +1106,12 @@ static void addServerToJSON(Json::array& servers, int id, const std::shared_ptr<
{"tcpAvgConnectionDuration", (double)a->tcpAvgConnectionDuration},
{"tlsResumptions", (double)a->tlsResumptions},
{"tcpLatency", (double)(a->latencyUsecTCP/1000.0)},
+ {"healthCheckFailures", (double)(a->d_healthCheckMetrics.d_failures)},
+ {"healthCheckFailuresParsing", (double)(a->d_healthCheckMetrics.d_parseErrors)},
+ {"healthCheckFailuresTimeout", (double)(a->d_healthCheckMetrics.d_timeOuts)},
+ {"healthCheckFailuresNetwork", (double)(a->d_healthCheckMetrics.d_networkErrors)},
+ {"healthCheckFailuresMismatch", (double)(a->d_healthCheckMetrics.d_mismatchErrors)},
+ {"healthCheckFailuresInvalid", (double)(a->d_healthCheckMetrics.d_invalidResponseErrors)},
{"dropRate", (double)a->dropRate}
};
@@ -1151,7 +1179,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
errorCounters = &front->tlsFrontend->d_tlsCounters;
}
else if (front->dohFrontend != nullptr) {
- errorCounters = &front->dohFrontend->d_tlsCounters;
+ errorCounters = &front->dohFrontend->d_tlsContext.d_tlsCounters;
}
if (errorCounters != nullptr) {
frontend["tlsHandshakeFailuresDHKeyTooSmall"] = (double)errorCounters->d_dhKeyTooSmall;
@@ -1174,7 +1202,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
for (const auto& doh : g_dohlocals) {
dohs.emplace_back(Json::object{
{ "id", num++ },
- { "address", doh->d_local.toStringWithPort() },
+ { "address", doh->d_tlsContext.d_addr.toStringWithPort() },
{ "http-connects", (double) doh->d_httpconnects },
{ "http1-queries", (double) doh->d_http1Stats.d_nbQueries },
{ "http2-queries", (double) doh->d_http2Stats.d_nbQueries },
@@ -1239,6 +1267,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
{"id", num++},
{"creationOrder", (double)a.d_creationOrder},
{"uuid", boost::uuids::to_string(a.d_id)},
+ {"name", a.d_name},
{"matches", (double)a.d_rule->d_matches},
{"rule", a.d_rule->toString()},
{"action", a.d_action->toString()},
@@ -1254,14 +1283,13 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
string acl;
{
- vector<string> vec;
- g_ACL.getLocal()->toStringVector(&vec);
+ auto aclEntries = g_ACL.getLocal()->toStringVector();
- for (const auto& s : vec) {
+ for (const auto& entry : aclEntries) {
if (!acl.empty()) {
acl += ", ";
}
- acl += s;
+ acl += entry;
}
}
@@ -1362,34 +1390,34 @@ static void handleStatsOnly(const YaHTTP::Request& req, YaHTTP::Response& resp)
Json::array doc;
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& item : *entries) {
if (item.d_name == "special-memory-usage") {
continue; // Too expensive for get-all
}
- if (const auto& val = boost::get<pdns::stat_t*>(&item.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (double)(*val)->load() }
});
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&item.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (*adval)->load() }
});
}
- else if (const auto& dval = boost::get<double*>(&item.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (**dval) }
});
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&item.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
@@ -1496,18 +1524,12 @@ static void handleAllowFrom(const YaHTTP::Request& req, YaHTTP::Response& resp)
}
}
if (resp.status == 200) {
- Json::array acl;
- vector<string> vec;
- g_ACL.getLocal()->toStringVector(&vec);
-
- for(const auto& s : vec) {
- acl.push_back(s);
- }
+ auto aclEntries = g_ACL.getLocal()->toStringVector();
Json::object obj{
{ "type", "ConfigSetting" },
{ "name", "allow-from" },
- { "value", acl }
+ { "value", aclEntries }
};
Json my_json = obj;
resp.body = my_json.dump();
@@ -1600,13 +1622,111 @@ static void handleCacheManagement(const YaHTTP::Request& req, YaHTTP::Response&
}
#endif /* DISABLE_WEB_CACHE_MANAGEMENT */
+template<typename T> static void addRingEntryToList(const struct timespec& now, Json::array& list, const T& entry)
+{
+ constexpr bool response = std::is_same_v<T, Rings::Response>;
+ Json::object tmp{
+ { "age", static_cast<double>(DiffTime(entry.when, now)) },
+ { "id", ntohs(entry.dh.id) },
+ { "name", entry.name.toString() },
+ { "requestor", entry.requestor.toStringWithPort() },
+ { "size", static_cast<int>(entry.size) },
+ { "qtype", entry.qtype },
+ { "protocol", entry.protocol.toString() },
+ { "rd", static_cast<bool>(entry.dh.rd) },
+ };
+ if constexpr (!response) {
+#if defined(DNSDIST_RINGS_WITH_MACADDRESS)
+ tmp.emplace("mac", entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string());
+#endif
+ }
+ else {
+ tmp.emplace("latency", static_cast<double>(entry.usec));
+ tmp.emplace("rcode", static_cast<uint8_t>(entry.dh.rcode));
+ tmp.emplace("tc", static_cast<bool>(entry.dh.tc));
+ tmp.emplace("aa", static_cast<bool>(entry.dh.aa));
+ tmp.emplace("answers", ntohs(entry.dh.ancount));
+ auto server = entry.ds.toStringWithPort();
+ tmp.emplace("backend", server != "0.0.0.0:0" ? std::move(server) : "Cache");
+ }
+ list.push_back(std::move(tmp));
+}
+
+static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp)
+{
+ handleCORS(req, resp);
+
+ std::optional<size_t> maxNumberOfQueries{std::nullopt};
+ std::optional<size_t> maxNumberOfResponses{std::nullopt};
+
+ const auto maxQueries = req.getvars.find("maxQueries");
+ if (maxQueries != req.getvars.end()) {
+ try {
+ maxNumberOfQueries = pdns::checked_stoi<size_t>(maxQueries->second);
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error parsing the 'maxQueries' value from rings HTTP GET query: %s", exp.what());
+ }
+ }
+
+ const auto maxResponses = req.getvars.find("maxResponses");
+ if (maxResponses != req.getvars.end()) {
+ try {
+ maxNumberOfResponses = pdns::checked_stoi<size_t>(maxResponses->second);
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error parsing the 'maxResponses' value from rings HTTP GET query: %s", exp.what());
+ }
+ }
+
+ resp.status = 200;
+
+ Json::object doc;
+ size_t numberOfQueries = 0;
+ size_t numberOfResponses = 0;
+ Json::array queries;
+ Json::array responses;
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ for (const auto& shard : g_rings.d_shards) {
+ if (!maxNumberOfQueries || numberOfQueries < *maxNumberOfQueries) {
+ auto queryRing = shard->queryRing.lock();
+ for (const auto& entry : *queryRing) {
+ addRingEntryToList(now, queries, entry);
+ numberOfQueries++;
+ if (maxNumberOfQueries && numberOfQueries >= *maxNumberOfQueries) {
+ break;
+ }
+ }
+ }
+ if (!maxNumberOfResponses || numberOfResponses < *maxNumberOfResponses) {
+ auto responseRing = shard->respRing.lock();
+ for (const auto& entry : *responseRing) {
+ addRingEntryToList(now, responses, entry);
+ numberOfResponses++;
+ if (maxNumberOfResponses && numberOfResponses >= *maxNumberOfResponses) {
+ break;
+ }
+ }
+ }
+ }
+ doc.emplace("queries", std::move(queries));
+ doc.emplace("responses", std::move(responses));
+ Json my_json = doc;
+ resp.body = my_json.dump();
+ resp.headers["Content-Type"] = "application/json";
+}
+
static std::unordered_map<std::string, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>> s_webHandlers;
void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler);
void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler)
{
- s_webHandlers[endpoint] = handler;
+ s_webHandlers[endpoint] = std::move(handler);
}
void clearWebHandlers()
@@ -1664,6 +1784,7 @@ void registerBuiltInWebHandlers()
registerWebHandler("/api/v1/servers/localhost", handleStats);
registerWebHandler("/api/v1/servers/localhost/pool", handlePoolStats);
registerWebHandler("/api/v1/servers/localhost/statistics", handleStatsOnly);
+ registerWebHandler("/api/v1/servers/localhost/rings", handleRings);
#ifndef DISABLE_WEB_CONFIG
registerWebHandler("/api/v1/servers/localhost/config", handleConfigDump);
registerWebHandler("/api/v1/servers/localhost/config/allow-from", handleAllowFrom);
@@ -1759,10 +1880,10 @@ static void connectionThread(WebClientConnection&& conn)
vinfolog("Webserver thread died with parse error exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what());
}
catch (const std::exception& e) {
- errlog("Webserver thread died with exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what());
+ vinfolog("Webserver thread died with exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what());
}
catch (...) {
- errlog("Webserver thread died with exception while processing a request from %s", conn.getClient().toStringWithPort());
+ vinfolog("Webserver thread died with exception while processing a request from %s", conn.getClient().toStringWithPort());
}
}
@@ -1845,7 +1966,7 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local)
t.detach();
}
catch (const std::exception& e) {
- errlog("Had an error accepting new webserver connection: %s", e.what());
+ vinfolog("Had an error accepting new webserver connection: %s", e.what());
}
}
}
diff --git a/dnsdist-web.hh b/dnsdist-web.hh
index 3497d65..7325025 100644
--- a/dnsdist-web.hh
+++ b/dnsdist-web.hh
@@ -1,6 +1,7 @@
#pragma once
#include "credentials.hh"
+#include "dnsdist-prometheus.hh"
void setWebserverAPIKey(std::unique_ptr<CredentialsHolder>&& apiKey);
void setWebserverPassword(std::unique_ptr<CredentialsHolder>&& password);
@@ -16,6 +17,6 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local);
void registerBuiltInWebHandlers();
void clearWebHandlers();
-bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customPrometheusName);
-
std::string getWebserverConfig();
+
+bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def);
diff --git a/dnsdist-xpf.cc b/dnsdist-xpf.cc
index 6f4cba5..eb2ba57 100644
--- a/dnsdist-xpf.cc
+++ b/dnsdist-xpf.cc
@@ -22,6 +22,7 @@
#include "dnsdist-xpf.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsparser.hh"
#include "xpf.hh"
@@ -54,7 +55,9 @@ bool addXPF(DNSQuestion& dq, uint16_t optionCode)
pos += payload.size();
(void) pos;
- dq.getHeader()->arcount = htons(ntohs(dq.getHeader()->arcount) + 1);
-
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.arcount = htons(ntohs(header.arcount) + 1);
+ return true;
+ });
return true;
}
diff --git a/dnsdist-xsk.cc b/dnsdist-xsk.cc
new file mode 100644
index 0000000..058e381
--- /dev/null
+++ b/dnsdist-xsk.cc
@@ -0,0 +1,260 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsdist.hh"
+#include "dnsdist-xsk.hh"
+
+#ifdef HAVE_XSK
+#include <sys/poll.h>
+
+#include "dolog.hh"
+#include "dnsdist-metrics.hh"
+#include "dnsdist-proxy-protocol.hh"
+#include "threadname.hh"
+#include "xsk.hh"
+
+namespace dnsdist::xsk
+{
+std::vector<std::shared_ptr<XskSocket>> g_xsk;
+
+void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<XskWorker> xskInfo)
+{
+ try {
+ setThreadName("dnsdist/XskResp");
+ auto localRespRuleActions = g_respruleactions.getLocal();
+ auto localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
+ auto pollfds = getPollFdsForWorker(*xskInfo);
+ while (!dss->isStopped()) {
+ poll(pollfds.data(), pollfds.size(), -1);
+ bool needNotify = false;
+ if ((pollfds[0].revents & POLLIN) != 0) {
+ needNotify = true;
+ xskInfo->cleanSocketNotification();
+#if defined(__SANITIZE_THREAD__)
+ xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
+#else
+ xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
+#endif
+ if (packet.getDataLen() < sizeof(dnsheader)) {
+ xskInfo->markAsFree(packet);
+ return;
+ }
+ const dnsheader_aligned dnsHeader(packet.getPayloadData());
+ const auto queryId = dnsHeader->id;
+ auto ids = dss->getState(queryId);
+ if (ids) {
+ if (!ids->isXSK()) {
+ dss->restoreState(queryId, std::move(*ids));
+ ids = std::nullopt;
+ }
+ }
+ if (!ids) {
+ xskInfo->markAsFree(packet);
+ return;
+ }
+ auto response = packet.clonePacketBuffer();
+ if (response.size() > packet.getCapacity()) {
+ /* fallback to sending the packet via normal socket */
+ ids->xskPacketHeader.clear();
+ }
+ if (!processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids))) {
+ xskInfo->markAsFree(packet);
+ infolog("XSK packet pushed to queue because processResponderPacket failed");
+ return;
+ }
+ if (response.size() > packet.getCapacity()) {
+ /* fallback to sending the packet via normal socket */
+ sendUDPResponse(ids->cs->udpFD, response, ids->delayMsec, ids->hopLocal, ids->hopRemote);
+ infolog("XSK packet falling back because packet is too large");
+ xskInfo->markAsFree(packet);
+ return;
+ }
+ packet.setHeader(ids->xskPacketHeader);
+ if (!packet.setPayload(response)) {
+ infolog("Unable to set XSK payload !");
+ }
+ if (ids->delayMsec > 0) {
+ packet.addDelay(ids->delayMsec);
+ }
+ packet.updatePacket();
+ xskInfo->pushToSendQueue(packet);
+ });
+ }
+ if (needNotify) {
+ xskInfo->notifyXskSocket();
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ errlog("XSK responder thread died because of exception: %s", e.what());
+ }
+ catch (const PDNSException& e) {
+ errlog("XSK responder thread died because of PowerDNS exception: %s", e.reason);
+ }
+ catch (...) {
+ errlog("XSK responder thread died because of an exception: %s", "unknown");
+ }
+}
+
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol)
+{
+ const auto& from = packet.getFromAddr();
+ expectProxyProtocol = expectProxyProtocolFrom(from);
+ if (!holders.acl->match(from) && !expectProxyProtocol) {
+ vinfolog("Query from %s dropped because of ACL", from.toStringWithPort());
+ ++dnsdist::metrics::g_stats.aclDrops;
+ return false;
+ }
+ clientState.queries++;
+ ++dnsdist::metrics::g_stats.queries;
+
+ return true;
+}
+
+void XskRouter(std::shared_ptr<XskSocket> xsk)
+{
+ setThreadName("dnsdist/XskRouter");
+ uint32_t failed = 0;
+ // packets to be submitted for sending
+ vector<XskPacket> fillInTx;
+ const auto& fds = xsk->getDescriptors();
+ // list of workers that need to be notified
+ std::set<int> needNotify;
+ while (true) {
+ try {
+ auto ready = xsk->wait(-1);
+ // descriptor 0 gets incoming AF_XDP packets
+ if ((fds.at(0).revents & POLLIN) != 0) {
+ auto packets = xsk->recv(64, &failed);
+ dnsdist::metrics::g_stats.nonCompliantQueries += failed;
+ for (auto& packet : packets) {
+ const auto dest = packet.getToAddr();
+ auto worker = xsk->getWorkerByDestination(dest);
+ if (!worker) {
+ xsk->markAsFree(packet);
+ continue;
+ }
+ worker->pushToProcessingQueue(packet);
+ needNotify.insert(worker->workerWaker.getHandle());
+ }
+ for (auto socket : needNotify) {
+ uint64_t value = 1;
+ auto written = write(socket, &value, sizeof(value));
+ if (written != sizeof(value)) {
+ // oh, well, the worker is clearly overloaded
+ // but there is nothing we can do about it,
+ // and hopefully the queue will be processed eventually
+ }
+ }
+ needNotify.clear();
+ ready--;
+ }
+ for (size_t fdIndex = 1; fdIndex < fds.size() && ready > 0; fdIndex++) {
+ if ((fds.at(fdIndex).revents & POLLIN) != 0) {
+ ready--;
+ const auto& info = xsk->getWorkerByDescriptor(fds.at(fdIndex).fd);
+#if defined(__SANITIZE_THREAD__)
+ info->outgoingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
+#else
+ info->outgoingPacketsQueue.consume_all([&](XskPacket& packet) {
+#endif
+ if ((packet.getFlags() & XskPacket::UPDATE) == 0) {
+ xsk->markAsFree(packet);
+ return;
+ }
+ if ((packet.getFlags() & XskPacket::DELAY) != 0) {
+ xsk->pushDelayed(packet);
+ return;
+ }
+ fillInTx.push_back(packet);
+ });
+ info->cleanWorkerNotification();
+ }
+ }
+ xsk->pickUpReadyPacket(fillInTx);
+ xsk->recycle(4096);
+ xsk->fillFq();
+ xsk->send(fillInTx);
+ }
+ catch (...) {
+ vinfolog("Exception in XSK router loop");
+ }
+ }
+}
+
+void XskClientThread(ClientState* clientState)
+{
+ setThreadName("dnsdist/xskClient");
+ auto xskInfo = clientState->xskInfo;
+ LocalHolders holders;
+
+ for (;;) {
+#if defined(__SANITIZE_THREAD__)
+ while (xskInfo->incomingPacketsQueue.lock()->read_available() == 0U) {
+#else
+ while (xskInfo->incomingPacketsQueue.read_available() == 0U) {
+#endif
+ xskInfo->waitForXskSocket();
+ }
+#if defined(__SANITIZE_THREAD__)
+ xskInfo->incomingPacketsQueue.lock()->consume_all([&](XskPacket& packet) {
+#else
+ xskInfo->incomingPacketsQueue.consume_all([&](XskPacket& packet) {
+#endif
+ if (XskProcessQuery(*clientState, holders, packet)) {
+ packet.updatePacket();
+ xskInfo->pushToSendQueue(packet);
+ }
+ else {
+ xskInfo->markAsFree(packet);
+ }
+ });
+ xskInfo->notifyXskSocket();
+ }
+}
+
+static std::string getDestinationMap(bool isV6)
+{
+ return !isV6 ? "/sys/fs/bpf/dnsdist/xsk-destinations-v4" : "/sys/fs/bpf/dnsdist/xsk-destinations-v6";
+}
+
+void addDestinationAddress(const ComboAddress& addr)
+{
+ auto map = getDestinationMap(addr.isIPv6());
+ XskSocket::addDestinationAddress(map, addr);
+}
+
+void removeDestinationAddress(const ComboAddress& addr)
+{
+ auto map = getDestinationMap(addr.isIPv6());
+ XskSocket::removeDestinationAddress(map, addr);
+}
+
+void clearDestinationAddresses()
+{
+ auto map = getDestinationMap(false);
+ XskSocket::clearDestinationMap(map, false);
+ map = getDestinationMap(true);
+ XskSocket::clearDestinationMap(map, true);
+}
+
+}
+#endif /* HAVE_XSK */
diff --git a/dnsdist-xsk.hh b/dnsdist-xsk.hh
new file mode 100644
index 0000000..f677b78
--- /dev/null
+++ b/dnsdist-xsk.hh
@@ -0,0 +1,46 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "config.h"
+
+#ifdef HAVE_XSK
+class XskPacket;
+class XskSocket;
+class XskWorker;
+
+#include <memory>
+
+namespace dnsdist::xsk
+{
+void XskResponderThread(std::shared_ptr<DownstreamState> dss, std::shared_ptr<XskWorker> xskInfo);
+bool XskIsQueryAcceptable(const XskPacket& packet, ClientState& clientState, LocalHolders& holders, bool& expectProxyProtocol);
+bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet);
+void XskRouter(std::shared_ptr<XskSocket> xsk);
+void XskClientThread(ClientState* clientState);
+void addDestinationAddress(const ComboAddress& addr);
+void removeDestinationAddress(const ComboAddress& addr);
+void clearDestinationAddresses();
+
+extern std::vector<std::shared_ptr<XskSocket>> g_xsk;
+}
+#endif /* HAVE_XSK */
diff --git a/dnsdist.1 b/dnsdist.1
index 89322a5..37f3477 100644
--- a/dnsdist.1
+++ b/dnsdist.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "DNSDIST" "1" "Dec 14, 2023" "" "dnsdist"
+.TH "DNSDIST" "1" "Apr 05, 2024" "" "dnsdist"
.SH NAME
dnsdist \- A DNS and DoS aware, scriptable loadbalancer
.SH SYNOPSIS
@@ -90,7 +90,7 @@ shared secret to connect to dnsdist. This should be the same key
that is used on the server (set with \fBsetKey()\fP). Note that this
will leak the key into your shell\(aqs history and into the systems
running process list. Only available when dnsdist is compiled with
-libsodium support.
+libsodium or libcrypto support.
.TP
.BI \-e\fP,\fB \-\-execute \ <command>
Connect to dnsdist and execute \fIcommand\fP\&.
@@ -141,6 +141,6 @@ Website: \fI\%https://dnsdist.org\fP
.SH AUTHOR
PowerDNS.COM BV and its contributors
.SH COPYRIGHT
-2015-2023, PowerDNS.COM BV and its contributors
+PowerDNS.COM BV and its contributors
.\" Generated by docutils manpage writer.
.
diff --git a/dnsdist.cc b/dnsdist.cc
index d83c2b9..0c99cf0 100644
--- a/dnsdist.cc
+++ b/dnsdist.cc
@@ -29,6 +29,7 @@
#include <limits>
#include <netinet/tcp.h>
#include <pwd.h>
+#include <set>
#include <sys/resource.h>
#include <unistd.h>
@@ -52,11 +53,15 @@
#include "dnsdist-cache.hh"
#include "dnsdist-carbon.hh"
#include "dnsdist-console.hh"
+#include "dnsdist-crypto.hh"
#include "dnsdist-discovery.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-edns.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-lua-hooks.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-random.hh"
@@ -65,10 +70,13 @@
#include "dnsdist-tcp.hh"
#include "dnsdist-web.hh"
#include "dnsdist-xpf.hh"
+#include "dnsdist-xsk.hh"
#include "base64.hh"
#include "capabilities.hh"
+#include "coverage.hh"
#include "delaypipe.hh"
+#include "doh.hh"
#include "dolog.hh"
#include "dnsname.hh"
#include "dnsparser.hh"
@@ -76,9 +84,9 @@
#include "gettime.hh"
#include "lock.hh"
#include "misc.hh"
-#include "sodcrypto.hh"
#include "sstuff.hh"
#include "threadname.hh"
+#include "xsk.hh"
/* Known sins:
@@ -94,14 +102,9 @@
using std::thread;
bool g_verbose;
-std::optional<std::ofstream> g_verboseStream{std::nullopt};
-
-struct DNSDistStats g_stats;
uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
uint32_t g_staleCacheEntriesTTL{0};
-bool g_syslog{true};
-bool g_logtimestamps{false};
bool g_allowEmptyResponse{false};
GlobalStateHolder<NetmaskGroup> g_ACL;
@@ -109,6 +112,8 @@ string g_outputBuffer;
std::vector<std::shared_ptr<TLSFrontend>> g_tlslocals;
std::vector<std::shared_ptr<DOHFrontend>> g_dohlocals;
+std::vector<std::shared_ptr<DOQFrontend>> g_doqlocals;
+std::vector<std::shared_ptr<DOH3Frontend>> g_doh3locals;
std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
shared_ptr<BPFFilter> g_defaultBPFFilter{nullptr};
@@ -153,7 +158,9 @@ uint32_t g_socketUDPRecvBuffer{0};
std::set<std::string> g_capabilitiesToRetain;
-static size_t const s_initialUDPPacketBufferSize = s_maxPacketCacheEntrySize + DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
+// we are not willing to receive a bigger UDP response than that, no matter what
+static constexpr size_t s_maxUDPResponsePacketSize{4096U};
+static size_t const s_initialUDPPacketBufferSize = s_maxUDPResponsePacketSize + DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
static_assert(s_initialUDPPacketBufferSize <= UINT16_MAX, "Packet size should fit in a uint16_t");
static ssize_t sendfromto(int sock, const void* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to)
@@ -196,8 +203,12 @@ static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qn
}
packet.resize(static_cast<uint16_t>(sizeof(dnsheader)+qnameWireLength+DNS_TYPE_SIZE+DNS_CLASS_SIZE));
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
- dh->ancount = dh->arcount = dh->nscount = 0;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(packet, [](dnsheader& header) {
+ header.ancount = 0;
+ header.arcount = 0;
+ header.nscount = 0;
+ return true;
+ });
if (hadEDNS) {
addEDNS(packet, maximumSize, z & EDNS_HEADER_FLAG_DO, payloadSize, 0);
@@ -205,7 +216,7 @@ static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qn
}
catch(...)
{
- ++g_stats.truncFail;
+ ++dnsdist::metrics::g_stats.truncFail;
}
}
@@ -226,13 +237,14 @@ struct DelayedPacket
}
};
-static DelayPipe<DelayedPacket>* g_delay = nullptr;
+static std::unique_ptr<DelayPipe<DelayedPacket>> g_delay{nullptr};
#endif /* DISABLE_DELAY_PIPE */
std::string DNSQuestion::getTrailingData() const
{
- const char* message = reinterpret_cast<const char*>(this->getHeader());
- const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto* message = reinterpret_cast<const char*>(this->getData().data());
+ const uint16_t messageLen = getDNSPacketLength(message, this->getData().size());
return std::string(message + messageLen, this->getData().size() - messageLen);
}
@@ -250,6 +262,14 @@ bool DNSQuestion::setTrailingData(const std::string& tail)
return true;
}
+bool DNSQuestion::editHeader(const std::function<bool(dnsheader&)>& editFunction)
+{
+ if (data.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
+ }
+ return dnsdist::PacketMangling::editDNSHeaderFromPacket(data, editFunction);
+}
+
static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
{
constexpr auto doAvg = [](double& var, double n, double weight) {
@@ -258,61 +278,73 @@ static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
if (protocol == dnsdist::Protocol::DoUDP || protocol == dnsdist::Protocol::DNSCryptUDP) {
if (udiff < 1000) {
- ++g_stats.latency0_1;
+ ++dnsdist::metrics::g_stats.latency0_1;
}
else if (udiff < 10000) {
- ++g_stats.latency1_10;
+ ++dnsdist::metrics::g_stats.latency1_10;
}
else if (udiff < 50000) {
- ++g_stats.latency10_50;
+ ++dnsdist::metrics::g_stats.latency10_50;
}
else if (udiff < 100000) {
- ++g_stats.latency50_100;
+ ++dnsdist::metrics::g_stats.latency50_100;
}
else if (udiff < 1000000) {
- ++g_stats.latency100_1000;
+ ++dnsdist::metrics::g_stats.latency100_1000;
}
else {
- ++g_stats.latencySlow;
+ ++dnsdist::metrics::g_stats.latencySlow;
}
- g_stats.latencySum += udiff / 1000;
- ++g_stats.latencyCount;
+ dnsdist::metrics::g_stats.latencySum += udiff / 1000;
+ ++dnsdist::metrics::g_stats.latencyCount;
- doAvg(g_stats.latencyAvg100, udiff, 100);
- doAvg(g_stats.latencyAvg1000, udiff, 1000);
- doAvg(g_stats.latencyAvg10000, udiff, 10000);
- doAvg(g_stats.latencyAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoTCP || protocol == dnsdist::Protocol::DNSCryptTCP) {
- doAvg(g_stats.latencyTCPAvg100, udiff, 100);
- doAvg(g_stats.latencyTCPAvg1000, udiff, 1000);
- doAvg(g_stats.latencyTCPAvg10000, udiff, 10000);
- doAvg(g_stats.latencyTCPAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoT) {
- doAvg(g_stats.latencyDoTAvg100, udiff, 100);
- doAvg(g_stats.latencyDoTAvg1000, udiff, 1000);
- doAvg(g_stats.latencyDoTAvg10000, udiff, 10000);
- doAvg(g_stats.latencyDoTAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoH) {
- doAvg(g_stats.latencyDoHAvg100, udiff, 100);
- doAvg(g_stats.latencyDoHAvg1000, udiff, 1000);
- doAvg(g_stats.latencyDoHAvg10000, udiff, 10000);
- doAvg(g_stats.latencyDoHAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg1000000, udiff, 1000000);
+ }
+ else if (protocol == dnsdist::Protocol::DoQ) {
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoQAvg1000000, udiff, 1000000);
+ }
+ else if (protocol == dnsdist::Protocol::DoH3) {
+ doAvg(dnsdist::metrics::g_stats.latencyDoH3Avg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoH3Avg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoH3Avg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoH3Avg1000000, udiff, 1000000);
}
}
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
{
if (response.size() < sizeof(dnsheader)) {
return false;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response.data());
+ const dnsheader_aligned dh(response.data());
if (dh->qr == 0) {
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
@@ -324,7 +356,7 @@ bool responseContentMatches(const PacketBuffer& response, const DNSName& qname,
return true;
}
else {
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
@@ -335,13 +367,14 @@ bool responseContentMatches(const PacketBuffer& response, const DNSName& qname,
uint16_t rqtype, rqclass;
DNSName rqname;
try {
- rqname = DNSName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, &rqtype, &rqclass, &qnameWireLength);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ rqname = DNSName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, &rqtype, &rqclass);
}
catch (const std::exception& e) {
if (remote && response.size() > 0 && static_cast<size_t>(response.size()) > sizeof(dnsheader)) {
infolog("Backend %s sent us a response with id %d that did not parse: %s", remote->d_config.remote.toStringWithPort(), ntohs(dh->id), e.what());
}
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
@@ -369,11 +402,14 @@ static void restoreFlags(struct dnsheader* dh, uint16_t origFlags)
*flags |= origFlags;
}
-static bool fixUpQueryTurnedResponse(DNSQuestion& dq, const uint16_t origFlags)
+static bool fixUpQueryTurnedResponse(DNSQuestion& dnsQuestion, const uint16_t origFlags)
{
- restoreFlags(dq.getHeader(), origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [origFlags](dnsheader& header) {
+ restoreFlags(&header, origFlags);
+ return true;
+ });
- return addEDNSToQueryTurnedResponse(dq);
+ return addEDNSToQueryTurnedResponse(dnsQuestion);
}
static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, bool* zeroScope)
@@ -382,8 +418,10 @@ static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t
return false;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
- restoreFlags(dh, origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [origFlags](dnsheader& header) {
+ restoreFlags(&header, origFlags);
+ return true;
+ });
if (response.size() == sizeof(dnsheader)) {
return true;
@@ -421,10 +459,12 @@ static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t
if (last) {
/* simply remove the last AR */
response.resize(response.size() - optLen);
- dh = reinterpret_cast<struct dnsheader*>(response.data());
- uint16_t arcount = ntohs(dh->arcount);
- arcount--;
- dh->arcount = htons(arcount);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [](dnsheader& header) {
+ uint16_t arcount = ntohs(header.arcount);
+ arcount--;
+ header.arcount = htons(arcount);
+ return true;
+ });
}
else {
/* Removing an intermediary RR could lead to compression error */
@@ -498,9 +538,24 @@ static bool applyRulesToResponse(const std::vector<DNSDistResponseRuleAction>& r
return true;
break;
case DNSResponseAction::Action::ServFail:
- dr.getHeader()->rcode = RCode::ServFail;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ return true;
+ });
return true;
break;
+ case DNSResponseAction::Action::Truncate:
+ if (!dr.overTCP()) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ return true;
+ });
+ truncateTC(dr.getMutableData(), dr.getMaximumSize(), dr.ids.qname.wirelength());
+ ++dnsdist::metrics::g_stats.ruleTruncated;
+ return true;
+ }
+ break;
/* non-terminal actions follow */
case DNSResponseAction::Action::Delay:
pdns::checked_stoi_into(dr.ids.delayMsec, ruleresult); // sorry
@@ -521,7 +576,7 @@ bool processResponseAfterRules(PacketBuffer& response, const std::vector<DNSDist
return false;
}
- if (dr.ids.packetCache && !dr.ids.selfGenerated && !dr.ids.skipCache && response.size() <= s_maxPacketCacheEntrySize) {
+ if (dr.ids.packetCache && !dr.ids.selfGenerated && !dr.ids.skipCache && (!dr.ids.forwardedOverUDP || response.size() <= s_maxUDPResponsePacketSize)) {
if (!dr.ids.useZeroScope) {
/* if the query was not suitable for zero-scope, for
example because it had an existing ECS entry so the hash is
@@ -555,6 +610,10 @@ bool processResponseAfterRules(PacketBuffer& response, const std::vector<DNSDist
ac(&dr, &result);
}
+ if (dr.ids.d_extendedError) {
+ dnsdist::edns::addExtendedDNSError(dr.getMutableData(), dr.getMaximumSize(), dr.ids.d_extendedError->infoCode, dr.ids.d_extendedError->extraText);
+ }
+
#ifdef HAVE_DNSCRYPT
if (!muted) {
if (!encryptResponse(response, dr.getMaximumSize(), dr.overTCP(), dr.ids.dnsCryptQuery)) {
@@ -579,11 +638,11 @@ bool processResponse(PacketBuffer& response, const std::vector<DNSDistResponseRu
return processResponseAfterRules(response, cacheInsertedRespRuleActions, dr, muted);
}
-static size_t getInitialUDPPacketBufferSize()
+static size_t getInitialUDPPacketBufferSize(bool expectProxyProtocol)
{
static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
- if (g_proxyProtocolACL.empty()) {
+ if (!expectProxyProtocol || g_proxyProtocolACL.empty()) {
return s_initialUDPPacketBufferSize;
}
@@ -593,10 +652,10 @@ static size_t getInitialUDPPacketBufferSize()
static size_t getMaximumIncomingPacketSize(const ClientState& cs)
{
if (cs.dnscryptCtx) {
- return getInitialUDPPacketBufferSize();
+ return getInitialUDPPacketBufferSize(cs.d_enableProxyProtocol);
}
- if (g_proxyProtocolACL.empty()) {
+ if (!cs.d_enableProxyProtocol || g_proxyProtocolACL.empty()) {
return s_udpIncomingBufferSize;
}
@@ -606,7 +665,7 @@ static size_t getMaximumIncomingPacketSize(const ClientState& cs)
bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
{
#ifndef DISABLE_DELAY_PIPE
- if (delayMsec && g_delay) {
+ if (delayMsec > 0 && g_delay != nullptr) {
DelayedPacket dp{origFD, response, origRemote, origDest};
g_delay->submit(dp, delayMsec);
return true;
@@ -636,16 +695,16 @@ void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff,
switch (cleartextDH.rcode) {
case RCode::NXDomain:
- ++g_stats.frontendNXDomain;
+ ++dnsdist::metrics::g_stats.frontendNXDomain;
break;
case RCode::ServFail:
if (fromBackend) {
- ++g_stats.servfailResponses;
+ ++dnsdist::metrics::g_stats.servfailResponses;
}
- ++g_stats.frontendServFail;
+ ++dnsdist::metrics::g_stats.frontendServFail;
break;
case RCode::NoError:
- ++g_stats.frontendNoError;
+ ++dnsdist::metrics::g_stats.frontendNoError;
break;
}
@@ -659,7 +718,10 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
if (ids.udpPayloadSize > 0 && response.size() > ids.udpPayloadSize) {
vinfolog("Got a response of size %d while the initial UDP payload size was %d, truncating", response.size(), ids.udpPayloadSize);
truncateTC(dr.getMutableData(), dr.getMaximumSize(), dr.ids.qname.wirelength());
- dr.getHeader()->tc = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dr.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ return true;
+ });
}
else if (dr.getHeader()->tc && g_truncateTC) {
truncateTC(response, dr.getMaximumSize(), dr.ids.qname.wirelength());
@@ -668,7 +730,7 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
/* when the answer is encrypted in place, we need to get a copy
of the original header before encryption to fill the ring buffer */
dnsheader cleartextDH;
- memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
+ memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
if (!isAsync) {
if (!processResponse(response, respRuleActions, cacheInsertedRespRuleActions, dr, ids.cs && ids.cs->muted)) {
@@ -680,15 +742,13 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
}
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
if (ids.cs) {
++ids.cs->responses;
}
bool muted = true;
- if (ids.cs && !ids.cs->muted) {
- ComboAddress empty;
- empty.sin4.sin_family = 0;
+ if (ids.cs != nullptr && !ids.cs->muted && !ids.isXSK()) {
sendUDPResponse(ids.cs->udpFD, response, dr.ids.delayMsec, ids.hopLocal, ids.hopRemote);
muted = false;
}
@@ -696,10 +756,15 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
if (!selfGenerated) {
double udiff = ids.queryRealTime.udiff();
if (!muted) {
- vinfolog("Got answer from %s, relayed to %s (UDP), took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (UDP), took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
}
else {
- vinfolog("Got answer from %s, NOT relayed to %s (UDP) since that frontend is muted, took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ if (!ids.isXSK()) {
+ vinfolog("Got answer from %s, NOT relayed to %s (UDP) since that frontend is muted, took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ }
+ else {
+ vinfolog("Got answer from %s, relayed to %s (UDP via XSK), took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ }
}
handleResponseSent(ids, udiff, dr.ids.origRemote, ds->d_config.remote, response.size(), cleartextDH, ds->getProtocol(), true);
@@ -709,6 +774,42 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
}
}
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<DNSDistResponseRuleAction>& localRespRuleActions, const std::vector<DNSDistResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+{
+
+ const dnsheader_aligned dnsHeader(response.data());
+ auto queryId = dnsHeader->id;
+
+ if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss)) {
+ dss->restoreState(queryId, std::move(ids));
+ return false;
+ }
+
+ auto dohUnit = std::move(ids.du);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(response, [&ids](dnsheader& header) {
+ header.id = ids.origID;
+ return true;
+ });
+ ++dss->responses;
+
+ double udiff = ids.queryRealTime.udiff();
+ // do that _before_ the processing, otherwise it's not fair to the backend
+ dss->latencyUsec = (127.0 * dss->latencyUsec / 128.0) + udiff / 128.0;
+ dss->reportResponse(dnsHeader->rcode);
+
+ /* don't call processResponse for DOH */
+ if (dohUnit) {
+#ifdef HAVE_DNS_OVER_HTTPS
+ // DoH query, we cannot touch dohUnit after that
+ DOHUnitInterface::handleUDPResponse(std::move(dohUnit), std::move(response), std::move(ids), dss);
+#endif
+ return false;
+ }
+
+ handleResponseForUDPClient(ids, response, localRespRuleActions, cacheInsertedRespRuleActions, dss, false, false);
+ return true;
+}
+
// listens on a dedicated socket, lobs answers from downstream servers to original requestors
void responderThread(std::shared_ptr<DownstreamState> dss)
{
@@ -716,7 +817,7 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
setThreadName("dnsdist/respond");
auto localRespRuleActions = g_respruleactions.getLocal();
auto localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
- const size_t initialBufferSize = getInitialUDPPacketBufferSize();
+ const size_t initialBufferSize = getInitialUDPPacketBufferSize(false);
/* allocate one more byte so we can detect truncation */
PacketBuffer response(initialBufferSize + 1);
uint16_t queryId = 0;
@@ -748,7 +849,7 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
for (const auto& fd : sockets) {
/* allocate one more byte so we can detect truncation */
- // NOLINTNEXTLINE(bugprone-use-after-move): resizing a vector has no preconditions so it is valid to do so after moving it
+ // NOLINTNEXTLINE(bugprone-use-after-move): resizing a vector has no preconditions so it is valid to do so after moving it
response.resize(initialBufferSize + 1);
ssize_t got = recv(fd, response.data(), response.size(), 0);
@@ -761,40 +862,37 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
}
response.resize(static_cast<size_t>(got));
- dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
- queryId = dh->id;
+ const dnsheader_aligned dnsHeader(response.data());
+ queryId = dnsHeader->id;
auto ids = dss->getState(queryId);
if (!ids) {
continue;
}
- unsigned int qnameWireLength = 0;
- if (fd != ids->backendFD || !responseContentMatches(response, ids->qname, ids->qtype, ids->qclass, dss, qnameWireLength)) {
+ if (!ids->isXSK() && fd != ids->backendFD) {
dss->restoreState(queryId, std::move(*ids));
continue;
}
- auto du = std::move(ids->du);
-
- dh->id = ids->origID;
- ++dss->responses;
-
- double udiff = ids->queryRealTime.udiff();
- // do that _before_ the processing, otherwise it's not fair to the backend
- dss->latencyUsec = (127.0 * dss->latencyUsec / 128.0) + udiff / 128.0;
- dss->reportResponse(dh->rcode);
-
- /* don't call processResponse for DOH */
- if (du) {
-#ifdef HAVE_DNS_OVER_HTTPS
- // DoH query, we cannot touch du after that
- handleUDPResponseForDoH(std::move(du), std::move(response), std::move(*ids));
-#endif
- continue;
+ if (processResponderPacket(dss, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfo) {
+#ifdef HAVE_XSK
+ auto& xskInfo = ids->cs->xskInfo;
+ auto xskPacket = xskInfo->getEmptyFrame();
+ if (!xskPacket) {
+ continue;
+ }
+ xskPacket->setHeader(ids->xskPacketHeader);
+ if (!xskPacket->setPayload(response)) {
+ }
+ if (ids->delayMsec > 0) {
+ xskPacket->addDelay(ids->delayMsec);
+ }
+ xskPacket->updatePacket();
+ xskInfo->pushToSendQueue(*xskPacket);
+ xskInfo->notifyXskSocket();
+#endif /* HAVE_XSK */
}
-
- handleResponseForUDPClient(*ids, response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dss, false, false);
}
}
catch (const std::exception& e) {
@@ -824,8 +922,8 @@ static void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent,
if (raw) {
std::vector<std::string> raws;
stringtok(raws, spoofContent, ",");
- SpoofAction sa(raws);
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(raws, std::nullopt);
+ tempSpoofAction(&dq, &result);
}
else {
std::vector<std::string> addrs;
@@ -834,13 +932,13 @@ static void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent,
if (addrs.size() == 1) {
try {
ComboAddress spoofAddr(spoofContent);
- SpoofAction sa({spoofAddr});
- sa(&dq, &result);
+ SpoofAction tempSpoofAction({spoofAddr});
+ tempSpoofAction(&dq, &result);
}
catch(const PDNSException &e) {
DNSName cname(spoofContent);
- SpoofAction sa(cname); // CNAME then
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(cname); // CNAME then
+ tempSpoofAction(&dq, &result);
}
} else {
std::vector<ComboAddress> cas;
@@ -851,8 +949,8 @@ static void spoofResponseFromString(DNSQuestion& dq, const string& spoofContent,
catch (...) {
}
}
- SpoofAction sa(cas);
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(cas);
+ tempSpoofAction(&dq, &result);
}
}
}
@@ -861,8 +959,8 @@ static void spoofPacketFromString(DNSQuestion& dq, const string& spoofContent)
{
string result;
- SpoofAction sa(spoofContent.c_str(), spoofContent.size());
- sa(&dq, &result);
+ SpoofAction tempSpoofAction(spoofContent.c_str(), spoofContent.size());
+ tempSpoofAction(&dq, &result);
}
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop)
@@ -871,28 +969,33 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s
return false;
}
- switch(action) {
+ auto setRCode = [&dq](uint8_t rcode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
+ };
+
+ switch (action) {
case DNSAction::Action::Allow:
return true;
break;
case DNSAction::Action::Drop:
- ++g_stats.ruleDrop;
+ ++dnsdist::metrics::g_stats.ruleDrop;
drop = true;
return true;
break;
case DNSAction::Action::Nxdomain:
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr = true;
+ setRCode(RCode::NXDomain);
return true;
break;
case DNSAction::Action::Refused:
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
break;
case DNSAction::Action::ServFail:
- dq.getHeader()->rcode = RCode::ServFail;
- dq.getHeader()->qr = true;
+ setRCode(RCode::ServFail);
return true;
break;
case DNSAction::Action::Spoof:
@@ -909,12 +1012,15 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s
break;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
- ++g_stats.ruleTruncated;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
+ ++dnsdist::metrics::g_stats.ruleTruncated;
return true;
}
break;
@@ -928,7 +1034,10 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::s
return true;
break;
case DNSAction::Action::NoRecurse:
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
break;
/* non-terminal actions follow */
@@ -970,10 +1079,18 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
}
#ifndef DISABLE_DYNBLOCKS
+ auto setRCode = [&dq](uint8_t rcode) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [rcode](dnsheader& header) {
+ header.rcode = rcode;
+ header.qr = true;
+ return true;
+ });
+ };
+
/* the Dynamic Block mechanism supports address and port ranges, so we need to pass the full address and port */
if (auto got = holders.dynNMGBlock->lookup(AddressAndPortRange(dq.ids.origRemote, dq.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
auto updateBlockStats = [&got]() {
- ++g_stats.dynBlocked;
+ ++dnsdist::metrics::g_stats.dynBlocked;
got->second.blocks++;
};
@@ -982,6 +1099,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
if (action == DNSAction::Action::None) {
action = g_dynBlockAction;
}
+
switch (action) {
case DNSAction::Action::NoOp:
/* do nothing */
@@ -991,27 +1109,28 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
vinfolog("Query from %s turned into NXDomain because of dynamic block", dq.ids.origRemote.toStringWithPort());
updateBlockStats();
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr=true;
+ setRCode(RCode::NXDomain);
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s refused because of dynamic block", dq.ids.origRemote.toStringWithPort());
updateBlockStats();
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
updateBlockStats();
vinfolog("Query from %s truncated because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
return true;
}
else {
@@ -1021,7 +1140,10 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
default:
updateBlockStats();
@@ -1033,7 +1155,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
if (auto got = holders.dynSMTBlock->lookup(dq.ids.qname)) {
auto updateBlockStats = [&got]() {
- ++g_stats.dynBlocked;
+ ++dnsdist::metrics::g_stats.dynBlocked;
got->blocks++;
};
@@ -1050,26 +1172,27 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
vinfolog("Query from %s for %s turned into NXDomain because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
updateBlockStats();
- dq.getHeader()->rcode = RCode::NXDomain;
- dq.getHeader()->qr = true;
+ setRCode(RCode::NXDomain);
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s for %s refused because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
updateBlockStats();
- dq.getHeader()->rcode = RCode::Refused;
- dq.getHeader()->qr = true;
+ setRCode(RCode::Refused);
return true;
case DNSAction::Action::Truncate:
if (!dq.overTCP()) {
updateBlockStats();
vinfolog("Query from %s for %s truncated because of dynamic block", dq.ids.origRemote.toStringWithPort(), dq.ids.qname.toLogString());
- dq.getHeader()->tc = true;
- dq.getHeader()->qr = true;
- dq.getHeader()->ra = dq.getHeader()->rd;
- dq.getHeader()->aa = false;
- dq.getHeader()->ad = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.tc = true;
+ header.qr = true;
+ header.ra = header.rd;
+ header.aa = false;
+ header.ad = false;
+ return true;
+ });
return true;
}
else {
@@ -1079,7 +1202,10 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.ids.origRemote.toStringWithPort());
- dq.getHeader()->rd = false;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rd = false;
+ return true;
+ });
return true;
default:
updateBlockStats();
@@ -1110,34 +1236,37 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const stru
return true;
}
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const PacketBuffer& request, bool healthCheck)
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& backend, const int socketDesc, const PacketBuffer& request, bool healthCheck)
{
ssize_t result;
- if (ss->d_config.sourceItf == 0) {
- result = send(sd, request.data(), request.size(), 0);
+ if (backend->d_config.sourceItf == 0) {
+ result = send(socketDesc, request.data(), request.size(), 0);
}
else {
struct msghdr msgh;
struct iovec iov;
cmsgbuf_aligned cbuf;
- ComboAddress remote(ss->d_config.remote);
+ ComboAddress remote(backend->d_config.remote);
fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), const_cast<char*>(reinterpret_cast<const char *>(request.data())), request.size(), &remote);
- addCMsgSrcAddr(&msgh, &cbuf, &ss->d_config.sourceAddr, ss->d_config.sourceItf);
- result = sendmsg(sd, &msgh, 0);
+ addCMsgSrcAddr(&msgh, &cbuf, &backend->d_config.sourceAddr, static_cast<int>(backend->d_config.sourceItf));
+ result = sendmsg(socketDesc, &msgh, 0);
}
if (result == -1) {
int savederrno = errno;
- vinfolog("Error sending request to backend %s: %s", ss->d_config.remote.toStringWithPort(), stringerror(savederrno));
+ vinfolog("Error sending request to backend %s: %s", backend->d_config.remote.toStringWithPort(), stringerror(savederrno));
/* This might sound silly, but on Linux send() might fail with EINVAL
if the interface the socket was bound to doesn't exist anymore.
We don't want to reconnect the real socket if the healthcheck failed,
because it's not using the same socket.
*/
- if (!healthCheck && (savederrno == EINVAL || savederrno == ENODEV || savederrno == ENETUNREACH || savederrno == EBADF)) {
- ss->reconnect();
+ if (!healthCheck) {
+ if (savederrno == EINVAL || savederrno == ENODEV || savederrno == ENETUNREACH || savederrno == EHOSTUNREACH || savederrno == EBADF) {
+ backend->reconnect();
+ }
+ backend->reportTimeoutOrError();
}
}
@@ -1150,14 +1279,14 @@ static bool isUDPQueryAcceptable(ClientState& cs, LocalHolders& holders, const s
/* message was too large for our buffer */
vinfolog("Dropping message too large for our buffer");
++cs.nonCompliantQueries;
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
- expectProxyProtocol = expectProxyProtocolFrom(remote);
+ expectProxyProtocol = cs.d_enableProxyProtocol && expectProxyProtocolFrom(remote);
if (!holders.acl->match(remote) && !expectProxyProtocol) {
vinfolog("Query from %s dropped because of ACL", remote.toStringWithPort());
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
return false;
}
@@ -1187,7 +1316,7 @@ static bool isUDPQueryAcceptable(ClientState& cs, LocalHolders& holders, const s
}
++cs.queries;
- ++g_stats.queries;
+ ++dnsdist::metrics::g_stats.queries;
return true;
}
@@ -1213,23 +1342,23 @@ bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_
return false;
}
-bool checkQueryHeaders(const struct dnsheader* dh, ClientState& cs)
+bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState)
{
- if (dh->qr) { // don't respond to responses
- ++g_stats.nonCompliantQueries;
- ++cs.nonCompliantQueries;
+ if (dnsHeader.qr) { // don't respond to responses
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
return false;
}
- if (dh->qdcount == 0) {
- ++g_stats.emptyQueries;
+ if (dnsHeader.qdcount == 0) {
+ ++dnsdist::metrics::g_stats.emptyQueries;
if (g_dropEmptyQueries) {
return false;
}
}
- if (dh->rd) {
- ++g_stats.rdQueries;
+ if (dnsHeader.rd) {
+ ++dnsdist::metrics::g_stats.rdQueries;
}
return true;
@@ -1270,8 +1399,12 @@ static bool prepareOutgoingResponse(LocalHolders& holders, const ClientState& cs
ac(&dr, &result);
}
+ if (dr.ids.d_extendedError) {
+ dnsdist::edns::addExtendedDNSError(dr.getMutableData(), dr.getMaximumSize(), dr.ids.d_extendedError->infoCode, dr.ids.d_extendedError->extraText);
+ }
+
if (cacheHit) {
- ++g_stats.cacheHits;
+ ++dnsdist::metrics::g_stats.cacheHits;
}
if (dr.isAsynchronous()) {
@@ -1303,20 +1436,19 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
const auto rcode = dq.getHeader()->rcode;
if (rcode == RCode::NXDomain) {
- ++g_stats.ruleNXDomain;
+ ++dnsdist::metrics::g_stats.ruleNXDomain;
}
else if (rcode == RCode::Refused) {
- ++g_stats.ruleRefused;
+ ++dnsdist::metrics::g_stats.ruleRefused;
}
else if (rcode == RCode::ServFail) {
- ++g_stats.ruleServFail;
+ ++dnsdist::metrics::g_stats.ruleServFail;
}
- ++g_stats.selfAnswered;
+ ++dnsdist::metrics::g_stats.selfAnswered;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
-
std::shared_ptr<ServerPool> serverPool = getPool(*holders.pools, dq.ids.poolName);
std::shared_ptr<ServerPolicy> poolPolicy = serverPool->policy;
dq.ids.packetCache = serverPool->packetCache;
@@ -1343,7 +1475,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
@@ -1370,7 +1502,10 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
yet, as we will do a second-lookup */
if (dq.ids.packetCache->get(dq, dq.getHeader()->id, &dq.ids.cacheKey, dq.ids.subnet, dq.ids.dnssecOK, forwardedOverUDP, allowExpired, false, true, dq.ids.protocol != dnsdist::Protocol::DoH || forwardedOverUDP)) {
- restoreFlags(dq.getHeader(), dq.ids.origFlags);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [flags=dq.ids.origFlags](dnsheader& header) {
+ restoreFlags(&header, flags);
+ return true;
+ });
vinfolog("Packet cache hit for query for %s|%s from %s (%s, %d bytes)", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort(), dq.ids.protocol.toString(), dq.getData().size());
@@ -1378,7 +1513,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
@@ -1389,7 +1524,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
@@ -1397,23 +1532,26 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
vinfolog("Packet cache miss for query for %s|%s from %s (%s, %d bytes)", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort(), dq.ids.protocol.toString(), dq.getData().size());
- ++g_stats.cacheMisses;
+ ++dnsdist::metrics::g_stats.cacheMisses;
}
if (!selectedBackend) {
- ++g_stats.noPolicy;
+ ++dnsdist::metrics::g_stats.noPolicy;
vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort());
if (g_servFailOnNoPolicy) {
- dq.getHeader()->rcode = RCode::ServFail;
- dq.getHeader()->qr = true;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dq.getMutableData(), [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ header.qr = true;
+ return true;
+ });
fixUpQueryTurnedResponse(dq, dq.ids.origFlags);
if (!prepareOutgoingResponse(holders, *dq.ids.cs, dq, false)) {
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
// no response-only statistics counter to update.
return ProcessQueryResult::SendAnswer;
@@ -1423,12 +1561,19 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
}
/* save the DNS flags as sent to the backend so we can cache the answer with the right flags later */
- dq.ids.cacheFlags = *getFlagsFromDNSHeader(dq.getHeader());
+ dq.ids.cacheFlags = *getFlagsFromDNSHeader(dq.getHeader().get());
if (dq.addXPF && selectedBackend->d_config.xpfRRCode != 0) {
addXPF(dq, selectedBackend->d_config.xpfRRCode);
}
+ if (selectedBackend->d_config.useProxyProtocol && dq.getProtocol().isEncrypted() && selectedBackend->d_config.d_proxyProtocolAdvertiseTLS) {
+ if (!dq.proxyProtocolValues) {
+ dq.proxyProtocolValues = std::make_unique<std::vector<ProxyProtocolValue>>();
+ }
+ dq.proxyProtocolValues->push_back(ProxyProtocolValue{"", static_cast<uint8_t>(ProxyProtocolValue::Types::PP_TLV_SSL)});
+ }
+
selectedBackend->incQueriesCount();
return ProcessQueryResult::PassToBackend;
}
@@ -1473,7 +1618,7 @@ public:
return handleResponse(now, std::move(response));
}
- void notifyIOError(InternalQueryState&& query, const struct timeval& now) override
+ void notifyIOError(const struct timeval&, TCPResponse&&) override
{
// nothing to do
}
@@ -1544,41 +1689,48 @@ ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::sha
return ProcessQueryResult::Drop;
}
-bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& ds, uint16_t queryID, DNSQuestion& dq, PacketBuffer& query, ComboAddress& dest)
+bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend)
{
- bool doh = dq.ids.du != nullptr;
+ bool doh = dnsQuestion.ids.du != nullptr;
bool failed = false;
- size_t proxyPayloadSize = 0;
- if (ds->d_config.useProxyProtocol) {
+ if (downstream->d_config.useProxyProtocol) {
try {
- if (addProxyProtocol(dq, &proxyPayloadSize)) {
- if (dq.ids.du) {
- dq.ids.du->proxyProtocolPayloadSize = proxyPayloadSize;
- }
- }
+ addProxyProtocol(dnsQuestion, &dnsQuestion.ids.d_proxyProtocolPayloadSize);
}
catch (const std::exception& e) {
- vinfolog("Adding proxy protocol payload to %s query from %s failed: %s", (dq.ids.du ? "DoH" : ""), dq.ids.origDest.toStringWithPort(), e.what());
+ vinfolog("Adding proxy protocol payload to %s query from %s failed: %s", (dnsQuestion.ids.du ? "DoH" : ""), dnsQuestion.ids.origDest.toStringWithPort(), e.what());
return false;
}
}
+ if (doh && !dnsQuestion.ids.d_packet) {
+ dnsQuestion.ids.d_packet = std::make_unique<PacketBuffer>(query);
+ }
+
try {
- int fd = ds->pickSocketForSending();
- dq.ids.backendFD = fd;
- dq.ids.origID = queryID;
- dq.ids.forwardedOverUDP = true;
+ int descriptor = downstream->pickSocketForSending();
+ if (actuallySend) {
+ dnsQuestion.ids.backendFD = descriptor;
+ }
+ dnsQuestion.ids.origID = queryID;
+ dnsQuestion.ids.forwardedOverUDP = true;
- vinfolog("Got query for %s|%s from %s%s, relayed to %s", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort(), (doh ? " (https)" : ""), ds->getNameWithAddr());
+ vinfolog("Got query for %s|%s from %s%s, relayed to %s%s", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), (doh ? " (https)" : ""), downstream->getNameWithAddr(), actuallySend ? "" : " (xsk)");
- auto idOffset = ds->saveState(std::move(dq.ids));
+ /* make a copy since we cannot touch dnsQuestion.ids after the move */
+ auto proxyProtocolPayloadSize = dnsQuestion.ids.d_proxyProtocolPayloadSize;
+ auto idOffset = downstream->saveState(std::move(dnsQuestion.ids));
/* set the correct ID */
- memcpy(query.data() + proxyPayloadSize, &idOffset, sizeof(idOffset));
+ memcpy(&query.at(proxyProtocolPayloadSize), &idOffset, sizeof(idOffset));
+
+ if (!actuallySend) {
+ return true;
+ }
/* you can't touch ids or du after this line, unless the call returned a non-negative value,
because it might already have been freed */
- ssize_t ret = udpClientSendRequestToBackend(ds, fd, query);
+ ssize_t ret = udpClientSendRequestToBackend(downstream, descriptor, query);
if (ret < 0) {
failed = true;
@@ -1587,15 +1739,12 @@ bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& ds, uint1
if (failed) {
/* clear up the state. In the very unlikely event it was reused
in the meantime, so be it. */
- auto cleared = ds->getState(idOffset);
+ auto cleared = downstream->getState(idOffset);
if (cleared) {
- dq.ids.du = std::move(cleared->du);
- if (dq.ids.du) {
- dq.ids.du->status_code = 502;
- }
+ dnsQuestion.ids.du = std::move(cleared->du);
}
- ++g_stats.downstreamSendErrors;
- ++ds->sendErrors;
+ ++dnsdist::metrics::g_stats.downstreamSendErrors;
+ ++downstream->sendErrors;
return false;
}
}
@@ -1651,16 +1800,20 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct
{
/* this pointer will be invalidated the second the buffer is resized, don't hold onto it! */
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(query.data());
- queryId = ntohs(dh->id);
+ const dnsheader_aligned dnsHeader(query.data());
+ queryId = ntohs(dnsHeader->id);
- if (!checkQueryHeaders(dh, cs)) {
+ if (!checkQueryHeaders(*dnsHeader, cs)) {
return;
}
- if (dh->qdcount == 0) {
- dh->rcode = RCode::NotImp;
- dh->qr = true;
+ if (dnsHeader->qdcount == 0) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+
sendUDPResponse(cs.udpFD, query, 0, dest, remote);
return;
}
@@ -1671,7 +1824,7 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct
ids.protocol = dnsdist::Protocol::DNSCryptUDP;
}
DNSQuestion dq(ids, query);
- const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader());
+ const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader().get());
ids.origFlags = *flags;
if (!proxyProtocolValues.empty()) {
@@ -1686,7 +1839,7 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct
}
// the buffer might have been invalidated by now (resized)
- struct dnsheader* dh = dq.getHeader();
+ const auto dh = dq.getHeader();
if (result == ProcessQueryResult::SendAnswer) {
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
@@ -1725,13 +1878,142 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct
return;
}
- assignOutgoingUDPQueryToBackend(ss, dh->id, dq, query, dest);
+ assignOutgoingUDPQueryToBackend(ss, dh->id, dq, query);
}
catch(const std::exception& e){
vinfolog("Got an error in UDP question thread while parsing a query from %s, id %d: %s", ids.origRemote.toStringWithPort(), queryId, e.what());
}
}
+#ifdef HAVE_XSK
+namespace dnsdist::xsk
+{
+bool XskProcessQuery(ClientState& cs, LocalHolders& holders, XskPacket& packet)
+{
+ uint16_t queryId = 0;
+ const auto& remote = packet.getFromAddr();
+ const auto& dest = packet.getToAddr();
+ InternalQueryState ids;
+ ids.cs = &cs;
+ ids.origRemote = remote;
+ ids.hopRemote = remote;
+ ids.origDest = dest;
+ ids.hopLocal = dest;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.xskPacketHeader = packet.cloneHeaderToPacketBuffer();
+
+ try {
+ bool expectProxyProtocol = false;
+ if (!XskIsQueryAcceptable(packet, cs, holders, expectProxyProtocol)) {
+ return false;
+ }
+
+ auto query = packet.clonePacketBuffer();
+ std::vector<ProxyProtocolValue> proxyProtocolValues;
+ if (expectProxyProtocol && !handleProxyProtocol(remote, false, *holders.acl, query, ids.origRemote, ids.origDest, proxyProtocolValues)) {
+ return false;
+ }
+
+ ids.queryRealTime.start();
+
+ auto dnsCryptResponse = checkDNSCryptQuery(cs, query, ids.dnsCryptQuery, ids.queryRealTime.d_start.tv_sec, false);
+ if (dnsCryptResponse) {
+ packet.setPayload(query);
+ return true;
+ }
+
+ {
+ /* this pointer will be invalidated the second the buffer is resized, don't hold onto it! */
+ dnsheader_aligned dnsHeader(query.data());
+ queryId = ntohs(dnsHeader->id);
+
+ if (!checkQueryHeaders(*dnsHeader.get(), cs)) {
+ return false;
+ }
+
+ if (dnsHeader->qdcount == 0) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+ packet.setPayload(query);
+ return true;
+ }
+ }
+
+ ids.qname = DNSName(reinterpret_cast<const char*>(query.data()), query.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
+ if (ids.origDest.sin4.sin_family == 0) {
+ ids.origDest = cs.local;
+ }
+ if (ids.dnsCryptQuery) {
+ ids.protocol = dnsdist::Protocol::DNSCryptUDP;
+ }
+ DNSQuestion dq(ids, query);
+ if (!proxyProtocolValues.empty()) {
+ dq.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>(std::move(proxyProtocolValues));
+ }
+ std::shared_ptr<DownstreamState> ss{nullptr};
+ auto result = processQuery(dq, holders, ss);
+
+ if (result == ProcessQueryResult::Drop) {
+ return false;
+ }
+
+ if (result == ProcessQueryResult::SendAnswer) {
+ packet.setPayload(query);
+ if (dq.ids.delayMsec > 0) {
+ packet.addDelay(dq.ids.delayMsec);
+ }
+ const auto dh = dq.getHeader();
+ handleResponseSent(ids.qname, ids.qtype, 0., remote, ComboAddress(), query.size(), *dh, dnsdist::Protocol::DoUDP, dnsdist::Protocol::DoUDP, false);
+ return true;
+ }
+
+ if (result != ProcessQueryResult::PassToBackend || ss == nullptr) {
+ return false;
+ }
+
+ // the buffer might have been invalidated by now (resized)
+ const auto dh = dq.getHeader();
+ if (ss->isTCPOnly()) {
+ std::string proxyProtocolPayload;
+ /* we need to do this _before_ creating the cross protocol query because
+ after that the buffer will have been moved */
+ if (ss->d_config.useProxyProtocol) {
+ proxyProtocolPayload = getProxyProtocolPayload(dq);
+ }
+
+ ids.origID = dh->id;
+ auto cpq = std::make_unique<UDPCrossProtocolQuery>(std::move(query), std::move(ids), ss);
+ cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
+
+ ss->passCrossProtocolQuery(std::move(cpq));
+ return false;
+ }
+
+ if (ss->d_xskInfos.empty()) {
+ assignOutgoingUDPQueryToBackend(ss, dh->id, dq, query, true);
+ return false;
+ }
+ else {
+ assignOutgoingUDPQueryToBackend(ss, dh->id, dq, query, false);
+ auto sourceAddr = ss->pickSourceAddressForSending();
+ packet.setAddr(sourceAddr, ss->d_config.sourceMACAddr, ss->d_config.remote, ss->d_config.destMACAddr);
+ packet.setPayload(query);
+ packet.rewrite();
+ return true;
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Got an error in UDP question thread while parsing a query from %s, id %d: %s", remote.toStringWithPort(), queryId, e.what());
+ }
+ return false;
+}
+
+}
+#endif /* HAVE_XSK */
+
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holders)
@@ -1760,7 +2042,7 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde
- we use it for self-generated responses (from rule or cache)
but we only accept incoming payloads up to that size
*/
- const size_t initialBufferSize = getInitialUDPPacketBufferSize();
+ const size_t initialBufferSize = getInitialUDPPacketBufferSize(cs->d_enableProxyProtocol);
const size_t maxIncomingPacketSize = getMaximumIncomingPacketSize(*cs);
/* initialize the structures needed to receive our messages */
@@ -1799,7 +2081,7 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde
const ComboAddress& remote = recvData[msgIdx].remote;
if (static_cast<size_t>(got) < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++cs->nonCompliantQueries;
continue;
}
@@ -1850,7 +2132,7 @@ static void udpClientThread(std::vector<ClientState*> states)
size_t maxIncomingPacketSize{0};
int socket{-1};
};
- const size_t initialBufferSize = getInitialUDPPacketBufferSize();
+ const size_t initialBufferSize = getInitialUDPPacketBufferSize(true);
PacketBuffer packet(initialBufferSize);
struct msghdr msgh;
@@ -1866,7 +2148,7 @@ static void udpClientThread(std::vector<ClientState*> states)
ssize_t got = recvmsg(param.socket, &msgh, 0);
if (got < 0 || static_cast<size_t>(got) < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++param.cs->nonCompliantQueries;
return;
}
@@ -1883,7 +2165,7 @@ static void udpClientThread(std::vector<ClientState*> states)
}
if (params.size() == 1) {
- auto param = params.at(0);
+ const auto& param = params.at(0);
remote.sin4.sin_family = param.cs->local.sin4.sin_family;
/* used by HarvestDestinationAddress */
cmsgbuf_aligned cbuf;
@@ -1949,28 +2231,29 @@ pdns::stat16_t g_cacheCleaningPercentage{100};
static void maintThread()
{
setThreadName("dnsdist/main");
- int interval = 1;
+ constexpr int interval = 1;
size_t counter = 0;
int32_t secondsToWaitLog = 0;
for (;;) {
- sleep(interval);
+ std::this_thread::sleep_for(std::chrono::seconds(interval));
{
auto lua = g_lua.lock();
- auto f = lua->readVariable<boost::optional<std::function<void()> > >("maintenance");
- if (f) {
- try {
- (*f)();
- secondsToWaitLog = 0;
+ try {
+ auto maintenanceCallback = lua->readVariable<boost::optional<std::function<void()> > >("maintenance");
+ if (maintenanceCallback) {
+ (*maintenanceCallback)();
}
- catch(const std::exception &e) {
- if (secondsToWaitLog <= 0) {
- infolog("Error during execution of maintenance function: %s", e.what());
- secondsToWaitLog = 61;
- }
- secondsToWaitLog -= interval;
+ dnsdist::lua::hooks::runMaintenanceHooks(*lua);
+ secondsToWaitLog = 0;
+ }
+ catch (const std::exception &e) {
+ if (secondsToWaitLog <= 0) {
+ warnlog("Error during execution of maintenance function(s): %s", e.what());
+ secondsToWaitLog = 61;
}
+ secondsToWaitLog -= interval;
}
}
@@ -1984,7 +2267,7 @@ static void maintThread()
if something prevents us from cleaning the expired entries */
auto localPools = g_pools.getLocal();
for (const auto& entry : *localPools) {
- auto& pool = entry.second;
+ const auto& pool = entry.second;
auto packetCache = pool->packetCache;
if (!packetCache) {
@@ -1996,7 +2279,7 @@ static void maintThread()
/* if we need to keep stale data for this cache (ie, not clear
expired entries when at least one pool using this cache
has all its backends down) */
- if (packetCache->keepStaleData() && iter->second == false) {
+ if (packetCache->keepStaleData() && !iter->second) {
/* so far all pools had at least one backend up */
if (pool->countServers(true) == 0) {
iter->second = true;
@@ -2007,10 +2290,10 @@ static void maintThread()
const time_t now = time(nullptr);
for (const auto& pair : caches) {
/* shall we keep expired entries ? */
- if (pair.second == true) {
+ if (pair.second) {
continue;
}
- auto& packetCache = pair.first;
+ const auto& packetCache = pair.first;
size_t upTo = (packetCache->getMaxEntries()* (100 - g_cacheCleaningPercentage)) / 100;
packetCache->purgeExpired(upTo, now);
}
@@ -2070,11 +2353,7 @@ static void healthChecksThread()
std::unique_ptr<FDMultiplexer> mplexer{nullptr};
for (auto& dss : *states) {
- auto delta = dss->sw.udiffAndSet()/1000000.0;
- dss->queryLoad.store(1.0*(dss->queries.load() - dss->prev.queries.load())/delta);
- dss->dropRate.store(1.0*(dss->reuseds.load() - dss->prev.reuseds.load())/delta);
- dss->prev.queries.store(dss->queries.load());
- dss->prev.reuseds.store(dss->reuseds.load());
+ dss->updateStatisticsInfo();
dss->handleUDPTimeouts();
@@ -2124,9 +2403,9 @@ static void bindAny(int af, int sock)
static void dropGroupPrivs(gid_t gid)
{
- if (gid) {
+ if (gid != 0) {
if (setgid(gid) == 0) {
- if (setgroups(0, NULL) < 0) {
+ if (setgroups(0, nullptr) < 0) {
warnlog("Warning: Unable to drop supplementary gids: %s", stringerror());
}
}
@@ -2138,8 +2417,8 @@ static void dropGroupPrivs(gid_t gid)
static void dropUserPrivs(uid_t uid)
{
- if(uid) {
- if(setuid(uid) < 0) {
+ if (uid != 0) {
+ if (setuid(uid) < 0) {
warnlog("Warning: Unable to set user ID to %d: %s", uid, stringerror());
}
}
@@ -2197,145 +2476,185 @@ static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCoun
static bool g_warned_ipv6_recvpktinfo = false;
-static void setUpLocalBind(std::unique_ptr<ClientState>& cstate)
+static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr, int& socket, bool tcp, bool warn)
{
- auto setupSocket = [](ClientState& cs, const ComboAddress& addr, int& socket, bool tcp, bool warn) {
- (void) warn;
- socket = SSocket(addr.sin4.sin_family, tcp == false ? SOCK_DGRAM : SOCK_STREAM, 0);
+ (void) warn;
+ socket = SSocket(addr.sin4.sin_family, !tcp ? SOCK_DGRAM : SOCK_STREAM, 0);
- if (tcp) {
- SSetsockopt(socket, SOL_SOCKET, SO_REUSEADDR, 1);
+ if (tcp) {
+ SSetsockopt(socket, SOL_SOCKET, SO_REUSEADDR, 1);
#ifdef TCP_DEFER_ACCEPT
- SSetsockopt(socket, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
+ SSetsockopt(socket, IPPROTO_TCP, TCP_DEFER_ACCEPT, 1);
#endif
- if (cs.fastOpenQueueSize > 0) {
+ if (clientState.fastOpenQueueSize > 0) {
#ifdef TCP_FASTOPEN
- SSetsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, cs.fastOpenQueueSize);
+ SSetsockopt(socket, IPPROTO_TCP, TCP_FASTOPEN, clientState.fastOpenQueueSize);
#ifdef TCP_FASTOPEN_KEY
- if (!g_TCPFastOpenKey.empty()) {
- auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, g_TCPFastOpenKey.data(), g_TCPFastOpenKey.size() * sizeof(g_TCPFastOpenKey[0]));
- if (res == -1) {
- throw runtime_error("setsockopt for level IPPROTO_TCP and opname TCP_FASTOPEN_KEY failed: " + stringerror());
- }
+ if (!g_TCPFastOpenKey.empty()) {
+ auto res = setsockopt(socket, IPPROTO_IP, TCP_FASTOPEN_KEY, g_TCPFastOpenKey.data(), g_TCPFastOpenKey.size() * sizeof(g_TCPFastOpenKey[0]));
+ if (res == -1) {
+ throw runtime_error("setsockopt for level IPPROTO_TCP and opname TCP_FASTOPEN_KEY failed: " + stringerror());
}
+ }
#endif /* TCP_FASTOPEN_KEY */
#else /* TCP_FASTOPEN */
- if (warn) {
- warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", addr.toStringWithPort());
- }
-#endif /* TCP_FASTOPEN */
+ if (warn) {
+ warnlog("TCP Fast Open has been configured on local address '%s' but is not supported", addr.toStringWithPort());
}
+#endif /* TCP_FASTOPEN */
}
+ }
- if (addr.sin4.sin_family == AF_INET6) {
- SSetsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, 1);
- }
+ if (addr.sin4.sin_family == AF_INET6) {
+ SSetsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+ }
- bindAny(addr.sin4.sin_family, socket);
+ bindAny(addr.sin4.sin_family, socket);
- if (!tcp && IsAnyAddress(addr)) {
- int one = 1;
- (void) setsockopt(socket, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
+ if (!tcp && IsAnyAddress(addr)) {
+ int one = 1;
+ (void) setsockopt(socket, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
#ifdef IPV6_RECVPKTINFO
- if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 &&
- !g_warned_ipv6_recvpktinfo) {
- warnlog("Warning: IPV6_RECVPKTINFO setsockopt failed: %s", stringerror());
- g_warned_ipv6_recvpktinfo = true;
- }
-#endif
+ if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 &&
+ !g_warned_ipv6_recvpktinfo) {
+ warnlog("Warning: IPV6_RECVPKTINFO setsockopt failed: %s", stringerror());
+ g_warned_ipv6_recvpktinfo = true;
}
+#endif
+ }
- if (cs.reuseport) {
- if (!setReusePort(socket)) {
- if (warn) {
- /* no need to warn again if configured but support is not available, we already did for UDP */
- warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", addr.toStringWithPort());
- }
+ if (clientState.reuseport) {
+ if (!setReusePort(socket)) {
+ if (warn) {
+ /* no need to warn again if configured but support is not available, we already did for UDP */
+ warnlog("SO_REUSEPORT has been configured on local address '%s' but is not supported", addr.toStringWithPort());
}
}
+ }
+ const bool isQUIC = clientState.doqFrontend != nullptr || clientState.doh3Frontend != nullptr;
+ if (isQUIC) {
+ /* disable fragmentation and force PMTU discovery for QUIC-enabled sockets */
+ try {
+ setSocketForcePMTU(socket, addr.sin4.sin_family);
+ }
+ catch (const std::exception& e) {
+ warnlog("Failed to set IP_MTU_DISCOVER on QUIC server socket for local address '%s': %s", addr.toStringWithPort(), e.what());
+ }
+ }
+ else if (!tcp && !clientState.dnscryptCtx) {
/* Only set this on IPv4 UDP sockets.
Don't set it for DNSCrypt binds. DNSCrypt pads queries for privacy
purposes, so we do receive large, sometimes fragmented datagrams. */
- if (!tcp && !cs.dnscryptCtx) {
+ try {
+ setSocketIgnorePMTU(socket, addr.sin4.sin_family);
+ }
+ catch (const std::exception& e) {
+ warnlog("Failed to set IP_MTU_DISCOVER on UDP server socket for local address '%s': %s", addr.toStringWithPort(), e.what());
+ }
+ }
+
+ if (!tcp) {
+ if (g_socketUDPSendBuffer > 0) {
try {
- setSocketIgnorePMTU(socket, addr.sin4.sin_family);
+ setSocketSendBuffer(socket, g_socketUDPSendBuffer);
}
catch (const std::exception& e) {
- warnlog("Failed to set IP_MTU_DISCOVER on UDP server socket for local address '%s': %s", addr.toStringWithPort(), e.what());
+ warnlog(e.what());
}
- }
-
- if (!tcp) {
- if (g_socketUDPSendBuffer > 0) {
- try {
- setSocketSendBuffer(socket, g_socketUDPSendBuffer);
- }
- catch (const std::exception& e) {
- warnlog(e.what());
+ } else {
+ try {
+ auto result = raiseSocketSendBufferToMax(socket);
+ if (result > 0) {
+ infolog("Raised send buffer to %u for local address '%s'", result, addr.toStringWithPort());
}
+ } catch (const std::exception& e) {
+ warnlog(e.what());
}
+ }
- if (g_socketUDPRecvBuffer > 0) {
- try {
- setSocketReceiveBuffer(socket, g_socketUDPRecvBuffer);
- }
- catch (const std::exception& e) {
- warnlog(e.what());
+ if (g_socketUDPRecvBuffer > 0) {
+ try {
+ setSocketReceiveBuffer(socket, g_socketUDPRecvBuffer);
+ }
+ catch (const std::exception& e) {
+ warnlog(e.what());
+ }
+ } else {
+ try {
+ auto result = raiseSocketReceiveBufferToMax(socket);
+ if (result > 0) {
+ infolog("Raised receive buffer to %u for local address '%s'", result, addr.toStringWithPort());
}
+ } catch (const std::exception& e) {
+ warnlog(e.what());
}
}
+ }
- const std::string& itf = cs.interface;
- if (!itf.empty()) {
+ const std::string& itf = clientState.interface;
+ if (!itf.empty()) {
#ifdef SO_BINDTODEVICE
- int res = setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
- if (res != 0) {
- warnlog("Error setting up the interface on local address '%s': %s", addr.toStringWithPort(), stringerror());
- }
+ int res = setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, itf.c_str(), itf.length());
+ if (res != 0) {
+ warnlog("Error setting up the interface on local address '%s': %s", addr.toStringWithPort(), stringerror());
+ }
#else
- if (warn) {
- warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", addr.toStringWithPort());
- }
-#endif
+ if (warn) {
+ warnlog("An interface has been configured on local address '%s' but SO_BINDTODEVICE is not supported", addr.toStringWithPort());
}
+#endif
+ }
#ifdef HAVE_EBPF
- if (g_defaultBPFFilter && !g_defaultBPFFilter->isExternal()) {
- cs.attachFilter(g_defaultBPFFilter, socket);
- vinfolog("Attaching default BPF Filter to %s frontend %s", (!tcp ? "UDP" : "TCP"), addr.toStringWithPort());
- }
+ if (g_defaultBPFFilter && !g_defaultBPFFilter->isExternal()) {
+ clientState.attachFilter(g_defaultBPFFilter, socket);
+ vinfolog("Attaching default BPF Filter to %s frontend %s", (!tcp ? std::string("UDP") : std::string("TCP")), addr.toStringWithPort());
+ }
#endif /* HAVE_EBPF */
- SBind(socket, addr);
+ SBind(socket, addr);
- if (tcp) {
- SListen(socket, cs.tcpListenQueueSize);
+ if (tcp) {
+ SListen(socket, clientState.tcpListenQueueSize);
- if (cs.tlsFrontend != nullptr) {
- infolog("Listening on %s for TLS", addr.toStringWithPort());
- }
- else if (cs.dohFrontend != nullptr) {
- infolog("Listening on %s for DoH", addr.toStringWithPort());
- }
- else if (cs.dnscryptCtx != nullptr) {
- infolog("Listening on %s for DNSCrypt", addr.toStringWithPort());
- }
- else {
- infolog("Listening on %s", addr.toStringWithPort());
- }
+ if (clientState.tlsFrontend != nullptr) {
+ infolog("Listening on %s for TLS", addr.toStringWithPort());
}
- };
+ else if (clientState.dohFrontend != nullptr) {
+ infolog("Listening on %s for DoH", addr.toStringWithPort());
+ }
+ else if (clientState.dnscryptCtx != nullptr) {
+ infolog("Listening on %s for DNSCrypt", addr.toStringWithPort());
+ }
+ else {
+ infolog("Listening on %s", addr.toStringWithPort());
+ }
+ } else {
+ if (clientState.doqFrontend != nullptr) {
+ infolog("Listening on %s for DoQ", addr.toStringWithPort());
+ } else if (clientState.doh3Frontend != nullptr) {
+ infolog("Listening on %s for DoH3", addr.toStringWithPort());
+ }
+#ifdef HAVE_XSK
+ else if (clientState.xskInfo != nullptr) {
+ infolog("Listening on %s (XSK-enabled)", addr.toStringWithPort());
+ }
+#endif
+ }
+}
+static void setUpLocalBind(std::unique_ptr<ClientState>& cstate)
+{
/* skip some warnings if there is an identical UDP context */
- bool warn = cstate->tcp == false || cstate->tlsFrontend != nullptr || cstate->dohFrontend != nullptr;
- int& fd = cstate->tcp == false ? cstate->udpFD : cstate->tcpFD;
+ bool warn = !cstate->tcp || cstate->tlsFrontend != nullptr || cstate->dohFrontend != nullptr;
+ int& descriptor = !cstate->tcp ? cstate->udpFD : cstate->tcpFD;
(void) warn;
- setupSocket(*cstate, cstate->local, fd, cstate->tcp, warn);
+ setupLocalSocket(*cstate, cstate->local, descriptor, cstate->tcp, warn);
for (auto& [addr, socket] : cstate->d_additionalAddresses) {
- setupSocket(*cstate, addr, socket, true, false);
+ setupLocalSocket(*cstate, addr, socket, true, false);
}
if (cstate->tlsFrontend != nullptr) {
@@ -2348,6 +2667,12 @@ static void setUpLocalBind(std::unique_ptr<ClientState>& cstate)
if (cstate->dohFrontend != nullptr) {
cstate->dohFrontend->setup();
}
+ if (cstate->doqFrontend != nullptr) {
+ cstate->doqFrontend->setup();
+ }
+ if (cstate->doh3Frontend != nullptr) {
+ cstate->doh3Frontend->setup();
+ }
cstate->ready = true;
}
@@ -2379,7 +2704,7 @@ static void usage()
cout<<"-c,--client Operate as a client, connect to dnsdist. This reads\n";
cout<<" controlSocket from your configuration file, but also\n";
cout<<" accepts an IP:PORT argument\n";
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
cout<<"-k,--setkey KEY Use KEY for encrypted communication to dnsdist. This\n";
cout<<" is similar to setting setKey in the configuration file.\n";
cout<<" NOTE: this will leak this key in your shell's history\n";
@@ -2403,28 +2728,25 @@ static void usage()
}
#ifdef COVERAGE
-extern "C"
-{
- void __gcov_dump(void);
-}
-
static void cleanupLuaObjects()
{
- /* when our coverage mode is enabled, we need to make
- that the Lua objects destroyed before the Lua contexts. */
+ /* when our coverage mode is enabled, we need to make sure
+ that the Lua objects are destroyed before the Lua contexts. */
g_ruleactions.setState({});
g_respruleactions.setState({});
g_cachehitrespruleactions.setState({});
g_selfansweredrespruleactions.setState({});
g_dstates.setState({});
g_policy.setState(ServerPolicy());
+ g_pools.setState({});
clearWebHandlers();
+ dnsdist::lua::hooks::clearMaintenanceHooks();
}
static void sigTermHandler(int)
{
cleanupLuaObjects();
- __gcov_dump();
+ pdns::coverage::dumpCoverageData();
_exit(EXIT_SUCCESS);
}
#else /* COVERAGE */
@@ -2447,7 +2769,7 @@ static void sigTermHandler(int)
we crash trying to exit, but let's try to avoid the warnings
in our tests.
*/
- if (g_syslog) {
+ if (dnsdist::logging::LoggingConfiguration::getSyslog()) {
syslog(LOG_INFO, "Exiting on user request");
}
std::cout<<"Exiting on user request"<<std::endl;
@@ -2457,211 +2779,463 @@ static void sigTermHandler(int)
}
#endif /* COVERAGE */
-int main(int argc, char** argv)
+static void reportFeatures()
{
- try {
- size_t udpBindsCount = 0;
- size_t tcpBindsCount = 0;
-#ifdef HAVE_LIBEDIT
-#ifndef DISABLE_COMPLETION
- rl_attempted_completion_function = my_completion;
- rl_completion_append_character = 0;
-#endif /* DISABLE_COMPLETION */
-#endif /* HAVE_LIBEDIT */
-
- signal(SIGPIPE, SIG_IGN);
- signal(SIGCHLD, SIG_IGN);
- signal(SIGTERM, sigTermHandler);
-
- openlog("dnsdist", LOG_PID|LOG_NDELAY, LOG_DAEMON);
-
-#ifdef HAVE_LIBSODIUM
- if (sodium_init() == -1) {
- cerr<<"Unable to initialize crypto library"<<endl;
- exit(EXIT_FAILURE);
- }
-#endif
- dnsdist::initRandom();
- g_hashperturb = dnsdist::getRandomValue(0xffffffff);
-
- ComboAddress clientAddress = ComboAddress();
- g_cmdLine.config=SYSCONFDIR "/dnsdist.conf";
- struct option longopts[]={
- {"acl", required_argument, 0, 'a'},
- {"check-config", no_argument, 0, 1},
- {"client", no_argument, 0, 'c'},
- {"config", required_argument, 0, 'C'},
- {"disable-syslog", no_argument, 0, 2},
- {"execute", required_argument, 0, 'e'},
- {"gid", required_argument, 0, 'g'},
- {"help", no_argument, 0, 'h'},
- {"local", required_argument, 0, 'l'},
- {"log-timestamps", no_argument, 0, 4},
- {"setkey", required_argument, 0, 'k'},
- {"supervised", no_argument, 0, 3},
- {"uid", required_argument, 0, 'u'},
- {"verbose", no_argument, 0, 'v'},
- {"version", no_argument, 0, 'V'},
- {0,0,0,0}
- };
- int longindex=0;
- string optstring;
- for(;;) {
- int c=getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts, &longindex);
- if(c==-1)
- break;
- switch(c) {
- case 1:
- g_cmdLine.checkConfig=true;
- break;
- case 2:
- g_syslog=false;
- break;
- case 3:
- g_cmdLine.beSupervised=true;
- break;
- case 4:
- g_logtimestamps=true;
- break;
- case 'C':
- g_cmdLine.config=optarg;
- break;
- case 'c':
- g_cmdLine.beClient=true;
- break;
- case 'e':
- g_cmdLine.command=optarg;
- break;
- case 'g':
- g_cmdLine.gid=optarg;
- break;
- case 'h':
- cout<<"dnsdist "<<VERSION<<endl;
- usage();
- cout<<"\n";
- exit(EXIT_SUCCESS);
- break;
- case 'a':
- optstring=optarg;
- g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
- break;
- case 'k':
-#ifdef HAVE_LIBSODIUM
- if (B64Decode(string(optarg), g_consoleKey) < 0) {
- cerr<<"Unable to decode key '"<<optarg<<"'."<<endl;
- exit(EXIT_FAILURE);
- }
-#else
- cerr<<"dnsdist has been built without libsodium, -k/--setkey is unsupported."<<endl;
- exit(EXIT_FAILURE);
-#endif
- break;
- case 'l':
- g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
- break;
- case 'u':
- g_cmdLine.uid=optarg;
- break;
- case 'v':
- g_verbose=true;
- break;
- case 'V':
#ifdef LUAJIT_VERSION
- cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<" ["<<LUAJIT_VERSION<<"])"<<endl;
+ cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<" ["<<LUAJIT_VERSION<<"])"<<endl;
#else
- cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<")"<<endl;
+ cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<")"<<endl;
+#endif
+ cout<<"Enabled features: ";
+#ifdef HAVE_XSK
+ cout<<"AF_XDP ";
#endif
- cout<<"Enabled features: ";
#ifdef HAVE_CDB
- cout<<"cdb ";
+ cout<<"cdb ";
+#endif
+#ifdef HAVE_DNS_OVER_QUIC
+ cout<<"dns-over-quic ";
+#endif
+#ifdef HAVE_DNS_OVER_HTTP3
+ cout<<"dns-over-http3 ";
#endif
#ifdef HAVE_DNS_OVER_TLS
- cout<<"dns-over-tls(";
+ cout<<"dns-over-tls(";
#ifdef HAVE_GNUTLS
- cout<<"gnutls";
+ cout<<"gnutls";
#ifdef HAVE_LIBSSL
- cout<<" ";
-#endif
+ cout<<" ";
#endif
+#endif /* HAVE_GNUTLS */
#ifdef HAVE_LIBSSL
- cout<<"openssl";
-#endif
- cout<<") ";
+ cout<<"openssl";
#endif
+ cout<<") ";
+#endif /* HAVE_DNS_OVER_TLS */
#ifdef HAVE_DNS_OVER_HTTPS
- cout<<"dns-over-https(DOH) ";
-#endif
+ cout<<"dns-over-https(";
+#ifdef HAVE_LIBH2OEVLOOP
+ cout<<"h2o";
+#endif /* HAVE_LIBH2OEVLOOP */
+#if defined(HAVE_LIBH2OEVLOOP) && defined(HAVE_NGHTTP2)
+ cout<<" ";
+#endif /* defined(HAVE_LIBH2OEVLOOP) && defined(HAVE_NGHTTP2) */
+#ifdef HAVE_NGHTTP2
+ cout<<"nghttp2";
+#endif /* HAVE_NGHTTP2 */
+ cout<<") ";
+#endif /* HAVE_DNS_OVER_HTTPS */
#ifdef HAVE_DNSCRYPT
- cout<<"dnscrypt ";
+ cout<<"dnscrypt ";
#endif
#ifdef HAVE_EBPF
- cout<<"ebpf ";
+ cout<<"ebpf ";
#endif
#ifdef HAVE_FSTRM
- cout<<"fstrm ";
+ cout<<"fstrm ";
#endif
#ifdef HAVE_IPCIPHER
- cout<<"ipcipher ";
+ cout<<"ipcipher ";
#endif
#ifdef HAVE_LIBEDIT
- cout<<"libedit ";
+ cout<<"libedit ";
#endif
#ifdef HAVE_LIBSODIUM
- cout<<"libsodium ";
+ cout<<"libsodium ";
#endif
#ifdef HAVE_LMDB
- cout<<"lmdb ";
-#endif
-#ifdef HAVE_NGHTTP2
- cout<<"outgoing-dns-over-https(nghttp2) ";
+ cout<<"lmdb ";
#endif
#ifndef DISABLE_PROTOBUF
- cout<<"protobuf ";
+ cout<<"protobuf ";
#endif
#ifdef HAVE_RE2
- cout<<"re2 ";
+ cout<<"re2 ";
#endif
#ifndef DISABLE_RECVMMSG
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
- cout<<"recvmmsg/sendmmsg ";
+ cout<<"recvmmsg/sendmmsg ";
#endif
#endif /* DISABLE_RECVMMSG */
#ifdef HAVE_NET_SNMP
- cout<<"snmp ";
+ cout<<"snmp ";
#endif
#ifdef HAVE_SYSTEMD
- cout<<"systemd";
+ cout<<"systemd";
#endif
- cout<<endl;
- exit(EXIT_SUCCESS);
- break;
- case '?':
- //getopt_long printed an error message.
- usage();
+ cout<<endl;
+}
+
+static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
+{
+ const std::array<struct option,16> longopts{{
+ {"acl", required_argument, nullptr, 'a'},
+ {"check-config", no_argument, nullptr, 1},
+ {"client", no_argument, nullptr, 'c'},
+ {"config", required_argument, nullptr, 'C'},
+ {"disable-syslog", no_argument, nullptr, 2},
+ {"execute", required_argument, nullptr, 'e'},
+ {"gid", required_argument, nullptr, 'g'},
+ {"help", no_argument, nullptr, 'h'},
+ {"local", required_argument, nullptr, 'l'},
+ {"log-timestamps", no_argument, nullptr, 4},
+ {"setkey", required_argument, nullptr, 'k'},
+ {"supervised", no_argument, nullptr, 3},
+ {"uid", required_argument, nullptr, 'u'},
+ {"verbose", no_argument, nullptr, 'v'},
+ {"version", no_argument, nullptr, 'V'},
+ {nullptr, 0, nullptr, 0}
+ }};
+ int longindex = 0;
+ string optstring;
+ while (true) {
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ int gotChar = getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts.data(), &longindex);
+ if (gotChar == -1) {
+ break;
+ }
+ switch (gotChar) {
+ case 1:
+ g_cmdLine.checkConfig = true;
+ break;
+ case 2:
+ dnsdist::logging::LoggingConfiguration::setSyslog(false);
+ break;
+ case 3:
+ g_cmdLine.beSupervised = true;
+ break;
+ case 4:
+ dnsdist::logging::LoggingConfiguration::setLogTimestamps(true);
+ break;
+ case 'C':
+ g_cmdLine.config = optarg;
+ break;
+ case 'c':
+ g_cmdLine.beClient = true;
+ break;
+ case 'e':
+ g_cmdLine.command = optarg;
+ break;
+ case 'g':
+ g_cmdLine.gid = optarg;
+ break;
+ case 'h':
+ cout<<"dnsdist "<<VERSION<<endl;
+ usage();
+ cout<<"\n";
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ exit(EXIT_SUCCESS);
+ break;
+ case 'a':
+ optstring = optarg;
+ g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
+ break;
+ case 'k':
+#if defined HAVE_LIBSODIUM || defined(HAVE_LIBCRYPTO)
+ if (B64Decode(string(optarg), g_consoleKey) < 0) {
+ cerr<<"Unable to decode key '"<<optarg<<"'."<<endl;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
exit(EXIT_FAILURE);
- break;
}
+#else
+ cerr<<"dnsdist has been built without libsodium or libcrypto, -k/--setkey is unsupported."<<endl;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ exit(EXIT_FAILURE);
+#endif
+ break;
+ case 'l':
+ g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
+ break;
+ case 'u':
+ g_cmdLine.uid = optarg;
+ break;
+ case 'v':
+ g_verbose = true;
+ break;
+ case 'V':
+ reportFeatures();
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ exit(EXIT_SUCCESS);
+ break;
+ case '?':
+ //getopt_long printed an error message.
+ usage();
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
+ exit(EXIT_FAILURE);
+ break;
}
+ }
- argc -= optind;
- argv += optind;
- (void) argc;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): argv
+ argv += optind;
- for (auto p = argv; *p; ++p) {
- if(g_cmdLine.beClient) {
- clientAddress = ComboAddress(*p, 5199);
- } else {
- g_cmdLine.remotes.push_back(*p);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): argv
+ for (const auto* ptr = argv; *ptr != nullptr; ++ptr) {
+ if (g_cmdLine.beClient) {
+ clientAddress = ComboAddress(*ptr, 5199);
+ } else {
+ g_cmdLine.remotes.emplace_back(*ptr);
+ }
+ }
+}
+static void setupPools()
+{
+ auto pools = g_pools.getCopy();
+ {
+ bool precompute = false;
+ if (g_policy.getLocal()->getName() == "chashed") {
+ precompute = true;
+ } else {
+ for (const auto& entry: pools) {
+ if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
+ precompute = true;
+ break ;
+ }
}
}
+ if (precompute) {
+ vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
+ // pre compute hashes
+ auto backends = g_dstates.getLocal();
+ for (const auto& backend: *backends) {
+ if (backend->d_config.d_weight < 100) {
+ vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
+ }
+
+ backend->hash();
+ }
+ }
+ }
+}
+
+static void dropPrivileges()
+{
+ uid_t newgid = getegid();
+ gid_t newuid = geteuid();
+
+ if (!g_cmdLine.gid.empty()) {
+ newgid = strToGID(g_cmdLine.gid);
+ }
+
+ if (!g_cmdLine.uid.empty()) {
+ newuid = strToUID(g_cmdLine.uid);
+ }
+
+ bool retainedCapabilities = true;
+ if (!g_capabilitiesToRetain.empty() &&
+ (getegid() != newgid || geteuid() != newuid)) {
+ retainedCapabilities = keepCapabilitiesAfterSwitchingIDs();
+ }
+
+ if (getegid() != newgid) {
+ if (running_in_service_mgr()) {
+ errlog("--gid/-g set on command-line, but dnsdist was started as a systemd service. Use the 'Group' setting in the systemd unit file to set the group to run as");
+ _exit(EXIT_FAILURE);
+ }
+ dropGroupPrivs(newgid);
+ }
+
+ if (geteuid() != newuid) {
+ if (running_in_service_mgr()) {
+ errlog("--uid/-u set on command-line, but dnsdist was started as a systemd service. Use the 'User' setting in the systemd unit file to set the user to run as");
+ _exit(EXIT_FAILURE);
+ }
+ dropUserPrivs(newuid);
+ }
+
+ if (retainedCapabilities) {
+ dropCapabilitiesAfterSwitchingIDs();
+ }
+
+ try {
+ /* we might still have capabilities remaining,
+ for example if we have been started as root
+ without --uid or --gid (please don't do that)
+ or as an unprivileged user with ambient
+ capabilities like CAP_NET_BIND_SERVICE.
+ */
+ dropCapabilities(g_capabilitiesToRetain);
+ }
+ catch (const std::exception& e) {
+ warnlog("%s", e.what());
+ }
+}
+
+static void initFrontends()
+{
+ if (!g_cmdLine.locals.empty()) {
+ for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+ /* DoH, DoT and DNSCrypt frontends are separate */
+ if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr && (*it)->doqFrontend == nullptr && (*it)->doh3Frontend == nullptr) {
+ it = g_frontends.erase(it);
+ }
+ else {
+ ++it;
+ }
+ }
+
+ for (const auto& loc : g_cmdLine.locals) {
+ /* UDP */
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), false, false, 0, "", std::set<int>{}, true));
+ /* TCP */
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress(loc, 53), true, false, 0, "", std::set<int>{}, true));
+ }
+ }
+
+ if (g_frontends.empty()) {
+ /* UDP */
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), false, false, 0, "", std::set<int>{}, true));
+ /* TCP */
+ g_frontends.emplace_back(std::make_unique<ClientState>(ComboAddress("127.0.0.1", 53), true, false, 0, "", std::set<int>{}, true));
+ }
+}
+
+namespace dnsdist
+{
+static void startFrontends()
+{
+#ifdef HAVE_XSK
+ for (auto& xskContext : dnsdist::xsk::g_xsk) {
+ std::thread xskThread(dnsdist::xsk::XskRouter, std::move(xskContext));
+ xskThread.detach();
+ }
+#endif /* HAVE_XSK */
+
+ std::vector<ClientState*> tcpStates;
+ std::vector<ClientState*> udpStates;
+ for (auto& clientState : g_frontends) {
+#ifdef HAVE_XSK
+ if (clientState->xskInfo) {
+ dnsdist::xsk::addDestinationAddress(clientState->local);
+
+ std::thread xskCT(dnsdist::xsk::XskClientThread, clientState.get());
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(xskCT.native_handle(), clientState->cpus);
+ }
+ xskCT.detach();
+ }
+#endif /* HAVE_XSK */
+
+ if (clientState->dohFrontend != nullptr && clientState->dohFrontend->d_library == "h2o") {
+#ifdef HAVE_DNS_OVER_HTTPS
+#ifdef HAVE_LIBH2OEVLOOP
+ std::thread dotThreadHandle(dohThread, clientState.get());
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(dotThreadHandle.native_handle(), clientState->cpus);
+ }
+ dotThreadHandle.detach();
+#endif /* HAVE_LIBH2OEVLOOP */
+#endif /* HAVE_DNS_OVER_HTTPS */
+ continue;
+ }
+ if (clientState->doqFrontend != nullptr) {
+#ifdef HAVE_DNS_OVER_QUIC
+ std::thread doqThreadHandle(doqThread, clientState.get());
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(doqThreadHandle.native_handle(), clientState->cpus);
+ }
+ doqThreadHandle.detach();
+#endif /* HAVE_DNS_OVER_QUIC */
+ continue;
+ }
+ if (clientState->doh3Frontend != nullptr) {
+#ifdef HAVE_DNS_OVER_HTTP3
+ std::thread doh3ThreadHandle(doh3Thread, clientState.get());
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(doh3ThreadHandle.native_handle(), clientState->cpus);
+ }
+ doh3ThreadHandle.detach();
+#endif /* HAVE_DNS_OVER_HTTP3 */
+ continue;
+ }
+ if (clientState->udpFD >= 0) {
+#ifdef USE_SINGLE_ACCEPTOR_THREAD
+ udpStates.push_back(clientState.get());
+#else /* USE_SINGLE_ACCEPTOR_THREAD */
+ std::thread udpClientThreadHandle(udpClientThread, std::vector<ClientState*>{ clientState.get() });
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(udpClientThreadHandle.native_handle(), clientState->cpus);
+ }
+ udpClientThreadHandle.detach();
+#endif /* USE_SINGLE_ACCEPTOR_THREAD */
+ }
+ else if (clientState->tcpFD >= 0) {
+#ifdef USE_SINGLE_ACCEPTOR_THREAD
+ tcpStates.push_back(clientState.get());
+#else /* USE_SINGLE_ACCEPTOR_THREAD */
+ std::thread tcpAcceptorThreadHandle(tcpAcceptorThread, std::vector<ClientState*>{clientState.get() });
+ if (!clientState->cpus.empty()) {
+ mapThreadToCPUList(tcpAcceptorThreadHandle.native_handle(), clientState->cpus);
+ }
+ tcpAcceptorThreadHandle.detach();
+#endif /* USE_SINGLE_ACCEPTOR_THREAD */
+ }
+ }
+#ifdef USE_SINGLE_ACCEPTOR_THREAD
+ if (!udpStates.empty()) {
+ std::thread udpThreadHandle(udpClientThread, udpStates);
+ udpThreadHandle.detach();
+ }
+ if (!tcpStates.empty()) {
+ g_tcpclientthreads = std::make_unique<TCPClientCollection>(1, tcpStates);
+ }
+#endif /* USE_SINGLE_ACCEPTOR_THREAD */
+}
+}
+
+int main(int argc, char** argv)
+{
+ try {
+ size_t udpBindsCount = 0;
+ size_t tcpBindsCount = 0;
+#ifdef HAVE_LIBEDIT
+#ifndef DISABLE_COMPLETION
+ rl_attempted_completion_function = my_completion;
+ rl_completion_append_character = 0;
+#endif /* DISABLE_COMPLETION */
+#endif /* HAVE_LIBEDIT */
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast): SIG_IGN macro
+ signal(SIGPIPE, SIG_IGN);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast): SIG_IGN macro
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGTERM, sigTermHandler);
+
+ openlog("dnsdist", LOG_PID|LOG_NDELAY, LOG_DAEMON);
+
+#ifdef HAVE_LIBSODIUM
+ if (sodium_init() == -1) {
+ cerr<<"Unable to initialize crypto library"<<endl;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): only on thread at this point
+ exit(EXIT_FAILURE);
+ }
+#endif
+ dnsdist::initRandom();
+ g_hashperturb = dnsdist::getRandomValue(0xffffffff);
+
+#ifdef HAVE_XSK
+ try {
+ dnsdist::xsk::clearDestinationAddresses();
+ }
+ catch (const std::exception& exp) {
+ /* silently handle failures: at this point we don't even know if XSK is enabled,
+ and we might not have the correct map (not the default one). */
+ }
+#endif /* HAVE_XSK */
+
+ ComboAddress clientAddress = ComboAddress();
+ g_cmdLine.config=SYSCONFDIR "/dnsdist.conf";
+
+ parseParameters(argc, argv, clientAddress);
ServerPolicy leastOutstandingPol{"leastOutstanding", leastOutstanding, false};
g_policy.setState(leastOutstandingPol);
if (g_cmdLine.beClient || !g_cmdLine.command.empty()) {
setupLua(*(g_lua.lock()), true, false, g_cmdLine.config);
- if (clientAddress != ComboAddress())
+ if (clientAddress != ComboAddress()) {
g_serverControl = clientAddress;
+ }
doClient(g_serverControl, g_cmdLine.command);
#ifdef COVERAGE
exit(EXIT_SUCCESS);
@@ -2671,9 +3245,10 @@ int main(int argc, char** argv)
}
auto acl = g_ACL.getCopy();
- if(acl.empty()) {
- for(auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"})
+ if (acl.empty()) {
+ for (const auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"}) {
acl.addMask(addr);
+ }
g_ACL.setState(acl);
}
@@ -2702,67 +3277,18 @@ int main(int argc, char** argv)
auto todo = setupLua(*(g_lua.lock()), false, false, g_cmdLine.config);
- auto localPools = g_pools.getCopy();
- {
- bool precompute = false;
- if (g_policy.getLocal()->getName() == "chashed") {
- precompute = true;
- } else {
- for (const auto& entry: localPools) {
- if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") {
- precompute = true;
- break ;
- }
- }
- }
- if (precompute) {
- vinfolog("Pre-computing hashes for consistent hash load-balancing policy");
- // pre compute hashes
- auto backends = g_dstates.getLocal();
- for (auto& backend: *backends) {
- if (backend->d_config.d_weight < 100) {
- vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->d_config.d_weight);
- }
-
- backend->hash();
- }
- }
- }
-
- if (!g_cmdLine.locals.empty()) {
- for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
- /* DoH, DoT and DNSCrypt frontends are separate */
- if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
- it = g_frontends.erase(it);
- }
- else {
- ++it;
- }
- }
+ setupPools();
- for (const auto& loc : g_cmdLine.locals) {
- /* UDP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {})));
- /* TCP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {})));
- }
- }
-
- if (g_frontends.empty()) {
- /* UDP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {})));
- /* TCP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {})));
- }
+ initFrontends();
g_configurationDone = true;
g_rings.init();
- for(auto& frontend : g_frontends) {
+ for (auto& frontend : g_frontends) {
setUpLocalBind(frontend);
- if (frontend->tcp == false) {
+ if (!frontend->tcp) {
++udpBindsCount;
}
else {
@@ -2770,88 +3296,43 @@ int main(int argc, char** argv)
}
}
- vector<string> vec;
- std::string acls;
- g_ACL.getLocal()->toStringVector(&vec);
- for(const auto& s : vec) {
- if (!acls.empty())
- acls += ", ";
- acls += s;
+ {
+ std::string acls;
+ auto aclEntries = g_ACL.getLocal()->toStringVector();
+ for (const auto& aclEntry : aclEntries) {
+ if (!acls.empty()) {
+ acls += ", ";
+ }
+ acls += aclEntry;
+ }
+ infolog("ACL allowing queries from: %s", acls);
}
- infolog("ACL allowing queries from: %s", acls.c_str());
- vec.clear();
- acls.clear();
- g_consoleACL.getLocal()->toStringVector(&vec);
- for (const auto& entry : vec) {
- if (!acls.empty()) {
- acls += ", ";
+ {
+ std::string acls;
+ auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+ for (const auto& entry : aclEntries) {
+ if (!acls.empty()) {
+ acls += ", ";
+ }
+ acls += entry;
}
- acls += entry;
+ infolog("Console ACL allowing connections from: %s", acls.c_str());
}
- infolog("Console ACL allowing connections from: %s", acls.c_str());
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
if (g_consoleEnabled && g_consoleKey.empty()) {
warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
}
#endif
- uid_t newgid=getegid();
- gid_t newuid=geteuid();
-
- if (!g_cmdLine.gid.empty()) {
- newgid = strToGID(g_cmdLine.gid);
- }
-
- if (!g_cmdLine.uid.empty()) {
- newuid = strToUID(g_cmdLine.uid);
- }
-
- bool retainedCapabilities = true;
- if (!g_capabilitiesToRetain.empty() &&
- (getegid() != newgid || geteuid() != newuid)) {
- retainedCapabilities = keepCapabilitiesAfterSwitchingIDs();
- }
-
- if (getegid() != newgid) {
- if (running_in_service_mgr()) {
- errlog("--gid/-g set on command-line, but dnsdist was started as a systemd service. Use the 'Group' setting in the systemd unit file to set the group to run as");
- _exit(EXIT_FAILURE);
- }
- dropGroupPrivs(newgid);
- }
-
- if (geteuid() != newuid) {
- if (running_in_service_mgr()) {
- errlog("--uid/-u set on command-line, but dnsdist was started as a systemd service. Use the 'User' setting in the systemd unit file to set the user to run as");
- _exit(EXIT_FAILURE);
- }
- dropUserPrivs(newuid);
- }
-
- if (retainedCapabilities) {
- dropCapabilitiesAfterSwitchingIDs();
- }
-
- try {
- /* we might still have capabilities remaining,
- for example if we have been started as root
- without --uid or --gid (please don't do that)
- or as an unprivileged user with ambient
- capabilities like CAP_NET_BIND_SERVICE.
- */
- dropCapabilities(g_capabilitiesToRetain);
- }
- catch (const std::exception& e) {
- warnlog("%s", e.what());
- }
+ dropPrivileges();
/* this need to be done _after_ dropping privileges */
#ifndef DISABLE_DELAY_PIPE
- g_delay = new DelayPipe<DelayedPacket>();
+ g_delay = std::make_unique<DelayPipe<DelayedPacket>>();
#endif /* DISABLE_DELAY_PIPE */
- if (g_snmpAgent) {
+ if (g_snmpAgent != nullptr) {
g_snmpAgent->run();
}
@@ -2870,16 +3351,18 @@ int main(int argc, char** argv)
g_tcpclientthreads = std::make_unique<TCPClientCollection>(*g_maxTCPClientThreads, std::vector<ClientState*>());
#endif
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
initDoHWorkers();
+#endif
- for (auto& t : todo) {
- t();
+ for (auto& todoItem : todo) {
+ todoItem();
}
- localPools = g_pools.getCopy();
+ auto localPools = g_pools.getCopy();
/* create the default pool no matter what */
createPoolIfNotExists(localPools, "");
- if (g_cmdLine.remotes.size()) {
+ if (!g_cmdLine.remotes.empty()) {
for (const auto& address : g_cmdLine.remotes) {
DownstreamState::Config config;
config.remote = ComboAddress(address, 53);
@@ -2902,12 +3385,14 @@ int main(int argc, char** argv)
auto states = g_dstates.getCopy(); // it is a copy, but the internal shared_ptrs are the real deal
auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent(states.size()));
for (auto& dss : states) {
+
if (dss->d_config.availability == DownstreamState::Availability::Auto || dss->d_config.availability == DownstreamState::Availability::Lazy) {
if (dss->d_config.availability == DownstreamState::Availability::Auto) {
dss->d_nextCheck = dss->d_config.checkInterval;
}
if (!queueHealthCheck(mplexer, dss, true)) {
+ dss->submitHealthCheckResult(true, false);
dss->setUpStatus(false);
warnlog("Marking downstream %s as 'down'", dss->getNameWithAddr());
}
@@ -2916,51 +3401,8 @@ int main(int argc, char** argv)
handleQueuedHealthChecks(*mplexer, true);
}
- std::vector<ClientState*> tcpStates;
- std::vector<ClientState*> udpStates;
- for(auto& cs : g_frontends) {
- if (cs->dohFrontend != nullptr) {
-#ifdef HAVE_DNS_OVER_HTTPS
- std::thread t1(dohThread, cs.get());
- if (!cs->cpus.empty()) {
- mapThreadToCPUList(t1.native_handle(), cs->cpus);
- }
- t1.detach();
-#endif /* HAVE_DNS_OVER_HTTPS */
- continue;
- }
- if (cs->udpFD >= 0) {
-#ifdef USE_SINGLE_ACCEPTOR_THREAD
- udpStates.push_back(cs.get());
-#else /* USE_SINGLE_ACCEPTOR_THREAD */
- thread t1(udpClientThread, std::vector<ClientState*>{ cs.get() });
- if (!cs->cpus.empty()) {
- mapThreadToCPUList(t1.native_handle(), cs->cpus);
- }
- t1.detach();
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
- }
- else if (cs->tcpFD >= 0) {
-#ifdef USE_SINGLE_ACCEPTOR_THREAD
- tcpStates.push_back(cs.get());
-#else /* USE_SINGLE_ACCEPTOR_THREAD */
- thread t1(tcpAcceptorThread, std::vector<ClientState*>{cs.get() });
- if (!cs->cpus.empty()) {
- mapThreadToCPUList(t1.native_handle(), cs->cpus);
- }
- t1.detach();
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
- }
- }
-#ifdef USE_SINGLE_ACCEPTOR_THREAD
- if (!udpStates.empty()) {
- thread udp(udpClientThread, udpStates);
- udp.detach();
- }
- if (!tcpStates.empty()) {
- g_tcpclientthreads = std::make_unique<TCPClientCollection>(1, tcpStates);
- }
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
+ dnsdist::startFrontends();
+
dnsdist::ServiceDiscovery::run();
#ifndef DISABLE_CARBON
@@ -3013,6 +3455,7 @@ int main(int argc, char** argv)
errlog("Fatal pdns error: %s", ae.reason);
}
#ifdef COVERAGE
+ cleanupLuaObjects();
exit(EXIT_FAILURE);
#else
_exit(EXIT_FAILURE);
@@ -3022,6 +3465,7 @@ int main(int argc, char** argv)
{
errlog("Fatal error: %s", e.what());
#ifdef COVERAGE
+ cleanupLuaObjects();
exit(EXIT_FAILURE);
#else
_exit(EXIT_FAILURE);
@@ -3031,6 +3475,7 @@ int main(int argc, char** argv)
{
errlog("Fatal pdns error: %s", ae.reason);
#ifdef COVERAGE
+ cleanupLuaObjects();
exit(EXIT_FAILURE);
#else
_exit(EXIT_FAILURE);
diff --git a/dnsdist.conf-dist b/dnsdist.conf-dist
index 2b218d5..93e061b 100644
--- a/dnsdist.conf-dist
+++ b/dnsdist.conf-dist
@@ -60,14 +60,14 @@
-- send the queries for selected domain suffixes to the servers
-- in the 'abuse' pool
--- addAction({"abuse.example.org.", "xxx."}, PoolAction("abuse"))
+-- addAction(SuffixMatchNodeRule({"abuse.example.org.", "xxx."}), PoolAction("abuse"))
-- drop queries for this exact qname
-- addAction(QNameRule("drop-me.example.org."), DropAction())
-- send the queries from a selected subnet to the
-- abuse pool
--- addAction("192.0.2.0/24", PoolAction("abuse"))
+-- addAction(NetmaskGroupRule("192.0.2.0/24"), PoolAction("abuse"))
-- Refuse incoming AXFR, IXFR, NOTIFY and UPDATE
-- Add trusted sources (slaves, masters) explicitely in front of this rule
diff --git a/dnsdist.hh b/dnsdist.hh
index 1f7b4e8..777b27a 100644
--- a/dnsdist.hh
+++ b/dnsdist.hh
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
+
#include "config.h"
#include "ext/luawrapper/include/LuaContext.hpp"
@@ -42,7 +43,9 @@
#include "dnsdist-lbpolicies.hh"
#include "dnsdist-protocols.hh"
#include "dnsname.hh"
-#include "doh.hh"
+#include "dnsdist-doh-common.hh"
+#include "doq.hh"
+#include "doh3.hh"
#include "ednsoptions.hh"
#include "iputils.hh"
#include "misc.hh"
@@ -87,20 +90,26 @@ struct DNSQuestion
return data;
}
- dnsheader* getHeader()
+ bool editHeader(const std::function<bool(dnsheader&)>& editFunction);
+
+ const dnsheader_aligned getHeader() const
{
if (data.size() < sizeof(dnsheader)) {
throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
}
- return reinterpret_cast<dnsheader*>(&data.at(0));
+ dnsheader_aligned dh(data.data());
+ return dh;
}
- const dnsheader* getHeader() const
+ /* this function is not safe against unaligned access, you should
+ use editHeader() instead, but we need it for the Lua bindings */
+ dnsheader* getMutableHeader() const
{
if (data.size() < sizeof(dnsheader)) {
throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
}
- return reinterpret_cast<const dnsheader*>(&data.at(0));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<dnsheader*>(data.data());
}
bool hasRoomFor(size_t more) const
@@ -140,6 +149,13 @@ struct DNSQuestion
ids.qTag->insert_or_assign(key, value);
}
+ void setTag(const std::string& key, std::string&& value) {
+ if (!ids.qTag) {
+ ids.qTag = std::make_unique<QTag>();
+ }
+ ids.qTag->insert_or_assign(key, std::move(value));
+ }
+
const struct timespec& getQueryRealTime() const
{
return ids.queryRealTime.d_start;
@@ -258,7 +274,7 @@ public:
class DNSResponseAction
{
public:
- enum class Action : uint8_t { Allow, Delay, Drop, HeaderModify, ServFail, None };
+ enum class Action : uint8_t { Allow, Delay, Drop, HeaderModify, ServFail, Truncate, None };
virtual Action operator()(DNSResponse*, string* ruleresult) const =0;
virtual ~DNSResponseAction()
{
@@ -330,156 +346,6 @@ extern vector<pair<struct timeval, std::string> > g_confDelta;
using pdns::stat_t;
-struct DNSDistStats
-{
- stat_t responses{0};
- stat_t servfailResponses{0};
- stat_t queries{0};
- stat_t frontendNXDomain{0};
- stat_t frontendServFail{0};
- stat_t frontendNoError{0};
- stat_t nonCompliantQueries{0};
- stat_t nonCompliantResponses{0};
- stat_t rdQueries{0};
- stat_t emptyQueries{0};
- stat_t aclDrops{0};
- stat_t dynBlocked{0};
- stat_t ruleDrop{0};
- stat_t ruleNXDomain{0};
- stat_t ruleRefused{0};
- stat_t ruleServFail{0};
- stat_t ruleTruncated{0};
- stat_t selfAnswered{0};
- stat_t downstreamTimeouts{0};
- stat_t downstreamSendErrors{0};
- stat_t truncFail{0};
- stat_t noPolicy{0};
- stat_t cacheHits{0};
- stat_t cacheMisses{0};
- stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0}, latencySum{0}, latencyCount{0};
- stat_t securityStatus{0};
- stat_t dohQueryPipeFull{0};
- stat_t dohResponsePipeFull{0};
- stat_t outgoingDoHQueryPipeFull{0};
- stat_t proxyProtocolInvalid{0};
- stat_t tcpQueryPipeFull{0};
- stat_t tcpCrossProtocolQueryPipeFull{0};
- stat_t tcpCrossProtocolResponsePipeFull{0};
- double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
- double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
- double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
- double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
- using statfunction_t = std::function<uint64_t(const std::string&)>;
- using entry_t = boost::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
- struct EntryPair
- {
- std::string d_name;
- entry_t d_value;
- };
-
- SharedLockGuarded<std::vector<EntryPair>> entries{std::vector<EntryPair>{
- {"responses", &responses},
- {"servfail-responses", &servfailResponses},
- {"queries", &queries},
- {"frontend-nxdomain", &frontendNXDomain},
- {"frontend-servfail", &frontendServFail},
- {"frontend-noerror", &frontendNoError},
- {"acl-drops", &aclDrops},
- {"rule-drop", &ruleDrop},
- {"rule-nxdomain", &ruleNXDomain},
- {"rule-refused", &ruleRefused},
- {"rule-servfail", &ruleServFail},
- {"rule-truncated", &ruleTruncated},
- {"self-answered", &selfAnswered},
- {"downstream-timeouts", &downstreamTimeouts},
- {"downstream-send-errors", &downstreamSendErrors},
- {"trunc-failures", &truncFail},
- {"no-policy", &noPolicy},
- {"latency0-1", &latency0_1},
- {"latency1-10", &latency1_10},
- {"latency10-50", &latency10_50},
- {"latency50-100", &latency50_100},
- {"latency100-1000", &latency100_1000},
- {"latency-slow", &latencySlow},
- {"latency-avg100", &latencyAvg100},
- {"latency-avg1000", &latencyAvg1000},
- {"latency-avg10000", &latencyAvg10000},
- {"latency-avg1000000", &latencyAvg1000000},
- {"latency-tcp-avg100", &latencyTCPAvg100},
- {"latency-tcp-avg1000", &latencyTCPAvg1000},
- {"latency-tcp-avg10000", &latencyTCPAvg10000},
- {"latency-tcp-avg1000000", &latencyTCPAvg1000000},
- {"latency-dot-avg100", &latencyDoTAvg100},
- {"latency-dot-avg1000", &latencyDoTAvg1000},
- {"latency-dot-avg10000", &latencyDoTAvg10000},
- {"latency-dot-avg1000000", &latencyDoTAvg1000000},
- {"latency-doh-avg100", &latencyDoHAvg100},
- {"latency-doh-avg1000", &latencyDoHAvg1000},
- {"latency-doh-avg10000", &latencyDoHAvg10000},
- {"latency-doh-avg1000000", &latencyDoHAvg1000000},
- {"uptime", uptimeOfProcess},
- {"real-memory-usage", getRealMemoryUsage},
- {"special-memory-usage", getSpecialMemoryUsage},
- {"udp-in-errors", std::bind(udpErrorStats, "udp-in-errors")},
- {"udp-noport-errors", std::bind(udpErrorStats, "udp-noport-errors")},
- {"udp-recvbuf-errors", std::bind(udpErrorStats, "udp-recvbuf-errors")},
- {"udp-sndbuf-errors", std::bind(udpErrorStats, "udp-sndbuf-errors")},
- {"udp-in-csum-errors", std::bind(udpErrorStats, "udp-in-csum-errors")},
- {"udp6-in-errors", std::bind(udp6ErrorStats, "udp6-in-errors")},
- {"udp6-recvbuf-errors", std::bind(udp6ErrorStats, "udp6-recvbuf-errors")},
- {"udp6-sndbuf-errors", std::bind(udp6ErrorStats, "udp6-sndbuf-errors")},
- {"udp6-noport-errors", std::bind(udp6ErrorStats, "udp6-noport-errors")},
- {"udp6-in-csum-errors", std::bind(udp6ErrorStats, "udp6-in-csum-errors")},
- {"tcp-listen-overflows", std::bind(tcpErrorStats, "ListenOverflows")},
- {"noncompliant-queries", &nonCompliantQueries},
- {"noncompliant-responses", &nonCompliantResponses},
- {"proxy-protocol-invalid", &proxyProtocolInvalid},
- {"rdqueries", &rdQueries},
- {"empty-queries", &emptyQueries},
- {"cache-hits", &cacheHits},
- {"cache-misses", &cacheMisses},
- {"cpu-iowait", getCPUIOWait},
- {"cpu-steal", getCPUSteal},
- {"cpu-sys-msec", getCPUTimeSystem},
- {"cpu-user-msec", getCPUTimeUser},
- {"fd-usage", getOpenFileDescriptors},
- {"dyn-blocked", &dynBlocked},
- {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
- {"security-status", &securityStatus},
- {"doh-query-pipe-full", &dohQueryPipeFull},
- {"doh-response-pipe-full", &dohResponsePipeFull},
- {"outgoing-doh-query-pipe-full", &outgoingDoHQueryPipeFull},
- {"tcp-query-pipe-full", &tcpQueryPipeFull},
- {"tcp-cross-protocol-query-pipe-full", &tcpCrossProtocolQueryPipeFull},
- {"tcp-cross-protocol-response-pipe-full", &tcpCrossProtocolResponsePipeFull},
- // Latency histogram
- {"latency-sum", &latencySum},
- {"latency-count", &latencyCount},
- }};
- struct MutableCounter
- {
- MutableCounter() = default;
- MutableCounter(MutableCounter&& rhs): d_value(rhs.d_value.load())
- {
- }
-
- mutable stat_t d_value{0};
- };
- struct MutableGauge
- {
- MutableGauge() = default;
- MutableGauge(MutableGauge&& rhs): d_value(rhs.d_value.load())
- {
- }
-
- mutable pdns::stat_t_trait<double> d_value{0};
- };
- SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> customCounters;
- SharedLockGuarded<std::map<std::string, MutableGauge, std::less<>>> customGauges;
-};
-
-extern struct DNSDistStats g_stats;
-
class BasicQPSLimiter
{
public:
@@ -605,9 +471,13 @@ struct QueryCount {
extern QueryCount g_qcount;
+class XskPacket;
+class XskSocket;
+class XskWorker;
+
struct ClientState
{
- ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_): cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort)
+ ClientState(const ComboAddress& local_, bool isTCP_, bool doReusePort, int fastOpenQueue, const std::string& itfName, const std::set<int>& cpus_, bool enableProxyProtocol): cpus(cpus_), interface(itfName), local(local_), fastOpenQueueSize(fastOpenQueue), tcp(isTCP_), reuseport(doReusePort), d_enableProxyProtocol(enableProxyProtocol)
{
}
@@ -642,7 +512,10 @@ struct ClientState
std::shared_ptr<DNSCryptContext> dnscryptCtx{nullptr};
std::shared_ptr<TLSFrontend> tlsFrontend{nullptr};
std::shared_ptr<DOHFrontend> dohFrontend{nullptr};
+ std::shared_ptr<DOQFrontend> doqFrontend{nullptr};
+ std::shared_ptr<DOH3Frontend> doh3Frontend{nullptr};
std::shared_ptr<BPFFilter> d_filter{nullptr};
+ std::shared_ptr<XskWorker> xskInfo{nullptr};
size_t d_maxInFlightQueriesPerConn{1};
size_t d_tcpConcurrentConnectionsLimit{0};
int udpFD{-1};
@@ -652,6 +525,7 @@ struct ClientState
bool muted{false};
bool tcp;
bool reuseport;
+ bool d_enableProxyProtocol{true}; // the global proxy protocol ACL still applies
bool ready{false};
int getSocket() const
@@ -679,6 +553,17 @@ struct ClientState
return tlsFrontend != nullptr || (dohFrontend != nullptr && dohFrontend->isHTTPS());
}
+ const TLSFrontend& getTLSFrontend() const
+ {
+ if (tlsFrontend != nullptr) {
+ return *tlsFrontend;
+ }
+ if (dohFrontend) {
+ return dohFrontend->d_tlsContext;
+ }
+ throw std::runtime_error("Trying to get a TLS frontend from a non-TLS ClientState");
+ }
+
dnsdist::Protocol getProtocol() const
{
if (dnscryptCtx) {
@@ -693,6 +578,12 @@ struct ClientState
else if (hasTLS()) {
return dnsdist::Protocol::DoT;
}
+ else if (doqFrontend != nullptr) {
+ return dnsdist::Protocol::DoQ;
+ }
+ else if (doh3Frontend != nullptr) {
+ return dnsdist::Protocol::DoH3;
+ }
else if (udpFD != -1) {
return dnsdist::Protocol::DoUDP;
}
@@ -705,7 +596,13 @@ struct ClientState
{
std::string result = udpFD != -1 ? "UDP" : "TCP";
- if (dohFrontend) {
+ if (doqFrontend) {
+ result += " (DNS over QUIC)";
+ }
+ else if (doh3Frontend) {
+ result += " (DNS over HTTP/3)";
+ }
+ else if (dohFrontend) {
if (dohFrontend->isHTTPS()) {
result += " (DNS over HTTPS)";
}
@@ -731,7 +628,7 @@ struct ClientState
}
}
- void attachFilter(shared_ptr<BPFFilter> bpf, int socket)
+ void attachFilter(shared_ptr<BPFFilter>& bpf, int socket)
{
detachFilter(socket);
@@ -754,7 +651,7 @@ struct ClientState
}
}
- void attachFilter(shared_ptr<BPFFilter> bpf)
+ void attachFilter(shared_ptr<BPFFilter>& bpf)
{
detachFilter();
@@ -810,6 +707,10 @@ struct DownstreamState: public std::enable_shared_from_this<DownstreamState>
std::string d_dohPath;
std::string name;
std::string nameWithAddr;
+#ifdef HAVE_XSK
+ std::array<uint8_t, 6> sourceMACAddr;
+ std::array<uint8_t, 6> destMACAddr;
+#endif /* HAVE_XSK */
size_t d_numberOfSockets{1};
size_t d_maxInFlightQueriesPerConn{1};
size_t d_tcpConcurrentConnectionsLimit{0};
@@ -839,6 +740,7 @@ struct DownstreamState: public std::enable_shared_from_this<DownstreamState>
bool mustResolve{false};
bool useECS{false};
bool useProxyProtocol{false};
+ bool d_proxyProtocolAdvertiseTLS{false};
bool setCD{false};
bool disableZeroScope{false};
bool tcpFastOpen{false};
@@ -851,6 +753,16 @@ struct DownstreamState: public std::enable_shared_from_this<DownstreamState>
bool d_upgradeToLazyHealthChecks{false};
};
+ struct HealthCheckMetrics
+ {
+ stat_t d_failures{0};
+ stat_t d_timeOuts{0};
+ stat_t d_parseErrors{0};
+ stat_t d_networkErrors{0};
+ stat_t d_mismatchErrors{0};
+ stat_t d_invalidResponseErrors{0};
+ };
+
DownstreamState(DownstreamState::Config&& config, std::shared_ptr<TLSCtx> tlsCtx, bool connect);
DownstreamState(const ComboAddress& remote): DownstreamState(DownstreamState::Config(remote), nullptr, false)
{
@@ -859,6 +771,7 @@ struct DownstreamState: public std::enable_shared_from_this<DownstreamState>
~DownstreamState();
Config d_config;
+ HealthCheckMetrics d_healthCheckMetrics;
stat_t sendErrors{0};
stat_t outstanding{0};
stat_t reuseds{0};
@@ -911,27 +824,46 @@ public:
std::vector<int> sockets;
StopWatch sw;
QPSLimiter qps;
+#ifdef HAVE_XSK
+ std::vector<std::shared_ptr<XskWorker>> d_xskInfos;
+ std::vector<std::shared_ptr<XskSocket>> d_xskSockets;
+#endif
std::atomic<uint64_t> idOffset{0};
size_t socketsOffset{0};
double latencyUsec{0.0};
double latencyUsecTCP{0.0};
unsigned int d_nextCheck{0};
uint16_t currentCheckFailures{0};
- uint8_t consecutiveSuccessfulChecks{0};
std::atomic<bool> hashesComputed{false};
std::atomic<bool> connected{false};
bool upStatus{false};
private:
+ void handleUDPTimeout(IDState& ids);
+ void updateNextLazyHealthCheck(LazyHealthCheckStats& stats, bool checkScheduled, std::optional<time_t> currentTime = std::nullopt);
void connectUDPSockets();
+#ifdef HAVE_XSK
+ void addXSKDestination(int fd);
+ void removeXSKDestination(int fd);
+#endif /* HAVE_XSK */
- std::thread tid;
std::mutex connectLock;
std::condition_variable d_connectedWait;
+#ifdef HAVE_XSK
+ SharedLockGuarded<std::vector<ComboAddress>> d_socketSourceAddresses;
+#endif
std::atomic_flag threadStarted;
+ uint8_t consecutiveSuccessfulChecks{0};
bool d_stopped{false};
public:
-
+ void updateStatisticsInfo()
+ {
+ auto delta = sw.udiffAndSet() / 1000000.0;
+ queryLoad.store(1.0 * (queries.load() - prev.queries.load()) / delta);
+ dropRate.store(1.0 * (reuseds.load() - prev.reuseds.load()) / delta);
+ prev.queries.store(queries.load());
+ prev.reuseds.store(reuseds.load());
+ }
void start();
bool isUp() const
@@ -1054,12 +986,17 @@ public:
void handleUDPTimeouts();
void reportTimeoutOrError();
void reportResponse(uint8_t rcode);
- void submitHealthCheckResult(bool initial, bool newState);
+ void submitHealthCheckResult(bool initial, bool newResult);
time_t getNextLazyHealthCheck();
uint16_t saveState(InternalQueryState&&);
void restoreState(uint16_t id, InternalQueryState&&);
std::optional<InternalQueryState> getState(uint16_t id);
+#ifdef HAVE_XSK
+ void registerXsk(std::vector<std::shared_ptr<XskSocket>>& xsks);
+ [[nodiscard]] ComboAddress pickSourceAddressForSending();
+#endif /* HAVE_XSK */
+
dnsdist::Protocol getProtocol() const
{
if (isDoH()) {
@@ -1085,9 +1022,6 @@ public:
static int s_udpTimeout;
static bool s_randomizeSockets;
static bool s_randomizeIDs;
-private:
- void handleUDPTimeout(IDState& ids);
- void updateNextLazyHealthCheck(LazyHealthCheckStats& stats, bool checkScheduled, std::optional<time_t> currentTime = std::nullopt);
};
using servers_t = vector<std::shared_ptr<DownstreamState>>;
@@ -1101,7 +1035,7 @@ public:
virtual ~DNSRule ()
{
}
- virtual bool matches(const DNSQuestion* dq) const =0;
+ virtual bool matches(const DNSQuestion* dq) const = 0;
virtual string toString() const = 0;
mutable stat_t d_matches{0};
};
@@ -1182,6 +1116,8 @@ extern ComboAddress g_serverControl; // not changed during runtime
extern std::vector<shared_ptr<TLSFrontend>> g_tlslocals;
extern std::vector<shared_ptr<DOHFrontend>> g_dohlocals;
+extern std::vector<shared_ptr<DOQFrontend>> g_doqlocals;
+extern std::vector<shared_ptr<DOH3Frontend>> g_doh3locals;
extern std::vector<std::unique_ptr<ClientState>> g_frontends;
extern bool g_truncateTC;
extern bool g_fixupCase;
@@ -1226,20 +1162,16 @@ struct LocalHolders
LocalStateHolder<pools_t> pools;
};
-void tcpAcceptorThread(std::vector<ClientState*> states);
-
-#ifdef HAVE_DNS_OVER_HTTPS
-void dohThread(ClientState* cs);
-#endif /* HAVE_DNS_OVER_HTTPS */
+void tcpAcceptorThread(const std::vector<ClientState*>& states);
void setLuaNoSideEffect(); // if nothing has been declared, set that there are no side effects
void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ side effect calls
bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
void resetLuaSideEffect(); // reset to indeterminate state
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote);
-bool checkQueryHeaders(const struct dnsheader* dh, ClientState& cs);
+bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState);
extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
int handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, time_t now, PacketBuffer& response);
@@ -1254,7 +1186,6 @@ extern bool g_addEDNSToSelfGeneratedResponses;
extern std::set<std::string> g_capabilitiesToRetain;
static const uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
-static const size_t s_maxPacketCacheEntrySize{4096}; // don't cache responses larger than this value
enum class ProcessQueryResult : uint8_t { Drop, SendAnswer, PassToBackend, Asynchronous };
ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
@@ -1262,10 +1193,11 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
bool processResponse(PacketBuffer& response, const std::vector<DNSDistResponseRuleAction>& respRuleActions, const std::vector<DNSDistResponseRuleAction>& insertedRespRuleActions, DNSResponse& dr, bool muted);
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop);
bool processResponseAfterRules(PacketBuffer& response, const std::vector<DNSDistResponseRuleAction>& cacheInsertedRespRuleActions, DNSResponse& dr, bool muted);
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<DNSDistResponseRuleAction>& localRespRuleActions, const std::vector<DNSDistResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids);
-bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& ds, uint16_t queryID, DNSQuestion& dq, PacketBuffer& query, ComboAddress& dest);
+bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend = true);
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const PacketBuffer& request, bool healthCheck = false);
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& backend, const int socketDesc, const PacketBuffer& request, bool healthCheck = false);
bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote);
void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, dnsdist::Protocol incomingProtocol, bool fromBackend);
void handleResponseSent(const InternalQueryState& ids, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, bool fromBackend);
diff --git a/dnslabeltext.cc b/dnslabeltext.cc
index e24deb6..2a9376f 100644
--- a/dnslabeltext.cc
+++ b/dnslabeltext.cc
@@ -26,7 +26,7 @@ vector<string> segmentDNSText(const string& input )
{
// cerr<<"segmentDNSText("<<input<<")"<<endl;
-#line 30 "dnslabeltext.cc"
+#line 27 "dnslabeltext.cc"
static const char _dnstext_actions[] = {
0, 1, 0, 1, 1, 1, 2, 1,
3, 1, 4, 1, 5, 2, 0, 1,
@@ -96,12 +96,12 @@ static const int dnstext_en_main = 1;
vector<string> ret;
-#line 100 "dnslabeltext.cc"
+#line 93 "dnslabeltext.cc"
{
cs = dnstext_start;
}
-#line 105 "dnslabeltext.cc"
+#line 96 "dnslabeltext.cc"
{
int _klen;
unsigned int _trans;
@@ -216,7 +216,7 @@ _match:
appendSplit(ret, segment, *(p));
}
break;
-#line 220 "dnslabeltext.cc"
+#line 204 "dnslabeltext.cc"
}
}
@@ -239,7 +239,7 @@ _again:
segment.clear();
}
break;
-#line 243 "dnslabeltext.cc"
+#line 225 "dnslabeltext.cc"
}
}
}
@@ -261,7 +261,7 @@ _again:
DNSName::string_t segmentDNSNameRaw(const char* realinput, size_t inputlen)
{
-#line 265 "dnslabeltext.cc"
+#line 243 "dnslabeltext.cc"
static const char _dnsnameraw_actions[] = {
0, 1, 0, 1, 1, 1, 2, 1,
3, 1, 4, 1, 5, 2, 1, 5,
@@ -333,12 +333,12 @@ static const int dnsnameraw_en_main = 1;
unsigned char labellen=0;
unsigned int lenpos=0;
-#line 337 "dnslabeltext.cc"
+#line 311 "dnslabeltext.cc"
{
cs = dnsnameraw_start;
}
-#line 342 "dnslabeltext.cc"
+#line 314 "dnslabeltext.cc"
{
int _klen;
unsigned int _trans;
@@ -460,7 +460,7 @@ _match:
labellen++;
}
break;
-#line 464 "dnslabeltext.cc"
+#line 429 "dnslabeltext.cc"
}
}
@@ -494,7 +494,7 @@ _again:
val=0;
}
break;
-#line 498 "dnslabeltext.cc"
+#line 460 "dnslabeltext.cc"
}
}
}
@@ -531,7 +531,7 @@ size_t parseRFC1035CharString(const std::string &in, std::string &val) {
* right place.
*/
-#line 535 "dnslabeltext.cc"
+#line 493 "dnslabeltext.cc"
static const char _dns_text_to_string_actions[] = {
0, 1, 0, 1, 2, 1, 3, 2,
0, 1
@@ -597,7 +597,7 @@ static const int dns_text_to_string_error = 0;
static const int dns_text_to_string_en_main = 1;
-#line 601 "dnslabeltext.cc"
+#line 557 "dnslabeltext.cc"
{
cs = dns_text_to_string_start;
}
@@ -610,7 +610,7 @@ static const int dns_text_to_string_en_main = 1;
(void) dns_text_to_string_error;
(void) dns_text_to_string_en_main;
-#line 614 "dnslabeltext.cc"
+#line 566 "dnslabeltext.cc"
{
int _klen;
unsigned int _trans;
@@ -712,7 +712,7 @@ _match:
counter++;
}
break;
-#line 716 "dnslabeltext.cc"
+#line 663 "dnslabeltext.cc"
}
}
@@ -743,7 +743,7 @@ size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, std:
std::string tmp;
-#line 747 "dnslabeltext.cc"
+#line 690 "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,7 +794,7 @@ static const int dns_text_to_value_list_error = 0;
static const int dns_text_to_value_list_en_main = 3;
-#line 798 "dnslabeltext.cc"
+#line 739 "dnslabeltext.cc"
{
cs = dns_text_to_value_list_start;
}
@@ -807,7 +807,7 @@ static const int dns_text_to_value_list_en_main = 3;
(void) dns_text_to_value_list_error;
(void) dns_text_to_value_list_en_main;
-#line 811 "dnslabeltext.cc"
+#line 748 "dnslabeltext.cc"
{
int _klen;
unsigned int _trans;
@@ -908,7 +908,7 @@ _match:
counter++;
}
break;
-#line 912 "dnslabeltext.cc"
+#line 844 "dnslabeltext.cc"
}
}
@@ -932,7 +932,7 @@ _again:
counter++;
}
break;
-#line 936 "dnslabeltext.cc"
+#line 866 "dnslabeltext.cc"
}
}
}
diff --git a/dnsmessage.proto b/dnsmessage.proto
index 99355df..e02cedb 100644
--- a/dnsmessage.proto
+++ b/dnsmessage.proto
@@ -43,6 +43,12 @@ message PBDNSMessage {
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)
+ }
+ enum HTTPVersion {
+ HTTP1 = 1; // HTTP/1.1
+ HTTP2 = 2; // HTTP/2
+ HTTP3 = 3; // HTTP/3
}
enum PolicyType {
UNKNOWN = 1; // No RPZ policy applied, or unknown type
@@ -177,6 +183,7 @@ message PBDNSMessage {
optional string custom = 8; // The name of the event for custom events
}
repeated Event trace = 23;
+ optional HTTPVersion httpVersion = 24; // HTTP version used for DNS over HTTP
}
message PBDNSMessageList {
diff --git a/dnsname.cc b/dnsname.cc
index 3bfbf30..bbac4ff 100644
--- a/dnsname.cc
+++ b/dnsname.cc
@@ -99,8 +99,7 @@ DNSName::DNSName(const std::string_view sw)
}
}
-
-DNSName::DNSName(const char* pos, int len, int 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)
{
if (offset >= len)
throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
@@ -114,64 +113,137 @@ DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t
packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset);
}
-// this should be the __only__ dns name parser in PowerDNS.
-void DNSName::packetParser(const char* qpos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset)
+static void checkLabelLength(uint8_t length)
{
- const unsigned char* pos=(const unsigned char*)qpos;
- unsigned char labellen;
- const unsigned char *opos = pos;
+ if (length == 0) {
+ throw std::range_error("no such thing as an empty label to append");
+ }
+ if (length > 63) {
+ throw std::range_error("label too long to append");
+ }
+}
- if (offset >= len)
- throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
- if (offset < (int) minOffset)
- throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")");
+// this parses a DNS name until a compression pointer is found
+size_t DNSName::parsePacketUncompressed(const pdns::views::UnsignedCharView& view, size_t pos, bool uncompress)
+{
+ const size_t initialPos = pos;
+ size_t totalLength = 0;
+ unsigned char labellen = 0;
- const unsigned char* end = pos + len;
- pos += offset;
- while((labellen=*pos++) && pos < end) { // "scan and copy"
- if(labellen >= 0xc0) {
- if(!uncompress)
- throw std::range_error("Found compressed label, instructed not to follow");
+ do {
+ labellen = view.at(pos);
+ ++pos;
+
+ if (labellen == 0) {
+ --pos;
+ break;
+ }
- labellen &= (~0xc0);
- int newpos = (labellen << 8) + *(const unsigned char*)pos;
-
- if(newpos < offset) {
- if(newpos < (int) minOffset)
- 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");
- packetParser((const char*)opos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset);
- } else
- throw std::range_error("Found a forward reference during label decompression");
- pos++;
+ if (labellen >= 0xc0) {
+ if (!uncompress) {
+ throw std::range_error("Found compressed label, instructed not to follow");
+ }
+ --pos;
break;
- } else if(labellen & 0xc0) {
+ }
+
+ if ((labellen & 0xc0) != 0) {
throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
}
- if (pos + labellen < end) {
- appendRawLabel((const char*)pos, labellen);
+ checkLabelLength(labellen);
+ // reserve one byte for the label length
+ if (totalLength + labellen > s_maxDNSNameLength - 1) {
+ throw std::range_error("name too long to append");
}
- else
+ if (pos + labellen >= view.size()) {
throw std::range_error("Found an invalid label length in qname");
- pos+=labellen;
- }
- if(d_storage.empty())
- d_storage.append(1, (char)0); // we just parsed the root
- if(consumed)
- *consumed = pos - opos - offset;
- if(qtype) {
- if (pos + 2 > end) {
- throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")");
}
- *qtype=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1);
+ pos += labellen;
+ totalLength += 1 + labellen;
}
- pos+=2;
- if(qclass) {
- if (pos + 2 > end) {
- throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")");
+ while (pos < view.size());
+
+ if (totalLength != 0) {
+ auto existingSize = d_storage.size();
+ if (existingSize > 0) {
+ // remove the last label count, we are about to override it */
+ --existingSize;
}
- *qclass=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1);
+ d_storage.reserve(existingSize + totalLength + 1);
+ d_storage.resize(existingSize + totalLength);
+ memcpy(&d_storage.at(existingSize), &view.at(initialPos), totalLength);
+ d_storage.append(1, static_cast<char>(0));
+ }
+ return pos;
+}
+
+// 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)
+{
+ if (offset >= len) {
+ throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
+ }
+
+ if (offset < static_cast<size_t>(minOffset)) {
+ throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")");
+ }
+ unsigned char labellen{0};
+
+ pdns::views::UnsignedCharView view(qpos, len);
+ auto pos = parsePacketUncompressed(view, offset, uncompress);
+
+ labellen = view.at(pos);
+ pos++;
+ if (labellen != 0 && pos < view.size()) {
+ if (labellen < 0xc0) {
+ abort();
+ }
+
+ if (!uncompress) {
+ throw std::range_error("Found compressed label, instructed not to follow");
+ }
+
+ labellen &= (~0xc0);
+ size_t newpos = (labellen << 8) + view.at(pos);
+
+ if (newpos >= offset) {
+ throw std::range_error("Found a forward reference during label decompression");
+ }
+
+ if (newpos < minOffset) {
+ 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");
+ }
+
+ packetParser(qpos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset);
+
+ pos++;
+ }
+
+ if (d_storage.empty()) {
+ d_storage.append(1, static_cast<char>(0)); // we just parsed the root
+ }
+
+ if (consumed != nullptr) {
+ *consumed = pos - offset;
+ }
+
+ if (qtype != nullptr) {
+ if (pos + 2 > view.size()) {
+ throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string(pos + 2)+ " > "+std::to_string(len)+")");
+ }
+ *qtype = view.at(pos)*256 + view.at(pos+1);
+ }
+
+ pos += 2;
+ if (qclass != nullptr) {
+ if (pos + 2 > view.size()) {
+ throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string(pos + 2)+ " > "+std::to_string(len)+")");
+ }
+ *qclass = view.at(pos)*256 + view.at(pos+1);
}
}
@@ -225,8 +297,9 @@ std::string DNSName::toLogString() const
std::string DNSName::toDNSString() const
{
- if (empty())
+ if (empty()) {
throw std::out_of_range("Attempt to DNSString an unset dnsname");
+ }
return std::string(d_storage.c_str(), d_storage.length());
}
@@ -250,11 +323,13 @@ size_t DNSName::wirelength() const {
// Are WE part of parent
bool DNSName::isPartOf(const DNSName& parent) const
{
- if(parent.empty() || empty())
+ if(parent.empty() || empty()) {
throw std::out_of_range("empty dnsnames aren't part of anything");
+ }
- if(parent.d_storage.size() > d_storage.size())
+ if(parent.d_storage.size() > d_storage.size()) {
return false;
+ }
// this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then
for(auto us=d_storage.cbegin(); us<d_storage.cend(); us+=*us+1) {
@@ -284,19 +359,24 @@ DNSName DNSName::makeRelative(const DNSName& zone) const
return ret;
}
-void DNSName::makeUsRelative(const DNSName& zone)
+void DNSName::makeUsRelative(const DNSName& zone)
{
if (isPartOf(zone)) {
d_storage.erase(d_storage.size()-zone.d_storage.size());
- d_storage.append(1, (char)0); // put back the trailing 0
- }
- else
+ d_storage.append(1, static_cast<char>(0)); // put back the trailing 0
+ }
+ else {
clear();
+ }
}
DNSName DNSName::getCommonLabels(const DNSName& other) const
{
- DNSName result;
+ if (empty() || other.empty()) {
+ return DNSName();
+ }
+
+ DNSName result(g_rootdnsname);
const std::vector<std::string> ours = getRawLabels();
const std::vector<std::string> others = other.getRawLabels();
@@ -319,8 +399,9 @@ DNSName DNSName::labelReverse() const
{
DNSName ret;
- if(isRoot())
+ if (isRoot()) {
return *this; // we don't create the root automatically below
+ }
if (!empty()) {
vector<string> l=getRawLabels();
@@ -339,41 +420,48 @@ void DNSName::appendRawLabel(const std::string& label)
void DNSName::appendRawLabel(const char* start, unsigned int length)
{
- if(length==0)
- throw std::range_error("no such thing as an empty label to append");
- if(length > 63)
- throw std::range_error("label too long to append");
- if(d_storage.size() + length > s_maxDNSNameLength - 1) // reserve one byte for the label length
+ checkLabelLength(length);
+
+ // reserve one byte for the label length
+ if (d_storage.size() + length > s_maxDNSNameLength - 1) {
throw std::range_error("name too long to append");
+ }
- if(d_storage.empty()) {
- d_storage.append(1, (char)length);
+ if (d_storage.empty()) {
+ d_storage.reserve(1 + length + 1);
+ d_storage.append(1, static_cast<char>(length));
}
else {
- *d_storage.rbegin()=(char)length;
+ d_storage.reserve(d_storage.size() + length + 1);
+ *d_storage.rbegin() = static_cast<char>(length);
}
d_storage.append(start, length);
- d_storage.append(1, (char)0);
+ d_storage.append(1, static_cast<char>(0));
}
void DNSName::prependRawLabel(const std::string& label)
{
- if(label.empty())
- throw std::range_error("no such thing as an empty label to prepend");
- if(label.size() > 63)
- throw std::range_error("label too long to prepend");
- if(d_storage.size() + label.size() > s_maxDNSNameLength - 1) // reserve one byte for the label length
+ checkLabelLength(label.size());
+
+ // reserve one byte for the label length
+ if (d_storage.size() + label.size() > s_maxDNSNameLength - 1) {
throw std::range_error("name too long to prepend");
+ }
- if(d_storage.empty())
- d_storage.append(1, (char)0);
+ if (d_storage.empty()) {
+ d_storage.reserve(1 + label.size() + 1);
+ d_storage.append(1, static_cast<char>(0));
+ }
+ else {
+ d_storage.reserve(d_storage.size() + 1 + label.size());
+ }
- string_t prep(1, (char)label.size());
+ string_t prep(1, static_cast<char>(label.size()));
prep.append(label.c_str(), label.size());
d_storage = prep+d_storage;
}
-bool DNSName::slowCanonCompare(const DNSName& rhs) const
+bool DNSName::slowCanonCompare(const DNSName& rhs) const
{
auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
@@ -411,16 +499,18 @@ DNSName DNSName::getLastLabel() const
bool DNSName::chopOff()
{
- if(d_storage.empty() || d_storage[0]==0)
+ if (d_storage.empty() || d_storage[0]==0) {
return false;
+ }
d_storage.erase(0, (unsigned int)d_storage[0]+1);
return true;
}
bool DNSName::isWildcard() const
{
- if(d_storage.size() < 2)
+ if (d_storage.size() < 2) {
return false;
+ }
auto p = d_storage.begin();
return (*p == 0x01 && *++p == '*');
}
@@ -450,8 +540,9 @@ unsigned int DNSName::countLabels() const
void DNSName::trimToLabels(unsigned int to)
{
- while(countLabels() > to && chopOff())
+ while(countLabels() > to && chopOff()) {
;
+ }
}
@@ -466,12 +557,15 @@ void DNSName::appendEscapedLabel(std::string& appendTo, const char* orig, size_t
while (pos < len) {
auto p = static_cast<uint8_t>(orig[pos]);
- if(p=='.')
+ if (p=='.') {
appendTo+="\\.";
- else if(p=='\\')
+ }
+ else if (p=='\\') {
appendTo+="\\\\";
- else if(p > 0x20 && p < 0x7f)
- appendTo.append(1, (char)p);
+ }
+ else if (p > 0x20 && p < 0x7f) {
+ appendTo.append(1, static_cast<char>(p));
+ }
else {
char buf[] = "000";
auto got = snprintf(buf, sizeof(buf), "%03" PRIu8, p);
@@ -494,11 +588,12 @@ bool DNSName::has8bitBytes() const
for (size_t idx = 0; idx < length; idx++) {
++pos;
char c = s.at(pos);
- if(!((c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9') ||
- c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
+ if (!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':')) {
return true;
+ }
}
++pos;
length = s.at(pos);
diff --git a/dnsname.hh b/dnsname.hh
index 29c8325..0d9112b 100644
--- a/dnsname.hh
+++ b/dnsname.hh
@@ -57,6 +57,7 @@ inline unsigned char dns_tolower(unsigned char c)
}
#include "burtle.hh"
+#include "views.hh"
// #include "dns.hh"
// #include "logger.hh"
@@ -80,7 +81,7 @@ class DNSName
public:
static const size_t s_maxDNSNameLength = 255;
- DNSName() {} //!< Constructs an *empty* DNSName, NOT the root!
+ 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
DNSName& operator=(const DNSName& rhs)
{
@@ -89,7 +90,7 @@ public:
}
return *this;
}
- DNSName& operator=(DNSName&& rhs)
+ DNSName& operator=(DNSName&& rhs) noexcept
{
if (this != &rhs) {
d_storage = std::move(rhs.d_storage);
@@ -100,7 +101,7 @@ public:
DNSName(DNSName&& a) = default;
explicit DNSName(std::string_view sw); //!< Constructs from a human formatted, escaped presentation
- DNSName(const char* p, int len, int 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* 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.
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
@@ -216,7 +217,8 @@ public:
private:
string_t d_storage;
- void packetParser(const char* p, int len, int 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);
+ 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);
static void throwSafeRangeError(const std::string& msg, const char* buf, size_t length);
@@ -561,8 +563,7 @@ private:
struct SuffixMatchNode
{
public:
- SuffixMatchNode()
- {}
+ SuffixMatchNode() = default;
SuffixMatchTree<bool> d_tree;
void add(const DNSName& dnsname)
diff --git a/dnsparser.cc b/dnsparser.cc
index b7c6a9b..5a17fc3 100644
--- a/dnsparser.cc
+++ b/dnsparser.cc
@@ -119,12 +119,12 @@ shared_ptr<DNSRecordContent> DNSRecordContent::deserialize(const DNSName& qname,
PacketReader pr(std::string_view(reinterpret_cast<const char*>(packet.data()), packet.size()), packet.size() - serialized.size() - sizeof(dnsrecordheader));
/* needed to get the record boundaries right */
pr.getDnsrecordheader(drh);
- auto content = DNSRecordContent::mastermake(dr, pr, Opcode::Query);
+ auto content = DNSRecordContent::make(dr, pr, Opcode::Query);
return content;
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr,
- PacketReader& pr)
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(const DNSRecord& dr,
+ PacketReader& pr)
{
uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
@@ -136,8 +136,8 @@ std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &
return i->second(dr, pr);
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
- const string& content)
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(uint16_t qtype, uint16_t qclass,
+ const string& content)
{
auto i = getZmakermap().find(pair(qclass, qtype));
if(i==getZmakermap().end()) {
@@ -147,7 +147,8 @@ std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, u
return i->second(content);
}
-std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
+std::shared_ptr<DNSRecordContent> DNSRecordContent::make(const DNSRecord& dr, PacketReader& pr, uint16_t oc)
+{
// For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
// not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
// For section 3.2.3, we do need content so we need to get it properly. But only for the correct QClasses.
@@ -207,19 +208,20 @@ DNSRecord::DNSRecord(const DNSResourceRecord& rr): d_name(rr.qname)
d_class = rr.qclass;
d_place = DNSResourceRecord::ANSWER;
d_clen = 0;
- d_content = DNSRecordContent::mastermake(d_type, rr.qclass, rr.content);
+ d_content = DNSRecordContent::make(d_type, rr.qclass, rr.content);
}
// If you call this and you are not parsing a packet coming from a socket, you are doing it wrong.
-DNSResourceRecord DNSResourceRecord::fromWire(const DNSRecord& d) {
- DNSResourceRecord rr;
- rr.qname = d.d_name;
- rr.qtype = QType(d.d_type);
- rr.ttl = d.d_ttl;
- rr.content = d.getContent()->getZoneRepresentation(true);
- rr.auth = false;
- rr.qclass = d.d_class;
- return rr;
+DNSResourceRecord DNSResourceRecord::fromWire(const DNSRecord& wire)
+{
+ DNSResourceRecord resourceRecord;
+ resourceRecord.qname = wire.d_name;
+ resourceRecord.qtype = QType(wire.d_type);
+ resourceRecord.ttl = wire.d_ttl;
+ resourceRecord.content = wire.getContent()->getZoneRepresentation(true);
+ resourceRecord.auth = false;
+ resourceRecord.qclass = wire.d_class;
+ return resourceRecord;
}
void MOADNSParser::init(bool query, const std::string_view& packet)
@@ -277,8 +279,8 @@ void MOADNSParser::init(bool query, const std::string_view& packet)
dr.d_type=ah.d_type;
dr.d_class=ah.d_class;
- dr.d_name=name;
- dr.d_clen=ah.d_clen;
+ dr.d_name = std::move(name);
+ dr.d_clen = ah.d_clen;
if (query &&
!(d_qtype == QType::IXFR && dr.d_place == DNSResourceRecord::AUTHORITY && dr.d_type == QType::SOA) && // IXFR queries have a SOA in their AUTHORITY section
@@ -288,7 +290,7 @@ void MOADNSParser::init(bool query, const std::string_view& packet)
}
else {
// cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
- dr.setContent(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
+ dr.setContent(DNSRecordContent::make(dr, pr, d_header.opcode));
}
/* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned:
@@ -515,6 +517,10 @@ string PacketReader::getText(bool multi, bool lenField)
break;
}
+ if (ret.empty() && !lenField) {
+ // all lenField == false cases (CAA and URI at the time of this writing) want that emptiness to be explicit
+ return "\"\"";
+ }
return ret;
}
@@ -535,7 +541,7 @@ string PacketReader::getUnquotedText(bool lenField)
return "";
d_pos++;
- string ret(&d_content.at(d_pos), &d_content.at(stop_at));
+ string ret(d_content.substr(d_pos, stop_at-d_pos));
d_pos = stop_at;
return ret;
}
@@ -768,7 +774,7 @@ static bool checkIfPacketContainsRecords(const PacketBuffer& packet, const std::
}
try {
- auto dh = reinterpret_cast<const dnsheader*>(packet.data());
+ const dnsheader_aligned dh(packet.data());
DNSPacketMangler dpm(const_cast<char*>(reinterpret_cast<const char*>(packet.data())), length);
const uint16_t qdcount = ntohs(dh->qdcount);
@@ -804,7 +810,7 @@ static int rewritePacketWithoutRecordTypes(const PacketBuffer& initialPacket, Pa
return EINVAL;
}
try {
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
+ const dnsheader_aligned dh(initialPacket.data());
if (ntohs(dh->qdcount) == 0)
return ENOENT;
@@ -979,7 +985,7 @@ uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA
}
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
@@ -1026,7 +1032,7 @@ uint32_t getDNSPacketLength(const char* packet, size_t length)
}
try
{
- const dnsheader* dh = reinterpret_cast<const dnsheader*>(packet);
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
@@ -1058,7 +1064,7 @@ uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t sectio
}
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
@@ -1148,7 +1154,7 @@ bool getEDNSUDPPayloadSizeAndZ(const char* packet, size_t length, uint16_t* payl
try
{
- const dnsheader* dh = (const dnsheader*) packet;
+ const dnsheader_aligned dh(packet);
DNSPacketMangler dpm(const_cast<char*>(packet), length);
const uint16_t qdcount = ntohs(dh->qdcount);
@@ -1191,13 +1197,12 @@ bool visitDNSPacket(const std::string_view& packet, const std::function<bool(uin
try
{
- dnsheader dh;
- memcpy(&dh, reinterpret_cast<const dnsheader*>(packet.data()), sizeof(dh));
- uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount);
+ const dnsheader_aligned dh(packet.data());
+ uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
PacketReader reader(packet);
uint64_t n;
- for (n = 0; n < ntohs(dh.qdcount) ; ++n) {
+ for (n = 0; n < ntohs(dh->qdcount) ; ++n) {
(void) reader.getName();
/* type and class */
reader.skip(4);
@@ -1206,7 +1211,7 @@ bool visitDNSPacket(const std::string_view& packet, const std::function<bool(uin
for (n = 0; n < numrecords; ++n) {
(void) reader.getName();
- uint8_t section = n < ntohs(dh.ancount) ? 1 : (n < (ntohs(dh.ancount) + ntohs(dh.nscount)) ? 2 : 3);
+ uint8_t section = n < ntohs(dh->ancount) ? 1 : (n < (ntohs(dh->ancount) + ntohs(dh->nscount)) ? 2 : 3);
uint16_t dnstype = reader.get16BitInt();
uint16_t dnsclass = reader.get16BitInt();
diff --git a/dnsparser.hh b/dnsparser.hh
index 014087e..20ce639 100644
--- a/dnsparser.hh
+++ b/dnsparser.hh
@@ -192,13 +192,13 @@ struct DNSRecord;
class DNSRecordContent
{
public:
- static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr);
- static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
- static std::shared_ptr<DNSRecordContent> mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
+ static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr);
+ static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr, uint16_t opcode);
+ static std::shared_ptr<DNSRecordContent> make(uint16_t qtype, uint16_t qclass, const string& zone);
static string upgradeContent(const DNSName& qname, const QType& qtype, const string& content);
virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
- virtual ~DNSRecordContent() {}
+ 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
diff --git a/dnstap.cc b/dnstap.cc
index 212c3b5..b032da9 100644
--- a/dnstap.cc
+++ b/dnstap.cc
@@ -7,23 +7,63 @@
#include <protozero/pbf_writer.hpp>
-namespace DnstapBaseFields {
- enum : protozero::pbf_tag_type { identity = 1, version = 2, extra = 3, message = 14, type = 15 };
+namespace DnstapBaseFields
+{
+enum : protozero::pbf_tag_type
+{
+ identity = 1,
+ version = 2,
+ extra = 3,
+ message = 14,
+ type = 15
+};
+}
+
+namespace DnstapMessageTypes
+{
+enum : protozero::pbf_tag_type
+{
+ message = 1
+};
}
-namespace DnstapMessageTypes {
- enum : protozero::pbf_tag_type { message = 1 };
+namespace DnstapSocketFamilyTypes
+{
+enum : protozero::pbf_tag_type
+{
+ inet = 1,
+ inet6 = 2
+};
}
-namespace DnstapSocketFamilyTypes {
- enum : protozero::pbf_tag_type { inet = 1, inet6 = 2 };
+namespace DnstapMessageFields
+{
+enum : protozero::pbf_tag_type
+{
+ type = 1,
+ socket_family = 2,
+ socket_protocol = 3,
+ query_address = 4,
+ response_address = 5,
+ query_port = 6,
+ response_port = 7,
+ query_time_sec = 8,
+ query_time_nsec = 9,
+ query_message = 10,
+ query_zone = 11,
+ response_time_sec = 12,
+ response_time_nsec = 13,
+ response_message = 14
+};
}
-namespace DnstapMessageFields {
- enum : protozero::pbf_tag_type { type = 1, socket_family = 2, socket_protocol = 3, query_address = 4, response_address = 5, query_port = 6, response_port = 7, query_time_sec = 8, query_time_nsec = 9, query_message = 10, query_zone = 11, response_time_sec = 12, response_time_nsec = 13, response_message = 14 };
+std::string&& DnstapMessage::getBuffer()
+{
+ 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, boost::optional<const DNSName&> auth): d_buffer(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<const DNSName&>& auth) :
+ d_buffer(std::move(buffer))
{
protozero::pbf_writer pbf{d_buffer};
@@ -33,7 +73,9 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ
protozero::pbf_writer pbf_message{pbf, DnstapBaseFields::message};
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
pbf_message.add_enum(DnstapMessageFields::type, static_cast<protozero::pbf_tag_type>(type));
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
pbf_message.add_enum(DnstapMessageFields::socket_protocol, static_cast<protozero::pbf_tag_type>(protocol));
if (requestor != nullptr) {
@@ -45,9 +87,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ
if (requestor != nullptr) {
if (requestor->sin4.sin_family == AF_INET) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
pbf_message.add_bytes(DnstapMessageFields::query_address, reinterpret_cast<const char*>(&requestor->sin4.sin_addr.s_addr), sizeof(requestor->sin4.sin_addr.s_addr));
}
else if (requestor->sin4.sin_family == AF_INET6) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
pbf_message.add_bytes(DnstapMessageFields::query_address, reinterpret_cast<const char*>(&requestor->sin6.sin6_addr.s6_addr), sizeof(requestor->sin6.sin6_addr.s6_addr));
}
pbf_message.add_uint32(DnstapMessageFields::query_port, ntohs(requestor->sin4.sin_port));
@@ -55,9 +99,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ
if (responder != nullptr) {
if (responder->sin4.sin_family == AF_INET) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
pbf_message.add_bytes(DnstapMessageFields::response_address, reinterpret_cast<const char*>(&responder->sin4.sin_addr.s_addr), sizeof(responder->sin4.sin_addr.s_addr));
}
else if (responder->sin4.sin_family == AF_INET6) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
pbf_message.add_bytes(DnstapMessageFields::response_address, reinterpret_cast<const char*>(&responder->sin6.sin6_addr.s6_addr), sizeof(responder->sin6.sin6_addr.s6_addr));
}
pbf_message.add_uint32(DnstapMessageFields::response_port, ntohs(responder->sin4.sin_port));
@@ -74,10 +120,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ
}
if (packet != nullptr && len >= sizeof(dnsheader)) {
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
- if (!dh->qr) {
+ const dnsheader_aligned dnsheader(packet);
+ if (!dnsheader->qr) {
pbf_message.add_bytes(DnstapMessageFields::query_message, packet, len);
- } else {
+ }
+ else {
pbf_message.add_bytes(DnstapMessageFields::response_message, packet, len);
}
}
diff --git a/dnstap.hh b/dnstap.hh
index 8a62b1a..357319b 100644
--- a/dnstap.hh
+++ b/dnstap.hh
@@ -35,15 +35,39 @@
class DnstapMessage
{
public:
- enum class MessageType : uint32_t { auth_query = 1, auth_response = 2, resolver_query = 3, resolver_response = 4, client_query = 5, client_response = 6, forwarder_query = 7, forwarded_response = 8, stub_query = 9, stub_response = 10, tool_query = 11, tool_response = 12 };
- enum class ProtocolType : uint32_t { DoUDP = 1, DoTCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 };
+ enum class MessageType : uint32_t
+ {
+ auth_query = 1,
+ auth_response = 2,
+ resolver_query = 3,
+ resolver_response = 4,
+ client_query = 5,
+ client_response = 6,
+ forwarder_query = 7,
+ forwarded_response = 8,
+ stub_query = 9,
+ stub_response = 10,
+ tool_query = 11,
+ tool_response = 12
+ };
+ enum class ProtocolType : uint32_t
+ {
+ DoUDP = 1,
+ DoTCP = 2,
+ DoT = 3,
+ DoH = 4,
+ DNSCryptUDP = 5,
+ DNSCryptTCP = 6,
+ DoQ = 7
+ };
- DnstapMessage(std::string& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional<const DNSName&> 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 boost::optional<const DNSName&>& auth = boost::none);
void setExtra(const std::string& extra);
+ std::string&& getBuffer();
-protected:
- std::string& d_buffer;
+private:
+ std::string d_buffer;
};
#endif /* DISABLE_PROTOBUF */
diff --git a/dnswriter.hh b/dnswriter.hh
index cfa4eb9..4d6d286 100644
--- a/dnswriter.hh
+++ b/dnswriter.hh
@@ -69,7 +69,7 @@ public:
void startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=QClass::IN, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, bool compress=true);
/** Shorthand way to add an Opt-record, for example for EDNS0 purposes */
- typedef vector<pair<uint16_t,std::string> > optvect_t;
+ using optvect_t = vector<pair<uint16_t,std::string> >;
void addOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t ednsFlags, const optvect_t& options=optvect_t(), const uint8_t version=0);
/** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too.
diff --git a/doh.cc b/doh.cc
index 1c86102..3213629 100644
--- a/doh.cc
+++ b/doh.cc
@@ -2,6 +2,7 @@
#include "doh.hh"
#ifdef HAVE_DNS_OVER_HTTPS
+#ifdef HAVE_LIBH2OEVLOOP
#define H2O_USE_EPOLL 1
#include <cerrno>
@@ -10,7 +11,6 @@
#include <boost/algorithm/string.hpp>
#include <h2o.h>
-//#include <h2o/http1.h>
#include <h2o/http2.h>
#include <openssl/err.h>
@@ -25,7 +25,9 @@
#include "dns.hh"
#include "dolog.hh"
#include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-dnsparser.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-rules.hh"
#include "dnsdist-xpf.hh"
@@ -55,7 +57,7 @@
*/
/* 'Intermediate' compatibility from https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 */
-#define DOH_DEFAULT_CIPHERS "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"
+static constexpr string_view DOH_DEFAULT_CIPHERS = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
class DOHAcceptContext
{
@@ -66,7 +68,9 @@ public:
d_rotatingTicketsKey.clear();
}
DOHAcceptContext(const DOHAcceptContext&) = delete;
+ DOHAcceptContext(DOHAcceptContext&&) = delete;
DOHAcceptContext& operator=(const DOHAcceptContext&) = delete;
+ DOHAcceptContext& operator=(DOHAcceptContext&&) = delete;
h2o_accept_ctx_t* get()
{
@@ -79,19 +83,19 @@ public:
d_h2o_accept_ctx.ssl_ctx = nullptr;
}
- void decrementConcurrentConnections()
+ void decrementConcurrentConnections() const
{
if (d_cs != nullptr) {
--d_cs->tcpCurrentConnections;
}
}
- time_t getNextTicketsKeyRotation() const
+ [[nodiscard]] time_t getNextTicketsKeyRotation() const
{
return d_ticketsKeyNextRotation;
}
- size_t getTicketsKeysCount() const
+ [[nodiscard]] size_t getTicketsKeysCount() const
{
size_t res = 0;
if (d_ticketKeys) {
@@ -155,57 +159,41 @@ public:
std::map<int, std::string> d_ocspResponses;
std::unique_ptr<OpenSSLTLSTicketKeysRing> d_ticketKeys{nullptr};
- std::unique_ptr<FILE, int(*)(FILE*)> d_keyLogFile{nullptr, fclose};
+ // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
+ pdns::UniqueFilePtr d_keyLogFile{nullptr};
ClientState* d_cs{nullptr};
time_t d_ticketsKeyRotationDelay{0};
private:
- h2o_accept_ctx_t d_h2o_accept_ctx;
- std::atomic<uint64_t> d_refcnt{1};
+ h2o_accept_ctx_t d_h2o_accept_ctx{};
time_t d_ticketsKeyNextRotation{0};
std::atomic_flag d_rotatingTicketsKey;
};
+struct DOHUnit;
+
// we create one of these per thread, and pass around a pointer to it
// through the bowels of h2o
struct DOHServerConfig
{
DOHServerConfig(uint32_t idleTimeout, uint32_t internalPipeBufferSize): accept_ctx(std::make_shared<DOHAcceptContext>())
{
- int fd[2];
#ifndef USE_SINGLE_ACCEPTOR_THREAD
- if (pipe(fd) < 0) {
- unixDie("Creating a pipe for DNS over HTTPS");
- }
- dohquerypair[0] = fd[1];
- dohquerypair[1] = fd[0];
-
- setNonBlocking(dohquerypair[0]);
- if (internalPipeBufferSize > 0) {
- setPipeBufferSize(dohquerypair[0], internalPipeBufferSize);
+ {
+ auto [sender, receiver] = pdns::channel::createObjectQueue<DOHUnit>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverBlocking, internalPipeBufferSize);
+ d_querySender = std::move(sender);
+ d_queryReceiver = std::move(receiver);
}
#endif /* USE_SINGLE_ACCEPTOR_THREAD */
- if (pipe(fd) < 0) {
-#ifndef USE_SINGLE_ACCEPTOR_THREAD
- close(dohquerypair[0]);
- close(dohquerypair[1]);
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
- unixDie("Creating a pipe for DNS over HTTPS");
- }
-
- dohresponsepair[0] = fd[1];
- dohresponsepair[1] = fd[0];
-
- setNonBlocking(dohresponsepair[0]);
- if (internalPipeBufferSize > 0) {
- setPipeBufferSize(dohresponsepair[0], internalPipeBufferSize);
+ {
+ auto [sender, receiver] = pdns::channel::createObjectQueue<DOHUnit>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
+ d_responseSender = std::move(sender);
+ d_responseReceiver = std::move(receiver);
}
- setNonBlocking(dohresponsepair[1]);
-
h2o_config_init(&h2o_config);
- h2o_config.http2.idle_timeout = idleTimeout * 1000;
+ h2o_config.http2.idle_timeout = static_cast<uint64_t>(idleTimeout) * 1000;
/* if you came here for a way to make the number of concurrent streams (concurrent requests per connection)
configurable, or even just bigger, I have bad news for you.
h2o_config.http2.max_concurrent_requests_per_connection (default of 100) is capped by
@@ -215,67 +203,106 @@ struct DOHServerConfig
*/
}
DOHServerConfig(const DOHServerConfig&) = delete;
+ DOHServerConfig(DOHServerConfig&&) = delete;
DOHServerConfig& operator=(const DOHServerConfig&) = delete;
+ DOHServerConfig& operator=(DOHServerConfig&&) = delete;
+ ~DOHServerConfig() = default;
LocalHolders holders;
std::set<std::string, std::less<>> paths;
- h2o_globalconf_t h2o_config;
- h2o_context_t h2o_ctx;
+ h2o_globalconf_t h2o_config{};
+ h2o_context_t h2o_ctx{};
std::shared_ptr<DOHAcceptContext> accept_ctx{nullptr};
- ClientState* cs{nullptr};
- std::shared_ptr<DOHFrontend> df{nullptr};
+ ClientState* clientState{nullptr};
+ std::shared_ptr<DOHFrontend> dohFrontend{nullptr};
#ifndef USE_SINGLE_ACCEPTOR_THREAD
- int dohquerypair[2]{-1,-1};
+ pdns::channel::Sender<DOHUnit> d_querySender;
+ pdns::channel::Receiver<DOHUnit> d_queryReceiver;
#endif /* USE_SINGLE_ACCEPTOR_THREAD */
- int dohresponsepair[2]{-1,-1};
+ pdns::channel::Sender<DOHUnit> d_responseSender;
+ pdns::channel::Receiver<DOHUnit> d_responseReceiver;
};
-/* This internal function sends back the object to the main thread to send a reply.
- The caller should NOT release or touch the unit after calling this function */
-static void sendDoHUnitToTheMainThread(DOHUnitUniquePtr&& du, const char* description)
+struct DOHUnit : public DOHUnitInterface
{
- /* taking a naked pointer since we are about to send that pointer over a pipe */
- auto ptr = du.release();
- /* increasing the reference counter. This should not be strictly needed because
- we already hold a reference and will only release it if we failed to send the
- pointer over the pipe, but TSAN seems confused when the responder thread gets
- a reply from a backend before the send() syscall sending the corresponding query
- to that backend has returned in the initial thread.
- The memory barrier needed to increase that counter seems to work around that.
+ DOHUnit(PacketBuffer&& query_, std::string&& path_, std::string&& host_): path(std::move(path_)), host(std::move(host_)), query(std::move(query_))
+ {
+ ids.ednsAdded = false;
+ }
+ ~DOHUnit() override
+ {
+ if (self != nullptr) {
+ *self = nullptr;
+ }
+ }
+
+ DOHUnit(const DOHUnit&) = delete;
+ DOHUnit(DOHUnit&&) = delete;
+ DOHUnit& operator=(const DOHUnit&) = delete;
+ DOHUnit& operator=(DOHUnit&&) = delete;
+
+ InternalQueryState ids;
+ std::string sni;
+ std::string path;
+ std::string scheme;
+ std::string host;
+ std::string contentType;
+ PacketBuffer query;
+ PacketBuffer response;
+ std::unique_ptr<std::unordered_map<std::string, std::string>> headers;
+ st_h2o_req_t* req{nullptr};
+ DOHUnit** self{nullptr};
+ DOHServerConfig* dsc{nullptr};
+ pdns::channel::Sender<DOHUnit>* responseSender{nullptr};
+ size_t query_at{0};
+ int rsock{-1};
+ /* the status_code is set from
+ processDOHQuery() (which is executed in
+ the DOH client thread) so that the correct
+ response can be sent in on_dnsdist(),
+ after the DOHUnit has been passed back to
+ the main DoH thread.
*/
- ptr->get();
- static_assert(sizeof(ptr) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
+ uint16_t status_code{200};
+ /* whether the query was re-sent to the backend over
+ TCP after receiving a truncated answer over UDP */
+ bool tcp{false};
+ bool truncated{false};
+
+ [[nodiscard]] std::string getHTTPPath() const override;
+ [[nodiscard]] std::string getHTTPQueryString() const override;
+ [[nodiscard]] const std::string& getHTTPHost() const override;
+ [[nodiscard]] const std::string& getHTTPScheme() const override;
+ [[nodiscard]] const std::unordered_map<std::string, std::string>& getHTTPHeaders() const override;
+ void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType="") override;
+ void handleTimeout() override;
+ void handleUDPResponse(PacketBuffer&& response, InternalQueryState&& state, [[maybe_unused]] const std::shared_ptr<DownstreamState>& downstream) override;
+};
+using DOHUnitUniquePtr = std::unique_ptr<DOHUnit>;
- ssize_t sent = write(ptr->rsock, &ptr, sizeof(ptr));
- if (sent != sizeof(ptr)) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- ++g_stats.dohResponsePipeFull;
+/* This internal function sends back the object to the main thread to send a reply.
+ The caller should NOT release or touch the unit after calling this function */
+static void sendDoHUnitToTheMainThread(DOHUnitUniquePtr&& dohUnit, const char* description)
+{
+ if (dohUnit->responseSender == nullptr) {
+ return;
+ }
+ try {
+ if (!dohUnit->responseSender->send(std::move(dohUnit))) {
+ ++dnsdist::metrics::g_stats.dohResponsePipeFull;
vinfolog("Unable to pass a %s to the DoH worker thread because the pipe is full", description);
}
- else {
- vinfolog("Unable to pass a %s to the DoH worker thread because we couldn't write to the pipe: %s", description, stringerror());
- }
-
- /* we fail to write over the pipe so we do not need to hold to that ref anymore */
- ptr->release();
+ } catch (const std::exception& e) {
+ vinfolog("Unable to pass a %s to the DoH worker thread because we couldn't write to the pipe: %s", description, e.what());
}
- /* we decrement the counter incremented above at the beginning of that function */
- ptr->release();
}
/* This function is called from other threads than the main DoH one,
- instructing it to send a 502 error to the client.
- It takes ownership of the unit. */
-void handleDOHTimeout(DOHUnitUniquePtr&& oldDU)
+ instructing it to send a 502 error to the client. */
+void DOHUnit::handleTimeout()
{
- if (oldDU == nullptr) {
- return;
- }
-
- /* we are about to erase an existing DU */
- oldDU->status_code = 502;
-
- sendDoHUnitToTheMainThread(std::move(oldDU), "DoH timeout");
+ status_code = 502;
+ sendDoHUnitToTheMainThread(std::unique_ptr<DOHUnit>(this), "DoH timeout");
}
struct DOHConnection
@@ -292,10 +319,10 @@ static thread_local std::unordered_map<int, DOHConnection> t_conns;
static void on_socketclose(void *data)
{
- auto conn = reinterpret_cast<DOHConnection*>(data);
+ auto* conn = static_cast<DOHConnection*>(data);
if (conn != nullptr) {
if (conn->d_acceptCtx) {
- struct timeval now;
+ struct timeval now{};
gettimeofday(&now, nullptr);
auto diff = now - conn->d_connectionStartTime;
@@ -352,17 +379,15 @@ static const std::string& getReasonFromStatusCode(uint16_t statusCode)
};
static const std::string unknown = "Unknown";
- const auto it = reasons.find(statusCode);
- if (it == reasons.end()) {
+ const auto reasonIt = reasons.find(statusCode);
+ if (reasonIt == reasons.end()) {
return unknown;
}
- else {
- return it->second;
- }
+ return reasonIt->second;
}
/* Always called from the main DoH thread */
-static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCode, const PacketBuffer& response, const std::unordered_map<std::string, std::string>& customResponseHeaders, const std::string& contentType, bool addContentType)
+static void handleResponse(DOHFrontend& dohFrontend, st_h2o_req_t* req, uint16_t statusCode, const PacketBuffer& response, const std::unordered_map<std::string, std::string>& customResponseHeaders, const std::string& contentType, bool addContentType)
{
constexpr int overwrite_if_exists = 1;
constexpr int maybe_token = 1;
@@ -371,7 +396,7 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
}
if (statusCode == 200) {
- ++df.d_validresponses;
+ ++dohFrontend.d_validresponses;
req->res.status = 200;
if (addContentType) {
@@ -380,12 +405,14 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
}
else {
/* we need to duplicate the header content because h2o keeps a pointer and we will be deleted before the response has been sent */
- h2o_iovec_t ct = h2o_strdup(&req->pool, contentType.c_str(), contentType.size());
- h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, nullptr, ct.base, ct.len);
+ h2o_iovec_t contentTypeVect = h2o_strdup(&req->pool, contentType.c_str(), contentType.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
+ h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, nullptr, contentTypeVect.base, contentTypeVect.len);
}
}
- if (df.d_sendCacheControlHeaders && response.size() > sizeof(dnsheader)) {
+ if (dohFrontend.d_sendCacheControlHeaders && response.size() > sizeof(dnsheader)) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
uint32_t minTTL = getDNSPacketMinTTL(reinterpret_cast<const char*>(response.data()), response.size());
if (minTTL != std::numeric_limits<uint32_t>::max()) {
std::string cacheControlValue = "max-age=" + std::to_string(minTTL);
@@ -396,18 +423,21 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
}
req->res.content_length = response.size();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): h2o API
h2o_send_inline(req, reinterpret_cast<const char*>(response.data()), response.size());
}
else if (statusCode >= 300 && statusCode < 400) {
/* in that case the response is actually a URL */
/* we need to duplicate the URL because h2o uses it for the location header, keeping a pointer, and we will be deleted before the response has been sent */
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): h2o API
h2o_iovec_t url = h2o_strdup(&req->pool, reinterpret_cast<const char*>(response.data()), response.size());
h2o_send_redirect(req, statusCode, getReasonFromStatusCode(statusCode).c_str(), url.base, url.len);
- ++df.d_redirectresponses;
+ ++dohFrontend.d_redirectresponses;
}
else {
// we need to make sure it's null-terminated */
if (!response.empty() && response.at(response.size() - 1) == 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): h2o API
h2o_send_error_generic(req, statusCode, getReasonFromStatusCode(statusCode).c_str(), reinterpret_cast<const char*>(response.data()), H2O_SEND_ERROR_KEEP_HEADERS);
}
else {
@@ -416,7 +446,7 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
h2o_send_error_400(req, getReasonFromStatusCode(statusCode).c_str(), "invalid DNS query" , 0);
break;
case 403:
- h2o_send_error_403(req, getReasonFromStatusCode(statusCode).c_str(), "dns query not allowed", 0);
+ h2o_send_error_403(req, getReasonFromStatusCode(statusCode).c_str(), "DoH query not allowed", 0);
break;
case 502:
h2o_send_error_502(req, getReasonFromStatusCode(statusCode).c_str(), "no downstream server available", 0);
@@ -429,18 +459,27 @@ static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCo
}
}
- ++df.d_errorresponses;
+ ++dohFrontend.d_errorresponses;
}
}
-class DoHTCPCrossQuerySender : public TCPQuerySender
+static std::unique_ptr<DOHUnit> getDUFromIDS(InternalQueryState& ids)
{
-public:
- DoHTCPCrossQuerySender()
- {
- }
+ auto dohUnit = std::unique_ptr<DOHUnit>(dynamic_cast<DOHUnit*>(ids.du.release()));
+ return dohUnit;
+}
- bool active() const override
+class DoHTCPCrossQuerySender final : public TCPQuerySender
+{
+public:
+ DoHTCPCrossQuerySender() = default;
+ DoHTCPCrossQuerySender(const DoHTCPCrossQuerySender&) = delete;
+ DoHTCPCrossQuerySender(DoHTCPCrossQuerySender&&) = delete;
+ DoHTCPCrossQuerySender& operator=(const DoHTCPCrossQuerySender&) = delete;
+ DoHTCPCrossQuerySender& operator=(DoHTCPCrossQuerySender&&) = delete;
+ ~DoHTCPCrossQuerySender() final = default;
+
+ [[nodiscard]] bool active() const override
{
return true;
}
@@ -451,28 +490,29 @@ public:
return;
}
- auto du = std::move(response.d_idstate.du);
- if (du->rsock == -1) {
+ auto dohUnit = getDUFromIDS(response.d_idstate);
+ if (dohUnit->responseSender == nullptr) {
return;
}
- du->response = std::move(response.d_buffer);
- du->ids = std::move(response.d_idstate);
- DNSResponse dr(du->ids, du->response, du->downstream);
+ dohUnit->response = std::move(response.d_buffer);
+ dohUnit->ids = std::move(response.d_idstate);
+ DNSResponse dr(dohUnit->ids, dohUnit->response, dohUnit->downstream);
- dnsheader cleartextDH;
- memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
+ dnsheader cleartextDH{};
+ memcpy(&cleartextDH, dr.getHeader().get(), sizeof(cleartextDH));
if (!response.isAsync()) {
static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions = g_respruleactions.getLocal();
static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
- dr.ids.du = std::move(du);
+ dr.ids.du = std::move(dohUnit);
- if (!processResponse(dr.ids.du->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false)) {
+ if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false)) {
if (dr.ids.du) {
- dr.ids.du->status_code = 503;
- sendDoHUnitToTheMainThread(std::move(dr.ids.du), "Response dropped by rules");
+ dohUnit = getDUFromIDS(dr.ids);
+ dohUnit->status_code = 503;
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "Response dropped by rules");
}
return;
}
@@ -481,26 +521,26 @@ public:
return;
}
- du = std::move(dr.ids.du);
+ dohUnit = getDUFromIDS(dr.ids);
}
- if (!du->ids.selfGenerated) {
- double udiff = du->ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (https), took %f usec", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
+ if (!dohUnit->ids.selfGenerated) {
+ double udiff = dohUnit->ids.queryRealTime.udiff();
+ vinfolog("Got answer from %s, relayed to %s (https), took %f us", dohUnit->downstream->d_config.remote.toStringWithPort(), dohUnit->ids.origRemote.toStringWithPort(), udiff);
- auto backendProtocol = du->downstream->getProtocol();
- if (backendProtocol == dnsdist::Protocol::DoUDP && du->tcp) {
+ auto backendProtocol = dohUnit->downstream->getProtocol();
+ if (backendProtocol == dnsdist::Protocol::DoUDP && dohUnit->tcp) {
backendProtocol = dnsdist::Protocol::DoTCP;
}
- handleResponseSent(du->ids, udiff, du->ids.origRemote, du->downstream->d_config.remote, du->response.size(), cleartextDH, backendProtocol, true);
+ handleResponseSent(dohUnit->ids, udiff, dohUnit->ids.origRemote, dohUnit->downstream->d_config.remote, dohUnit->response.size(), cleartextDH, backendProtocol, true);
}
- ++g_stats.responses;
- if (du->ids.cs) {
- ++du->ids.cs->responses;
+ ++dnsdist::metrics::g_stats.responses;
+ if (dohUnit->ids.cs != nullptr) {
+ ++dohUnit->ids.cs->responses;
}
- sendDoHUnitToTheMainThread(std::move(du), "cross-protocol response");
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "cross-protocol response");
}
void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
@@ -508,62 +548,69 @@ public:
return handleResponse(now, std::move(response));
}
- void notifyIOError(InternalQueryState&& query, const struct timeval& now) override
+ void notifyIOError(const struct timeval& now, TCPResponse&& response) override
{
+ auto& query = response.d_idstate;
if (!query.du) {
return;
}
- if (query.du->rsock == -1) {
+ auto dohUnit = getDUFromIDS(query);
+ if (dohUnit->responseSender == nullptr) {
return;
}
- auto du = std::move(query.du);
- du->ids = std::move(query);
- du->status_code = 502;
- sendDoHUnitToTheMainThread(std::move(du), "cross-protocol error response");
+ dohUnit->ids = std::move(query);
+ dohUnit->status_code = 502;
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "cross-protocol error response");
}
};
class DoHCrossProtocolQuery : public CrossProtocolQuery
{
public:
- DoHCrossProtocolQuery(DOHUnitUniquePtr&& du, bool isResponse)
+ DoHCrossProtocolQuery(DOHUnitUniquePtr&& dohUnit, bool isResponse)
{
if (isResponse) {
/* happens when a response becomes async */
- query = InternalQuery(std::move(du->response), std::move(du->ids));
+ query = InternalQuery(std::move(dohUnit->response), std::move(dohUnit->ids));
}
else {
/* we need to duplicate the query here because we might need
the existing query later if we get a truncated answer */
- query = InternalQuery(PacketBuffer(du->query), std::move(du->ids));
+ query = InternalQuery(PacketBuffer(dohUnit->query), std::move(dohUnit->ids));
}
- /* it might have been moved when we moved du->ids */
- if (du) {
- query.d_idstate.du = std::move(du);
+ /* it might have been moved when we moved dohUnit->ids */
+ if (dohUnit) {
+ query.d_idstate.du = std::move(dohUnit);
}
/* we _could_ remove it from the query buffer and put in query's d_proxyProtocolPayload,
- clearing query.d_proxyProtocolPayloadAdded and du->proxyProtocolPayloadSize.
+ clearing query.d_proxyProtocolPayloadAdded and dohUnit->proxyProtocolPayloadSize.
Leave it for now because we know that the onky case where the payload has been
added is when we tried over UDP, got a TC=1 answer and retried over TCP/DoT,
and we know the TCP/DoT code can handle it. */
- query.d_proxyProtocolPayloadAdded = query.d_idstate.du->proxyProtocolPayloadSize > 0;
+ query.d_proxyProtocolPayloadAdded = query.d_idstate.d_proxyProtocolPayloadSize > 0;
downstream = query.d_idstate.du->downstream;
- proxyProtocolPayloadSize = query.d_idstate.du->proxyProtocolPayloadSize;
}
void handleInternalError()
{
- query.d_idstate.du->status_code = 502;
- sendDoHUnitToTheMainThread(std::move(query.d_idstate.du), "DoH internal error");
+ auto dohUnit = getDUFromIDS(query.d_idstate);
+ if (dohUnit == nullptr) {
+ return;
+ }
+ dohUnit->status_code = 502;
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "DoH internal error");
}
std::shared_ptr<TCPQuerySender> getTCPQuerySender() override
{
- query.d_idstate.du->downstream = downstream;
+ auto* unit = dynamic_cast<DOHUnit*>(query.d_idstate.du.get());
+ if (unit != nullptr) {
+ unit->downstream = downstream;
+ }
return s_sender;
}
@@ -581,9 +628,9 @@ public:
return dr;
}
- DOHUnitUniquePtr&& releaseDU()
+ DOHUnitUniquePtr releaseDU()
{
- return std::move(query.d_idstate.du);
+ return getDUFromIDS(query.d_idstate);
}
private:
@@ -598,25 +645,25 @@ std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion&
throw std::runtime_error("Trying to create a DoH cross protocol query without a valid DoH unit");
}
- auto du = std::move(dq.ids.du);
- if (&dq.ids != &du->ids) {
- du->ids = std::move(dq.ids);
+ auto dohUnit = getDUFromIDS(dq.ids);
+ if (&dq.ids != &dohUnit->ids) {
+ dohUnit->ids = std::move(dq.ids);
}
- du->ids.origID = dq.getHeader()->id;
+ dohUnit->ids.origID = dq.getHeader()->id;
if (!isResponse) {
- if (du->query.data() != dq.getMutableData().data()) {
- du->query = std::move(dq.getMutableData());
+ if (dohUnit->query.data() != dq.getMutableData().data()) {
+ dohUnit->query = std::move(dq.getMutableData());
}
}
else {
- if (du->response.data() != dq.getMutableData().data()) {
- du->response = std::move(dq.getMutableData());
+ if (dohUnit->response.data() != dq.getMutableData().data()) {
+ dohUnit->response = std::move(dq.getMutableData());
}
}
- return std::make_unique<DoHCrossProtocolQuery>(std::move(du), isResponse);
+ return std::make_unique<DoHCrossProtocolQuery>(std::move(dohUnit), isResponse);
}
/*
@@ -624,181 +671,191 @@ std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion&
*/
static void processDOHQuery(DOHUnitUniquePtr&& unit, bool inMainThread = false)
{
- const auto handleImmediateResponse = [inMainThread](DOHUnitUniquePtr&& du, const char* reason) {
+ const auto handleImmediateResponse = [inMainThread](DOHUnitUniquePtr&& dohUnit, const char* reason) {
if (inMainThread) {
- handleResponse(*du->dsc->df, du->req, du->status_code, du->response, du->dsc->df->d_customResponseHeaders, du->contentType, true);
+ handleResponse(*dohUnit->dsc->dohFrontend, dohUnit->req, dohUnit->status_code, dohUnit->response, dohUnit->dsc->dohFrontend->d_customResponseHeaders, dohUnit->contentType, true);
/* so the unique pointer is stored in the InternalState which itself is stored in the unique pointer itself. We likely need
a better design, but for now let's just reset the internal one since we know it is no longer needed. */
- du->ids.du.reset();
+ dohUnit->ids.du.reset();
}
else {
- sendDoHUnitToTheMainThread(std::move(du), reason);
+ sendDoHUnitToTheMainThread(std::move(dohUnit), reason);
}
};
auto& ids = unit->ids;
- ids.du = std::move(unit);
- auto& du = ids.du;
uint16_t queryId = 0;
ComboAddress remote;
try {
- if (!du->req) {
+ if (unit->req == nullptr) {
// we got closed meanwhile. XXX small race condition here
- // but we should be fine as long as we don't touch du->req
+ // but we should be fine as long as we don't touch dohUnit->req
// outside of the main DoH thread
- du->status_code = 500;
- handleImmediateResponse(std::move(du), "DoH killed in flight");
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH killed in flight");
return;
}
- {
- // if there was no EDNS, we add it with a large buffer size
- // so we can use UDP to talk to the backend.
- auto dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.data()));
-
- if (!dh->arcount) {
- if (generateOptRR(std::string(), du->query, 4096, 4096, 0, false)) {
- dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.data())); // may have reallocated
- dh->arcount = htons(1);
- du->ids.ednsAdded = true;
- }
- }
- else {
- // we leave existing EDNS in place
- }
- }
-
- remote = du->ids.origRemote;
- DOHServerConfig* dsc = du->dsc;
+ remote = ids.origRemote;
+ DOHServerConfig* dsc = unit->dsc;
auto& holders = dsc->holders;
- ClientState& cs = *dsc->cs;
+ ClientState& clientState = *dsc->clientState;
- if (du->query.size() < sizeof(dnsheader)) {
- ++g_stats.nonCompliantQueries;
- ++cs.nonCompliantQueries;
- du->status_code = 400;
- handleImmediateResponse(std::move(du), "DoH non-compliant query");
+ if (unit->query.size() < sizeof(dnsheader) || unit->query.size() > std::numeric_limits<uint16_t>::max()) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ unit->status_code = 400;
+ handleImmediateResponse(std::move(unit), "DoH non-compliant query");
return;
}
- ++cs.queries;
- ++g_stats.queries;
- du->ids.queryRealTime.start();
+ ++clientState.queries;
+ ++dnsdist::metrics::g_stats.queries;
+ ids.queryRealTime.start();
{
/* don't keep that pointer around, it will be invalidated if the buffer is ever resized */
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(du->query.data());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const dnsheader_aligned dnsHeader(unit->query.data());
- if (!checkQueryHeaders(dh, cs)) {
- du->status_code = 400;
- handleImmediateResponse(std::move(du), "DoH invalid headers");
+ if (!checkQueryHeaders(*dnsHeader, clientState)) {
+ unit->status_code = 400;
+ handleImmediateResponse(std::move(unit), "DoH invalid headers");
return;
}
- if (dh->qdcount == 0) {
- dh->rcode = RCode::NotImp;
- dh->qr = true;
- du->response = std::move(du->query);
+ if (dnsHeader->qdcount == 0U) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+ unit->response = std::move(unit->query);
- handleImmediateResponse(std::move(du), "DoH empty query");
+ handleImmediateResponse(std::move(unit), "DoH empty query");
return;
}
- queryId = ntohs(dh->id);
+ queryId = ntohs(dnsHeader->id);
}
- auto downstream = du->downstream;
- du->ids.qname = DNSName(reinterpret_cast<const char*>(du->query.data()), du->query.size(), sizeof(dnsheader), false, &du->ids.qtype, &du->ids.qclass);
- DNSQuestion dq(du->ids, du->query);
- const uint16_t* flags = getFlagsFromDNSHeader(dq.getHeader());
- ids.origFlags = *flags;
- du->ids.cs = &cs;
- dq.sni = std::move(du->sni);
+ {
+ // if there was no EDNS, we add it with a large buffer size
+ // so we can use UDP to talk to the backend.
+ dnsheader_aligned dnsHeader(unit->query.data());
+ if (dnsHeader.get()->arcount == 0U) {
+ if (addEDNS(unit->query, 4096, false, 4096, 0)) {
+ ids.ednsAdded = true;
+ }
+ }
+ }
- auto result = processQuery(dq, holders, downstream);
+ auto downstream = unit->downstream;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ ids.qname = DNSName(reinterpret_cast<const char*>(unit->query.data()), static_cast<int>(unit->query.size()), static_cast<int>(sizeof(dnsheader)), false, &ids.qtype, &ids.qclass);
+ DNSQuestion dnsQuestion(ids, unit->query);
+ const uint16_t* flags = getFlagsFromDNSHeader(dnsQuestion.getHeader().get());
+ ids.origFlags = *flags;
+ ids.cs = &clientState;
+ dnsQuestion.sni = std::move(unit->sni);
+ ids.du = std::move(unit);
+ auto result = processQuery(dnsQuestion, holders, downstream);
if (result == ProcessQueryResult::Drop) {
- du->status_code = 403;
- handleImmediateResponse(std::move(du), "DoH dropped query");
+ unit = getDUFromIDS(ids);
+ unit->status_code = 403;
+ handleImmediateResponse(std::move(unit), "DoH dropped query");
return;
}
- else if (result == ProcessQueryResult::Asynchronous) {
+ if (result == ProcessQueryResult::Asynchronous) {
return;
}
- else if (result == ProcessQueryResult::SendAnswer) {
- if (du->response.empty()) {
- du->response = std::move(du->query);
+ if (result == ProcessQueryResult::SendAnswer) {
+ unit = getDUFromIDS(ids);
+ if (unit->response.empty()) {
+ unit->response = std::move(unit->query);
}
- if (du->response.size() >= sizeof(dnsheader) && du->contentType.empty()) {
- auto dh = reinterpret_cast<const struct dnsheader*>(du->response.data());
-
- handleResponseSent(du->ids.qname, QType(du->ids.qtype), 0., du->ids.origDest, ComboAddress(), du->response.size(), *dh, dnsdist::Protocol::DoH, dnsdist::Protocol::DoH, false);
+ if (unit->response.size() >= sizeof(dnsheader) && unit->contentType.empty()) {
+ dnsheader_aligned dnsHeader(unit->response.data());
+ handleResponseSent(unit->ids.qname, QType(unit->ids.qtype), 0., unit->ids.origDest, ComboAddress(), unit->response.size(), *(dnsHeader.get()), dnsdist::Protocol::DoH, dnsdist::Protocol::DoH, false);
}
- handleImmediateResponse(std::move(du), "DoH self-answered response");
+ handleImmediateResponse(std::move(unit), "DoH self-answered response");
return;
}
+ unit = getDUFromIDS(ids);
if (result != ProcessQueryResult::PassToBackend) {
- du->status_code = 500;
- handleImmediateResponse(std::move(du), "DoH no backend available");
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH no backend available");
return;
}
if (downstream == nullptr) {
- du->status_code = 502;
- handleImmediateResponse(std::move(du), "DoH no backend available");
+ unit->status_code = 502;
+ handleImmediateResponse(std::move(unit), "DoH no backend available");
return;
}
- du->downstream = downstream;
+ unit->downstream = downstream;
if (downstream->isTCPOnly()) {
std::string proxyProtocolPayload;
/* we need to do this _before_ creating the cross protocol query because
after that the buffer will have been moved */
if (downstream->d_config.useProxyProtocol) {
- proxyProtocolPayload = getProxyProtocolPayload(dq);
+ proxyProtocolPayload = getProxyProtocolPayload(dnsQuestion);
}
- du->ids.origID = htons(queryId);
- du->tcp = true;
+ unit->ids.origID = htons(queryId);
+ unit->tcp = true;
/* this moves du->ids, careful! */
- auto cpq = std::make_unique<DoHCrossProtocolQuery>(std::move(du), false);
+ auto cpq = std::make_unique<DoHCrossProtocolQuery>(std::move(unit), false);
+ if (!cpq) {
+ // make linters happy
+ return;
+ }
cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
if (downstream->passCrossProtocolQuery(std::move(cpq))) {
return;
}
- else {
- if (inMainThread) {
- du = cpq->releaseDU();
- du->status_code = 502;
- handleImmediateResponse(std::move(du), "DoH internal error");
+
+ if (inMainThread) {
+ // cpq is not altered if the call fails but linters are not smart enough to notice that
+ if (cpq) {
+ // NOLINTNEXTLINE(bugprone-use-after-move): cpq is not altered if the call fails
+ unit = cpq->releaseDU();
}
- else {
+ unit->status_code = 502;
+ handleImmediateResponse(std::move(unit), "DoH internal error");
+ }
+ else {
+ // cpq is not altered if the call fails but linters are not smart enough to notice that
+ if (cpq) {
+ // NOLINTNEXTLINE(bugprone-use-after-move): cpq is not altered if the call fails
cpq->handleInternalError();
}
- return;
}
+ return;
}
- ComboAddress dest = dq.ids.origDest;
- if (!assignOutgoingUDPQueryToBackend(downstream, htons(queryId), dq, du->query, dest)) {
- du->status_code = 502;
- handleImmediateResponse(std::move(du), "DoH internal error");
+ auto& query = unit->query;
+ ids.du = std::move(unit);
+ if (!assignOutgoingUDPQueryToBackend(downstream, htons(queryId), dnsQuestion, query)) {
+ unit = getDUFromIDS(ids);
+ unit->status_code = 502;
+ handleImmediateResponse(std::move(unit), "DoH internal error");
return;
}
}
catch (const std::exception& e) {
vinfolog("Got an error in DOH question thread while parsing a query from %s, id %d: %s", remote.toStringWithPort(), queryId, e.what());
- du->status_code = 500;
- handleImmediateResponse(std::move(du), "DoH internal error");
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH internal error");
return;
}
-
- return;
}
/* called when a HTTP response is about to be sent, from the main DoH thread */
@@ -808,16 +865,17 @@ static void on_response_ready_cb(struct st_h2o_filter_t *self, h2o_req_t *req, h
return;
}
- DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
+ auto* dsc = static_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
DOHFrontend::HTTPVersionStats* stats = nullptr;
if (req->version < 0x200) {
/* HTTP 1.x */
- stats = &dsc->df->d_http1Stats;
+ stats = &dsc->dohFrontend->d_http1Stats;
}
else {
/* HTTP 2.0 */
- stats = &dsc->df->d_http2Stats;
+ stats = &dsc->dohFrontend->d_http2Stats;
}
switch (req->res.status) {
@@ -848,10 +906,10 @@ static void on_response_ready_cb(struct st_h2o_filter_t *self, h2o_req_t *req, h
We use this to signal to the 'du' that this req is no longer alive */
static void on_generator_dispose(void *_self)
{
- DOHUnit** du = reinterpret_cast<DOHUnit**>(_self);
- if (*du) { // if 0, on_dnsdist cleaned up du already
- (*du)->self = nullptr;
- (*du)->req = nullptr;
+ auto* dohUnit = static_cast<DOHUnit**>(_self);
+ if (*dohUnit != nullptr) { // if nullptr, on_dnsdist cleaned up dohUnit already
+ (*dohUnit)->self = nullptr;
+ (*dohUnit)->req = nullptr;
}
}
@@ -862,6 +920,7 @@ static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_re
{
try {
/* we only parse it there as a sanity check, we will parse it again later */
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
DNSPacketMangler mangler(reinterpret_cast<char*>(query.data()), query.size());
mangler.skipDomainName();
mangler.skipBytes(4);
@@ -869,23 +928,24 @@ static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_re
/* we are doing quite some copies here, sorry about that,
but we can't keep accessing the req object once we are in a different thread
because the request might get killed by h2o at pretty much any time */
- auto du = std::make_unique<DOHUnit>(std::move(query), std::move(path), std::string(req->authority.base, req->authority.len));
- du->dsc = dsc;
- du->req = req;
- du->ids.origDest = local;
- du->ids.origRemote = remote;
- du->ids.protocol = dnsdist::Protocol::DoH;
- du->rsock = dsc->dohresponsepair[0];
+ auto dohUnit = std::make_unique<DOHUnit>(std::move(query), std::move(path), std::string(req->authority.base, req->authority.len));
+ dohUnit->dsc = dsc;
+ dohUnit->req = req;
+ dohUnit->ids.origDest = local;
+ dohUnit->ids.origRemote = remote;
+ dohUnit->ids.protocol = dnsdist::Protocol::DoH;
+ dohUnit->responseSender = &dsc->d_responseSender;
if (req->scheme != nullptr) {
- du->scheme = std::string(req->scheme->name.base, req->scheme->name.len);
+ dohUnit->scheme = std::string(req->scheme->name.base, req->scheme->name.len);
}
- du->query_at = req->query_at;
+ dohUnit->query_at = req->query_at;
- if (dsc->df->d_keepIncomingHeaders) {
- du->headers = std::make_unique<std::unordered_map<std::string, std::string>>();
- du->headers->reserve(req->headers.size);
+ if (dsc->dohFrontend->d_keepIncomingHeaders) {
+ dohUnit->headers = std::make_unique<std::unordered_map<std::string, std::string>>();
+ dohUnit->headers->reserve(req->headers.size);
for (size_t i = 0; i < req->headers.size; ++i) {
- (*du->headers)[std::string(req->headers.entries[i].name->base, req->headers.entries[i].name->len)] = std::string(req->headers.entries[i].value.base, req->headers.entries[i].value.len);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
+ (*dohUnit->headers)[std::string(req->headers.entries[i].name->base, req->headers.entries[i].name->len)] = std::string(req->headers.entries[i].value.base, req->headers.entries[i].value.len);
}
}
@@ -893,36 +953,25 @@ static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_re
h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn);
const char * sni = h2o_socket_get_ssl_server_name(sock);
if (sni != nullptr) {
- du->sni = sni;
+ dohUnit->sni = sni;
}
#endif /* HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME */
- du->self = reinterpret_cast<DOHUnit**>(h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose));
- auto ptr = du.release();
- *(ptr->self) = ptr;
+ dohUnit->self = static_cast<DOHUnit**>(h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose));
+ *(dohUnit->self) = dohUnit.get();
#ifdef USE_SINGLE_ACCEPTOR_THREAD
- processDOHQuery(DOHUnitUniquePtr(ptr, DOHUnit::release), true);
+ processDOHQuery(std::move(dohUnit), true);
#else /* USE_SINGLE_ACCEPTOR_THREAD */
- try {
- static_assert(sizeof(ptr) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
- ssize_t sent = write(dsc->dohquerypair[0], &ptr, sizeof(ptr));
- if (sent != sizeof(ptr)) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- ++g_stats.dohQueryPipeFull;
- vinfolog("Unable to pass a DoH query to the DoH worker thread because the pipe is full");
- }
- else {
- vinfolog("Unable to pass a DoH query to the DoH worker thread because we couldn't write to the pipe: %s", stringerror());
- }
- ptr->release();
- ptr = nullptr;
+ try {
+ if (!dsc->d_querySender.send(std::move(dohUnit))) {
+ ++dnsdist::metrics::g_stats.dohQueryPipeFull;
+ vinfolog("Unable to pass a DoH query to the DoH worker thread because the pipe is full");
h2o_send_error_500(req, "Internal Server Error", "Internal Server Error", 0);
}
}
catch (...) {
- if (ptr != nullptr) {
- ptr->release();
- }
+ vinfolog("Unable to pass a DoH query to the DoH worker thread because we couldn't write to the pipe: %s", stringerror());
+ h2o_send_error_500(req, "Internal Server Error", "Internal Server Error", 0);
}
#endif /* USE_SINGLE_ACCEPTOR_THREAD */
}
@@ -940,7 +989,9 @@ static bool getHTTPHeaderValue(const h2o_req_t* req, const std::string& headerNa
std::string_view headerNameView(headerName);
for (size_t i = 0; i < req->headers.size; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
if (std::string_view(req->headers.entries[i].name->base, req->headers.entries[i].name->len) == headerNameView) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
value = std::string_view(req->headers.entries[i].value.base, req->headers.entries[i].value.len);
/* don't stop there, we might have more than one header with the same name, and we want the last one */
found = true;
@@ -990,10 +1041,11 @@ static std::optional<ComboAddress> processForwardedForHeader(const h2o_req_t* re
static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
{
try {
- if (!req->conn->ctx->storage.size) {
+ if (req->conn->ctx->storage.size == 0) {
return 0; // although we might was well crash on this
}
- DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
+ auto* dsc = static_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn);
const int descriptor = h2o_socket_get_fd(sock);
@@ -1005,45 +1057,51 @@ static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
++conn.d_nbQueries;
if (conn.d_nbQueries == 1) {
if (h2o_socket_get_ssl_session_reused(sock) == 0) {
- ++dsc->cs->tlsNewSessions;
+ ++dsc->clientState->tlsNewSessions;
}
else {
- ++dsc->cs->tlsResumptions;
+ ++dsc->clientState->tlsResumptions;
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): h2o API
h2o_socket_getsockname(sock, reinterpret_cast<struct sockaddr*>(&conn.d_local));
}
auto remote = conn.d_remote;
- if (dsc->df->d_trustForwardedForHeader) {
+ if (dsc->dohFrontend->d_trustForwardedForHeader) {
auto newRemote = processForwardedForHeader(req, remote);
if (newRemote) {
- remote = std::move(*newRemote);
+ remote = *newRemote;
}
}
auto& holders = dsc->holders;
if (!holders.acl->match(remote)) {
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort());
- h2o_send_error_403(req, "Forbidden", "dns query not allowed because of ACL", 0);
+ h2o_send_error_403(req, "Forbidden", "DoH query not allowed because of ACL", 0);
return 0;
}
- if (auto tlsversion = h2o_socket_get_ssl_protocol_version(sock)) {
- if(!strcmp(tlsversion, "TLSv1.0"))
- ++dsc->cs->tls10queries;
- else if(!strcmp(tlsversion, "TLSv1.1"))
- ++dsc->cs->tls11queries;
- else if(!strcmp(tlsversion, "TLSv1.2"))
- ++dsc->cs->tls12queries;
- else if(!strcmp(tlsversion, "TLSv1.3"))
- ++dsc->cs->tls13queries;
- else
- ++dsc->cs->tlsUnknownqueries;
+ if (const auto* tlsversion = h2o_socket_get_ssl_protocol_version(sock)) {
+ if (strcmp(tlsversion, "TLSv1.0") == 0) {
+ ++dsc->clientState->tls10queries;
+ }
+ else if (strcmp(tlsversion, "TLSv1.1") == 0) {
+ ++dsc->clientState->tls11queries;
+ }
+ else if (strcmp(tlsversion, "TLSv1.2") == 0) {
+ ++dsc->clientState->tls12queries;
+ }
+ else if (strcmp(tlsversion, "TLSv1.3") == 0) {
+ ++dsc->clientState->tls13queries;
+ }
+ else {
+ ++dsc->clientState->tlsUnknownqueries;
+ }
}
- if (dsc->df->d_exactPathMatching) {
+ if (dsc->dohFrontend->d_exactPathMatching) {
const std::string_view pathOnly(req->path_normalized.base, req->path_normalized.len);
if (dsc->paths.count(pathOnly) == 0) {
h2o_send_error_404(req, "Not Found", "there is no endpoint configured for this path", 0);
@@ -1056,25 +1114,27 @@ static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
string path(req->path.base, req->path.len);
/* the responses map can be updated at runtime, so we need to take a copy of
the shared pointer, increasing the reference counter */
- auto responsesMap = dsc->df->d_responsesMap;
+ auto responsesMap = dsc->dohFrontend->d_responsesMap;
/* 1 byte for the root label, 2 type, 2 class, 4 TTL (fake), 2 record length, 2 option length, 2 option code, 2 family, 1 source, 1 scope, 16 max for a full v6 */
const size_t maxAdditionalSizeForEDNS = 35U;
if (responsesMap) {
for (const auto& entry : *responsesMap) {
if (entry->matches(path)) {
const auto& customHeaders = entry->getHeaders();
- handleResponse(*dsc->df, req, entry->getStatusCode(), entry->getContent(), customHeaders ? *customHeaders : dsc->df->d_customResponseHeaders, std::string(), false);
+ handleResponse(*dsc->dohFrontend, req, entry->getStatusCode(), entry->getContent(), customHeaders ? *customHeaders : dsc->dohFrontend->d_customResponseHeaders, std::string(), false);
return 0;
}
}
}
- if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))) {
- ++dsc->df->d_postqueries;
- if(req->version >= 0x0200)
- ++dsc->df->d_http2Stats.d_nbQueries;
- else
- ++dsc->df->d_http1Stats.d_nbQueries;
+ if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")) != 0) {
+ ++dsc->dohFrontend->d_postqueries;
+ if (req->version >= 0x0200) {
+ ++dsc->dohFrontend->d_http2Stats.d_nbQueries;
+ }
+ else {
+ ++dsc->dohFrontend->d_http1Stats.d_nbQueries;
+ }
PacketBuffer query;
/* We reserve a few additional bytes to be able to add EDNS later */
@@ -1085,9 +1145,10 @@ static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
}
else if(req->query_at != SIZE_MAX && (req->path.len - req->query_at > 5)) {
auto pos = path.find("?dns=");
- if(pos == string::npos)
+ if (pos == string::npos) {
pos = path.find("&dns=");
- if(pos != string::npos) {
+ }
+ if (pos != string::npos) {
// need to base64url decode this
string sdns(path.substr(pos+5));
boost::replace_all(sdns,"-", "+");
@@ -1110,119 +1171,47 @@ static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
decoded.reserve(estimate + maxAdditionalSizeForEDNS);
if(B64Decode(sdns, decoded) < 0) {
h2o_send_error_400(req, "Bad Request", "Unable to decode BASE64-URL", 0);
- ++dsc->df->d_badrequests;
+ ++dsc->dohFrontend->d_badrequests;
return 0;
}
- else {
- ++dsc->df->d_getqueries;
- if(req->version >= 0x0200)
- ++dsc->df->d_http2Stats.d_nbQueries;
- else
- ++dsc->df->d_http1Stats.d_nbQueries;
- doh_dispatch_query(dsc, self, req, std::move(decoded), conn.d_local, remote, std::move(path));
+ ++dsc->dohFrontend->d_getqueries;
+ if (req->version >= 0x0200) {
+ ++dsc->dohFrontend->d_http2Stats.d_nbQueries;
}
+ else {
+ ++dsc->dohFrontend->d_http1Stats.d_nbQueries;
+ }
+
+ doh_dispatch_query(dsc, self, req, std::move(decoded), conn.d_local, remote, std::move(path));
}
else
{
vinfolog("HTTP request without DNS parameter: %s", req->path.base);
h2o_send_error_400(req, "Bad Request", "Unable to find the DNS parameter", 0);
- ++dsc->df->d_badrequests;
+ ++dsc->dohFrontend->d_badrequests;
return 0;
}
}
else {
h2o_send_error_400(req, "Bad Request", "Unable to parse the request", 0);
- ++dsc->df->d_badrequests;
+ ++dsc->dohFrontend->d_badrequests;
}
return 0;
}
- catch(const std::exception& e)
- {
- errlog("DOH Handler function failed with error %s", e.what());
+ catch (const std::exception& e) {
+ vinfolog("DOH Handler function failed with error: '%s'", e.what());
return 0;
}
}
-HTTPHeaderRule::HTTPHeaderRule(const std::string& header, const std::string& regex)
- : d_header(toLower(header)), d_regex(regex), d_visual("http[" + header+ "] ~ " + regex)
-{
-}
-
-bool HTTPHeaderRule::matches(const DNSQuestion* dq) const
-{
- if (!dq->ids.du || !dq->ids.du->headers) {
- return false;
- }
-
- for (const auto& header : *dq->ids.du->headers) {
- if (header.first == d_header) {
- return d_regex.match(header.second);
- }
- }
- return false;
-}
-
-string HTTPHeaderRule::toString() const
-{
- return d_visual;
-}
-
-HTTPPathRule::HTTPPathRule(const std::string& path)
- : d_path(path)
-{
-
-}
-
-bool HTTPPathRule::matches(const DNSQuestion* dq) const
-{
- if (!dq->ids.du) {
- return false;
- }
-
- if (dq->ids.du->query_at == SIZE_MAX) {
- return dq->ids.du->path == d_path;
- }
- else {
- return d_path.compare(0, d_path.size(), dq->ids.du->path, 0, dq->ids.du->query_at) == 0;
- }
-}
-
-string HTTPPathRule::toString() const
-{
- return "url path == " + d_path;
-}
-
-HTTPPathRegexRule::HTTPPathRegexRule(const std::string& regex): d_regex(regex), d_visual("http path ~ " + regex)
-{
-}
-
-bool HTTPPathRegexRule::matches(const DNSQuestion* dq) const
+const std::unordered_map<std::string, std::string>& DOHUnit::getHTTPHeaders() const
{
- if (!dq->ids.du) {
- return false;
+ if (!headers) {
+ static const HeadersMap empty{};
+ return empty;
}
-
- return d_regex.match(dq->ids.du->getHTTPPath());
-}
-
-string HTTPPathRegexRule::toString() const
-{
- return d_visual;
-}
-
-std::unordered_map<std::string, std::string> DOHUnit::getHTTPHeaders() const
-{
- std::unordered_map<std::string, std::string> results;
- if (headers) {
- results.reserve(headers->size());
-
- for (const auto& header : *headers) {
- results.insert(header);
- }
- }
-
- return results;
+ return *headers;
}
std::string DOHUnit::getHTTPPath() const
@@ -1230,17 +1219,15 @@ std::string DOHUnit::getHTTPPath() const
if (query_at == SIZE_MAX) {
return path;
}
- else {
- return std::string(path, 0, query_at);
- }
+ return {path, 0, query_at};
}
-std::string DOHUnit::getHTTPHost() const
+const std::string& DOHUnit::getHTTPHost() const
{
return host;
}
-std::string DOHUnit::getHTTPScheme() const
+const std::string& DOHUnit::getHTTPScheme() const
{
return scheme;
}
@@ -1248,11 +1235,9 @@ std::string DOHUnit::getHTTPScheme() const
std::string DOHUnit::getHTTPQueryString() const
{
if (query_at == SIZE_MAX) {
- return std::string();
- }
- else {
- return path.substr(query_at);
+ return {};
}
+ return path.substr(query_at);
}
void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const std::string& contentType_)
@@ -1273,47 +1258,41 @@ void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const s
/* query has been parsed by h2o, which called doh_handler() in the main DoH thread.
In order not to block for long, doh_handler() called doh_dispatch_query() which allocated
a DOHUnit object and passed it to us */
-static void dnsdistclient(int qsock)
+static void dnsdistclient(pdns::channel::Receiver<DOHUnit>&& receiver)
{
setThreadName("dnsdist/doh-cli");
for(;;) {
try {
- DOHUnit* ptr = nullptr;
- ssize_t got = read(qsock, &ptr, sizeof(ptr));
- if (got < 0) {
- warnlog("Error receiving internal DoH query: %s", strerror(errno));
- continue;
- }
- else if (static_cast<size_t>(got) < sizeof(ptr)) {
+ auto tmp = receiver.receive();
+ if (!tmp) {
continue;
}
-
- DOHUnitUniquePtr du(ptr, DOHUnit::release);
+ auto dohUnit = std::move(*tmp);
/* we are not in the main DoH thread anymore, so there is a real risk of
a race condition where h2o kills the query while we are processing it,
- so we can't touch the content of du->req until we are back into the
+ so we can't touch the content of dohUnit->req until we are back into the
main DoH thread */
- if (!du->req) {
+ if (dohUnit->req == nullptr) {
// it got killed in flight already
- du->self = nullptr;
+ dohUnit->self = nullptr;
continue;
}
- processDOHQuery(std::move(du), false);
+ processDOHQuery(std::move(dohUnit), false);
}
catch (const std::exception& e) {
- errlog("Error while processing query received over DoH: %s", e.what());
+ vinfolog("Error while processing query received over DoH: %s", e.what());
}
catch (...) {
- errlog("Unspecified error while processing query received over DoH");
+ vinfolog("Unspecified error while processing query received over DoH");
}
}
}
#endif /* USE_SINGLE_ACCEPTOR_THREAD */
/* Called in the main DoH thread if h2o finds that dnsdist gave us an answer by writing into
- the dohresponsepair[0] side of the pipe so from:
+ the response channel so from:
- handleDOHTimeout() when we did not get a response fast enough (called
either from the health check thread (active) or from the frontend ones (reused))
- dnsdistclient (error 500 because processDOHQuery() returned a negative value)
@@ -1326,73 +1305,71 @@ static void on_dnsdist(h2o_socket_t *listener, const char *err)
for the CPU, the first thing we need to do is to send responses to free slots
anyway, otherwise queries and responses are piling up in our pipes, consuming
memory and likely coming up too late after the client has gone away */
+ auto* dsc = static_cast<DOHServerConfig*>(listener->data);
while (true) {
- DOHUnit *ptr = nullptr;
- DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(listener->data);
- ssize_t got = read(dsc->dohresponsepair[1], &ptr, sizeof(ptr));
-
- if (got < 0) {
- if (errno != EWOULDBLOCK && errno != EAGAIN) {
- errlog("Error reading a DOH internal response: %s", strerror(errno));
+ DOHUnitUniquePtr dohUnit{nullptr};
+ try {
+ auto tmp = dsc->d_responseReceiver.receive();
+ if (!tmp) {
+ return;
}
- return;
+ dohUnit = std::move(*tmp);
}
- else if (static_cast<size_t>(got) != sizeof(ptr)) {
- errlog("Error reading a DoH internal response, got %d bytes instead of the expected %d", got, sizeof(ptr));
+ catch (const std::exception& e) {
+ warnlog("Error reading a DOH internal response: %s", e.what());
return;
}
- DOHUnitUniquePtr du(ptr, DOHUnit::release);
- if (!du->req) { // it got killed in flight
- du->self = nullptr;
+ if (dohUnit->req == nullptr) { // it got killed in flight
+ dohUnit->self = nullptr;
continue;
}
- if (!du->tcp &&
- du->truncated &&
- du->query.size() > du->proxyProtocolPayloadSize &&
- (du->query.size() - du->proxyProtocolPayloadSize) > sizeof(dnsheader)) {
+ if (!dohUnit->tcp &&
+ dohUnit->truncated &&
+ dohUnit->query.size() > dohUnit->ids.d_proxyProtocolPayloadSize &&
+ (dohUnit->query.size() - dohUnit->ids.d_proxyProtocolPayloadSize) > sizeof(dnsheader)) {
/* restoring the original ID */
- dnsheader* queryDH = reinterpret_cast<struct dnsheader*>(du->query.data() + du->proxyProtocolPayloadSize);
- queryDH->id = du->ids.origID;
- du->ids.forwardedOverUDP = false;
- du->tcp = true;
- du->truncated = false;
- du->response.clear();
+ dnsdist::PacketMangling::editDNSHeaderFromRawPacket(&dohUnit->query.at(dohUnit->ids.d_proxyProtocolPayloadSize), [oldID=dohUnit->ids.origID](dnsheader& header) {
+ header.id = oldID;
+ return true;
+ });
+ dohUnit->ids.forwardedOverUDP = false;
+ dohUnit->tcp = true;
+ dohUnit->truncated = false;
+ dohUnit->response.clear();
- auto cpq = std::make_unique<DoHCrossProtocolQuery>(std::move(du), false);
+ auto cpq = std::make_unique<DoHCrossProtocolQuery>(std::move(dohUnit), false);
if (g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq))) {
continue;
}
- else {
- vinfolog("Unable to pass DoH query to a TCP worker thread after getting a TC response over UDP");
- continue;
- }
+ vinfolog("Unable to pass DoH query to a TCP worker thread after getting a TC response over UDP");
+ continue;
}
- if (du->self) {
+ if (dohUnit->self != nullptr) {
// we are back in the h2o main thread now, so we don't risk
- // a race (h2o killing the query) when accessing du->req anymore
- *du->self = nullptr; // so we don't clean up again in on_generator_dispose
- du->self = nullptr;
+ // a race (h2o killing the query) when accessing dohUnit->req anymore
+ *dohUnit->self = nullptr; // so we don't clean up again in on_generator_dispose
+ dohUnit->self = nullptr;
}
- handleResponse(*dsc->df, du->req, du->status_code, du->response, dsc->df->d_customResponseHeaders, du->contentType, true);
+ handleResponse(*dsc->dohFrontend, dohUnit->req, dohUnit->status_code, dohUnit->response, dsc->dohFrontend->d_customResponseHeaders, dohUnit->contentType, true);
}
}
/* called when a TCP connection has been accepted, the TLS session has not been established */
static void on_accept(h2o_socket_t *listener, const char *err)
{
- DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(listener->data);
- h2o_socket_t *sock = nullptr;
+ auto* dsc = static_cast<DOHServerConfig*>(listener->data);
if (err != nullptr) {
return;
}
- if ((sock = h2o_evloop_socket_accept(listener)) == nullptr) {
+ h2o_socket_t* sock = h2o_evloop_socket_accept(listener);
+ if (sock == nullptr) {
return;
}
@@ -1403,27 +1380,35 @@ static void on_accept(h2o_socket_t *listener, const char *err)
}
ComboAddress remote;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): h2o API
if (h2o_socket_getpeername(sock, reinterpret_cast<struct sockaddr*>(&remote)) == 0) {
vinfolog("Dropping DoH connection because we could not retrieve the remote host");
h2o_socket_close(sock);
return;
}
+ if (dsc->dohFrontend->d_earlyACLDrop && !dsc->dohFrontend->d_trustForwardedForHeader && !dsc->holders.acl->match(remote)) {
+ ++dnsdist::metrics::g_stats.aclDrops;
+ vinfolog("Dropping DoH connection from %s because of ACL", remote.toStringWithPort());
+ h2o_socket_close(sock);
+ return;
+ }
+
if (!dnsdist::IncomingConcurrentTCPConnectionsManager::accountNewTCPConnection(remote)) {
vinfolog("Dropping DoH connection from %s because we have too many from this client already", remote.toStringWithPort());
h2o_socket_close(sock);
return;
}
- auto concurrentConnections = ++dsc->cs->tcpCurrentConnections;
- if (dsc->cs->d_tcpConcurrentConnectionsLimit > 0 && concurrentConnections > dsc->cs->d_tcpConcurrentConnectionsLimit) {
- --dsc->cs->tcpCurrentConnections;
+ auto concurrentConnections = ++dsc->clientState->tcpCurrentConnections;
+ if (dsc->clientState->d_tcpConcurrentConnectionsLimit > 0 && concurrentConnections > dsc->clientState->d_tcpConcurrentConnectionsLimit) {
+ --dsc->clientState->tcpCurrentConnections;
h2o_socket_close(sock);
return;
}
- if (concurrentConnections > dsc->cs->tcpMaxConcurrentConnections.load()) {
- dsc->cs->tcpMaxConcurrentConnections.store(concurrentConnections);
+ if (concurrentConnections > dsc->clientState->tcpMaxConcurrentConnections.load()) {
+ dsc->clientState->tcpMaxConcurrentConnections.store(concurrentConnections);
}
auto& conn = t_conns[descriptor];
@@ -1438,14 +1423,14 @@ static void on_accept(h2o_socket_t *listener, const char *err)
sock->on_close.data = &conn;
sock->data = dsc;
- ++dsc->df->d_httpconnects;
+ ++dsc->dohFrontend->d_httpconnects;
h2o_accept(conn.d_acceptCtx->get(), sock);
}
-static int create_listener(std::shared_ptr<DOHServerConfig>& dsc, int fd)
+static int create_listener(std::shared_ptr<DOHServerConfig>& dsc, int descriptor)
{
- auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ);
+ auto* sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, descriptor, H2O_SOCKET_FLAG_DONT_READ);
sock->data = dsc.get();
h2o_socket_read_start(sock, on_accept);
@@ -1458,25 +1443,27 @@ static int ocsp_stapling_callback(SSL* ssl, void* arg)
if (ssl == nullptr || arg == nullptr) {
return SSL_TLSEXT_ERR_NOACK;
}
- const auto ocspMap = reinterpret_cast<std::map<int, std::string>*>(arg);
+ const auto* ocspMap = static_cast<std::map<int, std::string>*>(arg);
return libssl_ocsp_stapling_callback(ssl, *ocspMap);
}
#endif /* DISABLE_OCSP_STAPLING */
#if OPENSSL_VERSION_MAJOR >= 3
-static int ticket_key_callback(SSL *s, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char *iv, EVP_CIPHER_CTX *ectx, EVP_MAC_CTX *hctx, int enc)
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays): OpenSSL API
+static int ticket_key_callback(SSL* sslContext, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* ivector, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx, int enc)
#else
-static int ticket_key_callback(SSL *s, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays): OpenSSL API
+static int ticket_key_callback(SSL *sslContext, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* ivector, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx, int enc)
#endif
{
- DOHAcceptContext* ctx = reinterpret_cast<DOHAcceptContext*>(libssl_get_ticket_key_callback_data(s));
+ auto* ctx = static_cast<DOHAcceptContext*>(libssl_get_ticket_key_callback_data(sslContext));
if (ctx == nullptr || !ctx->d_ticketKeys) {
return -1;
}
ctx->handleTicketsKeyRotation();
- auto ret = libssl_ticket_key_callback(s, *ctx->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+ auto ret = libssl_ticket_key_callback(sslContext, *ctx->d_ticketKeys, keyName, ivector, ectx, hctx, enc);
if (enc == 0) {
if (ret == 0) {
++ctx->d_cs->tlsUnknownTicketKey;
@@ -1494,7 +1481,7 @@ static void setupTLSContext(DOHAcceptContext& acceptCtx,
TLSErrorCounters& counters)
{
if (tlsConfig.d_ciphers.empty()) {
- tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS;
+ tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS.data();
}
auto [ctx, warnings] = libssl_init_server_context(tlsConfig, acceptCtx.d_ocspResponses);
@@ -1535,91 +1522,29 @@ static void setupTLSContext(DOHAcceptContext& acceptCtx,
acceptCtx.loadTicketsKeys(tlsConfig.d_ticketKeyFile);
}
- auto nativeCtx = acceptCtx.get();
+ auto* nativeCtx = acceptCtx.get();
nativeCtx->ssl_ctx = ctx.release();
}
static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool setupTLS)
{
- auto nativeCtx = ctx.get();
+ auto* nativeCtx = ctx.get();
nativeCtx->ctx = &dsc.h2o_ctx;
nativeCtx->hosts = dsc.h2o_config.hosts;
- ctx.d_ticketsKeyRotationDelay = dsc.df->d_tlsConfig.d_ticketsKeyRotationDelay;
+ auto dohFrontend = std::atomic_load_explicit(&dsc.dohFrontend, std::memory_order_acquire);
+ ctx.d_ticketsKeyRotationDelay = dohFrontend->d_tlsContext.d_tlsConfig.d_ticketsKeyRotationDelay;
- if (setupTLS && dsc.df->isHTTPS()) {
+ if (setupTLS && dohFrontend->isHTTPS()) {
try {
setupTLSContext(ctx,
- dsc.df->d_tlsConfig,
- dsc.df->d_tlsCounters);
+ dohFrontend->d_tlsContext.d_tlsConfig,
+ dohFrontend->d_tlsContext.d_tlsCounters);
}
catch (const std::runtime_error& e) {
- throw std::runtime_error("Error setting up TLS context for DoH listener on '" + dsc.df->d_local.toStringWithPort() + "': " + e.what());
- }
- }
- ctx.d_cs = dsc.cs;
-}
-
-void DOHFrontend::rotateTicketsKey(time_t now)
-{
- if (d_dsc && d_dsc->accept_ctx) {
- d_dsc->accept_ctx->rotateTicketsKey(now);
- }
-}
-
-void DOHFrontend::loadTicketsKeys(const std::string& keyFile)
-{
- if (d_dsc && d_dsc->accept_ctx) {
- d_dsc->accept_ctx->loadTicketsKeys(keyFile);
- }
-}
-
-void DOHFrontend::handleTicketsKeyRotation()
-{
- if (d_dsc && d_dsc->accept_ctx) {
- d_dsc->accept_ctx->handleTicketsKeyRotation();
- }
-}
-
-time_t DOHFrontend::getNextTicketsKeyRotation() const
-{
- if (d_dsc && d_dsc->accept_ctx) {
- return d_dsc->accept_ctx->getNextTicketsKeyRotation();
- }
- return 0;
-}
-
-size_t DOHFrontend::getTicketsKeysCount() const
-{
- size_t res = 0;
- if (d_dsc && d_dsc->accept_ctx) {
- res = d_dsc->accept_ctx->getTicketsKeysCount();
- }
- return res;
-}
-
-void DOHFrontend::reloadCertificates()
-{
- auto newAcceptContext = std::make_shared<DOHAcceptContext>();
- setupAcceptContext(*newAcceptContext, *d_dsc, true);
- std::atomic_store_explicit(&d_dsc->accept_ctx, newAcceptContext, std::memory_order_release);
-}
-
-void DOHFrontend::setup()
-{
- registerOpenSSLUser();
-
- d_dsc = std::make_shared<DOHServerConfig>(d_idleTimeout, d_internalPipeBufferSize);
-
- if (isHTTPS()) {
- try {
- setupTLSContext(*d_dsc->accept_ctx,
- d_tlsConfig,
- d_tlsCounters);
- }
- catch (const std::runtime_error& e) {
- throw std::runtime_error("Error setting up TLS context for DoH listener on '" + d_local.toStringWithPort() + "': " + e.what());
+ throw std::runtime_error("Error setting up TLS context for DoH listener on '" + dohFrontend->d_tlsContext.d_addr.toStringWithPort() + "': " + e.what());
}
}
+ ctx.d_cs = dsc.clientState;
}
static h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *path, int (*on_req)(h2o_handler_t *, h2o_req_t *))
@@ -1629,7 +1554,7 @@ static h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *pa
return pathconf;
}
h2o_filter_t *filter = h2o_create_filter(pathconf, sizeof(*filter));
- if (filter) {
+ if (filter != nullptr) {
filter->on_setup_ostream = on_response_ready_cb;
}
@@ -1642,38 +1567,39 @@ static h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *pa
}
// this is the entrypoint from dnsdist.cc
-void dohThread(ClientState* cs)
+void dohThread(ClientState* clientState)
{
try {
- std::shared_ptr<DOHFrontend>& df = cs->dohFrontend;
- auto& dsc = df->d_dsc;
- dsc->cs = cs;
- dsc->df = cs->dohFrontend;
- dsc->h2o_config.server_name = h2o_iovec_init(df->d_serverTokens.c_str(), df->d_serverTokens.size());
+ std::shared_ptr<DOHFrontend>& dohFrontend = clientState->dohFrontend;
+ auto& dsc = dohFrontend->d_dsc;
+ dsc->clientState = clientState;
+ std::atomic_store_explicit(&dsc->dohFrontend, clientState->dohFrontend, std::memory_order_release);
+ dsc->h2o_config.server_name = h2o_iovec_init(dohFrontend->d_serverTokens.c_str(), dohFrontend->d_serverTokens.size());
#ifndef USE_SINGLE_ACCEPTOR_THREAD
- std::thread dnsdistThread(dnsdistclient, dsc->dohquerypair[1]);
+ std::thread dnsdistThread(dnsdistclient, std::move(dsc->d_queryReceiver));
dnsdistThread.detach(); // gets us better error reporting
#endif
setThreadName("dnsdist/doh");
// I wonder if this registers an IP address.. I think it does
// this may mean we need to actually register a site "name" here and not the IP address
- h2o_hostconf_t *hostconf = h2o_config_register_host(&dsc->h2o_config, h2o_iovec_init(df->d_local.toString().c_str(), df->d_local.toString().size()), 65535);
+ h2o_hostconf_t *hostconf = h2o_config_register_host(&dsc->h2o_config, h2o_iovec_init(dohFrontend->d_tlsContext.d_addr.toString().c_str(), dohFrontend->d_tlsContext.d_addr.toString().size()), 65535);
- for(const auto& url : df->d_urls) {
+ dsc->paths = dohFrontend->d_urls;
+ for (const auto& url : dsc->paths) {
register_handler(hostconf, url.c_str(), doh_handler);
- dsc->paths.insert(url);
}
h2o_context_init(&dsc->h2o_ctx, h2o_evloop_create(), &dsc->h2o_config);
// in this complicated way we insert the DOHServerConfig pointer in there
h2o_vector_reserve(nullptr, &dsc->h2o_ctx.storage, 1);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
dsc->h2o_ctx.storage.entries[0].data = dsc.get();
++dsc->h2o_ctx.storage.size;
- auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->dohresponsepair[1], H2O_SOCKET_FLAG_DONT_READ);
+ auto* sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->d_responseReceiver.getDescriptor(), H2O_SOCKET_FLAG_DONT_READ);
sock->data = dsc.get();
// this listens to responses from dnsdist to turn into http responses
@@ -1681,12 +1607,12 @@ void dohThread(ClientState* cs)
setupAcceptContext(*dsc->accept_ctx, *dsc, false);
- if (create_listener(dsc, cs->tcpFD) != 0) {
- throw std::runtime_error("DOH server failed to listen on " + df->d_local.toStringWithPort() + ": " + strerror(errno));
+ if (create_listener(dsc, clientState->tcpFD) != 0) {
+ throw std::runtime_error("DOH server failed to listen on " + dohFrontend->d_tlsContext.d_addr.toStringWithPort() + ": " + stringerror(errno));
}
- for (const auto& [addr, fd] : cs->d_additionalAddresses) {
- if (create_listener(dsc, fd) != 0) {
- throw std::runtime_error("DOH server failed to listen on additional address " + addr.toStringWithPort() + " for DOH local" + df->d_local.toStringWithPort() + ": " + strerror(errno));
+ for (const auto& [addr, descriptor] : clientState->d_additionalAddresses) {
+ if (create_listener(dsc, descriptor) != 0) {
+ throw std::runtime_error("DOH server failed to listen on additional address " + addr.toStringWithPort() + " for DOH local" + dohFrontend->d_tlsContext.d_addr.toStringWithPort() + ": " + stringerror(errno));
}
}
@@ -1695,12 +1621,12 @@ void dohThread(ClientState* cs)
int result = h2o_evloop_run(dsc->h2o_ctx.loop, INT32_MAX);
if (result == -1) {
if (errno != EINTR) {
- errlog("Error in the DoH event loop: %s", strerror(errno));
+ errlog("Error in the DoH event loop: %s", stringerror(errno));
stop = true;
}
}
}
- while (stop == false);
+ while (!stop);
}
catch (const std::exception& e) {
@@ -1711,55 +1637,117 @@ void dohThread(ClientState* cs)
}
}
-void handleUDPResponseForDoH(DOHUnitUniquePtr&& du, PacketBuffer&& udpResponse, InternalQueryState&& state)
+void DOHUnit::handleUDPResponse(PacketBuffer&& udpResponse, InternalQueryState&& state, [[maybe_unused]] const std::shared_ptr<DownstreamState>& downstream_)
{
- du->response = std::move(udpResponse);
- du->ids = std::move(state);
+ auto dohUnit = std::unique_ptr<DOHUnit>(this);
+ dohUnit->ids = std::move(state);
- const dnsheader* dh = reinterpret_cast<const struct dnsheader*>(du->response.data());
- if (!dh->tc) {
+ {
+ dnsheader_aligned dnsHeader(udpResponse.data());
+ if (dnsHeader.get()->tc) {
+ dohUnit->truncated = true;
+ }
+ }
+ if (!dohUnit->truncated) {
static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions = g_respruleactions.getLocal();
static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
- DNSResponse dr(du->ids, du->response, du->downstream);
- dnsheader cleartextDH;
- memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
+ DNSResponse dnsResponse(dohUnit->ids, udpResponse, dohUnit->downstream);
+ dnsheader cleartextDH{};
+ memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
- dr.ids.du = std::move(du);
- if (!processResponse(dr.ids.du->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false)) {
- if (dr.ids.du) {
- dr.ids.du->status_code = 503;
- sendDoHUnitToTheMainThread(std::move(dr.ids.du), "Response dropped by rules");
+ dnsResponse.ids.du = std::move(dohUnit);
+ if (!processResponse(udpResponse, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (dnsResponse.ids.du) {
+ dohUnit = getDUFromIDS(dnsResponse.ids);
+ dohUnit->status_code = 503;
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "Response dropped by rules");
}
return;
}
- if (dr.isAsynchronous()) {
+ if (dnsResponse.isAsynchronous()) {
return;
}
- du = std::move(dr.ids.du);
- double udiff = du->ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (https), took %f usec", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
+ dohUnit = getDUFromIDS(dnsResponse.ids);
+ dohUnit->response = std::move(udpResponse);
+ double udiff = dohUnit->ids.queryRealTime.udiff();
+ vinfolog("Got answer from %s, relayed to %s (https), took %f us", dohUnit->downstream->d_config.remote.toStringWithPort(), dohUnit->ids.origRemote.toStringWithPort(), udiff);
- handleResponseSent(du->ids, udiff, dr.ids.origRemote, du->downstream->d_config.remote, du->response.size(), cleartextDH, du->downstream->getProtocol(), true);
+ handleResponseSent(dohUnit->ids, udiff, dnsResponse.ids.origRemote, dohUnit->downstream->d_config.remote, dohUnit->response.size(), cleartextDH, dohUnit->downstream->getProtocol(), true);
- ++g_stats.responses;
- if (du->ids.cs) {
- ++du->ids.cs->responses;
+ ++dnsdist::metrics::g_stats.responses;
+ if (dohUnit->ids.cs != nullptr) {
+ ++dohUnit->ids.cs->responses;
}
}
- else {
- du->truncated = true;
+
+ sendDoHUnitToTheMainThread(std::move(dohUnit), "DoH response");
+}
+
+void H2ODOHFrontend::rotateTicketsKey(time_t now)
+{
+ if (d_dsc && d_dsc->accept_ctx) {
+ d_dsc->accept_ctx->rotateTicketsKey(now);
}
+}
- sendDoHUnitToTheMainThread(std::move(du), "DoH response");
+void H2ODOHFrontend::loadTicketsKeys(const std::string& keyFile)
+{
+ if (d_dsc && d_dsc->accept_ctx) {
+ d_dsc->accept_ctx->loadTicketsKeys(keyFile);
+ }
}
-#else /* HAVE_DNS_OVER_HTTPS */
+void H2ODOHFrontend::handleTicketsKeyRotation()
+{
+ if (d_dsc && d_dsc->accept_ctx) {
+ d_dsc->accept_ctx->handleTicketsKeyRotation();
+ }
+}
+
+std::string H2ODOHFrontend::getNextTicketsKeyRotation() const
+{
+ if (d_dsc && d_dsc->accept_ctx) {
+ return std::to_string(d_dsc->accept_ctx->getNextTicketsKeyRotation());
+ }
+ return {};
+}
+
+size_t H2ODOHFrontend::getTicketsKeysCount()
+{
+ size_t res = 0;
+ if (d_dsc && d_dsc->accept_ctx) {
+ res = d_dsc->accept_ctx->getTicketsKeysCount();
+ }
+ return res;
+}
-void handleDOHTimeout(DOHUnitUniquePtr&& oldDU)
+void H2ODOHFrontend::reloadCertificates()
{
+ auto newAcceptContext = std::make_shared<DOHAcceptContext>();
+ setupAcceptContext(*newAcceptContext, *d_dsc, true);
+ std::atomic_store_explicit(&d_dsc->accept_ctx, std::move(newAcceptContext), std::memory_order_release);
+}
+
+void H2ODOHFrontend::setup()
+{
+ registerOpenSSLUser();
+
+ d_dsc = std::make_shared<DOHServerConfig>(d_idleTimeout, d_internalPipeBufferSize);
+
+ if (isHTTPS()) {
+ try {
+ setupTLSContext(*d_dsc->accept_ctx,
+ d_tlsContext.d_tlsConfig,
+ d_tlsContext.d_tlsCounters);
+ }
+ catch (const std::runtime_error& e) {
+ throw std::runtime_error("Error setting up TLS context for DoH listener on '" + d_tlsContext.d_addr.toStringWithPort() + "': " + e.what());
+ }
+ }
}
+#endif /* HAVE_LIBH2OEVLOOP */
#endif /* HAVE_DNS_OVER_HTTPS */
diff --git a/doh.hh b/doh.hh
index 96e65f1..58a26f1 100644
--- a/doh.hh
+++ b/doh.hh
@@ -21,266 +21,37 @@
*/
#pragma once
-#include <unordered_map>
+#include "config.h"
-#include "iputils.hh"
-#include "libssl.hh"
-#include "noinitvector.hh"
-#include "stat_t.hh"
+#ifdef HAVE_DNS_OVER_HTTPS
+#ifdef HAVE_LIBH2OEVLOOP
-struct DOHServerConfig;
+#include <ctime>
+#include <memory>
+#include <string>
-class DOHResponseMapEntry
-{
-public:
- DOHResponseMapEntry(const std::string& regex, uint16_t status, const PacketBuffer& content, const boost::optional<std::unordered_map<std::string, std::string>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
- {
- if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() -1) != 0) {
- // we need to make sure it's null-terminated
- d_content.push_back(0);
- }
- }
-
- bool matches(const std::string& path) const
- {
- return d_regex.match(path);
- }
-
- uint16_t getStatusCode() const
- {
- return d_status;
- }
-
- const PacketBuffer& getContent() const
- {
- return d_content;
- }
-
- const boost::optional<std::unordered_map<std::string, std::string>>& getHeaders() const
- {
- return d_customHeaders;
- }
-
-private:
- Regex d_regex;
- boost::optional<std::unordered_map<std::string, std::string>> d_customHeaders;
- PacketBuffer d_content;
- uint16_t d_status;
-};
-
-struct DOHFrontend
-{
- DOHFrontend()
- {
- }
-
- std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
- std::shared_ptr<std::vector<std::shared_ptr<DOHResponseMapEntry>>> d_responsesMap;
- TLSConfig d_tlsConfig;
- TLSErrorCounters d_tlsCounters;
- std::string d_serverTokens{"h2o/dnsdist"};
- std::unordered_map<std::string, std::string> d_customResponseHeaders;
- ComboAddress d_local;
-
- uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds
- std::vector<std::string> d_urls;
-
- pdns::stat_t d_httpconnects{0}; // number of TCP/IP connections established
- pdns::stat_t d_getqueries{0}; // valid DNS queries received via GET
- pdns::stat_t d_postqueries{0}; // valid DNS queries received via POST
- pdns::stat_t d_badrequests{0}; // request could not be converted to dns query
- pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response
- pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response
- pdns::stat_t d_validresponses{0}; // valid responses sent out
-
- struct HTTPVersionStats
- {
- pdns::stat_t d_nbQueries{0}; // valid DNS queries received
- pdns::stat_t d_nb200Responses{0};
- pdns::stat_t d_nb400Responses{0};
- pdns::stat_t d_nb403Responses{0};
- pdns::stat_t d_nb500Responses{0};
- pdns::stat_t d_nb502Responses{0};
- pdns::stat_t d_nbOtherResponses{0};
- };
-
- HTTPVersionStats d_http1Stats;
- HTTPVersionStats d_http2Stats;
-#ifdef __linux__
- // On Linux this gives us 128k pending queries (default is 8192 queries),
- // which should be enough to deal with huge spikes
- uint32_t d_internalPipeBufferSize{1024*1024};
-#else
- uint32_t d_internalPipeBufferSize{0};
-#endif
- bool d_sendCacheControlHeaders{true};
- bool d_trustForwardedForHeader{false};
- /* whether we require tue query path to exactly match one of configured ones,
- or accept everything below these paths. */
- bool d_exactPathMatching{true};
- bool d_keepIncomingHeaders{false};
-
- time_t getTicketsKeyRotationDelay() const
- {
- return d_tlsConfig.d_ticketsKeyRotationDelay;
- }
-
- bool isHTTPS() const
- {
- return !d_tlsConfig.d_certKeyPairs.empty();
- }
-
-#ifndef HAVE_DNS_OVER_HTTPS
- void setup()
- {
- }
-
- void reloadCertificates()
- {
- }
-
- void rotateTicketsKey(time_t /* now */)
- {
- }
-
- void loadTicketsKeys(const std::string& /* keyFile */)
- {
- }
-
- void handleTicketsKeyRotation()
- {
- }
-
- time_t getNextTicketsKeyRotation() const
- {
- return 0;
- }
-
- size_t getTicketsKeysCount() const
- {
- size_t res = 0;
- return res;
- }
-
-#else
- void setup();
- void reloadCertificates();
-
- void rotateTicketsKey(time_t now);
- void loadTicketsKeys(const std::string& keyFile);
- void handleTicketsKeyRotation();
- time_t getNextTicketsKeyRotation() const;
- size_t getTicketsKeysCount() const;
-#endif /* HAVE_DNS_OVER_HTTPS */
-};
-
-#ifndef HAVE_DNS_OVER_HTTPS
-struct DOHUnit
-{
- static void release(DOHUnit*)
- {
- }
-
- void get()
- {
- }
-
- void release()
- {
- }
-
- size_t proxyProtocolPayloadSize{0};
- uint16_t status_code{200};
-};
-
-#else /* HAVE_DNS_OVER_HTTPS */
-#include <unordered_map>
+struct CrossProtocolQuery;
+struct DNSQuestion;
-#include "dnsdist-idstate.hh"
+std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
-struct st_h2o_req_t;
-struct DownstreamState;
+#include "dnsdist-doh-common.hh"
-struct DOHUnit
+struct H2ODOHFrontend : public DOHFrontend
{
- DOHUnit(PacketBuffer&& q, std::string&& p, std::string&& h): path(std::move(p)), host(std::move(h)), query(std::move(q))
- {
- ids.ednsAdded = false;
- }
-
- DOHUnit(const DOHUnit&) = delete;
- DOHUnit& operator=(const DOHUnit&) = delete;
-
- void get()
- {
- ++d_refcnt;
- }
-
- void release()
- {
- if (--d_refcnt == 0) {
- if (self) {
- *self = nullptr;
- }
-
- delete this;
- }
- }
-
- static void release(DOHUnit* ptr)
- {
- if (ptr) {
- ptr->release();
- }
- }
+public:
- InternalQueryState ids;
- std::string sni;
- std::string path;
- std::string scheme;
- std::string host;
- std::string contentType;
- PacketBuffer query;
- PacketBuffer response;
- std::shared_ptr<DownstreamState> downstream{nullptr};
- std::unique_ptr<std::unordered_map<std::string, std::string>> headers;
- st_h2o_req_t* req{nullptr};
- DOHUnit** self{nullptr};
- DOHServerConfig* dsc{nullptr};
- std::atomic<uint64_t> d_refcnt{1};
- size_t query_at{0};
- size_t proxyProtocolPayloadSize{0};
- int rsock{-1};
- /* the status_code is set from
- processDOHQuery() (which is executed in
- the DOH client thread) so that the correct
- response can be sent in on_dnsdist(),
- after the DOHUnit has been passed back to
- the main DoH thread.
- */
- uint16_t status_code{200};
- /* whether the query was re-sent to the backend over
- TCP after receiving a truncated answer over UDP */
- bool tcp{false};
- bool truncated{false};
+ void setup() override;
+ void reloadCertificates() override;
- std::string getHTTPPath() const;
- std::string getHTTPHost() const;
- std::string getHTTPScheme() const;
- std::string getHTTPQueryString() const;
- std::unordered_map<std::string, std::string> getHTTPHeaders() const;
- void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType="");
+ void rotateTicketsKey(time_t now) override;
+ void loadTicketsKeys(const std::string& keyFile) override;
+ void handleTicketsKeyRotation() override;
+ std::string getNextTicketsKeyRotation() const override;
+ size_t getTicketsKeysCount() override;
};
-void handleUDPResponseForDoH(std::unique_ptr<DOHUnit, void(*)(DOHUnit*)>&&, PacketBuffer&& response, InternalQueryState&& state);
-
-struct CrossProtocolQuery;
-struct DNSQuestion;
-
-std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
+void dohThread(ClientState* clientState);
+#endif /* HAVE_LIBH2OEVLOOP */
#endif /* HAVE_DNS_OVER_HTTPS */
-
-using DOHUnitUniquePtr = std::unique_ptr<DOHUnit, void(*)(DOHUnit*)>;
-
-void handleDOHTimeout(DOHUnitUniquePtr&& oldDU);
diff --git a/doh3.cc b/doh3.cc
new file mode 100644
index 0000000..d5216aa
--- /dev/null
+++ b/doh3.cc
@@ -0,0 +1,1031 @@
+/*
+ * 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 "doh3.hh"
+
+#ifdef HAVE_DNS_OVER_HTTP3
+#include <quiche.h>
+
+#include "dolog.hh"
+#include "iputils.hh"
+#include "misc.hh"
+#include "sstuff.hh"
+#include "threadname.hh"
+#include "base64.hh"
+
+#include "dnsdist-dnsparser.hh"
+#include "dnsdist-ecs.hh"
+#include "dnsdist-proxy-protocol.hh"
+#include "dnsdist-tcp.hh"
+#include "dnsdist-random.hh"
+
+#include "doq-common.hh"
+
+#if 0
+#define DEBUGLOG_ENABLED
+#define DEBUGLOG(x) std::cerr << x << std::endl;
+#else
+#define DEBUGLOG(x)
+#endif
+
+using namespace dnsdist::doq;
+
+using h3_headers_t = std::map<std::string, std::string>;
+
+class H3Connection
+{
+public:
+ H3Connection(const ComboAddress& peer, QuicheConfig config, QuicheConnection&& conn) :
+ d_peer(peer), d_conn(std::move(conn)), d_config(std::move(config))
+ {
+ }
+ H3Connection(const H3Connection&) = delete;
+ H3Connection(H3Connection&&) = default;
+ H3Connection& operator=(const H3Connection&) = delete;
+ H3Connection& operator=(H3Connection&&) = default;
+ ~H3Connection() = default;
+
+ ComboAddress d_peer;
+ QuicheConnection d_conn;
+ QuicheConfig d_config;
+ QuicheHTTP3Connection d_http3{nullptr, quiche_h3_conn_free};
+ // buffer request headers by streamID
+ std::unordered_map<uint64_t, h3_headers_t> d_headersBuffers;
+ std::unordered_map<uint64_t, PacketBuffer> d_streamBuffers;
+ std::unordered_map<uint64_t, PacketBuffer> d_streamOutBuffers;
+};
+
+static void sendBackDOH3Unit(DOH3UnitUniquePtr&& unit, const char* description);
+
+struct DOH3ServerConfig
+{
+ DOH3ServerConfig(QuicheConfig&& config_, QuicheHTTP3Config&& http3config_, uint32_t internalPipeBufferSize) :
+ config(std::move(config_)), http3config(std::move(http3config_))
+ {
+ {
+ auto [sender, receiver] = pdns::channel::createObjectQueue<DOH3Unit>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
+ d_responseSender = std::move(sender);
+ d_responseReceiver = std::move(receiver);
+ }
+ }
+ DOH3ServerConfig(const DOH3ServerConfig&) = delete;
+ DOH3ServerConfig(DOH3ServerConfig&&) = default;
+ DOH3ServerConfig& operator=(const DOH3ServerConfig&) = delete;
+ DOH3ServerConfig& operator=(DOH3ServerConfig&&) = default;
+ ~DOH3ServerConfig() = default;
+
+ using ConnectionsMap = std::map<PacketBuffer, H3Connection>;
+
+ LocalHolders holders;
+ ConnectionsMap d_connections;
+ QuicheConfig config;
+ QuicheHTTP3Config http3config;
+ ClientState* clientState{nullptr};
+ std::shared_ptr<DOH3Frontend> df{nullptr};
+ pdns::channel::Sender<DOH3Unit> d_responseSender;
+ pdns::channel::Receiver<DOH3Unit> d_responseReceiver;
+};
+
+/* these might seem useless, but they are needed because
+ they need to be declared _after_ the definition of DOH3ServerConfig
+ so that we can use a unique_ptr in DOH3Frontend */
+DOH3Frontend::DOH3Frontend() = default;
+DOH3Frontend::~DOH3Frontend() = default;
+
+class DOH3TCPCrossQuerySender final : public TCPQuerySender
+{
+public:
+ DOH3TCPCrossQuerySender() = default;
+
+ [[nodiscard]] bool active() const override
+ {
+ return true;
+ }
+
+ void handleResponse([[maybe_unused]] const struct timeval& now, TCPResponse&& response) override
+ {
+ if (!response.d_idstate.doh3u) {
+ return;
+ }
+
+ auto unit = std::move(response.d_idstate.doh3u);
+ if (unit->dsc == nullptr) {
+ return;
+ }
+
+ unit->response = std::move(response.d_buffer);
+ unit->ids = std::move(response.d_idstate);
+ DNSResponse dnsResponse(unit->ids, unit->response, unit->downstream);
+
+ dnsheader cleartextDH{};
+ memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
+
+ if (!response.isAsync()) {
+
+ static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions = g_respruleactions.getLocal();
+ static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
+
+ dnsResponse.ids.doh3u = std::move(unit);
+
+ if (!processResponse(dnsResponse.ids.doh3u->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (dnsResponse.ids.doh3u) {
+
+ sendBackDOH3Unit(std::move(dnsResponse.ids.doh3u), "Response dropped by rules");
+ }
+ return;
+ }
+
+ if (dnsResponse.isAsynchronous()) {
+ return;
+ }
+
+ unit = std::move(dnsResponse.ids.doh3u);
+ }
+
+ if (!unit->ids.selfGenerated) {
+ double udiff = unit->ids.queryRealTime.udiff();
+ vinfolog("Got answer from %s, relayed to %s (DoH3, %d bytes), took %f us", unit->downstream->d_config.remote.toStringWithPort(), unit->ids.origRemote.toStringWithPort(), unit->response.size(), udiff);
+
+ auto backendProtocol = unit->downstream->getProtocol();
+ if (backendProtocol == dnsdist::Protocol::DoUDP && unit->tcp) {
+ backendProtocol = dnsdist::Protocol::DoTCP;
+ }
+ handleResponseSent(unit->ids, udiff, unit->ids.origRemote, unit->downstream->d_config.remote, unit->response.size(), cleartextDH, backendProtocol, true);
+ }
+
+ ++dnsdist::metrics::g_stats.responses;
+ if (unit->ids.cs != nullptr) {
+ ++unit->ids.cs->responses;
+ }
+
+ sendBackDOH3Unit(std::move(unit), "Cross-protocol response");
+ }
+
+ void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
+ {
+ return handleResponse(now, std::move(response));
+ }
+
+ void notifyIOError([[maybe_unused]] const struct timeval& now, TCPResponse&& response) override
+ {
+ if (!response.d_idstate.doh3u) {
+ return;
+ }
+
+ auto unit = std::move(response.d_idstate.doh3u);
+ if (unit->dsc == nullptr) {
+ return;
+ }
+
+ /* this will signal an error */
+ unit->response.clear();
+ unit->ids = std::move(response.d_idstate);
+ sendBackDOH3Unit(std::move(unit), "Cross-protocol error");
+ }
+};
+
+class DOH3CrossProtocolQuery : public CrossProtocolQuery
+{
+public:
+ DOH3CrossProtocolQuery(DOH3UnitUniquePtr&& unit, bool isResponse)
+ {
+ if (isResponse) {
+ /* happens when a response becomes async */
+ query = InternalQuery(std::move(unit->response), std::move(unit->ids));
+ }
+ else {
+ /* we need to duplicate the query here because we might need
+ the existing query later if we get a truncated answer */
+ query = InternalQuery(PacketBuffer(unit->query), std::move(unit->ids));
+ }
+
+ /* it might have been moved when we moved unit->ids */
+ if (unit) {
+ query.d_idstate.doh3u = std::move(unit);
+ }
+
+ /* we _could_ remove it from the query buffer and put in query's d_proxyProtocolPayload,
+ clearing query.d_proxyProtocolPayloadAdded and unit->proxyProtocolPayloadSize.
+ Leave it for now because we know that the onky case where the payload has been
+ added is when we tried over UDP, got a TC=1 answer and retried over TCP/DoT,
+ and we know the TCP/DoT code can handle it. */
+ query.d_proxyProtocolPayloadAdded = query.d_idstate.doh3u->proxyProtocolPayloadSize > 0;
+ downstream = query.d_idstate.doh3u->downstream;
+ }
+
+ void handleInternalError()
+ {
+ sendBackDOH3Unit(std::move(query.d_idstate.doh3u), "DOH3 internal error");
+ }
+
+ std::shared_ptr<TCPQuerySender> getTCPQuerySender() override
+ {
+ query.d_idstate.doh3u->downstream = downstream;
+ return s_sender;
+ }
+
+ DNSQuestion getDQ() override
+ {
+ auto& ids = query.d_idstate;
+ DNSQuestion dnsQuestion(ids, query.d_buffer);
+ return dnsQuestion;
+ }
+
+ DNSResponse getDR() override
+ {
+ auto& ids = query.d_idstate;
+ DNSResponse dnsResponse(ids, query.d_buffer, downstream);
+ return dnsResponse;
+ }
+
+ DOH3UnitUniquePtr&& releaseDU()
+ {
+ return std::move(query.d_idstate.doh3u);
+ }
+
+private:
+ static std::shared_ptr<DOH3TCPCrossQuerySender> s_sender;
+};
+
+std::shared_ptr<DOH3TCPCrossQuerySender> DOH3CrossProtocolQuery::s_sender = std::make_shared<DOH3TCPCrossQuerySender>();
+
+static bool tryWriteResponse(H3Connection& conn, const uint64_t streamID, PacketBuffer& response)
+{
+ size_t pos = 0;
+ while (pos < response.size()) {
+ // send_body takes care of setting fin to false if it cannot send the entire content so we can try again.
+ auto res = quiche_h3_send_body(conn.d_http3.get(), conn.d_conn.get(),
+ streamID, &response.at(pos), response.size() - pos, true);
+ if (res == QUICHE_H3_ERR_DONE || res == QUICHE_H3_TRANSPORT_ERR_DONE) {
+ response.erase(response.begin(), response.begin() + static_cast<ssize_t>(pos));
+ return false;
+ }
+ if (res < 0) {
+ // Shutdown with internal error code
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(dnsdist::doq::DOQ_Error_Codes::DOQ_INTERNAL_ERROR));
+ return true;
+ }
+ pos += res;
+ }
+
+ return true;
+}
+
+static void h3_send_response(H3Connection& conn, const uint64_t streamID, uint16_t statusCode, const uint8_t* body, size_t len)
+{
+ std::string status = std::to_string(statusCode);
+ std::string lenStr = std::to_string(len);
+ std::array<quiche_h3_header, 3> headers{
+ (quiche_h3_header){
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .name = reinterpret_cast<const uint8_t*>(":status"),
+ .name_len = sizeof(":status") - 1,
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .value = reinterpret_cast<const uint8_t*>(status.data()),
+ .value_len = status.size(),
+ },
+ (quiche_h3_header){
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .name = reinterpret_cast<const uint8_t*>("content-length"),
+ .name_len = sizeof("content-length") - 1,
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .value = reinterpret_cast<const uint8_t*>(lenStr.data()),
+ .value_len = lenStr.size(),
+ },
+ (quiche_h3_header){
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .name = reinterpret_cast<const uint8_t*>("content-type"),
+ .name_len = sizeof("content-type") - 1,
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ .value = reinterpret_cast<const uint8_t*>("application/dns-message"),
+ .value_len = sizeof("application/dns-message") - 1,
+ },
+ };
+ auto returnValue = quiche_h3_send_response(conn.d_http3.get(), conn.d_conn.get(),
+ streamID, headers.data(),
+ // do not include content-type header info if there is no content
+ (len > 0 && statusCode == 200U ? headers.size() : headers.size() - 1),
+ len == 0);
+ if (returnValue != 0) {
+ /* in theory it could be QUICHE_H3_ERR_STREAM_BLOCKED if the stream is not writable / congested, but we are not going to handle this case */
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(dnsdist::doq::DOQ_Error_Codes::DOQ_INTERNAL_ERROR));
+ return;
+ }
+
+ if (len == 0) {
+ return;
+ }
+
+ size_t pos = 0;
+ while (pos < len) {
+ // send_body takes care of setting fin to false if it cannot send the entire content so we can try again.
+ auto res = quiche_h3_send_body(conn.d_http3.get(), conn.d_conn.get(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic): Quiche API
+ streamID, const_cast<uint8_t*>(body) + pos, len - pos, true);
+ if (res == QUICHE_H3_ERR_DONE || res == QUICHE_H3_TRANSPORT_ERR_DONE) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic): Quiche API
+ conn.d_streamOutBuffers[streamID] = PacketBuffer(body + pos, body + len);
+ return;
+ }
+ if (res < 0) {
+ // Shutdown with internal error code
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(1));
+ return;
+ }
+ pos += res;
+ }
+}
+
+static void h3_send_response(H3Connection& conn, const uint64_t streamID, uint16_t statusCode, const std::string& content)
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ h3_send_response(conn, streamID, statusCode, reinterpret_cast<const uint8_t*>(content.data()), content.size());
+}
+
+static void handleResponse(DOH3Frontend& frontend, H3Connection& conn, const uint64_t streamID, uint16_t statusCode, const PacketBuffer& response)
+{
+ if (statusCode == 200) {
+ ++frontend.d_validResponses;
+ }
+ else {
+ ++frontend.d_errorResponses;
+ }
+ if (response.empty()) {
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_UNSPECIFIED_ERROR));
+ }
+ else {
+ h3_send_response(conn, streamID, statusCode, &response.at(0), response.size());
+ }
+}
+
+void DOH3Frontend::setup()
+{
+ auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+ d_quicheParams.d_alpn = std::string(DOH3_ALPN.begin(), DOH3_ALPN.end());
+ configureQuiche(config, d_quicheParams, true);
+
+ auto http3config = QuicheHTTP3Config(quiche_h3_config_new(), quiche_h3_config_free);
+
+ d_server_config = std::make_unique<DOH3ServerConfig>(std::move(config), std::move(http3config), d_internalPipeBufferSize);
+}
+
+void DOH3Frontend::reloadCertificates()
+{
+ auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+ d_quicheParams.d_alpn = std::string(DOH3_ALPN.begin(), DOH3_ALPN.end());
+ configureQuiche(config, d_quicheParams, true);
+ std::atomic_store_explicit(&d_server_config->config, std::move(config), std::memory_order_release);
+}
+
+static std::optional<std::reference_wrapper<H3Connection>> getConnection(DOH3ServerConfig::ConnectionsMap& connMap, const PacketBuffer& connID)
+{
+ auto iter = connMap.find(connID);
+ if (iter == connMap.end()) {
+ return std::nullopt;
+ }
+ return iter->second;
+}
+
+static void sendBackDOH3Unit(DOH3UnitUniquePtr&& unit, const char* description)
+{
+ if (unit->dsc == nullptr) {
+ return;
+ }
+ try {
+ if (!unit->dsc->d_responseSender.send(std::move(unit))) {
+ ++dnsdist::metrics::g_stats.doh3ResponsePipeFull;
+ vinfolog("Unable to pass a %s to the DoH3 worker thread because the pipe is full", description);
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Unable to pass a %s to the DoH3 worker thread because we couldn't write to the pipe: %s", description, e.what());
+ }
+}
+
+static std::optional<std::reference_wrapper<H3Connection>> createConnection(DOH3ServerConfig& config, const PacketBuffer& serverSideID, const PacketBuffer& originalDestinationID, const ComboAddress& local, const ComboAddress& peer)
+{
+ auto quicheConfig = std::atomic_load_explicit(&config.config, std::memory_order_acquire);
+ auto quicheConn = QuicheConnection(quiche_accept(serverSideID.data(), serverSideID.size(),
+ originalDestinationID.data(), originalDestinationID.size(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const struct sockaddr*>(&local),
+ local.getSocklen(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const struct sockaddr*>(&peer),
+ peer.getSocklen(),
+ quicheConfig.get()),
+ quiche_conn_free);
+
+ if (config.df && !config.df->d_quicheParams.d_keyLogFile.empty()) {
+ quiche_conn_set_keylog_path(quicheConn.get(), config.df->d_quicheParams.d_keyLogFile.c_str());
+ }
+
+ auto conn = H3Connection(peer, std::move(quicheConfig), std::move(quicheConn));
+ auto pair = config.d_connections.emplace(serverSideID, std::move(conn));
+ return pair.first->second;
+}
+
+std::unique_ptr<CrossProtocolQuery> getDOH3CrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion, bool isResponse)
+{
+ if (!dnsQuestion.ids.doh3u) {
+ throw std::runtime_error("Trying to create a DoH3 cross protocol query without a valid DoH3 unit");
+ }
+
+ auto unit = std::move(dnsQuestion.ids.doh3u);
+ if (&dnsQuestion.ids != &unit->ids) {
+ unit->ids = std::move(dnsQuestion.ids);
+ }
+
+ unit->ids.origID = dnsQuestion.getHeader()->id;
+
+ if (!isResponse) {
+ if (unit->query.data() != dnsQuestion.getMutableData().data()) {
+ unit->query = std::move(dnsQuestion.getMutableData());
+ }
+ }
+ else {
+ if (unit->response.data() != dnsQuestion.getMutableData().data()) {
+ unit->response = std::move(dnsQuestion.getMutableData());
+ }
+ }
+
+ return std::make_unique<DOH3CrossProtocolQuery>(std::move(unit), isResponse);
+}
+
+static void processDOH3Query(DOH3UnitUniquePtr&& doh3Unit)
+{
+ const auto handleImmediateResponse = [](DOH3UnitUniquePtr&& unit, [[maybe_unused]] const char* reason) {
+ DEBUGLOG("handleImmediateResponse() reason=" << reason);
+ auto conn = getConnection(unit->dsc->df->d_server_config->d_connections, unit->serverConnID);
+ handleResponse(*unit->dsc->df, *conn, unit->streamID, unit->status_code, unit->response);
+ unit->ids.doh3u.reset();
+ };
+
+ auto& ids = doh3Unit->ids;
+ ids.doh3u = std::move(doh3Unit);
+ auto& unit = ids.doh3u;
+ uint16_t queryId = 0;
+ ComboAddress remote;
+
+ try {
+
+ remote = unit->ids.origRemote;
+ DOH3ServerConfig* dsc = unit->dsc;
+ auto& holders = dsc->holders;
+ ClientState& clientState = *dsc->clientState;
+
+ if (!holders.acl->match(remote)) {
+ vinfolog("Query from %s (DoH3) dropped because of ACL", remote.toStringWithPort());
+ ++dnsdist::metrics::g_stats.aclDrops;
+ unit->response.clear();
+
+ unit->status_code = 403;
+ handleImmediateResponse(std::move(unit), "DoH3 query dropped because of ACL");
+ return;
+ }
+
+ if (unit->query.size() < sizeof(dnsheader)) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ unit->response.clear();
+
+ unit->status_code = 400;
+ handleImmediateResponse(std::move(unit), "DoH3 non-compliant query");
+ return;
+ }
+
+ ++clientState.queries;
+ ++dnsdist::metrics::g_stats.queries;
+ unit->ids.queryRealTime.start();
+
+ {
+ /* don't keep that pointer around, it will be invalidated if the buffer is ever resized */
+ dnsheader_aligned dnsHeader(unit->query.data());
+
+ if (!checkQueryHeaders(*dnsHeader, clientState)) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ header.qr = true;
+ return true;
+ });
+ unit->response = std::move(unit->query);
+
+ unit->status_code = 400;
+ handleImmediateResponse(std::move(unit), "DoH3 invalid headers");
+ return;
+ }
+
+ if (dnsHeader->qdcount == 0) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+ unit->response = std::move(unit->query);
+
+ unit->status_code = 400;
+ handleImmediateResponse(std::move(unit), "DoH3 empty query");
+ return;
+ }
+
+ queryId = ntohs(dnsHeader->id);
+ }
+
+ auto downstream = unit->downstream;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ unit->ids.qname = DNSName(reinterpret_cast<const char*>(unit->query.data()), static_cast<int>(unit->query.size()), sizeof(dnsheader), false, &unit->ids.qtype, &unit->ids.qclass);
+ DNSQuestion dnsQuestion(unit->ids, unit->query);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [&ids](dnsheader& header) {
+ const uint16_t* flags = getFlagsFromDNSHeader(&header);
+ ids.origFlags = *flags;
+ return true;
+ });
+ unit->ids.cs = &clientState;
+
+ auto result = processQuery(dnsQuestion, holders, downstream);
+ if (result == ProcessQueryResult::Drop) {
+ unit->status_code = 403;
+ handleImmediateResponse(std::move(unit), "DoH3 dropped query");
+ return;
+ }
+ if (result == ProcessQueryResult::Asynchronous) {
+ return;
+ }
+ if (result == ProcessQueryResult::SendAnswer) {
+ if (unit->response.empty()) {
+ unit->response = std::move(unit->query);
+ }
+ if (unit->response.size() >= sizeof(dnsheader)) {
+ const dnsheader_aligned dnsHeader(unit->response.data());
+
+ handleResponseSent(unit->ids.qname, QType(unit->ids.qtype), 0., unit->ids.origDest, ComboAddress(), unit->response.size(), *dnsHeader, dnsdist::Protocol::DoH3, dnsdist::Protocol::DoH3, false);
+ }
+ handleImmediateResponse(std::move(unit), "DoH3 self-answered response");
+ return;
+ }
+
+ ++dnsdist::metrics::g_stats.responses;
+ if (unit->ids.cs != nullptr) {
+ ++unit->ids.cs->responses;
+ }
+
+ if (result != ProcessQueryResult::PassToBackend) {
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH3 no backend available");
+ return;
+ }
+
+ if (downstream == nullptr) {
+ unit->status_code = 502;
+ handleImmediateResponse(std::move(unit), "DoH3 no backend available");
+ return;
+ }
+
+ unit->downstream = downstream;
+
+ std::string proxyProtocolPayload;
+ /* we need to do this _before_ creating the cross protocol query because
+ after that the buffer will have been moved */
+ if (downstream->d_config.useProxyProtocol) {
+ proxyProtocolPayload = getProxyProtocolPayload(dnsQuestion);
+ }
+
+ unit->ids.origID = htons(queryId);
+ unit->tcp = true;
+
+ /* this moves unit->ids, careful! */
+ auto cpq = std::make_unique<DOH3CrossProtocolQuery>(std::move(unit), false);
+ cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
+
+ if (downstream->passCrossProtocolQuery(std::move(cpq))) {
+ return;
+ }
+ // NOLINTNEXTLINE(bugprone-use-after-move): it was only moved if the call succeeded
+ unit = cpq->releaseDU();
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH3 internal error");
+ return;
+ }
+ catch (const std::exception& e) {
+ vinfolog("Got an error in DOH3 question thread while parsing a query from %s, id %d: %s", remote.toStringWithPort(), queryId, e.what());
+ unit->status_code = 500;
+ handleImmediateResponse(std::move(unit), "DoH3 internal error");
+ return;
+ }
+}
+
+static void doh3_dispatch_query(DOH3ServerConfig& dsc, PacketBuffer&& query, const ComboAddress& local, const ComboAddress& remote, const PacketBuffer& serverConnID, const uint64_t streamID)
+{
+ try {
+ auto unit = std::make_unique<DOH3Unit>(std::move(query));
+ unit->dsc = &dsc;
+ unit->ids.origDest = local;
+ unit->ids.origRemote = remote;
+ unit->ids.protocol = dnsdist::Protocol::DoH3;
+ unit->serverConnID = serverConnID;
+ unit->streamID = streamID;
+
+ processDOH3Query(std::move(unit));
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Had error handling DoH3 DNS packet from %s: %s", remote.toStringWithPort(), exp.what());
+ }
+}
+
+static void flushResponses(pdns::channel::Receiver<DOH3Unit>& receiver)
+{
+ for (;;) {
+ try {
+ auto tmp = receiver.receive();
+ if (!tmp) {
+ return;
+ }
+
+ auto unit = std::move(*tmp);
+ auto conn = getConnection(unit->dsc->df->d_server_config->d_connections, unit->serverConnID);
+ if (conn) {
+ handleResponse(*unit->dsc->df, *conn, unit->streamID, unit->status_code, unit->response);
+ }
+ }
+ catch (const std::exception& e) {
+ errlog("Error while processing response received over DoH3: %s", e.what());
+ }
+ catch (...) {
+ errlog("Unspecified error while processing response received over DoH3");
+ }
+ }
+}
+
+static void flushStalledResponses(H3Connection& conn)
+{
+ for (auto streamIt = conn.d_streamOutBuffers.begin(); streamIt != conn.d_streamOutBuffers.end();) {
+ const auto streamID = streamIt->first;
+ auto& response = streamIt->second;
+ if (quiche_conn_stream_writable(conn.d_conn.get(), streamID, response.size()) == 1) {
+ if (tryWriteResponse(conn, streamID, response)) {
+ streamIt = conn.d_streamOutBuffers.erase(streamIt);
+ continue;
+ }
+ }
+ ++streamIt;
+ }
+}
+
+static void processH3HeaderEvent(ClientState& clientState, DOH3Frontend& frontend, H3Connection& conn, const ComboAddress& client, const PacketBuffer& serverConnID, const uint64_t streamID, quiche_h3_event* event)
+{
+ auto handleImmediateError = [&clientState, &frontend, &conn, streamID](const char* msg) {
+ DEBUGLOG(msg);
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ ++frontend.d_errorResponses;
+ h3_send_response(conn, streamID, 400, msg);
+ };
+
+ auto& headers = conn.d_headersBuffers.at(streamID);
+ // Callback result. Any value other than 0 will interrupt further header processing.
+ int cbresult = quiche_h3_event_for_each_header(
+ event,
+ [](uint8_t* name, size_t name_len, uint8_t* value, size_t value_len, void* argp) -> int {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ std::string_view key(reinterpret_cast<char*>(name), name_len);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ std::string_view content(reinterpret_cast<char*>(value), value_len);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): Quiche API
+ auto* headersptr = reinterpret_cast<h3_headers_t*>(argp);
+ headersptr->emplace(key, content);
+ return 0;
+ },
+ &headers);
+
+#ifdef DEBUGLOG_ENABLED
+ DEBUGLOG("Processed headers of stream " << streamID);
+ for (const auto& [key, value] : headers) {
+ DEBUGLOG(" " << key << ": " << value);
+ }
+#endif
+ if (cbresult != 0 || headers.count(":method") == 0) {
+ handleImmediateError("Unable to process query headers");
+ return;
+ }
+
+ if (headers.at(":method") == "GET") {
+ if (headers.count(":path") == 0 || headers.at(":path").empty()) {
+ handleImmediateError("Path not found");
+ return;
+ }
+ const auto& path = headers.at(":path");
+ auto payload = dnsdist::doh::getPayloadFromPath(path);
+ if (!payload) {
+ handleImmediateError("Unable to find the DNS parameter");
+ return;
+ }
+ if (payload->size() < sizeof(dnsheader)) {
+ handleImmediateError("DoH3 non-compliant query");
+ return;
+ }
+ DEBUGLOG("Dispatching GET query");
+ doh3_dispatch_query(*(frontend.d_server_config), std::move(*payload), clientState.local, client, serverConnID, streamID);
+ conn.d_streamBuffers.erase(streamID);
+ conn.d_headersBuffers.erase(streamID);
+ return;
+ }
+
+ if (headers.at(":method") == "POST") {
+ if (!quiche_h3_event_headers_has_body(event)) {
+ handleImmediateError("Empty POST query");
+ }
+ return;
+ }
+
+ handleImmediateError("Unsupported HTTP method");
+}
+
+static void processH3DataEvent(ClientState& clientState, DOH3Frontend& frontend, H3Connection& conn, const ComboAddress& client, const PacketBuffer& serverConnID, const uint64_t streamID, quiche_h3_event* event, PacketBuffer& buffer)
+{
+ auto handleImmediateError = [&clientState, &frontend, &conn, streamID](const char* msg) {
+ DEBUGLOG(msg);
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ ++frontend.d_errorResponses;
+ h3_send_response(conn, streamID, 400, msg);
+ };
+ auto& headers = conn.d_headersBuffers.at(streamID);
+
+ if (headers.at(":method") != "POST") {
+ handleImmediateError("DATA frame for non-POST method");
+ return;
+ }
+
+ if (headers.count("content-type") == 0 || headers.at("content-type") != "application/dns-message") {
+ handleImmediateError("Unsupported content-type");
+ return;
+ }
+
+ buffer.resize(std::numeric_limits<uint16_t>::max());
+ auto& streamBuffer = conn.d_streamBuffers[streamID];
+
+ while (true) {
+ buffer.resize(std::numeric_limits<uint16_t>::max());
+ ssize_t len = quiche_h3_recv_body(conn.d_http3.get(),
+ conn.d_conn.get(), streamID,
+ buffer.data(), buffer.size());
+
+ if (len <= 0) {
+ break;
+ }
+
+ buffer.resize(static_cast<size_t>(len));
+ streamBuffer.insert(streamBuffer.end(), buffer.begin(), buffer.end());
+ }
+
+ if (!quiche_conn_stream_finished(conn.d_conn.get(), streamID)) {
+ return;
+ }
+
+ if (streamBuffer.size() < sizeof(dnsheader)) {
+ conn.d_streamBuffers.erase(streamID);
+ handleImmediateError("DoH3 non-compliant query");
+ return;
+ }
+
+ DEBUGLOG("Dispatching POST query");
+ doh3_dispatch_query(*(frontend.d_server_config), std::move(streamBuffer), clientState.local, client, serverConnID, streamID);
+ conn.d_headersBuffers.erase(streamID);
+ conn.d_streamBuffers.erase(streamID);
+}
+
+static void processH3Events(ClientState& clientState, DOH3Frontend& frontend, H3Connection& conn, const ComboAddress& client, const PacketBuffer& serverConnID, PacketBuffer& buffer)
+{
+ while (true) {
+ quiche_h3_event* event{nullptr};
+ // Processes HTTP/3 data received from the peer
+ const int64_t streamID = quiche_h3_conn_poll(conn.d_http3.get(),
+ conn.d_conn.get(),
+ &event);
+
+ if (streamID < 0) {
+ break;
+ }
+ conn.d_headersBuffers.try_emplace(streamID, h3_headers_t{});
+
+ switch (quiche_h3_event_type(event)) {
+ case QUICHE_H3_EVENT_HEADERS: {
+ processH3HeaderEvent(clientState, frontend, conn, client, serverConnID, streamID, event);
+ break;
+ }
+ case QUICHE_H3_EVENT_DATA: {
+ processH3DataEvent(clientState, frontend, conn, client, serverConnID, streamID, event, buffer);
+ break;
+ }
+ case QUICHE_H3_EVENT_FINISHED:
+ case QUICHE_H3_EVENT_RESET:
+ case QUICHE_H3_EVENT_PRIORITY_UPDATE:
+ case QUICHE_H3_EVENT_GOAWAY:
+ break;
+ }
+
+ quiche_h3_event_free(event);
+ }
+}
+
+static void handleSocketReadable(DOH3Frontend& frontend, ClientState& clientState, Socket& sock, PacketBuffer& buffer)
+{
+ // destination connection ID, will have to be sent as original destination connection ID
+ PacketBuffer serverConnID;
+ // source connection ID, will have to be sent as destination connection ID
+ PacketBuffer clientConnID;
+ PacketBuffer tokenBuf;
+ while (true) {
+ ComboAddress client;
+ buffer.resize(4096);
+ if (!sock.recvFromAsync(buffer, client) || buffer.empty()) {
+ return;
+ }
+ DEBUGLOG("Received DoH3 datagram of size " << buffer.size() << " from " << client.toStringWithPort());
+
+ uint32_t version{0};
+ uint8_t type{0};
+ std::array<uint8_t, QUICHE_MAX_CONN_ID_LEN> scid{};
+ size_t scid_len = scid.size();
+ std::array<uint8_t, QUICHE_MAX_CONN_ID_LEN> dcid{};
+ size_t dcid_len = dcid.size();
+ std::array<uint8_t, MAX_TOKEN_LEN> token{};
+ size_t token_len = token.size();
+
+ auto res = quiche_header_info(buffer.data(), buffer.size(), LOCAL_CONN_ID_LEN,
+ &version, &type,
+ scid.data(), &scid_len,
+ dcid.data(), &dcid_len,
+ token.data(), &token_len);
+ if (res != 0) {
+ DEBUGLOG("Error in quiche_header_info: " << res);
+ continue;
+ }
+
+ serverConnID.assign(dcid.begin(), dcid.begin() + dcid_len);
+ // source connection ID, will have to be sent as destination connection ID
+ clientConnID.assign(scid.begin(), scid.begin() + scid_len);
+ auto conn = getConnection(frontend.d_server_config->d_connections, serverConnID);
+
+ if (!conn) {
+ DEBUGLOG("Connection not found");
+ if (type != static_cast<uint8_t>(DOQ_Packet_Types::QUIC_PACKET_TYPE_INITIAL)) {
+ DEBUGLOG("Packet is not initial");
+ continue;
+ }
+
+ if (!quiche_version_is_supported(version)) {
+ DEBUGLOG("Unsupported version");
+ ++frontend.d_doh3UnsupportedVersionErrors;
+ handleVersionNegociation(sock, clientConnID, serverConnID, client, buffer);
+ continue;
+ }
+
+ if (token_len == 0) {
+ /* stateless retry */
+ DEBUGLOG("No token received");
+ handleStatelessRetry(sock, clientConnID, serverConnID, client, version, buffer);
+ continue;
+ }
+
+ tokenBuf.assign(token.begin(), token.begin() + token_len);
+ auto originalDestinationID = validateToken(tokenBuf, client);
+ if (!originalDestinationID) {
+ ++frontend.d_doh3InvalidTokensReceived;
+ DEBUGLOG("Discarding invalid token");
+ continue;
+ }
+
+ DEBUGLOG("Creating a new connection");
+ conn = createConnection(*frontend.d_server_config, serverConnID, *originalDestinationID, clientState.local, client);
+ if (!conn) {
+ continue;
+ }
+ }
+ DEBUGLOG("Connection found");
+ quiche_recv_info recv_info = {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<struct sockaddr*>(&client),
+ client.getSocklen(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<struct sockaddr*>(&clientState.local),
+ clientState.local.getSocklen(),
+ };
+
+ auto done = quiche_conn_recv(conn->get().d_conn.get(), buffer.data(), buffer.size(), &recv_info);
+ if (done < 0) {
+ continue;
+ }
+
+ if (quiche_conn_is_established(conn->get().d_conn.get()) || quiche_conn_is_in_early_data(conn->get().d_conn.get())) {
+ DEBUGLOG("Connection is established");
+
+ if (!conn->get().d_http3) {
+ conn->get().d_http3 = QuicheHTTP3Connection(quiche_h3_conn_new_with_transport(conn->get().d_conn.get(), frontend.d_server_config->http3config.get()),
+ quiche_h3_conn_free);
+ if (!conn->get().d_http3) {
+ continue;
+ }
+ DEBUGLOG("Successfully created HTTP/3 connection");
+ }
+
+ processH3Events(clientState, frontend, conn->get(), client, serverConnID, buffer);
+
+ flushEgress(sock, conn->get().d_conn, client, buffer);
+ }
+ else {
+ DEBUGLOG("Connection not established");
+ }
+ }
+}
+
+// this is the entrypoint from dnsdist.cc
+void doh3Thread(ClientState* clientState)
+{
+ try {
+ std::shared_ptr<DOH3Frontend>& frontend = clientState->doh3Frontend;
+
+ frontend->d_server_config->clientState = clientState;
+ frontend->d_server_config->df = clientState->doh3Frontend;
+
+ setThreadName("dnsdist/doh3");
+
+ Socket sock(clientState->udpFD);
+ sock.setNonBlocking();
+
+ auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent());
+
+ auto responseReceiverFD = frontend->d_server_config->d_responseReceiver.getDescriptor();
+ mplexer->addReadFD(sock.getHandle(), [](int, FDMultiplexer::funcparam_t&) {});
+ mplexer->addReadFD(responseReceiverFD, [](int, FDMultiplexer::funcparam_t&) {});
+ std::vector<int> readyFDs;
+ PacketBuffer buffer(4096);
+ while (true) {
+ readyFDs.clear();
+ mplexer->getAvailableFDs(readyFDs, 500);
+
+ try {
+ if (std::find(readyFDs.begin(), readyFDs.end(), sock.getHandle()) != readyFDs.end()) {
+ handleSocketReadable(*frontend, *clientState, sock, buffer);
+ }
+
+ if (std::find(readyFDs.begin(), readyFDs.end(), responseReceiverFD) != readyFDs.end()) {
+ flushResponses(frontend->d_server_config->d_responseReceiver);
+ }
+
+ for (auto conn = frontend->d_server_config->d_connections.begin(); conn != frontend->d_server_config->d_connections.end();) {
+ quiche_conn_on_timeout(conn->second.d_conn.get());
+
+ flushEgress(sock, conn->second.d_conn, conn->second.d_peer, buffer);
+
+ if (quiche_conn_is_closed(conn->second.d_conn.get())) {
+#ifdef DEBUGLOG_ENABLED
+ quiche_stats stats;
+ quiche_path_stats path_stats;
+
+ quiche_conn_stats(conn->second.d_conn.get(), &stats);
+ quiche_conn_path_stats(conn->second.d_conn.get(), 0, &path_stats);
+
+ DEBUGLOG("Connection (DoH3) closed, recv=" << stats.recv << " sent=" << stats.sent << " lost=" << stats.lost << " rtt=" << path_stats.rtt << "ns cwnd=" << path_stats.cwnd);
+#endif
+ conn = frontend->d_server_config->d_connections.erase(conn);
+ }
+ else {
+ flushStalledResponses(conn->second);
+ ++conn;
+ }
+ }
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Caught exception in the main DoH3 thread: %s", exp.what());
+ }
+ catch (...) {
+ vinfolog("Unknown exception in the main DoH3 thread");
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ DEBUGLOG("Caught fatal error in the main DoH3 thread: " << e.what());
+ }
+}
+
+#endif /* HAVE_DNS_OVER_HTTP3 */
diff --git a/doh3.hh b/doh3.hh
new file mode 100644
index 0000000..954ea4a
--- /dev/null
+++ b/doh3.hh
@@ -0,0 +1,119 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <memory>
+
+#include "config.h"
+#include "channel.hh"
+#include "iputils.hh"
+#include "libssl.hh"
+#include "noinitvector.hh"
+#include "stat_t.hh"
+#include "dnsdist-idstate.hh"
+
+struct DOH3ServerConfig;
+struct DownstreamState;
+
+#ifdef HAVE_DNS_OVER_HTTP3
+
+#include "doq-common.hh"
+
+struct DOH3Frontend
+{
+ DOH3Frontend();
+ DOH3Frontend(const DOH3Frontend&) = delete;
+ DOH3Frontend(DOH3Frontend&&) = delete;
+ DOH3Frontend& operator=(const DOH3Frontend&) = delete;
+ DOH3Frontend& operator=(DOH3Frontend&&) = delete;
+ ~DOH3Frontend();
+
+ void setup();
+ void reloadCertificates();
+
+ std::unique_ptr<DOH3ServerConfig> d_server_config;
+ ComboAddress d_local;
+
+#ifdef __linux__
+ // On Linux this gives us 128k pending queries (default is 8192 queries),
+ // which should be enough to deal with huge spikes
+ uint32_t d_internalPipeBufferSize{1024 * 1024};
+#else
+ uint32_t d_internalPipeBufferSize{0};
+#endif
+
+ dnsdist::doq::QuicheParams d_quicheParams;
+ pdns::stat_t d_doh3UnsupportedVersionErrors{0}; // Unsupported protocol version errors
+ pdns::stat_t d_doh3InvalidTokensReceived{0}; // Discarded received tokens
+ pdns::stat_t d_validResponses{0}; // Valid responses sent
+ pdns::stat_t d_errorResponses{0}; // Empty responses (no backend, drops, invalid queries, etc.)
+};
+
+struct DOH3Unit
+{
+ DOH3Unit(PacketBuffer&& query_) :
+ query(std::move(query_))
+ {
+ }
+
+ DOH3Unit(const DOH3Unit&) = delete;
+ DOH3Unit& operator=(const DOH3Unit&) = delete;
+
+ InternalQueryState ids;
+ PacketBuffer query;
+ PacketBuffer response;
+ PacketBuffer serverConnID;
+ std::shared_ptr<DownstreamState> downstream{nullptr};
+ DOH3ServerConfig* dsc{nullptr};
+ uint64_t streamID{0};
+ size_t proxyProtocolPayloadSize{0};
+ uint16_t status_code{200};
+ /* whether the query was re-sent to the backend over
+ TCP after receiving a truncated answer over UDP */
+ bool tcp{false};
+};
+
+using DOH3UnitUniquePtr = std::unique_ptr<DOH3Unit>;
+
+struct CrossProtocolQuery;
+struct DNSQuestion;
+std::unique_ptr<CrossProtocolQuery> getDOH3CrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion, bool isResponse);
+
+void doh3Thread(ClientState* clientState);
+
+#else
+
+struct DOH3Unit
+{
+};
+
+struct DOH3Frontend
+{
+ DOH3Frontend()
+ {
+ }
+ void setup()
+ {
+ }
+};
+
+#endif
diff --git a/dolog.cc b/dolog.cc
new file mode 100644
index 0000000..55a92b8
--- /dev/null
+++ b/dolog.cc
@@ -0,0 +1,96 @@
+/*
+ * 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 <mutex>
+#include <sys/time.h>
+
+#include "dolog.hh"
+
+namespace dnsdist::logging
+{
+std::optional<std::ofstream> LoggingConfiguration::s_verboseStream{std::nullopt};
+std::string LoggingConfiguration::s_structuredLevelPrefix{"prio"};
+LoggingConfiguration::TimeFormat LoggingConfiguration::s_structuredTimeFormat{LoggingConfiguration::TimeFormat::Numeric};
+bool LoggingConfiguration::s_structuredLogging{false};
+bool LoggingConfiguration::s_logTimestamps{false};
+bool LoggingConfiguration::s_syslog{false};
+
+namespace
+{
+ const char* getTimeFormat()
+ {
+ if (!dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
+ return "%b %d %H:%M:%S ";
+ }
+
+ auto format = dnsdist::logging::LoggingConfiguration::getStructuredLoggingTimeFormat();
+ if (format == dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601) {
+ return "%FT%H:%M:%S%z";
+ }
+ return nullptr;
+ }
+}
+
+void logTime(std::ostream& stream)
+{
+ std::array<char, 50> buffer{""};
+
+ if (LoggingConfiguration::getStructuredLogging() && LoggingConfiguration::getStructuredLoggingTimeFormat() == LoggingConfiguration::TimeFormat::Numeric) {
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+ snprintf(buffer.data(), buffer.size(), "%lld.%03ld", static_cast<long long>(now.tv_sec), static_cast<long>(now.tv_usec / 1000));
+ }
+ else {
+ const auto* timeFormat = getTimeFormat();
+ if (timeFormat == nullptr) {
+ return;
+ }
+
+ time_t now{0};
+ time(&now);
+ struct tm localNow
+ {
+ };
+ localtime_r(&now, &localNow);
+
+ {
+ // strftime is not thread safe, it can access locale information
+ static std::mutex mutex;
+ auto lock = std::lock_guard(mutex);
+
+ if (strftime(buffer.data(), buffer.size(), timeFormat, &localNow) == 0) {
+ buffer[0] = '\0';
+ }
+ }
+ }
+
+ if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
+ stream << "ts=" << std::quoted(buffer.data()) << " ";
+ }
+ else {
+ stream << buffer.data();
+ }
+}
+
+}
diff --git a/dolog.hh b/dolog.hh
index a28777a..25c4952 100644
--- a/dolog.hh
+++ b/dolog.hh
@@ -20,7 +20,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
+#include <array>
#include <fstream>
+#include <iomanip>
#include <iostream>
#include <optional>
#include <sstream>
@@ -31,13 +33,12 @@
#include "logger.hh"
#endif // RECURSOR
-
/* This file is intended not to be metronome specific, and is simple example of C++2011
variadic templates in action.
- The goal is rapid easy to use logging to console & syslog.
+ The goal is rapid easy to use logging to console & syslog.
- Usage:
+ Usage:
string address="localhost";
vinfolog("Got TCP connection from %s", remote);
infolog("Bound to %s port %d", address, port);
@@ -50,162 +51,237 @@
This will happily print a string to %d! Doesn't do further format processing.
*/
-
-#if !defined(RECURSOR)
-inline void dolog(std::ostream& os, const char*s)
+template <typename O>
+inline void dolog(O& outputStream, const char* str)
{
- os<<s;
+ outputStream << str;
}
-template<typename T, typename... Args>
-void dolog(std::ostream& os, const char* s, T value, Args... args)
+template <typename O, typename T, typename... Args>
+void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
{
- while (*s) {
- if (*s == '%') {
- if (*(s + 1) == '%') {
- ++s;
+ while (*formatStr) {
+ if (*formatStr == '%') {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ if (*(formatStr + 1) == '%') {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ ++formatStr;
}
else {
- os << value;
- s += 2;
- dolog(os, s, args...);
- return;
+ outputStream << value;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ formatStr += 2;
+ dolog(outputStream, formatStr, args...);
+ return;
}
}
- os << *s++;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ outputStream << *formatStr++;
}
}
+#if !defined(RECURSOR)
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern bool g_verbose;
-extern bool g_syslog;
+
#ifdef DNSDIST
-extern bool g_logtimestamps;
-extern std::optional<std::ofstream> g_verboseStream;
+namespace dnsdist::logging
+{
+class LoggingConfiguration
+{
+public:
+ enum class TimeFormat
+ {
+ Numeric,
+ ISO8601
+ };
+
+ static void setVerbose(bool value = true)
+ {
+ g_verbose = value;
+ }
+ static void setSyslog(bool value = true)
+ {
+ s_syslog = value;
+ }
+ static void setStructuredLogging(bool value = true, std::string levelPrefix = "")
+ {
+ s_structuredLogging = value;
+ if (value) {
+ s_structuredLevelPrefix = levelPrefix.empty() ? "prio" : std::move(levelPrefix);
+ }
+ }
+ static void setLogTimestamps(bool value = true)
+ {
+ s_logTimestamps = value;
+ }
+ static void setStructuredTimeFormat(TimeFormat format)
+ {
+ s_structuredTimeFormat = format;
+ }
+ static void setVerboseStream(std::ofstream&& stream)
+ {
+ s_verboseStream = std::move(stream);
+ }
+ static bool getVerbose()
+ {
+ return g_verbose;
+ }
+ static bool getSyslog()
+ {
+ return s_syslog;
+ }
+ static bool getLogTimestamps()
+ {
+ return s_logTimestamps;
+ }
+ static std::optional<std::ofstream>& getVerboseStream()
+ {
+ return s_verboseStream;
+ }
+ static bool getStructuredLogging()
+ {
+ return s_structuredLogging;
+ }
+ static const std::string& getStructuredLoggingLevelPrefix()
+ {
+ return s_structuredLevelPrefix;
+ }
+
+ static TimeFormat getStructuredLoggingTimeFormat()
+ {
+ return s_structuredTimeFormat;
+ }
+
+private:
+ static std::optional<std::ofstream> s_verboseStream;
+ static std::string s_structuredLevelPrefix;
+ static TimeFormat s_structuredTimeFormat;
+ static bool s_structuredLogging;
+ static bool s_logTimestamps;
+ static bool s_syslog;
+};
+
+extern void logTime(std::ostream& stream);
+}
#endif
inline void setSyslogFacility(int facility)
{
/* we always call openlog() right away at startup */
closelog();
- openlog("dnsdist", LOG_PID|LOG_NDELAY, facility);
+ openlog("dnsdist", LOG_PID | LOG_NDELAY, facility);
+}
+
+namespace
+{
+inline const char* syslogLevelToStr(int level)
+{
+ static constexpr std::array levelStrs{
+ "Emergency",
+ "Alert",
+ "Critical",
+ "Error",
+ "Warning",
+ "Notice",
+ "Info",
+ "Debug"};
+ return levelStrs.at(level);
+}
}
-template<typename... Args>
-void genlog(std::ostream& stream, int level, bool doSyslog, const char* s, Args... args)
+template <typename... Args>
+void genlog(std::ostream& stream, [[maybe_unused]] int level, [[maybe_unused]] bool skipSyslog, const char* formatStr, const Args&... args)
{
std::ostringstream str;
- dolog(str, s, args...);
+ dolog(str, formatStr, args...);
auto output = str.str();
- if (doSyslog) {
+#ifdef DNSDIST
+ if (!skipSyslog && dnsdist::logging::LoggingConfiguration::getSyslog()) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): syslog is what it is
syslog(level, "%s", output.c_str());
}
-#ifdef DNSDIST
- if (g_logtimestamps) {
- char buffer[50] = "";
- struct tm tm;
- time_t t;
- time(&t);
- localtime_r(&t, &tm);
- if (strftime(buffer, sizeof(buffer), "%b %d %H:%M:%S ", &tm) == 0) {
- buffer[0] = '\0';
- }
- stream<<buffer;
+ if (dnsdist::logging::LoggingConfiguration::getLogTimestamps()) {
+ dnsdist::logging::logTime(stream);
}
-#endif
- stream<<output<<std::endl;
+ 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
}
-template<typename... Args>
-void verboselog(const char* s, Args... args)
+template <typename... Args>
+void verboselog(const char* formatStr, const Args&... args)
{
#ifdef DNSDIST
- if (g_verboseStream) {
- genlog(*g_verboseStream, LOG_DEBUG, false, s, args...);
+ if (auto& stream = dnsdist::logging::LoggingConfiguration::getVerboseStream()) {
+ genlog(*stream, LOG_DEBUG, true, formatStr, args...);
}
else {
#endif /* DNSDIST */
- genlog(std::cout, LOG_DEBUG, g_syslog, s, args...);
+ genlog(std::cout, LOG_DEBUG, false, formatStr, args...);
#ifdef DNSDIST
}
#endif /* DNSDIST */
}
-#define vinfolog if (g_verbose) verboselog
+#define vinfolog \
+ if (g_verbose) \
+ verboselog
-template<typename... Args>
-void infolog(const char* s, Args... args)
+template <typename... Args>
+void infolog(const char* formatStr, const Args&... args)
{
- genlog(std::cout, LOG_INFO, g_syslog, s, args...);
+ genlog(std::cout, LOG_INFO, false, formatStr, args...);
}
-template<typename... Args>
-void warnlog(const char* s, Args... args)
+template <typename... Args>
+void warnlog(const char* formatStr, const Args&... args)
{
- genlog(std::cout, LOG_WARNING, g_syslog, s, args...);
+ genlog(std::cout, LOG_WARNING, false, formatStr, args...);
}
-template<typename... Args>
-void errlog(const char* s, Args... args)
+template <typename... Args>
+void errlog(const char* formatStr, const Args&... args)
{
- genlog(std::cout, LOG_ERR, g_syslog, s, args...);
+ genlog(std::cout, LOG_ERR, false, formatStr, args...);
}
#else // RECURSOR
-
#define g_verbose 0
+#define vinfolog \
+ if (g_verbose) \
+ infolog
-inline void dolog(Logger::Urgency u, const char* s)
-{
- g_log << u << s << std::endl;
-}
-
-inline void dolog(const char* s)
-{
- g_log << s << std::endl;
-}
-
-template<typename T, typename... Args>
-void dolog(Logger::Urgency u, const char* s, T value, Args... args)
-{
- g_log << u;
- while (*s) {
- if (*s == '%') {
- if (*(s + 1) == '%') {
- ++s;
- }
- else {
- g_log << value;
- s += 2;
- dolog(s, args...);
- return;
- }
- }
- g_log << *s++;
- }
-}
-
-#define vinfolog if(g_verbose)infolog
-
-template<typename... Args>
-void infolog(const char* s, Args... args)
+template <typename... Args>
+void infolog(const char* formatStr, const Args&... args)
{
- dolog(Logger::Info, s, args...);
+ g_log << Logger::Info;
+ dolog(g_log, formatStr, args...);
}
-template<typename... Args>
-void warnlog(const char* s, Args... args)
+template <typename... Args>
+void warnlog(const char* formatStr, const Args&... args)
{
- dolog(Logger::Warning, s, args...);
+ g_log << Logger::Warning;
+ dolog(g_log, formatStr, args...);
}
-template<typename... Args>
-void errlog(const char* s, Args... args)
+template <typename... Args>
+void errlog(const char* formatStr, const Args&... args)
{
- dolog(Logger::Error, s, args...);
+ g_log << Logger::Error;
+ dolog(g_log, formatStr, args...);
}
#endif
diff --git a/doq-common.cc b/doq-common.cc
new file mode 100644
index 0000000..e92ccff
--- /dev/null
+++ b/doq-common.cc
@@ -0,0 +1,263 @@
+/*
+ * 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 "doq-common.hh"
+#include "dnsdist-random.hh"
+#include "libssl.hh"
+
+#ifdef HAVE_DNS_OVER_QUIC
+
+#if 0
+#define DEBUGLOG_ENABLED
+#define DEBUGLOG(x) std::cerr << x << std::endl;
+#else
+#define DEBUGLOG(x)
+#endif
+
+namespace dnsdist::doq
+{
+
+static const std::string s_quicRetryTokenKey = dnsdist::crypto::authenticated::newKey(false);
+
+PacketBuffer mintToken(const PacketBuffer& dcid, const ComboAddress& peer)
+{
+ try {
+ dnsdist::crypto::authenticated::Nonce nonce;
+ nonce.init();
+
+ const auto addrBytes = peer.toByteString();
+ // this token will be valid for 60s
+ const uint64_t ttd = time(nullptr) + 60U;
+ PacketBuffer plainTextToken;
+ plainTextToken.reserve(sizeof(ttd) + addrBytes.size() + dcid.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ plainTextToken.insert(plainTextToken.end(), reinterpret_cast<const uint8_t*>(&ttd), reinterpret_cast<const uint8_t*>(&ttd) + sizeof(ttd));
+ plainTextToken.insert(plainTextToken.end(), addrBytes.begin(), addrBytes.end());
+ plainTextToken.insert(plainTextToken.end(), dcid.begin(), dcid.end());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto encryptedToken = dnsdist::crypto::authenticated::encryptSym(std::string_view(reinterpret_cast<const char*>(plainTextToken.data()), plainTextToken.size()), s_quicRetryTokenKey, nonce, false);
+ // a bit sad, let's see if we can do better later
+ PacketBuffer encryptedTokenPacket;
+ encryptedTokenPacket.reserve(encryptedToken.size() + nonce.value.size());
+ encryptedTokenPacket.insert(encryptedTokenPacket.begin(), encryptedToken.begin(), encryptedToken.end());
+ encryptedTokenPacket.insert(encryptedTokenPacket.begin(), nonce.value.begin(), nonce.value.end());
+ return encryptedTokenPacket;
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error while minting DoH3 token: %s", exp.what());
+ throw;
+ }
+}
+
+void fillRandom(PacketBuffer& buffer, size_t size)
+{
+ buffer.reserve(size);
+ while (size > 0) {
+ buffer.insert(buffer.end(), dnsdist::getRandomValue(std::numeric_limits<uint8_t>::max()));
+ --size;
+ }
+}
+
+std::optional<PacketBuffer> getCID()
+{
+ PacketBuffer buffer;
+
+ fillRandom(buffer, LOCAL_CONN_ID_LEN);
+
+ return buffer;
+}
+
+// returns the original destination ID if the token is valid, nothing otherwise
+std::optional<PacketBuffer> validateToken(const PacketBuffer& token, const ComboAddress& peer)
+{
+ try {
+ dnsdist::crypto::authenticated::Nonce nonce;
+ auto addrBytes = peer.toByteString();
+ const uint64_t now = time(nullptr);
+ const auto minimumSize = nonce.value.size() + sizeof(now) + addrBytes.size();
+ if (token.size() <= minimumSize) {
+ return std::nullopt;
+ }
+
+ memcpy(nonce.value.data(), token.data(), nonce.value.size());
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto cipher = std::string_view(reinterpret_cast<const char*>(&token.at(nonce.value.size())), token.size() - nonce.value.size());
+ auto plainText = dnsdist::crypto::authenticated::decryptSym(cipher, s_quicRetryTokenKey, nonce, false);
+
+ if (plainText.size() <= sizeof(now) + addrBytes.size()) {
+ return std::nullopt;
+ }
+
+ uint64_t ttd{0};
+ memcpy(&ttd, plainText.data(), sizeof(ttd));
+ if (ttd < now) {
+ return std::nullopt;
+ }
+
+ if (std::memcmp(&plainText.at(sizeof(ttd)), &*addrBytes.begin(), addrBytes.size()) != 0) {
+ return std::nullopt;
+ }
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ return PacketBuffer(plainText.begin() + (sizeof(ttd) + addrBytes.size()), plainText.end());
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error while validating DoH3 token: %s", exp.what());
+ return std::nullopt;
+ }
+}
+
+void handleStatelessRetry(Socket& sock, const PacketBuffer& clientConnID, const PacketBuffer& serverConnID, const ComboAddress& peer, uint32_t version, PacketBuffer& buffer)
+{
+ auto newServerConnID = getCID();
+ if (!newServerConnID) {
+ return;
+ }
+
+ auto token = mintToken(serverConnID, peer);
+
+ buffer.resize(MAX_DATAGRAM_SIZE);
+ auto written = quiche_retry(clientConnID.data(), clientConnID.size(),
+ serverConnID.data(), serverConnID.size(),
+ newServerConnID->data(), newServerConnID->size(),
+ token.data(), token.size(),
+ version,
+ buffer.data(), buffer.size());
+
+ if (written < 0) {
+ DEBUGLOG("failed to create retry packet " << written);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ sock.sendTo(reinterpret_cast<const char*>(buffer.data()), static_cast<size_t>(written), peer);
+}
+
+void handleVersionNegociation(Socket& sock, const PacketBuffer& clientConnID, const PacketBuffer& serverConnID, const ComboAddress& peer, PacketBuffer& buffer)
+{
+ buffer.resize(MAX_DATAGRAM_SIZE);
+
+ auto written = quiche_negotiate_version(clientConnID.data(), clientConnID.size(),
+ serverConnID.data(), serverConnID.size(),
+ buffer.data(), buffer.size());
+
+ if (written < 0) {
+ DEBUGLOG("failed to create vneg packet " << written);
+ return;
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ sock.sendTo(reinterpret_cast<const char*>(buffer.data()), static_cast<size_t>(written), peer);
+}
+
+void flushEgress(Socket& sock, QuicheConnection& conn, const ComboAddress& peer, PacketBuffer& buffer)
+{
+ buffer.resize(MAX_DATAGRAM_SIZE);
+ quiche_send_info send_info;
+
+ while (true) {
+ auto written = quiche_conn_send(conn.get(), buffer.data(), buffer.size(), &send_info);
+ if (written == QUICHE_ERR_DONE) {
+ return;
+ }
+
+ if (written < 0) {
+ return;
+ }
+ // FIXME pacing (as send_info.at should tell us when to send the packet) ?
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ sock.sendTo(reinterpret_cast<const char*>(buffer.data()), static_cast<size_t>(written), peer);
+ }
+}
+
+void configureQuiche(QuicheConfig& config, const QuicheParams& params, bool isHTTP)
+{
+ for (const auto& pair : params.d_tlsConfig.d_certKeyPairs) {
+ auto res = quiche_config_load_cert_chain_from_pem_file(config.get(), pair.d_cert.c_str());
+ if (res != 0) {
+ throw std::runtime_error("Error loading the server certificate: " + std::to_string(res));
+ }
+ if (pair.d_key) {
+ res = quiche_config_load_priv_key_from_pem_file(config.get(), pair.d_key->c_str());
+ if (res != 0) {
+ throw std::runtime_error("Error loading the server key: " + std::to_string(res));
+ }
+ }
+ }
+
+ {
+ auto res = quiche_config_set_application_protos(config.get(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const uint8_t*>(params.d_alpn.data()),
+ params.d_alpn.size());
+ if (res != 0) {
+ throw std::runtime_error("Error setting ALPN: " + std::to_string(res));
+ }
+ }
+
+ quiche_config_set_max_idle_timeout(config.get(), params.d_idleTimeout * 1000);
+ /* maximum size of an outgoing packet, which means the buffer we pass to quiche_conn_send() should be at least that big */
+ quiche_config_set_max_send_udp_payload_size(config.get(), MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_recv_udp_payload_size(config.get(), MAX_DATAGRAM_SIZE);
+
+ // The number of concurrent remotely-initiated bidirectional streams to be open at any given time
+ // https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_streams_bidi
+ // 0 means none will get accepted, that's why we have a default value of 65535
+ quiche_config_set_initial_max_streams_bidi(config.get(), params.d_maxInFlight);
+
+ // The number of bytes of incoming stream data to be buffered for each localy or remotely-initiated bidirectional stream
+ quiche_config_set_initial_max_stream_data_bidi_local(config.get(), 8192);
+ quiche_config_set_initial_max_stream_data_bidi_remote(config.get(), 8192);
+
+ if (isHTTP) {
+ /* see rfc9114 section 6.2. Unidirectional Streams:
+ Each endpoint needs to create at least one unidirectional stream for the HTTP control stream.
+ QPACK requires two additional unidirectional streams, and other extensions might require further streams.
+ Therefore, the transport parameters sent by both clients and servers MUST allow the peer to create at least three
+ unidirectional streams.
+ These transport parameters SHOULD also provide at least 1,024 bytes of flow-control credit to each unidirectional stream.
+ */
+ quiche_config_set_initial_max_streams_uni(config.get(), 3U);
+ quiche_config_set_initial_max_stream_data_uni(config.get(), 1024U);
+ }
+
+ // The number of total bytes of incoming stream data to be buffered for the whole connection
+ // https://docs.rs/quiche/latest/quiche/struct.Config.html#method.set_initial_max_data
+ quiche_config_set_initial_max_data(config.get(), 8192 * params.d_maxInFlight);
+ if (!params.d_keyLogFile.empty()) {
+ quiche_config_log_keys(config.get());
+ }
+
+ auto algo = dnsdist::doq::s_available_cc_algorithms.find(params.d_ccAlgo);
+ if (algo != dnsdist::doq::s_available_cc_algorithms.end()) {
+ quiche_config_set_cc_algorithm(config.get(), static_cast<enum quiche_cc_algorithm>(algo->second));
+ }
+
+ {
+ PacketBuffer resetToken;
+ fillRandom(resetToken, 16);
+ quiche_config_set_stateless_reset_token(config.get(), resetToken.data());
+ }
+}
+
+};
+
+#endif
diff --git a/doq-common.hh b/doq-common.hh
new file mode 100644
index 0000000..d2222c6
--- /dev/null
+++ b/doq-common.hh
@@ -0,0 +1,102 @@
+/*
+ * 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 <map>
+#include <memory>
+
+#include "config.h"
+
+#if defined(HAVE_DNS_OVER_QUIC) || defined(HAVE_DNS_OVER_HTTP3)
+
+#include <quiche.h>
+
+#include "dolog.hh"
+#include "noinitvector.hh"
+#include "sstuff.hh"
+#include "libssl.hh"
+#include "dnsdist-crypto.hh"
+
+namespace dnsdist::doq
+{
+
+static const std::map<const std::string, int> s_available_cc_algorithms = {
+ {"reno", QUICHE_CC_RENO},
+ {"cubic", QUICHE_CC_CUBIC},
+ {"bbr", QUICHE_CC_BBR},
+};
+
+using QuicheConnection = std::unique_ptr<quiche_conn, decltype(&quiche_conn_free)>;
+using QuicheHTTP3Connection = std::unique_ptr<quiche_h3_conn, decltype(&quiche_h3_conn_free)>;
+using QuicheConfig = std::shared_ptr<quiche_config>;
+using QuicheHTTP3Config = std::unique_ptr<quiche_h3_config, decltype(&quiche_h3_config_free)>;
+
+struct QuicheParams
+{
+ TLSConfig d_tlsConfig;
+ std::string d_keyLogFile;
+ uint64_t d_idleTimeout{5};
+ uint64_t d_maxInFlight{65535};
+ std::string d_ccAlgo{"reno"};
+ std::string d_alpn;
+};
+
+/* from rfc9250 section-4.3 */
+enum class DOQ_Error_Codes : uint64_t
+{
+ DOQ_NO_ERROR = 0,
+ DOQ_INTERNAL_ERROR = 1,
+ DOQ_PROTOCOL_ERROR = 2,
+ DOQ_REQUEST_CANCELLED = 3,
+ DOQ_EXCESSIVE_LOAD = 4,
+ DOQ_UNSPECIFIED_ERROR = 5
+};
+
+/* Quiche type values do not match rfc9000 */
+enum class DOQ_Packet_Types : uint8_t
+{
+ QUIC_PACKET_TYPE_INITIAL = 1,
+ QUIC_PACKET_TYPE_RETRY = 2,
+ QUIC_PACKET_TYPE_HANDSHAKE = 3,
+ QUIC_PACKET_TYPE_ZERO_RTT = 4,
+ QUIC_PACKET_TYPE_SHORT = 5,
+ QUIC_PACKET_TYPE_VERSION_NEGOTIATION = 6
+};
+
+static constexpr size_t MAX_TOKEN_LEN = dnsdist::crypto::authenticated::getEncryptedSize(std::tuple_size<decltype(dnsdist::crypto::authenticated::Nonce::value)>{} /* nonce */ + sizeof(uint64_t) /* TTD */ + 16 /* IPv6 */ + QUICHE_MAX_CONN_ID_LEN);
+static constexpr size_t MAX_DATAGRAM_SIZE = 1200;
+static constexpr size_t LOCAL_CONN_ID_LEN = 16;
+static constexpr std::array<uint8_t, 4> DOQ_ALPN{'\x03', 'd', 'o', 'q'};
+static constexpr std::array<uint8_t, 3> DOH3_ALPN{'\x02', 'h', '3'};
+
+void fillRandom(PacketBuffer& buffer, size_t size);
+std::optional<PacketBuffer> getCID();
+PacketBuffer mintToken(const PacketBuffer& dcid, const ComboAddress& peer);
+std::optional<PacketBuffer> validateToken(const PacketBuffer& token, const ComboAddress& peer);
+void handleStatelessRetry(Socket& sock, const PacketBuffer& clientConnID, const PacketBuffer& serverConnID, const ComboAddress& peer, uint32_t version, PacketBuffer& buffer);
+void handleVersionNegociation(Socket& sock, const PacketBuffer& clientConnID, const PacketBuffer& serverConnID, const ComboAddress& peer, PacketBuffer& buffer);
+void flushEgress(Socket& sock, QuicheConnection& conn, const ComboAddress& peer, PacketBuffer& buffer);
+void configureQuiche(QuicheConfig& config, const QuicheParams& params, bool isHTTP);
+
+};
+
+#endif
diff --git a/doq.cc b/doq.cc
new file mode 100644
index 0000000..247b67a
--- /dev/null
+++ b/doq.cc
@@ -0,0 +1,822 @@
+/*
+ * 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 "doq.hh"
+
+#ifdef HAVE_DNS_OVER_QUIC
+#include <quiche.h>
+
+#include "dolog.hh"
+#include "iputils.hh"
+#include "misc.hh"
+#include "sstuff.hh"
+#include "threadname.hh"
+
+#include "dnsdist-dnsparser.hh"
+#include "dnsdist-ecs.hh"
+#include "dnsdist-proxy-protocol.hh"
+#include "dnsdist-tcp.hh"
+#include "dnsdist-random.hh"
+
+#include "doq-common.hh"
+
+using namespace dnsdist::doq;
+
+#if 0
+#define DEBUGLOG_ENABLED
+#define DEBUGLOG(x) std::cerr << x << std::endl;
+#else
+#define DEBUGLOG(x)
+#endif
+
+class Connection
+{
+public:
+ Connection(const ComboAddress& peer, QuicheConfig config, QuicheConnection conn) :
+ d_peer(peer), d_conn(std::move(conn)), d_config(std::move(config))
+ {
+ }
+ Connection(const Connection&) = delete;
+ Connection(Connection&&) = default;
+ Connection& operator=(const Connection&) = delete;
+ Connection& operator=(Connection&&) = default;
+ ~Connection() = default;
+
+ ComboAddress d_peer;
+ QuicheConnection d_conn;
+ QuicheConfig d_config;
+
+ std::unordered_map<uint64_t, PacketBuffer> d_streamBuffers;
+ std::unordered_map<uint64_t, PacketBuffer> d_streamOutBuffers;
+};
+
+static void sendBackDOQUnit(DOQUnitUniquePtr&& unit, const char* description);
+
+struct DOQServerConfig
+{
+ DOQServerConfig(QuicheConfig&& config_, uint32_t internalPipeBufferSize) :
+ config(std::move(config_))
+ {
+ {
+ auto [sender, receiver] = pdns::channel::createObjectQueue<DOQUnit>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
+ d_responseSender = std::move(sender);
+ d_responseReceiver = std::move(receiver);
+ }
+ }
+ DOQServerConfig(const DOQServerConfig&) = delete;
+ DOQServerConfig(DOQServerConfig&&) = default;
+ DOQServerConfig& operator=(const DOQServerConfig&) = delete;
+ DOQServerConfig& operator=(DOQServerConfig&&) = default;
+ ~DOQServerConfig() = default;
+
+ using ConnectionsMap = std::map<PacketBuffer, Connection>;
+
+ LocalHolders holders;
+ ConnectionsMap d_connections;
+ QuicheConfig config;
+ ClientState* clientState{nullptr};
+ std::shared_ptr<DOQFrontend> df{nullptr};
+ pdns::channel::Sender<DOQUnit> d_responseSender;
+ pdns::channel::Receiver<DOQUnit> d_responseReceiver;
+};
+
+/* these might seem useless, but they are needed because
+ they need to be declared _after_ the definition of DOQServerConfig
+ so that we can use a unique_ptr in DOQFrontend */
+DOQFrontend::DOQFrontend() = default;
+DOQFrontend::~DOQFrontend() = default;
+
+class DOQTCPCrossQuerySender final : public TCPQuerySender
+{
+public:
+ DOQTCPCrossQuerySender() = default;
+
+ [[nodiscard]] bool active() const override
+ {
+ return true;
+ }
+
+ void handleResponse([[maybe_unused]] const struct timeval& now, TCPResponse&& response) override
+ {
+ if (!response.d_idstate.doqu) {
+ return;
+ }
+
+ auto unit = std::move(response.d_idstate.doqu);
+ if (unit->dsc == nullptr) {
+ return;
+ }
+
+ unit->response = std::move(response.d_buffer);
+ unit->ids = std::move(response.d_idstate);
+ DNSResponse dnsResponse(unit->ids, unit->response, unit->downstream);
+
+ dnsheader cleartextDH{};
+ memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
+
+ if (!response.isAsync()) {
+
+ static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localRespRuleActions = g_respruleactions.getLocal();
+ static thread_local LocalStateHolder<vector<DNSDistResponseRuleAction>> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal();
+
+ dnsResponse.ids.doqu = std::move(unit);
+
+ if (!processResponse(dnsResponse.ids.doqu->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dnsResponse, false)) {
+ if (dnsResponse.ids.doqu) {
+
+ sendBackDOQUnit(std::move(dnsResponse.ids.doqu), "Response dropped by rules");
+ }
+ return;
+ }
+
+ if (dnsResponse.isAsynchronous()) {
+ return;
+ }
+
+ unit = std::move(dnsResponse.ids.doqu);
+ }
+
+ if (!unit->ids.selfGenerated) {
+ double udiff = unit->ids.queryRealTime.udiff();
+ vinfolog("Got answer from %s, relayed to %s (quic, %d bytes), took %f us", unit->downstream->d_config.remote.toStringWithPort(), unit->ids.origRemote.toStringWithPort(), unit->response.size(), udiff);
+
+ auto backendProtocol = unit->downstream->getProtocol();
+ if (backendProtocol == dnsdist::Protocol::DoUDP && unit->tcp) {
+ backendProtocol = dnsdist::Protocol::DoTCP;
+ }
+ handleResponseSent(unit->ids, udiff, unit->ids.origRemote, unit->downstream->d_config.remote, unit->response.size(), cleartextDH, backendProtocol, true);
+ }
+
+ ++dnsdist::metrics::g_stats.responses;
+ if (unit->ids.cs != nullptr) {
+ ++unit->ids.cs->responses;
+ }
+
+ sendBackDOQUnit(std::move(unit), "Cross-protocol response");
+ }
+
+ void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
+ {
+ return handleResponse(now, std::move(response));
+ }
+
+ void notifyIOError([[maybe_unused]] const struct timeval& now, TCPResponse&& response) override
+ {
+ if (!response.d_idstate.doqu) {
+ return;
+ }
+
+ auto unit = std::move(response.d_idstate.doqu);
+ if (unit->dsc == nullptr) {
+ return;
+ }
+
+ /* this will signal an error */
+ unit->response.clear();
+ unit->ids = std::move(response.d_idstate);
+ sendBackDOQUnit(std::move(unit), "Cross-protocol error");
+ }
+};
+
+class DOQCrossProtocolQuery : public CrossProtocolQuery
+{
+public:
+ DOQCrossProtocolQuery(DOQUnitUniquePtr&& unit, bool isResponse)
+ {
+ if (isResponse) {
+ /* happens when a response becomes async */
+ query = InternalQuery(std::move(unit->response), std::move(unit->ids));
+ }
+ else {
+ /* we need to duplicate the query here because we might need
+ the existing query later if we get a truncated answer */
+ query = InternalQuery(PacketBuffer(unit->query), std::move(unit->ids));
+ }
+
+ /* it might have been moved when we moved unit->ids */
+ if (unit) {
+ query.d_idstate.doqu = std::move(unit);
+ }
+
+ /* we _could_ remove it from the query buffer and put in query's d_proxyProtocolPayload,
+ clearing query.d_proxyProtocolPayloadAdded and unit->proxyProtocolPayloadSize.
+ Leave it for now because we know that the onky case where the payload has been
+ added is when we tried over UDP, got a TC=1 answer and retried over TCP/DoT,
+ and we know the TCP/DoT code can handle it. */
+ query.d_proxyProtocolPayloadAdded = query.d_idstate.doqu->proxyProtocolPayloadSize > 0;
+ downstream = query.d_idstate.doqu->downstream;
+ }
+
+ void handleInternalError()
+ {
+ sendBackDOQUnit(std::move(query.d_idstate.doqu), "DOQ internal error");
+ }
+
+ std::shared_ptr<TCPQuerySender> getTCPQuerySender() override
+ {
+ query.d_idstate.doqu->downstream = downstream;
+ return s_sender;
+ }
+
+ DNSQuestion getDQ() override
+ {
+ auto& ids = query.d_idstate;
+ DNSQuestion dnsQuestion(ids, query.d_buffer);
+ return dnsQuestion;
+ }
+
+ DNSResponse getDR() override
+ {
+ auto& ids = query.d_idstate;
+ DNSResponse dnsResponse(ids, query.d_buffer, downstream);
+ return dnsResponse;
+ }
+
+ DOQUnitUniquePtr&& releaseDU()
+ {
+ return std::move(query.d_idstate.doqu);
+ }
+
+private:
+ static std::shared_ptr<DOQTCPCrossQuerySender> s_sender;
+};
+
+std::shared_ptr<DOQTCPCrossQuerySender> DOQCrossProtocolQuery::s_sender = std::make_shared<DOQTCPCrossQuerySender>();
+
+static bool tryWriteResponse(Connection& conn, const uint64_t streamID, PacketBuffer& response)
+{
+ size_t pos = 0;
+ while (pos < response.size()) {
+ auto res = quiche_conn_stream_send(conn.d_conn.get(), streamID, &response.at(pos), response.size() - pos, true);
+ if (res == QUICHE_ERR_DONE) {
+ response.erase(response.begin(), response.begin() + static_cast<ssize_t>(pos));
+ return false;
+ }
+ if (res < 0) {
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_INTERNAL_ERROR));
+ return true;
+ }
+ pos += res;
+ }
+
+ return true;
+}
+
+static void handleResponse(DOQFrontend& frontend, Connection& conn, const uint64_t streamID, PacketBuffer& response)
+{
+ if (response.empty()) {
+ ++frontend.d_errorResponses;
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_UNSPECIFIED_ERROR));
+ return;
+ }
+ ++frontend.d_validResponses;
+ auto responseSize = static_cast<uint16_t>(response.size());
+ const std::array<uint8_t, 2> sizeBytes = {static_cast<uint8_t>(responseSize / 256), static_cast<uint8_t>(responseSize % 256)};
+ response.insert(response.begin(), sizeBytes.begin(), sizeBytes.end());
+ if (!tryWriteResponse(conn, streamID, response)) {
+ conn.d_streamOutBuffers[streamID] = std::move(response);
+ }
+}
+
+void DOQFrontend::setup()
+{
+ auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+ d_quicheParams.d_alpn = std::string(DOQ_ALPN.begin(), DOQ_ALPN.end());
+ configureQuiche(config, d_quicheParams, false);
+ d_server_config = std::make_unique<DOQServerConfig>(std::move(config), d_internalPipeBufferSize);
+}
+
+void DOQFrontend::reloadCertificates()
+{
+ auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+ d_quicheParams.d_alpn = std::string(DOQ_ALPN.begin(), DOQ_ALPN.end());
+ configureQuiche(config, d_quicheParams, false);
+ std::atomic_store_explicit(&d_server_config->config, std::move(config), std::memory_order_release);
+}
+
+static std::optional<std::reference_wrapper<Connection>> getConnection(DOQServerConfig::ConnectionsMap& connMap, const PacketBuffer& connID)
+{
+ auto iter = connMap.find(connID);
+ if (iter == connMap.end()) {
+ return std::nullopt;
+ }
+ return iter->second;
+}
+
+static void sendBackDOQUnit(DOQUnitUniquePtr&& unit, const char* description)
+{
+ if (unit->dsc == nullptr) {
+ return;
+ }
+ try {
+ if (!unit->dsc->d_responseSender.send(std::move(unit))) {
+ ++dnsdist::metrics::g_stats.doqResponsePipeFull;
+ vinfolog("Unable to pass a %s to the DoQ worker thread because the pipe is full", description);
+ }
+ }
+ catch (const std::exception& e) {
+ vinfolog("Unable to pass a %s to the DoQ worker thread because we couldn't write to the pipe: %s", description, e.what());
+ }
+}
+
+static std::optional<std::reference_wrapper<Connection>> createConnection(DOQServerConfig& config, const PacketBuffer& serverSideID, const PacketBuffer& originalDestinationID, const ComboAddress& local, const ComboAddress& peer)
+{
+ auto quicheConfig = std::atomic_load_explicit(&config.config, std::memory_order_acquire);
+ auto quicheConn = QuicheConnection(quiche_accept(serverSideID.data(), serverSideID.size(),
+ originalDestinationID.data(), originalDestinationID.size(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const struct sockaddr*>(&local),
+ local.getSocklen(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<const struct sockaddr*>(&peer),
+ peer.getSocklen(),
+ quicheConfig.get()),
+ quiche_conn_free);
+
+ if (config.df && !config.df->d_quicheParams.d_keyLogFile.empty()) {
+ quiche_conn_set_keylog_path(quicheConn.get(), config.df->d_quicheParams.d_keyLogFile.c_str());
+ }
+
+ auto conn = Connection(peer, std::move(quicheConfig), std::move(quicheConn));
+ auto pair = config.d_connections.emplace(serverSideID, std::move(conn));
+ return pair.first->second;
+}
+
+std::unique_ptr<CrossProtocolQuery> getDOQCrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion, bool isResponse)
+{
+ if (!dnsQuestion.ids.doqu) {
+ throw std::runtime_error("Trying to create a DoQ cross protocol query without a valid DoQ unit");
+ }
+
+ auto unit = std::move(dnsQuestion.ids.doqu);
+ if (&dnsQuestion.ids != &unit->ids) {
+ unit->ids = std::move(dnsQuestion.ids);
+ }
+
+ unit->ids.origID = dnsQuestion.getHeader()->id;
+
+ if (!isResponse) {
+ if (unit->query.data() != dnsQuestion.getMutableData().data()) {
+ unit->query = std::move(dnsQuestion.getMutableData());
+ }
+ }
+ else {
+ if (unit->response.data() != dnsQuestion.getMutableData().data()) {
+ unit->response = std::move(dnsQuestion.getMutableData());
+ }
+ }
+
+ return std::make_unique<DOQCrossProtocolQuery>(std::move(unit), isResponse);
+}
+
+static void processDOQQuery(DOQUnitUniquePtr&& doqUnit)
+{
+ const auto handleImmediateResponse = [](DOQUnitUniquePtr&& unit, [[maybe_unused]] const char* reason) {
+ DEBUGLOG("handleImmediateResponse() reason=" << reason);
+ auto conn = getConnection(unit->dsc->df->d_server_config->d_connections, unit->serverConnID);
+ handleResponse(*unit->dsc->df, *conn, unit->streamID, unit->response);
+ unit->ids.doqu.reset();
+ };
+
+ auto& ids = doqUnit->ids;
+ ids.doqu = std::move(doqUnit);
+ auto& unit = ids.doqu;
+ uint16_t queryId = 0;
+ ComboAddress remote;
+
+ try {
+
+ remote = unit->ids.origRemote;
+ DOQServerConfig* dsc = unit->dsc;
+ auto& holders = dsc->holders;
+ ClientState& clientState = *dsc->clientState;
+
+ if (!holders.acl->match(remote)) {
+ vinfolog("Query from %s (DoQ) dropped because of ACL", remote.toStringWithPort());
+ ++dnsdist::metrics::g_stats.aclDrops;
+ unit->response.clear();
+
+ handleImmediateResponse(std::move(unit), "DoQ query dropped because of ACL");
+ return;
+ }
+
+ if (unit->query.size() < sizeof(dnsheader)) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ unit->response.clear();
+
+ handleImmediateResponse(std::move(unit), "DoQ non-compliant query");
+ return;
+ }
+
+ ++clientState.queries;
+ ++dnsdist::metrics::g_stats.queries;
+ unit->ids.queryRealTime.start();
+
+ {
+ /* don't keep that pointer around, it will be invalidated if the buffer is ever resized */
+ dnsheader_aligned dnsHeader(unit->query.data());
+
+ if (!checkQueryHeaders(*dnsHeader, clientState)) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::ServFail;
+ header.qr = true;
+ return true;
+ });
+ unit->response = std::move(unit->query);
+
+ handleImmediateResponse(std::move(unit), "DoQ invalid headers");
+ return;
+ }
+
+ if (dnsHeader->qdcount == 0) {
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(unit->query, [](dnsheader& header) {
+ header.rcode = RCode::NotImp;
+ header.qr = true;
+ return true;
+ });
+ unit->response = std::move(unit->query);
+
+ handleImmediateResponse(std::move(unit), "DoQ empty query");
+ return;
+ }
+
+ queryId = ntohs(dnsHeader->id);
+ }
+
+ auto downstream = unit->downstream;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ unit->ids.qname = DNSName(reinterpret_cast<const char*>(unit->query.data()), static_cast<int>(unit->query.size()), sizeof(dnsheader), false, &unit->ids.qtype, &unit->ids.qclass);
+ DNSQuestion dnsQuestion(unit->ids, unit->query);
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [&ids](dnsheader& header) {
+ const uint16_t* flags = getFlagsFromDNSHeader(&header);
+ ids.origFlags = *flags;
+ return true;
+ });
+ unit->ids.cs = &clientState;
+
+ auto result = processQuery(dnsQuestion, holders, downstream);
+ if (result == ProcessQueryResult::Drop) {
+ handleImmediateResponse(std::move(unit), "DoQ dropped query");
+ return;
+ }
+ if (result == ProcessQueryResult::Asynchronous) {
+ return;
+ }
+ if (result == ProcessQueryResult::SendAnswer) {
+ if (unit->response.empty()) {
+ unit->response = std::move(unit->query);
+ }
+ if (unit->response.size() >= sizeof(dnsheader)) {
+ const dnsheader_aligned dnsHeader(unit->response.data());
+
+ handleResponseSent(unit->ids.qname, QType(unit->ids.qtype), 0., unit->ids.origDest, ComboAddress(), unit->response.size(), *dnsHeader, dnsdist::Protocol::DoQ, dnsdist::Protocol::DoQ, false);
+ }
+ handleImmediateResponse(std::move(unit), "DoQ self-answered response");
+ return;
+ }
+
+ ++dnsdist::metrics::g_stats.responses;
+ if (unit->ids.cs != nullptr) {
+ ++unit->ids.cs->responses;
+ }
+
+ if (result != ProcessQueryResult::PassToBackend) {
+ handleImmediateResponse(std::move(unit), "DoQ no backend available");
+ return;
+ }
+
+ if (downstream == nullptr) {
+ handleImmediateResponse(std::move(unit), "DoQ no backend available");
+ return;
+ }
+
+ unit->downstream = downstream;
+
+ std::string proxyProtocolPayload;
+ /* we need to do this _before_ creating the cross protocol query because
+ after that the buffer will have been moved */
+ if (downstream->d_config.useProxyProtocol) {
+ proxyProtocolPayload = getProxyProtocolPayload(dnsQuestion);
+ }
+
+ unit->ids.origID = htons(queryId);
+ unit->tcp = true;
+
+ /* this moves unit->ids, careful! */
+ auto cpq = std::make_unique<DOQCrossProtocolQuery>(std::move(unit), false);
+ cpq->query.d_proxyProtocolPayload = std::move(proxyProtocolPayload);
+
+ if (downstream->passCrossProtocolQuery(std::move(cpq))) {
+ return;
+ }
+ // NOLINTNEXTLINE(bugprone-use-after-move): it was only moved if the call succeeded
+ unit = cpq->releaseDU();
+ handleImmediateResponse(std::move(unit), "DoQ internal error");
+ return;
+ }
+ catch (const std::exception& e) {
+ vinfolog("Got an error in DOQ question thread while parsing a query from %s, id %d: %s", remote.toStringWithPort(), queryId, e.what());
+ handleImmediateResponse(std::move(unit), "DoQ internal error");
+ return;
+ }
+}
+
+static void doq_dispatch_query(DOQServerConfig& dsc, PacketBuffer&& query, const ComboAddress& local, const ComboAddress& remote, const PacketBuffer& serverConnID, const uint64_t streamID)
+{
+ try {
+ auto unit = std::make_unique<DOQUnit>(std::move(query));
+ unit->dsc = &dsc;
+ unit->ids.origDest = local;
+ unit->ids.origRemote = remote;
+ unit->ids.protocol = dnsdist::Protocol::DoQ;
+ unit->serverConnID = serverConnID;
+ unit->streamID = streamID;
+
+ processDOQQuery(std::move(unit));
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Had error handling DoQ DNS packet from %s: %s", remote.toStringWithPort(), exp.what());
+ }
+}
+
+static void flushResponses(pdns::channel::Receiver<DOQUnit>& receiver)
+{
+ for (;;) {
+ try {
+ auto tmp = receiver.receive();
+ if (!tmp) {
+ return;
+ }
+
+ auto unit = std::move(*tmp);
+ auto conn = getConnection(unit->dsc->df->d_server_config->d_connections, unit->serverConnID);
+ if (conn) {
+ handleResponse(*unit->dsc->df, *conn, unit->streamID, unit->response);
+ }
+ }
+ catch (const std::exception& e) {
+ errlog("Error while processing response received over DoQ: %s", e.what());
+ }
+ catch (...) {
+ errlog("Unspecified error while processing response received over DoQ");
+ }
+ }
+}
+
+static void flushStalledResponses(Connection& conn)
+{
+ for (auto streamIt = conn.d_streamOutBuffers.begin(); streamIt != conn.d_streamOutBuffers.end();) {
+ const auto& streamID = streamIt->first;
+ auto& response = streamIt->second;
+ if (quiche_conn_stream_writable(conn.d_conn.get(), streamID, response.size()) == 1) {
+ if (tryWriteResponse(conn, streamID, response)) {
+ streamIt = conn.d_streamOutBuffers.erase(streamIt);
+ continue;
+ }
+ }
+ ++streamIt;
+ }
+}
+
+static void handleReadableStream(DOQFrontend& frontend, ClientState& clientState, Connection& conn, uint64_t streamID, const ComboAddress& client, const PacketBuffer& serverConnID)
+{
+ auto& streamBuffer = conn.d_streamBuffers[streamID];
+ while (true) {
+ bool fin = false;
+ auto existingLength = streamBuffer.size();
+ streamBuffer.resize(existingLength + 512);
+ auto received = quiche_conn_stream_recv(conn.d_conn.get(), streamID,
+ &streamBuffer.at(existingLength), 512,
+ &fin);
+ if (received == 0 || received == QUICHE_ERR_DONE) {
+ streamBuffer.resize(existingLength);
+ return;
+ }
+ if (received < 0) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_PROTOCOL_ERROR));
+ return;
+ }
+
+ streamBuffer.resize(existingLength + received);
+ if (fin) {
+ break;
+ }
+ }
+
+ if (streamBuffer.size() < (sizeof(uint16_t) + sizeof(dnsheader))) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_PROTOCOL_ERROR));
+ return;
+ }
+
+ uint16_t payloadLength = streamBuffer.at(0) * 256 + streamBuffer.at(1);
+ streamBuffer.erase(streamBuffer.begin(), streamBuffer.begin() + 2);
+ if (payloadLength != streamBuffer.size()) {
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
+ ++clientState.nonCompliantQueries;
+ quiche_conn_stream_shutdown(conn.d_conn.get(), streamID, QUICHE_SHUTDOWN_WRITE, static_cast<uint64_t>(DOQ_Error_Codes::DOQ_PROTOCOL_ERROR));
+ return;
+ }
+ DEBUGLOG("Dispatching query");
+ doq_dispatch_query(*(frontend.d_server_config), std::move(streamBuffer), clientState.local, client, serverConnID, streamID);
+ conn.d_streamBuffers.erase(streamID);
+}
+
+static void handleSocketReadable(DOQFrontend& frontend, ClientState& clientState, Socket& sock, PacketBuffer& buffer)
+{
+ // destination connection ID, will have to be sent as original destination connection ID
+ PacketBuffer serverConnID;
+ // source connection ID, will have to be sent as destination connection ID
+ PacketBuffer clientConnID;
+ PacketBuffer tokenBuf;
+ while (true) {
+ ComboAddress client;
+ buffer.resize(4096);
+ if (!sock.recvFromAsync(buffer, client) || buffer.empty()) {
+ return;
+ }
+ DEBUGLOG("Received DoQ datagram of size " << buffer.size() << " from " << client.toStringWithPort());
+
+ uint32_t version{0};
+ uint8_t type{0};
+ std::array<uint8_t, QUICHE_MAX_CONN_ID_LEN> scid{};
+ size_t scid_len = scid.size();
+ std::array<uint8_t, QUICHE_MAX_CONN_ID_LEN> dcid{};
+ size_t dcid_len = dcid.size();
+ std::array<uint8_t, MAX_TOKEN_LEN> token{};
+ size_t token_len = token.size();
+
+ auto res = quiche_header_info(buffer.data(), buffer.size(), LOCAL_CONN_ID_LEN,
+ &version, &type,
+ scid.data(), &scid_len,
+ dcid.data(), &dcid_len,
+ token.data(), &token_len);
+ if (res != 0) {
+ DEBUGLOG("Error in quiche_header_info: " << res);
+ continue;
+ }
+
+ serverConnID.assign(dcid.begin(), dcid.begin() + dcid_len);
+ clientConnID.assign(scid.begin(), scid.begin() + scid_len);
+ auto conn = getConnection(frontend.d_server_config->d_connections, serverConnID);
+
+ if (!conn) {
+ DEBUGLOG("Connection not found");
+ if (type != static_cast<uint8_t>(DOQ_Packet_Types::QUIC_PACKET_TYPE_INITIAL)) {
+ DEBUGLOG("Packet is not initial");
+ continue;
+ }
+
+ if (!quiche_version_is_supported(version)) {
+ DEBUGLOG("Unsupported version");
+ ++frontend.d_doqUnsupportedVersionErrors;
+ handleVersionNegociation(sock, clientConnID, serverConnID, client, buffer);
+ continue;
+ }
+
+ if (token_len == 0) {
+ /* stateless retry */
+ DEBUGLOG("No token received");
+ handleStatelessRetry(sock, clientConnID, serverConnID, client, version, buffer);
+ continue;
+ }
+
+ tokenBuf.assign(token.begin(), token.begin() + token_len);
+ auto originalDestinationID = validateToken(tokenBuf, client);
+ if (!originalDestinationID) {
+ ++frontend.d_doqInvalidTokensReceived;
+ DEBUGLOG("Discarding invalid token");
+ continue;
+ }
+
+ DEBUGLOG("Creating a new connection");
+ conn = createConnection(*frontend.d_server_config, serverConnID, *originalDestinationID, clientState.local, client);
+ if (!conn) {
+ continue;
+ }
+ }
+ DEBUGLOG("Connection found");
+ quiche_recv_info recv_info = {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<struct sockaddr*>(&client),
+ client.getSocklen(),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ reinterpret_cast<struct sockaddr*>(&clientState.local),
+ clientState.local.getSocklen(),
+ };
+
+ auto done = quiche_conn_recv(conn->get().d_conn.get(), buffer.data(), buffer.size(), &recv_info);
+ if (done < 0) {
+ continue;
+ }
+
+ if (quiche_conn_is_established(conn->get().d_conn.get()) || quiche_conn_is_in_early_data(conn->get().d_conn.get())) {
+ auto readable = std::unique_ptr<quiche_stream_iter, decltype(&quiche_stream_iter_free)>(quiche_conn_readable(conn->get().d_conn.get()), quiche_stream_iter_free);
+
+ uint64_t streamID = 0;
+ while (quiche_stream_iter_next(readable.get(), &streamID)) {
+ handleReadableStream(frontend, clientState, *conn, streamID, client, serverConnID);
+ }
+
+ flushEgress(sock, conn->get().d_conn, client, buffer);
+ }
+ else {
+ DEBUGLOG("Connection not established");
+ }
+ }
+}
+
+// this is the entrypoint from dnsdist.cc
+void doqThread(ClientState* clientState)
+{
+ try {
+ std::shared_ptr<DOQFrontend>& frontend = clientState->doqFrontend;
+
+ frontend->d_server_config->clientState = clientState;
+ frontend->d_server_config->df = clientState->doqFrontend;
+
+ setThreadName("dnsdist/doq");
+
+ Socket sock(clientState->udpFD);
+ sock.setNonBlocking();
+
+ auto mplexer = std::unique_ptr<FDMultiplexer>(FDMultiplexer::getMultiplexerSilent());
+
+ auto responseReceiverFD = frontend->d_server_config->d_responseReceiver.getDescriptor();
+ mplexer->addReadFD(sock.getHandle(), [](int, FDMultiplexer::funcparam_t&) {});
+ mplexer->addReadFD(responseReceiverFD, [](int, FDMultiplexer::funcparam_t&) {});
+ std::vector<int> readyFDs;
+ PacketBuffer buffer(4096);
+ while (true) {
+ readyFDs.clear();
+ mplexer->getAvailableFDs(readyFDs, 500);
+
+ try {
+ if (std::find(readyFDs.begin(), readyFDs.end(), sock.getHandle()) != readyFDs.end()) {
+ handleSocketReadable(*frontend, *clientState, sock, buffer);
+ }
+
+ if (std::find(readyFDs.begin(), readyFDs.end(), responseReceiverFD) != readyFDs.end()) {
+ flushResponses(frontend->d_server_config->d_responseReceiver);
+ }
+
+ for (auto conn = frontend->d_server_config->d_connections.begin(); conn != frontend->d_server_config->d_connections.end();) {
+ quiche_conn_on_timeout(conn->second.d_conn.get());
+
+ flushEgress(sock, conn->second.d_conn, conn->second.d_peer, buffer);
+
+ if (quiche_conn_is_closed(conn->second.d_conn.get())) {
+#ifdef DEBUGLOG_ENABLED
+ quiche_stats stats;
+ quiche_path_stats path_stats;
+
+ quiche_conn_stats(conn->second.d_conn.get(), &stats);
+ quiche_conn_path_stats(conn->second.d_conn.get(), 0, &path_stats);
+
+ DEBUGLOG("Connection (DoQ) closed, recv=" << stats.recv << " sent=" << stats.sent << " lost=" << stats.lost << " rtt=" << path_stats.rtt << "ns cwnd=" << path_stats.cwnd);
+#endif
+ conn = frontend->d_server_config->d_connections.erase(conn);
+ }
+ else {
+ flushStalledResponses(conn->second);
+ ++conn;
+ }
+ }
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Caught exception in the main DoQ thread: %s", exp.what());
+ }
+ catch (...) {
+ vinfolog("Unknown exception in the main DoQ thread");
+ }
+ }
+ }
+ catch (const std::exception& e) {
+ DEBUGLOG("Caught fatal error in the main DoQ thread: " << e.what());
+ }
+}
+
+#endif /* HAVE_DNS_OVER_QUIC */
diff --git a/doq.hh b/doq.hh
new file mode 100644
index 0000000..2581941
--- /dev/null
+++ b/doq.hh
@@ -0,0 +1,119 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <memory>
+
+#include "config.h"
+#include "channel.hh"
+#include "iputils.hh"
+#include "libssl.hh"
+#include "noinitvector.hh"
+#include "doq.hh"
+#include "stat_t.hh"
+#include "dnsdist-idstate.hh"
+
+struct DOQServerConfig;
+struct DownstreamState;
+
+#ifdef HAVE_DNS_OVER_QUIC
+
+#include "doq-common.hh"
+
+struct DOQFrontend
+{
+ DOQFrontend();
+ DOQFrontend(const DOQFrontend&) = delete;
+ DOQFrontend(DOQFrontend&&) = delete;
+ DOQFrontend& operator=(const DOQFrontend&) = delete;
+ DOQFrontend& operator=(DOQFrontend&&) = delete;
+ ~DOQFrontend();
+
+ void setup();
+ void reloadCertificates();
+
+ std::unique_ptr<DOQServerConfig> d_server_config;
+ dnsdist::doq::QuicheParams d_quicheParams;
+ ComboAddress d_local;
+
+#ifdef __linux__
+ // On Linux this gives us 128k pending queries (default is 8192 queries),
+ // which should be enough to deal with huge spikes
+ uint32_t d_internalPipeBufferSize{1024 * 1024};
+#else
+ uint32_t d_internalPipeBufferSize{0};
+#endif
+
+ pdns::stat_t d_doqUnsupportedVersionErrors{0}; // Unsupported protocol version errors
+ pdns::stat_t d_doqInvalidTokensReceived{0}; // Discarded received tokens
+ pdns::stat_t d_validResponses{0}; // Valid responses sent
+ pdns::stat_t d_errorResponses{0}; // Empty responses (no backend, drops, invalid queries, etc.)
+};
+
+struct DOQUnit
+{
+ DOQUnit(PacketBuffer&& query_) :
+ query(std::move(query_))
+ {
+ }
+
+ DOQUnit(const DOQUnit&) = delete;
+ DOQUnit& operator=(const DOQUnit&) = delete;
+
+ InternalQueryState ids;
+ PacketBuffer query;
+ PacketBuffer response;
+ PacketBuffer serverConnID;
+ std::shared_ptr<DownstreamState> downstream{nullptr};
+ DOQServerConfig* dsc{nullptr};
+ uint64_t streamID{0};
+ size_t proxyProtocolPayloadSize{0};
+ /* whether the query was re-sent to the backend over
+ TCP after receiving a truncated answer over UDP */
+ bool tcp{false};
+};
+
+using DOQUnitUniquePtr = std::unique_ptr<DOQUnit>;
+
+struct CrossProtocolQuery;
+struct DNSQuestion;
+std::unique_ptr<CrossProtocolQuery> getDOQCrossProtocolQueryFromDQ(DNSQuestion& dnsQuestion, bool isResponse);
+
+void doqThread(ClientState* clientState);
+
+#else
+
+struct DOQUnit
+{
+};
+
+struct DOQFrontend
+{
+ DOQFrontend()
+ {
+ }
+ void setup()
+ {
+ }
+};
+
+#endif
diff --git a/ednscookies.cc b/ednscookies.cc
index 5e57f04..eefa0f4 100644
--- a/ednscookies.cc
+++ b/ednscookies.cc
@@ -74,7 +74,7 @@ void EDNSCookiesOpt::getEDNSCookiesOptFromString(const char* option, unsigned in
}
}
-bool EDNSCookiesOpt::isValid(const string& secret, const ComboAddress& source) const
+bool EDNSCookiesOpt::isValid([[maybe_unused]] const string& secret, [[maybe_unused]] const ComboAddress& source) const
{
#ifdef HAVE_CRYPTO_SHORTHASH
if (server.length() != 16 || client.length() != 8) {
@@ -139,7 +139,7 @@ bool EDNSCookiesOpt::shouldRefresh() const
return rfc1982LessThan(ts + 1800, now);
}
-bool EDNSCookiesOpt::makeServerCookie(const string& secret, const ComboAddress& source)
+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");
diff --git a/ednscookies.hh b/ednscookies.hh
index 7eff3c6..4780044 100644
--- a/ednscookies.hh
+++ b/ednscookies.hh
@@ -28,7 +28,7 @@ struct EDNSCookiesOpt
static const size_t EDNSCookieSecretSize = 32;
static const size_t EDNSCookieOptSize = 24;
- EDNSCookiesOpt(){};
+ EDNSCookiesOpt() = default;
EDNSCookiesOpt(const std::string& option);
EDNSCookiesOpt(const char* option, unsigned int len);
diff --git a/ednsextendederror.cc b/ednsextendederror.cc
new file mode 100644
index 0000000..5010e3d
--- /dev/null
+++ b/ednsextendederror.cc
@@ -0,0 +1,65 @@
+/*
+ * 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 <limits>
+
+#include "ednsextendederror.hh"
+
+static bool getEDNSExtendedErrorOptFromStringView(const std::string_view& option, EDNSExtendedError& eee)
+{
+ if (option.size() < sizeof(uint16_t)) {
+ return false;
+ }
+ eee.infoCode = static_cast<uint8_t>(option.at(0)) * 256 + static_cast<uint8_t>(option.at(1));
+
+ if (option.size() > sizeof(uint16_t)) {
+ eee.extraText = std::string(&option.at(sizeof(uint16_t)), option.size() - sizeof(uint16_t));
+ }
+
+ return true;
+}
+
+bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee)
+{
+ return getEDNSExtendedErrorOptFromStringView(std::string_view(option), eee);
+}
+
+bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee)
+{
+ return getEDNSExtendedErrorOptFromStringView(std::string_view(option, len), eee);
+}
+
+string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee)
+{
+ if (eee.extraText.size() > static_cast<size_t>(std::numeric_limits<uint16_t>::max() - 2)) {
+ throw std::runtime_error("Trying to create an EDNS Extended Error option with an extra text of size " + std::to_string(eee.extraText.size()));
+ }
+
+ string ret;
+ ret.reserve(sizeof(uint16_t) + eee.extraText.size());
+ ret.resize(sizeof(uint16_t));
+
+ ret[0] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) / 256);
+ ret[1] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) % 256);
+ ret.append(eee.extraText);
+
+ return ret;
+}
diff --git a/ednsextendederror.hh b/ednsextendederror.hh
new file mode 100644
index 0000000..5b264fc
--- /dev/null
+++ b/ednsextendederror.hh
@@ -0,0 +1,66 @@
+/*
+ * 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 "namespaces.hh"
+
+struct EDNSExtendedError
+{
+ enum class code : uint16_t
+ {
+ Other = 0,
+ UnsupportedDNSKEYAlgorithm = 1,
+ UnsupportedDSDigestType = 2,
+ StaleAnswer = 3,
+ ForgedAnswer = 4,
+ DNSSECIndeterminate = 5,
+ DNSSECBogus = 6,
+ SignatureExpired = 7,
+ SignatureNotYetValid = 8,
+ DNSKEYMissing = 9,
+ RRSIGsMissing = 10,
+ NoZoneKeyBitSet = 11,
+ NSECMissing = 12,
+ CachedError = 13,
+ NotReady = 14,
+ Blocked = 15,
+ Censored = 16,
+ Filtered = 17,
+ Prohibited = 18,
+ StaleNXDOMAINAnswer = 19,
+ NotAuthoritative = 20,
+ NotSupported = 21,
+ NoReachableAuthority = 22,
+ NetworkError = 23,
+ InvalidData = 24,
+ SignatureExpiredBeforeValid = 25,
+ TooEarly = 26,
+ UnsupportedNSEC3IterationsValue = 27,
+ UnableToConformToPolicy = 28,
+ Synthesized = 29,
+ };
+ uint16_t infoCode;
+ std::string extraText;
+};
+
+bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee);
+bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee);
+string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee);
diff --git a/ednssubnet.cc b/ednssubnet.cc
index cf78ecf..a4c3e28 100644
--- a/ednssubnet.cc
+++ b/ednssubnet.cc
@@ -25,60 +25,69 @@
#include "ednssubnet.hh"
#include "dns.hh"
-namespace {
- struct EDNSSubnetOptsWire
- {
- uint16_t family;
- uint8_t sourceMask;
- uint8_t scopeMask;
- } GCCPACKATTRIBUTE; // BRRRRR
+namespace
+{
+struct EDNSSubnetOptsWire
+{
+ uint16_t family;
+ uint8_t sourceMask;
+ uint8_t scopeMask;
+} GCCPACKATTRIBUTE; // BRRRRR
}
bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso)
{
- //cerr<<"options.size:"<<options.size()<<endl;
+ // cerr<<"options.size:"<<options.size()<<endl;
return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso);
}
bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso)
{
- EDNSSubnetOptsWire esow;
- static_assert (sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes");
- if(len < sizeof(esow))
+ EDNSSubnetOptsWire esow{};
+ static_assert(sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes");
+ if (len < sizeof(esow)) {
return false;
+ }
memcpy(&esow, options, sizeof(esow));
esow.family = ntohs(esow.family);
- //cerr<<"Family when parsing from string: "<<esow.family<<endl;
+ // cerr<<"Family when parsing from string: "<<esow.family<<endl;
ComboAddress address;
- unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1)>> 3)+1) : 0;
- //cerr<<"octetsin:"<<octetsin<<endl;
- if(esow.family == 1) {
- if(len != sizeof(esow)+octetsin)
+ unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1) >> 3) + 1) : 0;
+ // cerr<<"octetsin:"<<octetsin<<endl;
+ if (esow.family == 1) {
+ if (len != sizeof(esow) + octetsin) {
return false;
- if(octetsin > sizeof(address.sin4.sin_addr.s_addr))
+ }
+ if (octetsin > sizeof(address.sin4.sin_addr.s_addr)) {
return false;
+ }
address.reset();
address.sin4.sin_family = AF_INET;
- if(octetsin > 0)
- memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin);
- } else if(esow.family == 2) {
- if(len != sizeof(esow)+octetsin)
+ if (octetsin > 0) {
+ memcpy(&address.sin4.sin_addr.s_addr, options + sizeof(esow), octetsin); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ }
+ }
+ else if (esow.family == 2) {
+ if (len != sizeof(esow) + octetsin) {
return false;
- if(octetsin > sizeof(address.sin6.sin6_addr.s6_addr))
+ }
+ if (octetsin > sizeof(address.sin6.sin6_addr.s6_addr)) {
return false;
+ }
address.reset();
address.sin4.sin_family = AF_INET6;
- if(octetsin > 0)
- memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin);
+ if (octetsin > 0) {
+ memcpy(&address.sin6.sin6_addr.s6_addr, options + sizeof(esow), octetsin); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ }
}
- else
+ else {
return false;
- //cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
+ }
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 */
-
+
address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks
eso->scope = Netmask(address, esow.scopeMask);
@@ -88,21 +97,22 @@ bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubn
string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso)
{
string ret;
- EDNSSubnetOptsWire esow;
+ EDNSSubnetOptsWire esow{};
uint16_t family = htons(eso.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));
- int octetsout = ((esow.sourceMask - 1)>> 3)+1;
+ ret.assign((const char*)&esow, sizeof(esow)); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
+ int octetsout = ((esow.sourceMask - 1) >> 3) + 1;
- ComboAddress src=eso.source.getNetwork();
+ ComboAddress src = eso.source.getNetwork();
src.truncate(esow.sourceMask);
- if(family == htons(1))
- ret.append((const char*) &src.sin4.sin_addr.s_addr, octetsout);
- else
- ret.append((const char*) &src.sin6.sin6_addr.s6_addr, octetsout);
+ if (family == htons(1)) {
+ ret.append((const char*)&src.sin4.sin_addr.s_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
+ }
+ else {
+ ret.append((const char*)&src.sin6.sin6_addr.s6_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
+ }
return ret;
}
-
diff --git a/ednssubnet.hh b/ednssubnet.hh
index b0f6e48..19beb03 100644
--- a/ednssubnet.hh
+++ b/ednssubnet.hh
@@ -26,8 +26,8 @@
struct EDNSSubnetOpts
{
- Netmask source;
- Netmask scope;
+ Netmask source;
+ Netmask scope;
};
bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso);
diff --git a/epollmplexer.cc b/epollmplexer.cc
index 74de2c2..4ccb0a0 100644
--- a/epollmplexer.cc
+++ b/epollmplexer.cc
@@ -37,7 +37,7 @@ class EpollFDMultiplexer : public FDMultiplexer
{
public:
EpollFDMultiplexer(unsigned int maxEventsHint);
- ~EpollFDMultiplexer()
+ ~EpollFDMultiplexer() override
{
if (d_epollfd >= 0) {
close(d_epollfd);
diff --git a/ext/arc4random/Makefile.am b/ext/arc4random/Makefile.am
new file mode 100644
index 0000000..73479d1
--- /dev/null
+++ b/ext/arc4random/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libarc4random.la
+libarc4random_la_SOURCES = \
+ arc4random.c \
+ arc4random.h \
+ arc4random.hh \
+ arc4random_uniform.c \
+ bsd-getentropy.c \
+ chacha_private.h \
+ explicit_bzero.c \
+ includes.h \
+ log.h
diff --git a/ext/arc4random/Makefile.in b/ext/arc4random/Makefile.in
new file mode 100644
index 0000000..e814995
--- /dev/null
+++ b/ext/arc4random/Makefile.in
@@ -0,0 +1,750 @@
+# 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 = ext/arc4random
+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_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/dnsdist_enable_dnscrypt.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh3.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doq.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_tls_providers.m4 \
+ $(top_srcdir)/m4/dnsdist_with_cdb.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_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_dnstap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libedit.m4 \
+ $(top_srcdir)/m4/pdns_check_libh2o_evloop.m4 \
+ $(top_srcdir)/m4/pdns_check_lmdb.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_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_fuzz_targets.m4 \
+ $(top_srcdir)/m4/pdns_enable_ipcipher.m4 \
+ $(top_srcdir)/m4/pdns_enable_lto.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_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_ebpf.m4 \
+ $(top_srcdir)/m4/pdns_with_gnutls.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_nghttp2.m4 \
+ $(top_srcdir)/m4/pdns_with_quiche.m4 \
+ $(top_srcdir)/m4/pdns_with_re2.m4 \
+ $(top_srcdir)/m4/pdns_with_service_user.m4 \
+ $(top_srcdir)/m4/pdns_with_xsk.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 =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libarc4random_la_LIBADD =
+am_libarc4random_la_OBJECTS = arc4random.lo arc4random_uniform.lo \
+ bsd-getentropy.lo explicit_bzero.lo
+libarc4random_la_OBJECTS = $(am_libarc4random_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+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 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/arc4random.Plo \
+ ./$(DEPDIR)/arc4random_uniform.Plo \
+ ./$(DEPDIR)/bsd-getentropy.Plo ./$(DEPDIR)/explicit_bzero.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libarc4random_la_SOURCES)
+DIST_SOURCES = $(libarc4random_la_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)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ARC4RANDOM_LIBS = @ARC4RANDOM_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_ROOT = @BOOST_ROOT@
+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@
+BPF_CFLAGS = @BPF_CFLAGS@
+BPF_LIBS = @BPF_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+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@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_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@
+IPCRYPT_CFLAGS = @IPCRYPT_CFLAGS@
+IPCRYPT_LIBS = @IPCRYPT_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCAP_CFLAGS = @LIBCAP_CFLAGS@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBEDIT_CFLAGS = @LIBEDIT_CFLAGS@
+LIBEDIT_LIBS = @LIBEDIT_LIBS@
+LIBH2OEVLOOP_CFLAGS = @LIBH2OEVLOOP_CFLAGS@
+LIBH2OEVLOOP_LIBS = @LIBH2OEVLOOP_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBSSL_CFLAGS = @LIBSSL_CFLAGS@
+LIBSSL_LIBS = @LIBSSL_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+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@
+NGHTTP2_CFLAGS = @NGHTTP2_CFLAGS@
+NGHTTP2_LIBS = @NGHTTP2_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+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@
+QUICHE_CFLAGS = @QUICHE_CFLAGS@
+QUICHE_LIBS = @QUICHE_LIBS@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RE2_CFLAGS = @RE2_CFLAGS@
+RE2_LIBS = @RE2_LIBS@
+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@
+XDP_CFLAGS = @XDP_CFLAGS@
+XDP_LIBS = @XDP_LIBS@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+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@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+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@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libarc4random.la
+libarc4random_la_SOURCES = \
+ arc4random.c \
+ arc4random.h \
+ arc4random.hh \
+ arc4random_uniform.c \
+ bsd-getentropy.c \
+ chacha_private.h \
+ explicit_bzero.c \
+ includes.h \
+ log.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(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 ext/arc4random/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ext/arc4random/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):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || 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}; \
+ }
+
+libarc4random.la: $(libarc4random_la_OBJECTS) $(libarc4random_la_DEPENDENCIES) $(EXTRA_libarc4random_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libarc4random_la_OBJECTS) $(libarc4random_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc4random.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc4random_uniform.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsd-getentropy.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/explicit_bzero.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+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 $(LTLIBRARIES)
+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-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/arc4random.Plo
+ -rm -f ./$(DEPDIR)/arc4random_uniform.Plo
+ -rm -f ./$(DEPDIR)/bsd-getentropy.Plo
+ -rm -f ./$(DEPDIR)/explicit_bzero.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+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 ./$(DEPDIR)/arc4random.Plo
+ -rm -f ./$(DEPDIR)/arc4random_uniform.Plo
+ -rm -f ./$(DEPDIR)/bsd-getentropy.Plo
+ -rm -f ./$(DEPDIR)/explicit_bzero.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags 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-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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 --git a/ext/arc4random/arc4random.c b/ext/arc4random/arc4random.c
new file mode 100644
index 0000000..56ebd81
--- /dev/null
+++ b/ext/arc4random/arc4random.c
@@ -0,0 +1,256 @@
+/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * ChaCha based random number generator for OpenBSD.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifndef HAVE_ARC4RANDOM
+
+/*
+ * Always use the getentropy implementation from bsd-getentropy.c, which
+ * will call a native getentropy if available then fall back as required.
+ * We use a different name so that OpenSSL cannot call the wrong getentropy.
+ */
+#ifdef getentropy
+# undef getentropy
+#endif
+#define getentropy(x, y) (_ssh_compat_getentropy((x), (y)))
+
+#include "log.h"
+
+#define KEYSTREAM_ONLY
+#include "chacha_private.h"
+
+#define minimum(a, b) ((a) < (b) ? (a) : (b))
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+#define inline __inline
+#else /* __GNUC__ || _MSC_VER */
+#define inline
+#endif /* !__GNUC__ && !_MSC_VER */
+
+#define KEYSZ 32
+#define IVSZ 8
+#define BLOCKSZ 64
+#define RSBUFSZ (16*BLOCKSZ)
+
+#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
+
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
+static struct _rs {
+ size_t rs_have; /* valid bytes at end of rs_buf */
+ size_t rs_count; /* bytes till reseed */
+} *rs;
+
+/* Maybe be preserved in fork children, if _rs_allocate() decides. */
+static struct _rsx {
+ chacha_ctx rs_chacha; /* chacha context for random keystream */
+ u_char rs_buf[RSBUFSZ]; /* keystream blocks */
+} *rsx;
+
+static inline int _rs_allocate(struct _rs **, struct _rsx **);
+static inline void _rs_forkdetect(void);
+#include "arc4random.h"
+
+static inline void _rs_rekey(u_char *dat, size_t datlen);
+
+static inline void
+_rs_init(u_char *buf, size_t n)
+{
+ if (n < KEYSZ + IVSZ)
+ return;
+
+ if (rs == NULL) {
+ if (_rs_allocate(&rs, &rsx) == -1)
+ _exit(1);
+ }
+
+ chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
+ chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
+}
+
+static void
+_rs_stir(void)
+{
+ u_char rnd[KEYSZ + IVSZ];
+ uint32_t rekey_fuzz = 0;
+
+ if (getentropy(rnd, sizeof rnd) == -1)
+ _getentropy_fail();
+
+ if (!rs)
+ _rs_init(rnd, sizeof(rnd));
+ else
+ _rs_rekey(rnd, sizeof(rnd));
+ explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
+
+ /* invalidate rs_buf */
+ rs->rs_have = 0;
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+
+ /* rekey interval should not be predictable */
+ chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz,
+ (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
+ rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
+}
+
+static inline void
+_rs_stir_if_needed(size_t len)
+{
+ _rs_forkdetect();
+ if (!rs || rs->rs_count <= len)
+ _rs_stir();
+ if (rs->rs_count <= len)
+ rs->rs_count = 0;
+ else
+ rs->rs_count -= len;
+}
+
+static inline void
+_rs_rekey(u_char *dat, size_t datlen)
+{
+#ifndef KEYSTREAM_ONLY
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+#endif
+ /* fill rs_buf with the keystream */
+ chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+ rsx->rs_buf, sizeof(rsx->rs_buf));
+ /* mix in optional user provided data */
+ if (dat) {
+ size_t i, m;
+
+ m = minimum(datlen, KEYSZ + IVSZ);
+ for (i = 0; i < m; i++)
+ rsx->rs_buf[i] ^= dat[i];
+ }
+ /* immediately reinit for backtracking resistance */
+ _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+ memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+ rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
+}
+
+static inline void
+_rs_random_buf(void *_buf, size_t n)
+{
+ u_char *buf = (u_char *)_buf;
+ u_char *keystream;
+ size_t m;
+
+ _rs_stir_if_needed(n);
+ while (n > 0) {
+ if (rs->rs_have > 0) {
+ m = minimum(n, rs->rs_have);
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+ - rs->rs_have;
+ memcpy(buf, keystream, m);
+ memset(keystream, 0, m);
+ buf += m;
+ n -= m;
+ rs->rs_have -= m;
+ }
+ if (rs->rs_have == 0)
+ _rs_rekey(NULL, 0);
+ }
+}
+
+static inline void
+_rs_random_u32(uint32_t *val)
+{
+ u_char *keystream;
+
+ _rs_stir_if_needed(sizeof(*val));
+ if (rs->rs_have < sizeof(*val))
+ _rs_rekey(NULL, 0);
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+ memcpy(val, keystream, sizeof(*val));
+ memset(keystream, 0, sizeof(*val));
+ rs->rs_have -= sizeof(*val);
+}
+
+#include <pthread.h>
+static pthread_mutex_t arc4mutex = PTHREAD_MUTEX_INITIALIZER;
+
+uint32_t
+arc4random(void)
+{
+ uint32_t val;
+
+ _ARC4_LOCK();
+ _rs_random_u32(&val);
+ _ARC4_UNLOCK();
+ return val;
+}
+DEF_WEAK(arc4random);
+
+/*
+ * If we are providing arc4random, then we can provide a more efficient
+ * arc4random_buf().
+ */
+# ifndef HAVE_ARC4RANDOM_BUF
+void
+arc4random_buf(void *buf, size_t n)
+{
+ _ARC4_LOCK();
+ _rs_random_buf(buf, n);
+ _ARC4_UNLOCK();
+}
+DEF_WEAK(arc4random_buf);
+# endif /* !HAVE_ARC4RANDOM_BUF */
+#endif /* !HAVE_ARC4RANDOM */
+
+/* arc4random_buf() that uses platform arc4random() */
+#if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM)
+void
+arc4random_buf(void *_buf, size_t n)
+{
+ size_t i;
+ u_int32_t r = 0;
+ char *buf = (char *)_buf;
+
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ r = arc4random();
+ buf[i] = r & 0xff;
+ r >>= 8;
+ }
+ explicit_bzero(&r, sizeof(r));
+}
+#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
+
diff --git a/ext/arc4random/arc4random.h b/ext/arc4random/arc4random.h
new file mode 100644
index 0000000..402b263
--- /dev/null
+++ b/ext/arc4random/arc4random.h
@@ -0,0 +1,89 @@
+/* $OpenBSD: arc4random_linux.h,v 1.12 2019/07/11 10:37:28 inoguchi Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability. From LibreSSL with some adaptations.
+ */
+
+#include <sys/mman.h>
+
+#include <signal.h>
+
+/* OpenSSH isn't multithreaded */
+#define _ARC4_LOCK() pthread_mutex_lock(&arc4mutex);
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4mutex);
+#define _ARC4_ATFORK(f)
+
+static inline void
+_getentropy_fail(void)
+{
+ fatal("getentropy failed");
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+ _rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+ static pid_t _rs_pid = 0;
+ pid_t pid = getpid();
+
+ if (_rs_pid == 0 || _rs_pid == 1 || _rs_pid != pid || _rs_forked) {
+ _rs_pid = pid;
+ _rs_forked = 0;
+ if (rs)
+ memset(rs, 0, sizeof(*rs));
+ }
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+#if defined(MAP_ANON) && defined(MAP_PRIVATE)
+ if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+ return (-1);
+
+ if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+ munmap(*rsp, sizeof(**rsp));
+ *rsp = NULL;
+ return (-1);
+ }
+#else
+ if ((*rsp = calloc(1, sizeof(**rsp))) == NULL)
+ return (-1);
+ if ((*rsxp = calloc(1, sizeof(**rsxp))) == NULL) {
+ free(*rsp);
+ *rsp = NULL;
+ return (-1);
+ }
+#endif
+
+ _ARC4_ATFORK(_rs_forkhandler);
+ return (0);
+}
diff --git a/ext/arc4random/arc4random.hh b/ext/arc4random/arc4random.hh
new file mode 100644
index 0000000..6e01712
--- /dev/null
+++ b/ext/arc4random/arc4random.hh
@@ -0,0 +1,21 @@
+#pragma once
+#include <cstddef>
+#include <cinttypes>
+
+#include "config.h"
+
+extern "C"
+{
+#ifndef HAVE_ARC4RANDOM
+ uint32_t arc4random(void);
+#endif
+#ifndef HAVE_ARC4RANDOM_BUF
+ void arc4random_buf(void* buf, size_t nbytes);
+#endif
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+ uint32_t arc4random_uniform(uint32_t upper_bound);
+#endif
+#ifndef HAVE_EXPLICIT_BZERO
+ void explicit_bzero(void*, size_t len);
+#endif
+}
diff --git a/ext/arc4random/arc4random_uniform.c b/ext/arc4random/arc4random_uniform.c
new file mode 100644
index 0000000..591f92d
--- /dev/null
+++ b/ext/arc4random/arc4random_uniform.c
@@ -0,0 +1,64 @@
+/* $OpenBSD: arc4random_uniform.c,v 1.3 2019/01/20 02:59:07 bcook Exp $ */
+
+/*
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random_uniform.c */
+
+#include "includes.h"
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+uint32_t
+arc4random_uniform(uint32_t upper_bound)
+{
+ uint32_t r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+ /* 2**32 % x == (2**32 - x) % x */
+ min = -upper_bound % upper_bound;
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = arc4random();
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
diff --git a/ext/arc4random/bsd-getentropy.c b/ext/arc4random/bsd-getentropy.c
new file mode 100644
index 0000000..0231e06
--- /dev/null
+++ b/ext/arc4random/bsd-getentropy.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifndef SSH_RANDOM_DEV
+# define SSH_RANDOM_DEV "/dev/urandom"
+#endif /* SSH_RANDOM_DEV */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_RANDOM_H
+# include <sys/random.h>
+#endif
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef WITH_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#endif
+
+#include "log.h"
+
+int
+_ssh_compat_getentropy(void *s, size_t len)
+{
+#ifdef WITH_OPENSSL
+ if (RAND_bytes(s, len) <= 0)
+ fatal("Couldn't obtain random bytes (error 0x%lx)",
+ (unsigned long)ERR_get_error());
+#else
+ int fd, save_errno;
+ ssize_t r;
+ size_t o = 0;
+
+#ifdef HAVE_GETENTROPY
+ if ((r = getentropy(s, len)) == 0)
+ return 0;
+#endif /* HAVE_GETENTROPY */
+#ifdef HAVE_GETRANDOM
+ if ((r = getrandom(s, len, 0)) > 0 && (size_t)r == len)
+ return 0;
+#endif /* HAVE_GETRANDOM */
+
+ if ((fd = open(SSH_RANDOM_DEV, O_RDONLY)) == -1) {
+ save_errno = errno;
+ /* Try egd/prngd before giving up. */
+ if (seed_from_prngd(s, len) == 0)
+ return 0;
+ fatal("Couldn't open %s: %s", SSH_RANDOM_DEV,
+ strerror(save_errno));
+ }
+ while (o < len) {
+ r = read(fd, (u_char *)s + o, len - o);
+ if (r < 0) {
+ if (errno == EAGAIN || errno == EINTR ||
+ errno == EWOULDBLOCK)
+ continue;
+ fatal("read %s: %s", SSH_RANDOM_DEV, strerror(errno));
+ }
+ o += r;
+ }
+ close(fd);
+#endif /* WITH_OPENSSL */
+ return 0;
+}
diff --git a/ext/arc4random/chacha_private.h b/ext/arc4random/chacha_private.h
new file mode 100644
index 0000000..cdcb785
--- /dev/null
+++ b/ext/arc4random/chacha_private.h
@@ -0,0 +1,224 @@
+/* OPENBSD ORIGINAL: lib/libc/crypt/chacha_private.h */
+
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+/* $OpenBSD: chacha_private.h,v 1.3 2022/02/28 21:56:29 dtucker Exp $ */
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct
+{
+ u32 input[16]; /* could be compressed */
+} chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+ (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+ (((u32)((p)[0]) ) | \
+ ((u32)((p)[1]) << 8) | \
+ ((u32)((p)[2]) << 16) | \
+ ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v) ); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void
+chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
+{
+ const char *constants;
+
+ x->input[4] = U8TO32_LITTLE(k + 0);
+ x->input[5] = U8TO32_LITTLE(k + 4);
+ x->input[6] = U8TO32_LITTLE(k + 8);
+ x->input[7] = U8TO32_LITTLE(k + 12);
+ if (kbits == 256) { /* recommended */
+ k += 16;
+ constants = sigma;
+ } else { /* kbits == 128 */
+ constants = tau;
+ }
+ x->input[8] = U8TO32_LITTLE(k + 0);
+ x->input[9] = U8TO32_LITTLE(k + 4);
+ x->input[10] = U8TO32_LITTLE(k + 8);
+ x->input[11] = U8TO32_LITTLE(k + 12);
+ x->input[0] = U8TO32_LITTLE(constants + 0);
+ x->input[1] = U8TO32_LITTLE(constants + 4);
+ x->input[2] = U8TO32_LITTLE(constants + 8);
+ x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+static void
+chacha_ivsetup(chacha_ctx *x,const u8 *iv)
+{
+ x->input[12] = 0;
+ x->input[13] = 0;
+ x->input[14] = U8TO32_LITTLE(iv + 0);
+ x->input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+static void
+chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+ u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ u8 *ctarget = NULL;
+ u8 tmp[64];
+ u_int i;
+
+ if (!bytes) return;
+
+ j0 = x->input[0];
+ j1 = x->input[1];
+ j2 = x->input[2];
+ j3 = x->input[3];
+ j4 = x->input[4];
+ j5 = x->input[5];
+ j6 = x->input[6];
+ j7 = x->input[7];
+ j8 = x->input[8];
+ j9 = x->input[9];
+ j10 = x->input[10];
+ j11 = x->input[11];
+ j12 = x->input[12];
+ j13 = x->input[13];
+ j14 = x->input[14];
+ j15 = x->input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20;i > 0;i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12)
+ QUARTERROUND( x1, x5, x9,x13)
+ QUARTERROUND( x2, x6,x10,x14)
+ QUARTERROUND( x3, x7,x11,x15)
+ QUARTERROUND( x0, x5,x10,x15)
+ QUARTERROUND( x1, x6,x11,x12)
+ QUARTERROUND( x2, x7, x8,x13)
+ QUARTERROUND( x3, x4, x9,x14)
+ }
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+
+#ifndef KEYSTREAM_ONLY
+ x0 = XOR(x0,U8TO32_LITTLE(m + 0));
+ x1 = XOR(x1,U8TO32_LITTLE(m + 4));
+ x2 = XOR(x2,U8TO32_LITTLE(m + 8));
+ x3 = XOR(x3,U8TO32_LITTLE(m + 12));
+ x4 = XOR(x4,U8TO32_LITTLE(m + 16));
+ x5 = XOR(x5,U8TO32_LITTLE(m + 20));
+ x6 = XOR(x6,U8TO32_LITTLE(m + 24));
+ x7 = XOR(x7,U8TO32_LITTLE(m + 28));
+ x8 = XOR(x8,U8TO32_LITTLE(m + 32));
+ x9 = XOR(x9,U8TO32_LITTLE(m + 36));
+ x10 = XOR(x10,U8TO32_LITTLE(m + 40));
+ x11 = XOR(x11,U8TO32_LITTLE(m + 44));
+ x12 = XOR(x12,U8TO32_LITTLE(m + 48));
+ x13 = XOR(x13,U8TO32_LITTLE(m + 52));
+ x14 = XOR(x14,U8TO32_LITTLE(m + 56));
+ x15 = XOR(x15,U8TO32_LITTLE(m + 60));
+#endif
+
+ j12 = PLUSONE(j12);
+ if (!j12) {
+ j13 = PLUSONE(j13);
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+
+ U32TO8_LITTLE(c + 0,x0);
+ U32TO8_LITTLE(c + 4,x1);
+ U32TO8_LITTLE(c + 8,x2);
+ U32TO8_LITTLE(c + 12,x3);
+ U32TO8_LITTLE(c + 16,x4);
+ U32TO8_LITTLE(c + 20,x5);
+ U32TO8_LITTLE(c + 24,x6);
+ U32TO8_LITTLE(c + 28,x7);
+ U32TO8_LITTLE(c + 32,x8);
+ U32TO8_LITTLE(c + 36,x9);
+ U32TO8_LITTLE(c + 40,x10);
+ U32TO8_LITTLE(c + 44,x11);
+ U32TO8_LITTLE(c + 48,x12);
+ U32TO8_LITTLE(c + 52,x13);
+ U32TO8_LITTLE(c + 56,x14);
+ U32TO8_LITTLE(c + 60,x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+ }
+ x->input[12] = j12;
+ x->input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+#ifndef KEYSTREAM_ONLY
+ m += 64;
+#endif
+ }
+}
diff --git a/ext/arc4random/explicit_bzero.c b/ext/arc4random/explicit_bzero.c
new file mode 100644
index 0000000..68cd2c1
--- /dev/null
+++ b/ext/arc4random/explicit_bzero.c
@@ -0,0 +1,65 @@
+/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */
+/* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */
+/*
+ * Public domain.
+ * Written by Ted Unangst
+ */
+
+#include "includes.h"
+
+#include <string.h>
+
+/*
+ * explicit_bzero - don't let the compiler optimize away bzero
+ */
+
+#ifndef HAVE_EXPLICIT_BZERO
+
+#ifdef HAVE_EXPLICIT_MEMSET
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ (void)explicit_memset(p, 0, n);
+}
+
+#elif defined(HAVE_MEMSET_S)
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ if (n == 0)
+ return;
+ (void)memset_s(p, n, 0, n);
+}
+
+#else /* HAVE_MEMSET_S */
+
+/*
+ * Indirect bzero through a volatile pointer to hopefully avoid
+ * dead-store optimisation eliminating the call.
+ */
+static void (* volatile ssh_bzero)(void *, size_t) = bzero;
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ if (n == 0)
+ return;
+ /*
+ * clang -fsanitize=memory needs to intercept memset-like functions
+ * to correctly detect memory initialisation. Make sure one is called
+ * directly since our indirection trick above successfully confuses it.
+ */
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+ memset(p, 0, n);
+# endif
+#endif
+
+ ssh_bzero(p, n);
+}
+
+#endif /* HAVE_MEMSET_S */
+
+#endif /* HAVE_EXPLICIT_BZERO */
diff --git a/ext/arc4random/includes.h b/ext/arc4random/includes.h
new file mode 100644
index 0000000..f5bedfa
--- /dev/null
+++ b/ext/arc4random/includes.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "config.h"
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#define seed_from_prngd(a, b) -1
+
+#ifndef HAVE_ARC4RANDOM
+uint32_t arc4random(void);
+#endif
+#ifndef HAVE_ARC4RANDOM_BUF
+void arc4random_buf(void *buf, size_t nbytes);
+#endif
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+uint32_t arc4random_uniform(uint32_t upper_bound);
+#endif
+#ifndef HAVE_EXPLICIT_BZERO
+void explicit_bzero(void *, size_t len);
+#endif
+
+int _ssh_compat_getentropy(void *, size_t);
+
+#define DEF_WEAK(x)
diff --git a/ext/arc4random/log.h b/ext/arc4random/log.h
new file mode 100644
index 0000000..51d7af2
--- /dev/null
+++ b/ext/arc4random/log.h
@@ -0,0 +1 @@
+#define fatal(...) do { fprintf(stderr, __VA_ARGS__); abort(); } while (0)
diff --git a/ext/ipcrypt/Makefile.in b/ext/ipcrypt/Makefile.in
index 19a00e6..deaac7e 100644
--- a/ext/ipcrypt/Makefile.in
+++ b/ext/ipcrypt/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# 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,
@@ -97,6 +97,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \
$(top_srcdir)/m4/dnsdist_enable_dnscrypt.m4 \
$(top_srcdir)/m4/dnsdist_enable_doh.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh3.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doq.m4 \
$(top_srcdir)/m4/dnsdist_enable_tls_providers.m4 \
$(top_srcdir)/m4/dnsdist_with_cdb.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
@@ -116,6 +118,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_check_ragel.m4 \
$(top_srcdir)/m4/pdns_check_secure_memset.m4 \
$(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_fuzz_targets.m4 \
$(top_srcdir)/m4/pdns_enable_ipcipher.m4 \
$(top_srcdir)/m4/pdns_enable_lto.m4 \
$(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
@@ -133,10 +137,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_with_lua.m4 \
$(top_srcdir)/m4/pdns_with_net_snmp.m4 \
$(top_srcdir)/m4/pdns_with_nghttp2.m4 \
+ $(top_srcdir)/m4/pdns_with_quiche.m4 \
$(top_srcdir)/m4/pdns_with_re2.m4 \
$(top_srcdir)/m4/pdns_with_service_user.m4 \
- $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \
- $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/pdns_with_xsk.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)
@@ -211,8 +216,6 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -220,6 +223,7 @@ AMTAR = @AMTAR@
AM_CPPFLAGS = @AM_CPPFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
+ARC4RANDOM_LIBS = @ARC4RANDOM_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -230,13 +234,16 @@ BOOST_ROOT = @BOOST_ROOT@
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@
+BPF_CFLAGS = @BPF_CFLAGS@
+BPF_LIBS = @BPF_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_CFLAGS = @CDB_CFLAGS@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
-CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -253,8 +260,10 @@ 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@
GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -326,6 +335,8 @@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
+QUICHE_CFLAGS = @QUICHE_CFLAGS@
+QUICHE_LIBS = @QUICHE_LIBS@
RAGEL = @RAGEL@
RANLIB = @RANLIB@
RE2_CFLAGS = @RE2_CFLAGS@
@@ -345,6 +356,8 @@ SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
THREADFLAGS = @THREADFLAGS@
VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
+XDP_CFLAGS = @XDP_CFLAGS@
+XDP_LIBS = @XDP_LIBS@
YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
YAHTTP_LIBS = @YAHTTP_LIBS@
abs_builddir = @abs_builddir@
@@ -559,7 +572,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/ext/libbpf/libbpf.h b/ext/libbpf/libbpf.h
index 2fc7281..f429545 100644
--- a/ext/libbpf/libbpf.h
+++ b/ext/libbpf/libbpf.h
@@ -8,19 +8,6 @@ extern "C" {
struct bpf_insn;
-int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
- int max_entries, int map_flags);
-int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
-int bpf_lookup_elem(int fd, void *key, void *value);
-int bpf_delete_elem(int fd, void *key);
-int bpf_get_next_key(int fd, void *key, void *next_key);
-
-int bpf_prog_load(enum bpf_prog_type prog_type,
- const struct bpf_insn *insns, int insn_len,
- const char *license, int kern_version);
-
-int bpf_obj_pin(int fd, const char *pathname);
-int bpf_obj_get(const char *pathname);
#define LOG_BUF_SIZE 65536
extern char bpf_log_buf[LOG_BUF_SIZE];
diff --git a/ext/lmdb-safe/lmdb-safe.cc b/ext/lmdb-safe/lmdb-safe.cc
index 33c3d45..6729286 100644
--- a/ext/lmdb-safe/lmdb-safe.cc
+++ b/ext/lmdb-safe/lmdb-safe.cc
@@ -68,12 +68,17 @@ namespace LMDBLS {
return (lsh->d_flags & LS_FLAG_DELETED) != 0;
}
+ uint64_t LSgetTimestamp(std::string_view val) {
+ const LSheader* lsh = LSassertFixedHeaderSize(val);
+
+ return lsh->getTimestamp();
+ }
bool s_flag_deleted{false};
}
#endif /* #ifndef DNSDIST */
-MDBDbi::MDBDbi(MDB_env* env, MDB_txn* txn, const string_view dbname, int flags)
+MDBDbi::MDBDbi(MDB_env* /* env */, MDB_txn* txn, const string_view dbname, int flags) : d_dbi(-1)
{
// A transaction that uses this function must finish (either commit or abort) before any other transaction in the process may use this function.
diff --git a/ext/lmdb-safe/lmdb-safe.hh b/ext/lmdb-safe/lmdb-safe.hh
index 2d5983b..1c62d88 100644
--- a/ext/lmdb-safe/lmdb-safe.hh
+++ b/ext/lmdb-safe/lmdb-safe.hh
@@ -140,7 +140,9 @@ namespace LMDBLS {
return std::string((char*)this, sizeof(*this)) + std::string(ntohs(d_numextra)*8, '\0');
}
-
+ uint64_t getTimestamp() const {
+ return _LMDB_SAFE_BSWAP64MAYBE(d_timestamp);
+ }
};
static_assert(sizeof(LSheader)==24, "LSheader size is wrong");
@@ -154,6 +156,7 @@ namespace LMDBLS {
size_t LScheckHeaderAndGetSize(std::string_view val, size_t datasize=0);
size_t LScheckHeaderAndGetSize(const MDBOutVal *val, size_t datasize=0);
bool LSisDeleted(std::string_view val);
+ uint64_t LSgetTimestamp(std::string_view val);
extern bool s_flag_deleted;
}
diff --git a/ext/luawrapper/include/LuaContext.hpp b/ext/luawrapper/include/LuaContext.hpp
index ad6c86e..655375e 100644
--- a/ext/luawrapper/include/LuaContext.hpp
+++ b/ext/luawrapper/include/LuaContext.hpp
@@ -1643,6 +1643,7 @@ private:
// creating the object
// lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it
// and that's what we do with placement-new
+ static_assert(alignof(TType) <= 8);
const auto pointerLocation = static_cast<TType*>(lua_newuserdata(state, sizeof(TType)));
new (pointerLocation) TType(std::forward<TType2>(value));
}
@@ -2292,6 +2293,7 @@ struct LuaContext::Pusher<TReturnType (TParameters...)>
// creating the object
// lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it
// and that's what we do with placement-new
+ // static_assert(alignof(TFunctionObject) <= 8); XXX trips on at least c++lib 17, see #13766
const auto functionLocation = static_cast<TFunctionObject*>(lua_newuserdata(state, sizeof(TFunctionObject)));
new (functionLocation) TFunctionObject(std::move(fn));
@@ -2335,6 +2337,7 @@ struct LuaContext::Pusher<TReturnType (TParameters...)>
};
// we copy the function object onto the stack
+ static_assert(alignof(TFunctionObject) <= 8);
const auto functionObjectLocation = static_cast<TFunctionObject*>(lua_newuserdata(state, sizeof(TFunctionObject)));
new (functionObjectLocation) TFunctionObject(std::move(fn));
diff --git a/ext/yahttp/Makefile.in b/ext/yahttp/Makefile.in
index e6e5ece..3ca8537 100644
--- a/ext/yahttp/Makefile.in
+++ b/ext/yahttp/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# 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,
@@ -96,6 +96,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \
$(top_srcdir)/m4/dnsdist_enable_dnscrypt.m4 \
$(top_srcdir)/m4/dnsdist_enable_doh.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh3.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doq.m4 \
$(top_srcdir)/m4/dnsdist_enable_tls_providers.m4 \
$(top_srcdir)/m4/dnsdist_with_cdb.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
@@ -115,6 +117,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_check_ragel.m4 \
$(top_srcdir)/m4/pdns_check_secure_memset.m4 \
$(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_fuzz_targets.m4 \
$(top_srcdir)/m4/pdns_enable_ipcipher.m4 \
$(top_srcdir)/m4/pdns_enable_lto.m4 \
$(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
@@ -132,10 +136,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_with_lua.m4 \
$(top_srcdir)/m4/pdns_with_net_snmp.m4 \
$(top_srcdir)/m4/pdns_with_nghttp2.m4 \
+ $(top_srcdir)/m4/pdns_with_quiche.m4 \
$(top_srcdir)/m4/pdns_with_re2.m4 \
$(top_srcdir)/m4/pdns_with_service_user.m4 \
- $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \
- $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/pdns_with_xsk.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)
@@ -195,10 +200,8 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
+am__DIST_COMMON = $(srcdir)/Makefile.in README.md
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -230,6 +233,7 @@ AMTAR = @AMTAR@
AM_CPPFLAGS = @AM_CPPFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
+ARC4RANDOM_LIBS = @ARC4RANDOM_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -240,13 +244,16 @@ BOOST_ROOT = @BOOST_ROOT@
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@
+BPF_CFLAGS = @BPF_CFLAGS@
+BPF_LIBS = @BPF_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_CFLAGS = @CDB_CFLAGS@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
-CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -263,8 +270,10 @@ 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@
GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -336,6 +345,8 @@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
+QUICHE_CFLAGS = @QUICHE_CFLAGS@
+QUICHE_LIBS = @QUICHE_LIBS@
RAGEL = @RAGEL@
RANLIB = @RANLIB@
RE2_CFLAGS = @RE2_CFLAGS@
@@ -355,6 +366,8 @@ SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
THREADFLAGS = @THREADFLAGS@
VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
+XDP_CFLAGS = @XDP_CFLAGS@
+XDP_LIBS = @XDP_LIBS@
YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
YAHTTP_LIBS = @YAHTTP_LIBS@
abs_builddir = @abs_builddir@
@@ -557,7 +570,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/ext/yahttp/yahttp/Makefile.in b/ext/yahttp/yahttp/Makefile.in
index ac4f348..a59987f 100644
--- a/ext/yahttp/yahttp/Makefile.in
+++ b/ext/yahttp/yahttp/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# 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,
@@ -97,6 +97,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/ax_python_module.m4 $(top_srcdir)/m4/boost.m4 \
$(top_srcdir)/m4/dnsdist_enable_dnscrypt.m4 \
$(top_srcdir)/m4/dnsdist_enable_doh.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doh3.m4 \
+ $(top_srcdir)/m4/dnsdist_enable_doq.m4 \
$(top_srcdir)/m4/dnsdist_enable_tls_providers.m4 \
$(top_srcdir)/m4/dnsdist_with_cdb.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
@@ -116,6 +118,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_check_ragel.m4 \
$(top_srcdir)/m4/pdns_check_secure_memset.m4 \
$(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_fuzz_targets.m4 \
$(top_srcdir)/m4/pdns_enable_ipcipher.m4 \
$(top_srcdir)/m4/pdns_enable_lto.m4 \
$(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
@@ -133,10 +137,11 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_pthread_set_name.m4 \
$(top_srcdir)/m4/pdns_with_lua.m4 \
$(top_srcdir)/m4/pdns_with_net_snmp.m4 \
$(top_srcdir)/m4/pdns_with_nghttp2.m4 \
+ $(top_srcdir)/m4/pdns_with_quiche.m4 \
$(top_srcdir)/m4/pdns_with_re2.m4 \
$(top_srcdir)/m4/pdns_with_service_user.m4 \
- $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/warnings.m4 \
- $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/pdns_with_xsk.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)
@@ -229,8 +234,6 @@ am__define_uniq_tagged_files = \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -238,6 +241,7 @@ AMTAR = @AMTAR@
AM_CPPFLAGS = @AM_CPPFLAGS@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
+ARC4RANDOM_LIBS = @ARC4RANDOM_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -248,13 +252,16 @@ BOOST_ROOT = @BOOST_ROOT@
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@
+BPF_CFLAGS = @BPF_CFLAGS@
+BPF_LIBS = @BPF_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_CFLAGS = @CDB_CFLAGS@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
-CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
@@ -271,8 +278,10 @@ 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@
GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
@@ -344,6 +353,8 @@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
+QUICHE_CFLAGS = @QUICHE_CFLAGS@
+QUICHE_LIBS = @QUICHE_LIBS@
RAGEL = @RAGEL@
RANLIB = @RANLIB@
RE2_CFLAGS = @RE2_CFLAGS@
@@ -363,6 +374,8 @@ SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
THREADFLAGS = @THREADFLAGS@
VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
+XDP_CFLAGS = @XDP_CFLAGS@
+XDP_LIBS = @XDP_LIBS@
YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
YAHTTP_LIBS = @YAHTTP_LIBS@
abs_builddir = @abs_builddir@
@@ -583,7 +596,6 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
diff --git a/ext/yahttp/yahttp/cookie.hpp b/ext/yahttp/yahttp/cookie.hpp
index aa5359b..9e50d8b 100644
--- a/ext/yahttp/yahttp/cookie.hpp
+++ b/ext/yahttp/yahttp/cookie.hpp
@@ -118,7 +118,7 @@ namespace YaHTTP {
if (s.find("=") != std::string::npos)
keyValuePair(s, k, v);
else
- k = s;
+ k = std::move(s);
if (k == "expires") {
DateTime dt;
dt.parseCookie(v);
diff --git a/ext/yahttp/yahttp/reqresp.cpp b/ext/yahttp/yahttp/reqresp.cpp
index e5f9c95..a96def6 100644
--- a/ext/yahttp/yahttp/reqresp.cpp
+++ b/ext/yahttp/yahttp/reqresp.cpp
@@ -136,7 +136,7 @@ namespace YaHTTP {
if (target->headers.find(key) != target->headers.end()) {
target->headers[key] = target->headers[key] + ";" + value;
} else {
- target->headers[key] = value;
+ target->headers[key] = std::move(value);
}
}
}
diff --git a/ext/yahttp/yahttp/router.cpp b/ext/yahttp/yahttp/router.cpp
index 18ea9b6..e123b38 100644
--- a/ext/yahttp/yahttp/router.cpp
+++ b/ext/yahttp/yahttp/router.cpp
@@ -5,8 +5,6 @@
#include "router.hpp"
namespace YaHTTP {
- typedef funcptr::tuple<int,int> TDelim;
-
// router is defined here.
YaHTTP::Router Router::router;
@@ -24,76 +22,108 @@ namespace YaHTTP {
routes.push_back(funcptr::make_tuple(method2, url, handler, name));
};
- bool Router::route(Request *req, THandlerFunction& handler) {
- std::map<std::string, TDelim> params;
- int pos1,pos2;
- bool matched = false;
- std::string rname;
-
- // iterate routes
- for(TRouteList::iterator i = routes.begin(); !matched && i != routes.end(); i++) {
- int k1,k2,k3;
- std::string pname;
- std::string method, url;
- funcptr::tie(method, url, handler, rname) = *i;
-
- if (method.empty() == false && req->method != method) continue; // no match on method
- // see if we can't match the url
- params.clear();
- // simple matcher func
- for(k1=0, k2=0; k1 < static_cast<int>(url.size()) && k2 < static_cast<int>(req->url.path.size()); ) {
- if (url[k1] == '<') {
- pos1 = k2;
- k3 = k1+1;
+ bool Router::match(const std::string& route, const URL& requrl, std::map<std::string, TDelim> &params) {
+ size_t rpos = 0;
+ size_t upos = 0;
+ size_t npos = 0;
+ size_t nstart = 0;
+ size_t nend = 0;
+ std::string pname;
+ for(; rpos < route.size() && upos < requrl.path.size(); ) {
+ if (route[rpos] == '<') {
+ nstart = upos;
+ npos = rpos+1;
// start of parameter
- while(k1 < static_cast<int>(url.size()) && url[k1] != '>') k1++;
- pname = std::string(url.begin()+k3, url.begin()+k1);
+ while(rpos < route.size() && route[rpos] != '>') {
+ rpos++;
+ }
+ pname = std::string(route.begin()+static_cast<long>(npos), route.begin()+static_cast<long>(rpos));
// then we also look it on the url
- if (pname[0]=='*') {
+ if (pname[0] == '*') {
pname = pname.substr(1);
// this matches whatever comes after it, basically end of string
- pos2 = req->url.path.size();
- if (pname != "")
- params[pname] = funcptr::tie(pos1,pos2);
- k1 = url.size();
- k2 = req->url.path.size();
+ nend = requrl.path.size();
+ if (!pname.empty()) {
+ params[pname] = funcptr::tie(nstart,nend);
+ }
+ rpos = route.size();
+ upos = requrl.path.size();
break;
} else {
- // match until url[k1]
- while(k2 < static_cast<int>(req->url.path.size()) && req->url.path[k2] != url[k1+1]) k2++;
- pos2 = k2;
- params[pname] = funcptr::tie(pos1,pos2);
+ // match until url[upos] or next / if pattern is at end
+ while (upos < requrl.path.size()) {
+ if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
+ break;
+ }
+ if (requrl.path[upos] == route[rpos+1]) {
+ break;
+ }
+ upos++;
+ }
+ nend = upos;
+ params[pname] = funcptr::tie(nstart, nend);
}
- k2--;
+ upos--;
}
- else if (url[k1] != req->url.path[k2]) {
+ else if (route[rpos] != requrl.path[upos]) {
break;
}
- k1++; k2++;
+ rpos++; upos++;
+ }
+ return route[rpos] == requrl.path[upos];
+ }
+
+ RoutingResult Router::route(Request *req, THandlerFunction& handler) {
+ std::map<std::string, TDelim> params;
+ bool matched = false;
+ bool seen = false;
+ std::string rname;
+
+ // iterate routes
+ for (auto& route: routes) {
+ std::string method;
+ std::string url;
+ funcptr::tie(method, url, handler, rname) = route;
+
+ // see if we can't match the url
+ params.clear();
+ // simple matcher func
+ matched = match(url, req->url, params);
+
+ if (matched && !method.empty() && req->method != method) {
+ // method did not match, record it though so we can return correct result
+ matched = false;
+ seen = true;
+ continue;
}
+ if (matched) {
+ break;
+ }
+ }
- // ensure.
- if (url[k1] != req->url.path[k2])
- matched = false;
- else
- matched = true;
+ if (!matched) {
+ if (seen) {
+ return RouteNoMethod;
+ }
+ // no route
+ return RouteNotFound;
}
- if (!matched) { return false; } // no route
- req->parameters.clear();
+ req->parameters.clear();
- for(std::map<std::string, TDelim>::iterator i = params.begin(); i != params.end(); i++) {
- int p1,p2;
- funcptr::tie(p1,p2) = i->second;
- std::string value(req->url.path.begin() + p1, req->url.path.begin() + p2);
+ for (const auto& param: params) {
+ int nstart = 0;
+ int nend = 0;
+ funcptr::tie(nstart, nend) = param.second;
+ std::string value(req->url.path.begin() + nstart, req->url.path.begin() + nend);
value = Utility::decodeURL(value);
- req->parameters[i->first] = value;
+ req->parameters[param.first] = std::move(value);
}
- req->routeName = rname;
+ req->routeName = std::move(rname);
- return true;
+ return RouteFound;
};
void Router::printRoutes(std::ostream &os) {
diff --git a/ext/yahttp/yahttp/router.hpp b/ext/yahttp/yahttp/router.hpp
index 205119c..3cb13ed 100644
--- a/ext/yahttp/yahttp/router.hpp
+++ b/ext/yahttp/yahttp/router.hpp
@@ -25,9 +25,16 @@ namespace funcptr = boost;
#include <utility>
namespace YaHTTP {
+ enum RoutingResult {
+ RouteFound = 1,
+ RouteNotFound = 0,
+ RouteNoMethod = -1,
+ };
+
typedef funcptr::function <void(Request* req, Response* resp)> THandlerFunction; //!< Handler function pointer
typedef funcptr::tuple<std::string, std::string, THandlerFunction, std::string> TRoute; //!< Route tuple (method, urlmask, handler, name)
typedef std::vector<TRoute> TRouteList; //!< List of routes in order of evaluation
+ typedef funcptr::tuple<int,int> TDelim;
/*! Implements simple router.
@@ -44,26 +51,28 @@ is consumed but not stored. Note that only path is matched, scheme, host and url
static Router router; //<! Singleton instance of Router
public:
void map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name); //<! Instance method for mapping urls
- bool route(Request *req, THandlerFunction& handler); //<! Instance method for performing routing
+ RoutingResult route(Request *req, THandlerFunction& handler); //<! Instance method for performing routing
void printRoutes(std::ostream &os); //<! Instance method for printing routes
std::pair<std::string, std::string> urlFor(const std::string &name, const strstr_map_t& arguments); //<! Instance method for generating paths
+ static bool match(const std::string& route, const URL& requrl, std::map<std::string, TDelim>& params); //<! Instance method for matching a route
/*! Map an URL.
-If method is left empty, it will match any method. Name is also optional, but needed if you want to find it for making URLs
+If method is left empty, it will match any method. Name is also optional, but needed if you want to find it for making URLs
*/
- static void Map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map(method, url, handler, name); };
- static void Get(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("GET", url, handler, name); }; //<! Helper for mapping GET
- static void Post(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("POST", url, handler, name); }; //<! Helper for mapping POST
- static void Put(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PUT", url, handler, name); }; //<! Helper for mapping PUT
- static void Patch(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PATCH", url, handler, name); }; //<! Helper for mapping PATCH
- static void Delete(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("DELETE", url, handler, name); }; //<! Helper for mapping DELETE
- static void Any(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("", url, handler, name); }; //<! Helper for mapping any method
+ static void Map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map(method, url, std::move(handler), name); };
+ static void Get(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("GET", url, std::move(handler), name); }; //<! Helper for mapping GET
+ static void Post(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("POST", url, std::move(handler), name); }; //<! Helper for mapping POST
+ static void Put(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PUT", url, std::move(handler), name); }; //<! Helper for mapping PUT
+ static void Patch(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PATCH", url, std::move(handler), name); }; //<! Helper for mapping PATCH
+ static void Delete(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("DELETE", url, std::move(handler), name); }; //<! Helper for mapping DELETE
+ static void Any(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("", url, std::move(handler), name); }; //<! Helper for mapping any method
- static bool Route(Request *req, THandlerFunction& handler) { return router.route(req, handler); }; //<! Performs routing based on req->url.path
+ static bool Match(const std::string& route, const URL& requrl, std::map<std::string, TDelim>& params) { return router.match(route, requrl, params); };
+ static RoutingResult Route(Request *req, THandlerFunction& handler) { return router.route(req, handler); }; //<! Performs routing based on req->url.path, returns RouteFound if route is found and method matches, RouteNoMethod if route is seen but method did match, and RouteNotFound if not found.
static void PrintRoutes(std::ostream &os) { router.printRoutes(os); }; //<! Prints all known routes to given output stream
static std::pair<std::string, std::string> URLFor(const std::string &name, const strstr_map_t& arguments) { return router.urlFor(name,arguments); }; //<! Generates url from named route and arguments. Missing arguments are assumed empty
- static const TRouteList& GetRoutes() { return router.routes; } //<! Reference to route list
+ static const TRouteList& GetRoutes() { return router.routes; } //<! Reference to route list
static void Clear() { router.routes.clear(); } //<! Clear all routes
TRouteList routes; //<! Instance variable for routes
diff --git a/ext/yahttp/yahttp/utility.hpp b/ext/yahttp/yahttp/utility.hpp
index 23e6b8a..1d5e41e 100644
--- a/ext/yahttp/yahttp/utility.hpp
+++ b/ext/yahttp/yahttp/utility.hpp
@@ -392,7 +392,7 @@ namespace YaHTTP {
}
key = decodeURL(key);
value = decodeURL(value);
- parameter_map[key] = value;
+ parameter_map[key] = std::move(value);
if (nextpos == std::string::npos) {
// no more parameters left
break;
diff --git a/fuzz_dnsdistcache.cc b/fuzz_dnsdistcache.cc
new file mode 100644
index 0000000..6c10920
--- /dev/null
+++ b/fuzz_dnsdistcache.cc
@@ -0,0 +1,61 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-cache.hh"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+
+ if (size > std::numeric_limits<uint16_t>::max()) {
+ return 0;
+ }
+
+ /* dnsdist's version */
+ DNSDistPacketCache pcSkipCookies(10000);
+ // By default, cookies are not hashed
+ pcSkipCookies.setECSParsingEnabled(true);
+
+ DNSDistPacketCache pcHashCookies(10000);
+ pcHashCookies.setECSParsingEnabled(true);
+ // Do not skip cookies
+ pcHashCookies.setSkippedOptions({});
+
+ try {
+ uint16_t qtype;
+ uint16_t qclass;
+ unsigned int consumed;
+ PacketBuffer vect(data, data + size);
+ const DNSName qname(reinterpret_cast<const char*>(data), size, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ pcSkipCookies.getKey(qname.getStorage(), consumed, vect, false);
+ pcHashCookies.getKey(qname.getStorage(), consumed, vect, false);
+ boost::optional<Netmask> subnet;
+ DNSDistPacketCache::getClientSubnet(vect, consumed, subnet);
+ }
+ catch (const std::exception& e) {
+ }
+ catch (const PDNSException& e) {
+ }
+
+ return 0;
+}
diff --git a/fuzz_xsk.cc b/fuzz_xsk.cc
new file mode 100644
index 0000000..7066edc
--- /dev/null
+++ b/fuzz_xsk.cc
@@ -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.
+ */
+
+#include "xsk.hh"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+#ifdef HAVE_XSK
+ if (size > XskSocket::getFrameSize()) {
+ return 0;
+ }
+
+ try {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): packet data is usually mutable
+ XskPacket packet(const_cast<uint8_t*>(data), size, size);
+ if (packet.parse(false)) {
+ const auto& dest = packet.getToAddr();
+ const auto& orig = packet.getFromAddr();
+ const auto* payload = packet.getPayloadData();
+ auto capacity = packet.getCapacity();
+ auto length = packet.getDataLen();
+ auto frameLen = packet.getFrameLen();
+ auto header = packet.cloneHeaderToPacketBuffer();
+ auto buffer = packet.clonePacketBuffer();
+ (void)dest;
+ (void)orig;
+ (void)payload;
+ (void)capacity;
+ (void)length;
+ (void)frameLen;
+ }
+ }
+ catch (const std::exception& e) {
+ }
+#endif /* HAVE_XSK */
+ return 0;
+}
diff --git a/gettime.cc b/gettime.cc
index b6d95a4..e7b37b6 100644
--- a/gettime.cc
+++ b/gettime.cc
@@ -36,8 +36,9 @@ int gettime(struct timespec *tp, bool needRealTime)
#else
#include <sys/time.h>
+#include <cstddef>
-int gettime(struct timespec *tp, bool needRealTime)
+int gettime(struct timespec *tp, bool /* needRealTime */)
{
struct timeval tv;
diff --git a/html/index.html b/html/index.html
index 4f3bc69..29571e9 100644
--- a/html/index.html
+++ b/html/index.html
@@ -50,7 +50,7 @@
</tr></table>
<p>
Uptime: <span id="uptime"></span>, Number of queries: <span id="questions"></span> (<span id="qps"></span> qps), ACL drops: <span id="acl-drops"></span>, Dynamic drops: <span id="dyn-drops"></span>, Rule drops: <span id="rule-drops"></span><br/>
- Average response time: UDP <span id="latency"></span> ms, TCP <span id="latency-tcp"></span> ms, DoT <span id="latency-dot"></span> ms, DoH <span id="latency-doh"></span> ms <br/>
+ Average response time: UDP <span id="latency"></span> ms, TCP <span id="latency-tcp"></span> ms, DoT <span id="latency-dot"></span> ms, DoH <span id="latency-doh"></span> ms, DoQ <span id="latency-doq"></span> ms <br/>
CPU Usage: <span id="cpu"></span>%, Cache hitrate: <span id="phitrate"></span>%, Server selection policy: <span id="server-policy"></span><br/>
Listening on: <span id="local"></span>, ACL: <span id="acl"></span>
</p>
diff --git a/html/local.js b/html/local.js
index cefb0a4..4f9f125 100644
--- a/html/local.js
+++ b/html/local.js
@@ -154,6 +154,7 @@ $(document).ready(function() {
$("#latency-tcp").text((data["latency-tcp-avg10000"]/1000.0).toFixed(2));
$("#latency-dot").text((data["latency-dot-avg10000"]/1000.0).toFixed(2));
$("#latency-doh").text((data["latency-doh-avg10000"]/1000.0).toFixed(2));
+ $("#latency-doq").text((data["latency-doq-avg10000"]/1000.0).toFixed(2));
if(!gdata["cpu-sys-msec"])
gdata=data;
@@ -204,10 +205,10 @@ $(document).ready(function() {
bouw = bouw + "</table>";
$("#downstreams").html(bouw);
- bouw='<table width="100%"><tr align=left><th>#</th><th align=left>Rule</th><th>Action</th><th>Matches</th></tr>';
+ bouw='<table width="100%"><tr align=left><th>#</th><th align=left>Name</th><th align=left>Rule</th><th>Action</th><th>Matches</th></tr>';
if(data["rules"].length) {
$.each(data["rules"], function(a,b) {
- bouw = bouw + ("<tr align=left><td>"+b["id"]+"</td><td align=left>"+b["rule"]+"</td><td>"+b["action"]+"</td>");
+ bouw = bouw + ("<tr align=left><td>"+b["id"]+"</td><td align=left>"+b["name"]+"</td><td align=left>"+b["rule"]+"</td><td>"+b["action"]+"</td>");
bouw = bouw + ("<td>"+b["matches"]+"</td></tr>");
});
}
@@ -216,10 +217,10 @@ $(document).ready(function() {
bouw = bouw + "</table>";
$("#rules").html(bouw);
- bouw='<table width="100%"><tr align=left><th>#</th><th align=left>Response Rule</th><th>Action</th><th>Matches</th></tr>';
+ bouw='<table width="100%"><tr align=left><th>#</th><th align=left>Name</th><th align=left>Response Rule</th><th>Action</th><th>Matches</th></tr>';
if(data["response-rules"].length) {
$.each(data["response-rules"], function(a,b) {
- bouw = bouw + ("<tr align=left><td>"+b["id"]+"</td><td align=left>"+b["rule"]+"</td><td>"+b["action"]+"</td>");
+ bouw = bouw + ("<tr align=left><td>"+b["id"]+"</td><td align=left>"+b["name"]+"</td><td align=left>"+b["rule"]+"</td><td>"+b["action"]+"</td>");
bouw = bouw + ("<td>"+b["matches"]+"</td></tr>");
});
}
diff --git a/htmlfiles.h b/htmlfiles.h
index c498570..e7897e0 100644
--- a/htmlfiles.h
+++ b/htmlfiles.h
@@ -488,106 +488,108 @@ static const unsigned char gindex_htmlData[] = {
0x63, 0x79, 0x2d, 0x64, 0x6f, 0x74, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x20,
0x6d, 0x73, 0x2c, 0x20, 0x44, 0x6f, 0x48, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64,
0x3d, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x64, 0x6f, 0x68, 0x22, 0x3e, 0x3c,
- 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x20, 0x6d, 0x73, 0x20, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x50, 0x55, 0x20, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3a,
- 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x63, 0x70, 0x75, 0x22, 0x3e,
- 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x25, 0x2c, 0x20, 0x43, 0x61, 0x63, 0x68, 0x65, 0x20,
- 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69,
- 0x64, 0x3d, 0x22, 0x70, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x22, 0x3e, 0x3c, 0x2f, 0x73,
- 0x70, 0x61, 0x6e, 0x3e, 0x25, 0x2c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65,
- 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x3a, 0x20,
- 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e,
- 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4c, 0x69, 0x73, 0x74,
- 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x3a, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20,
- 0x69, 0x64, 0x3d, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61,
- 0x6e, 0x3e, 0x2c, 0x20, 0x41, 0x43, 0x4c, 0x3a, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69,
- 0x64, 0x3d, 0x22, 0x61, 0x63, 0x6c, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22,
- 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x32, 0x30,
- 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x20, 0x76, 0x61, 0x6c,
- 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x74, 0x6f, 0x70, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64,
- 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x31, 0x32, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61,
- 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0x51, 0x50,
- 0x53, 0x20, 0x2f, 0x20, 0x53, 0x45, 0x52, 0x56, 0x46, 0x41, 0x49, 0x4c, 0x50, 0x53, 0x3c, 0x2f,
- 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64,
- 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f,
- 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64,
- 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x71, 0x70, 0x73, 0x79, 0x5f, 0x61, 0x78, 0x69, 0x73,
+ 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x20, 0x6d, 0x73, 0x2c, 0x20, 0x44, 0x6f, 0x51, 0x20, 0x3c,
+ 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79,
+ 0x2d, 0x64, 0x6f, 0x71, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x20, 0x6d, 0x73,
+ 0x20, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x50, 0x55,
+ 0x20, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64,
+ 0x3d, 0x22, 0x63, 0x70, 0x75, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x25, 0x2c,
+ 0x20, 0x43, 0x61, 0x63, 0x68, 0x65, 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3a, 0x20,
+ 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x70, 0x68, 0x69, 0x74, 0x72, 0x61,
+ 0x74, 0x65, 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x25, 0x2c, 0x20, 0x53, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70,
+ 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x3a, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d,
+ 0x22, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3e,
+ 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x3a,
+ 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x22, 0x3e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x2c, 0x20, 0x41, 0x43, 0x4c, 0x3a, 0x20,
+ 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x61, 0x63, 0x6c, 0x22, 0x3e, 0x3c,
+ 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
+ 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64,
+ 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x32, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x3c, 0x74, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x74, 0x6f, 0x70, 0x22,
+ 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20,
+ 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x31, 0x32, 0x22,
+ 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74,
+ 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e,
+ 0x74, 0x65, 0x72, 0x22, 0x3e, 0x51, 0x50, 0x53, 0x20, 0x2f, 0x20, 0x53, 0x45, 0x52, 0x56, 0x46,
+ 0x41, 0x49, 0x4c, 0x50, 0x53, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e,
+ 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d,
+ 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x71, 0x70,
+ 0x73, 0x79, 0x5f, 0x61, 0x78, 0x69, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x71, 0x70, 0x73, 0x63, 0x68,
+ 0x61, 0x72, 0x74, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69,
+ 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
+ 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c,
+ 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0x43, 0x41, 0x43,
+ 0x48, 0x45, 0x20, 0x48, 0x49, 0x54, 0x52, 0x41, 0x54, 0x45, 0x20, 0x2f, 0x20, 0x43, 0x50, 0x55,
+ 0x20, 0x25, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64,
+ 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x68,
+ 0x61, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x3e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x63, 0x70, 0x75, 0x79, 0x5f,
+ 0x61, 0x78, 0x69, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
+ 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x63, 0x70, 0x75, 0x63, 0x68, 0x61, 0x72, 0x74,
0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20,
- 0x69, 0x64, 0x3d, 0x22, 0x71, 0x70, 0x73, 0x63, 0x68, 0x61, 0x72, 0x74, 0x22, 0x3e, 0x3c, 0x2f,
- 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74,
- 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
- 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65,
- 0x6e, 0x74, 0x65, 0x72, 0x22, 0x3e, 0x43, 0x41, 0x43, 0x48, 0x45, 0x20, 0x48, 0x49, 0x54, 0x52,
- 0x41, 0x54, 0x45, 0x20, 0x2f, 0x20, 0x43, 0x50, 0x55, 0x20, 0x25, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f,
+ 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20,
- 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e,
- 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20,
- 0x69, 0x64, 0x3d, 0x22, 0x63, 0x70, 0x75, 0x79, 0x5f, 0x61, 0x78, 0x69, 0x73, 0x22, 0x3e, 0x3c,
- 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d,
- 0x22, 0x63, 0x70, 0x75, 0x63, 0x68, 0x61, 0x72, 0x74, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76,
- 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x63,
- 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x31, 0x35, 0x22, 0x20,
- 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x20, 0x63, 0x6c, 0x61,
- 0x73, 0x73, 0x3d, 0x22, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20,
+ 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x3c, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x63, 0x65, 0x6c, 0x6c, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e,
+ 0x67, 0x3d, 0x22, 0x31, 0x35, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30,
+ 0x30, 0x25, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x6f, 0x72, 0x64, 0x65,
+ 0x72, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22,
+ 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64,
+ 0x69, 0x76, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c,
+ 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x3e, 0x3c,
+ 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e,
- 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72,
- 0x65, 0x61, 0x6d, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x20, 0x3c, 0x2f, 0x74,
- 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
- 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d,
- 0x22, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c, 0x2f,
- 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64,
- 0x3d, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73,
+ 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c,
+ 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69,
+ 0x64, 0x3d, 0x22, 0x64, 0x79, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0x3c, 0x2f, 0x64,
+ 0x69, 0x76, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64,
+ 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x65, 0x62, 0x70, 0x66, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x72, 0x3e,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
- 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x64, 0x79, 0x6e, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c, 0x2f, 0x74, 0x64,
- 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f,
- 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x3c, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22,
- 0x65, 0x62, 0x70, 0x66, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76,
- 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x70, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x3c, 0x70, 0x3e,
- 0x3c, 0x2f, 0x70, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a,
- 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c,
- 0x3e, 0x0a,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x64,
+ 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x3c, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x2f,
+ 0x3e, 0x3c, 0x62, 0x72, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x70, 0x3e,
+ 0x3c, 0x2f, 0x70, 0x3e, 0x3c, 0x70, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
+ 0x0a, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a,
};
static const unsigned char gjs_d3_min_jsData[] = {
@@ -25066,367 +25068,326 @@ static const unsigned char glocal_jsData[] = {
0x64, 0x6f, 0x68, 0x2d, 0x61, 0x76, 0x67, 0x31, 0x30, 0x30, 0x30, 0x30, 0x22, 0x5d, 0x2f, 0x31,
0x30, 0x30, 0x30, 0x2e, 0x30, 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32,
0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x21, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63,
- 0x70, 0x75, 0x2d, 0x73, 0x79, 0x73, 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x29, 0x20, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x67, 0x64, 0x61, 0x74, 0x61, 0x3d, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x0a,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x70, 0x75, 0x3d, 0x28, 0x28, 0x31, 0x2e, 0x30, 0x2a, 0x64,
- 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x73, 0x79, 0x73, 0x2d, 0x6d, 0x73, 0x65,
- 0x63, 0x22, 0x5d, 0x2b, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70,
- 0x75, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x20, 0x2d, 0x20,
- 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x73,
- 0x79, 0x73, 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64,
- 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x6d, 0x73,
- 0x65, 0x63, 0x22, 0x5d, 0x29, 0x2f, 0x31, 0x30, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28,
- 0x22, 0x23, 0x63, 0x70, 0x75, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x63, 0x70, 0x75,
+ 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2d,
+ 0x64, 0x6f, 0x71, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x28, 0x64, 0x61, 0x74, 0x61,
+ 0x5b, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x64, 0x6f, 0x71, 0x2d, 0x61, 0x76,
+ 0x67, 0x31, 0x30, 0x30, 0x30, 0x30, 0x22, 0x5d, 0x2f, 0x31, 0x30, 0x30, 0x30, 0x2e, 0x30, 0x29,
0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61,
- 0x72, 0x20, 0x71, 0x70, 0x73, 0x3d, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22,
- 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64,
- 0x61, 0x74, 0x61, 0x5b, 0x22, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x5d, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x24, 0x28, 0x22, 0x23, 0x71, 0x70, 0x73, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x71,
- 0x70, 0x73, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x24, 0x28, 0x22, 0x23, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73,
- 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x5d, 0x29, 0x3b,
- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x70, 0x73,
- 0x3d, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x66,
- 0x61, 0x69, 0x6c, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x2d,
- 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x66,
- 0x61, 0x69, 0x6c, 0x2d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x3b,
- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3d,
- 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d,
- 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61,
- 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d, 0x2b, 0x31,
- 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x6d,
- 0x69, 0x73, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
+ 0x28, 0x21, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x73, 0x79, 0x73,
+ 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x29, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x64,
+ 0x61, 0x74, 0x61, 0x3d, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63,
+ 0x70, 0x75, 0x3d, 0x28, 0x28, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63,
+ 0x70, 0x75, 0x2d, 0x73, 0x79, 0x73, 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x2b, 0x31, 0x2e,
+ 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x75, 0x73, 0x65, 0x72,
+ 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x20, 0x2d, 0x20, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64,
+ 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x70, 0x75, 0x2d, 0x73, 0x79, 0x73, 0x2d, 0x6d, 0x73, 0x65,
+ 0x63, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63,
+ 0x70, 0x75, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x6d, 0x73, 0x65, 0x63, 0x22, 0x5d, 0x29, 0x2f,
+ 0x31, 0x30, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x63, 0x70, 0x75, 0x22,
+ 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x63, 0x70, 0x75, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78,
+ 0x65, 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x71, 0x70, 0x73, 0x3d,
+ 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65,
+ 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x71,
+ 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x71, 0x70,
+ 0x73, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x71, 0x70, 0x73, 0x2e, 0x74, 0x6f, 0x46,
+ 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x29, 0x2e, 0x74, 0x65,
+ 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d,
+ 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x5d, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20,
+ 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x70, 0x73, 0x3d, 0x31, 0x2e, 0x30, 0x2a, 0x64,
+ 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x2d, 0x72, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64,
+ 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x2d, 0x72, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20,
+ 0x74, 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3d, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61,
+ 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d,
+ 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68,
+ 0x65, 0x2d, 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d, 0x2b, 0x31, 0x2e, 0x30, 0x2a, 0x64, 0x61, 0x74,
0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x6d, 0x69, 0x73, 0x73, 0x65, 0x73, 0x22,
- 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x30,
- 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x28, 0x74, 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x20, 0x3e,
- 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74,
- 0x65, 0x3d, 0x31, 0x30, 0x30, 0x2e, 0x30, 0x2a, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63,
- 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a,
- 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68, 0x69, 0x74,
- 0x73, 0x22, 0x5d, 0x29, 0x2f, 0x74, 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x70, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65,
- 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x2e,
- 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x70, 0x68, 0x69, 0x74,
- 0x72, 0x61, 0x74, 0x65, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x30, 0x29, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x71, 0x70, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73,
- 0x2e, 0x61, 0x64, 0x64, 0x44, 0x61, 0x74, 0x61, 0x28, 0x7b, 0x20, 0x71, 0x70, 0x73, 0x3a, 0x20,
- 0x71, 0x70, 0x73, 0x2c, 0x20, 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x70, 0x73, 0x3a,
- 0x20, 0x73, 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x70, 0x73, 0x7d, 0x29, 0x3b, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x71,
- 0x70, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29,
- 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x63, 0x70, 0x75, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x69,
- 0x65, 0x73, 0x2e, 0x61, 0x64, 0x64, 0x44, 0x61, 0x74, 0x61, 0x28, 0x7b, 0x20, 0x6f, 0x6e, 0x65,
- 0x3a, 0x20, 0x63, 0x70, 0x75, 0x2c, 0x20, 0x74, 0x77, 0x6f, 0x3a, 0x20, 0x68, 0x69, 0x74, 0x72,
- 0x61, 0x74, 0x65, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x70, 0x75, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e,
- 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x64, 0x61, 0x74, 0x61,
- 0x3d, 0x64, 0x61, 0x74, 0x61, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
- 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x61, 0x6a, 0x61, 0x78, 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c,
- 0x3a, 0x20, 0x27, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x73, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79,
- 0x70, 0x65, 0x3a, 0x20, 0x27, 0x47, 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54,
- 0x79, 0x70, 0x65, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f,
- 0x6e, 0x70, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61,
- 0x74, 0x61, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x76,
- 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61,
- 0x74, 0x61, 0x5b, 0x22, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22,
- 0x5d, 0x2b, 0x22, 0x20, 0x22, 0x2b, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x76, 0x65, 0x72, 0x73,
- 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22,
- 0x23, 0x61, 0x63, 0x6c, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61,
- 0x5b, 0x22, 0x61, 0x63, 0x6c, 0x22, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
- 0x28, 0x22, 0x23, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28,
- 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x5d, 0x29, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27, 0x3c,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30,
- 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x72, 0x69, 0x67,
- 0x68, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68,
- 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x4e, 0x61, 0x6d, 0x65,
- 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c,
- 0x65, 0x66, 0x74, 0x3e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e,
- 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
- 0x74, 0x68, 0x3e, 0x55, 0x44, 0x50, 0x20, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x3c, 0x2f,
- 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x54, 0x43, 0x50, 0x20, 0x4c, 0x61, 0x74, 0x65, 0x6e,
- 0x63, 0x79, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x51, 0x75, 0x65, 0x72, 0x69,
- 0x65, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x44, 0x72, 0x6f, 0x70, 0x73,
- 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x51, 0x50, 0x53, 0x3c, 0x2f, 0x74, 0x68,
- 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4f, 0x75, 0x74, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68,
- 0x3e, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e,
- 0x4f, 0x72, 0x64, 0x65, 0x72, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c,
- 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x3c, 0x2f,
- 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63,
+ 0x68, 0x65, 0x2d, 0x6d, 0x69, 0x73, 0x73, 0x65, 0x73, 0x22, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72,
+ 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x74,
+ 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72,
- 0x76, 0x65, 0x72, 0x73, 0x22, 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x28, 0x61, 0x2c, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28,
- 0x22, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x72, 0x69, 0x67, 0x68, 0x74,
- 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d, 0x2b, 0x22,
- 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c,
- 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x2b,
- 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d,
- 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
- 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b,
- 0x62, 0x5b, 0x22, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64,
- 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61,
- 0x72, 0x20, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x62, 0x5b, 0x22,
- 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x75,
- 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x62, 0x5b, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79,
- 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x29, 0x20, 0x3f, 0x20, 0x22, 0x2d,
- 0x22, 0x20, 0x3a, 0x20, 0x62, 0x5b, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d,
- 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x30, 0x2e,
+ 0x30, 0x2a, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68,
+ 0x69, 0x74, 0x73, 0x22, 0x5d, 0x2d, 0x31, 0x2e, 0x30, 0x2a, 0x67, 0x64, 0x61, 0x74, 0x61, 0x5b,
+ 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x68, 0x69, 0x74, 0x73, 0x22, 0x5d, 0x29, 0x2f, 0x74,
+ 0x6f, 0x74, 0x70, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28,
+ 0x22, 0x23, 0x70, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78,
+ 0x74, 0x28, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65,
+ 0x64, 0x28, 0x32, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74,
- 0x65, 0x6e, 0x63, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x62, 0x5b, 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61,
- 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c,
- 0x20, 0x7c, 0x7c, 0x20, 0x62, 0x5b, 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63,
- 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x29, 0x20, 0x3f, 0x20, 0x22,
- 0x2d, 0x22, 0x20, 0x3a, 0x20, 0x62, 0x5b, 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e,
- 0x63, 0x79, 0x22, 0x5d, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x3b,
+ 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x70, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x22, 0x29,
+ 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x71, 0x70, 0x73, 0x67, 0x72,
+ 0x61, 0x70, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x61, 0x64, 0x64, 0x44, 0x61,
+ 0x74, 0x61, 0x28, 0x7b, 0x20, 0x71, 0x70, 0x73, 0x3a, 0x20, 0x71, 0x70, 0x73, 0x2c, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x66, 0x61, 0x69, 0x6c, 0x70, 0x73, 0x3a, 0x20, 0x73, 0x65, 0x72, 0x76, 0x66,
+ 0x61, 0x69, 0x6c, 0x70, 0x73, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x71, 0x70, 0x73, 0x67, 0x72, 0x61, 0x70,
+ 0x68, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x70, 0x75,
+ 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x61, 0x64, 0x64,
+ 0x44, 0x61, 0x74, 0x61, 0x28, 0x7b, 0x20, 0x6f, 0x6e, 0x65, 0x3a, 0x20, 0x63, 0x70, 0x75, 0x2c,
+ 0x20, 0x74, 0x77, 0x6f, 0x3a, 0x20, 0x68, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x7d, 0x29, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d,
- 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b,
- 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74,
- 0x64, 0x3e, 0x22, 0x2b, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2b, 0x22,
- 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x71, 0x75,
- 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74,
- 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x72, 0x65, 0x75, 0x73, 0x65, 0x64, 0x73, 0x22, 0x5d,
- 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x28, 0x62, 0x5b,
- 0x22, 0x71, 0x70, 0x73, 0x22, 0x5d, 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28,
- 0x32, 0x29, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62,
- 0x5b, 0x22, 0x6f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x2b,
- 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b,
- 0x20, 0x28, 0x22, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x77, 0x65, 0x69, 0x67,
- 0x68, 0x74, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22,
- 0x2b, 0x62, 0x5b, 0x22, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74,
- 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74,
- 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c,
- 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77,
- 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x64,
- 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d,
- 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74,
- 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68,
- 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e,
- 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x52, 0x75, 0x6c, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
- 0x74, 0x68, 0x3e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74,
- 0x68, 0x3e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f,
- 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x64, 0x61,
- 0x74, 0x61, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x5d, 0x2e, 0x6c, 0x65, 0x6e, 0x67,
- 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
- 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65,
- 0x73, 0x22, 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c,
- 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x63, 0x70, 0x75, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72,
+ 0x28, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x64, 0x61, 0x74, 0x61, 0x3d, 0x64, 0x61, 0x74, 0x61, 0x3b,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f,
+ 0x72, 0x3a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x7b,
+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e,
+ 0x61, 0x6a, 0x61, 0x78, 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x27, 0x61, 0x70, 0x69,
+ 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x27, 0x47,
+ 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x27,
+ 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x3a, 0x20, 0x66, 0x61,
+ 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x66,
+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20,
- 0x28, 0x22, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74,
- 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d, 0x2b, 0x22,
- 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c,
- 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x22, 0x5d, 0x2b,
- 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x61,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x22, 0x29,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x64, 0x61,
+ 0x65, 0x6d, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x20, 0x22, 0x2b,
+ 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x29,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
- 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c,
- 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22,
- 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x20, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20,
- 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20,
- 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x20, 0x63,
- 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66, 0x6f, 0x6e, 0x74,
- 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x22,
- 0x3e, 0x4e, 0x6f, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65,
- 0x64, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x61, 0x63, 0x6c, 0x22, 0x29,
+ 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x61, 0x63, 0x6c, 0x22,
+ 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x6c, 0x6f, 0x63,
+ 0x61, 0x6c, 0x22, 0x29, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76,
+ 0x61, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20,
+ 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72,
+ 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3e, 0x3c, 0x74, 0x68,
+ 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e,
+ 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
+ 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x41, 0x64,
+ 0x64, 0x72, 0x65, 0x73, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x55, 0x44, 0x50,
+ 0x20, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68,
+ 0x3e, 0x54, 0x43, 0x50, 0x20, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x3c, 0x2f, 0x74, 0x68,
+ 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3c, 0x2f, 0x74, 0x68,
+ 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x44, 0x72, 0x6f, 0x70, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
+ 0x74, 0x68, 0x3e, 0x51, 0x50, 0x53, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4f,
+ 0x75, 0x74, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x57, 0x65, 0x69, 0x67, 0x68,
+ 0x74, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x3c,
+ 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65,
+ 0x66, 0x74, 0x3e, 0x50, 0x6f, 0x6f, 0x6c, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74,
0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d,
- 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x72, 0x75, 0x6c,
- 0x65, 0x73, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b,
- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22,
- 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e,
- 0x3c, 0x74, 0x68, 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c,
- 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x20, 0x52, 0x75, 0x6c, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x41,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4d, 0x61,
- 0x74, 0x63, 0x68, 0x65, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27,
- 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22,
- 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x5d,
- 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68,
+ 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x22, 0x5d,
+ 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x62, 0x29, 0x20,
+ 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20,
+ 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x72, 0x20, 0x61,
+ 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22,
+ 0x2b, 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c,
+ 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b,
+ 0x62, 0x5b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
+ 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22,
+ 0x2b, 0x62, 0x5b, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c,
+ 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b,
- 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22,
- 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x62, 0x29,
- 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x61, 0x74, 0x65,
+ 0x6e, 0x63, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x62, 0x5b, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63,
+ 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20,
+ 0x62, 0x5b, 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d, 0x3d,
+ 0x20, 0x30, 0x2e, 0x30, 0x29, 0x20, 0x3f, 0x20, 0x22, 0x2d, 0x22, 0x20, 0x3a, 0x20, 0x62, 0x5b,
+ 0x22, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78,
+ 0x65, 0x64, 0x28, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22,
- 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c,
- 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f,
- 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66,
- 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c,
- 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x61, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x22, 0x29, 0x3b, 0x0a,
+ 0x76, 0x61, 0x72, 0x20, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x3d,
+ 0x20, 0x28, 0x62, 0x5b, 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22,
+ 0x5d, 0x20, 0x3d, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x62, 0x5b,
+ 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x3d,
+ 0x3d, 0x20, 0x30, 0x2e, 0x30, 0x29, 0x20, 0x3f, 0x20, 0x22, 0x2d, 0x22, 0x20, 0x3a, 0x20, 0x62,
+ 0x5b, 0x22, 0x74, 0x63, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5d, 0x2e, 0x74,
+ 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20,
+ 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63,
+ 0x79, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x74, 0x63,
+ 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c,
+ 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22,
+ 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b,
+ 0x22, 0x72, 0x65, 0x75, 0x73, 0x65, 0x64, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64,
+ 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x28, 0x62, 0x5b, 0x22, 0x71, 0x70, 0x73, 0x22, 0x5d,
+ 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x2b, 0x22, 0x3c, 0x2f,
+ 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6f, 0x75, 0x74, 0x73,
+ 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
+ 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75,
0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x64,
- 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0x5d, 0x2b,
- 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20,
+ 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x5d, 0x2b, 0x22,
+ 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6f, 0x72,
+ 0x64, 0x65, 0x72, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20,
+ 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22,
+ 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f,
+ 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x20,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75,
+ 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72,
+ 0x65, 0x61, 0x6d, 0x73, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77,
+ 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f,
+ 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
+ 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67,
+ 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68,
+ 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e,
+ 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69,
+ 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x52, 0x75, 0x6c, 0x65, 0x3c, 0x2f, 0x74, 0x68,
+ 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x74, 0x68, 0x3e,
+ 0x3c, 0x74, 0x68, 0x3e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e,
+ 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28,
+ 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x5d, 0x2e, 0x6c, 0x65,
+ 0x6e, 0x67, 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x72, 0x75,
+ 0x6c, 0x65, 0x73, 0x22, 0x5d, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
+ 0x61, 0x2c, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75,
- 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69,
- 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x20, 0x63, 0x6f, 0x6c, 0x73,
- 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x63, 0x6f,
- 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x22, 0x3e, 0x4e, 0x6f,
- 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20,
- 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f,
- 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20,
+ 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65,
+ 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d,
+ 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e,
+ 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22,
+ 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67,
+ 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65,
+ 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62,
+ 0x5b, 0x22, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64,
+ 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c,
- 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
- 0x28, 0x22, 0x23, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65,
- 0x73, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a,
+ 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20,
+ 0x28, 0x22, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68,
+ 0x65, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e,
+ 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b,
+ 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
+ 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77,
+ 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c,
+ 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72,
+ 0x22, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66,
+ 0x6f, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x22, 0x3e, 0x4e, 0x6f, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x64, 0x65, 0x66,
+ 0x69, 0x6e, 0x65, 0x64, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
+ 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75,
+ 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c, 0x2f, 0x74, 0x61,
+ 0x62, 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23,
+ 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75,
+ 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27,
+ 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30,
+ 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65,
+ 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x23, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68,
+ 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x4e, 0x61, 0x6d, 0x65,
+ 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c,
+ 0x65, 0x66, 0x74, 0x3e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x52, 0x75, 0x6c,
+ 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73,
+ 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x28, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x63, 0x6f,
- 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x29, 0x25, 0x35, 0x29, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72,
- 0x73, 0x28, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e,
- 0x61, 0x6a, 0x61, 0x78, 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f,
- 0x6e, 0x73, 0x74, 0x61, 0x74, 0x3f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x3d, 0x64, 0x79,
- 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79, 0x70,
- 0x65, 0x3a, 0x20, 0x27, 0x47, 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79,
- 0x70, 0x65, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f, 0x6e,
- 0x70, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65,
- 0x73, 0x73, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61, 0x74,
- 0x61, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x6f,
- 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
- 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67,
- 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x44, 0x79, 0x6e, 0x20, 0x62,
- 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x20, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x3c, 0x2f,
- 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x3c, 0x2f,
- 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x3c, 0x2f, 0x74,
- 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x65, 0x42, 0x50, 0x46, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
- 0x74, 0x68, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x52, 0x65,
- 0x61, 0x73, 0x6f, 0x6e, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b,
- 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x67, 0x6f, 0x74, 0x73,
- 0x6f, 0x6d, 0x65, 0x3d, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x69, 0x66, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x5d, 0x2e, 0x6c, 0x65, 0x6e, 0x67,
+ 0x74, 0x68, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
+ 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x5d, 0x2c, 0x20, 0x66, 0x75,
+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64, 0x61, 0x74, 0x61, 0x2c, 0x20, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20,
+ 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x72, 0x20, 0x61,
+ 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b,
+ 0x62, 0x5b, 0x22, 0x69, 0x64, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74,
+ 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b, 0x62,
+ 0x5b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c,
+ 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x22, 0x2b,
+ 0x62, 0x5b, 0x22, 0x72, 0x75, 0x6c, 0x65, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
+ 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x5b, 0x22, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+ 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x62, 0x6f, 0x75, 0x77, 0x2b,
- 0x28, 0x22, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x61, 0x2b, 0x22, 0x3c,
- 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x73, 0x65, 0x63, 0x6f,
- 0x6e, 0x64, 0x73, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b,
- 0x62, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c,
- 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x65, 0x62, 0x70, 0x66, 0x2b, 0x22, 0x3c, 0x2f, 0x74,
- 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
- 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a,
- 0x09, 0x09, 0x09, 0x20, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d, 0x74, 0x72, 0x75, 0x65,
- 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20,
+ 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x28, 0x22, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62,
+ 0x5b, 0x22, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0x5d, 0x2b, 0x22, 0x3c, 0x2f, 0x74,
+ 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x21, 0x67, 0x6f, 0x74, 0x73,
- 0x6f, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f,
- 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72,
- 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74,
- 0x65, 0x72, 0x22, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e,
- 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61,
- 0x61, 0x61, 0x61, 0x61, 0x22, 0x3e, 0x4e, 0x6f, 0x20, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
- 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x3c, 0x2f,
- 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27,
- 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x62, 0x6f, 0x75,
- 0x77, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x64, 0x79, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22,
- 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x7d, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e,
- 0x61, 0x6a, 0x61, 0x78, 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f,
- 0x6e, 0x73, 0x74, 0x61, 0x74, 0x3f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x3d, 0x65, 0x62,
- 0x70, 0x66, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79,
- 0x70, 0x65, 0x3a, 0x20, 0x27, 0x47, 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54,
- 0x79, 0x70, 0x65, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f,
- 0x6e, 0x70, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61,
- 0x74, 0x61, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62,
- 0x6f, 0x75, 0x77, 0x3d, 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74,
- 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69,
- 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4b, 0x65, 0x72, 0x6e,
- 0x65, 0x6c, 0x2d, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x64, 0x79, 0x6e, 0x20, 0x62, 0x6c, 0x6f,
- 0x63, 0x6b, 0x65, 0x64, 0x20, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x3c, 0x2f, 0x74, 0x68,
- 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x3c, 0x2f, 0x74, 0x68,
- 0x3e, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73,
+ 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20,
+ 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22,
+ 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d,
+ 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d,
+ 0x22, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x22, 0x3e, 0x4e, 0x6f, 0x20, 0x72, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69,
+ 0x6e, 0x65, 0x64, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c,
+ 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77,
+ 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x72,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2d, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x29, 0x2e,
+ 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29,
+ 0x3b, 0x0a, 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
+ 0x28, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b,
+ 0x2b, 0x29, 0x25, 0x35, 0x29, 0x0a, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x52, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x73, 0x28, 0x29, 0x3b,
+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x61, 0x6a, 0x61, 0x78,
+ 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x73, 0x74, 0x61,
+ 0x74, 0x3f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x3d, 0x64, 0x79, 0x6e, 0x62, 0x6c, 0x6f,
+ 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x27,
+ 0x47, 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20,
+ 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x3a, 0x20, 0x66,
+ 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a, 0x20,
+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x20, 0x7b,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x27,
+ 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x30,
+ 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65,
+ 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x44, 0x79, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+ 0x65, 0x64, 0x20, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
+ 0x74, 0x68, 0x3e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c,
+ 0x74, 0x68, 0x3e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74,
+ 0x68, 0x3e, 0x65, 0x42, 0x50, 0x46, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x20, 0x61,
+ 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c, 0x65, 0x66, 0x74, 0x3e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x09, 0x09, 0x20,
0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d,
0x66, 0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
@@ -25438,37 +25399,91 @@ static const unsigned char glocal_jsData[] = {
0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x61, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e,
0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2b,
0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x62, 0x6c,
- 0x6f, 0x63, 0x6b, 0x73, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e,
- 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x09, 0x20, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d,
- 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a,
- 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x21, 0x67, 0x6f, 0x74, 0x73, 0x6f,
- 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75,
- 0x77, 0x20, 0x3d, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e,
- 0x3c, 0x74, 0x64, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65,
- 0x72, 0x22, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c,
- 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61,
- 0x61, 0x61, 0x61, 0x22, 0x3e, 0x4e, 0x6f, 0x20, 0x65, 0x42, 0x50, 0x46, 0x20, 0x62, 0x6c, 0x6f,
+ 0x6f, 0x63, 0x6b, 0x73, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22,
+ 0x2b, 0x62, 0x2e, 0x65, 0x62, 0x70, 0x66, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74,
+ 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2b, 0x22, 0x3c, 0x2f,
+ 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x09, 0x20,
+ 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x09, 0x09, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x21, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x29,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d,
+ 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64,
+ 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x20,
+ 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66, 0x6f, 0x6e,
+ 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x22, 0x3e, 0x4e, 0x6f, 0x20, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x20, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x73, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74,
0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x62, 0x6f, 0x75, 0x77, 0x2b, 0x22, 0x3c,
0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
- 0x28, 0x22, 0x23, 0x65, 0x62, 0x70, 0x66, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x29, 0x2e, 0x68,
- 0x74, 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x7d, 0x29,
- 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x31, 0x22, 0x29,
- 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x69, 0x6e,
- 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x24,
- 0x28, 0x22, 0x23, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x32, 0x22, 0x29, 0x2e, 0x63, 0x6c, 0x69,
+ 0x28, 0x22, 0x23, 0x64, 0x79, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x29, 0x2e, 0x68, 0x74,
+ 0x6d, 0x6c, 0x28, 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x7d, 0x29, 0x3b,
+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x61, 0x6a, 0x61, 0x78,
+ 0x28, 0x7b, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x73, 0x74, 0x61,
+ 0x74, 0x3f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x3d, 0x65, 0x62, 0x70, 0x66, 0x62, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x27, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20,
+ 0x27, 0x47, 0x45, 0x54, 0x27, 0x2c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x3a,
+ 0x20, 0x27, 0x6a, 0x73, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x3a, 0x20,
+ 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a,
+ 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x20,
+ 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x3d,
+ 0x27, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31,
+ 0x30, 0x30, 0x25, 0x22, 0x3e, 0x3c, 0x74, 0x72, 0x20, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x6c,
+ 0x65, 0x66, 0x74, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x2d, 0x62,
+ 0x61, 0x73, 0x65, 0x64, 0x20, 0x64, 0x79, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64,
+ 0x20, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68,
+ 0x3e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74,
+ 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x3c, 0x2f, 0x74, 0x68,
+ 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x76, 0x61, 0x72, 0x20, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d, 0x66, 0x61, 0x6c, 0x73,
+ 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x65, 0x61, 0x63, 0x68, 0x28, 0x64,
+ 0x61, 0x74, 0x61, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c,
+ 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f,
+ 0x75, 0x77, 0x3d, 0x62, 0x6f, 0x75, 0x77, 0x2b, 0x28, 0x22, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74,
+ 0x64, 0x3e, 0x22, 0x2b, 0x61, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e,
+ 0x22, 0x2b, 0x62, 0x2e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2b, 0x22, 0x3c, 0x2f, 0x74,
+ 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x22, 0x2b, 0x62, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73,
+ 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x22, 0x29, 0x3b, 0x0a,
+ 0x09, 0x09, 0x09, 0x20, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x3d, 0x74, 0x72, 0x75, 0x65,
+ 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x09, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x21, 0x67, 0x6f, 0x74, 0x73, 0x6f, 0x6d, 0x65, 0x29, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x75, 0x77, 0x20, 0x3d, 0x20,
+ 0x62, 0x6f, 0x75, 0x77, 0x20, 0x2b, 0x20, 0x27, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x20,
+ 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x20, 0x63,
+ 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x3e, 0x3c, 0x66, 0x6f, 0x6e, 0x74,
+ 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x22,
+ 0x3e, 0x4e, 0x6f, 0x20, 0x65, 0x42, 0x50, 0x46, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x20,
+ 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x3c, 0x2f, 0x66, 0x6f, 0x6e, 0x74, 0x3e, 0x3c, 0x2f, 0x74,
+ 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x27, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x62, 0x6f, 0x75, 0x77, 0x3d, 0x62, 0x6f, 0x75, 0x77, 0x2b, 0x22, 0x3c, 0x2f, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x3e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x65,
+ 0x62, 0x70, 0x66, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28,
+ 0x62, 0x6f, 0x75, 0x77, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x7d, 0x29, 0x3b, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x24,
+ 0x28, 0x22, 0x23, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x31, 0x22, 0x29, 0x2e, 0x63, 0x6c, 0x69,
0x63, 0x6b, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66,
- 0x66, 0x65, 0x72, 0x73, 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x64, 0x61,
- 0x74, 0x65, 0x28, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x74,
- 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2c, 0x20, 0x31, 0x30,
- 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x29, 0x3b, 0x0a,
+ 0x66, 0x65, 0x72, 0x73, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x66,
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x32, 0x22, 0x29, 0x2e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x28, 0x75,
+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x73,
+ 0x29, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x29,
+ 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
+ 0x6c, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2c, 0x20, 0x31, 0x30, 0x30, 0x30, 0x29, 0x3b,
+ 0x0a, 0x7d, 0x29, 0x3b, 0x0a,
};
static const unsigned char gpowerdns_logo_220px_pngData[] = {
diff --git a/install-sh b/install-sh
index 8175c64..ec298b5 100755
--- a/install-sh
+++ b/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2018-03-11.20; # UTC
+scriptversion=2020-11-14.01; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -69,6 +69,11 @@ posix_mkdir=
# Desired mode of installed file.
mode=0755
+# Create dirs (including intermediate dirs) using mode 755.
+# This is like GNU 'install' as of coreutils 8.32 (2020).
+mkdir_umask=22
+
+backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
@@ -99,18 +104,28 @@ Options:
--version display version info and exit.
-c (ignored)
- -C install only if different (preserve the last data modification time)
+ -C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
+ -p pass -p to $cpprog.
-s $stripprog installed files.
+ -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+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/
"
while test $# -ne 0; do
@@ -137,8 +152,13 @@ while test $# -ne 0; do
-o) chowncmd="$chownprog $2"
shift;;
+ -p) cpprog="$cpprog -p";;
+
-s) stripcmd=$stripprog;;
+ -S) backupsuffix="$2"
+ shift;;
+
-t)
is_target_a_directory=always
dst_arg=$2
@@ -255,6 +275,10 @@ do
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
+ # Don't chown directories that already exist.
+ if test $dstdir_status = 0; then
+ chowncmd=""
+ fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@@ -301,22 +325,6 @@ do
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
@@ -326,52 +334,49 @@ do
fi
posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- # Note that $RANDOM variable is not portable (e.g. dash); Use it
- # here however when possible just to lower collision chance.
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-
- trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- # Because "mkdir -p" follows existing symlinks and we likely work
- # directly in world-writeable /tmp, make sure that the '$tmpdir'
- # directory is successfully created first before we actually test
- # 'mkdir -p' feature.
- if (umask $mkdir_umask &&
- $mkdirprog $mkdir_mode "$tmpdir" &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities 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.
- test_tmpdir="$tmpdir/a"
- ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
- fi
- trap '' 0;;
- esac;;
+ # The $RANDOM variable is not portable (e.g., dash). Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap '
+ ret=$?
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
+ exit $ret
+ ' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p'.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities 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.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
esac
if
@@ -382,7 +387,7 @@ do
then :
else
- # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
@@ -411,7 +416,7 @@ do
prefixes=
else
if $posix_mkdir; then
- (umask=$mkdir_umask &&
+ (umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
@@ -451,7 +456,18 @@ do
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
- (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+ (umask $cp_umask &&
+ { test -z "$stripcmd" || {
+ # Create $dsttmp read-write so that cp doesn't create it read-only,
+ # which would cause strip to fail.
+ if test -z "$doit"; then
+ : >"$dsttmp" # No need to fork-exec 'touch'.
+ else
+ $doit touch "$dsttmp"
+ fi
+ }
+ } &&
+ $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
@@ -477,6 +493,13 @@ do
then
rm -f "$dsttmp"
else
+ # If $backupsuffix is set, and the file being installed
+ # already exists, attempt a backup. Don't worry if it fails,
+ # e.g., if mv doesn't support -f.
+ if test -n "$backupsuffix" && test -f "$dst"; then
+ $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+ fi
+
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
@@ -491,9 +514,9 @@ do
# file should still install successfully.
{
test ! -f "$dst" ||
- $doit $rmcmd -f "$dst" 2>/dev/null ||
+ $doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
diff --git a/iputils.cc b/iputils.cc
index e0c7218..4409997 100644
--- a/iputils.cc
+++ b/iputils.cc
@@ -25,23 +25,24 @@
#include "iputils.hh"
+#include <fstream>
#include <sys/socket.h>
#include <boost/format.hpp>
-#if HAVE_GETIFADDRS
+#ifdef HAVE_GETIFADDRS
#include <ifaddrs.h>
#endif
/** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */
-static void RuntimeError(std::string&& error)
+static void RuntimeError(const std::string& error)
{
- throw runtime_error(std::move(error));
+ throw runtime_error(error);
}
-static void NetworkErr(std::string&& error)
+static void NetworkErr(const std::string& error)
{
- throw NetworkError(std::move(error));
+ throw NetworkError(error);
}
int SSocket(int family, int type, int flags)
@@ -147,7 +148,7 @@ int SSetsockopt(int sockfd, int level, int opname, int value)
return ret;
}
-void setSocketIgnorePMTU(int sockfd, int family)
+void setSocketIgnorePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
{
if (family == AF_INET) {
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
@@ -191,6 +192,27 @@ void setSocketIgnorePMTU(int sockfd, int family)
}
}
+void setSocketForcePMTU([[maybe_unused]] int sockfd, [[maybe_unused]] int family)
+{
+ if (family == AF_INET) {
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
+ /* IP_PMTUDISC_DO enables Path MTU discovery and prevents fragmentation */
+ SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO);
+#elif defined(IP_DONTFRAG)
+ /* at least this prevents fragmentation */
+ SSetsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, 1);
+#endif /* defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) */
+ }
+ else {
+#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
+ /* IPV6_PMTUDISC_DO enables Path MTU discovery and prevents fragmentation */
+ SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IPV6_PMTUDISC_DO);
+#elif defined(IPV6_DONTFRAG)
+ /* at least this prevents fragmentation */
+ SSetsockopt(sockfd, IPPROTO_IPV6, IPV6_DONTFRAG, 1);
+#endif /* defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) */
+ }
+}
bool setReusePort(int sockfd)
{
@@ -537,10 +559,44 @@ void setSocketSendBuffer(int fd, uint32_t size)
setSocketBuffer(fd, SO_SNDBUF, size);
}
+#ifdef __linux__
+static uint32_t raiseSocketBufferToMax(int socket, int optname, const std::string& readMaxFromFile)
+{
+ std::ifstream ifs(readMaxFromFile);
+ if (ifs) {
+ std::string line;
+ if (getline(ifs, line)) {
+ auto max = pdns::checked_stoi<uint32_t>(line);
+ setSocketBuffer(socket, optname, max);
+ return max;
+ }
+ }
+ return 0;
+}
+#endif
+
+uint32_t raiseSocketReceiveBufferToMax([[maybe_unused]] int socket)
+{
+#ifdef __linux__
+ return raiseSocketBufferToMax(socket, SO_RCVBUF, "/proc/sys/net/core/rmem_max");
+#else
+ return 0;
+#endif
+}
+
+uint32_t raiseSocketSendBufferToMax([[maybe_unused]] int socket)
+{
+#ifdef __linux__
+ return raiseSocketBufferToMax(socket, SO_SNDBUF, "/proc/sys/net/core/wmem_max");
+#else
+ return 0;
+#endif
+}
+
std::set<std::string> getListOfNetworkInterfaces()
{
std::set<std::string> result;
-#if HAVE_GETIFADDRS
+#ifdef HAVE_GETIFADDRS
struct ifaddrs *ifaddr;
if (getifaddrs(&ifaddr) == -1) {
return result;
@@ -558,11 +614,11 @@ std::set<std::string> getListOfNetworkInterfaces()
return result;
}
+#ifdef HAVE_GETIFADDRS
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf)
{
std::vector<ComboAddress> result;
-#if HAVE_GETIFADDRS
- struct ifaddrs *ifaddr;
+ struct ifaddrs *ifaddr = nullptr;
if (getifaddrs(&ifaddr) == -1) {
return result;
}
@@ -586,11 +642,17 @@ std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string
}
freeifaddrs(ifaddr);
-#endif
return result;
}
+#else
+std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& /* itf */)
+{
+ std::vector<ComboAddress> result;
+ return result;
+}
+#endif // HAVE_GETIFADDRS
-#if HAVE_GETIFADDRS
+#ifdef HAVE_GETIFADDRS
static uint8_t convertNetmaskToBits(const uint8_t* mask, socklen_t len)
{
if (mask == nullptr || len > 16) {
@@ -611,11 +673,11 @@ static uint8_t convertNetmaskToBits(const uint8_t* mask, socklen_t len)
}
#endif /* HAVE_GETIFADDRS */
+#ifdef HAVE_GETIFADDRS
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf)
{
std::vector<Netmask> result;
-#if HAVE_GETIFADDRS
- struct ifaddrs *ifaddr;
+ struct ifaddrs *ifaddr = nullptr;
if (getifaddrs(&ifaddr) == -1) {
return result;
}
@@ -648,6 +710,12 @@ std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf)
}
freeifaddrs(ifaddr);
-#endif
return result;
}
+#else
+std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& /* itf */)
+{
+ std::vector<Netmask> result;
+ return result;
+}
+#endif // HAVE_GETIFADDRS
diff --git a/iputils.hh b/iputils.hh
index dafc24a..e5943c8 100644
--- a/iputils.hh
+++ b/iputils.hh
@@ -123,6 +123,24 @@ union ComboAddress {
return rhs.operator<(*this);
}
+ struct addressPortOnlyHash
+ {
+ uint32_t operator()(const ComboAddress& ca) const
+ {
+ const unsigned char* start = nullptr;
+ if (ca.sin4.sin_family == AF_INET) {
+ start = reinterpret_cast<const unsigned char*>(&ca.sin4.sin_addr.s_addr);
+ auto tmp = burtle(start, 4, 0);
+ return burtle(reinterpret_cast<const uint8_t*>(&ca.sin4.sin_port), 2, tmp);
+ }
+ {
+ start = reinterpret_cast<const unsigned char*>(&ca.sin6.sin6_addr.s6_addr);
+ auto tmp = burtle(start, 16, 0);
+ return burtle(reinterpret_cast<const unsigned char*>(&ca.sin6.sin6_port), 2, tmp);
+ }
+ }
+ };
+
struct addressOnlyHash
{
uint32_t operator()(const ComboAddress& ca) const
@@ -212,8 +230,9 @@ union ComboAddress {
sin4.sin_port = 0;
if(makeIPv4sockaddr(str, &sin4)) {
sin6.sin6_family = AF_INET6;
- if(makeIPv6sockaddr(str, &sin6) < 0)
+ if(makeIPv6sockaddr(str, &sin6) < 0) {
throw PDNSException("Unable to convert presentation address '"+ str +"'");
+ }
}
if(!sin4.sin_port) // 'str' overrides port!
@@ -332,6 +351,11 @@ union ComboAddress {
return toStringWithPortExcept(53);
}
+ [[nodiscard]] string toStructuredLogString() const
+ {
+ return toStringWithPort();
+ }
+
string toByteString() const
{
if (isIPv4()) {
@@ -342,11 +366,14 @@ union ComboAddress {
void truncate(unsigned int bits) noexcept;
- uint16_t getPort() const
+ uint16_t getNetworkOrderPort() const noexcept
{
- return ntohs(sin4.sin_port);
+ return sin4.sin_port;
+ }
+ uint16_t getPort() const noexcept
+ {
+ return ntohs(getNetworkOrderPort());
}
-
void setPort(uint16_t port)
{
sin4.sin_port = htons(port);
@@ -483,22 +510,22 @@ public:
Netmask(const ComboAddress& network, uint8_t bits=0xff): d_network(network)
{
d_network.sin4.sin_port = 0;
- setBits(network.isIPv4() ? std::min(bits, static_cast<uint8_t>(32)) : std::min(bits, static_cast<uint8_t>(128)));
+ setBits(bits);
}
Netmask(const sockaddr_in* network, uint8_t bits = 0xff): d_network(network)
{
d_network.sin4.sin_port = 0;
- setBits(std::min(bits, static_cast<uint8_t>(32)));
+ setBits(bits);
}
Netmask(const sockaddr_in6* network, uint8_t bits = 0xff): d_network(network)
{
d_network.sin4.sin_port = 0;
- setBits(std::min(bits, static_cast<uint8_t>(128)));
+ setBits(bits);
}
void setBits(uint8_t value)
{
- d_bits = value;
+ d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
if (d_bits < 32) {
d_mask = ~(0xFFFFFFFF >> d_bits);
@@ -1182,13 +1209,13 @@ public:
}
//<! Returns "best match" for key_type, which might not be value
- const node_type* lookup(const key_type& value) const {
+ [[nodiscard]] node_type* lookup(const key_type& value) const {
uint8_t max_bits = value.getBits();
return lookupImpl(value, max_bits);
}
//<! Perform best match lookup for value, using at most max_bits
- const node_type* lookup(const ComboAddress& value, int max_bits = 128) const {
+ [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const {
uint8_t addr_bits = value.getBits();
if (max_bits < 0 || max_bits > addr_bits) {
max_bits = addr_bits;
@@ -1257,7 +1284,7 @@ public:
}
//<! checks whether the container is empty.
- bool empty() const {
+ [[nodiscard]] bool empty() const {
return (d_size == 0);
}
@@ -1283,7 +1310,8 @@ public:
}
//<! swaps the contents with another NetmaskTree
- void swap(NetmaskTree& rhs) {
+ void swap(NetmaskTree& rhs) noexcept
+ {
std::swap(d_root, rhs.d_root);
std::swap(d_left, rhs.d_left);
std::swap(d_size, rhs.d_size);
@@ -1291,7 +1319,7 @@ public:
private:
- const node_type* lookupImpl(const key_type& value, uint8_t max_bits) const {
+ [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const {
TreeNode *node = nullptr;
if (value.isIPv4())
@@ -1353,8 +1381,7 @@ private:
class NetmaskGroup
{
public:
- NetmaskGroup() noexcept {
- }
+ NetmaskGroup() noexcept = default;
//! If this IP address is matched by any of the classes within
@@ -1457,11 +1484,14 @@ public:
return str.str();
}
- void toStringVector(vector<string>* vec) const
+ std::vector<std::string> toStringVector() const
{
- for(auto iter = tree.begin(); iter != tree.end(); ++iter) {
- vec->push_back((iter->second ? "" : "!") + iter->first.toString());
+ std::vector<std::string> out;
+ out.reserve(tree.size());
+ for (const auto& entry : tree) {
+ out.push_back((entry.second ? "" : "!") + entry.first.toString());
}
+ return out;
}
void toMasks(const string &ips)
@@ -1509,7 +1539,8 @@ public:
d_addr.sin4.sin_port = 0; // this guarantees d_network compares identical
}
- AddressAndPortRange(ComboAddress ca, uint8_t addrMask, uint8_t portMask = 0): d_addr(std::move(ca)), d_addrMask(addrMask), d_portMask(portMask)
+ AddressAndPortRange(ComboAddress ca, uint8_t addrMask, uint8_t portMask = 0) :
+ d_addr(ca), d_addrMask(addrMask), d_portMask(portMask)
{
if (!d_addr.isIPv4()) {
d_portMask = 0;
@@ -1691,6 +1722,7 @@ int SAccept(int sockfd, ComboAddress& remote);
int SListen(int sockfd, int limit);
int SSetsockopt(int sockfd, int level, int opname, int value);
void setSocketIgnorePMTU(int sockfd, int family);
+void setSocketForcePMTU(int sockfd, int family);
bool setReusePort(int sockfd);
#if defined(IP_PKTINFO)
@@ -1721,3 +1753,5 @@ std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
void setSocketBuffer(int fd, int optname, uint32_t size);
void setSocketReceiveBuffer(int fd, uint32_t size);
void setSocketSendBuffer(int fd, uint32_t size);
+uint32_t raiseSocketReceiveBufferToMax(int socket);
+uint32_t raiseSocketSendBufferToMax(int socket);
diff --git a/libssl.cc b/libssl.cc
index ab7b77e..f9e87aa 100644
--- a/libssl.cc
+++ b/libssl.cc
@@ -32,6 +32,8 @@
#include <openssl/core.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
+#else
+#include <openssl/hmac.h>
#endif
#ifdef HAVE_LIBSODIUM
@@ -200,7 +202,7 @@ std::pair<bool, std::string> libssl_load_provider(const std::string& providerNam
#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
-std::pair<bool, std::string> libssl_load_engine(const std::string& engineName, const std::optional<std::string>& defaultString)
+std::pair<bool, std::string> libssl_load_engine([[maybe_unused]] const std::string& engineName, [[maybe_unused]] const std::optional<std::string>& defaultString)
{
#ifdef OPENSSL_NO_ENGINE
return { false, "OpenSSL has been built without engine support" };
@@ -254,9 +256,9 @@ void libssl_set_ticket_key_callback_data(SSL_CTX* ctx, void* data)
}
#if OPENSSL_VERSION_MAJOR >= 3
-int libssl_ticket_key_callback(SSL* s, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx, int enc)
+int libssl_ticket_key_callback(SSL* /* s */, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx, int enc)
#else
-int libssl_ticket_key_callback(SSL* s, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx, int enc)
+int libssl_ticket_key_callback(SSL* /* s */, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx, int enc)
#endif
{
if (enc != 0) {
@@ -288,19 +290,16 @@ int libssl_ticket_key_callback(SSL* s, OpenSSLTLSTicketKeysRing& keyring, unsign
return 1;
}
-static long libssl_server_name_callback(SSL* ssl, int* al, void* arg)
+static int libssl_server_name_callback(SSL* ssl, int* /* alert */, void* /* arg */)
{
- (void) al;
- (void) arg;
-
- if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) {
+ if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != nullptr) {
return SSL_TLSEXT_ERR_OK;
}
return SSL_TLSEXT_ERR_NOACK;
}
-static void libssl_info_callback(const SSL *ssl, int where, int ret)
+static void libssl_info_callback(const SSL *ssl, int where, int /* ret */)
{
SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl);
if (sslCtx == nullptr) {
@@ -472,23 +471,23 @@ bool libssl_generate_ocsp_response(const std::string& certFile, const std::strin
{
const EVP_MD* rmd = EVP_sha256();
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(certFile.c_str(), "r"), fclose);
- if (!fp) {
+ auto filePtr = pdns::UniqueFilePtr(fopen(certFile.c_str(), "r"));
+ if (!filePtr) {
throw std::runtime_error("Unable to open '" + certFile + "' when loading the certificate to generate an OCSP response");
}
- auto cert = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(fp.get(), nullptr, nullptr, nullptr), X509_free);
+ auto cert = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(filePtr.get(), nullptr, nullptr, nullptr), X509_free);
- fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(caCert.c_str(), "r"), fclose);
- if (!fp) {
+ filePtr = pdns::UniqueFilePtr(fopen(caCert.c_str(), "r"));
+ if (!filePtr) {
throw std::runtime_error("Unable to open '" + caCert + "' when loading the issuer certificate to generate an OCSP response");
}
- auto issuer = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(fp.get(), nullptr, nullptr, nullptr), X509_free);
- fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(caKey.c_str(), "r"), fclose);
- if (!fp) {
+ auto issuer = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(filePtr.get(), nullptr, nullptr, nullptr), X509_free);
+ filePtr = pdns::UniqueFilePtr(fopen(caKey.c_str(), "r"));
+ if (!filePtr) {
throw std::runtime_error("Unable to open '" + caKey + "' when loading the issuer key to generate an OCSP response");
}
- auto issuerKey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(PEM_read_PrivateKey(fp.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
- fp.reset();
+ auto issuerKey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(PEM_read_PrivateKey(filePtr.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
+ filePtr.reset();
auto bs = std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)>(OCSP_BASICRESP_new(), OCSP_BASICRESP_free);
auto thisupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_gmtime_adj(nullptr, 0), ASN1_TIME_free);
@@ -627,13 +626,11 @@ OpenSSLTLSTicketKeysRing::OpenSSLTLSTicketKeysRing(size_t capacity)
d_ticketKeys.write_lock()->set_capacity(capacity);
}
-OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing()
-{
-}
+OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() = default;
-void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey> newKey)
+void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
{
- d_ticketKeys.write_lock()->push_front(newKey);
+ d_ticketKeys.write_lock()->push_front(std::move(newKey));
}
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
@@ -665,7 +662,7 @@ void OpenSSLTLSTicketKeysRing::loadTicketsKeys(const std::string& keyFile)
try {
do {
auto newKey = std::make_shared<OpenSSLTLSTicketKey>(file);
- addKey(newKey);
+ addKey(std::move(newKey));
keyLoaded = true;
}
while (!file.fail());
@@ -680,10 +677,10 @@ void OpenSSLTLSTicketKeysRing::loadTicketsKeys(const std::string& keyFile)
file.close();
}
-void OpenSSLTLSTicketKeysRing::rotateTicketsKey(time_t now)
+void OpenSSLTLSTicketKeysRing::rotateTicketsKey(time_t /* now */)
{
auto newKey = std::make_shared<OpenSSLTLSTicketKey>();
- addKey(newKey);
+ addKey(std::move(newKey));
}
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey()
@@ -940,13 +937,13 @@ std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::st
/* load certificate and private key */
for (const auto& pair : config.d_certKeyPairs) {
if (!pair.d_key) {
-#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY) && HAVE_SSL_CTX_USE_CERT_AND_KEY == 1
+#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY)
// If no separate key is given, treat it as a pkcs12 file
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(pair.d_cert.c_str(), "r"), fclose);
- if (!fp) {
+ 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<PKCS12, void(*)(PKCS12*)>(d2i_PKCS12_fp(fp.get(), nullptr), PKCS12_free);
+ auto p12 = std::unique_ptr<PKCS12, void(*)(PKCS12*)>(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free);
if (!p12) {
throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert);
}
@@ -1014,7 +1011,7 @@ std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::st
#ifndef DISABLE_OCSP_STAPLING
if (!config.d_ocspFiles.empty()) {
try {
- ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, keyTypes, warnings);
+ 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()));
@@ -1032,7 +1029,7 @@ std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::st
}
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
- return std::make_pair(std::move(ctx), std::move(warnings));
+ return {std::move(ctx), std::move(warnings)};
}
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
@@ -1043,36 +1040,30 @@ static void libssl_key_log_file_callback(const SSL* ssl, const char* line)
return;
}
- auto fp = reinterpret_cast<FILE*>(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex));
- if (fp == nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
+ auto* filePtr = reinterpret_cast<FILE*>(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex));
+ if (filePtr == nullptr) {
return;
}
- fprintf(fp, "%s\n", line);
- fflush(fp);
+ fprintf(filePtr, "%s\n", line);
+ fflush(filePtr);
}
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
-std::unique_ptr<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile)
+pdns::UniqueFilePtr libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile)
{
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
- int fd = open(logFile.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0600);
- if (fd == -1) {
- unixDie("Error opening TLS log file '" + logFile + "'");
+ auto filePtr = pdns::openFileForWriting(logFile, 0600, false, true);
+ if (!filePtr) {
+ auto error = errno;
+ throw std::runtime_error("Error opening file " + logFile + " for writing: " + stringerror(error));
}
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(fd, "a"), fclose);
- if (!fp) {
- int error = errno; // close might clobber errno
- close(fd);
- throw std::runtime_error("Error opening TLS log file '" + logFile + "': " + stringerror(error));
- }
-
- SSL_CTX_set_ex_data(ctx.get(), s_keyLogIndex, fp.get());
+ SSL_CTX_set_ex_data(ctx.get(), s_keyLogIndex, filePtr.get());
SSL_CTX_set_keylog_callback(ctx.get(), &libssl_key_log_file_callback);
-
- return fp;
+ return filePtr;
#else
- return std::unique_ptr<FILE, int(*)(FILE*)>(nullptr, fclose);
+ return {};
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
}
diff --git a/libssl.hh b/libssl.hh
index fd5d90c..8dd7ff3 100644
--- a/libssl.hh
+++ b/libssl.hh
@@ -12,6 +12,7 @@
#include "config.h"
#include "circular_buffer.hh"
#include "lock.hh"
+#include "misc.hh"
enum class LibsslTLSVersion : uint8_t { Unknown, TLS10, TLS11, TLS12, TLS13 };
@@ -21,7 +22,7 @@ struct TLSCertKeyPair
std::optional<std::string> d_key;
std::optional<std::string> d_password;
explicit TLSCertKeyPair(const std::string& cert, std::optional<std::string> key = std::nullopt, std::optional<std::string> password = std::nullopt):
- d_cert(cert), d_key(key), d_password(password) {
+ d_cert(cert), d_key(std::move(key)), d_password(std::move(password)) {
}
};
@@ -53,6 +54,8 @@ public:
bool d_asyncMode{false};
/* enable kTLS mode, if supported */
bool d_ktls{false};
+ /* set read ahead mode, if supported */
+ bool d_readAhead{true};
};
struct TLSErrorCounters
@@ -113,7 +116,6 @@ class OpenSSLTLSTicketKeysRing
public:
OpenSSLTLSTicketKeysRing(size_t capacity);
~OpenSSLTLSTicketKeysRing();
- void addKey(std::shared_ptr<OpenSSLTLSTicketKey> newKey);
std::shared_ptr<OpenSSLTLSTicketKey> getEncryptionKey();
std::shared_ptr<OpenSSLTLSTicketKey> getDecryptionKey(unsigned char name[TLS_TICKETS_KEY_NAME_SIZE], bool& activeKey);
size_t getKeysCount();
@@ -121,6 +123,8 @@ public:
void rotateTicketsKey(time_t now);
private:
+ void addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey);
+
SharedLockGuarded<boost::circular_buffer<std::shared_ptr<OpenSSLTLSTicketKey> > > d_ticketKeys;
};
@@ -151,7 +155,7 @@ bool libssl_set_min_tls_version(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)
std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::string>> libssl_init_server_context(const TLSConfig& config,
std::map<int, std::string>& ocspResponses);
-std::unique_ptr<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile);
+pdns::UniqueFilePtr libssl_set_key_log_file(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, const std::string& logFile);
/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
#ifndef DISABLE_NPN
diff --git a/lock.hh b/lock.hh
index d17a924..611d8ad 100644
--- a/lock.hh
+++ b/lock.hh
@@ -81,9 +81,7 @@
class ReadWriteLock
{
public:
- ReadWriteLock()
- {
- }
+ ReadWriteLock() = default;
ReadWriteLock(const ReadWriteLock& rhs) = delete;
ReadWriteLock(ReadWriteLock&& rhs) = delete;
@@ -111,7 +109,8 @@ public:
ReadLock(const ReadLock& rhs) = delete;
ReadLock& operator=(const ReadLock& rhs) = delete;
- ReadLock(ReadLock&& rhs) : d_lock(std::move(rhs.d_lock))
+ ReadLock(ReadLock&& rhs) noexcept :
+ d_lock(std::move(rhs.d_lock))
{
}
@@ -136,7 +135,8 @@ public:
WriteLock(const WriteLock& rhs) = delete;
WriteLock& operator=(const WriteLock& rhs) = delete;
- WriteLock(WriteLock&& rhs) : d_lock(std::move(rhs.d_lock))
+ WriteLock(WriteLock&& rhs) noexcept :
+ d_lock(std::move(rhs.d_lock))
{
}
@@ -275,9 +275,7 @@ public:
{
}
- explicit LockGuarded()
- {
- }
+ explicit LockGuarded() = default;
LockGuardedTryHolder<T> try_lock()
{
@@ -423,9 +421,7 @@ public:
{
}
- explicit SharedLockGuarded()
- {
- }
+ explicit SharedLockGuarded() = default;
SharedLockGuardedTryHolder<T> try_write_lock()
{
diff --git a/logging.hh b/logging.hh
index 0ddf6be..c08a8e6 100644
--- a/logging.hh
+++ b/logging.hh
@@ -69,7 +69,7 @@ struct is_to_string_available<T, std::void_t<decltype(std::to_string(std::declva
{
};
-// Same mechanism for t.toLogString()
+// Same mechanism for t.toLogString() and t.toStructuredLogString()
template <typename T, typename = void>
struct is_toLogString_available : std::false_type
{
@@ -81,6 +81,16 @@ struct is_toLogString_available<T, std::void_t<decltype(std::declval<T>().toLogS
};
template <typename T, typename = void>
+struct is_toStructuredLogString_available : std::false_type
+{
+};
+
+template <typename T>
+struct is_toStructuredLogString_available<T, std::void_t<decltype(std::declval<T>().toStructuredLogString())>> : std::true_type
+{
+};
+
+template <typename T, typename = void>
struct is_toString_available : std::false_type
{
};
@@ -103,6 +113,9 @@ struct Loggable : public Logr::Loggable
if constexpr (std::is_same_v<T, std::string>) {
return _t;
}
+ else if constexpr (is_toStructuredLogString_available<T>::value) {
+ return _t.toStructuredLogString();
+ }
else if constexpr (is_toLogString_available<T>::value) {
return _t.toLogString();
}
@@ -202,6 +215,7 @@ extern bool g_slogStructured;
// SLOG(g_log<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl,
// startupLog->error("No such file", "Unable to parse configuration file", "config_file", Logging::Loggable(configname));
//
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SLOG(oldStyle, slogCall) \
do { \
if (g_slogStructured) { \
@@ -210,11 +224,12 @@ extern bool g_slogStructured;
else { \
oldStyle; \
} \
- } while (0);
+ } while (0)
#else // No structured logging (e.g. auth)
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define SLOG(oldStyle, slogCall) \
do { \
oldStyle; \
- } while (0);
+ } while (0)
#endif // RECURSOR
diff --git a/ltmain.sh b/ltmain.sh
index bb9035a..7b74079 100644
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -1,12 +1,12 @@
-#! /bin/sh
+#! /usr/bin/env sh
## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
-## by inline-source v2014-01-03.01
+## by inline-source v2019-02-19.15
-# libtool (GNU libtool) 2.4.6
+# libtool (GNU libtool) 2.4.7
# Provide generalized library-building support services.
# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# Copyright (C) 1996-2019, 2021-2022 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.
@@ -31,8 +31,8 @@
PROGRAM=libtool
PACKAGE=libtool
-VERSION=2.4.6
-package_revision=2.4.6
+VERSION=2.4.7
+package_revision=2.4.7
## ------ ##
@@ -64,34 +64,25 @@ package_revision=2.4.6
# libraries, which are installed to $pkgauxdir.
# Set a version string for this script.
-scriptversion=2015-01-20.17; # UTC
+scriptversion=2019-02-19.15; # UTC
# General shell script boiler plate, and helper functions.
# Written by Gary V. Vaughan, 2004
-# Copyright (C) 2004-2015 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.
-
-# 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
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-
-# As a special exception to the GNU General Public License, if you distribute
-# this file as part of a program or library that is built using GNU Libtool,
-# you may include this file under the same distribution terms that you use
-# for the rest of that program.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNES 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, see <http://www.gnu.org/licenses/>.
+# This is free software. There is NO warranty; not even for
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (C) 2004-2019, 2021 Bootstrap Authors
+#
+# This file is dual licensed under the terms of the MIT license
+# <https://opensource.org/license/MIT>, and GPL version 2 or later
+# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
+# these licenses when using or redistributing this software or any of
+# the files within it. See the URLs above, or the file `LICENSE`
+# included in the Bootstrap distribution for the full license texts.
-# Please report bugs or propose patches to gary@gnu.org.
+# Please report bugs or propose patches to:
+# <https://github.com/gnulib-modules/bootstrap/issues>
## ------ ##
@@ -139,9 +130,12 @@ do
_G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
fi"
done
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+# These NLS vars are set unconditionally (bootstrap issue #24). Unset those
+# in case the environment reset is needed later and the $save_* variant is not
+# defined (see the code above).
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
# Make sure IFS has a sensible default
sp=' '
@@ -159,6 +153,26 @@ if test "${PATH_SEPARATOR+set}" != set; then
fi
+# func_unset VAR
+# --------------
+# Portably unset VAR.
+# In some shells, an 'unset VAR' statement leaves a non-zero return
+# status if VAR is already unset, which might be problematic if the
+# statement is used at the end of a function (thus poisoning its return
+# value) or when 'set -e' is active (causing even a spurious abort of
+# the script in this case).
+func_unset ()
+{
+ { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; }
+}
+
+
+# Make sure CDPATH doesn't cause `cd` commands to output the target dir.
+func_unset CDPATH
+
+# Make sure ${,E,F}GREP behave sanely.
+func_unset GREP_OPTIONS
+
## ------------------------- ##
## Locate command utilities. ##
@@ -259,7 +273,7 @@ test -z "$SED" && {
rm -f conftest.in conftest.tmp conftest.nl conftest.out
}
- func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+ func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin"
rm -f conftest.sed
SED=$func_path_progs_result
}
@@ -295,7 +309,7 @@ test -z "$GREP" && {
rm -f conftest.in conftest.tmp conftest.nl conftest.out
}
- func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+ func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin"
GREP=$func_path_progs_result
}
@@ -360,6 +374,35 @@ sed_double_backslash="\
s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
s/\n//g"
+# require_check_ifs_backslash
+# ---------------------------
+# Check if we can use backslash as IFS='\' separator, and set
+# $check_ifs_backshlash_broken to ':' or 'false'.
+require_check_ifs_backslash=func_require_check_ifs_backslash
+func_require_check_ifs_backslash ()
+{
+ _G_save_IFS=$IFS
+ IFS='\'
+ _G_check_ifs_backshlash='a\\b'
+ for _G_i in $_G_check_ifs_backshlash
+ do
+ case $_G_i in
+ a)
+ check_ifs_backshlash_broken=false
+ ;;
+ '')
+ break
+ ;;
+ *)
+ check_ifs_backshlash_broken=:
+ break
+ ;;
+ esac
+ done
+ IFS=$_G_save_IFS
+ require_check_ifs_backslash=:
+}
+
## ----------------- ##
## Global variables. ##
@@ -580,16 +623,16 @@ if test yes = "$_G_HAVE_PLUSEQ_OP"; then
{
$debug_cmd
- func_quote_for_eval "$2"
- eval "$1+=\\ \$func_quote_for_eval_result"
+ func_quote_arg pretty "$2"
+ eval "$1+=\\ \$func_quote_arg_result"
}'
else
func_append_quoted ()
{
$debug_cmd
- func_quote_for_eval "$2"
- eval "$1=\$$1\\ \$func_quote_for_eval_result"
+ func_quote_arg pretty "$2"
+ eval "$1=\$$1\\ \$func_quote_arg_result"
}
fi
@@ -1091,85 +1134,203 @@ func_relative_path ()
}
-# func_quote_for_eval ARG...
-# --------------------------
-# Aesthetically quote ARGs to be evaled later.
-# This function returns two values:
-# i) func_quote_for_eval_result
-# double-quoted, suitable for a subsequent eval
-# ii) func_quote_for_eval_unquoted_result
-# has all characters that are still active within double
-# quotes backslashified.
-func_quote_for_eval ()
+# func_quote_portable EVAL ARG
+# ----------------------------
+# Internal function to portably implement func_quote_arg. Note that we still
+# keep attention to performance here so we as much as possible try to avoid
+# calling sed binary (so far O(N) complexity as long as func_append is O(1)).
+func_quote_portable ()
{
$debug_cmd
- func_quote_for_eval_unquoted_result=
- func_quote_for_eval_result=
- while test 0 -lt $#; do
- case $1 in
- *[\\\`\"\$]*)
- _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
- *)
- _G_unquoted_arg=$1 ;;
- esac
- if test -n "$func_quote_for_eval_unquoted_result"; then
- func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
- else
- func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+ $require_check_ifs_backslash
+
+ func_quote_portable_result=$2
+
+ # one-time-loop (easy break)
+ while true
+ do
+ if $1; then
+ func_quote_portable_result=`$ECHO "$2" | $SED \
+ -e "$sed_double_quote_subst" -e "$sed_double_backslash"`
+ break
fi
- case $_G_unquoted_arg in
- # Double-quote args containing shell metacharacters to delay
- # word splitting, command substitution and variable expansion
- # for a subsequent eval.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- _G_quoted_arg=\"$_G_unquoted_arg\"
+ # Quote for eval.
+ case $func_quote_portable_result in
+ *[\\\`\"\$]*)
+ # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string
+ # contains the shell wildcard characters.
+ case $check_ifs_backshlash_broken$func_quote_portable_result in
+ :*|*[\[\*\?]*)
+ func_quote_portable_result=`$ECHO "$func_quote_portable_result" \
+ | $SED "$sed_quote_subst"`
+ break
+ ;;
+ esac
+
+ func_quote_portable_old_IFS=$IFS
+ for _G_char in '\' '`' '"' '$'
+ do
+ # STATE($1) PREV($2) SEPARATOR($3)
+ set start "" ""
+ func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy
+ IFS=$_G_char
+ for _G_part in $func_quote_portable_result
+ do
+ case $1 in
+ quote)
+ func_append func_quote_portable_result "$3$2"
+ set quote "$_G_part" "\\$_G_char"
+ ;;
+ start)
+ set first "" ""
+ func_quote_portable_result=
+ ;;
+ first)
+ set quote "$_G_part" ""
+ ;;
+ esac
+ done
+ done
+ IFS=$func_quote_portable_old_IFS
;;
- *)
- _G_quoted_arg=$_G_unquoted_arg
- ;;
+ *) ;;
esac
-
- if test -n "$func_quote_for_eval_result"; then
- func_append func_quote_for_eval_result " $_G_quoted_arg"
- else
- func_append func_quote_for_eval_result "$_G_quoted_arg"
- fi
- shift
+ break
done
+
+ func_quote_portable_unquoted_result=$func_quote_portable_result
+ case $func_quote_portable_result in
+ # double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and variable expansion
+ # for a subsequent eval.
+ # many bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_portable_result=\"$func_quote_portable_result\"
+ ;;
+ esac
}
-# func_quote_for_expand ARG
-# -------------------------
-# Aesthetically quote ARG to be evaled later; same as above,
-# but do not quote variable references.
-func_quote_for_expand ()
-{
- $debug_cmd
+# func_quotefast_eval ARG
+# -----------------------
+# Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG',
+# but optimized for speed. Result is stored in $func_quotefast_eval.
+if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then
+ printf -v _GL_test_printf_tilde %q '~'
+ if test '\~' = "$_GL_test_printf_tilde"; then
+ func_quotefast_eval ()
+ {
+ printf -v func_quotefast_eval_result %q "$1"
+ }
+ else
+ # Broken older Bash implementations. Make those faster too if possible.
+ func_quotefast_eval ()
+ {
+ case $1 in
+ '~'*)
+ func_quote_portable false "$1"
+ func_quotefast_eval_result=$func_quote_portable_result
+ ;;
+ *)
+ printf -v func_quotefast_eval_result %q "$1"
+ ;;
+ esac
+ }
+ fi
+else
+ func_quotefast_eval ()
+ {
+ func_quote_portable false "$1"
+ func_quotefast_eval_result=$func_quote_portable_result
+ }
+fi
- case $1 in
- *[\\\`\"]*)
- _G_arg=`$ECHO "$1" | $SED \
- -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
- *)
- _G_arg=$1 ;;
+
+# func_quote_arg MODEs ARG
+# ------------------------
+# Quote one ARG to be evaled later. MODEs argument may contain zero or more
+# specifiers listed below separated by ',' character. This function returns two
+# values:
+# i) func_quote_arg_result
+# double-quoted (when needed), suitable for a subsequent eval
+# ii) func_quote_arg_unquoted_result
+# has all characters that are still active within double
+# quotes backslashified. Available only if 'unquoted' is specified.
+#
+# Available modes:
+# ----------------
+# 'eval' (default)
+# - escape shell special characters
+# 'expand'
+# - the same as 'eval'; but do not quote variable references
+# 'pretty'
+# - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might
+# be used later in func_quote to get output like: 'echo "a b"' instead
+# of 'echo a\ b'. This is slower than default on some shells.
+# 'unquoted'
+# - produce also $func_quote_arg_unquoted_result which does not contain
+# wrapping double-quotes.
+#
+# Examples for 'func_quote_arg pretty,unquoted string':
+#
+# string | *_result | *_unquoted_result
+# ------------+-----------------------+-------------------
+# " | \" | \"
+# a b | "a b" | a b
+# "a b" | "\"a b\"" | \"a b\"
+# * | "*" | *
+# z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\"
+#
+# Examples for 'func_quote_arg pretty,unquoted,expand string':
+#
+# string | *_result | *_unquoted_result
+# --------------+---------------------+--------------------
+# z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\"
+func_quote_arg ()
+{
+ _G_quote_expand=false
+ case ,$1, in
+ *,expand,*)
+ _G_quote_expand=:
+ ;;
esac
- case $_G_arg in
- # Double-quote args containing shell metacharacters to delay
- # word splitting and command substitution for a subsequent eval.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- _G_arg=\"$_G_arg\"
+ case ,$1, in
+ *,pretty,*|*,expand,*|*,unquoted,*)
+ func_quote_portable $_G_quote_expand "$2"
+ func_quote_arg_result=$func_quote_portable_result
+ func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result
+ ;;
+ *)
+ # Faster quote-for-eval for some shells.
+ func_quotefast_eval "$2"
+ func_quote_arg_result=$func_quotefast_eval_result
;;
esac
+}
+
- func_quote_for_expand_result=$_G_arg
+# func_quote MODEs ARGs...
+# ------------------------
+# Quote all ARGs to be evaled later and join them into single command. See
+# func_quote_arg's description for more info.
+func_quote ()
+{
+ $debug_cmd
+ _G_func_quote_mode=$1 ; shift
+ func_quote_result=
+ while test 0 -lt $#; do
+ func_quote_arg "$_G_func_quote_mode" "$1"
+ if test -n "$func_quote_result"; then
+ func_append func_quote_result " $func_quote_arg_result"
+ else
+ func_append func_quote_result "$func_quote_arg_result"
+ fi
+ shift
+ done
}
@@ -1215,8 +1376,8 @@ func_show_eval ()
_G_cmd=$1
_G_fail_exp=${2-':'}
- func_quote_for_expand "$_G_cmd"
- eval "func_notquiet $func_quote_for_expand_result"
+ func_quote_arg pretty,expand "$_G_cmd"
+ eval "func_notquiet $func_quote_arg_result"
$opt_dry_run || {
eval "$_G_cmd"
@@ -1241,8 +1402,8 @@ func_show_eval_locale ()
_G_fail_exp=${2-':'}
$opt_quiet || {
- func_quote_for_expand "$_G_cmd"
- eval "func_echo $func_quote_for_expand_result"
+ func_quote_arg expand,pretty "$_G_cmd"
+ eval "func_echo $func_quote_arg_result"
}
$opt_dry_run || {
@@ -1369,30 +1530,26 @@ func_lt_ver ()
# End:
#! /bin/sh
-# Set a version string for this script.
-scriptversion=2014-01-07.03; # UTC
-
# A portable, pluggable option parser for Bourne shell.
# Written by Gary V. Vaughan, 2010
-# Copyright (C) 2010-2015 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.
-
-# 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
-# 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 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.
+# This is free software. There is NO warranty; not even for
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (C) 2010-2019, 2021 Bootstrap Authors
+#
+# This file is dual licensed under the terms of the MIT license
+# <https://opensource.org/license/MIT>, and GPL version 2 or later
+# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of
+# these licenses when using or redistributing this software or any of
+# the files within it. See the URLs above, or the file `LICENSE`
+# included in the Bootstrap distribution for the full license texts.
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# Please report bugs or propose patches to:
+# <https://github.com/gnulib-modules/bootstrap/issues>
-# Please report bugs or propose patches to gary@gnu.org.
+# Set a version string for this script.
+scriptversion=2019-02-19.15; # UTC
## ------ ##
@@ -1415,7 +1572,7 @@ scriptversion=2014-01-07.03; # UTC
#
# In order for the '--version' option to work, you will need to have a
# suitably formatted comment like the one at the top of this file
-# starting with '# Written by ' and ending with '# warranty; '.
+# starting with '# Written by ' and ending with '# Copyright'.
#
# For '-h' and '--help' to work, you will also need a one line
# description of your script's purpose in a comment directly above the
@@ -1427,7 +1584,7 @@ scriptversion=2014-01-07.03; # UTC
# to display verbose messages only when your user has specified
# '--verbose'.
#
-# After sourcing this file, you can plug processing for additional
+# After sourcing this file, you can plug in processing for additional
# options by amending the variables from the 'Configuration' section
# below, and following the instructions in the 'Option parsing'
# section further down.
@@ -1476,8 +1633,8 @@ fatal_help="Try '\$progname --help' for more information."
## ------------------------- ##
# This section contains functions for adding, removing, and running hooks
-# to the main code. A hook is just a named list of of function, that can
-# be run in order later on.
+# in the main code. A hook is just a list of function names that can be
+# run in order later on.
# func_hookable FUNC_NAME
# -----------------------
@@ -1510,7 +1667,8 @@ func_add_hook ()
# func_remove_hook FUNC_NAME HOOK_FUNC
# ------------------------------------
-# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+# Remove HOOK_FUNC from the list of hook functions to be called by
+# FUNC_NAME.
func_remove_hook ()
{
$debug_cmd
@@ -1519,10 +1677,28 @@ func_remove_hook ()
}
+# func_propagate_result FUNC_NAME_A FUNC_NAME_B
+# ---------------------------------------------
+# If the *_result variable of FUNC_NAME_A _is set_, assign its value to
+# *_result variable of FUNC_NAME_B.
+func_propagate_result ()
+{
+ $debug_cmd
+
+ func_propagate_result_result=:
+ if eval "test \"\${${1}_result+set}\" = set"
+ then
+ eval "${2}_result=\$${1}_result"
+ else
+ func_propagate_result_result=false
+ fi
+}
+
+
# func_run_hooks FUNC_NAME [ARG]...
# ---------------------------------
# Run all hook functions registered to FUNC_NAME.
-# It is assumed that the list of hook functions contains nothing more
+# It's assumed that the list of hook functions contains nothing more
# than a whitespace-delimited list of legal shell function names, and
# no effort is wasted trying to catch shell meta-characters or preserve
# whitespace.
@@ -1532,22 +1708,19 @@ func_run_hooks ()
case " $hookable_fns " in
*" $1 "*) ;;
- *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+ *) func_fatal_error "'$1' does not support hook functions." ;;
esac
eval _G_hook_fns=\$$1_hooks; shift
for _G_hook in $_G_hook_fns; do
- eval $_G_hook '"$@"'
-
- # store returned options list back into positional
- # parameters for next 'cmd' execution.
- eval _G_hook_result=\$${_G_hook}_result
- eval set dummy "$_G_hook_result"; shift
+ func_unset "${_G_hook}_result"
+ eval $_G_hook '${1+"$@"}'
+ func_propagate_result $_G_hook func_run_hooks
+ if $func_propagate_result_result; then
+ eval set dummy "$func_run_hooks_result"; shift
+ fi
done
-
- func_quote_for_eval ${1+"$@"}
- func_run_hooks_result=$func_quote_for_eval_result
}
@@ -1557,10 +1730,18 @@ func_run_hooks ()
## --------------- ##
# In order to add your own option parsing hooks, you must accept the
-# full positional parameter list in your hook function, remove any
-# options that you action, and then pass back the remaining unprocessed
-# options in '<hooked_function_name>_result', escaped suitably for
-# 'eval'. Like this:
+# full positional parameter list from your hook function. You may remove
+# or edit any options that you action, and then pass back the remaining
+# unprocessed options in '<hooked_function_name>_result', escaped
+# suitably for 'eval'.
+#
+# The '<hooked_function_name>_result' variable is automatically unset
+# before your hook gets called; for best performance, only set the
+# *_result variable when necessary (i.e. don't call the 'func_quote'
+# function unnecessarily because it can be an expensive operation on some
+# machines).
+#
+# Like this:
#
# my_options_prep ()
# {
@@ -1570,9 +1751,8 @@ func_run_hooks ()
# usage_message=$usage_message'
# -s, --silent don'\''t print informational messages
# '
-#
-# func_quote_for_eval ${1+"$@"}
-# my_options_prep_result=$func_quote_for_eval_result
+# # No change in '$@' (ignored completely by this hook). Leave
+# # my_options_prep_result variable intact.
# }
# func_add_hook func_options_prep my_options_prep
#
@@ -1581,25 +1761,36 @@ func_run_hooks ()
# {
# $debug_cmd
#
-# # Note that for efficiency, we parse as many options as we can
+# args_changed=false
+#
+# # Note that, for efficiency, we parse as many options as we can
# # recognise in a loop before passing the remainder back to the
# # caller on the first unrecognised argument we encounter.
# while test $# -gt 0; do
# opt=$1; shift
# case $opt in
-# --silent|-s) opt_silent=: ;;
+# --silent|-s) opt_silent=:
+# args_changed=:
+# ;;
# # Separate non-argument short options:
# -s*) func_split_short_opt "$_G_opt"
# set dummy "$func_split_short_opt_name" \
# "-$func_split_short_opt_arg" ${1+"$@"}
# shift
+# args_changed=:
# ;;
-# *) set dummy "$_G_opt" "$*"; shift; break ;;
+# *) # Make sure the first unrecognised option "$_G_opt"
+# # is added back to "$@" in case we need it later,
+# # if $args_changed was set to 'true'.
+# set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
# esac
# done
#
-# func_quote_for_eval ${1+"$@"}
-# my_silent_option_result=$func_quote_for_eval_result
+# # Only call 'func_quote' here if we processed at least one argument.
+# if $args_changed; then
+# func_quote eval ${1+"$@"}
+# my_silent_option_result=$func_quote_result
+# fi
# }
# func_add_hook func_parse_options my_silent_option
#
@@ -1610,17 +1801,26 @@ func_run_hooks ()
#
# $opt_silent && $opt_verbose && func_fatal_help "\
# '--silent' and '--verbose' options are mutually exclusive."
-#
-# func_quote_for_eval ${1+"$@"}
-# my_option_validation_result=$func_quote_for_eval_result
# }
# func_add_hook func_validate_options my_option_validation
#
-# You'll alse need to manually amend $usage_message to reflect the extra
+# You'll also need to manually amend $usage_message to reflect the extra
# options you parse. It's preferable to append if you can, so that
# multiple option parsing hooks can be added safely.
+# func_options_finish [ARG]...
+# ----------------------------
+# Finishing the option parse loop (call 'func_options' hooks ATM).
+func_options_finish ()
+{
+ $debug_cmd
+
+ func_run_hooks func_options ${1+"$@"}
+ func_propagate_result func_run_hooks func_options_finish
+}
+
+
# func_options [ARG]...
# ---------------------
# All the functions called inside func_options are hookable. See the
@@ -1630,17 +1830,27 @@ func_options ()
{
$debug_cmd
- func_options_prep ${1+"$@"}
- eval func_parse_options \
- ${func_options_prep_result+"$func_options_prep_result"}
- eval func_validate_options \
- ${func_parse_options_result+"$func_parse_options_result"}
+ _G_options_quoted=false
- eval func_run_hooks func_options \
- ${func_validate_options_result+"$func_validate_options_result"}
+ for my_func in options_prep parse_options validate_options options_finish
+ do
+ func_unset func_${my_func}_result
+ func_unset func_run_hooks_result
+ eval func_$my_func '${1+"$@"}'
+ func_propagate_result func_$my_func func_options
+ if $func_propagate_result_result; then
+ eval set dummy "$func_options_result"; shift
+ _G_options_quoted=:
+ fi
+ done
- # save modified positional parameters for caller
- func_options_result=$func_run_hooks_result
+ $_G_options_quoted || {
+ # As we (func_options) are top-level options-parser function and
+ # nobody quoted "$@" for us yet, we need to do it explicitly for
+ # caller.
+ func_quote eval ${1+"$@"}
+ func_options_result=$func_quote_result
+ }
}
@@ -1649,9 +1859,8 @@ func_options ()
# All initialisations required before starting the option parse loop.
# Note that when calling hook functions, we pass through the list of
# positional parameters. If a hook function modifies that list, and
-# needs to propogate that back to rest of this script, then the complete
-# modified list must be put in 'func_run_hooks_result' before
-# returning.
+# needs to propagate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before returning.
func_hookable func_options_prep
func_options_prep ()
{
@@ -1662,9 +1871,7 @@ func_options_prep ()
opt_warning_types=
func_run_hooks func_options_prep ${1+"$@"}
-
- # save modified positional parameters for caller
- func_options_prep_result=$func_run_hooks_result
+ func_propagate_result func_run_hooks func_options_prep
}
@@ -1676,25 +1883,32 @@ func_parse_options ()
{
$debug_cmd
- func_parse_options_result=
-
+ _G_parse_options_requote=false
# this just eases exit handling
while test $# -gt 0; do
# Defer to hook functions for initial option parsing, so they
# get priority in the event of reusing an option name.
func_run_hooks func_parse_options ${1+"$@"}
-
- # Adjust func_parse_options positional parameters to match
- eval set dummy "$func_run_hooks_result"; shift
+ func_propagate_result func_run_hooks func_parse_options
+ if $func_propagate_result_result; then
+ eval set dummy "$func_parse_options_result"; shift
+ # Even though we may have changed "$@", we passed the "$@" array
+ # down into the hook and it quoted it for us (because we are in
+ # this if-branch). No need to quote it again.
+ _G_parse_options_requote=false
+ fi
# Break out of the loop if we already parsed every option.
test $# -gt 0 || break
+ # We expect that one of the options parsed in this function matches
+ # and thus we remove _G_opt from "$@" and need to re-quote.
+ _G_match_parse_options=:
_G_opt=$1
shift
case $_G_opt in
--debug|-x) debug_cmd='set -x'
- func_echo "enabling shell trace mode"
+ func_echo "enabling shell trace mode" >&2
$debug_cmd
;;
@@ -1704,7 +1918,10 @@ func_parse_options ()
;;
--warnings|--warning|-W)
- test $# = 0 && func_missing_arg $_G_opt && break
+ if test $# = 0 && func_missing_arg $_G_opt; then
+ _G_parse_options_requote=:
+ break
+ fi
case " $warning_categories $1" in
*" $1 "*)
# trailing space prevents matching last $1 above
@@ -1757,15 +1974,24 @@ func_parse_options ()
shift
;;
- --) break ;;
+ --) _G_parse_options_requote=: ; break ;;
-*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
- *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ *) set dummy "$_G_opt" ${1+"$@"}; shift
+ _G_match_parse_options=false
+ break
+ ;;
esac
+
+ if $_G_match_parse_options; then
+ _G_parse_options_requote=:
+ fi
done
- # save modified positional parameters for caller
- func_quote_for_eval ${1+"$@"}
- func_parse_options_result=$func_quote_for_eval_result
+ if $_G_parse_options_requote; then
+ # save modified positional parameters for caller
+ func_quote eval ${1+"$@"}
+ func_parse_options_result=$func_quote_result
+ fi
}
@@ -1782,12 +2008,10 @@ func_validate_options ()
test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
func_run_hooks func_validate_options ${1+"$@"}
+ func_propagate_result func_run_hooks func_validate_options
# Bail if the options were screwed!
$exit_cmd $EXIT_FAILURE
-
- # save modified positional parameters for caller
- func_validate_options_result=$func_run_hooks_result
}
@@ -1843,8 +2067,8 @@ func_missing_arg ()
# func_split_equals STRING
# ------------------------
-# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
-# splitting STRING at the '=' sign.
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables
+# after splitting STRING at the '=' sign.
test -z "$_G_HAVE_XSI_OPS" \
&& (eval 'x=a/b/c;
test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
@@ -1859,8 +2083,9 @@ then
func_split_equals_lhs=${1%%=*}
func_split_equals_rhs=${1#*=}
- test "x$func_split_equals_lhs" = "x$1" \
- && func_split_equals_rhs=
+ if test "x$func_split_equals_lhs" = "x$1"; then
+ func_split_equals_rhs=
+ fi
}'
else
# ...otherwise fall back to using expr, which is often a shell builtin.
@@ -1870,7 +2095,7 @@ else
func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
func_split_equals_rhs=
- test "x$func_split_equals_lhs" = "x$1" \
+ test "x$func_split_equals_lhs=" = "x$1" \
|| func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
}
fi #func_split_equals
@@ -1896,7 +2121,7 @@ else
{
$debug_cmd
- func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+ func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'`
func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
}
fi #func_split_short_opt
@@ -1938,31 +2163,44 @@ func_usage_message ()
# func_version
# ------------
# Echo version message to standard output and exit.
+# The version message is extracted from the calling file's header
+# comments, with leading '# ' stripped:
+# 1. First display the progname and version
+# 2. Followed by the header comment line matching /^# Written by /
+# 3. Then a blank line followed by the first following line matching
+# /^# Copyright /
+# 4. Immediately followed by any lines between the previous matches,
+# except lines preceding the intervening completely blank line.
+# For example, see the header comments of this file.
func_version ()
{
$debug_cmd
printf '%s\n' "$progname $scriptversion"
$SED -n '
- /(C)/!b go
- :more
- /\./!{
- N
- s|\n# | |
- b more
- }
- :go
- /^# Written by /,/# warranty; / {
- s|^# ||
- s|^# *$||
- s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
- p
+ /^# Written by /!b
+ s|^# ||; p; n
+
+ :fwd2blnk
+ /./ {
+ n
+ b fwd2blnk
}
- /^# Written by / {
- s|^# ||
- p
+ p; n
+
+ :holdwrnt
+ s|^# ||
+ s|^# *$||
+ /^Copyright /!{
+ /./H
+ n
+ b holdwrnt
}
- /^warranty; /q' < "$progpath"
+
+ s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+ G
+ s|\(\n\)\n*|\1|g
+ p; q' < "$progpath"
exit $?
}
@@ -1972,12 +2210,12 @@ func_version ()
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC"
# time-stamp-time-zone: "UTC"
# End:
# Set a version string.
-scriptversion='(GNU libtool) 2.4.6'
+scriptversion='(GNU libtool) 2.4.7'
# func_echo ARG...
@@ -2068,7 +2306,7 @@ include the following information:
compiler: $LTCC
compiler flags: $LTCFLAGS
linker: $LD (gnu? $with_gnu_ld)
- version: $progname (GNU libtool) 2.4.6
+ version: $progname (GNU libtool) 2.4.7
automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
@@ -2124,7 +2362,7 @@ fi
# a configuration failure hint, and exit.
func_fatal_configuration ()
{
- func__fatal_error ${1+"$@"} \
+ func_fatal_error ${1+"$@"} \
"See the $PACKAGE documentation for more information." \
"Fatal configuration error."
}
@@ -2270,6 +2508,8 @@ libtool_options_prep ()
nonopt=
preserve_args=
+ _G_rc_lt_options_prep=:
+
# Shorthand for --mode=foo, only valid as the first argument
case $1 in
clean|clea|cle|cl)
@@ -2293,11 +2533,16 @@ libtool_options_prep ()
uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
shift; set dummy --mode uninstall ${1+"$@"}; shift
;;
+ *)
+ _G_rc_lt_options_prep=false
+ ;;
esac
- # Pass back the list of options.
- func_quote_for_eval ${1+"$@"}
- libtool_options_prep_result=$func_quote_for_eval_result
+ if $_G_rc_lt_options_prep; then
+ # Pass back the list of options.
+ func_quote eval ${1+"$@"}
+ libtool_options_prep_result=$func_quote_result
+ fi
}
func_add_hook func_options_prep libtool_options_prep
@@ -2309,9 +2554,12 @@ libtool_parse_options ()
{
$debug_cmd
+ _G_rc_lt_parse_options=false
+
# Perform our own loop to consume as many options as possible in
# each iteration.
while test $# -gt 0; do
+ _G_match_lt_parse_options=:
_G_opt=$1
shift
case $_G_opt in
@@ -2386,15 +2634,20 @@ libtool_parse_options ()
func_append preserve_args " $_G_opt"
;;
- # An option not handled by this hook function:
- *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ # An option not handled by this hook function:
+ *) set dummy "$_G_opt" ${1+"$@"} ; shift
+ _G_match_lt_parse_options=false
+ break
+ ;;
esac
+ $_G_match_lt_parse_options && _G_rc_lt_parse_options=:
done
-
- # save modified positional parameters for caller
- func_quote_for_eval ${1+"$@"}
- libtool_parse_options_result=$func_quote_for_eval_result
+ if $_G_rc_lt_parse_options; then
+ # save modified positional parameters for caller
+ func_quote eval ${1+"$@"}
+ libtool_parse_options_result=$func_quote_result
+ fi
}
func_add_hook func_parse_options libtool_parse_options
@@ -2451,8 +2704,8 @@ libtool_validate_options ()
}
# Pass back the unparsed argument list
- func_quote_for_eval ${1+"$@"}
- libtool_validate_options_result=$func_quote_for_eval_result
+ func_quote eval ${1+"$@"}
+ libtool_validate_options_result=$func_quote_result
}
func_add_hook func_validate_options libtool_validate_options
@@ -3418,8 +3671,8 @@ func_mode_compile ()
esac
done
- func_quote_for_eval "$libobj"
- test "X$libobj" != "X$func_quote_for_eval_result" \
+ func_quote_arg pretty "$libobj"
+ test "X$libobj" != "X$func_quote_arg_result" \
&& $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
&& func_warning "libobj name '$libobj' may not contain shell special characters."
func_dirname_and_basename "$obj" "/" ""
@@ -3492,8 +3745,8 @@ compiler."
func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
srcfile=$func_to_tool_file_result
- func_quote_for_eval "$srcfile"
- qsrcfile=$func_quote_for_eval_result
+ func_quote_arg pretty "$srcfile"
+ qsrcfile=$func_quote_arg_result
# Only build a PIC object if we are building libtool libraries.
if test yes = "$build_libtool_libs"; then
@@ -3648,7 +3901,8 @@ This mode accepts the following additional options:
-prefer-non-pic try to build non-PIC objects only
-shared do not build a '.o' file suitable for static linking
-static only build a '.o' file suitable for static linking
- -Wc,FLAG pass FLAG directly to the compiler
+ -Wc,FLAG
+ -Xcompiler FLAG pass FLAG directly to the compiler
COMPILE-COMMAND is a command to be used in creating a 'standard' object file
from the given SOURCEFILE.
@@ -3754,6 +4008,8 @@ The following components of LINK-COMMAND are treated specially:
-weak LIBNAME declare that the target provides the LIBNAME interface
-Wc,FLAG
-Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wa,FLAG
+ -Xassembler FLAG pass linker-specific FLAG directly to the assembler
-Wl,FLAG
-Xlinker FLAG pass linker-specific FLAG directly to the linker
-XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
@@ -4096,8 +4352,8 @@ func_mode_install ()
case $nonopt in *shtool*) :;; *) false;; esac
then
# Aesthetically quote it.
- func_quote_for_eval "$nonopt"
- install_prog="$func_quote_for_eval_result "
+ func_quote_arg pretty "$nonopt"
+ install_prog="$func_quote_arg_result "
arg=$1
shift
else
@@ -4107,8 +4363,8 @@ func_mode_install ()
# The real first argument should be the name of the installation program.
# Aesthetically quote it.
- func_quote_for_eval "$arg"
- func_append install_prog "$func_quote_for_eval_result"
+ func_quote_arg pretty "$arg"
+ func_append install_prog "$func_quote_arg_result"
install_shared_prog=$install_prog
case " $install_prog " in
*[\\\ /]cp\ *) install_cp=: ;;
@@ -4165,12 +4421,12 @@ func_mode_install ()
esac
# Aesthetically quote the argument.
- func_quote_for_eval "$arg"
- func_append install_prog " $func_quote_for_eval_result"
+ func_quote_arg pretty "$arg"
+ func_append install_prog " $func_quote_arg_result"
if test -n "$arg2"; then
- func_quote_for_eval "$arg2"
+ func_quote_arg pretty "$arg2"
fi
- func_append install_shared_prog " $func_quote_for_eval_result"
+ func_append install_shared_prog " $func_quote_arg_result"
done
test -z "$install_prog" && \
@@ -4181,8 +4437,8 @@ func_mode_install ()
if test -n "$install_override_mode" && $no_mode; then
if $install_cp; then :; else
- func_quote_for_eval "$install_override_mode"
- func_append install_shared_prog " -m $func_quote_for_eval_result"
+ func_quote_arg pretty "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_arg_result"
fi
fi
@@ -4478,8 +4734,8 @@ func_mode_install ()
relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
$opt_quiet || {
- func_quote_for_expand "$relink_command"
- eval "func_echo $func_quote_for_expand_result"
+ func_quote_arg expand,pretty "$relink_command"
+ eval "func_echo $func_quote_arg_result"
}
if eval "$relink_command"; then :
else
@@ -5258,7 +5514,8 @@ else
if test \"\$libtool_execute_magic\" != \"$magic\"; then
file=\"\$0\""
- qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ func_quote_arg pretty "$ECHO"
+ qECHO=$func_quote_arg_result
$ECHO "\
# A function that is used when there is no print builtin or printf.
@@ -5268,7 +5525,7 @@ func_fallback_echo ()
\$1
_LTECHO_EOF'
}
- ECHO=\"$qECHO\"
+ ECHO=$qECHO
fi
# Very basic option parsing. These options are (a) specific to
@@ -6611,9 +6868,9 @@ func_mode_link ()
while test "$#" -gt 0; do
arg=$1
shift
- func_quote_for_eval "$arg"
- qarg=$func_quote_for_eval_unquoted_result
- func_append libtool_args " $func_quote_for_eval_result"
+ func_quote_arg pretty,unquoted "$arg"
+ qarg=$func_quote_arg_unquoted_result
+ func_append libtool_args " $func_quote_arg_result"
# If the previous option needs an argument, assign it.
if test -n "$prev"; then
@@ -6849,6 +7106,13 @@ func_mode_link ()
prev=
continue
;;
+ xassembler)
+ func_append compiler_flags " -Xassembler $qarg"
+ prev=
+ func_append compile_command " -Xassembler $qarg"
+ func_append finalize_command " -Xassembler $qarg"
+ continue
+ ;;
xcclinker)
func_append linker_flags " $qarg"
func_append compiler_flags " $qarg"
@@ -7019,7 +7283,7 @@ func_mode_link ()
# These systems don't actually have a C library (as such)
test X-lc = "X$arg" && continue
;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*)
# Do not include libc due to us having libc/libc_r.
test X-lc = "X$arg" && continue
;;
@@ -7039,7 +7303,7 @@ func_mode_link ()
esac
elif test X-lc_r = "X$arg"; then
case $host in
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*)
# Do not include libc_r directly, use -pthread flag.
continue
;;
@@ -7069,8 +7333,20 @@ func_mode_link ()
prev=xcompiler
continue
;;
-
- -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199.
+ -pthread)
+ case $host in
+ *solaris2*) ;;
+ *)
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+ -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \
|-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
func_append compiler_flags " $arg"
func_append compile_command " $arg"
@@ -7211,9 +7487,9 @@ func_mode_link ()
save_ifs=$IFS; IFS=,
for flag in $args; do
IFS=$save_ifs
- func_quote_for_eval "$flag"
- func_append arg " $func_quote_for_eval_result"
- func_append compiler_flags " $func_quote_for_eval_result"
+ func_quote_arg pretty "$flag"
+ func_append arg " $func_quote_arg_result"
+ func_append compiler_flags " $func_quote_arg_result"
done
IFS=$save_ifs
func_stripname ' ' '' "$arg"
@@ -7227,16 +7503,21 @@ func_mode_link ()
save_ifs=$IFS; IFS=,
for flag in $args; do
IFS=$save_ifs
- func_quote_for_eval "$flag"
- func_append arg " $wl$func_quote_for_eval_result"
- func_append compiler_flags " $wl$func_quote_for_eval_result"
- func_append linker_flags " $func_quote_for_eval_result"
+ func_quote_arg pretty "$flag"
+ func_append arg " $wl$func_quote_arg_result"
+ func_append compiler_flags " $wl$func_quote_arg_result"
+ func_append linker_flags " $func_quote_arg_result"
done
IFS=$save_ifs
func_stripname ' ' '' "$arg"
arg=$func_stripname_result
;;
+ -Xassembler)
+ prev=xassembler
+ continue
+ ;;
+
-Xcompiler)
prev=xcompiler
continue
@@ -7254,8 +7535,8 @@ func_mode_link ()
# -msg_* for osf cc
-msg_*)
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
+ func_quote_arg pretty "$arg"
+ arg=$func_quote_arg_result
;;
# Flags to be passed through unchanged, with rationale:
@@ -7272,12 +7553,17 @@ func_mode_link ()
# -tp=* Portland pgcc target processor selection
# --sysroot=* for sysroot support
# -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -specs=* GCC specs files
# -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang/GCC memory and address sanitizer
+ # -fuse-ld=* Linker select flags for GCC
+ # -Wa,* Pass flags directly to the assembler
-64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
- -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+ -specs=*|-fsanitize=*|-fuse-ld=*|-Wa,*)
+ func_quote_arg pretty "$arg"
+ arg=$func_quote_arg_result
func_append compile_command " $arg"
func_append finalize_command " $arg"
func_append compiler_flags " $arg"
@@ -7298,15 +7584,15 @@ func_mode_link ()
continue
else
# Otherwise treat like 'Some other compiler flag' below
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
+ func_quote_arg pretty "$arg"
+ arg=$func_quote_arg_result
fi
;;
# Some other compiler flag.
-* | +*)
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
+ func_quote_arg pretty "$arg"
+ arg=$func_quote_arg_result
;;
*.$objext)
@@ -7426,8 +7712,8 @@ func_mode_link ()
*)
# Unknown arguments in both finalize_command and compile_command need
# to be aesthetically quoted because they are evaled later.
- func_quote_for_eval "$arg"
- arg=$func_quote_for_eval_result
+ func_quote_arg pretty "$arg"
+ arg=$func_quote_arg_result
;;
esac # arg
@@ -8632,7 +8918,7 @@ func_mode_link ()
test CXX = "$tagname" && {
case $host_os in
linux*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*) # Sun C++ 5.9
func_suncc_cstd_abi
@@ -8805,7 +9091,7 @@ func_mode_link ()
#
case $version_type in
# correct linux to gnu/linux during the next big refactor
- darwin|freebsd-elf|linux|osf|windows|none)
+ darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none)
func_arith $number_major + $number_minor
current=$func_arith_result
age=$number_minor
@@ -8896,7 +9182,7 @@ func_mode_link ()
versuffix=.$current.$revision
;;
- freebsd-elf)
+ freebsd-elf | midnightbsd-elf)
func_arith $current - $age
major=.$func_arith_result
versuffix=$major.$age.$revision
@@ -9122,7 +9408,7 @@ func_mode_link ()
*-*-netbsd*)
# Don't link with libc until the a.out ld.so is fixed.
;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*)
# Do not include libc due to us having libc/libc_r.
;;
*-*-sco3.2v5* | *-*-sco5v6*)
@@ -9935,8 +10221,8 @@ EOF
for cmd in $concat_cmds; do
IFS=$save_ifs
$opt_quiet || {
- func_quote_for_expand "$cmd"
- eval "func_echo $func_quote_for_expand_result"
+ func_quote_arg expand,pretty "$cmd"
+ eval "func_echo $func_quote_arg_result"
}
$opt_dry_run || eval "$cmd" || {
lt_exit=$?
@@ -10029,8 +10315,8 @@ EOF
eval cmd=\"$cmd\"
IFS=$save_ifs
$opt_quiet || {
- func_quote_for_expand "$cmd"
- eval "func_echo $func_quote_for_expand_result"
+ func_quote_arg expand,pretty "$cmd"
+ eval "func_echo $func_quote_arg_result"
}
$opt_dry_run || eval "$cmd" || {
lt_exit=$?
@@ -10508,12 +10794,13 @@ EOF
elif eval var_value=\$$var; test -z "$var_value"; then
relink_command="$var=; export $var; $relink_command"
else
- func_quote_for_eval "$var_value"
- relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ func_quote_arg pretty "$var_value"
+ relink_command="$var=$func_quote_arg_result; export $var; $relink_command"
fi
done
- relink_command="(cd `pwd`; $relink_command)"
- relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ func_quote eval cd "`pwd`"
+ func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)"
+ relink_command=$func_quote_arg_unquoted_result
fi
# Only actually do things if not in dry run mode.
@@ -10753,13 +11040,15 @@ EOF
elif eval var_value=\$$var; test -z "$var_value"; then
relink_command="$var=; export $var; $relink_command"
else
- func_quote_for_eval "$var_value"
- relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ func_quote_arg pretty,unquoted "$var_value"
+ relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command"
fi
done
# Quote the link command for shipping.
- relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
- relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ func_quote eval cd "`pwd`"
+ relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ func_quote_arg pretty,unquoted "$relink_command"
+ relink_command=$func_quote_arg_unquoted_result
if test yes = "$hardcode_automatic"; then
relink_command=
fi
diff --git a/m4/boost.m4 b/m4/boost.m4
index d1b6e2c..30a4d91 100644
--- a/m4/boost.m4
+++ b/m4/boost.m4
@@ -1615,6 +1615,9 @@ if test x$boost_cv_inc_path != xno; then
# I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
# the same defines as GCC's).
for i in \
+ "defined __clang__ && __clang_major__ == 17 && __clang_minor__ == 0 @ clang170" \
+ "defined __clang__ && __clang_major__ == 16 && __clang_minor__ == 0 @ clang160" \
+ "defined __clang__ && __clang_major__ == 15 && __clang_minor__ == 0 @ clang150" \
"defined __clang__ && __clang_major__ == 14 && __clang_minor__ == 0 @ clang140" \
"defined __clang__ && __clang_major__ == 13 && __clang_minor__ == 0 @ clang130" \
"defined __clang__ && __clang_major__ == 12 && __clang_minor__ == 0 @ clang120" \
diff --git a/m4/dnsdist_enable_doh.m4 b/m4/dnsdist_enable_doh.m4
index 876a218..baf9118 100644
--- a/m4/dnsdist_enable_doh.m4
+++ b/m4/dnsdist_enable_doh.m4
@@ -1,7 +1,7 @@
AC_DEFUN([DNSDIST_ENABLE_DNS_OVER_HTTPS], [
AC_MSG_CHECKING([whether to enable incoming DNS over HTTPS (DoH) support])
AC_ARG_ENABLE([dns-over-https],
- AS_HELP_STRING([--enable-dns-over-https], [enable incoming DNS over HTTPS (DoH) support (requires libh2o) @<:@default=no@:>@]),
+ AS_HELP_STRING([--enable-dns-over-https], [enable incoming DNS over HTTPS (DoH) support (requires libh2o or nghttp2) @<:@default=no@:>@]),
[enable_dns_over_https=$enableval],
[enable_dns_over_https=no]
)
diff --git a/m4/dnsdist_enable_doh3.m4 b/m4/dnsdist_enable_doh3.m4
new file mode 100644
index 0000000..ffac6f0
--- /dev/null
+++ b/m4/dnsdist_enable_doh3.m4
@@ -0,0 +1,14 @@
+AC_DEFUN([DNSDIST_ENABLE_DNS_OVER_HTTP3], [
+ AC_MSG_CHECKING([whether to enable incoming DNS over HTTP3 (DoH3) support])
+ AC_ARG_ENABLE([dns-over-http3],
+ AS_HELP_STRING([--enable-dns-over-http3], [enable incoming DNS over HTTP3 (DoH3) support (requires quiche) @<:@default=no@:>@]),
+ [enable_dns_over_http3=$enableval],
+ [enable_dns_over_http3=no]
+ )
+ AC_MSG_RESULT([$enable_dns_over_http3])
+ AM_CONDITIONAL([HAVE_DNS_OVER_HTTP3], [test "x$enable_dns_over_http3" != "xno"])
+
+ AM_COND_IF([HAVE_DNS_OVER_HTTP3], [
+ AC_DEFINE([HAVE_DNS_OVER_HTTP3], [1], [Define to 1 if you enable DNS over HTTP/3 support])
+ ])
+])
diff --git a/m4/dnsdist_enable_doq.m4 b/m4/dnsdist_enable_doq.m4
new file mode 100644
index 0000000..0488e0e
--- /dev/null
+++ b/m4/dnsdist_enable_doq.m4
@@ -0,0 +1,14 @@
+AC_DEFUN([DNSDIST_ENABLE_DNS_OVER_QUIC], [
+ AC_MSG_CHECKING([whether to enable incoming DNS over QUIC (DoQ) support])
+ AC_ARG_ENABLE([dns-over-quic],
+ AS_HELP_STRING([--enable-dns-over-quic], [enable incoming DNS over QUIC (DoQ) support (requires quiche) @<:@default=no@:>@]),
+ [enable_dns_over_quic=$enableval],
+ [enable_dns_over_quic=no]
+ )
+ AC_MSG_RESULT([$enable_dns_over_quic])
+ AM_CONDITIONAL([HAVE_DNS_OVER_QUIC], [test "x$enable_dns_over_quic" != "xno"])
+
+ AM_COND_IF([HAVE_DNS_OVER_QUIC], [
+ AC_DEFINE([HAVE_DNS_OVER_QUIC], [1], [Define to 1 if you enable DNS over QUIC support])
+ ])
+])
diff --git a/m4/libtool.m4 b/m4/libtool.m4
index a3bc337..79a2451 100644
--- a/m4/libtool.m4
+++ b/m4/libtool.m4
@@ -1,6 +1,7 @@
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
#
-# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+# Copyright (C) 1996-2001, 2003-2019, 2021-2022 Free Software
+# Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# This file is free software; the Free Software Foundation gives
@@ -31,7 +32,7 @@ m4_define([_LT_COPYING], [dnl
# along with this program. If not, see <http://www.gnu.org/licenses/>.
])
-# serial 58 LT_INIT
+# serial 59 LT_INIT
# LT_PREREQ(VERSION)
@@ -181,6 +182,7 @@ m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_CHECK_SHELL_FEATURES])dnl
m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_DECL_FILECMD])dnl
m4_require([_LT_CHECK_MAGIC_METHOD])dnl
m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
m4_require([_LT_CMD_OLD_ARCHIVE])dnl
@@ -219,8 +221,8 @@ esac
ofile=libtool
can_build_shared=yes
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
+# All known linkers require a '.a' archive for static linking (except MSVC and
+# ICC, which need '.lib').
libext=a
with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -778,7 +780,7 @@ _LT_EOF
# if finds mixed CR/LF and LF-only lines. Since sed operates in
# text mode, it properly converts lines to CR/LF. This bash problem
# is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
+ $SED '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
mv -f "$cfgfile" "$ofile" ||
@@ -1042,8 +1044,8 @@ int forced_loaded() { return 2;}
_LT_EOF
echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
$LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
- echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
- $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
$RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
cat > conftest.c << _LT_EOF
@@ -1067,17 +1069,12 @@ _LT_EOF
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]][[,.]]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ darwin*)
+ case $MACOSX_DEPLOYMENT_TARGET,$host in
+ 10.[[012]],*|,*powerpc*-darwin[[5-8]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ *)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
@@ -1126,12 +1123,12 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
output_verbose_link_cmd=func_echo_all
_LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
_LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
- _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
m4_if([$1], [CXX],
[ if test yes != "$lt_cv_apple_cc_single_mod"; then
_LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
fi
],[])
else
@@ -1245,7 +1242,8 @@ _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
# _LT_WITH_SYSROOT
# ----------------
AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
+[m4_require([_LT_DECL_SED])dnl
+AC_MSG_CHECKING([for sysroot])
AC_ARG_WITH([sysroot],
[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
[Search for dependent libraries within DIR (or the compiler's sysroot
@@ -1262,7 +1260,7 @@ case $with_sysroot in #(
fi
;; #(
/*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"`
;; #(
no|'')
;; #(
@@ -1292,7 +1290,7 @@ ia64-*-hpux*)
# options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*ELF-32*)
HPUX_IA64_MODE=32
;;
@@ -1309,7 +1307,7 @@ ia64-*-hpux*)
echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
if test yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
;;
@@ -1321,7 +1319,7 @@ ia64-*-hpux*)
;;
esac
else
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -32"
;;
@@ -1343,7 +1341,7 @@ mips64*-*linux*)
echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
emul=elf
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*32-bit*)
emul="${emul}32"
;;
@@ -1351,7 +1349,7 @@ mips64*-*linux*)
emul="${emul}64"
;;
esac
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*MSB*)
emul="${emul}btsmip"
;;
@@ -1359,7 +1357,7 @@ mips64*-*linux*)
emul="${emul}ltsmip"
;;
esac
- case `/usr/bin/file conftest.$ac_objext` in
+ case `$FILECMD conftest.$ac_objext` in
*N32*)
emul="${emul}n32"
;;
@@ -1379,14 +1377,14 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
# not appear in the list.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*32-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*x86-64*)
LD="${LD-ld} -m elf32_x86_64"
;;
@@ -1454,7 +1452,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
# options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.o` in
+ case `$FILECMD conftest.o` in
*64-bit*)
case $lt_cv_prog_gnu_ld in
yes*)
@@ -1493,9 +1491,22 @@ need_locks=$enable_libtool_lock
m4_defun([_LT_PROG_AR],
[AC_CHECK_TOOLS(AR, [ar], false)
: ${AR=ar}
-: ${AR_FLAGS=cru}
_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+# Use ARFLAGS variable as AR's operation code to sync the variable naming with
+# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
+# higher priority because thats what people were doing historically (setting
+# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS
+# variable obsoleted/removed.
+
+test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr}
+lt_ar_flags=$AR_FLAGS
+_LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)])
+
+# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override
+# by AR_FLAGS because that was never working and AR_FLAGS is about to die.
+_LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}],
+ [Flags to create an archive])
AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
[lt_cv_ar_at_file=no
@@ -1714,7 +1725,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
lt_cv_sys_max_cmd_len=8192;
;;
- bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -1757,7 +1768,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
sysv5* | sco5v6* | sysv4.2uw2*)
kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'`
else
lt_cv_sys_max_cmd_len=32768
fi
@@ -2207,26 +2218,35 @@ m4_defun([_LT_CMD_STRIPLIB],
striplib=
old_striplib=
AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- AC_MSG_RESULT([yes])
+if test -z "$STRIP"; then
+ AC_MSG_RESULT([no])
else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
+ if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ old_striplib="$STRIP --strip-debug"
+ striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+ else
+ case $host_os in
+ darwin*)
+ # FIXME - insert some real tests, host_os isn't really good enough
striplib="$STRIP -x"
old_striplib="$STRIP -S"
AC_MSG_RESULT([yes])
- else
+ ;;
+ freebsd*)
+ if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then
+ old_striplib="$STRIP --strip-debug"
+ striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
AC_MSG_RESULT([no])
- fi
- ;;
- *)
- AC_MSG_RESULT([no])
- ;;
- esac
+ ;;
+ esac
+ fi
fi
_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
_LT_DECL([], [striplib], [1])
@@ -2549,7 +2569,7 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
;;
@@ -2559,14 +2579,14 @@ m4_if([$1], [],[
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
;;
- *,cl*)
- # Native MSVC
+ *,cl* | *,icl*)
+ # Native MSVC or ICC
libname_spec='$name'
soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
library_names_spec='$libname.dll.lib'
@@ -2585,7 +2605,7 @@ m4_if([$1], [],[
done
IFS=$lt_save_ifs
# Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
;;
cygwin*)
# Convert to unix form, then to dos form, then back to unix form
@@ -2622,7 +2642,7 @@ m4_if([$1], [],[
;;
*)
- # Assume MSVC wrapper
+ # Assume MSVC and ICC wrapper
library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
@@ -2655,7 +2675,7 @@ dgux*)
shlibpath_var=LD_LIBRARY_PATH
;;
-freebsd* | dragonfly*)
+freebsd* | dragonfly* | midnightbsd*)
# DragonFly does not have aout. When/if they implement a new
# versioning mechanism, adjust this.
if test -x /usr/bin/objformat; then
@@ -3454,7 +3474,7 @@ beos*)
bsdi[[45]]*)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_cmd='$FILECMD -L'
lt_cv_file_magic_test_file=/shlib/libc.so
;;
@@ -3488,14 +3508,14 @@ darwin* | rhapsody*)
lt_cv_deplibs_check_method=pass_all
;;
-freebsd* | dragonfly*)
+freebsd* | dragonfly* | midnightbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
case $host_cpu in
i*86 )
# Not sure whether the presence of OpenBSD here was a mistake.
# Let's accept both of them until this is cleared up.
lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
;;
esac
@@ -3509,7 +3529,7 @@ haiku*)
;;
hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
case $host_cpu in
ia64*)
lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
@@ -3556,7 +3576,7 @@ netbsd*)
newos6*)
lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_cmd=$FILECMD
lt_cv_file_magic_test_file=/usr/lib/libnls.so
;;
@@ -3683,13 +3703,13 @@ else
mingw*) lt_bad_file=conftest.nm/nofile ;;
*) lt_bad_file=/dev/null ;;
esac
- case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in
*$lt_bad_file* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
break 2
;;
*)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
break 2
@@ -3715,7 +3735,7 @@ else
# Let the user override the test.
else
AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
- case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in
*COFF*)
DUMPBIN="$DUMPBIN -symbols -headers"
;;
@@ -3955,7 +3975,7 @@ esac
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
# Gets list of data symbols to import.
- lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'"
# Adjust the below global symbol transforms to fixup imported variables.
lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
@@ -3973,20 +3993,20 @@ fi
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+lt_cv_sys_global_symbol_to_cdecl="$SED -n"\
$lt_cdecl_hook\
" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\
$lt_c_name_hook\
" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
# Transform an extracted symbol line into symbol name with lib prefix and
# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\
$lt_c_name_lib_hook\
" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
@@ -4010,7 +4030,7 @@ for ac_symprfx in "" "_"; do
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
# Fake it for dumpbin and say T for any non-static function,
# D for any global variable and I for any imported variable.
- # Also find C++ and __fastcall symbols from MSVC++,
+ # Also find C++ and __fastcall symbols from MSVC++ or ICC,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK ['"\
" {last_section=section; section=\$ 3};"\
@@ -4028,9 +4048,9 @@ for ac_symprfx in "" "_"; do
" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx]"
else
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'"
# Check to see that the pipe works correctly.
pipe_works=no
@@ -4317,7 +4337,7 @@ m4_if([$1], [CXX], [
;;
esac
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
# FreeBSD uses GNU C++
;;
hpux9* | hpux10* | hpux11*)
@@ -4400,7 +4420,7 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
@@ -4736,7 +4756,7 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
# Sun Fortran 8.3 passes all unrecognized flags to the linker
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
@@ -4919,7 +4939,7 @@ m4_if([$1], [CXX], [
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
@@ -4927,7 +4947,7 @@ m4_if([$1], [CXX], [
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
- cl*)
+ cl* | icl*)
_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
;;
*)
@@ -4984,15 +5004,15 @@ dnl Note also adjust exclude_expsyms for C++ above.
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
+ # Microsoft Visual C++ or Intel C++ Compiler.
if test yes != "$GCC"; then
with_gnu_ld=no
fi
;;
interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
+ # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
with_gnu_ld=yes
;;
openbsd* | bitrig*)
@@ -5044,7 +5064,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
supports_anon_versioning=no
- case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+ case `$LD -v | $SED -e 's/([[^)]]\+)\s\+//' 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -5156,6 +5176,7 @@ _LT_EOF
emximp -o $lib $output_objdir/$libname.def'
_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
;;
interix[[3-9]]*)
@@ -5170,7 +5191,7 @@ _LT_EOF
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
@@ -5213,7 +5234,7 @@ _LT_EOF
_LT_TAGVAR(compiler_needs_object, $1)=yes
;;
esac
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*) # Sun C 5.9
_LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
@@ -5225,7 +5246,7 @@ _LT_EOF
if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
@@ -5241,7 +5262,7 @@ _LT_EOF
_LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
@@ -5373,7 +5394,7 @@ _LT_EOF
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
_LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
@@ -5556,12 +5577,12 @@ _LT_EOF
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
+ # Microsoft Visual C++ or Intel C++ Compiler.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
case $cc_basename in
- cl*)
- # Native MSVC
+ cl* | icl*)
+ # Native MSVC or ICC
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=yes
@@ -5602,7 +5623,7 @@ _LT_EOF
fi'
;;
*)
- # Assume MSVC wrapper
+ # Assume MSVC and ICC wrapper
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Tell ltmain to make .lib files, not .a files.
@@ -5650,7 +5671,7 @@ _LT_EOF
;;
# FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_direct, $1)=yes
@@ -5861,6 +5882,7 @@ _LT_EOF
emximp -o $lib $output_objdir/$libname.def'
_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
;;
osf3*)
@@ -6631,8 +6653,8 @@ if test yes != "$_lt_caught_CXX_error"; then
cygwin* | mingw* | pw32* | cegcc*)
case $GXX,$cc_basename in
- ,cl* | no,cl*)
- # Native MSVC
+ ,cl* | no,cl* | ,icl* | no,icl*)
+ # Native MSVC or ICC
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
@@ -6730,6 +6752,7 @@ if test yes != "$_lt_caught_CXX_error"; then
emximp -o $lib $output_objdir/$libname.def'
_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
;;
dgux*)
@@ -6760,7 +6783,7 @@ if test yes != "$_lt_caught_CXX_error"; then
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
;;
- freebsd* | dragonfly*)
+ freebsd* | dragonfly* | midnightbsd*)
# FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
# conventions
_LT_TAGVAR(ld_shlibs, $1)=yes
@@ -6897,7 +6920,7 @@ if test yes != "$_lt_caught_CXX_error"; then
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
@@ -7037,13 +7060,13 @@ if test yes != "$_lt_caught_CXX_error"; then
_LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
;;
*)
- case `$CC -V 2>&1 | sed 5q` in
+ case `$CC -V 2>&1 | $SED 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
@@ -8189,6 +8212,14 @@ _LT_DECL([], [DLLTOOL], [1], [DLL creation program])
AC_SUBST([DLLTOOL])
])
+# _LT_DECL_FILECMD
+# ----------------
+# Check for a file(cmd) program that can be used to detect file type and magic
+m4_defun([_LT_DECL_FILECMD],
+[AC_CHECK_TOOL([FILECMD], [file], [:])
+_LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types])
+])# _LD_DECL_FILECMD
+
# _LT_DECL_SED
# ------------
# Check for a fully-functional sed program, that truncates
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
index 94b0829..b0b5e9c 100644
--- a/m4/ltoptions.m4
+++ b/m4/ltoptions.m4
@@ -1,7 +1,7 @@
# Helper functions for option handling. -*- Autoconf -*-
#
-# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
-# Foundation, Inc.
+# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free
+# Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
index 48bc934..902508b 100644
--- a/m4/ltsugar.m4
+++ b/m4/ltsugar.m4
@@ -1,6 +1,6 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
-# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
index fa04b52..b155d0a 100644
--- a/m4/ltversion.m4
+++ b/m4/ltversion.m4
@@ -1,6 +1,7 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
-# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation,
+# Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
@@ -9,15 +10,15 @@
# @configure_input@
-# serial 4179 ltversion.m4
+# serial 4245 ltversion.m4
# This file is part of GNU Libtool
-m4_define([LT_PACKAGE_VERSION], [2.4.6])
-m4_define([LT_PACKAGE_REVISION], [2.4.6])
+m4_define([LT_PACKAGE_VERSION], [2.4.7])
+m4_define([LT_PACKAGE_REVISION], [2.4.7])
AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.6'
-macro_revision='2.4.6'
+[macro_version='2.4.7'
+macro_revision='2.4.7'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
index c6b26f8..0f7a875 100644
--- a/m4/lt~obsolete.m4
+++ b/m4/lt~obsolete.m4
@@ -1,7 +1,7 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
-# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
-# Foundation, Inc.
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free
+# Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
diff --git a/m4/pdns_check_libh2o_evloop.m4 b/m4/pdns_check_libh2o_evloop.m4
index 00781ce..43c1122 100644
--- a/m4/pdns_check_libh2o_evloop.m4
+++ b/m4/pdns_check_libh2o_evloop.m4
@@ -1,21 +1,40 @@
-AC_DEFUN([PDNS_CHECK_LIBH2OEVLOOP], [
+AC_DEFUN([PDNS_WITH_LIBH2OEVLOOP], [
+ AC_MSG_CHECKING([whether we will be linking in libh2o-evloop])
HAVE_LIBH2OEVLOOP=0
- PKG_CHECK_MODULES([LIBH2OEVLOOP], [libh2o-evloop], [
- [HAVE_LIBH2OEVLOOP=1]
- AC_DEFINE([HAVE_LIBH2OEVLOOP], [1], [Define to 1 if you have libh2o-evloop])
- save_CFLAGS=$CFLAGS
- save_LIBS=$LIBS
- CFLAGS="$LIBH2OEVLOOP_CFLAGS $CFLAGS"
- LIBS="$LIBH2OEVLOOP_LIBS $LIBS"
- AC_CHECK_DECLS([h2o_socket_get_ssl_server_name], [
+ AC_ARG_WITH([h2o],
+ AS_HELP_STRING([--with-h2o],[use libh2o-evloop @<:@default=no@:>@]),
+ [with_h2o=$withval],
+ [with_h2o=no],
+ )
+ AC_MSG_RESULT([$with_h2o])
+
+ AS_IF([test "x$with_h2o" = "xyes" -o "x$with_h2o" = "xauto"], [
+ PKG_CHECK_MODULES([LIBH2OEVLOOP], [libh2o-evloop], [
+ [HAVE_LIBH2OEVLOOP=1]
+ AC_DEFINE([HAVE_LIBH2OEVLOOP], [1], [Define to 1 if you have libh2o-evloop])
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$LIBH2OEVLOOP_CFLAGS $CFLAGS"
+ LIBS="$LIBH2OEVLOOP_LIBS $LIBS"
+ AC_CHECK_DECLS([h2o_socket_get_ssl_server_name], [
AC_DEFINE([HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME], [1], [define to 1 if h2o_socket_get_ssl_server_name is available.])
],
[ : ],
[AC_INCLUDES_DEFAULT
#include <h2o/socket.h>
])
- CFLAGS=$save_CFLAGS
- LIBS=$save_LIBS
- ], [ : ])
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
+ ], [ : ])
+ ])
AM_CONDITIONAL([HAVE_LIBH2OEVLOOP], [test "x$LIBH2OEVLOOP_LIBS" != "x"])
+ AM_COND_IF([HAVE_LIBH2OEVLOOP], [
+ AC_DEFINE([HAVE_LIBH2OEVLOOP], [1], [Define to 1 if you enable h2o-evloop support])
+ ])
+
+ AS_IF([test "x$with_h2o" = "xyes"], [
+ AS_IF([test x"LIBH2OEVLOOP_LIBS" = "x"], [
+ AC_MSG_ERROR([h2o-evloop requested but libraries were not found])
+ ])
+ ])
])
diff --git a/m4/pdns_check_secure_memset.m4 b/m4/pdns_check_secure_memset.m4
index 4f58219..220eaeb 100644
--- a/m4/pdns_check_secure_memset.m4
+++ b/m4/pdns_check_secure_memset.m4
@@ -1,3 +1,3 @@
AC_DEFUN([PDNS_CHECK_SECURE_MEMSET], [
- AC_CHECK_FUNCS([explicit_bzero explicit_memset])
+ AC_CHECK_FUNCS([explicit_bzero explicit_memset memset_s])
])
diff --git a/m4/pdns_enable_coverage.m4 b/m4/pdns_enable_coverage.m4
new file mode 100644
index 0000000..9e06468
--- /dev/null
+++ b/m4/pdns_enable_coverage.m4
@@ -0,0 +1,32 @@
+AC_DEFUN([PDNS_ENABLE_COVERAGE], [
+ AC_MSG_CHECKING([whether to enable code coverage])
+ AC_ARG_ENABLE([coverage],
+ AS_HELP_STRING([--enable-coverage],
+ [enable code coverage @<:@default=no@:>@]),
+ [enable_coverage=$enableval],
+ [enable_coverage=no]
+ )
+ AC_MSG_RESULT([$enable_coverage])
+
+ AS_IF([test "x$enable_coverage" = "xclang"], [
+ dnl let's see if the clang++ specific format is supported,
+ dnl as it has a much lower overhead and is more accurate,
+ dnl see https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+ gl_COMPILER_OPTION_IF([-fprofile-instr-generate -fcoverage-mapping], [
+ CFLAGS="$CFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping"
+ CXXFLAGS="$CXXFLAGS -DCOVERAGE -DCLANG_COVERAGE -fprofile-instr-generate -fcoverage-mapping"
+ ], [
+ AC_MSG_ERROR([$CXX does not support gathering coverage data in the clang format])
+ ])
+ ])
+
+ AS_IF([test "x$enable_coverage" = "xyes"], [
+ gl_COMPILER_OPTION_IF([-fprofile-arcs -ftest-coverage], [
+ CFLAGS="$CFLAGS -DCOVERAGE --coverage"
+ CXXFLAGS="$CXXFLAGS -DCOVERAGE --coverage"
+ LDFLAGS="$LDFLAGS --coverage"
+ ], [
+ AC_MSG_ERROR([$CXX does not support gathering coverage data])
+ ])
+ ])
+])
diff --git a/m4/pdns_enable_fuzz_targets.m4 b/m4/pdns_enable_fuzz_targets.m4
new file mode 100644
index 0000000..9973fd9
--- /dev/null
+++ b/m4/pdns_enable_fuzz_targets.m4
@@ -0,0 +1,11 @@
+AC_DEFUN([PDNS_ENABLE_FUZZ_TARGETS], [
+ AC_MSG_CHECKING([whether to enable fuzzing targets])
+ AC_ARG_ENABLE([fuzz_targets],
+ AS_HELP_STRING([--enable-fuzz-targets],
+ [enable fuzz targets @<:@default=no@:>@]),
+ [enable_fuzz_targets=$enableval],
+ [enable_fuzz_targets=no]
+ )
+ AC_MSG_RESULT([$enable_fuzz_targets])
+ AM_CONDITIONAL([FUZZ_TARGETS], [test "x$enable_fuzz_targets" != "xno"])
+])
diff --git a/m4/pdns_with_net_snmp.m4 b/m4/pdns_with_net_snmp.m4
index 08ce139..19102b6 100644
--- a/m4/pdns_with_net_snmp.m4
+++ b/m4/pdns_with_net_snmp.m4
@@ -1,9 +1,9 @@
AC_DEFUN([PDNS_WITH_NET_SNMP], [
AC_MSG_CHECKING([if we need to link in Net SNMP])
AC_ARG_WITH([net-snmp],
- AS_HELP_STRING([--with-net-snmp],[enable net snmp support @<:@default=auto@:>@]),
+ AS_HELP_STRING([--with-net-snmp],[enable net snmp support @<:@default=no@:>@]),
[with_net_snmp=$withval],
- [with_net_snmp=auto],
+ [with_net_snmp=no],
)
AC_MSG_RESULT([$with_net_snmp])
diff --git a/m4/pdns_with_nghttp2.m4 b/m4/pdns_with_nghttp2.m4
index 8305b2b..273385c 100644
--- a/m4/pdns_with_nghttp2.m4
+++ b/m4/pdns_with_nghttp2.m4
@@ -13,6 +13,13 @@ AC_DEFUN([PDNS_WITH_NGHTTP2], [
PKG_CHECK_MODULES([NGHTTP2], [libnghttp2], [
[HAVE_NGHTTP2=1]
AC_DEFINE([HAVE_NGHTTP2], [1], [Define to 1 if you have nghttp2])
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$NGHTTP2_CFLAGS $CFLAGS"
+ LIBS="$NGHTTP2_LIBS $LIBS"
+ AC_CHECK_FUNCS([nghttp2_check_header_value_rfc9113 nghttp2_check_method nghttp2_check_path])
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
], [ : ])
])
])
diff --git a/m4/pdns_with_quiche.m4 b/m4/pdns_with_quiche.m4
new file mode 100644
index 0000000..5c3297b
--- /dev/null
+++ b/m4/pdns_with_quiche.m4
@@ -0,0 +1,25 @@
+AC_DEFUN([PDNS_WITH_QUICHE], [
+ AC_MSG_CHECKING([whether we will be linking in quiche])
+ HAVE_QUICHE=0
+ AC_ARG_WITH([quiche],
+ AS_HELP_STRING([--with-quiche],[use quiche @<:@default=auto@:>@]),
+ [with_quiche=$withval],
+ [with_quiche=auto],
+ )
+ AC_MSG_RESULT([$with_quiche])
+
+ AS_IF([test "x$with_quiche" != "xno"], [
+ AS_IF([test "x$with_quiche" = "xyes" -o "x$with_quiche" = "xauto"], [
+ PKG_CHECK_MODULES([QUICHE], [quiche >= 0.15.0], [
+ [HAVE_QUICHE=1]
+ AC_DEFINE([HAVE_QUICHE], [1], [Define to 1 if you have quiche])
+ ], [ : ])
+ ])
+ ])
+ AM_CONDITIONAL([HAVE_QUICHE], [test "x$QUICHE_LIBS" != "x"])
+ AS_IF([test "x$with_quiche" = "xyes"], [
+ AS_IF([test x"$QUICHE_LIBS" = "x"], [
+ AC_MSG_ERROR([quiche requested but libraries were not found])
+ ])
+ ])
+])
diff --git a/m4/pdns_with_xsk.m4 b/m4/pdns_with_xsk.m4
new file mode 100644
index 0000000..a8faf13
--- /dev/null
+++ b/m4/pdns_with_xsk.m4
@@ -0,0 +1,38 @@
+AC_DEFUN([PDNS_WITH_XSK],[
+ AC_MSG_CHECKING([if we have AF_XDP (XSK) support])
+ AC_ARG_WITH([xsk],
+ AS_HELP_STRING([--with-xsk],[enable AF_XDP (XDK) support @<:@default=auto@:>@]),
+ [with_xsk=$withval],
+ [with_xsk=auto],
+ )
+ AC_MSG_RESULT([$with_xsk])
+
+ AS_IF([test "x$with_xsk" != "xno"], [
+ AS_IF([test "x$with_xsk" = "xyes" -o "x$with_xsk" = "xauto"], [
+ PKG_CHECK_MODULES([XDP], [libxdp], [
+ AC_DEFINE([HAVE_XDP], [1], [Define to 1 if you have the XDP library])
+ ], [:])
+ PKG_CHECK_MODULES([BPF], [libbpf], [
+ AC_DEFINE([HAVE_BPF], [1], [Define to 1 if you have the BPF library])
+ save_CFLAGS=$CFLAGS
+ save_LIBS=$LIBS
+ CFLAGS="$BPF_CFLAGS $CFLAGS"
+ LIBS="$BPF_LIBS $LIBS"
+ AC_CHECK_FUNCS([bpf_xdp_query])
+ CFLAGS=$save_CFLAGS
+ LIBS=$save_LIBS
+ ], [:])
+ ])
+ ])
+
+ AM_CONDITIONAL([HAVE_XSK], [test x"$BPF_LIBS" != "x" -a x"$XDP_LIBS" != "x"])
+ AM_COND_IF([HAVE_XSK], [
+ AC_DEFINE([HAVE_XSK], [1], [Define to 1 if you have AF_XDP (XSK) support enabled])
+ ])
+
+ AS_IF([test "x$with_xsk" = "xyes"], [
+ AS_IF([test x"$BPF_LIBS" = "x" -o x"$XDP_LIBS" = "x" ], [
+ AC_MSG_ERROR([AF_XDP (XSK) support requested but required libbpf and/or libxdp were not found])
+ ])
+ ])
+])
diff --git a/misc.cc b/misc.cc
index b28b4a2..b69155d 100644
--- a/misc.cc
+++ b/misc.cc
@@ -56,6 +56,7 @@
#include <boost/format.hpp>
#include "iputils.hh"
#include "dnsparser.hh"
+#include "dns_random.hh"
#include <pwd.h>
#include <grp.h>
#include <climits>
@@ -432,41 +433,46 @@ int waitForMultiData(const set<int>& fds, const int seconds, const int useconds,
}
}
set<int>::const_iterator it(pollinFDs.begin());
- advance(it, random() % pollinFDs.size());
+ advance(it, dns_random(pollinFDs.size()));
*fdOut = *it;
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*fd)
+int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fdPtr)
{
- int ret;
-
- struct pollfd pfds[2];
- memset(&pfds[0], 0, 2*sizeof(struct pollfd));
+ std::array<pollfd,2> 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 + (fd2 >= 0); // fd2 can optionally be -1
+ int nsocks = 1 + static_cast<int>(fd2 >= 0); // fd2 can optionally be -1
- if(seconds >= 0)
- ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000);
- else
- ret = poll(pfds, nsocks, -1);
- if(!ret || ret < 0)
+ 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) && !(pfds[1].revents & POLLIN))
- *fd = pfds[0].fd;
- else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN))
- *fd = pfds[1].fd;
+ 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) {
- *fd = pfds[random()%2].fd;
+ *fdPtr = pfds.at(dns_random_uint32() % 2).fd;
+ }
+ else {
+ *fdPtr = -1; // should never happen
}
- else
- *fd = -1; // should never happen
return 1;
}
@@ -576,17 +582,25 @@ string bitFlip(const string &str)
void cleanSlashes(string &str)
{
- string::const_iterator i;
string out;
- for(i=str.begin();i!=str.end();++i) {
- if(*i=='/' && i!=str.begin() && *(i-1)=='/')
- continue;
- out.append(1,*i);
+ bool keepNextSlash = true;
+ for (const auto& value : str) {
+ if (value == '/') {
+ if (keepNextSlash) {
+ keepNextSlash = false;
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ keepNextSlash = true;
+ }
+ out.append(1, value);
}
- str=out;
+ str = std::move(out);
}
-
bool IpToU32(const string &str, uint32_t *ip)
{
if(str.empty()) {
@@ -847,11 +861,11 @@ bool stringfgets(FILE* fp, std::string& line)
bool readFileIfThere(const char* fname, std::string* line)
{
line->clear();
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(fname, "r"), fclose);
- if (!fp) {
+ auto filePtr = pdns::UniqueFilePtr(fopen(fname, "r"));
+ if (!filePtr) {
return false;
}
- return stringfgets(fp.get(), *line);
+ return stringfgets(filePtr.get(), *line);
}
Regex::Regex(const string &expr)
@@ -1014,7 +1028,7 @@ bool isNonBlocking(int sock)
return flags & O_NONBLOCK;
}
-bool setReceiveSocketErrors(int sock, int af)
+bool setReceiveSocketErrors([[maybe_unused]] int sock, [[maybe_unused]] int af)
{
#ifdef __linux__
int tmp = 1, ret;
@@ -1159,7 +1173,7 @@ int getMACAddress(const ComboAddress& ca, char* dest, size_t destLen)
return foundMAC ? 0 : ENOENT;
}
#else
-int getMACAddress(const ComboAddress& ca, char* dest, size_t len)
+int getMACAddress(const ComboAddress& /* ca */, char* /* dest */, size_t /* len */)
{
return ENOENT;
}
@@ -1175,7 +1189,7 @@ string getMACAddress(const ComboAddress& ca)
return ret;
}
-uint64_t udpErrorStats(const std::string& str)
+uint64_t udpErrorStats([[maybe_unused]] const std::string& str)
{
#ifdef __linux__
ifstream ifs("/proc/net/snmp");
@@ -1217,7 +1231,7 @@ uint64_t udpErrorStats(const std::string& str)
return 0;
}
-uint64_t udp6ErrorStats(const std::string& str)
+uint64_t udp6ErrorStats([[maybe_unused]] const std::string& str)
{
#ifdef __linux__
const std::map<std::string, std::string> keys = {
@@ -1371,30 +1385,29 @@ DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum)
uint64_t getOpenFileDescriptors(const std::string&)
{
#ifdef __linux__
- DIR* dirhdl=opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str());
- if(!dirhdl)
- return 0;
-
- struct dirent *entry;
- int ret=0;
- while((entry = readdir(dirhdl))) {
+ 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;
try {
- pdns::checked_stoi_into(num, entry->d_name);
+ pdns::checked_stoi_into(num, std::string(name));
+ if (std::to_string(num) == name) {
+ nbFileDescriptors++;
+ }
} catch (...) {
- continue; // was not a number.
+ // was not a number.
}
- if(std::to_string(num) == entry->d_name)
- ret++;
+ return true;
+ });
+ if (directoryError) {
+ return 0U;
}
- closedir(dirhdl);
- return ret;
-
+ return nbFileDescriptors;
#elif defined(__OpenBSD__)
// FreeBSD also has this in libopenbsd, but I don't know if that's available always
return getdtablecount();
#else
- return 0;
+ return 0U;
#endif
}
@@ -1545,7 +1558,7 @@ bool isSettingThreadCPUAffinitySupported()
#endif
}
-int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus)
+int mapThreadToCPUList([[maybe_unused]] pthread_t tid, [[maybe_unused]] const std::set<int>& cpus)
{
#ifdef HAVE_PTHREAD_SETAFFINITY_NP
# ifdef __NetBSD__
@@ -1613,7 +1626,7 @@ std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath)
return results;
}
-size_t getPipeBufferSize(int fd)
+size_t getPipeBufferSize([[maybe_unused]] int fd)
{
#ifdef F_GETPIPE_SZ
int res = fcntl(fd, F_GETPIPE_SZ);
@@ -1627,7 +1640,7 @@ size_t getPipeBufferSize(int fd)
#endif /* F_GETPIPE_SZ */
}
-bool setPipeBufferSize(int fd, size_t size)
+bool setPipeBufferSize([[maybe_unused]] int fd, [[maybe_unused]] size_t size)
{
#ifdef F_SETPIPE_SZ
if (size > static_cast<size_t>(std::numeric_limits<int>::max())) {
@@ -1735,3 +1748,57 @@ bool constantTimeStringEquals(const std::string& a, const std::string& b)
#endif /* !HAVE_SODIUM_MEMCMP */
#endif /* !HAVE_CRYPTO_MEMCMP */
}
+
+namespace pdns
+{
+struct CloseDirDeleter
+{
+ void operator()(DIR* dir) const noexcept {
+ closedir(dir);
+ }
+};
+
+std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor)
+{
+ auto dirHandle = std::unique_ptr<DIR, CloseDirDeleter>(opendir(directory.c_str()));
+ if (!dirHandle) {
+ auto err = errno;
+ return std::string("Error opening directory '" + directory + "': " + stringerror(err));
+ }
+
+ bool keepGoing = true;
+ struct dirent* ent = nullptr;
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): readdir is thread-safe nowadays and readdir_r is deprecated
+ while (keepGoing && (ent = readdir(dirHandle.get())) != nullptr) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay: dirent API
+ auto name = std::string_view(ent->d_name, strlen(ent->d_name));
+ keepGoing = visitor(ent->d_ino, name);
+ }
+
+ return std::nullopt;
+}
+
+UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist, bool appendIfExists)
+{
+ int flags = O_WRONLY | O_CREAT;
+ if (mustNotExist) {
+ flags |= O_EXCL;
+ }
+ else if (appendIfExists) {
+ flags |= O_APPEND;
+ }
+ int fileDesc = open(filePath.c_str(), flags, permissions);
+ if (fileDesc == -1) {
+ return {};
+ }
+ auto filePtr = pdns::UniqueFilePtr(fdopen(fileDesc, appendIfExists ? "a" : "w"));
+ if (!filePtr) {
+ auto error = errno;
+ close(fileDesc);
+ errno = error;
+ return {};
+ }
+ return filePtr;
+}
+
+}
diff --git a/misc.hh b/misc.hh
index 8800cd7..76887ee 100644
--- a/misc.hh
+++ b/misc.hh
@@ -49,7 +49,6 @@ class DNSName;
typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
namespace pdns
{
-#if defined(HAVE_LIBCRYPTO)
/**
* \brief Retrieves the errno-based error message in a reentrant way.
*
@@ -63,6 +62,7 @@ namespace pdns
*/
auto getMessageFromErrno(int errnum) -> std::string;
+#if defined(HAVE_LIBCRYPTO)
namespace OpenSSL
{
/**
@@ -131,9 +131,8 @@ stringtok (Container &container, string const &in,
template<typename T> bool rfc1982LessThan(T a, T b)
{
- static_assert(std::is_unsigned<T>::value, "rfc1982LessThan only works for unsigned types");
- typedef typename std::make_signed<T>::type signed_t;
- return static_cast<signed_t>(a - b) < 0;
+ static_assert(std::is_unsigned_v<T>, "rfc1982LessThan only works for unsigned types");
+ return std::make_signed_t<T>(a - b) < 0;
}
// fills container with ranges, so {posbegin,posend}
@@ -414,17 +413,21 @@ struct CIStringCompare
struct CIStringComparePOSIX
{
- bool operator() (const std::string& lhs, const std::string& rhs)
+ bool operator() (const std::string& lhs, const std::string& rhs) const
{
- std::string::const_iterator a,b;
const std::locale &loc = std::locale("POSIX");
- a=lhs.begin();b=rhs.begin();
- while(a!=lhs.end()) {
- if (b==rhs.end() || std::tolower(*b,loc)<std::tolower(*a,loc)) return false;
- else if (std::tolower(*a,loc)<std::tolower(*b,loc)) return true;
- ++a;++b;
+ auto lhsIter = lhs.begin();
+ auto rhsIter = rhs.begin();
+ while (lhsIter != lhs.end()) {
+ if (rhsIter == rhs.end() || std::tolower(*rhsIter,loc) < std::tolower(*lhsIter,loc)) {
+ return false;
+ }
+ if (std::tolower(*lhsIter,loc) < std::tolower(*rhsIter,loc)) {
+ return true;
+ }
+ ++lhsIter;++rhsIter;
}
- return (b!=rhs.end());
+ return rhsIter != rhs.end();
}
};
@@ -616,7 +619,7 @@ T valueOrEmpty(const P val) {
// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
template <typename Integer,
-typename std::enable_if_t<std::is_integral<Integer>::value, bool> = true>
+typename std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
const char* addS(Integer siz, const char* singular = "", const char *plural = "s")
{
if (siz == 1) {
@@ -626,7 +629,7 @@ const char* addS(Integer siz, const char* singular = "", const char *plural = "s
}
template <typename C,
-typename std::enable_if_t<std::is_class<C>::value, bool> = true>
+typename std::enable_if_t<std::is_class_v<C>, bool> = true>
const char* addS(const C& c, const char* singular = "", const char *plural = "s")
{
return addS(c.size(), singular, plural);
@@ -790,10 +793,7 @@ struct FDWrapper
~FDWrapper()
{
- if (d_fd != -1) {
- close(d_fd);
- d_fd = -1;
- }
+ reset();
}
FDWrapper(FDWrapper&& rhs) noexcept : d_fd(rhs.d_fd)
@@ -803,7 +803,7 @@ struct FDWrapper
FDWrapper& operator=(FDWrapper&& rhs) noexcept
{
- if (d_fd != -1) {
+ if (d_fd >= 0) {
close(d_fd);
}
d_fd = rhs.d_fd;
@@ -821,6 +821,37 @@ struct FDWrapper
return d_fd;
}
+ void reset()
+ {
+ if (d_fd >= 0) {
+ close(d_fd);
+ }
+ d_fd = -1;
+ }
+
private:
int d_fd{-1};
};
+
+namespace pdns
+{
+[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
+
+struct FilePtrDeleter
+{
+ /* using a deleter instead of decltype(&fclose) has two big advantages:
+ - the deleter is included in the type and does not have to be passed
+ when creating a new object (easier to use, less memory usage, in theory
+ better inlining)
+ - we avoid the annoying "ignoring attributes on template argument ‘int (*)(FILE*)’"
+ warning from the compiler, which is there because fclose is tagged as __nonnull((1))
+ */
+ void operator()(FILE* filePtr) const noexcept {
+ fclose(filePtr);
+ }
+};
+
+using UniqueFilePtr = std::unique_ptr<FILE, FilePtrDeleter>;
+
+UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false);
+}
diff --git a/missing b/missing
index 625aeb1..1fe1611 100755
--- a/missing
+++ b/missing
@@ -3,7 +3,7 @@
scriptversion=2018-03-07.03; # UTC
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
diff --git a/mplexer.hh b/mplexer.hh
index 70b36d2..0fab107 100644
--- a/mplexer.hh
+++ b/mplexer.hh
@@ -73,8 +73,7 @@ public:
FDMultiplexer() :
d_inrun(false)
{}
- virtual ~FDMultiplexer()
- {}
+ virtual ~FDMultiplexer() = default;
// The maximum number of events processed in a single run, not the maximum of watched descriptors
static constexpr unsigned int s_maxevents = 1024;
@@ -106,7 +105,7 @@ public:
}
/* do the addition _after_ so the entry is not added if there is an error */
- accountingAddFD(d_readCallbacks, fd, toDo, parameter, ttd);
+ accountingAddFD(d_readCallbacks, fd, std::move(toDo), parameter, ttd);
}
//! Add an fd to the write watch list - currently an fd can only be on one list at a time!
@@ -122,7 +121,7 @@ public:
}
/* do the addition _after_ so the entry is not added if there is an error */
- accountingAddFD(d_writeCallbacks, fd, toDo, parameter, ttd);
+ accountingAddFD(d_writeCallbacks, fd, std::move(toDo), parameter, ttd);
}
//! Remove an fd from the read watch list. You can't call this function on an fd that is closed already!
@@ -185,14 +184,14 @@ public:
{
accountingRemoveFD(d_writeCallbacks, fd);
this->alterFD(fd, EventKind::Write, EventKind::Read);
- accountingAddFD(d_readCallbacks, fd, toDo, parameter, ttd);
+ accountingAddFD(d_readCallbacks, fd, std::move(toDo), parameter, ttd);
}
void alterFDToWrite(int fd, callbackfunc_t toDo, const funcparam_t& parameter = funcparam_t(), const struct timeval* ttd = nullptr)
{
accountingRemoveFD(d_readCallbacks, fd);
this->alterFD(fd, EventKind::Read, EventKind::Write);
- accountingAddFD(d_writeCallbacks, fd, toDo, parameter, ttd);
+ accountingAddFD(d_writeCallbacks, fd, std::move(toDo), parameter, ttd);
}
std::vector<std::pair<int, funcparam_t>> getTimeouts(const struct timeval& tv, bool writes = false)
@@ -282,7 +281,7 @@ protected:
{
Callback cb;
cb.d_fd = fd;
- cb.d_callback = toDo;
+ cb.d_callback = std::move(toDo);
cb.d_parameter = parameter;
memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
if (ttd) {
diff --git a/pollmplexer.cc b/pollmplexer.cc
index 8d33123..936c0c5 100644
--- a/pollmplexer.cc
+++ b/pollmplexer.cc
@@ -30,9 +30,6 @@ class PollFDMultiplexer : public FDMultiplexer
public:
PollFDMultiplexer(unsigned int /* maxEventsHint */)
{}
- ~PollFDMultiplexer()
- {
- }
int run(struct timeval* tv, int timeout = 500) override;
void getAvailableFDs(std::vector<int>& fds, int timeout) override;
diff --git a/protozero.cc b/protozero.cc
index 6f6fcf3..e8c1dce 100644
--- a/protozero.cc
+++ b/protozero.cc
@@ -85,7 +85,7 @@ void pdns::ProtoZero::Message::addRRsFromPacket(const char* packet, const size_t
return;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ const dnsheader_aligned dh(packet);
if (ntohs(dh->ancount) == 0) {
return;
diff --git a/protozero.hh b/protozero.hh
index 439d862..8dd49db 100644
--- a/protozero.hh
+++ b/protozero.hh
@@ -37,14 +37,15 @@ namespace pdns {
public:
enum class MetaValueField : protozero::pbf_tag_type { stringVal = 1, intVal = 2 };
+ enum class HTTPVersion : protozero::pbf_tag_type { HTTP1 = 1, HTTP2 = 2, HTTP3 = 3 };
enum class MetaField : protozero::pbf_tag_type { key = 1, value = 2 };
enum class Event : protozero::pbf_tag_type { ts = 1, event = 2, start = 3, boolVal = 4, intVal = 5, stringVal = 6, bytesVal = 7, custom = 8 };
enum class MessageType : int32_t { DNSQueryType = 1, DNSResponseType = 2, DNSOutgoingQueryType = 3, DNSIncomingResponseType = 4 };
- enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23 };
+ enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23, httpVersion = 24 };
enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 };
enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 };
enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 };
- enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 };
+ enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6, DoQ = 7 };
Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer}
{
@@ -63,6 +64,11 @@ namespace pdns {
add_enum(d_message, Field::type, static_cast<int32_t>(mtype));
}
+ void setHTTPVersion(HTTPVersion version)
+ {
+ add_enum(d_message, Field::httpVersion, static_cast<int32_t>(version));
+ }
+
void setMessageIdentity(const boost::uuids::uuid& uniqueId)
{
add_bytes(d_message, Field::messageId, reinterpret_cast<const char*>(uniqueId.begin()), uniqueId.size());
diff --git a/proxy-protocol.hh b/proxy-protocol.hh
index 373a750..a44c721 100644
--- a/proxy-protocol.hh
+++ b/proxy-protocol.hh
@@ -33,6 +33,8 @@ struct ProxyProtocolValue
{
return type == rhs.type && content == rhs.content;
}
+
+ enum class Types : uint8_t { PP_TLV_ALPN = 0x01, PP_TLV_SSL = 0x20 };
};
static const size_t s_proxyProtocolMinimumHeaderSize = 16;
diff --git a/remote_logger.cc b/remote_logger.cc
index 94a8a94..d07a5aa 100644
--- a/remote_logger.cc
+++ b/remote_logger.cc
@@ -134,7 +134,7 @@ bool RemoteLogger::reconnect()
catch (const std::exception& e) {
#ifdef WE_ARE_RECURSOR
SLOG(g_log<<Logger::Warning<<"Error connecting to remote logger "<<d_remote.toStringWithPort()<<": "<<e.what()<<std::endl,
- g_slog->withName("protobuf")->error(Logr::Error, e.what(), "Exception while connection to remote logger", "address", Logging::Loggable(d_remote)));
+ g_slog->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());
#endif
diff --git a/snmp-agent.cc b/snmp-agent.cc
index f00bf6d..a335f31 100644
--- a/snmp-agent.cc
+++ b/snmp-agent.cc
@@ -25,8 +25,7 @@
# include <net-snmp/library/large_fd_set.h>
#endif
-const oid SNMPAgent::snmpTrapOID[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
-const size_t SNMPAgent::snmpTrapOIDLen = OID_LENGTH(SNMPAgent::snmpTrapOID);
+const std::array<oid, 11> SNMPAgent::snmpTrapOID = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
uint64_t value)
@@ -41,32 +40,31 @@ int SNMPAgent::setCounter64Value(netsnmp_request_info* request,
return SNMP_ERR_NOERROR;
}
-bool SNMPAgent::sendTrap(int fd,
+bool SNMPAgent::sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
netsnmp_variable_list* varList)
{
- ssize_t written = write(fd, &varList, sizeof(varList));
-
- if (written != sizeof(varList)) {
- snmp_free_varbind(varList);
+ try {
+ auto obj = std::unique_ptr<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>(varList, snmp_free_varbind);
+ return sender.send(std::move(obj));
+ }
+ catch (...) {
return false;
}
- return true;
}
void SNMPAgent::handleTrapsEvent()
{
- netsnmp_variable_list* varList = nullptr;
- ssize_t got = 0;
-
- do {
- got = read(d_trapPipe[0], &varList, sizeof(varList));
-
- if (got == sizeof(varList)) {
- send_v2trap(varList);
- snmp_free_varbind(varList);
+ try {
+ while (true) {
+ auto obj = d_receiver.receive(snmp_free_varbind);
+ if (!obj) {
+ break;
+ }
+ send_v2trap(obj->get());
}
}
- while (got > 0);
+ catch (const std::exception& e) {
+ }
}
void SNMPAgent::handleSNMPQueryEvent(int fd)
@@ -78,7 +76,7 @@ void SNMPAgent::handleSNMPQueryEvent(int fd)
snmp_read2(&fdset);
}
-void SNMPAgent::handleTrapsCB(int fd, FDMultiplexer::funcparam_t& var)
+void SNMPAgent::handleTrapsCB(int /* fd */, FDMultiplexer::funcparam_t& var)
{
SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
if (!agent || !*agent)
@@ -121,7 +119,7 @@ void SNMPAgent::worker()
/* we want to be notified if a trap is waiting
to be sent */
- mplexer->addReadFD(d_trapPipe[0], &handleTrapsCB, this);
+ mplexer->addReadFD(d_receiver.getDescriptor(), &handleTrapsCB, this);
while(true) {
netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
@@ -161,7 +159,7 @@ void SNMPAgent::worker()
#endif /* HAVE_NET_SNMP */
}
-SNMPAgent::SNMPAgent(const std::string& name, const std::string& daemonSocket)
+SNMPAgent::SNMPAgent([[maybe_unused]] const std::string& name, [[maybe_unused]] const std::string& daemonSocket)
{
#ifdef HAVE_NET_SNMP
netsnmp_enable_subagent();
@@ -187,20 +185,8 @@ SNMPAgent::SNMPAgent(const std::string& name, const std::string& daemonSocket)
init_snmp(name.c_str());
- if (pipe(d_trapPipe) < 0)
- unixDie("Creating pipe");
-
- if (!setNonBlocking(d_trapPipe[0])) {
- close(d_trapPipe[0]);
- close(d_trapPipe[1]);
- unixDie("Setting pipe non-blocking");
- }
-
- if (!setNonBlocking(d_trapPipe[1])) {
- close(d_trapPipe[0]);
- close(d_trapPipe[1]);
- unixDie("Setting pipe non-blocking");
- }
-
+ auto [sender, receiver] = pdns::channel::createObjectQueue<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>();
+ d_sender = std::move(sender);
+ d_receiver = std::move(receiver);
#endif /* HAVE_NET_SNMP */
}
diff --git a/snmp-agent.hh b/snmp-agent.hh
index e4ba134..c75db08 100644
--- a/snmp-agent.hh
+++ b/snmp-agent.hh
@@ -16,6 +16,7 @@
#endif /* HAVE_NET_SNMP */
#include "mplexer.hh"
+#include "channel.hh"
class SNMPAgent
{
@@ -23,11 +24,6 @@ public:
SNMPAgent(const std::string& name, const std::string& daemonSocket);
virtual ~SNMPAgent()
{
-#ifdef HAVE_NET_SNMP
-
- close(d_trapPipe[0]);
- close(d_trapPipe[1]);
-#endif /* HAVE_NET_SNMP */
}
void run()
@@ -45,13 +41,13 @@ public:
protected:
#ifdef HAVE_NET_SNMP
/* OID for snmpTrapOID.0 */
- static const oid snmpTrapOID[];
- static const size_t snmpTrapOIDLen;
+ static const std::array<oid, 11> snmpTrapOID;
- static bool sendTrap(int fd,
+ static bool sendTrap(pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)>& sender,
netsnmp_variable_list* varList);
- int d_trapPipe[2] = { -1, -1};
+ pdns::channel::Sender<netsnmp_variable_list, void(*)(netsnmp_variable_list*)> d_sender;
+ pdns::channel::Receiver<netsnmp_variable_list, void(*)(netsnmp_variable_list*)> d_receiver;
#endif /* HAVE_NET_SNMP */
private:
void worker();
diff --git a/sodcrypto.cc b/sodcrypto.cc
deleted file mode 100644
index b92c6e0..0000000
--- a/sodcrypto.cc
+++ /dev/null
@@ -1,354 +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 <iostream>
-#include "namespaces.hh"
-#include "noinitvector.hh"
-#include "misc.hh"
-#include "base64.hh"
-#include "sodcrypto.hh"
-
-
-#ifdef HAVE_LIBSODIUM
-
-string newKey()
-{
- std::string key;
- key.resize(crypto_secretbox_KEYBYTES);
-
- randombytes_buf(reinterpret_cast<unsigned char*>(&key.at(0)), key.size());
-
- return "\""+Base64Encode(key)+"\"";
-}
-
-bool sodIsValidKey(const std::string& key)
-{
- return key.size() == crypto_secretbox_KEYBYTES;
-}
-
-std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
-{
- if (!sodIsValidKey(key)) {
- throw std::runtime_error("Invalid encryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key");
- }
-
- std::string ciphertext;
- ciphertext.resize(msg.length() + crypto_secretbox_MACBYTES);
- crypto_secretbox_easy(reinterpret_cast<unsigned char*>(&ciphertext.at(0)),
- reinterpret_cast<const unsigned char*>(msg.c_str()),
- msg.length(),
- nonce.value,
- reinterpret_cast<const unsigned char*>(key.c_str()));
-
- nonce.increment();
- return ciphertext;
-}
-
-std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
-{
- std::string decrypted;
-
- if (msg.length() < crypto_secretbox_MACBYTES) {
- throw std::runtime_error("Could not decrypt message of size " + std::to_string(msg.length()));
- }
-
- if (!sodIsValidKey(key)) {
- throw std::runtime_error("Invalid decryption key of size " + std::to_string(key.size()) + ", use setKey() to set a valid key");
- }
-
- decrypted.resize(msg.length() - crypto_secretbox_MACBYTES);
-
- if (crypto_secretbox_open_easy(reinterpret_cast<unsigned char*>(const_cast<char *>(decrypted.data())),
- reinterpret_cast<const unsigned char*>(msg.c_str()),
- msg.length(),
- nonce.value,
- reinterpret_cast<const unsigned char*>(key.c_str())) != 0) {
- throw std::runtime_error("Could not decrypt message, please check that the key configured with setKey() is correct");
- }
-
- nonce.increment();
- return decrypted;
-}
-#else
-std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
-{
- return msg;
-}
-std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce& nonce)
-{
- return msg;
-}
-
-string newKey()
-{
- return "\"plaintext\"";
-}
-
-bool sodIsValidKey(const std::string& key)
-{
- return true;
-}
-
-#endif
-
-
-#include "base64.hh"
-#include <inttypes.h>
-
-namespace anonpdns {
-static char B64Decode1(char cInChar)
-{
- // The incoming character will be A-Z, a-z, 0-9, +, /, or =.
- // The idea is to quickly determine which grouping the
- // letter belongs to and return the associated value
- // without having to search the global encoding string
- // (the value we're looking for would be the resulting
- // index into that string).
- //
- // To do that, we'll play some tricks...
- unsigned char iIndex = '\0';
- switch ( cInChar ) {
- case '+':
- iIndex = 62;
- break;
-
- case '/':
- iIndex = 63;
- break;
-
- case '=':
- iIndex = 0;
- break;
-
- default:
- // Must be 'A'-'Z', 'a'-'z', '0'-'9', or an error...
- //
- // Numerically, small letters are "greater" in value than
- // capital letters and numerals (ASCII value), and capital
- // letters are "greater" than numerals (again, ASCII value),
- // so we check for numerals first, then capital letters,
- // and finally small letters.
- iIndex = '9' - cInChar;
- if ( iIndex > 0x3F ) {
- // Not from '0' to '9'...
- iIndex = 'Z' - cInChar;
- if ( iIndex > 0x3F ) {
- // Not from 'A' to 'Z'...
- iIndex = 'z' - cInChar;
- if ( iIndex > 0x3F ) {
- // Invalid character...cannot
- // decode!
- iIndex = 0x80; // set the high bit
- } // if
- else {
- // From 'a' to 'z'
- iIndex = (('z' - iIndex) - 'a') + 26;
- } // else
- } // if
- else {
- // From 'A' to 'Z'
- iIndex = ('Z' - iIndex) - 'A';
- } // else
- } // if
- else {
- // Adjust the index...
- iIndex = (('9' - iIndex) - '0') + 52;
- } // else
- break;
-
- } // switch
-
- return iIndex;
-}
-
-static inline char B64Encode1(unsigned char uc)
-{
- if (uc < 26)
- {
- return 'A'+uc;
- }
- if (uc < 52)
- {
- return 'a'+(uc-26);
- }
- if (uc < 62)
- {
- return '0'+(uc-52);
- }
- if (uc == 62)
- {
- return '+';
- }
- return '/';
-};
-
-
-
-}
-using namespace anonpdns;
-
-template<typename Container> int B64Decode(const std::string& strInput, Container& strOutput)
-{
- // Set up a decoding buffer
- long cBuf = 0;
- char* pBuf = (char*)&cBuf;
-
- // Decoding management...
- int iBitGroup = 0, iInNum = 0;
-
- // While there are characters to process...
- //
- // We'll decode characters in blocks of 4, as
- // there are 4 groups of 6 bits in 3 bytes. The
- // incoming Base64 character is first decoded, and
- // then it is inserted into the decode buffer
- // (with any relevant shifting, as required).
- // Later, after all 3 bytes have been reconstituted,
- // we assign them to the output string, ultimately
- // to be returned as the original message.
- int iInSize = strInput.size();
- unsigned char cChar = '\0';
- uint8_t pad = 0;
- while ( iInNum < iInSize ) {
- // Fill the decode buffer with 4 groups of 6 bits
- cBuf = 0; // clear
- pad = 0;
- for ( iBitGroup = 0; iBitGroup < 4; ++iBitGroup ) {
- if ( iInNum < iInSize ) {
- // Decode a character
- if(strInput.at(iInNum)=='=')
- pad++;
- while(isspace(strInput.at(iInNum)))
- iInNum++;
- cChar = B64Decode1(strInput.at(iInNum++));
-
- } // if
- else {
- // Decode a padded zero
- cChar = '\0';
- } // else
-
- // Check for valid decode
- if ( cChar > 0x7F )
- return -1;
-
- // Adjust the bits
- switch ( iBitGroup ) {
- case 0:
- // The first group is copied into
- // the least significant 6 bits of
- // the decode buffer...these 6 bits
- // will eventually shift over to be
- // the most significant bits of the
- // third byte.
- cBuf = cBuf | cChar;
- break;
-
- default:
- // For groupings 1-3, simply shift
- // the bits in the decode buffer over
- // by 6 and insert the 6 from the
- // current decode character.
- cBuf = (cBuf << 6) | cChar;
- break;
-
- } // switch
- } // for
-
- // Interpret the resulting 3 bytes...note there
- // may have been padding, so those padded bytes
- // are actually ignored.
-#if BYTE_ORDER == BIG_ENDIAN
- strOutput.push_back(pBuf[sizeof(long)-3]);
- strOutput.push_back(pBuf[sizeof(long)-2]);
- strOutput.push_back(pBuf[sizeof(long)-1]);
-#else
- strOutput.push_back(pBuf[2]);
- strOutput.push_back(pBuf[1]);
- strOutput.push_back(pBuf[0]);
-#endif
- } // while
- if(pad)
- strOutput.resize(strOutput.size()-pad);
-
- return 1;
-}
-
-template int B64Decode<std::vector<uint8_t>>(const std::string& strInput, std::vector<uint8_t>& strOutput);
-template int B64Decode<PacketBuffer>(const std::string& strInput, PacketBuffer& strOutput);
-template int B64Decode<std::string>(const std::string& strInput, std::string& strOutput);
-
-/*
-www.kbcafe.com
-Copyright 2001-2002 Randy Charles Morin
-The Encode static method takes an array of 8-bit values and returns a base-64 stream.
-*/
-
-
-std::string Base64Encode (const std::string& vby)
-{
- std::string retval;
- if (vby.size () == 0)
- {
- return retval;
- };
- for (unsigned int i = 0; i < vby.size (); i += 3)
- {
- unsigned char by1 = 0, by2 = 0, by3 = 0;
- by1 = vby[i];
- if (i + 1 < vby.size ())
- {
- by2 = vby[i + 1];
- };
- if (i + 2 < vby.size ())
- {
- by3 = vby[i + 2];
- }
- unsigned char by4 = 0, by5 = 0, by6 = 0, by7 = 0;
- by4 = by1 >> 2;
- by5 = ((by1 & 0x3) << 4) | (by2 >> 4);
- by6 = ((by2 & 0xf) << 2) | (by3 >> 6);
- by7 = by3 & 0x3f;
- retval += B64Encode1 (by4);
- retval += B64Encode1 (by5);
- if (i + 1 < vby.size ())
- {
- retval += B64Encode1 (by6);
- }
- else
- {
- retval += "=";
- };
- if (i + 2 < vby.size ())
- {
- retval += B64Encode1 (by7);
- }
- else
- {
- retval += "=";
- };
- /* if ((i % (76 / 4 * 3)) == 0)
- {
- retval += "\r\n";
- }*/
- };
- return retval;
-};
diff --git a/sodcrypto.hh b/sodcrypto.hh
deleted file mode 100644
index ca35631..0000000
--- a/sodcrypto.hh
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-#include "config.h"
-#include <string>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#ifndef HAVE_LIBSODIUM
-struct SodiumNonce
-{
- void init(){};
- void merge(const SodiumNonce& lower, const SodiumNonce& higher) {};
- void increment(){};
- unsigned char value[1]{0};
-};
-#else
-#include <sodium.h>
-
-struct SodiumNonce
-{
- SodiumNonce()
- {
- memset(&value, 0, sizeof(value));
- }
-
- void init()
- {
- randombytes_buf(value, sizeof value);
- }
-
- void merge(const SodiumNonce& lower, const SodiumNonce& higher)
- {
- static const size_t halfSize = (sizeof value) / 2;
- memcpy(value, lower.value, halfSize);
- memcpy(value + halfSize, higher.value + halfSize, halfSize);
- }
-
- void increment()
- {
- uint32_t* p = (uint32_t*)value;
- uint32_t count=htonl(*p);
- *p=ntohl(++count);
- }
-
- string toString() const
- {
- return string((const char*)value, crypto_secretbox_NONCEBYTES);
- }
-
- unsigned char value[crypto_secretbox_NONCEBYTES];
-};
-#endif
-std::string newKeypair();
-std::string sodEncryptSym(const std::string& msg, const std::string& key, SodiumNonce&);
-std::string sodDecryptSym(const std::string& msg, const std::string& key, SodiumNonce&);
-std::string newKey();
-bool sodIsValidKey(const std::string& key);
diff --git a/sstuff.hh b/sstuff.hh
index 208697c..88f6809 100644
--- a/sstuff.hh
+++ b/sstuff.hh
@@ -38,9 +38,9 @@
#include <boost/utility.hpp>
#include <csignal>
#include "namespaces.hh"
+#include "noinitvector.hh"
-
-typedef int ProtocolType; //!< Supported protocol types
+using ProtocolType = int; //!< Supported protocol types
//! Representation of a Socket and many of the Berkeley functions available
class Socket : public boost::noncopyable
@@ -58,12 +58,13 @@ public:
setCloseOnExec(d_socket);
}
- Socket(Socket&& rhs): d_buffer(std::move(rhs.d_buffer)), d_socket(rhs.d_socket)
+ Socket(Socket&& rhs) noexcept :
+ d_buffer(std::move(rhs.d_buffer)), d_socket(rhs.d_socket)
{
rhs.d_socket = -1;
}
- Socket& operator=(Socket&& rhs)
+ Socket& operator=(Socket&& rhs) noexcept
{
if (d_socket != -1) {
close(d_socket);
@@ -173,57 +174,64 @@ public:
/** For datagram sockets, receive a datagram and learn where it came from
\param dgram Will be filled with the datagram
\param ep Will be filled with the origin of the datagram */
- void recvFrom(string &dgram, ComboAddress &ep)
+ void recvFrom(string &dgram, ComboAddress& remote)
{
- socklen_t remlen = sizeof(ep);
- ssize_t bytes;
- d_buffer.resize(s_buflen);
- if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&ep) , &remlen)) <0)
- throw NetworkError("After recvfrom: "+stringerror());
-
- dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
+ socklen_t remlen = sizeof(remote);
+ if (dgram.size() < s_buflen) {
+ dgram.resize(s_buflen);
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote) , &remlen);
+ if (bytes < 0) {
+ throw NetworkError("After recvfrom: " + stringerror());
+ }
+ dgram.resize(static_cast<size_t>(bytes));
}
- bool recvFromAsync(string &dgram)
+ bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote)
{
- struct sockaddr_in remote;
socklen_t remlen = sizeof(remote);
- ssize_t bytes;
- d_buffer.resize(s_buflen);
- if((bytes=recvfrom(d_socket, &d_buffer[0], s_buflen, 0, reinterpret_cast<sockaddr *>(&remote), &remlen))<0) {
- if(errno!=EAGAIN) {
- throw NetworkError("After async recvfrom: "+stringerror());
+ if (dgram.size() < s_buflen) {
+ dgram.resize(s_buflen);
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto bytes = recvfrom(d_socket, dgram.data(), dgram.size(), 0, reinterpret_cast<sockaddr *>(&remote), &remlen);
+ if (bytes < 0) {
+ if (errno != EAGAIN) {
+ throw NetworkError("After async recvfrom: " + stringerror());
}
else {
return false;
}
}
- dgram.assign(d_buffer, 0, static_cast<size_t>(bytes));
+ dgram.resize(static_cast<size_t>(bytes));
return true;
}
-
//! For datagram sockets, send a datagram to a destination
- void sendTo(const char* msg, size_t len, const ComboAddress &ep)
+ void sendTo(const char* msg, size_t len, const ComboAddress& remote)
{
- if(sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&ep), ep.getSocklen())<0)
- throw NetworkError("After sendto: "+stringerror());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr *>(&remote), remote.getSocklen()) < 0) {
+ throw NetworkError("After sendto: " + stringerror());
+ }
}
//! For connected datagram sockets, send a datagram
void send(const std::string& msg)
{
- if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
+ if (::send(d_socket, msg.data(), msg.size(), 0) < 0) {
throw NetworkError("After send: "+stringerror());
+ }
}
/** For datagram sockets, send a datagram to a destination
\param dgram The datagram
- \param ep The intended destination of the datagram */
- void sendTo(const string &dgram, const ComboAddress &ep)
+ \param remote The intended destination of the datagram */
+ void sendTo(const string& dgram, const ComboAddress& remote)
{
- sendTo(dgram.c_str(), dgram.length(), ep);
+ sendTo(dgram.data(), dgram.length(), remote);
}
diff --git a/standalone_fuzz_target_runner.cc b/standalone_fuzz_target_runner.cc
new file mode 100644
index 0000000..0ca9106
--- /dev/null
+++ b/standalone_fuzz_target_runner.cc
@@ -0,0 +1,52 @@
+#include <cstdint>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <sys/stat.h>
+#include <vector>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+extern "C" __attribute__((weak)) int LLVMFuzzerInitialize(int* argc, char*** argv);
+
+int main(int argc, char** argv)
+{
+ std::cerr<<"StandaloneFuzzTargetMain: running "<<(argc-1)<<" inputs"<<std::endl;
+
+ if (LLVMFuzzerInitialize) {
+ LLVMFuzzerInitialize(&argc, &argv);
+ }
+
+ for (int i = 1; i < argc; i++) {
+
+ struct stat st;
+ if (stat(argv[i], &st) || !S_ISREG(st.st_mode)) {
+ std::cerr<<"Skipping non-regular file: "<<std::string(argv[i])<<std::endl;
+ continue;
+ }
+
+ std::cerr<<"Running: "<<std::string(argv[i])<<std::endl;
+
+ std::ifstream file(argv[i], std::ios::binary);
+ file.seekg(0, std::ios::end);
+ size_t fileSize = file.tellg();
+ file.seekg(0, std::ios::beg);
+
+ std::vector<char> buffer;
+ buffer.resize(fileSize);
+
+ file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
+
+ if (file.fail()) {
+ file.close();
+ throw std::runtime_error("Error reading fuzzing input from file '" + std::string(argv[i]) + '"');
+ }
+
+ file.close();
+
+ LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(buffer.data()), fileSize);
+
+ std::cerr<<"Done: '"<<std::string(argv[i])<<"': ("<<fileSize<<" bytes)"<<std::endl;
+ }
+
+ return 0;
+}
diff --git a/stat_t.hh b/stat_t.hh
index 389a626..d339cec 100644
--- a/stat_t.hh
+++ b/stat_t.hh
@@ -71,7 +71,7 @@ namespace pdns {
}
private:
- typename std::aligned_storage<sizeof(base_t), CPU_LEVEL1_DCACHE_LINESIZE>::type counter;
+ typename std::aligned_storage_t<sizeof(base_t), CPU_LEVEL1_DCACHE_LINESIZE> counter;
};
typedef stat_t_trait<uint64_t> stat_t;
diff --git a/statnode.cc b/statnode.cc
index a2b4934..898c221 100644
--- a/statnode.cc
+++ b/statnode.cc
@@ -35,8 +35,7 @@ StatNode::Stat StatNode::print(unsigned int depth, Stat newstat, bool silent) co
return newstat;
}
-
-void StatNode::visit(visitor_t visitor, Stat &newstat, unsigned int depth) const
+void StatNode::visit(const visitor_t& visitor, Stat& newstat, unsigned int depth) const
{
Stat childstat(s);
@@ -49,8 +48,7 @@ void StatNode::visit(visitor_t visitor, Stat &newstat, unsigned int depth) const
newstat += childstat;
}
-
-void StatNode::submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, boost::optional<const ComboAddress&> remote)
+void StatNode::submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, const boost::optional<const ComboAddress&>& remote)
{
// cerr<<"FIRST submit called on '"<<domain<<"'"<<endl;
std::vector<string> tmp = domain.getRawLabels();
@@ -69,7 +67,7 @@ void StatNode::submit(const DNSName& domain, int rcode, unsigned int bytes, bool
www.powerdns.com.
*/
-void StatNode::submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, boost::optional<const ComboAddress&> remote, unsigned int count, bool hit)
+void StatNode::submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, const boost::optional<const ComboAddress&>& remote, unsigned int count, bool hit)
{
// cerr<<"Submit called for domain='"<<domain<<"': ";
// for(const std::string& n : labels)
diff --git a/statnode.hh b/statnode.hh
index 4f95905..18c17c2 100644
--- a/statnode.hh
+++ b/statnode.hh
@@ -30,10 +30,7 @@ public:
struct Stat
{
- Stat()
- {
- }
-
+ Stat() {};
uint64_t queries{0};
uint64_t noerrors{0};
uint64_t nxdomains{0};
@@ -68,9 +65,9 @@ public:
std::string fullname;
uint8_t labelsCount{0};
- void submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, boost::optional<const ComboAddress&> remote);
+ void submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, const boost::optional<const ComboAddress&>& remote);
Stat print(unsigned int depth=0, Stat newstat=Stat(), bool silent=false) const;
- void visit(visitor_t visitor, Stat& newstat, unsigned int depth=0) const;
+ void visit(const visitor_t& visitor, Stat& newstat, unsigned int depth = 0) const;
bool empty() const
{
return children.empty() && s.remotes.empty();
@@ -78,5 +75,5 @@ public:
children_t children;
private:
- void submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, boost::optional<const ComboAddress&> remote, unsigned int count, bool hit);
+ void submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, const boost::optional<const ComboAddress&>& remote, unsigned int count, bool hit);
};
diff --git a/tcpiohandler-mplexer.hh b/tcpiohandler-mplexer.hh
index d62ba78..a69c7c1 100644
--- a/tcpiohandler-mplexer.hh
+++ b/tcpiohandler-mplexer.hh
@@ -128,11 +128,11 @@ public:
if (isWaitingForWrite()) {
d_isWaitingForWrite = false;
- d_mplexer.alterFDToRead(d_fd, callback, callbackData, ttd ? &*ttd : nullptr);
+ d_mplexer.alterFDToRead(d_fd, std::move(callback), callbackData, ttd ? &*ttd : nullptr);
DEBUGLOG(__PRETTY_FUNCTION__<<": alter from write to read FD "<<d_fd);
}
else {
- d_mplexer.addReadFD(d_fd, callback, callbackData, ttd ? &*ttd : nullptr);
+ d_mplexer.addReadFD(d_fd, std::move(callback), callbackData, ttd ? &*ttd : nullptr);
DEBUGLOG(__PRETTY_FUNCTION__<<": add read FD "<<d_fd);
}
@@ -149,11 +149,11 @@ public:
if (isWaitingForRead()) {
d_isWaitingForRead = false;
- d_mplexer.alterFDToWrite(d_fd, callback, callbackData, ttd ? &*ttd : nullptr);
+ d_mplexer.alterFDToWrite(d_fd, std::move(callback), callbackData, ttd ? &*ttd : nullptr);
DEBUGLOG(__PRETTY_FUNCTION__<<": alter from read to write FD "<<d_fd);
}
else {
- d_mplexer.addWriteFD(d_fd, callback, callbackData, ttd ? &*ttd : nullptr);
+ d_mplexer.addWriteFD(d_fd, std::move(callback), callbackData, ttd ? &*ttd : nullptr);
DEBUGLOG(__PRETTY_FUNCTION__<<": add write FD "<<d_fd);
}
diff --git a/tcpiohandler.cc b/tcpiohandler.cc
index 72c149b..cf82471 100644
--- a/tcpiohandler.cc
+++ b/tcpiohandler.cc
@@ -11,7 +11,7 @@ const bool TCPIOHandler::s_disableConnectForUnitTests = false;
#include <sodium.h>
#endif /* HAVE_LIBSODIUM */
-#ifdef HAVE_DNS_OVER_TLS
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
#ifdef HAVE_LIBSSL
#include <openssl/conf.h>
@@ -52,7 +52,7 @@ public:
OpenSSLTLSTicketKeysRing d_ticketKeys;
std::map<int, std::string> d_ocspResponses;
std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> d_tlsCtx{nullptr, SSL_CTX_free};
- std::unique_ptr<FILE, int(*)(FILE*)> d_keyLogFile{nullptr, fclose};
+ pdns::UniqueFilePtr d_keyLogFile{nullptr};
};
class OpenSSLSession : public TLSSession
@@ -62,10 +62,6 @@ public:
{
}
- virtual ~OpenSSLSession()
- {
- }
-
std::unique_ptr<SSL_SESSION, void(*)(SSL_SESSION*)> getNative()
{
return std::move(d_sess);
@@ -79,7 +75,7 @@ class OpenSSLTLSConnection: public TLSConnection
{
public:
/* server side connection */
- OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<OpenSSLFrontendContext> feContext): d_feContext(feContext), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(d_feContext->d_tlsCtx.get()), SSL_free)), d_timeout(timeout)
+ OpenSSLTLSConnection(int socket, const struct timeval& timeout, std::shared_ptr<OpenSSLFrontendContext> feContext): d_feContext(std::move(feContext)), d_conn(std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(d_feContext->d_tlsCtx.get()), SSL_free)), d_timeout(timeout)
{
d_socket = socket;
@@ -133,7 +129,7 @@ public:
#endif
}
else {
-#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && HAVE_SSL_SET_HOSTFLAGS // grrr libressl
+#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && defined(HAVE_SSL_SET_HOSTFLAGS) // grrr libressl
SSL_set_hostflags(d_conn.get(), X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
if (SSL_set1_host(d_conn.get(), d_hostname.c_str()) != 1) {
throw std::runtime_error("Error setting TLS hostname for certificate validation");
@@ -432,15 +428,6 @@ public:
return got;
}
- bool hasBufferedData() const override
- {
- if (d_conn) {
- return SSL_pending(d_conn.get()) > 0;
- }
-
- return false;
- }
-
bool isUsable() const override
{
if (!d_conn) {
@@ -629,6 +616,10 @@ public:
}
#endif /* DISABLE_OCSP_STAPLING */
+ if (fe.d_tlsConfig.d_readAhead) {
+ SSL_CTX_set_read_ahead(d_feContext->d_tlsCtx.get(), 1);
+ }
+
libssl_set_error_counters_callback(d_feContext->d_tlsCtx, &fe.d_tlsCounters);
if (!fe.d_tlsConfig.d_keyLogFile.empty()) {
@@ -822,7 +813,7 @@ public:
}
}
- void loadTicketsKeys(const std::string& keyFile) override final
+ void loadTicketsKeys(const std::string& keyFile) final
{
d_feContext->d_ticketKeys.loadTicketsKeys(keyFile);
@@ -866,7 +857,7 @@ public:
private:
/* called in a client context, if the client advertised more than one ALPN values and the server returned more than one as well, to select the one to use. */
#ifndef DISABLE_NPN
- static int npnSelectCallback(SSL* s, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
+ static int npnSelectCallback(SSL* /* s */, unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg)
{
if (!arg) {
return SSL_TLSEXT_ERR_ALERT_WARNING;
@@ -885,25 +876,28 @@ private:
if (!arg) {
return SSL_TLSEXT_ERR_ALERT_WARNING;
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
OpenSSLTLSIOCtx* obj = reinterpret_cast<OpenSSLTLSIOCtx*>(arg);
- size_t pos = 0;
- while (pos < inlen) {
- size_t protoLen = in[pos];
- pos++;
- if (protoLen > (inlen - pos)) {
- /* something is very wrong */
- return SSL_TLSEXT_ERR_ALERT_WARNING;
- }
+ const pdns::views::UnsignedCharView inView(in, inlen);
+ // Server preference algorithm as per RFC 7301 section 3.2
+ for (const auto& tentative : obj->d_alpnProtos) {
+ size_t pos = 0;
+ while (pos < inView.size()) {
+ size_t protoLen = inView.at(pos);
+ pos++;
+ if (protoLen > (inlen - pos)) {
+ /* something is very wrong */
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
- for (const auto& tentative : obj->d_alpnProtos) {
- if (tentative.size() == protoLen && memcmp(in + pos, tentative.data(), tentative.size()) == 0) {
- *out = in + pos;
+ if (tentative.size() == protoLen && memcmp(&inView.at(pos), tentative.data(), tentative.size()) == 0) {
+ *out = &inView.at(pos);
*outlen = protoLen;
return SSL_TLSEXT_ERR_OK;
}
+ pos += protoLen;
}
- pos += protoLen;
}
return SSL_TLSEXT_ERR_NOACK;
@@ -1020,7 +1014,7 @@ public:
sess.size = 0;
}
- virtual ~GnuTLSSession()
+ ~GnuTLSSession() override
{
if (d_sess.data != nullptr && d_sess.size > 0) {
safe_memory_release(d_sess.data, d_sess.size);
@@ -1115,7 +1109,7 @@ public:
gnutls_handshake_set_timeout(d_conn.get(), timeout.tv_sec * 1000 + timeout.tv_usec / 1000);
gnutls_record_set_timeout(d_conn.get(), timeout.tv_sec * 1000 + timeout.tv_usec / 1000);
-#if HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
+#ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
if (validateCerts && !d_host.empty()) {
gnutls_session_set_verify_cert(d_conn.get(), d_host.c_str(), GNUTLS_VERIFY_ALLOW_UNSORTED_CHAIN);
rc = gnutls_server_name_set(d_conn.get(), GNUTLS_NAME_DNS, d_host.c_str(), d_host.size());
@@ -1134,9 +1128,9 @@ public:
/* The callback prototype changed in 3.4.0. */
#if GNUTLS_VERSION_NUMBER >= 0x030400
- static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int incoming, const gnutls_datum_t* msg)
+ static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int /* incoming */, const gnutls_datum_t* /* msg */)
#else
- static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int incoming)
+ static int newTicketFromServerCb(gnutls_session_t session, unsigned int htype, unsigned post, unsigned int /* incoming */)
#endif /* GNUTLS_VERSION_NUMBER >= 0x030400 */
{
if (htype != GNUTLS_HANDSHAKE_NEW_SESSION_TICKET || post != GNUTLS_HOOK_POST || session == nullptr) {
@@ -1158,7 +1152,7 @@ public:
return 0;
}
- IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
+ IOState tryConnect(bool fastOpen, [[maybe_unused]] const ComboAddress& remote) override
{
int ret = 0;
@@ -1263,7 +1257,7 @@ public:
else if (gnutls_error_is_fatal(ret) || ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
if (d_client) {
std::string error;
-#if HAVE_GNUTLS_SESSION_GET_VERIFY_CERT_STATUS
+#ifdef HAVE_GNUTLS_SESSION_GET_VERIFY_CERT_STATUS
if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
gnutls_datum_t out;
if (gnutls_certificate_verification_status_print(gnutls_session_get_verify_cert_status(d_conn.get()), gnutls_certificate_type_get(d_conn.get()), &out, 0) == 0) {
@@ -1314,7 +1308,7 @@ public:
else if (res == GNUTLS_E_AGAIN) {
return IOState::NeedWrite;
}
- warnlog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res));
+ vinfolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res));
}
}
while (pos < toWrite);
@@ -1350,7 +1344,7 @@ public:
else if (res == GNUTLS_E_AGAIN) {
return IOState::NeedRead;
}
- warnlog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res));
+ vinfolog("Warning, non-fatal error while writing to TLS connection: %s", gnutls_strerror(res));
}
}
while (pos < toRead);
@@ -1440,15 +1434,6 @@ public:
return got;
}
- bool hasBufferedData() const override
- {
- if (d_conn) {
- return gnutls_record_check_pending(d_conn.get()) > 0;
- }
-
- return false;
- }
-
bool isUsable() const override
{
if (!d_conn) {
@@ -1678,7 +1663,7 @@ public:
}
}
- virtual ~GnuTLSIOCtx() override
+ ~GnuTLSIOCtx() override
{
d_creds.reset();
@@ -1754,7 +1739,7 @@ public:
auto newKey = std::make_shared<GnuTLSTicketsKey>();
{
- *(d_ticketsKey.write_lock()) = newKey;
+ *(d_ticketsKey.write_lock()) = std::move(newKey);
}
if (d_ticketsKeyRotationDelay > 0) {
@@ -1762,7 +1747,7 @@ public:
}
}
- void loadTicketsKeys(const std::string& file) override final
+ void loadTicketsKeys(const std::string& file) final
{
if (!d_enableTickets) {
return;
@@ -1770,7 +1755,7 @@ public:
auto newKey = std::make_shared<GnuTLSTicketsKey>(file);
{
- *(d_ticketsKey.write_lock()) = newKey;
+ *(d_ticketsKey.write_lock()) = std::move(newKey);
}
if (d_ticketsKeyRotationDelay > 0) {
@@ -1811,7 +1796,7 @@ private:
#endif /* HAVE_GNUTLS */
-#endif /* HAVE_DNS_OVER_TLS */
+#endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
{
@@ -1824,67 +1809,85 @@ bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
return true;
}
+bool setupDoHProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx)
+{
+ if (ctx == nullptr) {
+ return false;
+ }
+ /* This code is only called for incoming/server TLS contexts (not outgoing/client),
+ and h2o sets it own ALPN values.
+ We want to set the ALPN for DoH:
+ - HTTP/1.1 so that the OpenSSL callback ALPN accepts it, letting us later return a static response
+ - HTTP/2
+ */
+ const std::vector<std::vector<uint8_t>> dohAlpns{{'h', '2'},{'h', 't', 't', 'p', '/', '1', '.', '1'}};
+ ctx->setALPNProtos(dohAlpns);
+
+ return true;
+}
+
bool TLSFrontend::setupTLS()
{
-#ifdef HAVE_DNS_OVER_TLS
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
std::shared_ptr<TLSCtx> newCtx{nullptr};
/* get the "best" available provider */
- if (!d_provider.empty()) {
-#ifdef HAVE_GNUTLS
- if (d_provider == "gnutls") {
- newCtx = std::make_shared<GnuTLSIOCtx>(*this);
- setupDoTProtocolNegotiation(newCtx);
- std::atomic_store_explicit(&d_ctx, newCtx, std::memory_order_release);
- return true;
- }
-#endif /* HAVE_GNUTLS */
-#ifdef HAVE_LIBSSL
- if (d_provider == "openssl") {
- newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
- setupDoTProtocolNegotiation(newCtx);
- std::atomic_store_explicit(&d_ctx, newCtx, std::memory_order_release);
- return true;
- }
-#endif /* HAVE_LIBSSL */
+#if defined(HAVE_GNUTLS)
+ if (d_provider == "gnutls") {
+ newCtx = std::make_shared<GnuTLSIOCtx>(*this);
}
-#ifdef HAVE_LIBSSL
- newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
-#else /* HAVE_LIBSSL */
-#ifdef HAVE_GNUTLS
- newCtx = std::make_shared<GnuTLSIOCtx>(*this);
#endif /* HAVE_GNUTLS */
+#if defined(HAVE_LIBSSL)
+ if (d_provider == "openssl") {
+ newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+ }
#endif /* HAVE_LIBSSL */
- setupDoTProtocolNegotiation(newCtx);
- std::atomic_store_explicit(&d_ctx, newCtx, std::memory_order_release);
-#endif /* HAVE_DNS_OVER_TLS */
+ if (!newCtx) {
+#if defined(HAVE_LIBSSL)
+ newCtx = std::make_shared<OpenSSLTLSIOCtx>(*this);
+#elif defined(HAVE_GNUTLS)
+ newCtx = std::make_shared<GnuTLSIOCtx>(*this);
+#else
+#error "TLS support needed but neither libssl nor GnuTLS were selected"
+#endif
+ }
+
+ if (d_alpn == ALPN::DoT) {
+ setupDoTProtocolNegotiation(newCtx);
+ }
+ else if (d_alpn == ALPN::DoH) {
+ setupDoHProtocolNegotiation(newCtx);
+ }
+
+ std::atomic_store_explicit(&d_ctx, std::move(newCtx), std::memory_order_release);
+#endif /* HAVE_DNS_OVER_TLS || HAVE_DNS_OVER_HTTPS */
return true;
}
-std::shared_ptr<TLSCtx> getTLSContext(const TLSContextParameters& params)
+std::shared_ptr<TLSCtx> getTLSContext([[maybe_unused]] const TLSContextParameters& params)
{
#ifdef HAVE_DNS_OVER_TLS
/* get the "best" available provider */
if (!params.d_provider.empty()) {
-#ifdef HAVE_GNUTLS
+#if defined(HAVE_GNUTLS)
if (params.d_provider == "gnutls") {
return std::make_shared<GnuTLSIOCtx>(params);
}
#endif /* HAVE_GNUTLS */
-#ifdef HAVE_LIBSSL
+#if defined(HAVE_LIBSSL)
if (params.d_provider == "openssl") {
return std::make_shared<OpenSSLTLSIOCtx>(params);
}
#endif /* HAVE_LIBSSL */
}
-#ifdef HAVE_LIBSSL
+#if defined(HAVE_LIBSSL)
return std::make_shared<OpenSSLTLSIOCtx>(params);
-#else /* HAVE_LIBSSL */
-#ifdef HAVE_GNUTLS
+#elif defined(HAVE_GNUTLS)
return std::make_shared<GnuTLSIOCtx>(params);
-#endif /* HAVE_GNUTLS */
-#endif /* HAVE_LIBSSL */
+#else
+#error "DNS over TLS support needed but neither libssl nor GnuTLS were selected"
+#endif
#endif /* HAVE_DNS_OVER_TLS */
return nullptr;
diff --git a/tcpiohandler.hh b/tcpiohandler.hh
index 88f0dc7..058d104 100644
--- a/tcpiohandler.hh
+++ b/tcpiohandler.hh
@@ -15,15 +15,13 @@ enum class IOState : uint8_t { Done, NeedRead, NeedWrite, Async };
class TLSSession
{
public:
- virtual ~TLSSession()
- {
- }
+ virtual ~TLSSession() = default;
};
class TLSConnection
{
public:
- virtual ~TLSConnection() { }
+ virtual ~TLSConnection() = default;
virtual void doHandshake() = 0;
virtual IOState tryConnect(bool fastOpen, const ComboAddress& remote) = 0;
virtual void connect(bool fastOpen, const ComboAddress& remote, const struct timeval& timeout) = 0;
@@ -32,7 +30,6 @@ public:
virtual size_t write(const void* buffer, size_t bufferSize, const struct timeval& writeTimeout) = 0;
virtual IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) = 0;
virtual IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete=false) = 0;
- virtual bool hasBufferedData() const = 0;
virtual std::string getServerNameIndication() const = 0;
virtual std::vector<uint8_t> getNextProtocol() const = 0;
virtual LibsslTLSVersion getTLSVersion() const = 0;
@@ -76,7 +73,7 @@ public:
{
d_rotatingTicketsKey.clear();
}
- virtual ~TLSCtx() {}
+ virtual ~TLSCtx() = default;
virtual std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) = 0;
virtual std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) = 0;
virtual void rotateTicketsKey(time_t now) = 0;
@@ -136,7 +133,9 @@ protected:
class TLSFrontend
{
public:
- TLSFrontend()
+ enum class ALPN : uint8_t { Unset, DoT, DoH };
+
+ TLSFrontend(ALPN alpn): d_alpn(alpn)
{
}
@@ -223,7 +222,9 @@ public:
TLSErrorCounters d_tlsCounters;
ComboAddress d_addr;
std::string d_provider;
-
+ ALPN d_alpn{ALPN::Unset};
+ /* whether the proxy protocol is inside or outside the TLS layer */
+ bool d_proxyProtocolOutsideTLS{false};
protected:
std::shared_ptr<TLSCtx> d_ctx{nullptr};
};
@@ -231,16 +232,16 @@ protected:
class TCPIOHandler
{
public:
- enum class Type : uint8_t { Client, Server };
-
- TCPIOHandler(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout, std::shared_ptr<TLSCtx> ctx): d_socket(socket)
+ TCPIOHandler(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout, const std::shared_ptr<TLSCtx>& ctx) :
+ d_socket(socket)
{
if (ctx) {
d_conn = ctx->getClientConnection(host, hostIsAddr, d_socket, timeout);
}
}
- TCPIOHandler(int socket, const struct timeval& timeout, std::shared_ptr<TLSCtx> ctx, time_t now): d_socket(socket)
+ TCPIOHandler(int socket, const struct timeval& timeout, const std::shared_ptr<TLSCtx>& ctx, time_t now) :
+ d_socket(socket)
{
if (ctx) {
d_conn = ctx->getConnection(d_socket, timeout, now);
@@ -364,13 +365,13 @@ public:
return Done when toRead bytes have been read, needRead or needWrite if the IO operation
would block.
*/
- IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete=false)
+ IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete=false, bool bypassFilters=false)
{
if (buffer.size() < toRead || pos >= toRead) {
throw std::out_of_range("Calling tryRead() with a too small buffer (" + std::to_string(buffer.size()) + ") for a read of " + std::to_string(toRead - pos) + " bytes starting at " + std::to_string(pos));
}
- if (d_conn) {
+ if (!bypassFilters && d_conn) {
return d_conn->tryRead(buffer, pos, toRead, allowIncomplete);
}
@@ -473,14 +474,6 @@ public:
return writen2WithTimeout(d_socket, buffer, bufferSize, writeTimeout);
}
- bool hasBufferedData() const
- {
- if (d_conn) {
- return d_conn->hasBufferedData();
- }
- return false;
- }
-
std::string getServerNameIndication() const
{
if (d_conn) {
@@ -582,3 +575,4 @@ struct TLSContextParameters
std::shared_ptr<TLSCtx> getTLSContext(const TLSContextParameters& params);
bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx);
+bool setupDoHProtocolNegotiation(std::shared_ptr<TLSCtx>& ctx);
diff --git a/test-base64_cc.cc b/test-base64_cc.cc
index 2f694b1..d246b0d 100644
--- a/test-base64_cc.cc
+++ b/test-base64_cc.cc
@@ -1,4 +1,7 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#ifdef HAVE_CONFIG_H
#include "config.h"
diff --git a/test-channel.cc b/test-channel.cc
new file mode 100644
index 0000000..75c5a59
--- /dev/null
+++ b/test-channel.cc
@@ -0,0 +1,157 @@
+#ifndef BOOST_TEST_DYN_LINK
+#define BOOST_TEST_DYN_LINK
+#endif
+
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+
+#include "channel.hh"
+
+struct MyObject
+{
+ uint64_t a{0};
+};
+
+BOOST_AUTO_TEST_SUITE(test_channel)
+
+BOOST_AUTO_TEST_CASE(test_object_queue)
+{
+ auto [sender, receiver] = pdns::channel::createObjectQueue<MyObject>();
+
+ BOOST_CHECK(receiver.getDescriptor() != -1);
+ BOOST_CHECK_EQUAL(receiver.isClosed(), false);
+
+ auto got = receiver.receive();
+ BOOST_CHECK(!got);
+
+ auto obj = std::make_unique<MyObject>();
+ obj->a = 42U;
+ BOOST_CHECK_EQUAL(sender.send(std::move(obj)), true);
+ BOOST_CHECK(!obj);
+ got = receiver.receive();
+ BOOST_CHECK(got != std::nullopt && *got);
+ BOOST_CHECK_EQUAL((*got)->a, 42U);
+}
+
+BOOST_AUTO_TEST_CASE(test_object_queue_full)
+{
+ auto [sender, receiver] = pdns::channel::createObjectQueue<MyObject>();
+
+ {
+ auto got = receiver.receive();
+ BOOST_CHECK(!got);
+ }
+
+ /* add objects to the queue until it becomes full */
+ bool blocked = false;
+ size_t queued = 0;
+ while (!blocked) {
+ auto obj = std::make_unique<MyObject>();
+ obj->a = 42U;
+ blocked = !sender.send(std::move(obj));
+ if (blocked) {
+ BOOST_CHECK(obj);
+ }
+ else {
+ BOOST_CHECK(!obj);
+ ++queued;
+ }
+ }
+
+ BOOST_CHECK_GT(queued, 1U);
+
+ /* clear the queue */
+ blocked = false;
+ size_t received = 0;
+ while (!blocked) {
+ auto got = receiver.receive();
+ if (got) {
+ ++received;
+ }
+ else {
+ blocked = true;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(queued, received);
+
+ /* we should be able to write again */
+ auto obj = std::make_unique<MyObject>();
+ obj->a = 42U;
+ BOOST_CHECK(sender.send(std::move(obj)));
+ /* and to get it */
+ {
+ auto got = receiver.receive();
+ BOOST_CHECK(got);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_object_queue_throw_on_eof)
+{
+ auto [sender, receiver] = pdns::channel::createObjectQueue<MyObject>();
+ sender.close();
+ BOOST_CHECK_THROW(receiver.receive(), std::runtime_error);
+ BOOST_CHECK_EQUAL(receiver.isClosed(), true);
+}
+
+BOOST_AUTO_TEST_CASE(test_object_queue_do_not_throw_on_eof)
+{
+ auto [sender, receiver] = pdns::channel::createObjectQueue<MyObject>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, 0U, false);
+ sender.close();
+ auto got = receiver.receive();
+ BOOST_CHECK(got == std::nullopt);
+ BOOST_CHECK_EQUAL(receiver.isClosed(), true);
+}
+
+BOOST_AUTO_TEST_CASE(test_notification_queue_full)
+{
+ auto [notifier, waiter] = pdns::channel::createNotificationQueue();
+
+ BOOST_CHECK(waiter.getDescriptor() != -1);
+ BOOST_CHECK_EQUAL(waiter.isClosed(), false);
+ waiter.clear();
+
+ /* add notifications until the queue becomes full */
+ bool blocked = false;
+ while (!blocked) {
+ blocked = notifier.notify();
+ }
+
+ /* clear the queue */
+ waiter.clear();
+
+ /* we should be able to write again */
+ BOOST_CHECK(notifier.notify());
+}
+
+BOOST_AUTO_TEST_CASE(test_notification_queue_throw_on_eof)
+{
+ auto [notifier, waiter] = pdns::channel::createNotificationQueue();
+
+ BOOST_CHECK(waiter.getDescriptor() != -1);
+ BOOST_CHECK_EQUAL(waiter.isClosed(), false);
+
+ BOOST_CHECK_EQUAL(notifier.notify(), true);
+ waiter.clear();
+
+ notifier = pdns::channel::Notifier();
+ BOOST_CHECK_THROW(waiter.clear(), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_notification_queue_do_not_throw_on_eof)
+{
+ auto [notifier, waiter] = pdns::channel::createNotificationQueue(true, 0, false);
+
+ BOOST_CHECK(waiter.getDescriptor() != -1);
+ BOOST_CHECK_EQUAL(waiter.isClosed(), false);
+
+ BOOST_CHECK_EQUAL(notifier.notify(), true);
+ waiter.clear();
+
+ notifier = pdns::channel::Notifier();
+ waiter.clear();
+ BOOST_CHECK_EQUAL(waiter.isClosed(), true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test-connectionmanagement_hh.cc b/test-connectionmanagement_hh.cc
index 8320518..7ebaf31 100644
--- a/test-connectionmanagement_hh.cc
+++ b/test-connectionmanagement_hh.cc
@@ -1,5 +1,7 @@
-
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
diff --git a/test-credentials_cc.cc b/test-credentials_cc.cc
index 109f2b0..ae71485 100644
--- a/test-credentials_cc.cc
+++ b/test-credentials_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/algorithm/string.hpp>
diff --git a/test-delaypipe_hh.cc b/test-delaypipe_hh.cc
index 9e678ee..4bc0b02 100644
--- a/test-delaypipe_hh.cc
+++ b/test-delaypipe_hh.cc
@@ -1,4 +1,7 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -22,8 +25,7 @@ BOOST_AUTO_TEST_CASE(test_object_pipe) {
op.close();
BOOST_CHECK_EQUAL(op.readTimeout(&i, 1), 0);
-
-};
+}
std::atomic<int> done = 0;
BOOST_AUTO_TEST_CASE(test_delay_pipe_small) {
@@ -53,9 +55,9 @@ BOOST_AUTO_TEST_CASE(test_delay_pipe_small) {
sleep(1);
BOOST_CHECK_EQUAL(done, n);
-};
+}
-BOOST_AUTO_TEST_CASE(test_delay_pipe_big) {
+BOOST_AUTO_TEST_CASE(test_delay_pipe_big) {
done=0;
struct Work
{
@@ -74,7 +76,6 @@ BOOST_AUTO_TEST_CASE(test_delay_pipe_big) {
sleep(1);
BOOST_CHECK_EQUAL(done, n);
-};
-
+}
BOOST_AUTO_TEST_SUITE_END();
diff --git a/test-dnscrypt_cc.cc b/test-dnscrypt_cc.cc
index f19010c..d6d48f6 100644
--- a/test-dnscrypt_cc.cc
+++ b/test-dnscrypt_cc.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -32,9 +35,6 @@
#include <unistd.h>
bool g_verbose{false};
-bool g_syslog{true};
-bool g_logtimestamps{false};
-std::optional<std::ofstream> g_verboseStream{std::nullopt};
BOOST_AUTO_TEST_SUITE(test_dnscrypt_cc)
diff --git a/test-dnsdist-connections-cache.cc b/test-dnsdist-connections-cache.cc
index 024d9db..b6f86b6 100644
--- a/test-dnsdist-connections-cache.cc
+++ b/test-dnsdist-connections-cache.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
diff --git a/test-dnsdist-dnsparser.cc b/test-dnsdist-dnsparser.cc
index cc29a19..a7bb4e3 100644
--- a/test-dnsdist-dnsparser.cc
+++ b/test-dnsdist-dnsparser.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -451,7 +454,7 @@ BOOST_AUTO_TEST_CASE(test_Overlay)
BOOST_CHECK_EQUAL(record.d_name, target);
BOOST_CHECK_EQUAL(record.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(record.d_ttl, 7200);
+ BOOST_CHECK_EQUAL(record.d_ttl, 7200U);
BOOST_CHECK_EQUAL(record.d_place, 1U);
BOOST_CHECK_GE(record.d_contentOffset, lastOffset);
lastOffset = record.d_contentOffset + record.d_contentLength;
diff --git a/test-dnsdist-lua-ffi.cc b/test-dnsdist-lua-ffi.cc
index 776aee0..79c9ef9 100644
--- a/test-dnsdist-lua-ffi.cc
+++ b/test-dnsdist-lua-ffi.cc
@@ -19,17 +19,21 @@
* 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 <boost/test/unit_test.hpp>
#include "dnsdist-lua-ffi.hh"
#include "dnsdist-rings.hh"
+#include "dnsdist-web.hh"
#include "dnsparser.hh"
#include "dnswriter.hh"
-bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customPrometheusName)
+bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def)
{
return true;
}
@@ -90,6 +94,8 @@ BOOST_AUTO_TEST_CASE(test_Query)
BOOST_REQUIRE_EQUAL(bufferSize, sizeof(ids.origRemote.sin4.sin_addr.s_addr));
BOOST_CHECK(memcmp(buffer, &ids.origRemote.sin4.sin_addr.s_addr, sizeof(ids.origRemote.sin4.sin_addr.s_addr)) == 0);
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_remote_port(&lightDQ), 4242U);
+ BOOST_CHECK(!dnsdist_ffi_dnsquestion_is_remote_v6(nullptr));
+ BOOST_CHECK(!dnsdist_ffi_dnsquestion_is_remote_v6(&lightDQ));
}
{
@@ -432,8 +438,8 @@ BOOST_AUTO_TEST_CASE(test_Server)
BOOST_CHECK_EQUAL(dnsdist_ffi_server_is_up(&server), false);
BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_name(&server), "");
BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_name_with_addr(&server), dsAddr.toStringWithPort());
- BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_weight(&server), 1U);
- BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_order(&server), 1U);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_weight(&server), 1);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_order(&server), 1);
BOOST_CHECK_EQUAL(dnsdist_ffi_server_get_latency(&server), 0.0);
}
@@ -465,7 +471,7 @@ BOOST_AUTO_TEST_CASE(test_PacketCache)
ids.queryRealTime.start();
DNSQuestion dq(ids, query);
packetCache->get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
- packetCache->insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ packetCache->insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
std::string poolName("test-pool");
auto testPool = std::make_shared<ServerPool>();
@@ -683,6 +689,12 @@ BOOST_AUTO_TEST_CASE(test_RingBuffers)
{
dnsheader dh;
memset(&dh, 0, sizeof(dh));
+ dh.id = htons(42);
+ dh.rd = 1;
+ dh.ancount = htons(1);
+ dh.nscount = htons(1);
+ dh.arcount = htons(1);
+ dh.rcode = RCode::NXDomain;
DNSName qname("rings.luaffi.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress backend("192.0.2.42");
@@ -715,11 +727,22 @@ BOOST_AUTO_TEST_CASE(test_RingBuffers)
BOOST_CHECK_EQUAL(dnsdist_ffi_ring_get_entries_by_mac(nullptr, nullptr), 0U);
BOOST_CHECK(list == nullptr);
BOOST_CHECK(!dnsdist_ffi_ring_entry_is_response(nullptr, 0));
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_age(nullptr, 0) == 0.0);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_name(nullptr, 0) == nullptr);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_type(nullptr, 0) == 0);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_requestor(nullptr, 0) == nullptr);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_backend(nullptr, 0) == nullptr);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_protocol(nullptr, 0) == 0);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_size(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_latency(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_id(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_rcode(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_aa(nullptr, 0) == false);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_rd(nullptr, 0) == false);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_tc(nullptr, 0) == false);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_ancount(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_nscount(nullptr, 0) == 0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_arcount(nullptr, 0) == 0);
BOOST_CHECK(!dnsdist_ffi_ring_entry_has_mac_address(nullptr, 0));
BOOST_CHECK(dnsdist_ffi_ring_entry_get_mac_address(nullptr, 0) == nullptr);
}
@@ -731,11 +754,25 @@ BOOST_AUTO_TEST_CASE(test_RingBuffers)
BOOST_CHECK(dnsdist_ffi_ring_entry_is_response(list, 1));
for (size_t idx = 0; idx < 2; idx++) {
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_age(list, idx) >= 0.0);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_age(list, idx) < 2.0);
BOOST_CHECK(dnsdist_ffi_ring_entry_get_name(list, idx) == qname.toString());
BOOST_CHECK(dnsdist_ffi_ring_entry_get_type(list, idx) == qtype);
- BOOST_CHECK(dnsdist_ffi_ring_entry_get_requestor(list, idx) == requestor1.toString());
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_requestor(list, idx) == requestor1.toStringWithPort());
BOOST_CHECK(dnsdist_ffi_ring_entry_get_protocol(list, idx) == protocol.toNumber());
BOOST_CHECK_EQUAL(dnsdist_ffi_ring_entry_get_size(list, idx), size);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_ring_entry_get_id(list, idx), 42U);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_aa(list, idx) == false);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_rd(list, idx) == true);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_tc(list, idx) == false);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_ancount(list, idx) == 1);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_nscount(list, idx) == 1);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_arcount(list, idx) == 1);
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_rcode(list, idx) == RCode::NXDomain);
+ if (dnsdist_ffi_ring_entry_is_response(list, idx)) {
+ BOOST_CHECK(dnsdist_ffi_ring_entry_get_backend(list, idx) == backend.toStringWithPort());
+ BOOST_CHECK_EQUAL(dnsdist_ffi_ring_entry_get_latency(list, idx), responseTime);
+ }
BOOST_CHECK(!dnsdist_ffi_ring_entry_has_mac_address(list, idx));
BOOST_CHECK(dnsdist_ffi_ring_entry_get_mac_address(list, idx) == std::string());
}
@@ -743,7 +780,7 @@ BOOST_AUTO_TEST_CASE(test_RingBuffers)
dnsdist_ffi_ring_entry_list_free(list);
list = nullptr;
- // no the right requestor
+ // not the right requestor
BOOST_REQUIRE_EQUAL(dnsdist_ffi_ring_get_entries_by_addr("192.0.2.2", &list), 0U);
BOOST_CHECK(list == nullptr);
@@ -779,4 +816,31 @@ BOOST_AUTO_TEST_CASE(test_NetworkEndpoint)
}
}
+BOOST_AUTO_TEST_CASE(test_hash)
+{
+ const uint32_t seed = 0x42;
+ const std::array<unsigned char, 10> data{{'0', 'x', 'd', 'e', 'a', 'd', 'b', 'E', 'e', 'F'}};
+ const std::array<unsigned char, 10> capitalizedData{{'0', 'X', 'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'}};
+
+ {
+ /* invalid */
+ BOOST_CHECK_EQUAL(dnsdist_ffi_hash(0, nullptr, 0, false), 0U);
+ BOOST_CHECK_EQUAL(dnsdist_ffi_hash(seed, nullptr, 0, false), seed);
+ }
+ {
+ /* case sensitive */
+ auto hash = dnsdist_ffi_hash(seed, data.data(), data.size(), false);
+ BOOST_CHECK_EQUAL(hash, burtle(data.data(), data.size(), seed));
+ BOOST_CHECK_NE(hash, burtle(capitalizedData.data(), capitalizedData.size(), seed));
+ BOOST_CHECK_NE(hash, burtleCI(capitalizedData.data(), capitalizedData.size(), seed));
+ }
+ {
+ /* case insensitive */
+ auto hash = dnsdist_ffi_hash(seed, data.data(), data.size(), true);
+ BOOST_CHECK_EQUAL(hash, burtleCI(data.data(), data.size(), seed));
+ BOOST_CHECK_NE(hash, burtle(capitalizedData.data(), capitalizedData.size(), seed));
+ BOOST_CHECK_EQUAL(hash, burtleCI(capitalizedData.data(), capitalizedData.size(), seed));
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END();
diff --git a/test-dnsdist_cc.cc b/test-dnsdist_cc.cc
index c4fe42b..90a513f 100644
--- a/test-dnsdist_cc.cc
+++ b/test-dnsdist_cc.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -30,6 +33,7 @@
#include "dnsdist-internal-queries.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-xpf.hh"
+#include "dnsdist-xsk.hh"
#include "dolog.hh"
#include "dnsname.hh"
@@ -54,9 +58,9 @@ bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMs
return false;
}
-bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& ds, uint16_t queryID, DNSQuestion& dq, PacketBuffer& query, ComboAddress& dest)
+bool assignOutgoingUDPQueryToBackend(std::shared_ptr<DownstreamState>& downstream, uint16_t queryID, DNSQuestion& dnsQuestion, PacketBuffer& query, bool actuallySend)
{
- return false;
+ return true;
}
namespace dnsdist {
@@ -70,6 +74,18 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap(DownstreamState const&)
{
return false;
}
+namespace dnsdist::xsk
+{
+bool XskProcessQuery(ClientState& clientState, LocalHolders& holders, XskPacket& packet)
+{
+ return false;
+}
+}
+
+bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer& response, const std::vector<DNSDistResponseRuleAction>& localRespRuleActions, const std::vector<DNSDistResponseRuleAction>& cacheInsertedRespRuleActions, InternalQueryState&& ids)
+{
+ return false;
+}
BOOST_AUTO_TEST_SUITE(test_dnsdist_cc)
diff --git a/test-dnsdistasync.cc b/test-dnsdistasync.cc
index 7e8e137..e535ba3 100644
--- a/test-dnsdistasync.cc
+++ b/test-dnsdistasync.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -36,15 +39,15 @@ public:
return true;
}
- void handleResponse(const struct timeval&, TCPResponse&&) override
+ void handleResponse([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
}
- void handleXFRResponse(const struct timeval&, TCPResponse&&) override
+ void handleXFRResponse([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
}
- void notifyIOError(InternalQueryState&&, const struct timeval&) override
+ void notifyIOError([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
errorRaised = true;
}
@@ -112,23 +115,29 @@ BOOST_AUTO_TEST_CASE(test_TimeoutFailClose)
auto holder = std::make_unique<dnsdist::AsynchronousHolder>(false);
uint16_t asyncID = 1;
uint16_t queryID = 42;
- struct timeval ttd;
- gettimeofday(&ttd, nullptr);
- // timeout in 10 ms
- const timeval add{0, 10000};
- ttd = ttd + add;
+ struct timeval ttd
+ {
+ };
std::shared_ptr<DummyQuerySender> sender{nullptr};
{
+ // timeout in 10 ms
+ const timeval add{0, 10000};
auto query = std::make_unique<DummyCrossProtocolQuery>();
sender = query->d_sender;
BOOST_REQUIRE(sender != nullptr);
+ gettimeofday(&ttd, nullptr);
+ ttd = ttd + add;
holder->push(asyncID, queryID, ttd, std::move(query));
BOOST_CHECK(!holder->empty());
}
- // sleep for 20 ms, to be sure
- usleep(20000);
+ // the event should be triggered after 10 ms, but we have seen
+ // many spurious failures on our CI, likely because the box is
+ // overloaded, so sleep for up to 100 ms to be sure
+ for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+ usleep(10000);
+ }
BOOST_CHECK(holder->empty());
BOOST_CHECK(sender->errorRaised.load());
@@ -155,8 +164,13 @@ BOOST_AUTO_TEST_CASE(test_AddingExpiredEvent)
holder->push(asyncID, queryID, ttd, std::move(query));
}
- // sleep for 20 ms
- usleep(20000);
+ // the expired event should be triggered almost immediately,
+ // but we have seen many spurious failures on our CI,
+ // likely because the box is overloaded, so sleep for up to
+ // 100 ms to be sure
+ for (size_t counter = 0; !holder->empty() && counter < 10; counter++) {
+ usleep(10000);
+ }
BOOST_CHECK(holder->empty());
BOOST_CHECK(sender->errorRaised.load());
diff --git a/test-dnsdistbackend_cc.cc b/test-dnsdistbackend_cc.cc
index 983f912..28bf510 100644
--- a/test-dnsdistbackend_cc.cc
+++ b/test-dnsdistbackend_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
@@ -261,8 +264,8 @@ BOOST_AUTO_TEST_CASE(test_LazyExponentialBackOff)
BOOST_CHECK_EQUAL(ds.getStatus(), "down");
BOOST_CHECK_EQUAL(ds.healthCheckRequired(currentTime), false);
/* and the wait time between two checks will double every time a failure occurs */
- BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures))));
- BOOST_CHECK_EQUAL(ds.currentCheckFailures, 0U);
+ BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures - 1))));
+ BOOST_CHECK_EQUAL(ds.currentCheckFailures, 1U);
/* so after 5 failures */
const size_t nbFailures = 5;
@@ -271,8 +274,8 @@ BOOST_AUTO_TEST_CASE(test_LazyExponentialBackOff)
BOOST_CHECK(ds.healthCheckRequired(currentTime));
ds.submitHealthCheckResult(false, false);
}
- BOOST_CHECK_EQUAL(ds.currentCheckFailures, nbFailures);
- BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures))));
+ BOOST_CHECK_EQUAL(ds.currentCheckFailures, nbFailures + 1);
+ BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures - 1))));
/* we need minRiseSuccesses successful health-checks to go up */
BOOST_REQUIRE(config.minRiseSuccesses >= 1);
diff --git a/test-dnsdistdynblocks_hh.cc b/test-dnsdistdynblocks_hh.cc
index dda6ff8..fbd24dd 100644
--- a/test-dnsdistdynblocks_hh.cc
+++ b/test-dnsdistdynblocks_hh.cc
@@ -1,11 +1,15 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-rings.hh"
Rings g_rings;
@@ -15,9 +19,22 @@ shared_ptr<BPFFilter> g_defaultBPFFilter{nullptr};
BOOST_AUTO_TEST_SUITE(dnsdistdynblocks_hh)
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+struct TestFixture
+{
+ TestFixture()
+ {
+ g_rings.reset();
+ g_rings.init();
+ }
+ ~TestFixture()
+ {
+ g_rings.reset();
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -36,9 +53,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
const auto action = DNSAction::Action::Drop;
const std::string reason = "Exceeded query rate";
- g_rings.reset();
- g_rings.init();
-
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
@@ -54,10 +68,10 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
/* we do not care about the response during that test, but we want to make sure
these do not interfere with the computation */
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfQueries);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -76,8 +90,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -108,8 +122,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
for (size_t idx = 0; idx < numberOfQueries; idx++) {
struct timespec when = now;
when.tv_sec -= (9 - timeIdx);
- g_rings.insertQuery(when, requestor1, qname, qtype, size, dh, protocol);
- g_rings.insertResponse(when, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertQuery(when, requestor1, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertResponse(when, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * numberOfSeconds);
@@ -154,11 +168,11 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6) {
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6, TestFixture) {
/* Check that we correctly group IPv6 addresses from the same /64 subnet into the same
dynamic block entry, if instructed to do so */
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("2001:db8::1");
ComboAddress backend("2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff");
@@ -180,9 +194,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6) {
dbrg.setQuiet(true);
dbrg.setMasks(32, 64, 0);
- g_rings.reset();
- g_rings.init();
-
/* block above 50 qps for numberOfSeconds seconds, no warning */
dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
@@ -195,10 +206,10 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
/* we do not care about the response during that test, but we want to make sure
these do not interfere with the computation */
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfQueries);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -218,8 +229,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6) {
for (size_t idx = 0; idx < numberOfQueries; idx++) {
ComboAddress requestor("2001:db8::" + std::to_string(idx));
- g_rings.insertQuery(now, requestor, qname, qtype, size, dh, protocol);
- g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertQuery(now, requestor, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -257,10 +268,10 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_RangeV6) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports, TestFixture) {
/* Check that we correctly split IPv4 addresses based on port ranges, when instructed to do so */
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1:42");
ComboAddress backend("192.0.2.254");
@@ -283,9 +294,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
/* split v4 by ports using a /2 (0 - 16383, 16384 - 32767, 32768 - 49151, 49152 - 65535) */
dbrg.setMasks(32, 128, 2);
- g_rings.reset();
- g_rings.init();
-
/* block above 50 qps for numberOfSeconds seconds, no warning */
dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
@@ -298,10 +306,10 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
/* we do not care about the response during that test, but we want to make sure
these do not interfere with the computation */
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfQueries);
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -321,8 +329,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
for (size_t idx = 0; idx < numberOfQueries; idx++) {
ComboAddress requestor("192.0.2.1:" + std::to_string(idx));
- g_rings.insertQuery(now, requestor, qname, qtype, size, dh, protocol);
- g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertQuery(now, requestor, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -370,8 +378,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
for (size_t idx = 0; idx < numberOfQueries; idx++) {
ComboAddress requestor("192.0.2.1:" + std::to_string(idx));
- g_rings.insertQuery(now, requestor, qname, qtype, size, dh, protocol);
- g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertQuery(now, requestor, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertResponse(now, requestor, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -391,11 +399,11 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_V4Ports) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses) {
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses, TestFixture) {
/* check that the responses are not accounted as queries when a
rcode rate rule is defined (sounds very specific but actually happened) */
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -438,10 +446,10 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses) {
struct timespec when = now;
when.tv_sec -= (99 - timeIdx);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(when, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(when, requestor1, qname, qtype, size, dnsHeader, protocol);
/* we do not care about the response during that test, but we want to make sure
these do not interfere with the computation */
- g_rings.insertResponse(when, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(when, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfQueries * 100);
@@ -453,9 +461,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QueryRate_responses) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_QTypeRate, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -473,8 +481,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- g_rings.reset();
- g_rings.init();
/* block above 50 qps for numberOfSeconds seconds, no warning */
dbrg.setQTypeRate(QType::AAAA, 50, 0, numberOfSeconds, reason, blockDuration, action);
@@ -488,7 +494,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -506,7 +512,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, QType::A, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, QType::A, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -524,7 +530,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -543,9 +549,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_QTypeRate) {
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRate) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRate, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -578,9 +584,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRate) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
@@ -596,9 +602,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRate) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = RCode::FormErr;
+ dnsHeader.rcode = RCode::FormErr;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
@@ -615,9 +621,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRate) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
@@ -636,9 +642,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRate) {
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -660,9 +666,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- g_rings.reset();
- g_rings.init();
-
/* block above 0.2 ServFail/Total ratio over numberOfSeconds seconds, no warning, minimum number of queries should be at least 51 */
dbrg.setRCodeRatio(rcode, 0.2, 0, numberOfSeconds, reason, blockDuration, action, 51);
@@ -673,13 +676,13 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 20; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
- dh.rcode = RCode::NoError;
+ dnsHeader.rcode = RCode::NoError;
for (size_t idx = 0; idx < 80; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
@@ -694,9 +697,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = RCode::FormErr;
+ dnsHeader.rcode = RCode::FormErr;
for (size_t idx = 0; idx < 50; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
@@ -712,13 +715,13 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 21; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
- dh.rcode = RCode::NoError;
+ dnsHeader.rcode = RCode::NoError;
for (size_t idx = 0; idx < 79; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
@@ -742,13 +745,13 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < 11; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
- dh.rcode = RCode::NoError;
+ dnsHeader.rcode = RCode::NoError;
for (size_t idx = 0; idx < 39; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
@@ -758,9 +761,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_RCodeRatio) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -782,9 +785,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate) {
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- g_rings.reset();
- g_rings.init();
-
/* block above 10kB/s for numberOfSeconds seconds, no warning */
dbrg.setResponseByteRate(10000, 0, numberOfSeconds, reason, blockDuration, action);
@@ -796,9 +796,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
@@ -814,9 +814,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
g_dynblockNMG.setState(emptyNMG);
- dh.rcode = rcode;
+ dnsHeader.rcode = rcode;
for (size_t idx = 0; idx < numberOfResponses; idx++) {
- g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dh, backend, outgoingProtocol);
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), numberOfResponses);
@@ -832,12 +832,133 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_ResponseByteRate) {
BOOST_CHECK_EQUAL(block.blocks, 0U);
BOOST_CHECK_EQUAL(block.warning, false);
}
+}
+
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_CacheMissRatio, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
+ DNSName qname("rings.powerdns.com.");
+ ComboAddress requestor1("192.0.2.1");
+ ComboAddress requestor2("192.0.2.2");
+ ComboAddress backend("192.0.2.42");
+ ComboAddress cacheHit;
+ uint16_t qtype = QType::AAAA;
+ uint16_t size = 42;
+ dnsdist::Protocol outgoingProtocol = dnsdist::Protocol::DoUDP;
+ unsigned int responseTime = 100 * 1000; /* 100ms */
+ struct timespec now
+ {
+ };
+ gettime(&now);
+ NetmaskTree<DynBlock, AddressAndPortRange> emptyNMG;
+
+ time_t numberOfSeconds = 10;
+ unsigned int blockDuration = 60;
+ const auto action = DNSAction::Action::Drop;
+ const std::string reason = "Exceeded cache-miss ratio";
+
+ DynBlockRulesGroup dbrg;
+ dbrg.setQuiet(true);
+
+ /* block above 0.5 Cache-Miss/Total ratio over numberOfSeconds seconds, no warning, minimum number of queries should be at least 51, global cache hit at least 80% */
+ dnsdist::metrics::g_stats.cacheHits.store(80);
+ dnsdist::metrics::g_stats.cacheMisses.store(20);
+ dbrg.setCacheMissRatio(0.5, 0, numberOfSeconds, reason, blockDuration, action, 51, 0.8);
+
+ {
+ /* insert 50 cache misses and 50 cache hits from a given client in the last 10s
+ this should not trigger the rule */
+ g_rings.clear();
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
+ g_dynblockNMG.setState(emptyNMG);
+
+ for (size_t idx = 0; idx < 20; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
+ }
+ for (size_t idx = 0; idx < 80; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, cacheHit, outgoingProtocol);
+ }
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
+
+ dbrg.apply(now);
+ BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ }
+
+ {
+ /* insert 51 cache misses and 49 hits from a given client in the last 10s
+ this should trigger the rule this time */
+ g_rings.clear();
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
+ g_dynblockNMG.setState(emptyNMG);
+
+ for (size_t idx = 0; idx < 51; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
+ }
+ for (size_t idx = 0; idx < 49; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, cacheHit, outgoingProtocol);
+ }
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
+
+ dbrg.apply(now);
+ BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 1U);
+ BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) != nullptr);
+ BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor2) == nullptr);
+ const auto& block = g_dynblockNMG.getLocal()->lookup(requestor1)->second;
+ BOOST_CHECK_EQUAL(block.reason, reason);
+ BOOST_CHECK_EQUAL(block.until.tv_sec, now.tv_sec + blockDuration);
+ BOOST_CHECK(block.domain.empty());
+ BOOST_CHECK(block.action == action);
+ BOOST_CHECK_EQUAL(block.blocks, 0U);
+ BOOST_CHECK_EQUAL(block.warning, false);
+ }
+ {
+ /* insert 40 misses and 10 hits from a given client in the last 10s
+ this should NOT trigger the rule since we don't have more than 50 queries */
+ g_rings.clear();
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
+ g_dynblockNMG.setState(emptyNMG);
+
+ for (size_t idx = 0; idx < 40; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
+ }
+ for (size_t idx = 0; idx < 10; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, cacheHit, outgoingProtocol);
+ }
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 50U);
+
+ dbrg.apply(now);
+ BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_CHECK(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ }
+
+ /* the global cache-hit rate is too low, should not trigger */
+ dnsdist::metrics::g_stats.cacheHits.store(60);
+ dnsdist::metrics::g_stats.cacheMisses.store(40);
+ {
+ /* insert 51 cache misses and 49 hits from a given client in the last 10s */
+ g_rings.clear();
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 0U);
+ g_dynblockNMG.setState(emptyNMG);
+
+ for (size_t idx = 0; idx < 51; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, backend, outgoingProtocol);
+ }
+ for (size_t idx = 0; idx < 49; idx++) {
+ g_rings.insertResponse(now, requestor1, qname, qtype, responseTime, size, dnsHeader, cacheHit, outgoingProtocol);
+ }
+ BOOST_CHECK_EQUAL(g_rings.getNumberOfResponseEntries(), 100U);
+
+ dbrg.apply(now);
+ BOOST_CHECK_EQUAL(g_dynblockNMG.getLocal()->size(), 0U);
+ BOOST_REQUIRE(g_dynblockNMG.getLocal()->lookup(requestor1) == nullptr);
+ }
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Warning, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.2");
@@ -856,9 +977,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- g_rings.reset();
- g_rings.init();
-
/* warn above 20 qps for numberOfSeconds seconds, block above 50 qps */
dbrg.setQueryRate(50, 20, numberOfSeconds, reason, blockDuration, action);
@@ -871,7 +989,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -889,7 +1007,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -917,7 +1035,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -946,7 +1064,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), 0U);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -977,7 +1095,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries);
@@ -998,9 +1116,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Warning) {
}
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Ranges) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesGroup_Ranges, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
ComboAddress requestor1("192.0.2.1");
ComboAddress requestor2("192.0.2.42");
@@ -1026,9 +1144,6 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Ranges) {
/* block above 50 qps for numberOfSeconds seconds, no warning */
dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
- g_rings.reset();
- g_rings.init();
-
{
/* insert just above 50 qps from the two clients in the last 10s
this should trigger the rule for the first one but not the second one */
@@ -1038,8 +1153,8 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Ranges) {
g_dynblockNMG.setState(emptyNMG);
for (size_t idx = 0; idx < numberOfQueries; idx++) {
- g_rings.insertQuery(now, requestor1, qname, qtype, size, dh, protocol);
- g_rings.insertQuery(now, requestor2, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor1, qname, qtype, size, dnsHeader, protocol);
+ g_rings.insertQuery(now, requestor2, qname, qtype, size, dnsHeader, protocol);
}
BOOST_CHECK_EQUAL(g_rings.getNumberOfQueryEntries(), numberOfQueries * 2);
@@ -1058,9 +1173,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesGroup_Ranges) {
}
-BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
- dnsheader dh;
- memset(&dh, 0, sizeof(dh));
+BOOST_FIXTURE_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN, TestFixture) {
+ dnsheader dnsHeader{};
+ memset(&dnsHeader, 0, sizeof(dnsHeader));
DNSName qname("rings.powerdns.com.");
uint16_t qtype = QType::AAAA;
uint16_t size = 42;
@@ -1094,7 +1209,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
*/
for (size_t idx = 0; idx < 256; idx++) {
const ComboAddress requestor("192.0.2." + std::to_string(idx));
- g_rings.insertQuery(now, requestor, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor, qname, qtype, size, dnsHeader, protocol);
}
/* we apply the rules, all clients should be blocked */
@@ -1142,15 +1257,15 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>>(true, boost::none);
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
}
- return std::tuple<bool, boost::optional<std::string>>(false, boost::none);
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
});
/* insert one fake response for 255 DNS names */
const ComboAddress requestor("192.0.2.1");
for (size_t idx = 0; idx < 256; idx++) {
- g_rings.insertResponse(now, requestor, DNSName(std::to_string(idx)) + qname, qtype, 1000 /*usec*/, size, dh, requestor /* backend, technically, but we don't care */, outgoingProtocol);
+ g_rings.insertResponse(now, requestor, DNSName(std::to_string(idx)) + qname, qtype, 1000 /*usec*/, size, dnsHeader, requestor /* backend, technically, but we don't care */, outgoingProtocol);
}
/* we apply the rules, all suffixes should be blocked */
@@ -1160,6 +1275,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
const DNSName name(DNSName(std::to_string(idx)) + qname);
const auto* block = g_dynblockSMT.getLocal()->lookup(name);
BOOST_REQUIRE(block != nullptr);
+ BOOST_REQUIRE(block->action == action);
/* simulate that:
- 1.rings.powerdns.com. got 1 query
...
@@ -1198,15 +1314,15 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>>(true, "blocked for a different reason");
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, "blocked for a different reason", static_cast<int>(DNSAction::Action::Truncate));
}
- return std::tuple<bool, boost::optional<std::string>>(false, boost::none);
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
});
/* insert one fake response for 255 DNS names */
const ComboAddress requestor("192.0.2.1");
for (size_t idx = 0; idx < 256; idx++) {
- g_rings.insertResponse(now, requestor, DNSName(std::to_string(idx)) + qname, qtype, 1000 /*usec*/, size, dh, requestor /* backend, technically, but we don't care */, dnsdist::Protocol::DoUDP);
+ g_rings.insertResponse(now, requestor, DNSName(std::to_string(idx)) + qname, qtype, 1000 /*usec*/, size, dnsHeader, requestor /* backend, technically, but we don't care */, dnsdist::Protocol::DoUDP);
}
/* we apply the rules, all suffixes should be blocked */
@@ -1216,6 +1332,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
const DNSName name(DNSName(std::to_string(idx)) + qname);
const auto* block = g_dynblockSMT.getLocal()->lookup(name);
BOOST_REQUIRE(block != nullptr);
+ BOOST_REQUIRE(block->action == DNSAction::Action::Truncate);
/* simulate that:
- 1.rings.powerdns.com. got 1 query
...
@@ -1255,9 +1372,9 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>>(true, boost::none);
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
}
- return std::tuple<bool, boost::optional<std::string>>(false, boost::none);
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
});
bool done = false;
@@ -1266,7 +1383,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
for (size_t idxC = 0; !done && idxC < 256; idxC++) {
for (size_t idxD = 0; !done && idxD < 256; idxD++) {
const DNSName victim(std::to_string(idxB) + "." + std::to_string(idxC) + "." + std::to_string(idxD) + qname.toString());
- g_rings.insertResponse(now, requestor, victim, qtype, 1000 /*usec*/, size, dh, requestor /* backend, technically, but we don't care */, outgoingProtocol);
+ g_rings.insertResponse(now, requestor, victim, qtype, 1000 /*usec*/, size, dnsHeader, requestor /* backend, technically, but we don't care */, outgoingProtocol);
if (g_rings.getNumberOfQueryEntries() == 1000000) {
done = true;
break;
@@ -1311,7 +1428,7 @@ BOOST_AUTO_TEST_CASE(test_DynBlockRulesMetricsCache_GetTopN) {
for (size_t idxC = 0; !done && idxC < 256; idxC++) {
for (size_t idxD = 0; !done && idxD < 256; idxD++) {
const ComboAddress requestor("192." + std::to_string(idxB) + "." + std::to_string(idxC) + "." + std::to_string(idxD));
- g_rings.insertQuery(now, requestor, qname, qtype, size, dh, protocol);
+ g_rings.insertQuery(now, requestor, qname, qtype, size, dnsHeader, protocol);
if (g_rings.getNumberOfQueryEntries() == 1000000) {
done = true;
break;
diff --git a/test-dnsdistedns.cc b/test-dnsdistedns.cc
new file mode 100644
index 0000000..603bc3e
--- /dev/null
+++ b/test-dnsdistedns.cc
@@ -0,0 +1,202 @@
+/*
+ * 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 <boost/test/unit_test.hpp>
+
+#include "dnsdist-edns.hh"
+#include "dnsname.hh"
+#include "dnswriter.hh"
+#include "ednscookies.hh"
+#include "ednsextendederror.hh"
+#include "ednsoptions.hh"
+#include "ednssubnet.hh"
+
+BOOST_AUTO_TEST_SUITE(test_dnsdist_edns)
+
+BOOST_AUTO_TEST_CASE(getExtendedDNSError)
+{
+ const DNSName name("www.powerdns.com.");
+
+ {
+ /* no EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(!infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDNS but no EDE */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ pw.addOpt(512, 0, 0);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(!infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDE with a numerical code but no text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::NetworkError),
+ .extraText = ""};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDE with both code and text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* EDE with truncated text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ /* truncate the EDE text by one byte */
+ query.resize(query.size() - 1U);
+
+ BOOST_CHECK_THROW(dnsdist::edns::getExtendedDNSError(query), std::range_error);
+ }
+
+ {
+ /* EDE before ECS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ EDNSSubnetOpts ecsOpt;
+ ecsOpt.source = Netmask(ComboAddress("192.0.2.1"), 24U);
+ const auto ecsOptStr = makeEDNSSubnetOptsString(ecsOpt);
+ opts.emplace_back(EDNSOptionCode::ECS, ecsOptStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* EDE after ECS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ EDNSSubnetOpts ecsOpt;
+ ecsOpt.source = Netmask(ComboAddress("192.0.2.1"), 24U);
+ const auto ecsOptStr = makeEDNSSubnetOptsString(ecsOpt);
+ opts.emplace_back(EDNSOptionCode::ECS, ecsOptStr);
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* Cookie, EDE, padding */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSCookiesOpt cookieOpt("deadbeefdeadbeef");
+ const auto cookieOptStr = cookieOpt.makeOptString();
+ opts.emplace_back(EDNSOptionCode::COOKIE, cookieOptStr);
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ std::string paddingOptStr;
+ paddingOptStr.resize(42U);
+ opts.emplace_back(EDNSOptionCode::PADDING, paddingOptStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/test-dnsdistkvs_cc.cc b/test-dnsdistkvs_cc.cc
index 8c5d756..7177d67 100644
--- a/test-dnsdistkvs_cc.cc
+++ b/test-dnsdistkvs_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
diff --git a/test-dnsdistlbpolicies_cc.cc b/test-dnsdistlbpolicies_cc.cc
index c7e638b..401108f 100644
--- a/test-dnsdistlbpolicies_cc.cc
+++ b/test-dnsdistlbpolicies_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
@@ -20,8 +23,6 @@ DNSDistSNMPAgent* g_snmpAgent{nullptr};
#if BENCH_POLICIES
bool g_verbose{true};
-bool g_syslog{true};
-bool g_logtimestamps{false};
#include "dnsdist-rings.hh"
Rings g_rings;
GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
@@ -34,52 +35,26 @@ std::vector<std::unique_ptr<ClientState>> g_frontends;
/* add stub implementations, we don't want to include the corresponding object files
and their dependencies */
-#ifdef HAVE_DNS_OVER_HTTPS
-std::unordered_map<std::string, std::string> DOHUnit::getHTTPHeaders() const
-{
- return {};
-}
-
-std::string DOHUnit::getHTTPPath() const
-{
- return "";
-}
-
-std::string DOHUnit::getHTTPHost() const
-{
- return "";
-}
-
-std::string DOHUnit::getHTTPScheme() const
-{
- return "";
-}
-
-std::string DOHUnit::getHTTPQueryString() const
-{
- return "";
-}
-
-void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const std::string& contentType_)
-{
-}
-#endif /* HAVE_DNS_OVER_HTTPS */
-
-void handleDOHTimeout(DOHUnitUniquePtr&& oldDU)
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
+bool TLSFrontend::setupTLS()
{
+ return true;
}
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
std::string DNSQuestion::getTrailingData() const
{
return "";
}
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
bool DNSQuestion::setTrailingData(const std::string& tail)
{
return false;
}
-bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& reason)
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static): this is a stub, the real one is not that simple..
+bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dnsQuestion, const std::string& reason)
{
return false;
}
@@ -88,16 +63,18 @@ void setLuaNoSideEffect()
{
}
-DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
+DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const
{
return DNSAction::Action::None;
}
-bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>&)
+bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& tlsCtx)
{
+ (void)tlsCtx;
return true;
}
+// NOLINTNEXTLINE(performance-unnecessary-value-param): this is a stub, the real one is not that simple and the performance does not matter
void responderThread(std::shared_ptr<DownstreamState> dss)
{
}
@@ -112,14 +89,14 @@ static DNSQuestion getDQ(const DNSName* providedName = nullptr)
static InternalQueryState ids;
ids.origDest = ComboAddress("127.0.0.1:53");
ids.origRemote = ComboAddress("192.0.2.1:42");
- ids.qname = providedName ? *providedName : qname;
+ ids.qname = providedName != nullptr ? *providedName : qname;
ids.qtype = QType::A;
ids.qclass = QClass::IN;
ids.protocol = dnsdist::Protocol::DoUDP;
ids.queryRealTime.start();
- DNSQuestion dq(ids, packet);
- return dq;
+ DNSQuestion dnsQuestion(ids, packet);
+ return dnsQuestion;
}
static void benchPolicy(const ServerPolicy& pol)
@@ -131,11 +108,11 @@ static void benchPolicy(const ServerPolicy& pol)
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
ServerPolicy::NumberedServerVector servers;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
servers.at(idx - 1).second->setUp();
/* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */
servers.at(idx - 1).second->setWeight(1000);
@@ -146,12 +123,12 @@ static void benchPolicy(const ServerPolicy& pol)
StopWatch sw;
sw.start();
for (size_t idx = 0; idx < 1000; idx++) {
- for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
- }
+ for (const auto& name : names) {
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ }
}
- cerr<<pol.name<<" took "<<std::to_string(sw.udiff())<<" us for "<<names.size()<<endl;
+ cerr << pol.name << " took " << std::to_string(sw.udiff()) << " us for " << names.size() << endl;
g_verbose = existingVerboseValue;
#endif /* BENCH_POLICIES */
@@ -167,49 +144,51 @@ static void resetLuaContext()
BOOST_AUTO_TEST_SUITE(dnsdistlbpolicies)
-BOOST_AUTO_TEST_CASE(test_firstAvailable) {
- auto dq = getDQ();
+BOOST_AUTO_TEST_CASE(test_firstAvailable)
+{
+ auto dnsQuestion = getDQ();
ServerPolicy pol{"firstAvailable", firstAvailable, false};
ServerPolicy::NumberedServerVector servers;
- servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
+ servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
/* servers start as 'down' */
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
/* mark the server as 'up' */
servers.at(0).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server != nullptr);
/* add a second server, we should still get the first one */
- servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
- server = pol.getSelectedBackend(servers, dq);
+ servers.emplace_back(2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")));
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(0).second);
/* mark the first server as 'down', second as 'up' */
servers.at(0).second->setDown();
servers.at(1).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
benchPolicy(pol);
}
-BOOST_AUTO_TEST_CASE(test_firstAvailableWithOrderAndQPS) {
- auto dq = getDQ();
+BOOST_AUTO_TEST_CASE(test_firstAvailableWithOrderAndQPS)
+{
+ auto dnsQuestion = getDQ();
size_t qpsLimit = 10;
ServerPolicy pol{"firstAvailable", firstAvailable, false};
ServerPolicy::NumberedServerVector servers;
- servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
- servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
+ servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
+ servers.emplace_back(2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")));
/* Second server has a higher order, so most queries should be routed to the first (remember that
we need to keep them ordered!).
- However the first server has a QPS limit at 10 qps, so any query above that should be routed
+ However the first server has a QPS limit at 10 qps, so any query above that should be routed
to the second server. */
servers.at(0).second->d_config.order = 1;
servers.at(1).second->d_config.order = 2;
@@ -221,7 +200,7 @@ BOOST_AUTO_TEST_CASE(test_firstAvailableWithOrderAndQPS) {
/* the first queries under the QPS limit should be
sent to the first server */
for (size_t idx = 0; idx < qpsLimit; idx++) {
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(0).second);
server->incQueriesCount();
@@ -229,65 +208,66 @@ BOOST_AUTO_TEST_CASE(test_firstAvailableWithOrderAndQPS) {
/* then to the second server */
for (size_t idx = 0; idx < 100; idx++) {
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
server->incQueriesCount();
}
}
-BOOST_AUTO_TEST_CASE(test_roundRobin) {
- auto dq = getDQ();
+BOOST_AUTO_TEST_CASE(test_roundRobin)
+{
+ auto dnsQuestion = getDQ();
ServerPolicy pol{"roundrobin", roundrobin, false};
ServerPolicy::NumberedServerVector servers;
/* selecting a server on an empty server list */
g_roundrobinFailOnNoServer = false;
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
- servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
+ servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
/* servers start as 'down' but the RR policy returns a server unless g_roundrobinFailOnNoServer is set */
g_roundrobinFailOnNoServer = true;
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
g_roundrobinFailOnNoServer = false;
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server != nullptr);
/* mark the server as 'up' */
servers.at(0).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server != nullptr);
/* add a second server, we should get the first one then the second one */
- servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
+ servers.emplace_back(2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")));
servers.at(1).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(0).second);
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
/* mark the first server as 'down', second as 'up' */
servers.at(0).second->setDown();
servers.at(1).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
/* mark all servers 'up' */
- for (auto& s : servers) {
- s.second->setUp();
- serversMap[s.second] = 0;
+ for (auto& serv : servers) {
+ serv.second->setUp();
+ serversMap[serv.second] = 0;
}
for (size_t idx = 0; idx < 1000; idx++) {
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -301,32 +281,33 @@ BOOST_AUTO_TEST_CASE(test_roundRobin) {
benchPolicy(pol);
}
-BOOST_AUTO_TEST_CASE(test_leastOutstanding) {
- auto dq = getDQ();
+BOOST_AUTO_TEST_CASE(test_leastOutstanding)
+{
+ auto dnsQuestion = getDQ();
ServerPolicy pol{"leastOutstanding", leastOutstanding, false};
ServerPolicy::NumberedServerVector servers;
- servers.push_back({ 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")) });
+ servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
/* servers start as 'down' */
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server == nullptr);
/* mark the server as 'up' */
servers.at(0).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_CHECK(server != nullptr);
/* add a second server, we should still get the first one */
- servers.push_back({ 2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")) });
- server = pol.getSelectedBackend(servers, dq);
+ servers.emplace_back(2, std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53")));
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(0).second);
/* mark the first server as 'down', second as 'up' */
servers.at(0).second->setDown();
servers.at(1).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
@@ -334,21 +315,22 @@ BOOST_AUTO_TEST_CASE(test_leastOutstanding) {
servers.at(0).second->setUp();
servers.at(0).second->outstanding = 42;
servers.at(1).second->setUp();
- server = pol.getSelectedBackend(servers, dq);
+ server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(server != nullptr);
BOOST_CHECK(server == servers.at(1).second);
benchPolicy(pol);
}
-BOOST_AUTO_TEST_CASE(test_wrandom) {
- auto dq = getDQ();
+BOOST_AUTO_TEST_CASE(test_wrandom)
+{
+ auto dnsQuestion = getDQ();
ServerPolicy pol{"wrandom", wrandom, false};
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
@@ -356,7 +338,7 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
benchPolicy(pol);
for (size_t idx = 0; idx < 1000; idx++) {
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -381,10 +363,10 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
BOOST_CHECK_EQUAL(entry.first->d_config.d_weight, 1);
}
/* change the weight of the last server to 100, default is 1 */
- servers.at(servers.size()-1).second->d_config.d_weight = 100;
+ servers.at(servers.size() - 1).second->d_config.d_weight = 100;
for (size_t idx = 0; idx < 1000; idx++) {
- auto server = pol.getSelectedBackend(servers, dq);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -396,25 +378,26 @@ BOOST_AUTO_TEST_CASE(test_wrandom) {
totalW += entry.first->d_config.d_weight;
}
BOOST_CHECK_EQUAL(total, 1000U);
- auto last = servers.at(servers.size()-1).second;
+ auto last = servers.at(servers.size() - 1).second;
const auto got = serversMap[last];
- float expected = (1000 * 1.0 * last->d_config.d_weight) / totalW;
+ float expected = static_cast<float>(1000 * 1.0 * last->d_config.d_weight) / static_cast<float>(totalW);
BOOST_CHECK_GT(got, expected / 2);
BOOST_CHECK_LT(got, expected * 2);
}
-BOOST_AUTO_TEST_CASE(test_whashed) {
+BOOST_AUTO_TEST_CASE(test_whashed)
+{
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
ServerPolicy pol{"whashed", whashed, false};
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
@@ -422,8 +405,8 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
benchPolicy(pol);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -445,10 +428,10 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
/* request 1000 times the same name, we should go to the same server every time */
{
- auto dq = getDQ(&names.at(0));
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&names.at(0));
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
for (size_t idx = 0; idx < 1000; idx++) {
- BOOST_CHECK(pol.getSelectedBackend(servers, dq) == server);
+ BOOST_CHECK(pol.getSelectedBackend(servers, dnsQuestion) == server);
}
}
@@ -458,11 +441,11 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
BOOST_CHECK_EQUAL(entry.first->d_config.d_weight, 1);
}
/* change the weight of the last server to 100, default is 1 */
- servers.at(servers.size()-1).second->setWeight(100);
+ servers.at(servers.size() - 1).second->setWeight(100);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -474,28 +457,29 @@ BOOST_AUTO_TEST_CASE(test_whashed) {
totalW += entry.first->d_config.d_weight;
}
BOOST_CHECK_EQUAL(total, names.size());
- auto last = servers.at(servers.size()-1).second;
+ auto last = servers.at(servers.size() - 1).second;
const auto got = serversMap[last];
- float expected = (names.size() * 1.0 * last->d_config.d_weight) / totalW;
+ float expected = static_cast<float>(static_cast<double>(names.size()) * 1.0 * last->d_config.d_weight) / static_cast<float>(totalW);
BOOST_CHECK_GT(got, expected / 2);
BOOST_CHECK_LT(got, expected * 2);
}
-BOOST_AUTO_TEST_CASE(test_chashed) {
+BOOST_AUTO_TEST_CASE(test_chashed)
+{
bool existingVerboseValue = g_verbose;
g_verbose = false;
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
ServerPolicy pol{"chashed", chashed, false};
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
/* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */
@@ -507,8 +491,8 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
benchPolicy(pol);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -530,10 +514,10 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
/* request 1000 times the same name, we should go to the same server every time */
{
- auto dq = getDQ(&names.at(0));
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&names.at(0));
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
for (size_t idx = 0; idx < 1000; idx++) {
- BOOST_CHECK(pol.getSelectedBackend(servers, dq) == server);
+ BOOST_CHECK(pol.getSelectedBackend(servers, dnsQuestion) == server);
}
}
@@ -543,11 +527,11 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
BOOST_CHECK_EQUAL(entry.first->d_config.d_weight, 1000);
}
/* change the weight of the last server to 100000, others stay at 1000 */
- servers.at(servers.size()-1).second->setWeight(100000);
+ servers.at(servers.size() - 1).second->setWeight(100000);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -559,20 +543,21 @@ BOOST_AUTO_TEST_CASE(test_chashed) {
totalW += entry.first->d_config.d_weight;
}
BOOST_CHECK_EQUAL(total, names.size());
- auto last = servers.at(servers.size()-1).second;
+ auto last = servers.at(servers.size() - 1).second;
const auto got = serversMap[last];
- float expected = (names.size() * 1.0 * last->d_config.d_weight) / totalW;
+ float expected = static_cast<float>(static_cast<double>(names.size()) * 1.0 * last->d_config.d_weight) / static_cast<float>(totalW);
BOOST_CHECK_GT(got, expected / 2);
BOOST_CHECK_LT(got, expected * 2);
g_verbose = existingVerboseValue;
}
-BOOST_AUTO_TEST_CASE(test_lua) {
+BOOST_AUTO_TEST_CASE(test_lua)
+{
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
static const std::string policySetupStr = R"foo(
@@ -585,9 +570,9 @@ BOOST_AUTO_TEST_CASE(test_lua) {
setServerPolicyLua("luaroundrobin", luaroundrobin)
)foo";
resetLuaContext();
- g_lua.lock()->writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) {
- g_policy.setState(ServerPolicy{name, policy, true});
- });
+ g_lua.lock()->writeFunction("setServerPolicyLua", [](const string& name, const ServerPolicy::policyfunc_t& policy) {
+ g_policy.setState(ServerPolicy{name, policy, true});
+ });
g_lua.lock()->executeCode(policySetupStr);
{
@@ -595,15 +580,15 @@ BOOST_AUTO_TEST_CASE(test_lua) {
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -624,11 +609,12 @@ BOOST_AUTO_TEST_CASE(test_lua) {
#ifdef LUAJIT_VERSION
-BOOST_AUTO_TEST_CASE(test_lua_ffi_rr) {
+BOOST_AUTO_TEST_CASE(test_lua_ffi_rr)
+{
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
static const std::string policySetupStr = R"foo(
@@ -645,9 +631,9 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr) {
)foo";
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
- g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
- g_policy.setState(ServerPolicy(name, policy));
- });
+ g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
+ g_policy.setState(ServerPolicy(name, policy));
+ });
g_lua.lock()->executeCode(policySetupStr);
{
@@ -655,15 +641,15 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr) {
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -682,11 +668,50 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_rr) {
resetLuaContext();
}
-BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed) {
+BOOST_AUTO_TEST_CASE(test_lua_ffi_no_server_available)
+{
+ DNSName dnsName("powerdns.com.");
+ static const std::string policySetupStr = R"foo(
+ local ffi = require("ffi")
+ local C = ffi.C
+ local counter = 0
+ function ffipolicy(servers_list, dq)
+ local serversCount = tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list))
+ -- return clearly out of bounds value to indicate that no server can be used
+ return serversCount + 100
+ end
+
+ setServerPolicyLuaFFI("FFI policy", ffipolicy)
+ )foo";
+ resetLuaContext();
+ g_lua.lock()->executeCode(getLuaFFIWrappers());
+ g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& policyName, ServerPolicy::ffipolicyfunc_t policy) {
+ g_policy.setState(ServerPolicy(policyName, std::move(policy)));
+ });
+ g_lua.lock()->executeCode(policySetupStr);
+
+ {
+ ServerPolicy pol = g_policy.getCopy();
+ ServerPolicy::NumberedServerVector servers;
+ for (size_t idx = 1; idx <= 10; idx++) {
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
+ servers.at(idx - 1).second->setUp();
+ }
+ BOOST_REQUIRE_EQUAL(servers.size(), 10U);
+
+ auto dnsQuestion = getDQ(&dnsName);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
+ BOOST_REQUIRE(server == nullptr);
+ }
+ resetLuaContext();
+}
+
+BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed)
+{
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
static const std::string policySetupStr = R"foo(
@@ -702,9 +727,9 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed) {
)foo";
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
- g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
- g_policy.setState(ServerPolicy(name, policy));
- });
+ g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
+ g_policy.setState(ServerPolicy(name, policy));
+ });
g_lua.lock()->executeCode(policySetupStr);
{
@@ -712,15 +737,15 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed) {
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -739,11 +764,12 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_hashed) {
resetLuaContext();
}
-BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed) {
+BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed)
+{
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
static const std::string policySetupStr = R"foo(
@@ -757,9 +783,9 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed) {
)foo";
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
- g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
- g_policy.setState(ServerPolicy(name, policy));
- });
+ g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
+ g_policy.setState(ServerPolicy(name, policy));
+ });
g_lua.lock()->executeCode(policySetupStr);
{
@@ -767,15 +793,15 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed) {
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
@@ -794,14 +820,15 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed) {
resetLuaContext();
}
-BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed) {
+BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
+{
bool existingVerboseValue = g_verbose;
g_verbose = false;
std::vector<DNSName> names;
names.reserve(1000);
for (size_t idx = 0; idx < 1000; idx++) {
- names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ names.emplace_back("powerdns-" + std::to_string(idx) + ".com.");
}
static const std::string policySetupStr = R"foo(
@@ -815,9 +842,9 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed) {
)foo";
resetLuaContext();
g_lua.lock()->executeCode(getLuaFFIWrappers());
- g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
- g_policy.setState(ServerPolicy(name, policy));
- });
+ g_lua.lock()->writeFunction("setServerPolicyLuaFFI", [](const string& name, const ServerPolicy::ffipolicyfunc_t& policy) {
+ g_policy.setState(ServerPolicy(name, policy));
+ });
g_lua.lock()->executeCode(policySetupStr);
{
@@ -825,7 +852,7 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed) {
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.emplace_back(idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")));
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
/* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */
@@ -836,8 +863,8 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed) {
BOOST_REQUIRE_EQUAL(servers.size(), 10U);
for (const auto& name : names) {
- auto dq = getDQ(&name);
- auto server = pol.getSelectedBackend(servers, dq);
+ auto dnsQuestion = getDQ(&name);
+ auto server = pol.getSelectedBackend(servers, dnsQuestion);
BOOST_REQUIRE(serversMap.count(server) == 1);
++serversMap[server];
}
diff --git a/test-dnsdistluanetwork.cc b/test-dnsdistluanetwork.cc
index 1255418..6ddc4a2 100644
--- a/test-dnsdistluanetwork.cc
+++ b/test-dnsdistluanetwork.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
diff --git a/test-dnsdistnghttp2-in_cc.cc b/test-dnsdistnghttp2-in_cc.cc
new file mode 100644
index 0000000..160833c
--- /dev/null
+++ b/test-dnsdistnghttp2-in_cc.cc
@@ -0,0 +1,773 @@
+/*
+ * 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 <boost/test/unit_test.hpp>
+
+#include "dnswriter.hh"
+#include "dnsdist.hh"
+#include "dnsdist-proxy-protocol.hh"
+#include "dnsdist-nghttp2-in.hh"
+
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
+#include <nghttp2/nghttp2.h>
+
+extern std::function<ProcessQueryResult(DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
+
+BOOST_AUTO_TEST_SUITE(test_dnsdistnghttp2_in_cc)
+
+struct ExpectedStep
+{
+public:
+ enum class ExpectedRequest
+ {
+ handshakeClient,
+ readFromClient,
+ writeToClient,
+ closeClient,
+ };
+
+ ExpectedStep(ExpectedRequest req, IOState next, size_t bytes_ = 0, std::function<void(int descriptor)> func = nullptr) :
+ cb(std::move(func)), request(req), nextState(next), bytes(bytes_)
+ {
+ }
+
+ std::function<void(int descriptor)> cb{nullptr};
+ ExpectedRequest request;
+ IOState nextState;
+ size_t bytes{0};
+};
+
+struct ExpectedData
+{
+ PacketBuffer d_proxyProtocolPayload;
+ std::vector<PacketBuffer> d_queries;
+ std::vector<PacketBuffer> d_responses;
+ std::vector<uint16_t> d_responseCodes;
+};
+
+class DOHConnection;
+
+static std::deque<ExpectedStep> s_steps;
+static std::map<uint64_t, ExpectedData> s_connectionContexts;
+static std::map<int, std::unique_ptr<DOHConnection>> s_connectionBuffers;
+static uint64_t s_connectionID{0};
+
+std::ostream& operator<<(std::ostream& outs, ExpectedStep::ExpectedRequest step);
+
+std::ostream& operator<<(std::ostream& outs, ExpectedStep::ExpectedRequest step)
+{
+ static const std::vector<std::string> requests = {"handshake with client", "read from client", "write to client", "close connection to client", "connect to the backend", "read from the backend", "write to the backend", "close connection to backend"};
+ outs << requests.at(static_cast<size_t>(step));
+ return outs;
+}
+
+class DOHConnection
+{
+public:
+ DOHConnection(uint64_t connectionID) :
+ d_session(std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)>(nullptr, nghttp2_session_del)), d_connectionID(connectionID)
+ {
+ const auto& context = s_connectionContexts.at(connectionID);
+ d_clientOutBuffer.insert(d_clientOutBuffer.begin(), context.d_proxyProtocolPayload.begin(), context.d_proxyProtocolPayload.end());
+
+ nghttp2_session_callbacks* cbs = nullptr;
+ nghttp2_session_callbacks_new(&cbs);
+ std::unique_ptr<nghttp2_session_callbacks, void (*)(nghttp2_session_callbacks*)> callbacks(cbs, nghttp2_session_callbacks_del);
+ cbs = nullptr;
+ nghttp2_session_callbacks_set_send_callback(callbacks.get(), send_callback);
+ nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks.get(), on_frame_recv_callback);
+ nghttp2_session_callbacks_set_on_header_callback(callbacks.get(), on_header_callback);
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks.get(), on_data_chunk_recv_callback);
+ nghttp2_session_callbacks_set_on_stream_close_callback(callbacks.get(), on_stream_close_callback);
+ nghttp2_session* sess = nullptr;
+ nghttp2_session_client_new(&sess, callbacks.get(), this);
+ d_session = std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)>(sess, nghttp2_session_del);
+
+ std::array<nghttp2_settings_entry, 3> settings{
+ /* rfc7540 section-8.2.2:
+ "Advertising a SETTINGS_MAX_CONCURRENT_STREAMS value of zero disables
+ server push by preventing the server from creating the necessary
+ streams."
+ */
+ nghttp2_settings_entry{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0},
+ nghttp2_settings_entry{NGHTTP2_SETTINGS_ENABLE_PUSH, 0},
+ /* we might want to make the initial window size configurable, but 16M is a large enough default */
+ nghttp2_settings_entry{NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 16 * 1024 * 1024}};
+ /* client 24 bytes magic string will be sent by nghttp2 library */
+ auto result = nghttp2_submit_settings(d_session.get(), NGHTTP2_FLAG_NONE, settings.data(), settings.size());
+ if (result != 0) {
+ throw std::runtime_error("Error submitting settings:" + std::string(nghttp2_strerror(result)));
+ }
+
+ const std::string host("unit-tests");
+ const std::string path("/dns-query");
+ for (const auto& query : context.d_queries) {
+ const auto querySize = std::to_string(query.size());
+ std::vector<nghttp2_nv> headers;
+ /* Pseudo-headers need to come first (rfc7540 8.1.2.1) */
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::METHOD_NAME, NGHTTP2Headers::HeaderConstantIndexes::METHOD_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_NAME, NGHTTP2Headers::HeaderConstantIndexes::SCHEME_VALUE);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::AUTHORITY_NAME, host);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::PATH_NAME, path);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_NAME, NGHTTP2Headers::HeaderConstantIndexes::ACCEPT_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_NAME, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_TYPE_VALUE);
+ NGHTTP2Headers::addStaticHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_NAME, NGHTTP2Headers::HeaderConstantIndexes::USER_AGENT_VALUE);
+ NGHTTP2Headers::addDynamicHeader(headers, NGHTTP2Headers::HeaderConstantIndexes::CONTENT_LENGTH_NAME, querySize);
+
+ d_position = 0;
+ d_currentQuery = query;
+ nghttp2_data_provider data_provider;
+ data_provider.source.ptr = this;
+ data_provider.read_callback = [](nghttp2_session* session, int32_t stream_id, uint8_t* buf, size_t length, uint32_t* data_flags, nghttp2_data_source* source, void* user_data) -> ssize_t {
+ auto* conn = static_cast<DOHConnection*>(user_data);
+ auto& pos = conn->d_position;
+ const auto& currentQuery = conn->d_currentQuery;
+ size_t toCopy = 0;
+ if (pos < currentQuery.size()) {
+ size_t remaining = currentQuery.size() - pos;
+ toCopy = length > remaining ? remaining : length;
+ memcpy(buf, &currentQuery.at(pos), toCopy);
+ pos += toCopy;
+ }
+
+ if (pos >= currentQuery.size()) {
+ *data_flags |= NGHTTP2_DATA_FLAG_EOF;
+ }
+ return static_cast<ssize_t>(toCopy);
+ };
+
+ auto newStreamId = nghttp2_submit_request(d_session.get(), nullptr, headers.data(), headers.size(), &data_provider, this);
+ if (newStreamId < 0) {
+ throw std::runtime_error("Error submitting HTTP request:" + std::string(nghttp2_strerror(newStreamId)));
+ }
+
+ result = nghttp2_session_send(d_session.get());
+ if (result != 0) {
+ throw std::runtime_error("Error in nghttp2_session_send:" + std::to_string(result));
+ }
+ }
+ }
+
+ std::map<int32_t, PacketBuffer> d_responses;
+ std::map<int32_t, uint16_t> d_responseCodes;
+ std::unique_ptr<nghttp2_session, void (*)(nghttp2_session*)> d_session;
+ PacketBuffer d_currentQuery;
+ PacketBuffer d_clientOutBuffer;
+ uint64_t d_connectionID{0};
+ size_t d_position{0};
+
+ void submitIncoming(const PacketBuffer& data, size_t pos, size_t toWrite) const
+ {
+ ssize_t readlen = nghttp2_session_mem_recv(d_session.get(), &data.at(pos), toWrite);
+ if (readlen < 0) {
+ throw("Fatal error while submitting line " + std::to_string(__LINE__) + ": " + std::string(nghttp2_strerror(static_cast<int>(readlen))));
+ }
+
+ /* just in case, see if we have anything to send */
+ int got = nghttp2_session_send(d_session.get());
+ if (got != 0) {
+ throw("Fatal error while sending: " + std::string(nghttp2_strerror(got)));
+ }
+ }
+
+private:
+ static ssize_t send_callback(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data)
+ {
+ auto* conn = static_cast<DOHConnection*>(user_data);
+ //NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): nghttp2 API
+ conn->d_clientOutBuffer.insert(conn->d_clientOutBuffer.end(), data, data + length);
+ return static_cast<ssize_t>(length);
+ }
+
+ static int on_frame_recv_callback(nghttp2_session* session, const nghttp2_frame* frame, void* user_data)
+ {
+ auto* conn = static_cast<DOHConnection*>(user_data);
+ if ((frame->hd.type == NGHTTP2_HEADERS || frame->hd.type == NGHTTP2_DATA) && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) != 0) {
+ const auto& response = conn->d_responses.at(frame->hd.stream_id);
+ if (conn->d_responseCodes.at(frame->hd.stream_id) != 200U) {
+ return 0;
+ }
+
+ BOOST_REQUIRE_GT(response.size(), sizeof(dnsheader));
+ const dnsheader_aligned dnsHeader(response.data());
+ uint16_t queryID = ntohs(dnsHeader.get()->id);
+
+ const auto& expected = s_connectionContexts.at(conn->d_connectionID).d_responses.at(queryID);
+ BOOST_REQUIRE_EQUAL(expected.size(), response.size());
+ for (size_t idx = 0; idx < response.size(); idx++) {
+ if (expected.at(idx) != response.at(idx)) {
+ cerr << "Mismatch at offset " << idx << ", expected " << std::to_string(response.at(idx)) << " got " << std::to_string(expected.at(idx)) << endl;
+ BOOST_CHECK(false);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ static int on_data_chunk_recv_callback(nghttp2_session* session, uint8_t flags, int32_t stream_id, const uint8_t* data, size_t len, void* user_data)
+ {
+ auto* conn = static_cast<DOHConnection*>(user_data);
+ auto& response = conn->d_responses[stream_id];
+ //NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): nghttp2 API
+ response.insert(response.end(), data, data + len);
+ return 0;
+ }
+
+ static int on_header_callback(nghttp2_session* session, const nghttp2_frame* frame, const uint8_t* name, size_t namelen, const uint8_t* value, size_t valuelen, uint8_t flags, void* user_data)
+ {
+ auto* conn = static_cast<DOHConnection*>(user_data);
+ const std::string status(":status");
+ if (frame->hd.type == NGHTTP2_HEADERS && frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
+ if (namelen == status.size() && memcmp(status.data(), name, status.size()) == 0) {
+ try {
+ uint16_t responseCode{0};
+ auto expected = s_connectionContexts.at(conn->d_connectionID).d_responseCodes.at((frame->hd.stream_id - 1) / 2);
+ //NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): nghttp2 API
+ pdns::checked_stoi_into(responseCode, std::string(reinterpret_cast<const char*>(value), valuelen));
+ conn->d_responseCodes[frame->hd.stream_id] = responseCode;
+ if (responseCode != expected) {
+ cerr << "Mismatch response code, expected " << std::to_string(expected) << " got " << std::to_string(responseCode) << endl;
+ BOOST_CHECK(false);
+ }
+ }
+ catch (const std::exception& e) {
+ infolog("Error parsing the status header for stream ID %d: %s", frame->hd.stream_id, e.what());
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ }
+ }
+ return 0;
+ }
+
+ static int on_stream_close_callback(nghttp2_session* session, int32_t stream_id, uint32_t error_code, void* user_data)
+ {
+ return 0;
+ }
+};
+
+class MockupTLSConnection : public TLSConnection
+{
+public:
+ MockupTLSConnection(int descriptor, [[maybe_unused]] bool client = false, [[maybe_unused]] bool needProxyProtocol = false) :
+ d_descriptor(descriptor)
+ {
+ auto connectionID = s_connectionID++;
+ auto conn = std::make_unique<DOHConnection>(connectionID);
+ s_connectionBuffers[d_descriptor] = std::move(conn);
+ }
+ MockupTLSConnection(const MockupTLSConnection&) = delete;
+ MockupTLSConnection(MockupTLSConnection&&) = delete;
+ MockupTLSConnection& operator=(const MockupTLSConnection&) = delete;
+ MockupTLSConnection& operator=(MockupTLSConnection&&) = delete;
+ ~MockupTLSConnection() override = default;
+
+ IOState tryHandshake() override
+ {
+ auto step = getStep();
+ BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::handshakeClient);
+
+ return step.nextState;
+ }
+
+ IOState tryWrite(const PacketBuffer& buffer, size_t& pos, size_t toWrite) override
+ {
+ auto& conn = s_connectionBuffers.at(d_descriptor);
+ auto step = getStep();
+ BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::writeToClient);
+
+ if (step.bytes == 0) {
+ if (step.nextState == IOState::NeedWrite) {
+ return step.nextState;
+ }
+ throw std::runtime_error("Remote host closed the connection");
+ }
+
+ toWrite -= pos;
+ BOOST_REQUIRE_GE(buffer.size(), pos + toWrite);
+
+ if (step.bytes < toWrite) {
+ toWrite = step.bytes;
+ }
+
+ conn->submitIncoming(buffer, pos, toWrite);
+ pos += toWrite;
+
+ return step.nextState;
+ }
+
+ IOState tryRead(PacketBuffer& buffer, size_t& pos, size_t toRead, bool allowIncomplete = false) override
+ {
+ auto& conn = s_connectionBuffers.at(d_descriptor);
+ auto step = getStep();
+ BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::readFromClient);
+
+ if (step.bytes == 0) {
+ if (step.nextState == IOState::NeedRead) {
+ return step.nextState;
+ }
+ throw std::runtime_error("Remote host closed the connection");
+ }
+
+ auto& externalBuffer = conn->d_clientOutBuffer;
+ toRead -= pos;
+
+ if (step.bytes < toRead) {
+ toRead = step.bytes;
+ }
+ if (allowIncomplete) {
+ if (toRead > externalBuffer.size()) {
+ toRead = externalBuffer.size();
+ }
+ }
+ else {
+ BOOST_REQUIRE_GE(externalBuffer.size(), toRead);
+ }
+
+ BOOST_REQUIRE_GE(buffer.size(), toRead);
+
+ //NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ std::copy(externalBuffer.begin(), externalBuffer.begin() + toRead, buffer.begin() + pos);
+ pos += toRead;
+ //NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ externalBuffer.erase(externalBuffer.begin(), externalBuffer.begin() + toRead);
+
+ return step.nextState;
+ }
+
+ IOState tryConnect(bool fastOpen, const ComboAddress& remote) override
+ {
+ throw std::runtime_error("Should not happen");
+ }
+
+ void close() override
+ {
+ auto step = getStep();
+ BOOST_REQUIRE_EQUAL(step.request, ExpectedStep::ExpectedRequest::closeClient);
+ }
+
+ [[nodiscard]] bool isUsable() const override
+ {
+ return true;
+ }
+
+ [[nodiscard]] std::string getServerNameIndication() const override
+ {
+ return "";
+ }
+
+ [[nodiscard]] std::vector<uint8_t> getNextProtocol() const override
+ {
+ return std::vector<uint8_t>{'h', '2'};
+ }
+
+ [[nodiscard]] LibsslTLSVersion getTLSVersion() const override
+ {
+ return LibsslTLSVersion::TLS13;
+ }
+
+ [[nodiscard]] bool hasSessionBeenResumed() const override
+ {
+ return false;
+ }
+
+ [[nodiscard]] std::vector<std::unique_ptr<TLSSession>> getSessions() override
+ {
+ return {};
+ }
+
+ void setSession(std::unique_ptr<TLSSession>& session) override
+ {
+ }
+
+ [[nodiscard]] std::vector<int> getAsyncFDs() override
+ {
+ return {};
+ }
+
+ /* unused in that context, don't bother */
+ void doHandshake() override
+ {
+ }
+
+ void connect(bool fastOpen, const ComboAddress& remote, const struct timeval& timeout) override
+ {
+ }
+
+ size_t read(void* buffer, size_t bufferSize, const struct timeval& readTimeout, const struct timeval& totalTimeout = {0, 0}, bool allowIncomplete = false) override
+ {
+ return 0;
+ }
+
+ size_t write(const void* buffer, size_t bufferSize, const struct timeval& writeTimeout) override
+ {
+ return 0;
+ }
+
+private:
+ [[nodiscard]] ExpectedStep getStep() const
+ {
+ BOOST_REQUIRE(!s_steps.empty());
+ auto step = s_steps.front();
+ s_steps.pop_front();
+
+ if (step.cb) {
+ step.cb(d_descriptor);
+ }
+
+ return step;
+ }
+
+ const int d_descriptor;
+};
+
+#include "test-dnsdistnghttp2_common.hh"
+
+struct TestFixture
+{
+ TestFixture()
+ {
+ reset();
+ }
+ TestFixture(const TestFixture&) = delete;
+ TestFixture(TestFixture&&) = delete;
+ TestFixture& operator=(const TestFixture&) = delete;
+ TestFixture& operator=(TestFixture&&) = delete;
+ ~TestFixture()
+ {
+ reset();
+ }
+
+private:
+ void reset()
+ {
+ s_steps.clear();
+ s_connectionContexts.clear();
+ s_connectionBuffers.clear();
+ s_connectionID = 0;
+ /* we _NEED_ to set this function to empty otherwise we might get what was set
+ by the last test, and we might not like it at all */
+ s_processQuery = nullptr;
+ g_proxyProtocolACL.clear();
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
+{
+ auto local = getBackendAddress("1", 80);
+ ClientState localCS(local, true, false, 0, "", {}, true);
+ localCS.dohFrontend = std::make_shared<DOHFrontend>(std::make_shared<MockupTLSCtx>());
+ localCS.dohFrontend->d_urls.insert("/dns-query");
+
+ TCPClientThreadData threadData;
+ threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
+
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+
+ size_t counter = 0;
+ DNSName name("powerdns.com.");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ pwQ.getHeader()->id = htons(counter);
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->id = htons(counter);
+ pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfr32BitInt(0x01020304);
+ pwR.commit();
+
+ {
+ /* dnsdist drops the query right away after receiving it, client closes the connection */
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {403U}};
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* settings + headers + data client -> server.. */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 128},
+ /* .. continued */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 60},
+ /* headers + data */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, std::numeric_limits<size_t>::max()},
+ /* wait for next query, but the client closes the connection */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ }
+
+ {
+ /* client closes the connection right in the middle of sending the query */
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {403U}};
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* client sends one byte */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 1},
+ /* then closes the connection */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ /* mark the incoming FD as always ready */
+ dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
+ threadData.mplexer->run(&now);
+ }
+ }
+
+ {
+ /* dnsdist sends a response right away, client closes the connection after getting the response */
+ s_processQuery = [response](DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
+ /* self answered */
+ dnsQuestion.getMutableData() = response;
+ return ProcessQueryResult::SendAnswer;
+ };
+
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {200U}};
+
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* settings + headers + data client -> server.. */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 128},
+ /* .. continued */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 60},
+ /* headers + data */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, std::numeric_limits<size_t>::max()},
+ /* wait for next query, but the client closes the connection */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ }
+
+ {
+ /* dnsdist sends a response right away, but the client closes the connection without even reading the response */
+ s_processQuery = [response](DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
+ /* self answered */
+ dnsQuestion.getMutableData() = response;
+ return ProcessQueryResult::SendAnswer;
+ };
+
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {200U}};
+
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* settings + headers + data client -> server.. */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 128},
+ /* .. continued */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 60},
+ /* we want to send the response but the client closes the connection */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ /* mark the incoming FD as always ready */
+ dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
+ threadData.mplexer->run(&now);
+ }
+ }
+
+ {
+ /* dnsdist sends a response right away, client closes the connection while getting the response */
+ s_processQuery = [response](DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
+ /* self answered */
+ dnsQuestion.getMutableData() = response;
+ return ProcessQueryResult::SendAnswer;
+ };
+
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {200U}};
+
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* settings + headers + data client -> server.. */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 128},
+ /* .. continued */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 60},
+ /* headers + data (partial write) */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::NeedWrite, 1},
+ /* nothing to read after that */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead, 0},
+ /* then the client closes the connection before we are done */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ /* mark the incoming FD as always ready */
+ dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
+ threadData.mplexer->run(&now);
+ }
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendTimeout, TestFixture)
+{
+ auto local = getBackendAddress("1", 80);
+ ClientState localCS(local, true, false, 0, "", {}, true);
+ localCS.dohFrontend = std::make_shared<DOHFrontend>(std::make_shared<MockupTLSCtx>());
+ localCS.dohFrontend->d_urls.insert("/dns-query");
+
+ TCPClientThreadData threadData;
+ threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
+
+ auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
+
+ struct timeval now
+ {
+ };
+ gettimeofday(&now, nullptr);
+
+ size_t counter = 0;
+ DNSName name("powerdns.com.");
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ pwQ.getHeader()->id = htons(counter);
+
+ PacketBuffer response;
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->id = htons(counter);
+ pwR.startRecord(name, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ pwR.xfr32BitInt(0x01020304);
+ pwR.commit();
+
+ {
+ /* dnsdist forwards the query to the backend, which does not answer -> timeout */
+ s_processQuery = [backend](DNSQuestion& dnsQuestion, std::shared_ptr<DownstreamState>& selectedBackend) -> ProcessQueryResult {
+ selectedBackend = backend;
+ return ProcessQueryResult::PassToBackend;
+ };
+ s_connectionContexts[counter++] = ExpectedData{{}, {query}, {response}, {502U}};
+ s_steps = {
+ /* opening */
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* settings server -> client */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 15},
+ /* settings + headers + data client -> server.. */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 128},
+ /* .. continued */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 60},
+ /* trying to read a new request while processing the first one */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::NeedRead},
+ /* headers + data */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, std::numeric_limits<size_t>::max(), [&threadData](int desc) {
+ /* set the incoming descriptor as ready */
+ dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(desc);
+ }},
+ /* wait for next query, but the client closes the connection */
+ {ExpectedStep::ExpectedRequest::readFromClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ state->handleIO();
+ TCPResponse resp;
+ resp.d_idstate.d_streamID = 1;
+ state->notifyIOError(now, std::move(resp));
+ while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
+ threadData.mplexer->run(&now);
+ }
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_ClientTimeout_BackendTimeout, TestFixture)
+{
+ auto local = getBackendAddress("1", 80);
+ ClientState localCS(local, true, false, 0, "", {}, true);
+ localCS.dohFrontend = std::make_shared<DOHFrontend>(std::make_shared<MockupTLSCtx>());
+ localCS.dohFrontend->d_urls.insert("/dns-query");
+
+ TCPClientThreadData threadData;
+ threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
+
+ auto backend = std::make_shared<DownstreamState>(getBackendAddress("42", 53));
+
+ timeval now{};
+ gettimeofday(&now, nullptr);
+
+ size_t counter = 0;
+ s_connectionContexts[counter++] = ExpectedData{{}, {}, {}, {}};
+ s_steps = {
+ {ExpectedStep::ExpectedRequest::handshakeClient, IOState::Done},
+ /* write to client, but the client closes the connection */
+ {ExpectedStep::ExpectedRequest::writeToClient, IOState::Done, 0},
+ /* server close */
+ {ExpectedStep::ExpectedRequest::closeClient, IOState::Done},
+ };
+
+ auto state = std::make_shared<IncomingHTTP2Connection>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
+ auto base = std::static_pointer_cast<IncomingTCPConnectionState>(state);
+ IncomingHTTP2Connection::handleTimeout(base, true);
+ state->handleIO();
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
diff --git a/test-dnsdistnghttp2_cc.cc b/test-dnsdistnghttp2_cc.cc
index 41d9992..98c3724 100644
--- a/test-dnsdistnghttp2_cc.cc
+++ b/test-dnsdistnghttp2_cc.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -31,7 +34,7 @@
#include "dnsdist-nghttp2.hh"
#include "sstuff.hh"
-#ifdef HAVE_NGHTTP2
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
#include <nghttp2/nghttp2.h>
BOOST_AUTO_TEST_SUITE(test_dnsdistnghttp2_cc)
@@ -70,6 +73,7 @@ struct ExpectedData
static std::deque<ExpectedStep> s_steps;
static std::map<uint16_t, ExpectedData> s_responses;
+static std::unique_ptr<FDMultiplexer> s_mplexer;
std::ostream& operator<<(std::ostream& os, const ExpectedStep::ExpectedRequest d);
@@ -250,7 +254,7 @@ private:
auto& query = conn->d_queries.at(frame->hd.stream_id);
BOOST_REQUIRE_GT(query.size(), sizeof(dnsheader));
- auto dh = reinterpret_cast<const dnsheader*>(query.data());
+ const dnsheader_aligned dh(query.data());
uint16_t id = ntohs(dh->id);
// cerr<<"got query ID "<<id<<endl;
@@ -405,11 +409,6 @@ public:
BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::closeClient : ExpectedStep::ExpectedRequest::closeBackend);
}
- bool hasBufferedData() const override
- {
- return false;
- }
-
bool isUsable() const override
{
return true;
@@ -486,110 +485,7 @@ private:
bool d_client{false};
};
-class MockupTLSCtx : public TLSCtx
-{
-public:
- ~MockupTLSCtx()
- {
- }
-
- std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) override
- {
- return std::make_unique<MockupTLSConnection>(socket);
- }
-
- std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) override
- {
- return std::make_unique<MockupTLSConnection>(socket, true, d_needProxyProtocol);
- }
-
- void rotateTicketsKey(time_t now) override
- {
- }
-
- size_t getTicketsKeysCount() override
- {
- return 0;
- }
-
- std::string getName() const override
- {
- return "Mockup TLS";
- }
-
- bool d_needProxyProtocol{false};
-};
-
-class MockupFDMultiplexer : public FDMultiplexer
-{
-public:
- MockupFDMultiplexer()
- {
- }
-
- ~MockupFDMultiplexer()
- {
- }
-
- int run(struct timeval* tv, int timeout = 500) override
- {
- int ret = 0;
-
- gettimeofday(tv, nullptr); // MANDATORY
-
- /* 'ready' might be altered by a callback while we are iterating */
- const auto readyFDs = ready;
- for (const auto fd : readyFDs) {
- {
- const auto& it = d_readCallbacks.find(fd);
-
- if (it != d_readCallbacks.end()) {
- it->d_callback(it->d_fd, it->d_parameter);
- }
- }
-
- {
- const auto& it = d_writeCallbacks.find(fd);
-
- if (it != d_writeCallbacks.end()) {
- it->d_callback(it->d_fd, it->d_parameter);
- }
- }
- }
-
- return ret;
- }
-
- void getAvailableFDs(std::vector<int>& fds, int timeout) override
- {
- }
-
- void addFD(int fd, FDMultiplexer::EventKind kind) override
- {
- }
-
- void removeFD(int fd, FDMultiplexer::EventKind) override
- {
- }
-
- string getName() const override
- {
- return "mockup";
- }
-
- void setReady(int fd)
- {
- ready.insert(fd);
- }
-
- void setNotReady(int fd)
- {
- ready.erase(fd);
- }
-
-private:
- std::set<int> ready;
-};
+#include "test-dnsdistnghttp2_common.hh"
class MockupQuerySender : public TCPQuerySender
{
@@ -607,7 +503,7 @@ public:
}
BOOST_REQUIRE_GT(response.d_buffer.size(), sizeof(dnsheader));
- auto dh = reinterpret_cast<const dnsheader*>(response.d_buffer.data());
+ const dnsheader_aligned dh(response.d_buffer.data());
uint16_t id = ntohs(dh->id);
BOOST_REQUIRE_EQUAL(id, d_id);
@@ -626,11 +522,11 @@ public:
d_valid = true;
}
- void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
+ void handleXFRResponse([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
}
- void notifyIOError(InternalQueryState&& query, const struct timeval& now) override
+ void notifyIOError([[maybe_unused]] const struct timeval& now, [[maybe_unused]] TCPResponse&& response) override
{
d_error = true;
}
@@ -641,36 +537,6 @@ public:
bool d_error{false};
};
-static bool isIPv6Supported()
-{
- try {
- ComboAddress addr("[2001:db8:53::1]:53");
- auto socket = std::make_unique<Socket>(addr.sin4.sin_family, SOCK_STREAM, 0);
- socket->setNonBlocking();
- int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0});
- if (res == 0 || res == EINPROGRESS) {
- return true;
- }
- return false;
- }
- catch (const std::exception& e) {
- return false;
- }
-}
-
-static ComboAddress getBackendAddress(const std::string& lastDigit, uint16_t port)
-{
- static const bool useV6 = isIPv6Supported();
-
- if (useV6) {
- return ComboAddress("2001:db8:53::" + lastDigit, port);
- }
-
- return ComboAddress("192.0.2." + lastDigit, port);
-}
-
-static std::unique_ptr<FDMultiplexer> s_mplexer;
-
struct TestFixture
{
TestFixture()
@@ -691,7 +557,7 @@ struct TestFixture
BOOST_FIXTURE_TEST_CASE(test_SingleQuery, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -767,7 +633,7 @@ BOOST_FIXTURE_TEST_CASE(test_SingleQuery, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ConcurrentQueries, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -856,7 +722,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConcurrentQueries, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ConnectionReuse, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -964,7 +830,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionReuse, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_InvalidDNSAnswer, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1045,7 +911,7 @@ BOOST_FIXTURE_TEST_CASE(test_InvalidDNSAnswer, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileWriting, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1132,7 +998,7 @@ BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileWriting, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileReading, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1219,7 +1085,7 @@ BOOST_FIXTURE_TEST_CASE(test_TimeoutWhileReading, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ShortWrite, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1306,7 +1172,7 @@ BOOST_FIXTURE_TEST_CASE(test_ShortWrite, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ShortRead, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1400,7 +1266,7 @@ BOOST_FIXTURE_TEST_CASE(test_ShortRead, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileReading, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1486,7 +1352,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileReading, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileWriting, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1580,7 +1446,7 @@ BOOST_FIXTURE_TEST_CASE(test_ConnectionClosedWhileWriting, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_GoAwayFromServer, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1691,7 +1557,7 @@ BOOST_FIXTURE_TEST_CASE(test_GoAwayFromServer, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_HTTP500FromServer, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1784,7 +1650,7 @@ BOOST_FIXTURE_TEST_CASE(test_HTTP500FromServer, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_WrongStreamID, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1884,7 +1750,7 @@ BOOST_FIXTURE_TEST_CASE(test_WrongStreamID, TestFixture)
BOOST_FIXTURE_TEST_CASE(test_ProxyProtocol, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
tlsCtx->d_needProxyProtocol = true;
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -1983,4 +1849,4 @@ BOOST_FIXTURE_TEST_CASE(test_ProxyProtocol, TestFixture)
}
BOOST_AUTO_TEST_SUITE_END();
-#endif /* HAVE_NGHTTP2 */
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
diff --git a/test-dnsdistnghttp2_common.hh b/test-dnsdistnghttp2_common.hh
new file mode 100644
index 0000000..b6f9bdd
--- /dev/null
+++ b/test-dnsdistnghttp2_common.hh
@@ -0,0 +1,155 @@
+/*
+ * 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
+
+class MockupTLSCtx : public TLSCtx
+{
+public:
+ ~MockupTLSCtx()
+ {
+ }
+
+ std::unique_ptr<TLSConnection> getConnection(int socket, const struct timeval& timeout, time_t now) override
+ {
+ return std::make_unique<MockupTLSConnection>(socket);
+ }
+
+ std::unique_ptr<TLSConnection> getClientConnection(const std::string& host, bool hostIsAddr, int socket, const struct timeval& timeout) override
+ {
+ return std::make_unique<MockupTLSConnection>(socket, true, d_needProxyProtocol);
+ }
+
+ void rotateTicketsKey(time_t now) override
+ {
+ }
+
+ size_t getTicketsKeysCount() override
+ {
+ return 0;
+ }
+
+ std::string getName() const override
+ {
+ return "Mockup TLS";
+ }
+
+ bool d_needProxyProtocol{false};
+};
+
+class MockupFDMultiplexer : public FDMultiplexer
+{
+public:
+ MockupFDMultiplexer()
+ {
+ }
+
+ ~MockupFDMultiplexer()
+ {
+ }
+
+ int run(struct timeval* tv, int timeout = 500) override
+ {
+ int ret = 0;
+
+ gettimeofday(tv, nullptr); // MANDATORY
+
+ /* 'ready' might be altered by a callback while we are iterating */
+ const auto readyFDs = ready;
+ for (const auto fd : readyFDs) {
+ {
+ const auto& it = d_readCallbacks.find(fd);
+
+ if (it != d_readCallbacks.end()) {
+ it->d_callback(it->d_fd, it->d_parameter);
+ }
+ }
+
+ {
+ const auto& it = d_writeCallbacks.find(fd);
+
+ if (it != d_writeCallbacks.end()) {
+ it->d_callback(it->d_fd, it->d_parameter);
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ void getAvailableFDs(std::vector<int>& fds, int timeout) override
+ {
+ }
+
+ void addFD(int fd, FDMultiplexer::EventKind kind) override
+ {
+ }
+
+ void removeFD(int fd, FDMultiplexer::EventKind) override
+ {
+ }
+
+ string getName() const override
+ {
+ return "mockup";
+ }
+
+ void setReady(int fd)
+ {
+ ready.insert(fd);
+ }
+
+ void setNotReady(int fd)
+ {
+ ready.erase(fd);
+ }
+
+private:
+ std::set<int> ready;
+};
+
+static bool isIPv6Supported()
+{
+ try {
+ ComboAddress addr("[2001:db8:53::1]:53");
+ auto socket = std::make_unique<Socket>(addr.sin4.sin_family, SOCK_STREAM, 0);
+ socket->setNonBlocking();
+ int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0});
+ if (res == 0 || res == EINPROGRESS) {
+ return true;
+ }
+ return false;
+ }
+ catch (const std::exception& e) {
+ return false;
+ }
+}
+
+static ComboAddress getBackendAddress(const std::string& lastDigit, uint16_t port)
+{
+ static const bool useV6 = isIPv6Supported();
+
+ if (useV6) {
+ return ComboAddress("2001:db8:53::" + lastDigit, port);
+ }
+
+ return ComboAddress("192.0.2." + lastDigit, port);
+}
diff --git a/test-dnsdistpacketcache_cc.cc b/test-dnsdistpacketcache_cc.cc
index 4bad3d0..42d2bad 100644
--- a/test-dnsdistpacketcache_cc.cc
+++ b/test-dnsdistpacketcache_cc.cc
@@ -1,4 +1,7 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
@@ -52,17 +55,17 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
if (found == true) {
- BOOST_CHECK_EQUAL(dq.getData().size(), response.size());
- int match = memcmp(dq.getData().data(), response.data(), dq.getData().size());
+ BOOST_CHECK_EQUAL(dnsQuestion.getData().size(), response.size());
+ int match = memcmp(dnsQuestion.getData().data(), response.data(), dnsQuestion.getData().size());
BOOST_CHECK_EQUAL(match, 0);
BOOST_CHECK(!subnet);
}
@@ -83,8 +86,8 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
pwQ.getHeader()->rd = 1;
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
if (found == true) {
auto removed = PC.expungeByName(ids.qname);
BOOST_CHECK_EQUAL(removed, 1U);
@@ -102,8 +105,8 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
pwQ.getHeader()->rd = 1;
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
+ DNSQuestion dnsQuestion(ids, query);
+ if (PC.get(dnsQuestion, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
matches++;
}
}
@@ -157,23 +160,23 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) {
pwR.getHeader()->qr = 1;
pwR.getHeader()->id = pwQ.getHeader()->id;
pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
- ComboAddress v6("2001:db8::1");
- pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
+ ComboAddress v6addr("2001:db8::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
pwR.commit();
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
if (found == true) {
- BOOST_CHECK_EQUAL(dq.getData().size(), response.size());
- int match = memcmp(dq.getData().data(), response.data(), dq.getData().size());
+ BOOST_CHECK_EQUAL(dnsQuestion.getData().size(), response.size());
+ int match = memcmp(dnsQuestion.getData().data(), response.data(), dnsQuestion.getData().size());
BOOST_CHECK_EQUAL(match, 0);
BOOST_CHECK(!subnet);
}
@@ -194,8 +197,8 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) {
pwQ.getHeader()->rd = 1;
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
+ DNSQuestion dnsQuestion(ids, query);
+ if (PC.get(dnsQuestion, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
matches++;
}
}
@@ -252,21 +255,21 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) {
pwR.getHeader()->qr = 1;
pwR.getHeader()->id = pwQ.getHeader()->id;
pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
- ComboAddress v6("2001:db8::1");
- pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
+ ComboAddress v6addr("2001:db8::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
pwR.commit();
{
/* UDP */
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
}
@@ -276,13 +279,13 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
ids.protocol = dnsdist::Protocol::DoTCP;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, !receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
}
@@ -322,20 +325,20 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL of 0 (-> should not enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0));
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0));
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL non-zero (-> should enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300));
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300));
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
}
@@ -378,19 +381,19 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
@@ -433,19 +436,19 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
@@ -487,20 +490,20 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
bool allowTruncated = true;
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
allowTruncated = false;
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
BOOST_CHECK_EQUAL(found, false);
}
catch(const PDNSException& e) {
@@ -509,6 +512,155 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) {
}
}
+BOOST_AUTO_TEST_CASE(test_PacketCacheMaximumSize) {
+ const size_t maxEntries = 150000;
+ DNSDistPacketCache packetCache(maxEntries, 86400, 1);
+ InternalQueryState ids;
+ ids.qtype = QType::A;
+ ids.qclass = QClass::IN;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+
+ ComboAddress remote;
+ bool dnssecOK = false;
+ ids.qname = DNSName("maximum.size");
+
+ PacketBuffer query;
+ uint16_t queryID{0};
+ {
+ GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0);
+ pwQ.getHeader()->rd = 1;
+ queryID = pwQ.getHeader()->id;
+ }
+
+ PacketBuffer response;
+ {
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = queryID;
+ pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ ComboAddress v6addr("2001:db8::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
+ pwR.commit();
+ }
+
+ /* first, we set the maximum entry size to the response packet size */
+ packetCache.setMaximumEntrySize(response.size());
+
+ {
+ /* UDP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, true);
+ BOOST_CHECK(!subnet);
+ }
+
+ {
+ /* same but over TCP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ ids.protocol = dnsdist::Protocol::DoTCP;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, true);
+ BOOST_CHECK(!subnet);
+ }
+
+ /* then we set it slightly below response packet size */
+ packetCache.expunge(0);
+ packetCache.setMaximumEntrySize(response.size() - 1);
+ {
+ /* UDP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, false);
+ }
+
+ {
+ /* same but over TCP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ ids.protocol = dnsdist::Protocol::DoTCP;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, false);
+ }
+
+ /* now we generate a very big response packet, it should be cached over TCP and UDP (although in practice dnsdist will refuse to cache it for the UDP case) */
+ packetCache.expunge(0);
+ response.clear();
+ {
+ GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0);
+ pwR.getHeader()->rd = 1;
+ pwR.getHeader()->ra = 1;
+ pwR.getHeader()->qr = 1;
+ pwR.getHeader()->id = queryID;
+ for (size_t idx = 0; idx < 1000; idx++) {
+ pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
+ ComboAddress v6addr("2001:db8::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
+ }
+ pwR.commit();
+ }
+
+ BOOST_REQUIRE_GT(response.size(), 4096U);
+ packetCache.setMaximumEntrySize(response.size());
+
+ {
+ /* UDP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, true);
+ }
+
+ {
+ /* same but over TCP */
+ uint32_t key = 0;
+ boost::optional<Netmask> subnet;
+ ids.protocol = dnsdist::Protocol::DoTCP;
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = packetCache.get(dnsQuestion, 0, &key, subnet, dnssecOK, !receivedOverUDP);
+ BOOST_CHECK_EQUAL(found, false);
+ BOOST_CHECK(!subnet);
+
+ packetCache.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
+ found = packetCache.get(dnsQuestion, queryID, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
+ BOOST_CHECK_EQUAL(found, true);
+ }
+}
+
static DNSDistPacketCache g_PC(500000);
static void threadMangler(unsigned int offset)
@@ -539,10 +691,10 @@ static void threadMangler(unsigned int offset)
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ g_PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
- g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
+ g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
}
}
catch(PDNSException& e) {
@@ -572,8 +724,8 @@ static void threadReader(unsigned int offset)
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = g_PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
if (!found) {
g_missing++;
}
@@ -650,8 +802,8 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
ComboAddress remote("192.0.2.1");
ids.queryRealTime.start();
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
@@ -661,8 +813,8 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
pwR.getHeader()->rd = 1;
pwR.getHeader()->id = qid;
pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
- ComboAddress v6("::1");
- pwR.xfrCAWithoutPort(6, v6);
+ ComboAddress v6addr("::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
pwR.commit();
pwR.addOpt(512, 0, 0, ednsOptions);
pwR.commit();
@@ -670,7 +822,7 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
BOOST_CHECK_EQUAL(PC.getSize(), 1U);
- found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
+ found = PC.get(dnsQuestion, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, true);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
@@ -692,8 +844,8 @@ BOOST_AUTO_TEST_CASE(test_PCCollision) {
ComboAddress remote("192.0.2.1");
ids.queryRealTime.start();
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &secondKey, subnetOut, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &secondKey, subnetOut, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK_EQUAL(secondKey, key);
BOOST_REQUIRE(subnetOut);
@@ -771,8 +923,8 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
ComboAddress remote("192.0.2.1");
ids.queryRealTime.start();
ids.origRemote = remote;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnetOut, true, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
PacketBuffer response;
@@ -780,8 +932,8 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
pwR.getHeader()->rd = 1;
pwR.getHeader()->id = qid;
pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
- ComboAddress v6("::1");
- pwR.xfrCAWithoutPort(6, v6);
+ ComboAddress v6addr("::1");
+ pwR.xfrCAWithoutPort(6, v6addr);
pwR.commit();
pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
pwR.commit();
@@ -789,10 +941,10 @@ BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
BOOST_CHECK_EQUAL(PC.getSize(), 1U);
- found = PC.get(dq, 0, &key, subnetOut, false, receivedOverUDP);
+ found = PC.get(dnsQuestion, 0, &key, subnetOut, false, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
- found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP);
+ found = PC.get(dnsQuestion, 0, &key, subnetOut, true, receivedOverUDP);
BOOST_CHECK_EQUAL(found, true);
}
@@ -1069,13 +1221,13 @@ BOOST_AUTO_TEST_CASE(test_PacketCacheXFR) {
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(ids, query);
- bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
+ DNSQuestion dnsQuestion(ids, query);
+ bool found = PC.get(dnsQuestion, 0, &key, subnet, dnssecOK, receivedOverUDP);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none);
- found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dnsQuestion.getHeader().get())), dnssecOK, ids.qname, ids.qtype, ids.qclass, response, receivedOverUDP, 0, boost::none);
+ found = PC.get(dnsQuestion, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
BOOST_CHECK_EQUAL(found, false);
}
}
diff --git a/test-dnsdistrings_cc.cc b/test-dnsdistrings_cc.cc
index a642a95..77450c8 100644
--- a/test-dnsdistrings_cc.cc
+++ b/test-dnsdistrings_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <thread>
diff --git a/test-dnsdistrules_cc.cc b/test-dnsdistrules_cc.cc
index b636ea9..8f7363a 100644
--- a/test-dnsdistrules_cc.cc
+++ b/test-dnsdistrules_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <thread>
@@ -154,4 +157,75 @@ BOOST_AUTO_TEST_CASE(test_poolOutstandingRule) {
BOOST_CHECK_EQUAL(pOR2.matches(&dq), false);
}
+BOOST_AUTO_TEST_CASE(test_payloadSizeRule) {
+ auto dnsQuestion = getDQ();
+
+ {
+ PayloadSizeRule rule("equal", dnsQuestion.getData().size());
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to " + std::to_string(dnsQuestion.getData().size()));
+ }
+
+ {
+ PayloadSizeRule rule("equal", dnsQuestion.getData().size() + 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
+ }
+
+ {
+ PayloadSizeRule rule("greater", dnsQuestion.getData().size());
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
+ BOOST_CHECK_EQUAL(rule.toString(), "payload size is greater than " + std::to_string(dnsQuestion.getData().size()));
+ }
+
+ {
+ PayloadSizeRule rule("greater", dnsQuestion.getData().size() - 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ }
+
+ {
+ PayloadSizeRule rule("smaller", dnsQuestion.getData().size());
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
+ BOOST_CHECK_EQUAL(rule.toString(), "payload size is smaller than " + std::to_string(dnsQuestion.getData().size()));
+ }
+
+ {
+ PayloadSizeRule rule("smaller", dnsQuestion.getData().size() + 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ }
+
+ {
+ PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size());
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to or greater than " + std::to_string(dnsQuestion.getData().size()));
+ }
+
+ {
+ PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size() - 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ }
+
+ {
+ PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size() + 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
+ }
+
+ {
+ PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size());
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to or smaller than " + std::to_string(dnsQuestion.getData().size()));
+ }
+
+ {
+ PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size() + 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
+ }
+
+ {
+ PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size() - 1);
+ BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
+ }
+
+ BOOST_CHECK_THROW(PayloadSizeRule("invalid", 42U), std::runtime_error);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test-dnsdistsvc_cc.cc b/test-dnsdistsvc_cc.cc
index a7cad91..6350f3a 100644
--- a/test-dnsdistsvc_cc.cc
+++ b/test-dnsdistsvc_cc.cc
@@ -1,5 +1,8 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
diff --git a/test-dnsdisttcp_cc.cc b/test-dnsdisttcp_cc.cc
index 0904441..22a27c6 100644
--- a/test-dnsdisttcp_cc.cc
+++ b/test-dnsdisttcp_cc.cc
@@ -19,7 +19,10 @@
* 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 <boost/test/unit_test.hpp>
@@ -31,7 +34,6 @@
#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-tcp-upstream.hh"
-struct DNSDistStats g_stats;
GlobalStateHolder<NetmaskGroup> g_ACL;
GlobalStateHolder<vector<DNSDistRuleAction> > g_ruleactions;
GlobalStateHolder<vector<DNSDistResponseRuleAction> > g_respruleactions;
@@ -49,7 +51,7 @@ bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_
return false;
}
-bool checkQueryHeaders(const struct dnsheader* dh, ClientState&)
+bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState)
{
return true;
}
@@ -63,7 +65,7 @@ void handleResponseSent(const InternalQueryState& ids, double udiff, const Combo
{
}
-static std::function<ProcessQueryResult(DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
+std::function<ProcessQueryResult(DNSQuestion& dq, std::shared_ptr<DownstreamState>& selectedBackend)> s_processQuery;
ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
{
@@ -74,7 +76,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::sha
return ProcessQueryResult::Drop;
}
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
{
return true;
}
@@ -209,11 +211,6 @@ public:
BOOST_REQUIRE_EQUAL(step.request, !d_client ? ExpectedStep::ExpectedRequest::closeClient : ExpectedStep::ExpectedRequest::closeBackend);
}
- bool hasBufferedData() const override
- {
- return false;
- }
-
bool isUsable() const override
{
return true;
@@ -441,6 +438,39 @@ static void prependPayloadEditingID(PacketBuffer& buffer, const PacketBuffer& pa
buffer.insert(buffer.begin(), newPayload.begin(), newPayload.end());
}
+struct TestFixture
+{
+ TestFixture()
+ {
+ reset();
+ }
+ TestFixture(const TestFixture&) = delete;
+ TestFixture(TestFixture&&) = delete;
+ TestFixture& operator=(const TestFixture&) = delete;
+ TestFixture& operator=(TestFixture&&) = delete;
+ ~TestFixture()
+ {
+ reset();
+ }
+
+ static void reset()
+ {
+ s_steps.clear();
+ s_readBuffer.clear();
+ s_writeBuffer.clear();
+ s_backendReadBuffer.clear();
+ s_backendWriteBuffer.clear();
+
+ g_proxyProtocolACL.clear();
+ g_verbose = false;
+ IncomingTCPConnectionState::clearAllDownstreamConnections();
+
+ /* we _NEED_ to set this function to empty otherwise we might get what was set
+ by the last test, and we might not like it at all */
+ s_processQuery = nullptr;
+ }
+};
+
static void testInit(const std::string& name, TCPClientThreadData& threadData)
{
#ifdef DEBUGLOG_ENABLED
@@ -449,25 +479,16 @@ static void testInit(const std::string& name, TCPClientThreadData& threadData)
(void) name;
#endif
- s_steps.clear();
- s_readBuffer.clear();
- s_writeBuffer.clear();
- s_backendReadBuffer.clear();
- s_backendWriteBuffer.clear();
-
- g_proxyProtocolACL.clear();
- g_verbose = false;
- IncomingTCPConnectionState::clearAllDownstreamConnections();
-
+ TestFixture::reset();
threadData.mplexer = std::make_unique<MockupFDMultiplexer>();
}
#define TEST_INIT(str) testInit(str, threadData)
-BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -501,7 +522,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
}
@@ -524,7 +545,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
BOOST_CHECK(s_writeBuffer == query);
}
@@ -559,7 +580,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -583,7 +604,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
}
@@ -611,7 +632,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * count);
#endif
}
@@ -637,7 +658,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
later.tv_sec += g_tcpRecvTimeout + 1;
@@ -673,7 +694,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
later.tv_sec += g_tcpRecvTimeout + 1;
@@ -706,15 +727,15 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
}
}
-BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -767,7 +788,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * 2U);
}
@@ -794,7 +815,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
}
@@ -824,7 +845,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setNotReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
struct timeval later = now;
later.tv_sec += g_tcpRecvTimeout + 1;
@@ -841,10 +862,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered)
}
}
-BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
auto tlsCtx = std::make_shared<MockupTLSCtx>();
localCS.tlsFrontend = std::make_shared<TLSFrontend>(tlsCtx);
@@ -904,7 +925,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
BOOST_CHECK(s_writeBuffer == query);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
@@ -944,7 +965,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
BOOST_CHECK(s_backendWriteBuffer == query);
@@ -983,7 +1004,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
BOOST_CHECK(s_backendWriteBuffer == query);
@@ -1026,7 +1047,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
BOOST_CHECK(s_backendWriteBuffer == query);
@@ -1053,7 +1074,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1091,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1161,7 +1182,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
/* set the incoming descriptor as ready! */
dynamic_cast<MockupFDMultiplexer*>(threadData.mplexer.get())->setReady(-1);
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -1222,7 +1243,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1258,7 +1279,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
struct timeval later = now;
later.tv_sec += backend->d_config.tcpSendTimeout + 1;
auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
@@ -1304,7 +1325,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
struct timeval later = now;
later.tv_sec += backend->d_config.tcpRecvTimeout + 1;
auto expiredConns = threadData.mplexer->getTimeouts(later, false);
@@ -1361,7 +1382,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1417,7 +1438,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
BOOST_CHECK(s_writeBuffer == query);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
@@ -1476,7 +1497,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), 0U);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1528,7 +1549,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size() * backend->d_config.d_retries);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1588,7 +1609,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size());
BOOST_CHECK(s_writeBuffer == query);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size() * backend->d_config.d_retries);
@@ -1629,7 +1650,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), 0U);
BOOST_CHECK_EQUAL(s_backendWriteBuffer.size(), query.size());
BOOST_CHECK(s_backendWriteBuffer == query);
@@ -1691,7 +1712,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(s_writeBuffer.size(), query.size() * count);
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
@@ -1733,7 +1754,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
BOOST_CHECK_EQUAL(backend->outstanding.load(), 0U);
/* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
@@ -1741,10 +1762,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR)
}
}
-BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
/* enable out-of-order on the front side */
localCS.d_maxInFlightQueriesPerConn = 65536;
@@ -1917,7 +1938,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -2049,7 +2070,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
@@ -2229,7 +2250,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
@@ -2305,7 +2326,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -2388,7 +2409,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while ((threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -2505,7 +2526,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -2657,7 +2678,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -2864,7 +2885,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -3038,7 +3059,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -3302,7 +3323,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -3428,7 +3449,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -3513,7 +3534,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -3578,7 +3599,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -3769,7 +3790,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -3854,7 +3875,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
@@ -3881,10 +3902,10 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR)
}
}
-BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR)
+BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
{
auto local = getBackendAddress("1", 80);
- ClientState localCS(local, true, false, false, "", {});
+ ClientState localCS(local, true, false, 0, "", {}, true);
/* enable out-of-order on the front side */
localCS.d_maxInFlightQueriesPerConn = 65536;
@@ -4086,7 +4107,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0) {
threadData.mplexer->run(&now);
}
@@ -4138,7 +4159,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR)
};
auto state = std::make_shared<IncomingTCPConnectionState>(ConnectionInfo(&localCS, getBackendAddress("84", 4242)), threadData, now);
- IncomingTCPConnectionState::handleIO(state, now);
+ state->handleIO();
while (!timeout && (threadData.mplexer->getWatchedFDCount(false) != 0 || threadData.mplexer->getWatchedFDCount(true) != 0)) {
threadData.mplexer->run(&now);
}
diff --git a/test-dnsparser_cc.cc b/test-dnsparser_cc.cc
index 05894f3..bfcc668 100644
--- a/test-dnsparser_cc.cc
+++ b/test-dnsparser_cc.cc
@@ -1,4 +1,7 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#ifdef HAVE_CONFIG_H
@@ -607,7 +610,7 @@ BOOST_AUTO_TEST_CASE(test_clearDNSPacketUnsafeRecordTypes) {
// MX is unsafe, but we asked to remove it
BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 1, QType::A), 1);
BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 1, QType::AAAA), 0);
- BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 3, QType::A), 1);
+ BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 3, QType::A), 1);
BOOST_CHECK_EQUAL(getRecordsOfTypeCount(reinterpret_cast<char*>(packet.data()), packet.size(), 3, QType::MX), 0);
}
diff --git a/test-driver b/test-driver
index b8521a4..be73b80 100755
--- a/test-driver
+++ b/test-driver
@@ -3,7 +3,7 @@
scriptversion=2018-03-07.03; # UTC
-# Copyright (C) 2011-2018 Free Software Foundation, Inc.
+# Copyright (C) 2011-2021 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
@@ -42,11 +42,13 @@ print_usage ()
{
cat <<END
Usage:
- test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
- [--expect-failure={yes|no}] [--color-tests={yes|no}]
- [--enable-hard-errors={yes|no}] [--]
+ test-driver --test-name NAME --log-file PATH --trs-file PATH
+ [--expect-failure {yes|no}] [--color-tests {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.
END
}
@@ -103,8 +105,11 @@ trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
-# Test script is run here.
-"$@" >$log_file 2>&1
+# Test script is run here. We create the file first, then append to it,
+# to ameliorate tests themselves also writing to the log file. Our tests
+# don't, but others can (automake bug#35762).
+: >"$log_file"
+"$@" >>"$log_file" 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
@@ -126,7 +131,7 @@ esac
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
-echo "$res $test_name (exit status: $estatus)" >>$log_file
+echo "$res $test_name (exit status: $estatus)" >>"$log_file"
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
diff --git a/test-iputils_hh.cc b/test-iputils_hh.cc
index a299fed..b30df73 100644
--- a/test-iputils_hh.cc
+++ b/test-iputils_hh.cc
@@ -1,5 +1,9 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -264,6 +268,24 @@ BOOST_AUTO_TEST_CASE(test_Netmask) {
BOOST_CHECK(all < empty);
BOOST_CHECK(empty > full);
BOOST_CHECK(full < empty);
+
+ /* invalid (too large) mask */
+ {
+ Netmask invalidMaskV4("192.0.2.1/33");
+ BOOST_CHECK_EQUAL(invalidMaskV4.getBits(), 32U);
+ BOOST_CHECK(invalidMaskV4.getNetwork() == ComboAddress("192.0.2.1"));
+ Netmask invalidMaskV6("fe80::92fb:a6ff:fe4a:51da/129");
+ BOOST_CHECK_EQUAL(invalidMaskV6.getBits(), 128U);
+ BOOST_CHECK(invalidMaskV6.getNetwork() == ComboAddress("fe80::92fb:a6ff:fe4a:51da"));
+ }
+ {
+ Netmask invalidMaskV4(ComboAddress("192.0.2.1"), 33);
+ BOOST_CHECK_EQUAL(invalidMaskV4.getBits(), 32U);
+ BOOST_CHECK(invalidMaskV4.getNetwork() == ComboAddress("192.0.2.1"));
+ Netmask invalidMaskV6(ComboAddress("fe80::92fb:a6ff:fe4a:51da"), 129);
+ BOOST_CHECK_EQUAL(invalidMaskV6.getBits(), 128U);
+ BOOST_CHECK(invalidMaskV6.getNetwork() == ComboAddress("fe80::92fb:a6ff:fe4a:51da"));
+ }
}
static std::string NMGOutputToSorted(const std::string& str)
diff --git a/test-luawrapper.cc b/test-luawrapper.cc
index 1004790..dd01254 100644
--- a/test-luawrapper.cc
+++ b/test-luawrapper.cc
@@ -1,5 +1,9 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
diff --git a/test-mplexer.cc b/test-mplexer.cc
index 5a6bbde..20a2365 100644
--- a/test-mplexer.cc
+++ b/test-mplexer.cc
@@ -1,5 +1,7 @@
-
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
#include <thread>
@@ -51,7 +53,7 @@ BOOST_AUTO_TEST_CASE(test_MPlexer)
ttd.tv_sec -= 5;
bool writeCBCalled = false;
- auto writeCB = [](int fd, FDMultiplexer::funcparam_t& param) {
+ auto writeCB = [](int /* fd */, FDMultiplexer::funcparam_t& param) {
auto calledPtr = boost::any_cast<bool*>(param);
BOOST_REQUIRE(calledPtr != nullptr);
*calledPtr = true;
@@ -100,7 +102,7 @@ BOOST_AUTO_TEST_CASE(test_MPlexer)
BOOST_CHECK_EQUAL(ready, 0);
bool readCBCalled = false;
- auto readCB = [](int fd, FDMultiplexer::funcparam_t& param) {
+ auto readCB = [](int /* fd */, FDMultiplexer::funcparam_t& param) {
auto calledPtr = boost::any_cast<bool*>(param);
BOOST_REQUIRE(calledPtr != nullptr);
*calledPtr = true;
@@ -243,12 +245,12 @@ BOOST_AUTO_TEST_CASE(test_MPlexer_ReadAndWrite)
bool readCBCalled = false;
bool writeCBCalled = false;
- auto readCB = [](int fd, FDMultiplexer::funcparam_t& param) {
+ auto readCB = [](int /* fd */, FDMultiplexer::funcparam_t& param) {
auto calledPtr = boost::any_cast<bool*>(param);
BOOST_REQUIRE(calledPtr != nullptr);
*calledPtr = true;
};
- auto writeCB = [](int fd, FDMultiplexer::funcparam_t& param) {
+ auto writeCB = [](int /* fd */, FDMultiplexer::funcparam_t& param) {
auto calledPtr = boost::any_cast<bool*>(param);
BOOST_REQUIRE(calledPtr != nullptr);
*calledPtr = true;
diff --git a/test-proxy_protocol_cc.cc b/test-proxy_protocol_cc.cc
index 6a672c4..7cee098 100644
--- a/test-proxy_protocol_cc.cc
+++ b/test-proxy_protocol_cc.cc
@@ -1,5 +1,9 @@
+#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
+#endif
+
#define BOOST_TEST_NO_MAIN
+
#include <boost/test/unit_test.hpp>
#include "iputils.hh"
diff --git a/testrunner.cc b/testrunner.cc
index b6a6852..66b82aa 100644
--- a/testrunner.cc
+++ b/testrunner.cc
@@ -19,7 +19,10 @@
* 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_MAIN
#define BOOST_TEST_MODULE unit
diff --git a/views.hh b/views.hh
new file mode 100644
index 0000000..c3c8c89
--- /dev/null
+++ b/views.hh
@@ -0,0 +1,55 @@
+/*
+ * 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 <string_view>
+
+namespace pdns::views
+{
+
+class UnsignedCharView
+{
+public:
+ UnsignedCharView(const char* data_, size_t size_) :
+ view(data_, size_)
+ {
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): No unsigned char view in C++17
+ UnsignedCharView(const unsigned char* data_, size_t size_) :
+ view(reinterpret_cast<const char*>(data_), size_)
+ {
+ }
+ const unsigned char& at(std::string_view::size_type pos) const
+ {
+ return reinterpret_cast<const unsigned char&>(view.at(pos));
+ }
+
+ size_t size() const
+ {
+ return view.size();
+ }
+
+private:
+ std::string_view view;
+};
+
+}
diff --git a/xsk.cc b/xsk.cc
new file mode 100644
index 0000000..72f4791
--- /dev/null
+++ b/xsk.cc
@@ -0,0 +1,1262 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_XSK
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <fcntl.h>
+#include <iterator>
+#include <linux/bpf.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <linux/if_xdp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdexcept>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <vector>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+extern "C"
+{
+#include <xdp/libxdp.h>
+}
+
+#include "gettime.hh"
+#include "xsk.hh"
+
+#ifdef DEBUG_UMEM
+namespace
+{
+struct UmemEntryStatus
+{
+ enum class Status : uint8_t
+ {
+ Free,
+ FillQueue,
+ Received,
+ TXQueue
+ };
+ Status status{Status::Free};
+};
+
+LockGuarded<std::unordered_map<uint64_t, UmemEntryStatus>> s_umems;
+
+void checkUmemIntegrity(const char* function, int line, uint64_t offset, const std::set<UmemEntryStatus::Status>& validStatuses, UmemEntryStatus::Status newStatus)
+{
+ auto umems = s_umems.lock();
+ if (validStatuses.count(umems->at(offset).status) == 0) {
+ std::cerr << "UMEM integrity check failed at " << function << ": " << line << ": status is " << static_cast<int>(umems->at(offset).status) << ", expected: ";
+ for (const auto status : validStatuses) {
+ std::cerr << static_cast<int>(status) << " ";
+ }
+ std::cerr << std::endl;
+ abort();
+ }
+ (*umems)[offset].status = newStatus;
+}
+}
+#endif /* DEBUG_UMEM */
+
+constexpr bool XskSocket::isPowOfTwo(uint32_t value) noexcept
+{
+ return value != 0 && (value & (value - 1)) == 0;
+}
+
+int XskSocket::firstTimeout()
+{
+ if (waitForDelay.empty()) {
+ return -1;
+ }
+ timespec now{};
+ gettime(&now);
+ const auto& firstTime = waitForDelay.top().getSendTime();
+ const auto res = timeDifference(now, firstTime);
+ if (res <= 0) {
+ return 0;
+ }
+ return res;
+}
+
+XskSocket::XskSocket(size_t frameNum_, std::string ifName_, uint32_t queue_id, const std::string& xskMapPath) :
+ frameNum(frameNum_), ifName(std::move(ifName_)), socket(nullptr, xsk_socket__delete), sharedEmptyFrameOffset(std::make_shared<LockGuarded<vector<uint64_t>>>())
+{
+ if (!isPowOfTwo(frameNum_) || !isPowOfTwo(frameSize)
+ || !isPowOfTwo(fqCapacity) || !isPowOfTwo(cqCapacity) || !isPowOfTwo(rxCapacity) || !isPowOfTwo(txCapacity)) {
+ throw std::runtime_error("The number of frame , the size of frame and the capacity of rings must is a pow of 2");
+ }
+ getMACFromIfName();
+
+ memset(&cq, 0, sizeof(cq));
+ memset(&fq, 0, sizeof(fq));
+ memset(&tx, 0, sizeof(tx));
+ memset(&rx, 0, sizeof(rx));
+
+ xsk_umem_config umemCfg{};
+ umemCfg.fill_size = fqCapacity;
+ umemCfg.comp_size = cqCapacity;
+ umemCfg.frame_size = frameSize;
+ umemCfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
+ umemCfg.flags = 0;
+ umem.umemInit(frameNum_ * frameSize, &cq, &fq, &umemCfg);
+
+ {
+ xsk_socket_config socketCfg{};
+ socketCfg.rx_size = rxCapacity;
+ socketCfg.tx_size = txCapacity;
+ socketCfg.bind_flags = XDP_USE_NEED_WAKEUP;
+ socketCfg.xdp_flags = XDP_FLAGS_SKB_MODE;
+ socketCfg.libxdp_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
+ xsk_socket* tmp = nullptr;
+ auto ret = xsk_socket__create(&tmp, ifName.c_str(), queue_id, umem.umem, &rx, &tx, &socketCfg);
+ if (ret != 0) {
+ throw std::runtime_error("Error creating a xsk socket of if_name " + ifName + ": " + stringerror(ret));
+ }
+ socket = std::unique_ptr<xsk_socket, decltype(&xsk_socket__delete)>(tmp, xsk_socket__delete);
+ }
+
+ uniqueEmptyFrameOffset.reserve(frameNum);
+ {
+ for (uint64_t idx = 0; idx < frameNum; idx++) {
+ uniqueEmptyFrameOffset.push_back(idx * frameSize + XDP_PACKET_HEADROOM);
+#ifdef DEBUG_UMEM
+ {
+ auto umems = s_umems.lock();
+ (*umems)[idx * frameSize + XDP_PACKET_HEADROOM] = UmemEntryStatus();
+ }
+#endif /* DEBUG_UMEM */
+ }
+ }
+
+ fillFq(fqCapacity);
+
+ const auto xskfd = xskFd();
+ fds.push_back(pollfd{
+ .fd = xskfd,
+ .events = POLLIN,
+ .revents = 0});
+
+ const auto xskMapFd = FDWrapper(bpf_obj_get(xskMapPath.c_str()));
+
+ if (xskMapFd.getHandle() < 0) {
+ throw std::runtime_error("Error getting BPF map from path '" + xskMapPath + "'");
+ }
+
+ auto ret = bpf_map_update_elem(xskMapFd.getHandle(), &queue_id, &xskfd, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into xsk_map '" + xskMapPath + "': " + std::to_string(ret));
+ }
+}
+
+// see xdp.h in contrib/
+struct IPv4AndPort
+{
+ uint32_t addr;
+ uint16_t port;
+};
+struct IPv6AndPort
+{
+ struct in6_addr addr;
+ uint16_t port;
+};
+
+static FDWrapper getDestinationMap(const std::string& mapPath)
+{
+ auto destMapFd = FDWrapper(bpf_obj_get(mapPath.c_str()));
+ if (destMapFd.getHandle() < 0) {
+ throw std::runtime_error("Error getting the XSK destination addresses map path '" + mapPath + "'");
+ }
+ return destMapFd;
+}
+
+void XskSocket::clearDestinationMap(const std::string& mapPath, bool isV6)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ if (!isV6) {
+ IPv4AndPort prevKey{};
+ IPv4AndPort key{};
+ while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ prevKey = key;
+ }
+ }
+ else {
+ IPv6AndPort prevKey{};
+ IPv6AndPort key{};
+ while (bpf_map_get_next_key(destMapFd.getHandle(), &prevKey, &key) == 0) {
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ prevKey = key;
+ }
+ }
+}
+
+void XskSocket::addDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ bool value = true;
+ if (destination.isIPv4()) {
+ IPv4AndPort key{};
+ key.addr = destination.sin4.sin_addr.s_addr;
+ key.port = destination.sin4.sin_port;
+ auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into xsk_map '" + mapPath + "': " + std::to_string(ret));
+ }
+ }
+ else {
+ IPv6AndPort key{};
+ key.addr = destination.sin6.sin6_addr;
+ key.port = destination.sin6.sin6_port;
+ auto ret = bpf_map_update_elem(destMapFd.getHandle(), &key, &value, 0);
+ if (ret != 0) {
+ throw std::runtime_error("Error inserting into XSK destination addresses map '" + mapPath + "': " + std::to_string(ret));
+ }
+ }
+}
+
+void XskSocket::removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination)
+{
+ auto destMapFd = getDestinationMap(mapPath);
+ if (destination.isIPv4()) {
+ IPv4AndPort key{};
+ key.addr = destination.sin4.sin_addr.s_addr;
+ key.port = destination.sin4.sin_port;
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ }
+ else {
+ IPv6AndPort key{};
+ key.addr = destination.sin6.sin6_addr;
+ key.port = destination.sin6.sin6_port;
+ bpf_map_delete_elem(destMapFd.getHandle(), &key);
+ }
+}
+
+void XskSocket::fillFq(uint32_t fillSize) noexcept
+{
+ {
+ // if we have less than holdThreshold frames in the shared queue (which might be an issue
+ // when the XskWorker needs empty frames), move frames from the unique container into the
+ // shared one. This might not be optimal right now.
+ auto frames = sharedEmptyFrameOffset->lock();
+ if (frames->size() < holdThreshold) {
+ const auto moveSize = std::min(holdThreshold - frames->size(), uniqueEmptyFrameOffset.size());
+ if (moveSize > 0) {
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ frames->insert(frames->end(), std::make_move_iterator(uniqueEmptyFrameOffset.end() - moveSize), std::make_move_iterator(uniqueEmptyFrameOffset.end()));
+ uniqueEmptyFrameOffset.resize(uniqueEmptyFrameOffset.size() - moveSize);
+ }
+ }
+ }
+
+ if (uniqueEmptyFrameOffset.size() < fillSize) {
+ return;
+ }
+
+ uint32_t idx{0};
+ auto toFill = xsk_ring_prod__reserve(&fq, fillSize, &idx);
+ if (toFill == 0) {
+ return;
+ }
+ uint32_t processed = 0;
+ for (; processed < toFill; processed++) {
+ *xsk_ring_prod__fill_addr(&fq, idx++) = uniqueEmptyFrameOffset.back();
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Free}, UmemEntryStatus::Status::FillQueue);
+#endif /* DEBUG_UMEM */
+ uniqueEmptyFrameOffset.pop_back();
+ }
+
+ xsk_ring_prod__submit(&fq, processed);
+}
+
+int XskSocket::wait(int timeout)
+{
+ auto waitAtMost = std::min(timeout, firstTimeout());
+ return poll(fds.data(), fds.size(), waitAtMost);
+}
+
+[[nodiscard]] uint64_t XskSocket::frameOffset(const XskPacket& packet) const noexcept
+{
+ return packet.getFrameOffsetFrom(umem.bufBase);
+}
+
+[[nodiscard]] int XskSocket::xskFd() const noexcept
+{
+ return xsk_socket__fd(socket.get());
+}
+
+void XskSocket::send(std::vector<XskPacket>& packets)
+{
+ while (!packets.empty()) {
+ auto packetSize = packets.size();
+ if (packetSize > std::numeric_limits<uint32_t>::max()) {
+ packetSize = std::numeric_limits<uint32_t>::max();
+ }
+ size_t toSend = std::min(static_cast<uint32_t>(packetSize), txCapacity);
+ uint32_t idx{0};
+ auto toFill = xsk_ring_prod__reserve(&tx, toSend, &idx);
+ if (toFill == 0) {
+ return;
+ }
+
+ size_t queued = 0;
+ for (const auto& packet : packets) {
+ if (queued == toFill) {
+ break;
+ }
+ *xsk_ring_prod__tx_desc(&tx, idx++) = {
+ .addr = frameOffset(packet),
+ .len = packet.getFrameLen(),
+ .options = 0};
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::Received}, UmemEntryStatus::Status::TXQueue);
+#endif /* DEBUG_UMEM */
+ queued++;
+ }
+ xsk_ring_prod__submit(&tx, toFill);
+ packets.erase(packets.begin(), packets.begin() + toFill);
+ }
+}
+
+std::vector<XskPacket> XskSocket::recv(uint32_t recvSizeMax, uint32_t* failedCount)
+{
+ uint32_t idx{0};
+ std::vector<XskPacket> res;
+ // how many descriptors to packets have been filled
+ const auto recvSize = xsk_ring_cons__peek(&rx, recvSizeMax, &idx);
+ if (recvSize == 0) {
+ return res;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const auto baseAddr = reinterpret_cast<uint64_t>(umem.bufBase);
+ uint32_t failed = 0;
+ uint32_t processed = 0;
+ res.reserve(recvSize);
+ for (; processed < recvSize; processed++) {
+ try {
+ const auto* desc = xsk_ring_cons__rx_desc(&rx, idx++);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr)
+ XskPacket packet = XskPacket(reinterpret_cast<uint8_t*>(desc->addr + baseAddr), desc->len, frameSize);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, frameOffset(packet), {UmemEntryStatus::Status::Free, UmemEntryStatus::Status::FillQueue}, UmemEntryStatus::Status::Received);
+#endif /* DEBUG_UMEM */
+
+ if (!packet.parse(false)) {
+ ++failed;
+ markAsFree(packet);
+ }
+ else {
+ res.push_back(packet);
+ }
+ }
+ catch (const std::exception& exp) {
+ std::cerr << "Exception while processing the XSK RX queue: " << exp.what() << std::endl;
+ break;
+ }
+ catch (...) {
+ std::cerr << "Exception while processing the XSK RX queue" << std::endl;
+ break;
+ }
+ }
+
+ // this releases the descriptor, but not the packet (umem entries)
+ // which will only be made available again when pushed into the fill
+ // queue
+ xsk_ring_cons__release(&rx, processed);
+ if (failedCount != nullptr) {
+ *failedCount = failed;
+ }
+
+ return res;
+}
+
+void XskSocket::pickUpReadyPacket(std::vector<XskPacket>& packets)
+{
+ timespec now{};
+ gettime(&now);
+ while (!waitForDelay.empty() && timeDifference(now, waitForDelay.top().getSendTime()) <= 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto& top = const_cast<XskPacket&>(waitForDelay.top());
+ packets.push_back(top);
+ waitForDelay.pop();
+ }
+}
+
+void XskSocket::recycle(size_t size) noexcept
+{
+ uint32_t idx{0};
+ const auto completeSize = xsk_ring_cons__peek(&cq, size, &idx);
+ if (completeSize == 0) {
+ return;
+ }
+ uniqueEmptyFrameOffset.reserve(uniqueEmptyFrameOffset.size() + completeSize);
+ uint32_t processed = 0;
+ for (; processed < completeSize; ++processed) {
+ uniqueEmptyFrameOffset.push_back(*xsk_ring_cons__comp_addr(&cq, idx++));
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, uniqueEmptyFrameOffset.back(), {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+ }
+ xsk_ring_cons__release(&cq, processed);
+}
+
+void XskSocket::XskUmem::umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config)
+{
+ size = memSize;
+ bufBase = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if (bufBase == MAP_FAILED) {
+ throw std::runtime_error("mmap failed");
+ }
+ auto ret = xsk_umem__create(&umem, bufBase, size, fillQueue, completionQueue, config);
+ if (ret != 0) {
+ munmap(bufBase, size);
+ throw std::runtime_error("Error creating a umem of size " + std::to_string(size) + ": " + stringerror(ret));
+ }
+}
+
+std::string XskSocket::getMetrics() const
+{
+ xdp_statistics stats{};
+ socklen_t optlen = sizeof(stats);
+ int err = getsockopt(xskFd(), SOL_XDP, XDP_STATISTICS, &stats, &optlen);
+ if (err != 0) {
+ return "";
+ }
+ if (optlen != sizeof(struct xdp_statistics)) {
+ return "";
+ }
+
+ ostringstream ret;
+ ret << "RX dropped: " << std::to_string(stats.rx_dropped) << std::endl;
+ ret << "RX invalid descs: " << std::to_string(stats.rx_invalid_descs) << std::endl;
+ ret << "TX invalid descs: " << std::to_string(stats.tx_invalid_descs) << std::endl;
+ ret << "RX ring full: " << std::to_string(stats.rx_ring_full) << std::endl;
+ ret << "RX fill ring empty descs: " << std::to_string(stats.rx_fill_ring_empty_descs) << std::endl;
+ ret << "TX ring empty descs: " << std::to_string(stats.tx_ring_empty_descs) << std::endl;
+ return ret.str();
+}
+
+[[nodiscard]] std::string XskSocket::getXDPMode() const
+{
+#ifdef HAVE_BPF_XDP_QUERY
+ unsigned int itfIdx = if_nametoindex(ifName.c_str());
+ if (itfIdx == 0) {
+ return "unable to get interface index";
+ }
+ bpf_xdp_query_opts info{};
+ info.sz = sizeof(info);
+ int ret = bpf_xdp_query(static_cast<int>(itfIdx), 0, &info);
+ if (ret != 0) {
+ return {};
+ }
+ switch (info.attach_mode) {
+ case XDP_ATTACHED_DRV:
+ case XDP_ATTACHED_HW:
+ return "native";
+ case XDP_ATTACHED_SKB:
+ return "emulated";
+ default:
+ return "unknown";
+ }
+#else /* HAVE_BPF_XDP_QUERY */
+ return "undetected";
+#endif /* HAVE_BPF_XDP_QUERY */
+}
+
+void XskSocket::markAsFree(const XskPacket& packet)
+{
+ auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+
+ uniqueEmptyFrameOffset.push_back(offset);
+}
+
+XskSocket::XskUmem::~XskUmem()
+{
+ if (umem != nullptr) {
+ xsk_umem__delete(umem);
+ }
+ if (bufBase != nullptr) {
+ munmap(bufBase, size);
+ }
+}
+
+[[nodiscard]] size_t XskPacket::getL4HeaderOffset() const noexcept
+{
+ return sizeof(ethhdr) + (v6 ? (sizeof(ipv6hdr)) : sizeof(iphdr));
+}
+
+[[nodiscard]] size_t XskPacket::getDataOffset() const noexcept
+{
+ return getL4HeaderOffset() + sizeof(udphdr);
+}
+
+[[nodiscard]] size_t XskPacket::getDataSize() const noexcept
+{
+ return frameLength - getDataOffset();
+}
+
+[[nodiscard]] ethhdr XskPacket::getEthernetHeader() const noexcept
+{
+ ethhdr ethHeader{};
+ if (frameLength >= sizeof(ethHeader)) {
+ memcpy(&ethHeader, frame, sizeof(ethHeader));
+ }
+ return ethHeader;
+}
+
+void XskPacket::setEthernetHeader(const ethhdr& ethHeader) noexcept
+{
+ if (frameLength < sizeof(ethHeader)) {
+ frameLength = sizeof(ethHeader);
+ }
+ memcpy(frame, &ethHeader, sizeof(ethHeader));
+}
+
+[[nodiscard]] iphdr XskPacket::getIPv4Header() const noexcept
+{
+ iphdr ipv4Header{};
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv4Header)));
+ assert(!v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&ipv4Header, frame + sizeof(ethhdr), sizeof(ipv4Header));
+ return ipv4Header;
+}
+
+void XskPacket::setIPv4Header(const iphdr& ipv4Header) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(iphdr)));
+ assert(!v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + sizeof(ethhdr), &ipv4Header, sizeof(ipv4Header));
+}
+
+[[nodiscard]] ipv6hdr XskPacket::getIPv6Header() const noexcept
+{
+ ipv6hdr ipv6Header{};
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+ assert(v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&ipv6Header, frame + sizeof(ethhdr), sizeof(ipv6Header));
+ return ipv6Header;
+}
+
+void XskPacket::setIPv6Header(const ipv6hdr& ipv6Header) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + sizeof(ipv6Header)));
+ assert(v6);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + sizeof(ethhdr), &ipv6Header, sizeof(ipv6Header));
+}
+
+[[nodiscard]] udphdr XskPacket::getUDPHeader() const noexcept
+{
+ udphdr udpHeader{};
+ assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&udpHeader, frame + getL4HeaderOffset(), sizeof(udpHeader));
+ return udpHeader;
+}
+
+void XskPacket::setUDPHeader(const udphdr& udpHeader) noexcept
+{
+ assert(frameLength >= (sizeof(ethhdr) + (v6 ? sizeof(ipv6hdr) : sizeof(iphdr)) + sizeof(udpHeader)));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + getL4HeaderOffset(), &udpHeader, sizeof(udpHeader));
+}
+
+bool XskPacket::parse(bool fromSetHeader)
+{
+ if (frameLength <= sizeof(ethhdr)) {
+ return false;
+ }
+
+ auto ethHeader = getEthernetHeader();
+ uint8_t l4Protocol{0};
+ if (ethHeader.h_proto == htons(ETH_P_IP)) {
+ if (frameLength < (sizeof(ethhdr) + sizeof(iphdr) + sizeof(udphdr))) {
+ return false;
+ }
+ v6 = false;
+ auto ipHeader = getIPv4Header();
+ if (ipHeader.ihl != (static_cast<uint8_t>(sizeof(iphdr) / 4))) {
+ // ip options is not supported now!
+ return false;
+ }
+ // check ip.check == ipv4Checksum() is not needed!
+ // We check it in BPF program
+ // we don't, actually.
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ from = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ to = makeComboAddressFromRaw(4, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+ l4Protocol = ipHeader.protocol;
+ if (!fromSetHeader && (frameLength - sizeof(ethhdr)) != ntohs(ipHeader.tot_len)) {
+ // too small, or too large (trailing data), go away
+ return false;
+ }
+ }
+ else if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+ if (frameLength < (sizeof(ethhdr) + sizeof(ipv6hdr) + sizeof(udphdr))) {
+ return false;
+ }
+ v6 = true;
+ auto ipHeader = getIPv6Header();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ from = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.saddr), sizeof(ipHeader.saddr));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ to = makeComboAddressFromRaw(6, reinterpret_cast<const char*>(&ipHeader.daddr), sizeof(ipHeader.daddr));
+ l4Protocol = ipHeader.nexthdr;
+ if (!fromSetHeader && (frameLength - (sizeof(ethhdr) + sizeof(ipv6hdr))) != ntohs(ipHeader.payload_len)) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+
+ if (l4Protocol != IPPROTO_UDP) {
+ return false;
+ }
+
+ // check udp.check == ipv4Checksum() is not needed!
+ // We check it in BPF program
+ // we don't, actually.
+ auto udpHeader = getUDPHeader();
+ if (!fromSetHeader) {
+ // Because of XskPacket::setHeader
+ if (getDataOffset() > frameLength) {
+ return false;
+ }
+
+ if (getDataSize() + sizeof(udphdr) != ntohs(udpHeader.len)) {
+ return false;
+ }
+ }
+
+ from.setPort(ntohs(udpHeader.source));
+ to.setPort(ntohs(udpHeader.dest));
+ return true;
+}
+
+uint32_t XskPacket::getDataLen() const noexcept
+{
+ return getDataSize();
+}
+
+uint32_t XskPacket::getFrameLen() const noexcept
+{
+ return frameLength;
+}
+
+size_t XskPacket::getCapacity() const noexcept
+{
+ return frameSize;
+}
+
+void XskPacket::changeDirectAndUpdateChecksum() noexcept
+{
+ auto ethHeader = getEthernetHeader();
+ {
+ std::array<uint8_t, ETH_ALEN> tmp{};
+ static_assert(tmp.size() == sizeof(ethHeader.h_dest), "Size Error");
+ static_assert(tmp.size() == sizeof(ethHeader.h_source), "Size Error");
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(tmp.data(), ethHeader.h_dest, tmp.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_dest, ethHeader.h_source, tmp.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_source, tmp.data(), tmp.size());
+ }
+ if (ethHeader.h_proto == htons(ETH_P_IPV6)) {
+ // IPV6
+ auto ipv6 = getIPv6Header();
+ std::swap(ipv6.daddr, ipv6.saddr);
+ assert(ipv6.nexthdr == IPPROTO_UDP);
+
+ auto udp = getUDPHeader();
+ std::swap(udp.dest, udp.source);
+ udp.len = htons(getDataSize() + sizeof(udp));
+ udp.check = 0;
+ /* needed to get the correct checksum */
+ setIPv6Header(ipv6);
+ setUDPHeader(udp);
+ udp.check = tcp_udp_v6_checksum(&ipv6);
+ rewriteIpv6Header(&ipv6, getFrameLen());
+ setIPv6Header(ipv6);
+ setUDPHeader(udp);
+ }
+ else {
+ // IPV4
+ auto ipv4 = getIPv4Header();
+ std::swap(ipv4.daddr, ipv4.saddr);
+ assert(ipv4.protocol == IPPROTO_UDP);
+
+ auto udp = getUDPHeader();
+ std::swap(udp.dest, udp.source);
+ udp.len = htons(getDataSize() + sizeof(udp));
+ udp.check = 0;
+ /* needed to get the correct checksum */
+ setIPv4Header(ipv4);
+ setUDPHeader(udp);
+ udp.check = tcp_udp_v4_checksum(&ipv4);
+ rewriteIpv4Header(&ipv4, getFrameLen());
+ setIPv4Header(ipv4);
+ setUDPHeader(udp);
+ }
+ setEthernetHeader(ethHeader);
+}
+
+void XskPacket::rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept
+{
+ ipv4header->version = 4;
+ ipv4header->ihl = sizeof(iphdr) / 4;
+ ipv4header->tos = 0;
+ ipv4header->tot_len = htons(frameLen - sizeof(ethhdr));
+ ipv4header->id = 0;
+ ipv4header->frag_off = 0;
+ ipv4header->ttl = DefaultTTL;
+ ipv4header->check = 0;
+ ipv4header->check = ipv4Checksum(ipv4header);
+}
+
+void XskPacket::rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept
+{
+ ipv6header->version = 6;
+ ipv6header->priority = 0;
+ ipv6header->payload_len = htons(frameLen - sizeof(ethhdr) - sizeof(ipv6hdr));
+ ipv6header->hop_limit = DefaultTTL;
+ memset(&ipv6header->flow_lbl, 0, sizeof(ipv6header->flow_lbl));
+}
+
+bool XskPacket::isIPV6() const noexcept
+{
+ return v6;
+}
+
+XskPacket::XskPacket(uint8_t* frame_, size_t dataSize, size_t frameSize_) :
+ frame(frame_), frameLength(dataSize), frameSize(frameSize_ - XDP_PACKET_HEADROOM)
+{
+}
+
+PacketBuffer XskPacket::clonePacketBuffer() const
+{
+ const auto size = getDataSize();
+ PacketBuffer tmp(size);
+ if (size > 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(tmp.data(), frame + getDataOffset(), size);
+ }
+ return tmp;
+}
+
+bool XskPacket::setPayload(const PacketBuffer& buf)
+{
+ const auto bufSize = buf.size();
+ const auto currentCapacity = getCapacity();
+ if (bufSize == 0 || bufSize > currentCapacity) {
+ return false;
+ }
+ flags |= UPDATE;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(frame + getDataOffset(), buf.data(), bufSize);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ frameLength = getDataOffset() + bufSize;
+ return true;
+}
+
+void XskPacket::addDelay(const int relativeMilliseconds) noexcept
+{
+ gettime(&sendTime);
+ sendTime.tv_nsec += static_cast<int64_t>(relativeMilliseconds) * 1000000L;
+ sendTime.tv_sec += sendTime.tv_nsec / 1000000000L;
+ sendTime.tv_nsec %= 1000000000L;
+}
+
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept
+{
+ return lhs.getSendTime() < rhs.getSendTime();
+}
+
+const ComboAddress& XskPacket::getFromAddr() const noexcept
+{
+ return from;
+}
+
+const ComboAddress& XskPacket::getToAddr() const noexcept
+{
+ return to;
+}
+
+void XskWorker::notify(int desc)
+{
+ uint64_t value = 1;
+ ssize_t res = 0;
+ while ((res = write(desc, &value, sizeof(value))) == EINTR) {
+ }
+ if (res != sizeof(value)) {
+ throw runtime_error("Unable Wake Up XskSocket Failed");
+ }
+}
+
+XskWorker::XskWorker() :
+ workerWaker(createEventfd()), xskSocketWaker(createEventfd())
+{
+}
+
+void XskWorker::pushToProcessingQueue(XskPacket& packet)
+{
+#if defined(__SANITIZE_THREAD__)
+ if (!incomingPacketsQueue.lock()->push(packet)) {
+#else
+ if (!incomingPacketsQueue.push(packet)) {
+#endif
+ markAsFree(packet);
+ }
+}
+
+void XskWorker::pushToSendQueue(XskPacket& packet)
+{
+#if defined(__SANITIZE_THREAD__)
+ if (!outgoingPacketsQueue.lock()->push(packet)) {
+#else
+ if (!outgoingPacketsQueue.push(packet)) {
+#endif
+ markAsFree(packet);
+ }
+}
+
+const void* XskPacket::getPayloadData() const
+{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return frame + getDataOffset();
+}
+
+void XskPacket::setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept
+{
+ auto ethHeader = getEthernetHeader();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_dest, toMAC.data(), toMAC.size());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(ethHeader.h_source, fromMAC.data(), fromMAC.size());
+ setEthernetHeader(ethHeader);
+ to = to_;
+ from = from_;
+ v6 = !to.isIPv4();
+ flags = 0;
+}
+
+void XskPacket::rewrite() noexcept
+{
+ flags |= REWRITE;
+ auto ethHeader = getEthernetHeader();
+ if (!v6) {
+ ethHeader.h_proto = htons(ETH_P_IP);
+
+ auto ipHeader = getIPv4Header();
+ ipHeader.daddr = to.sin4.sin_addr.s_addr;
+ ipHeader.saddr = from.sin4.sin_addr.s_addr;
+
+ auto udpHeader = getUDPHeader();
+ ipHeader.protocol = IPPROTO_UDP;
+ udpHeader.source = from.sin4.sin_port;
+ udpHeader.dest = to.sin4.sin_port;
+ udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+ udpHeader.check = 0;
+ /* needed to get the correct checksum */
+ setIPv4Header(ipHeader);
+ setUDPHeader(udpHeader);
+ udpHeader.check = tcp_udp_v4_checksum(&ipHeader);
+ rewriteIpv4Header(&ipHeader, getFrameLen());
+ setIPv4Header(ipHeader);
+ setUDPHeader(udpHeader);
+ }
+ else {
+ ethHeader.h_proto = htons(ETH_P_IPV6);
+
+ auto ipHeader = getIPv6Header();
+ memcpy(&ipHeader.daddr, &to.sin6.sin6_addr, sizeof(ipHeader.daddr));
+ memcpy(&ipHeader.saddr, &from.sin6.sin6_addr, sizeof(ipHeader.saddr));
+
+ auto udpHeader = getUDPHeader();
+ ipHeader.nexthdr = IPPROTO_UDP;
+ udpHeader.source = from.sin6.sin6_port;
+ udpHeader.dest = to.sin6.sin6_port;
+ udpHeader.len = htons(getDataSize() + sizeof(udpHeader));
+ udpHeader.check = 0;
+ /* needed to get the correct checksum */
+ setIPv6Header(ipHeader);
+ setUDPHeader(udpHeader);
+ udpHeader.check = tcp_udp_v6_checksum(&ipHeader);
+ setIPv6Header(ipHeader);
+ setUDPHeader(udpHeader);
+ }
+
+ setEthernetHeader(ethHeader);
+}
+
+[[nodiscard]] __be16 XskPacket::ipv4Checksum(const struct iphdr* ipHeader) noexcept
+{
+ auto partial = ip_checksum_partial(ipHeader, sizeof(iphdr), 0);
+ return ip_checksum_fold(partial);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v4_checksum(const struct iphdr* ipHeader) const noexcept
+{
+ // ip options is not supported !!!
+ const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+ auto sum = tcp_udp_v4_header_checksum_partial(ipHeader->saddr, ipHeader->daddr, ipHeader->protocol, l4Length);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+ return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] __be16 XskPacket::tcp_udp_v6_checksum(const struct ipv6hdr* ipv6) const noexcept
+{
+ const auto l4Length = static_cast<uint16_t>(getDataSize() + sizeof(udphdr));
+ uint64_t sum = tcp_udp_v6_header_checksum_partial(&ipv6->saddr, &ipv6->daddr, ipv6->nexthdr, l4Length);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ sum = ip_checksum_partial(frame + getL4HeaderOffset(), l4Length, sum);
+ return ip_checksum_fold(sum);
+}
+
+[[nodiscard]] uint64_t XskPacket::ip_checksum_partial(const void* ptr, const size_t len, uint64_t sum) noexcept
+{
+ size_t position{0};
+ /* Main loop: 32 bits at a time */
+ for (position = 0; position < len; position += sizeof(uint32_t)) {
+ uint32_t value{};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+ sum += value;
+ }
+
+ /* Handle un-32bit-aligned trailing bytes */
+ if ((len - position) >= 2) {
+ uint16_t value{};
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ memcpy(&value, static_cast<const uint8_t*>(ptr) + position, sizeof(value));
+ sum += value;
+ position += sizeof(value);
+ }
+
+ if ((len - position) > 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ const auto* ptr8 = static_cast<const uint8_t*>(ptr) + position;
+ sum += ntohs(*ptr8 << 8); /* RFC says pad last byte */
+ }
+
+ return sum;
+}
+
+[[nodiscard]] __be16 XskPacket::ip_checksum_fold(uint64_t sum) noexcept
+{
+ while ((sum & ~0xffffffffULL) != 0U) {
+ sum = (sum >> 32) + (sum & 0xffffffffULL);
+ }
+ while ((sum & 0xffff0000ULL) != 0U) {
+ sum = (sum >> 16) + (sum & 0xffffULL);
+ }
+
+ return static_cast<__be16>(~sum);
+}
+
+#ifndef __packed
+#define packed_attribute __attribute__((packed))
+#else
+#define packed_attribute __packed
+#endif
+
+// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept
+{
+ struct header
+ {
+ __be32 src_ip;
+ __be32 dst_ip;
+ __uint8_t mbz;
+ __uint8_t protocol;
+ __be16 length;
+ };
+ /* The IPv4 pseudo-header is defined in RFC 793, Section 3.1. */
+ struct ipv4_pseudo_header_t
+ {
+ /* We use a union here to avoid aliasing issues with gcc -O2 */
+ union
+ {
+ header packed_attribute fields;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ uint32_t words[3];
+ };
+ };
+ ipv4_pseudo_header_t pseudo_header{};
+ static_assert(sizeof(pseudo_header) == 12, "IPv4 pseudo-header size is incorrect");
+
+ /* Fill in the pseudo-header. */
+ pseudo_header.fields.src_ip = src_ip;
+ pseudo_header.fields.dst_ip = dst_ip;
+ pseudo_header.fields.mbz = 0;
+ pseudo_header.fields.protocol = protocol;
+ pseudo_header.fields.length = htons(len);
+ return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+[[nodiscard]] uint64_t XskPacket::tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept
+{
+ struct header
+ {
+ struct in6_addr src_ip;
+ struct in6_addr dst_ip;
+ __be32 length;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ __uint8_t mbz[3];
+ __uint8_t next_header;
+ };
+ /* The IPv6 pseudo-header is defined in RFC 2460, Section 8.1. */
+ struct ipv6_pseudo_header_t
+ {
+ /* We use a union here to avoid aliasing issues with gcc -O2 */
+ union
+ {
+ header packed_attribute fields;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
+ uint32_t words[10];
+ };
+ };
+ ipv6_pseudo_header_t pseudo_header{};
+ static_assert(sizeof(pseudo_header) == 40, "IPv6 pseudo-header size is incorrect");
+
+ /* Fill in the pseudo-header. */
+ pseudo_header.fields.src_ip = *src_ip;
+ pseudo_header.fields.dst_ip = *dst_ip;
+ pseudo_header.fields.length = htonl(len);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memset(pseudo_header.fields.mbz, 0, sizeof(pseudo_header.fields.mbz));
+ pseudo_header.fields.next_header = protocol;
+ return ip_checksum_partial(&pseudo_header, sizeof(pseudo_header), 0);
+}
+
+void XskPacket::setHeader(PacketBuffer& buf)
+{
+ memcpy(frame, buf.data(), buf.size());
+ frameLength = buf.size();
+ buf.clear();
+ flags = 0;
+ if (!parse(true)) {
+ throw std::runtime_error("Error setting the XSK frame header");
+ }
+}
+
+PacketBuffer XskPacket::cloneHeaderToPacketBuffer() const
+{
+ const auto size = getFrameLen() - getDataSize();
+ PacketBuffer tmp(size);
+ memcpy(tmp.data(), frame, size);
+ return tmp;
+}
+
+int XskWorker::createEventfd()
+{
+ auto desc = ::eventfd(0, EFD_CLOEXEC);
+ if (desc < 0) {
+ throw runtime_error("Unable create eventfd");
+ }
+ return desc;
+}
+
+void XskWorker::waitForXskSocket() const noexcept
+{
+ uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+void XskWorker::notifyXskSocket() const
+{
+ notify(xskSocketWaker);
+}
+
+std::shared_ptr<XskWorker> XskWorker::create()
+{
+ return std::make_shared<XskWorker>();
+}
+
+void XskSocket::addWorker(std::shared_ptr<XskWorker> worker)
+{
+ const auto socketWaker = worker->xskSocketWaker.getHandle();
+ worker->umemBufBase = umem.bufBase;
+ d_workers.insert({socketWaker, std::move(worker)});
+ fds.push_back(pollfd{
+ .fd = socketWaker,
+ .events = POLLIN,
+ .revents = 0});
+};
+
+void XskSocket::addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest)
+{
+ d_workerRoutes.lock()->insert({dest, worker});
+}
+
+void XskSocket::removeWorkerRoute(const ComboAddress& dest)
+{
+ d_workerRoutes.lock()->erase(dest);
+}
+
+uint64_t XskWorker::frameOffset(const XskPacket& packet) const noexcept
+{
+ return packet.getFrameOffsetFrom(umemBufBase);
+}
+
+void XskWorker::notifyWorker() const
+{
+ notify(workerWaker);
+}
+
+void XskSocket::getMACFromIfName()
+{
+ ifreq ifr{};
+ auto desc = FDWrapper(::socket(AF_INET, SOCK_DGRAM, 0));
+ if (desc < 0) {
+ throw std::runtime_error("Error creating a socket to get the MAC address of interface " + ifName);
+ }
+
+ if (ifName.size() >= IFNAMSIZ) {
+ throw std::runtime_error("Unable to get MAC address for interface " + ifName + ": name too long");
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ strncpy(ifr.ifr_name, ifName.c_str(), ifName.length() + 1);
+ if (ioctl(desc.getHandle(), SIOCGIFHWADDR, &ifr) < 0 || ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ throw std::runtime_error("Error getting MAC address for interface " + ifName);
+ }
+ static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= std::tuple_size<decltype(source)>{}, "The size of an ARPHRD_ETHER MAC address is smaller than expected");
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ memcpy(source.data(), ifr.ifr_hwaddr.sa_data, source.size());
+}
+
+[[nodiscard]] int XskSocket::timeDifference(const timespec& lhs, const timespec& rhs) noexcept
+{
+ const auto res = lhs.tv_sec * 1000 + lhs.tv_nsec / 1000000L - (rhs.tv_sec * 1000 + rhs.tv_nsec / 1000000L);
+ return static_cast<int>(res);
+}
+
+void XskWorker::cleanWorkerNotification() const noexcept
+{
+ uint64_t value = read(xskSocketWaker, &value, sizeof(value));
+}
+
+void XskWorker::cleanSocketNotification() const noexcept
+{
+ uint64_t value = read(workerWaker, &value, sizeof(value));
+}
+
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info)
+{
+ std::vector<pollfd> fds;
+ int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ if (timerfd < 0) {
+ throw std::runtime_error("create_timerfd failed");
+ }
+ fds.push_back(pollfd{
+ .fd = info.workerWaker,
+ .events = POLLIN,
+ .revents = 0,
+ });
+ fds.push_back(pollfd{
+ .fd = timerfd,
+ .events = POLLIN,
+ .revents = 0,
+ });
+ return fds;
+}
+
+void XskWorker::fillUniqueEmptyOffset()
+{
+ auto frames = sharedEmptyFrameOffset->lock();
+ const auto moveSize = std::min(static_cast<size_t>(32), frames->size());
+ if (moveSize > 0) {
+ // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
+ uniqueEmptyFrameOffset.insert(uniqueEmptyFrameOffset.end(), std::make_move_iterator(frames->end() - moveSize), std::make_move_iterator(frames->end()));
+ frames->resize(frames->size() - moveSize);
+ }
+}
+
+std::optional<XskPacket> XskWorker::getEmptyFrame()
+{
+ if (!uniqueEmptyFrameOffset.empty()) {
+ auto offset = uniqueEmptyFrameOffset.back();
+ uniqueEmptyFrameOffset.pop_back();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return XskPacket(offset + umemBufBase, 0, frameSize);
+ }
+ fillUniqueEmptyOffset();
+ if (!uniqueEmptyFrameOffset.empty()) {
+ auto offset = uniqueEmptyFrameOffset.back();
+ uniqueEmptyFrameOffset.pop_back();
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ return XskPacket(offset + umemBufBase, 0, frameSize);
+ }
+ return std::nullopt;
+}
+
+void XskWorker::markAsFree(const XskPacket& packet)
+{
+ auto offset = frameOffset(packet);
+#ifdef DEBUG_UMEM
+ checkUmemIntegrity(__PRETTY_FUNCTION__, __LINE__, offset, {UmemEntryStatus::Status::Received, UmemEntryStatus::Status::TXQueue}, UmemEntryStatus::Status::Free);
+#endif /* DEBUG_UMEM */
+ uniqueEmptyFrameOffset.push_back(offset);
+}
+
+uint32_t XskPacket::getFlags() const noexcept
+{
+ return flags;
+}
+
+void XskPacket::updatePacket() noexcept
+{
+ if ((flags & UPDATE) == 0U) {
+ return;
+ }
+ if ((flags & REWRITE) == 0U) {
+ changeDirectAndUpdateChecksum();
+ }
+}
+#endif /* HAVE_XSK */
diff --git a/xsk.hh b/xsk.hh
new file mode 100644
index 0000000..8d2b57d
--- /dev/null
+++ b/xsk.hh
@@ -0,0 +1,340 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+#include "config.h"
+
+#ifdef HAVE_XSK
+#include <array>
+#include <bits/types/struct_timespec.h>
+#include <boost/lockfree/spsc_queue.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <cstdint>
+#include <memory>
+#include <poll.h>
+#include <queue>
+#include <stdexcept>
+#include <string>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+#include <xdp/xsk.h>
+
+#include "iputils.hh"
+#include "lock.hh"
+#include "misc.hh"
+#include "noinitvector.hh"
+
+class XskPacket;
+class XskWorker;
+class XskSocket;
+
+using MACAddr = std::array<uint8_t, 6>;
+
+// We use an XskSocket to manage an AF_XDP Socket corresponding to a NIC queue.
+// The XDP program running in the kernel redirects the data to the XskSocket in userspace.
+// We allocate frames that are placed into the descriptors in the fill queue, allowing the kernel to put incoming packets into the frames and place descriptors into the rx queue.
+// Once we have read the descriptors from the rx queue we release them, but we own the frames.
+// After we are done with the frame, we place them into descriptors of either the fill queue (empty frames) or tx queues (packets to be sent).
+// Once the kernel is done, it places descriptors referencing these frames into the cq where we can recycle them (packets destined to the tx queue or empty frame to the fill queue queue).
+
+// XskSocket routes packets to multiple worker threads registered on XskSocket via XskSocket::addWorker based on the destination port number of the packet.
+// The kernel and the worker thread holding XskWorker will wake up the XskSocket through XskFd and the Eventfd corresponding to each worker thread, respectively.
+
+class XskSocket
+{
+ struct XskUmem
+ {
+ xsk_umem* umem{nullptr};
+ uint8_t* bufBase{nullptr};
+ size_t size{0};
+ void umemInit(size_t memSize, xsk_ring_cons* completionQueue, xsk_ring_prod* fillQueue, xsk_umem_config* config);
+ ~XskUmem();
+ XskUmem() = default;
+ };
+ using WorkerContainer = std::unordered_map<int, std::shared_ptr<XskWorker>>;
+ WorkerContainer d_workers;
+ using WorkerRoutesMap = std::unordered_map<ComboAddress, std::shared_ptr<XskWorker>, ComboAddress::addressPortOnlyHash>;
+ // it might be better to move to a StateHolder for performance
+ LockGuarded<WorkerRoutesMap> d_workerRoutes;
+ // number of frames to keep in sharedEmptyFrameOffset
+ static constexpr size_t holdThreshold = 256;
+ // number of frames to insert into the fill queue
+ static constexpr size_t fillThreshold = 128;
+ static constexpr size_t frameSize = 2048;
+ // number of entries (frames) in the umem
+ const size_t frameNum;
+ // responses that have been delayed
+ std::priority_queue<XskPacket> waitForDelay;
+ MACAddr source{};
+ const std::string ifName;
+ // AF_XDP socket then worker waker sockets
+ vector<pollfd> fds;
+ // list of frames, aka (indexes of) umem entries that can be reused to fill fq,
+ // collected from packets that we could not route (unknown destination),
+ // could not parse, were dropped during processing (!UPDATE), or
+ // simply recycled from cq after being processed by the kernel
+ vector<uint64_t> uniqueEmptyFrameOffset;
+ // completion ring: queue where sent packets are stored by the kernel
+ xsk_ring_cons cq{};
+ // rx ring: queue where the incoming packets are stored, read by XskRouter
+ xsk_ring_cons rx{};
+ // fill ring: queue where umem entries available to be filled (put into rx) are stored
+ xsk_ring_prod fq{};
+ // tx ring: queue where outgoing packets are stored
+ xsk_ring_prod tx{};
+ std::unique_ptr<xsk_socket, void (*)(xsk_socket*)> socket;
+ XskUmem umem;
+
+ static constexpr uint32_t fqCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 4;
+ static constexpr uint32_t cqCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 4;
+ static constexpr uint32_t rxCapacity = XSK_RING_CONS__DEFAULT_NUM_DESCS * 2;
+ static constexpr uint32_t txCapacity = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2;
+
+ constexpr static bool isPowOfTwo(uint32_t value) noexcept;
+ [[nodiscard]] static int timeDifference(const timespec& lhs, const timespec& rhs) noexcept;
+
+ [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+ [[nodiscard]] int firstTimeout();
+ void getMACFromIfName();
+
+public:
+ static void clearDestinationMap(const std::string& mapPath, bool isV6);
+ static void addDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+ static void removeDestinationAddress(const std::string& mapPath, const ComboAddress& destination);
+ static constexpr size_t getFrameSize()
+ {
+ return frameSize;
+ }
+ // list of free umem entries that can be reused
+ std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
+ XskSocket(size_t frameNum, std::string ifName, uint32_t queue_id, const std::string& xskMapPath);
+ [[nodiscard]] int xskFd() const noexcept;
+ // wait until one event has occurred
+ [[nodiscard]] int wait(int timeout);
+ // add as many packets as possible to the rx queue for sending */
+ void send(std::vector<XskPacket>& packets);
+ // look at incoming packets in rx, return them if parsing succeeeded
+ [[nodiscard]] std::vector<XskPacket> recv(uint32_t recvSizeMax, uint32_t* failedCount);
+ void addWorker(std::shared_ptr<XskWorker> worker);
+ void addWorkerRoute(const std::shared_ptr<XskWorker>& worker, const ComboAddress& dest);
+ void removeWorkerRoute(const ComboAddress& dest);
+ [[nodiscard]] std::string getMetrics() const;
+ [[nodiscard]] std::string getXDPMode() const;
+ void markAsFree(const XskPacket& packet);
+ [[nodiscard]] const std::shared_ptr<XskWorker>& getWorkerByDescriptor(int desc) const
+ {
+ return d_workers.at(desc);
+ }
+ [[nodiscard]] std::shared_ptr<XskWorker> getWorkerByDestination(const ComboAddress& destination)
+ {
+ auto routes = d_workerRoutes.lock();
+ auto workerIt = routes->find(destination);
+ if (workerIt == routes->end()) {
+ return nullptr;
+ }
+ return workerIt->second;
+ }
+ [[nodiscard]] const std::vector<pollfd>& getDescriptors() const
+ {
+ return fds;
+ }
+ [[nodiscard]] MACAddr getSourceMACAddress() const
+ {
+ return source;
+ }
+ [[nodiscard]] const std::string& getInterfaceName() const
+ {
+ return ifName;
+ }
+ // pick ups available frames from uniqueEmptyFrameOffset
+ // insert entries from uniqueEmptyFrameOffset into fq
+ void fillFq(uint32_t fillSize = fillThreshold) noexcept;
+ // picks up entries that have been processed (sent) from cq and push them into uniqueEmptyFrameOffset
+ void recycle(size_t size) noexcept;
+ // look at delayed packets, and send the ones that are ready
+ void pickUpReadyPacket(std::vector<XskPacket>& packets);
+ void pushDelayed(XskPacket& packet)
+ {
+ waitForDelay.push(packet);
+ }
+};
+
+struct ethhdr;
+struct iphdr;
+struct ipv6hdr;
+struct udphdr;
+
+class XskPacket
+{
+public:
+ enum Flags : uint32_t
+ {
+ UPDATE = 1 << 0,
+ DELAY = 1 << 1,
+ REWRITE = 1 << 2
+ };
+
+private:
+ ComboAddress from;
+ ComboAddress to;
+ timespec sendTime{};
+ uint8_t* frame{nullptr};
+ size_t frameLength{0};
+ size_t frameSize{0};
+ uint32_t flags{0};
+ bool v6{false};
+
+ // You must set ipHeader.check = 0 before calling this method
+ [[nodiscard]] static __be16 ipv4Checksum(const struct iphdr*) noexcept;
+ [[nodiscard]] static uint64_t ip_checksum_partial(const void* p, size_t len, uint64_t sum) noexcept;
+ [[nodiscard]] static __be16 ip_checksum_fold(uint64_t sum) noexcept;
+ [[nodiscard]] static uint64_t tcp_udp_v4_header_checksum_partial(__be32 src_ip, __be32 dst_ip, uint8_t protocol, uint16_t len) noexcept;
+ [[nodiscard]] static uint64_t tcp_udp_v6_header_checksum_partial(const struct in6_addr* src_ip, const struct in6_addr* dst_ip, uint8_t protocol, uint32_t len) noexcept;
+ static void rewriteIpv4Header(struct iphdr* ipv4header, size_t frameLen) noexcept;
+ static void rewriteIpv6Header(struct ipv6hdr* ipv6header, size_t frameLen) noexcept;
+
+ // You must set l4Header.check = 0 before calling this method
+ // ip options is not supported
+ [[nodiscard]] __be16 tcp_udp_v4_checksum(const struct iphdr*) const noexcept;
+ // You must set l4Header.check = 0 before calling this method
+ [[nodiscard]] __be16 tcp_udp_v6_checksum(const struct ipv6hdr*) const noexcept;
+ /* offset of the L4 (udphdr) header (after ethhdr and iphdr/ipv6hdr) */
+ [[nodiscard]] size_t getL4HeaderOffset() const noexcept;
+ /* offset of the data after the UDP header */
+ [[nodiscard]] size_t getDataOffset() const noexcept;
+ [[nodiscard]] size_t getDataSize() const noexcept;
+ [[nodiscard]] ethhdr getEthernetHeader() const noexcept;
+ void setEthernetHeader(const ethhdr& ethHeader) noexcept;
+ [[nodiscard]] iphdr getIPv4Header() const noexcept;
+ void setIPv4Header(const iphdr& ipv4Header) noexcept;
+ [[nodiscard]] ipv6hdr getIPv6Header() const noexcept;
+ void setIPv6Header(const ipv6hdr& ipv6Header) noexcept;
+ [[nodiscard]] udphdr getUDPHeader() const noexcept;
+ void setUDPHeader(const udphdr& udpHeader) noexcept;
+ void changeDirectAndUpdateChecksum() noexcept;
+
+ constexpr static uint8_t DefaultTTL = 64;
+
+public:
+ [[nodiscard]] const ComboAddress& getFromAddr() const noexcept;
+ [[nodiscard]] const ComboAddress& getToAddr() const noexcept;
+ [[nodiscard]] const void* getPayloadData() const;
+ [[nodiscard]] bool isIPV6() const noexcept;
+ [[nodiscard]] size_t getCapacity() const noexcept;
+ [[nodiscard]] uint32_t getDataLen() const noexcept;
+ [[nodiscard]] uint32_t getFrameLen() const noexcept;
+ [[nodiscard]] PacketBuffer clonePacketBuffer() const;
+ [[nodiscard]] PacketBuffer cloneHeaderToPacketBuffer() const;
+ void setAddr(const ComboAddress& from_, MACAddr fromMAC, const ComboAddress& to_, MACAddr toMAC) noexcept;
+ bool setPayload(const PacketBuffer& buf);
+ void rewrite() noexcept;
+ void setHeader(PacketBuffer& buf);
+ XskPacket(uint8_t* frame, size_t dataSize, size_t frameSize);
+ void addDelay(int relativeMilliseconds) noexcept;
+ void updatePacket() noexcept;
+ // parse IP and UDP payloads
+ bool parse(bool fromSetHeader);
+ [[nodiscard]] uint32_t getFlags() const noexcept;
+ [[nodiscard]] timespec getSendTime() const noexcept
+ {
+ return sendTime;
+ }
+ [[nodiscard]] uint64_t getFrameOffsetFrom(const uint8_t* base) const noexcept
+ {
+ return frame - base;
+ }
+};
+bool operator<(const XskPacket& lhs, const XskPacket& rhs) noexcept;
+
+/* g++ defines __SANITIZE_THREAD__
+ clang++ supports the nice __has_feature(thread_sanitizer),
+ let's merge them */
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#define __SANITIZE_THREAD__ 1
+#endif
+#endif
+
+// XskWorker obtains XskPackets of specific ports in the NIC from XskSocket through cq.
+// After finishing processing the packet, XskWorker puts the packet into sq so that XskSocket decides whether to send it through the network card according to XskPacket::flags.
+// XskWorker wakes up XskSocket via xskSocketWaker after putting the packets in sq.
+class XskWorker
+{
+#if defined(__SANITIZE_THREAD__)
+ using XskPacketRing = LockGuarded<boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>>;
+#else
+ using XskPacketRing = boost::lockfree::spsc_queue<XskPacket, boost::lockfree::capacity<XSK_RING_CONS__DEFAULT_NUM_DESCS * 2>>;
+#endif
+
+public:
+ // queue of packets to be processed by this worker
+ XskPacketRing incomingPacketsQueue;
+ // queue of packets processed by this worker (to be sent, or discarded)
+ XskPacketRing outgoingPacketsQueue;
+
+ uint8_t* umemBufBase{nullptr};
+ // list of frames that are shared with the XskRouter
+ std::shared_ptr<LockGuarded<vector<uint64_t>>> sharedEmptyFrameOffset;
+ // list of frames that we own, used to generate new packets (health-check)
+ vector<uint64_t> uniqueEmptyFrameOffset;
+ const size_t frameSize{XskSocket::getFrameSize()};
+ FDWrapper workerWaker;
+ FDWrapper xskSocketWaker;
+
+ XskWorker();
+ static int createEventfd();
+ static void notify(int desc);
+ static std::shared_ptr<XskWorker> create();
+ void pushToProcessingQueue(XskPacket& packet);
+ void pushToSendQueue(XskPacket& packet);
+ void markAsFree(const XskPacket& packet);
+ // notify worker that at least one packet is available for processing
+ void notifyWorker() const;
+ // notify the router that packets are ready to be sent
+ void notifyXskSocket() const;
+ void waitForXskSocket() const noexcept;
+ void cleanWorkerNotification() const noexcept;
+ void cleanSocketNotification() const noexcept;
+ [[nodiscard]] uint64_t frameOffset(const XskPacket& packet) const noexcept;
+ // reap empty umem entry from sharedEmptyFrameOffset into uniqueEmptyFrameOffset
+ void fillUniqueEmptyOffset();
+ // look for an empty umem entry in uniqueEmptyFrameOffset
+ // then sharedEmptyFrameOffset if needed
+ std::optional<XskPacket> getEmptyFrame();
+};
+std::vector<pollfd> getPollFdsForWorker(XskWorker& info);
+#else
+class XskSocket
+{
+};
+class XskPacket
+{
+};
+class XskWorker
+{
+};
+
+#endif /* HAVE_XSK */