]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
feat(dnsdist): remove h2o support 16723/head
authorPieter Lexis <pieter.lexis@powerdns.com>
Wed, 14 Jan 2026 13:43:10 +0000 (14:43 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Fri, 16 Jan 2026 08:18:14 +0000 (09:18 +0100)
32 files changed:
builder-support/helpers/h2o.json [deleted file]
builder-support/helpers/install_h2o.sh [deleted file]
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-doh-common.hh
pdns/dnsdistdist/dnsdist-idstate.hh
pdns/dnsdistdist/dnsdist-internal-queries.cc
pdns/dnsdistdist/dnsdist-lua.cc
pdns/dnsdistdist/dnsdist-settings-definitions.yml
pdns/dnsdistdist/dnsdist.cc
pdns/dnsdistdist/docs/guides/dns-over-https.rst
pdns/dnsdistdist/docs/install.rst
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsdistdist/docs/reference/selectors.rst
pdns/dnsdistdist/docs/upgrade_guide.rst
pdns/dnsdistdist/doh.cc [deleted file]
pdns/dnsdistdist/doh.hh [deleted file]
pdns/dnsdistdist/m4/dnsdist_enable_doh.m4
pdns/dnsdistdist/m4/pdns_check_libh2o_evloop.m4 [deleted file]
pdns/dnsdistdist/meson.build
pdns/dnsdistdist/meson/doh2/meson.build
pdns/dnsdistdist/meson/h2o/meson.build [deleted file]
pdns/dnsdistdist/meson_options.txt
regression-tests.dnsdist/dnsdisttests.py
regression-tests.dnsdist/test_Async.py
regression-tests.dnsdist/test_DOH.py
regression-tests.dnsdist/test_OCSP.py
regression-tests.dnsdist/test_Protobuf.py
regression-tests.dnsdist/test_ProxyProtocol.py
regression-tests.dnsdist/test_TLSSessionResumption.py
tasks.py

diff --git a/builder-support/helpers/h2o.json b/builder-support/helpers/h2o.json
deleted file mode 100644 (file)
index 39089d6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "version": "2.2.6-pdns3",
-  "license": "MIT",
-  "publisher": "https://github.com/h2o/h2o",
-  "SHA256SUM": "c37b2184169f41a2d10bacb8a2b0e90df238b7a172478ddc77e7077754e0ab17"
-}
diff --git a/builder-support/helpers/install_h2o.sh b/builder-support/helpers/install_h2o.sh
deleted file mode 100755 (executable)
index cb8366a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-set -v
-set -e
-
-readonly H2O_VERSION=$(jq -r .version < h2o.json)
-readonly H2O_TARBALL="v${H2O_VERSION}.tar.gz"
-readonly H2O_TARBALL_URL="https://github.com/PowerDNS/h2o/archive/refs/tags/${H2O_TARBALL}"
-readonly H2O_TARBALL_HASH=$(jq -r .SHA256SUM < h2o.json)
-
-cd /tmp
-echo $0: Downloading $H2O_TARBALL
-curl -f -L -o "${H2O_TARBALL}" "${H2O_TARBALL_URL}"
-
-# Line below should echo two spaces between digest and name
-if echo "${H2O_TARBALL_HASH}  ${H2O_TARBALL}" | sha256sum -c -; then
-  true
-else
-  result=$?
-  echo "error: Downloaded ${H2O_TARBALL_URL} failed sha256sum validation"
-  exit $result
-fi
-tar xf "${H2O_TARBALL}"
-CFLAGS='-fPIC' cmake -DWITH_PICOTLS=off -DWITH_BUNDLED_SSL=off -DWITH_MRUBY=off -DCMAKE_INSTALL_PREFIX=/opt ./h2o-${H2O_VERSION}
-make -j $(nproc)
-make install
-rm -rf "${H2O_TARBALL}" "h2o-${H2O_VERSION}"
index f5e03c69f7ea7995b0de0057caf0aae0df29e6c6..1e6daf61636d589f9f6bc3cbd51887c7a12e9af0 100644 (file)
@@ -111,9 +111,6 @@ if HAVE_GNUTLS
 AM_CPPFLAGS += $(GNUTLS_CFLAGS)
 endif
 
-if HAVE_LIBH2OEVLOOP
-AM_CPPFLAGS += $(LIBH2OEVLOOP_CFLAGS)
-endif
 endif
 
 EXTRA_DIST=COPYING \
@@ -264,7 +261,6 @@ dnsdist_SOURCES = \
        dnsparser.hh dnsparser.cc \
        dnstap.cc dnstap.hh \
        dnswriter.cc dnswriter.hh \
-       doh.hh \
        doh3.cc doh3.hh \
        dolog.cc dolog.hh \
        doq-common.hh \
@@ -522,11 +518,6 @@ if HAVE_GNUTLS
 dnsdist_LDADD += $(GNUTLS_LIBS)
 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
@@ -637,7 +628,6 @@ fuzz_target_dnsdistcache_SOURCES = \
        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 \
index 2297d1a78b27186ca5680083dd62d1ff80adbf67..cd4ac5561c9c929ec5155e3499dad00cfebbd037 100644 (file)
@@ -82,7 +82,6 @@ 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_NGHTTP2], [false])
@@ -111,10 +110,8 @@ AS_IF([test "x$enable_dns_over_tls" != "xno"], [
 
 AS_IF([test "x$enable_dns_over_https" != "xno"], [
   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_NGHTTP2" != "x1" ], [
+    AC_MSG_ERROR([DNS over HTTPS support requested but nghttp2 was not found])
   ])
 
   AS_IF([test "x$HAVE_GNUTLS" != "x1" -a "x$HAVE_LIBSSL" != "x1"], [
@@ -304,10 +301,6 @@ 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])]
index f25e41d1f40e2a2ffe736002e4d826f2a5285828..811452ab9b28814b5ce9bf5754ced03c829d3ab2 100644 (file)
@@ -40,7 +40,6 @@
 #include "dnsdist-kvs.hh"
 #include "dnsdist-web.hh"
 #include "dnsdist-xsk.hh"
-#include "doh.hh"
 #include "fstrm_logger.hh"
 #include "iputils.hh"
 #include "remote_logger.hh"
@@ -359,17 +358,7 @@ static bool handleTLSConfiguration(const dnsdist::rust::settings::BindConfigurat
     tlsContext->d_provider = std::string(bind.tls.provider);
     boost::algorithm::to_lower(tlsContext->d_provider);
     frontend->d_library = std::string(bind.doh.provider);
-    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", bind.listen_address);
-      return false;
-#endif /* HAVE_LIBH2OEVLOOP */
-    }
-    else if (frontend->d_library == "nghttp2") {
+    if (frontend->d_library == "nghttp2") {
 #ifndef HAVE_NGHTTP2
       errlog("DOH bind %s is configured to use nghttp2 but the library is not available", bind.listen_address);
       return false;
index 8c1c6623cdcf2dde0f54d3113888acfa48359fbd..48d29a46b99b66cbdc95195ed320fc0bc7d5f32c 100644 (file)
@@ -99,7 +99,7 @@ struct DOHFrontend
   std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
   std::shared_ptr<std::vector<std::shared_ptr<DOHResponseMapEntry>>> d_responsesMap;
   std::shared_ptr<TLSFrontend> d_tlsContext;
-  std::string d_serverTokens{"h2o/dnsdist"};
+  std::string d_serverTokens{"dnsdist"};
   std::unordered_map<std::string, std::string> d_customResponseHeaders;
   std::string d_library;
 
index 0bee1016596f9df0fe2b08125eeb7c0cb9ecccf2..185ad693a049dca9cc50597b817d08baf5c01f70 100644 (file)
@@ -296,7 +296,7 @@ struct IDState
        the 'outstanding' counters, which should only be increased when we are picking
        an empty state, and not when reusing ;
        For DoH, though, we have dynamically allocated a DOHUnit object that needs to
-       be freed, as well as internal objects internals to libh2o.
+       be freed, as well as internal objects.
      - one of the UDP receiver threads receiving a response from a backend, picking
        the corresponding state and sending the response to the client ;
      - the 'healthcheck' thread scanning the states to actively discover timeouts,
index 66b327e51ba8e1102ea71b044910695605b9cc21..a50bae16469ad49460118614aab1d8a718bcf1c9 100644 (file)
@@ -22,7 +22,6 @@
 #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);
@@ -37,11 +36,6 @@ std::unique_ptr<CrossProtocolQuery> getInternalQueryFromDQ(DNSQuestion& dnsQuest
   }
 #ifdef HAVE_DNS_OVER_HTTPS
   else if (protocol == dnsdist::Protocol::DoH) {
-#ifdef HAVE_LIBH2OEVLOOP
-    if (dnsQuestion.ids.cs->dohFrontend->d_library == "h2o") {
-      return getDoHCrossProtocolQueryFromDQ(dnsQuestion, isResponse);
-    }
-#endif /* HAVE_LIBH2OEVLOOP */
     return getTCPCrossProtocolQueryFromDQ(dnsQuestion);
   }
 #endif
index 4f70538f1bc389da8a85ed0f8b3aaed0947335d4..dc062fbb2ef578065427b8cdcbfbf3c09b561757 100644 (file)
@@ -65,7 +65,6 @@
 
 #include "base64.hh"
 #include "coverage.hh"
-#include "doh.hh"
 #include "doq-common.hh"
 #include "dolog.hh"
 #include "threadname.hh"
@@ -2163,21 +2162,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     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") {
+    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;
index a466bd04884cbf58fa68c5bf93d9792e965731f3..ad1318f283e23949f46374d5e54531fccbff1505 100644 (file)
@@ -948,7 +948,6 @@ incoming_doh:
       descripton: "Which underlying HTTP2 library should be used"
       supported-values:
         - "nghttp2"
-        - "h2o"
     - name: "paths"
       type: "Vec<String>"
       default: "/dns-query"
@@ -960,7 +959,7 @@ incoming_doh:
     - name: "server_tokens"
       type: "String"
       default: ""
-      description: "The content of the Server: HTTP header returned by dnsdist. The default is ``h2o/dnsdist`` when ``h2o`` is used, ``nghttp2-<version>/dnsdist`` when ``nghttp2`` is"
+      description: "The content of the Server: HTTP header returned by dnsdist. The default is ``nghttp2-<version>/dnsdist`` when ``nghttp2`` is used"
     - name: "send_cache_control_headers"
       type: "bool"
       default: "true"
index 200f4d3d4bb4a6c620ea428a9310e348a1646d2d..d14d6876e0642514ed98ab451d4e9abe1a2c0bdf 100644 (file)
@@ -80,7 +80,6 @@
 #include "capabilities.hh"
 #include "coverage.hh"
 #include "delaypipe.hh"
-#include "doh.hh"
 #include "dolog.hh"
 #include "dnsname.hh"
 #include "ednsoptions.hh"
@@ -3019,12 +3018,6 @@ static void reportFeatures()
 #endif /* HAVE_DNS_OVER_TLS */
 #ifdef HAVE_DNS_OVER_HTTPS
   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 */
@@ -3350,18 +3343,6 @@ static void startFrontends()
     }
 #endif /* HAVE_XSK */
 
-    if (clientState->dohFrontend != nullptr && clientState->dohFrontend->d_library == "h2o") {
-#ifdef HAVE_DNS_OVER_HTTPS
-#ifdef HAVE_LIBH2OEVLOOP
-      std::thread dohThreadHandle(dohThread, clientState.get());
-      if (!clientState->cpus.empty()) {
-        mapThreadToCPUList(dohThreadHandle.native_handle(), clientState->cpus);
-      }
-      dohThreadHandle.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());
index ecb1a0f65f0d38a326f7f1833c72772ff31dd15b..ca26a2bb93f2814b74c9c3d122b427be4bbb72ad 100644 (file)
@@ -6,7 +6,7 @@ DNS-over-HTTPS (DoH)
 
 :program:`dnsdist` supports DNS-over-HTTPS (DoH, standardized in RFC 8484) for incoming queries since 1.4.0, and for outgoing queries since 1.7.0.
 To see if the installation supports this, run ``dnsdist --version``.
-If the output shows ``dns-over-https(DOH)`` (``dns-over-https(h2o nghttp2)``, ``dns-over-https(h2o)`` or ``dns-over-https(nghttp2)`` since 1.9.0) , incoming DNS-over-HTTPS is supported. If ``outgoing-dns-over-https(nghttp2)`` shows up then outgoing DNS-over-HTTPS is supported.
+If the output shows ``dns-over-https(DOH)`` (``dns-over-https(nghttp2)`` since 1.9.0) , incoming DNS-over-HTTPS is supported. If ``outgoing-dns-over-https(nghttp2)`` shows up then outgoing DNS-over-HTTPS is supported.
 
 Incoming
 --------
@@ -88,7 +88,7 @@ To let dnsdist listen for DoH queries over HTTP on localhost at port 8053 add on
 HTTP/1 support
 ^^^^^^^^^^^^^^
 
-dnsdist initially relied on the ``h2o`` library to support incoming DNS over HTTPS. Since 1.9.0, ``h2o`` has been deprecated and ``nghttp2`` is the
+dnsdist initially relied on the ``h2o`` library to support incoming DNS over HTTPS. Since 2.1.0, ``h2o`` is no longer in use and ``nghttp2`` is the
 preferred library for incoming DoH support, because ``h2o`` has unfortunately really never been maintained in a way that is suitable for use as a library
 (see https://github.com/h2o/h2o/issues/3230). While we took great care to make the migration as painless as possible, ``h2o`` supported HTTP/1 while ``nghttp2``
 does not. This is not an issue for actual DNS over HTTPS clients that support HTTP/2, but might be one in setups running dnsdist behind a reverse-proxy that
index 2763cea519eabc049e90dddab6d14cc8a42aeed2..9ffcfac8608e08d080a9e467c5a25c9daee35ef4 100644 (file)
@@ -54,7 +54,6 @@ dnsdist depends on the following libraries:
   (required for building with ``meson``)
 * `libbpf <https://github.com/libbpf/libbpf>`_ and `libxdp <https://github.com/xdp-project/xdp-tools>`_ (optional, `XSK`/`AF_XDP` support)
 * `libcap <https://sites.google.com/site/fullycapable/>`_ (optional, capabilities support)
-* `libh2o <https://github.com/h2o/h2o>`_ (optional, incoming DoH support, deprecated in 1.9.0 in favor of ``nghttp2``)
 * `libsodium <https://download.libsodium.org/doc/>`_ (optional, DNSCrypt support)
 * `LMDB <http://www.lmdb.tech/doc/>`_ (optional, LMDB support)
 * `net-snmp <https://www.net-snmp.org/>`_ (optional, SNMP support)
index 65e82ae8fe123497867203dcde5c7533d222ba61..25a4f24326be43bd79baa20f1b96358e4c1d4391 100644 (file)
@@ -164,7 +164,7 @@ Listen Sockets
   * ``idleTimeout=30``: int - Set the idle timeout, in seconds.
   * ``ciphers``: str - The TLS ciphers to use, in OpenSSL format. Ciphers for TLS 1.3 must be specified via ``ciphersTLS13``.
   * ``ciphersTLS13``: str - The TLS ciphers to use for TLS 1.3, in OpenSSL format.
-  * ``serverTokens``: str - The content of the Server: HTTP header returned by dnsdist. The default is "h2o/dnsdist" when ``h2o`` is used, "nghttp2-<version>/dnsdist" when ``nghttp2`` is.
+  * ``serverTokens``: str - The content of the Server: HTTP header returned by dnsdist. The default is "nghttp2-<version>/dnsdist" when ``nghttp2`` is used.
   * ``customResponseHeaders={}``: table - Set custom HTTP header(s) returned by dnsdist.
   * ``ocspResponses``: list - List of files containing OCSP responses, in the same order than the certificates and keys, that will be used to provide OCSP stapling responses.
   * ``minTLSVersion``: str - Minimum version of the TLS protocol to support. Possible values are 'tls1.0', 'tls1.1', 'tls1.2' and 'tls1.3'. Default is to require at least TLS 1.0.
@@ -187,7 +187,7 @@ Listen Sockets
   * ``keepIncomingHeaders``: bool - Whether to retain the incoming headers in memory, to be able to use :func:`HTTPHeaderRule` or :meth:`DNSQuestion.getHTTPHeaders`. Default is false. Before 1.8.0 the headers were always kept in-memory.
   * ``additionalAddresses``: list - List of additional addresses (with port) to listen on. Using this option instead of creating a new frontend for each address avoids the creation of new thread and Frontend objects, reducing the memory usage. The drawback is that there will be a single set of metrics for all addresses.
   * ``ignoreTLSConfigurationErrors=false``: bool - Ignore TLS configuration errors (such as invalid certificate path) and just issue a warning instead of aborting the whole process
-  * ``library``: str - Which underlying HTTP2 library should be used, either h2o or nghttp2. Until 1.9.0 only h2o was available, but the use of this library is now deprecated as it is no longer maintained. nghttp2 is the new default since 1.9.0.
+  * ``library``: str - Which underlying HTTP2 library should be used, only ``nghttp2`` is supported.
   * ``ktls=false``: bool - Whether to enable the experimental kernel TLS support on Linux, if both the kernel and the OpenSSL library support it. Default is false.
   * ``tlsAsyncMode=false``: bool - Whether to enable experimental asynchronous TLS I/O operations if the ``nghttp2`` library is used, ``OpenSSL`` is used as the TLS implementation and an asynchronous capable SSL engine (or provider) is loaded. See also :func:`loadTLSEngine` or :func:`loadTLSProvider` to load the engine (or provider).
   * ``readAhead``: bool - When the TLS provider is set to OpenSSL, whether we tell the library to read as many input bytes as possible, which leads to better performance by reducing the number of syscalls. Default is true.
index 1aafd51f9f32baf771c16e2398e8ac3c459e3e8a..e5288ae1ecc821f0ec3976735bab2953d5ecd91f 100644 (file)
@@ -354,9 +354,6 @@ Selectors can be combined via :func:`AndRule`, :func:`OrRule` and :func:`NotRule
   Matches against the TLS Server Name Indication value sent by the client, if any. Only makes
   sense for DoT or DoH, and for that last one matching on the HTTP Host header using :func:`HTTPHeaderRule`
   might provide more consistent results.
-  As of the version 2.3.0-beta of h2o, it is unfortunately not possible to extract the SNI value from DoH
-  connections, and it is therefore necessary to use the HTTP Host header until version 2.3.0 is released,
-  or ``nghttp2`` is used for incoming DoH instead (1.9.0+).
 
   :param str name: The exact SNI name to match.
 
index b8d253898ea2d6dc0ffa37e369107eb64aee902b..69572f81d1ceb6adb83791dba64318e324247e23 100644 (file)
@@ -6,6 +6,11 @@ Upgrade Guide
 
 Custom load-balancing policies written in Lua now need to return the index in the servers array of the backend they intend to select, instead of returning a reference to the backend itself.
 
+dnsdist no longer supports ``h2o`` for incoming DNS over HTTPS, as it is unfortunately no longer maintained in a way that is suitable for use as a library
+(see https://github.com/h2o/h2o/issues/3230). This means that only ``nghttp2`` is supported from now on.
+Note that ``nghttp2`` only supports HTTP/2, and not HTTP/1, while ``h2o`` supported both. This is not an issue for actual DNS over HTTPS clients that
+support HTTP/2, but might be one in setups running dnsdist behind a reverse-proxy that does not support HTTP/2. See :doc:`guides/dns-over-https` for some work-around.
+
 1.9.x to 2.0.0
 --------------
 
diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc
deleted file mode 100644 (file)
index 9f76101..0000000
+++ /dev/null
@@ -1,1792 +0,0 @@
-#include "config.h"
-#include "doh.hh"
-
-#ifdef HAVE_DNS_OVER_HTTPS
-#ifdef HAVE_LIBH2OEVLOOP
-#define H2O_USE_EPOLL 1
-
-#include <cerrno>
-#include <iostream>
-#include <thread>
-#include <string_view>
-
-#include <boost/algorithm/string.hpp>
-#include <h2o.h>
-#include <h2o/http2.h>
-
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-
-#include "base64.hh"
-#include "dnsname.hh"
-#undef CERT
-#include "dnsdist.hh"
-#include "dnsdist-tcp.hh"
-#include "misc.hh"
-#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 "libssl.hh"
-#include "threadname.hh"
-
-/* So, how does this work. We use h2o for our http2 and TLS needs.
-   If the operator has configured multiple IP addresses to listen on,
-   we launch multiple h2o listener threads. We can hook in to multiple
-   URLs though on the same IP. There is no SNI yet (I think).
-
-   h2o is event driven, so we get callbacks if a new DNS query arrived.
-   When it does, we do some minimal parsing on it, and send it on to the
-   dnsdist worker thread which we also launched.
-
-   This dnsdist worker thread injects the query into the normal dnsdist flow
-   (over a pipe). The response also goes back over a (different) pipe,
-   where we pick it up and deliver it back to h2o.
-
-   For coordination, we use the h2o socket multiplexer, which is sensitive to our
-   pipe too.
-*/
-
-/* h2o notes.
-   Paths and parameters etc just *happen* to be null-terminated in HTTP2.
-   They are not in HTTP1. So you MUST use the length field!
-*/
-
-/* 'Intermediate' compatibility from https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 */
-static constexpr std::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
-{
-public:
-  DOHAcceptContext()
-  {
-    memset(&d_h2o_accept_ctx, 0, sizeof(d_h2o_accept_ctx));
-    d_rotatingTicketsKey.clear();
-  }
-  DOHAcceptContext(const DOHAcceptContext&) = delete;
-  DOHAcceptContext(DOHAcceptContext&&) = delete;
-  DOHAcceptContext& operator=(const DOHAcceptContext&) = delete;
-  DOHAcceptContext& operator=(DOHAcceptContext&&) = delete;
-
-  h2o_accept_ctx_t* get()
-  {
-    return &d_h2o_accept_ctx;
-  }
-
-  ~DOHAcceptContext()
-  {
-    SSL_CTX_free(d_h2o_accept_ctx.ssl_ctx);
-    d_h2o_accept_ctx.ssl_ctx = nullptr;
-  }
-
-  void decrementConcurrentConnections() const
-  {
-    if (d_cs != nullptr) {
-      --d_cs->tcpCurrentConnections;
-    }
-  }
-
-  [[nodiscard]] time_t getNextTicketsKeyRotation() const
-  {
-    return d_ticketsKeyNextRotation;
-  }
-
-  [[nodiscard]] size_t getTicketsKeysCount() const
-  {
-    size_t res = 0;
-    if (d_ticketKeys) {
-      res = d_ticketKeys->getKeysCount();
-    }
-    return res;
-  }
-
-  void rotateTicketsKey(time_t now)
-  {
-    if (!d_ticketKeys) {
-      return;
-    }
-
-    d_ticketKeys->rotateTicketsKey(now);
-
-    if (d_ticketsKeyRotationDelay > 0) {
-      d_ticketsKeyNextRotation = now + d_ticketsKeyRotationDelay;
-    }
-  }
-
-  void loadTicketsKeys(const std::string& keyFile)
-  {
-    if (!d_ticketKeys) {
-      return;
-    }
-    d_ticketKeys->loadTicketsKeys(keyFile);
-
-    if (d_ticketsKeyRotationDelay > 0) {
-      d_ticketsKeyNextRotation = time(nullptr) + d_ticketsKeyRotationDelay;
-    }
-  }
-
-  void handleTicketsKeyRotation()
-  {
-    if (d_ticketsKeyRotationDelay == 0) {
-      return;
-    }
-
-    time_t now = time(nullptr);
-    if (now > d_ticketsKeyNextRotation) {
-      if (d_rotatingTicketsKey.test_and_set()) {
-        /* someone is already rotating */
-        return;
-      }
-      try {
-        rotateTicketsKey(now);
-
-        d_rotatingTicketsKey.clear();
-      }
-      catch(const std::runtime_error& e) {
-        d_rotatingTicketsKey.clear();
-        throw std::runtime_error(std::string("Error generating a new tickets key for TLS context:") + e.what());
-      }
-      catch(...) {
-        d_rotatingTicketsKey.clear();
-        throw;
-      }
-    }
-  }
-
-  std::map<int, std::string> d_ocspResponses;
-  std::unique_ptr<OpenSSLTLSTicketKeysRing> d_ticketKeys{nullptr};
-  // 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{};
-  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>())
-  {
-#ifndef USE_SINGLE_ACCEPTOR_THREAD
-    {
-      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 */
-
-    {
-      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);
-    }
-
-    h2o_config_init(&h2o_config);
-    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
-       H2O_HTTP2_SETTINGS_HOST.max_concurrent_streams which is not configurable. Even if decided to change the
-       hard-coded value, libh2o's author warns that there might be parts of the code where the stream ID is stored
-       in 8 bits, making 256 a hard value: https://github.com/h2o/h2o/issues/805
-    */
-  }
-  DOHServerConfig(const DOHServerConfig&) = delete;
-  DOHServerConfig(DOHServerConfig&&) = delete;
-  DOHServerConfig& operator=(const DOHServerConfig&) = delete;
-  DOHServerConfig& operator=(DOHServerConfig&&) = delete;
-  ~DOHServerConfig() = default;
-
-  std::set<std::string, std::less<>> paths;
-  h2o_globalconf_t h2o_config{};
-  h2o_context_t h2o_ctx{};
-  std::unique_ptr<h2o_socket_t,decltype(&h2o_socket_close)> h2o_socket{nullptr, h2o_socket_close};
-  std::shared_ptr<DOHAcceptContext> accept_ctx{nullptr};
-  ClientState* clientState{nullptr};
-  std::shared_ptr<DOHFrontend> dohFrontend{nullptr};
-#ifndef USE_SINGLE_ACCEPTOR_THREAD
-  pdns::channel::Sender<DOHUnit> d_querySender;
-  pdns::channel::Receiver<DOHUnit> d_queryReceiver;
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
-  pdns::channel::Sender<DOHUnit> d_responseSender;
-  pdns::channel::Receiver<DOHUnit> d_responseReceiver;
-};
-
-struct DOHUnit : public DOHUnitInterface
-{
-  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.
-  */
-  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;
-  [[nodiscard]] std::shared_ptr<TCPQuerySender> getQuerySender() const override
-  {
-    return nullptr;
-  }
-  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>;
-
-/* 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);
-    }
-  } 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());
-  }
-}
-
-/* This function is called from other threads than the main DoH one,
-   instructing it to send a 502 error to the client. */
-void DOHUnit::handleTimeout()
-{
-  status_code = 502;
-  sendDoHUnitToTheMainThread(std::unique_ptr<DOHUnit>(this), "DoH timeout");
-}
-
-struct DOHConnection
-{
-  std::shared_ptr<DOHAcceptContext> d_acceptCtx{nullptr};
-  ComboAddress d_remote;
-  ComboAddress d_local;
-  struct timeval d_connectionStartTime{0, 0};
-  size_t d_nbQueries{0};
-  int d_desc{-1};
-  uint8_t d_concurrentStreams{0};
-};
-
-static thread_local std::unordered_map<int, DOHConnection> t_conns;
-
-static void on_socketclose(void *data)
-{
-  auto* conn = static_cast<DOHConnection*>(data);
-  if (conn != nullptr) {
-    if (conn->d_acceptCtx) {
-      struct timeval now{};
-      gettimeofday(&now, nullptr);
-
-      auto diff = now - conn->d_connectionStartTime;
-
-      conn->d_acceptCtx->decrementConcurrentConnections();
-      conn->d_acceptCtx->d_cs->updateTCPMetrics(conn->d_nbQueries, diff.tv_sec * 1000 + diff.tv_usec / 1000, 0);
-    }
-
-    dnsdist::IncomingConcurrentTCPConnectionsManager::accountClosedTCPConnection(conn->d_remote);
-    // you can no longer touch conn, or data, after this call
-    t_conns.erase(conn->d_desc);
-  }
-}
-
-static const std::string& getReasonFromStatusCode(uint16_t statusCode)
-{
-  /* no need to care too much about this, HTTP/2 has no 'reason' anyway */
-  static const std::unordered_map<uint16_t, std::string> reasons = {
-    { 200, "OK" },
-    { 301, "Moved Permanently" },
-    { 302, "Found" },
-    { 303, "See Other" },
-    { 304, "Not Modified" },
-    { 305, "Use Proxy" },
-    { 306, "Switch Proxy" },
-    { 307, "Temporary Redirect" },
-    { 308, "Permanent Redirect" },
-    { 400, "Bad Request" },
-    { 401, "Unauthorized" },
-    { 402, "Payment Required" },
-    { 403, "Forbidden" },
-    { 404, "Not Found" },
-    { 405, "Method Not Allowed" },
-    { 406, "Not Acceptable" },
-    { 407, "Proxy Authentication Required" },
-    { 408, "Request Timeout" },
-    { 409, "Conflict" },
-    { 410, "Gone" },
-    { 411, "Length Required" },
-    { 412, "Precondition Failed" },
-    { 413, "Payload Too Large" },
-    { 414, "URI Too Long" },
-    { 415, "Unsupported Media Type" },
-    { 416, "Range Not Satisfiable" },
-    { 417, "Expectation Failed" },
-    { 418, "I'm a teapot" },
-    { 451, "Unavailable For Legal Reasons" },
-    { 500, "Internal Server Error" },
-    { 501, "Not Implemented" },
-    { 502, "Bad Gateway" },
-    { 503, "Service Unavailable" },
-    { 504, "Gateway Timeout" },
-    { 505, "HTTP Version Not Supported" }
-  };
-  static const std::string unknown = "Unknown";
-
-  const auto reasonIt = reasons.find(statusCode);
-  if (reasonIt == reasons.end()) {
-    return unknown;
-  }
-  return reasonIt->second;
-}
-
-static DOHConnection* getConnectionFromQuery(const h2o_req_t* req)
-{
-  h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn);
-  const int descriptor = h2o_socket_get_fd(sock);
-  if (descriptor == -1) {
-    /* this should not happen, but let's not crash on it */
-    return nullptr;
-  }
-  return &t_conns.at(descriptor);
-}
-
-/* Always called from the main DoH thread */
-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;
-  for (auto const& headerPair : customResponseHeaders) {
-    h2o_set_header_by_str(&req->pool, &req->res.headers, headerPair.first.c_str(), headerPair.first.size(), maybe_token, headerPair.second.c_str(), headerPair.second.size(), overwrite_if_exists);
-  }
-
-  if (statusCode == 200) {
-    ++dohFrontend.d_validresponses;
-    req->res.status = 200;
-
-    if (addContentType) {
-      if (contentType.empty()) {
-        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, nullptr, H2O_STRLIT("application/dns-message"));
-      }
-      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 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 (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);
-        /* 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 ccv = h2o_strdup(&req->pool, cacheControlValue.c_str(), cacheControlValue.size());
-        h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CACHE_CONTROL, nullptr, ccv.base, ccv.len);
-      }
-    }
-
-    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);
-    ++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 {
-      switch(statusCode) {
-      case 400:
-        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(), "DoH query not allowed", 0);
-        break;
-      case 502:
-        h2o_send_error_502(req, getReasonFromStatusCode(statusCode).c_str(), "no downstream server available", 0);
-        break;
-      case 500:
-        /* fall-through */
-      default:
-        h2o_send_error_500(req, getReasonFromStatusCode(statusCode).c_str(), "Internal Server Error", 0);
-        break;
-      }
-    }
-
-    ++dohFrontend.d_errorresponses;
-  }
-
-  if (auto* conn = getConnectionFromQuery(req)) {
-    --conn->d_concurrentStreams;
-  }
-}
-
-static std::unique_ptr<DOHUnit> getDUFromIDS(InternalQueryState& ids)
-{
-  auto dohUnit = std::unique_ptr<DOHUnit>(dynamic_cast<DOHUnit*>(ids.du.release()));
-  return dohUnit;
-}
-
-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;
-  }
-
-  void handleResponse(const struct timeval& now, TCPResponse&& response) override
-  {
-    (void)now;
-    if (!response.d_idstate.du) {
-      return;
-    }
-
-    auto dohUnit = getDUFromIDS(response.d_idstate);
-    if (dohUnit->responseSender == nullptr) {
-      return;
-    }
-
-    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().get(), sizeof(cleartextDH));
-
-    if (!response.isAsync()) {
-      dr.ids.du = std::move(dohUnit);
-
-      if (!processResponse(dynamic_cast<DOHUnit*>(dr.ids.du.get())->response, dr, false)) {
-        if (dr.ids.du) {
-          dohUnit = getDUFromIDS(dr.ids);
-          dohUnit->status_code = 503;
-          sendDoHUnitToTheMainThread(std::move(dohUnit), "Response dropped by rules");
-        }
-        return;
-      }
-
-      if (dr.isAsynchronous()) {
-        return;
-      }
-
-      dohUnit = getDUFromIDS(dr.ids);
-    }
-
-    if (!dohUnit->ids.selfGenerated) {
-      auto udiff = dohUnit->ids.queryRealTime.udiff();
-      vinfolog("Got answer from %s, relayed to %s (https), took %d us", dohUnit->downstream->d_config.remote.toStringWithPort(), dohUnit->ids.origRemote.toStringWithPort(), udiff);
-
-      auto backendProtocol = dohUnit->downstream->getProtocol();
-      if (backendProtocol == dnsdist::Protocol::DoUDP && dohUnit->tcp) {
-        backendProtocol = dnsdist::Protocol::DoTCP;
-      }
-      handleResponseSent(dohUnit->ids, udiff, dohUnit->ids.origRemote, dohUnit->downstream->d_config.remote, dohUnit->response.size(), cleartextDH, backendProtocol, true);
-    }
-
-    ++dnsdist::metrics::g_stats.responses;
-    if (dohUnit->ids.cs != nullptr) {
-      ++dohUnit->ids.cs->responses;
-    }
-
-    sendDoHUnitToTheMainThread(std::move(dohUnit), "cross-protocol response");
-  }
-
-  void handleXFRResponse(const struct timeval& now, TCPResponse&& response) override
-  {
-    return handleResponse(now, std::move(response));
-  }
-
-  void notifyIOError(const struct timeval& now, TCPResponse&& response) override
-  {
-    (void)now;
-    auto& query = response.d_idstate;
-    if (!query.du) {
-      return;
-    }
-
-    auto dohUnit = getDUFromIDS(query);
-    if (dohUnit->responseSender == nullptr) {
-      return;
-    }
-
-    dohUnit->ids = std::move(query);
-    dohUnit->status_code = 502;
-    sendDoHUnitToTheMainThread(std::move(dohUnit), "cross-protocol error response");
-  }
-};
-
-class DoHCrossProtocolQuery : public CrossProtocolQuery
-{
-public:
-  DoHCrossProtocolQuery(DOHUnitUniquePtr&& dohUnit, bool isResponse)
-  {
-    if (isResponse) {
-      /* happens when a response becomes async */
-      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(dohUnit->query), std::move(dohUnit->ids));
-    }
-
-    /* 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 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.d_proxyProtocolPayloadSize > 0;
-    downstream = query.d_idstate.du->downstream;
-  }
-
-  void handleInternalError()
-  {
-    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
-  {
-    auto* unit = dynamic_cast<DOHUnit*>(query.d_idstate.du.get());
-    if (unit != nullptr) {
-      unit->downstream = downstream;
-    }
-    return s_sender;
-  }
-
-  DNSQuestion getDQ() override
-  {
-    auto& ids = query.d_idstate;
-    DNSQuestion dq(ids, query.d_buffer);
-    return dq;
-  }
-
-  DNSResponse getDR() override
-  {
-    auto& ids = query.d_idstate;
-    DNSResponse dr(ids, query.d_buffer, downstream);
-    return dr;
-   }
-
-  DOHUnitUniquePtr releaseDU()
-  {
-    return getDUFromIDS(query.d_idstate);
-  }
-
-private:
-  static std::shared_ptr<DoHTCPCrossQuerySender> s_sender;
-};
-
-std::shared_ptr<DoHTCPCrossQuerySender> DoHCrossProtocolQuery::s_sender = std::make_shared<DoHTCPCrossQuerySender>();
-
-std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse)
-{
-  if (!dq.ids.du) {
-    throw std::runtime_error("Trying to create a DoH cross protocol query without a valid DoH unit");
-  }
-
-  auto dohUnit = getDUFromIDS(dq.ids);
-  if (&dq.ids != &dohUnit->ids) {
-   dohUnit->ids = std::move(dq.ids);
-  }
-
-  dohUnit->ids.origID = dq.getHeader()->id;
-
-  if (!isResponse) {
-    if (dohUnit->query.data() != dq.getMutableData().data()) {
-      dohUnit->query = std::move(dq.getMutableData());
-    }
-  }
-  else {
-    if (dohUnit->response.data() != dq.getMutableData().data()) {
-      dohUnit->response = std::move(dq.getMutableData());
-    }
-  }
-
-  return std::make_unique<DoHCrossProtocolQuery>(std::move(dohUnit), isResponse);
-}
-
-/*
-   We are not in the main DoH thread but in the DoH 'client' thread.
-*/
-static void processDOHQuery(DOHUnitUniquePtr&& unit, bool inMainThread = false)
-{
-  const auto handleImmediateResponse = [inMainThread](DOHUnitUniquePtr&& dohUnit, const char* reason) {
-    if (inMainThread) {
-      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. */
-      dohUnit->ids.du.reset();
-    }
-    else {
-      sendDoHUnitToTheMainThread(std::move(dohUnit), reason);
-    }
-  };
-
-  dnsdist::configuration::refreshLocalRuntimeConfiguration();
-
-  auto& ids = unit->ids;
-  uint16_t queryId = 0;
-  ComboAddress remote;
-
-  try {
-    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 dohUnit->req
-      // outside of the main DoH thread
-      unit->status_code = 500;
-      handleImmediateResponse(std::move(unit), "DoH killed in flight");
-      return;
-    }
-
-    remote = ids.origRemote;
-    DOHServerConfig* dsc = unit->dsc;
-    ClientState& clientState = *dsc->clientState;
-
-    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;
-    }
-
-    ++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 */
-      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
-      const dnsheader_aligned dnsHeader(unit->query.data());
-
-      if (!checkQueryHeaders(*dnsHeader, clientState)) {
-        unit->status_code = 400;
-        handleImmediateResponse(std::move(unit), "DoH invalid headers");
-        return;
-      }
-
-      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(unit), "DoH empty query");
-        return;
-      }
-
-      queryId = ntohs(dnsHeader->id);
-    }
-
-    {
-      // 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 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, downstream);
-
-    if (result == ProcessQueryResult::Drop) {
-      unit = getDUFromIDS(ids);
-      unit->status_code = 403;
-      handleImmediateResponse(std::move(unit), "DoH dropped query");
-      return;
-    }
-    if (result == ProcessQueryResult::Asynchronous) {
-      return;
-    }
-    if (result == ProcessQueryResult::SendAnswer) {
-      unit = getDUFromIDS(ids);
-      if (unit->response.empty()) {
-        unit->response = std::move(unit->query);
-      }
-      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(unit), "DoH self-answered response");
-      return;
-    }
-
-    unit = getDUFromIDS(ids);
-    if (result != ProcessQueryResult::PassToBackend) {
-      unit->status_code = 500;
-      handleImmediateResponse(std::move(unit), "DoH no backend available");
-      return;
-    }
-
-    if (downstream == nullptr) {
-      unit->status_code = 502;
-      handleImmediateResponse(std::move(unit), "DoH no backend available");
-      return;
-    }
-
-    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(dnsQuestion);
-      }
-
-      unit->ids.origID = htons(queryId);
-      unit->tcp = true;
-
-      /* this moves du->ids, careful! */
-      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;
-      }
-
-      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();
-        }
-        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;
-    }
-
-    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());
-    unit->status_code = 500;
-    handleImmediateResponse(std::move(unit), "DoH internal error");
-    return;
-  }
-}
-
-/* called when a HTTP response is about to be sent, from the main DoH thread */
-static void on_response_ready_cb(struct st_h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t **slot)
-{
-  (void)self;
-  if (req == nullptr) {
-    return;
-  }
-
-  // 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->dohFrontend->d_http1Stats;
-  }
-  else {
-    /* HTTP 2.0 */
-    stats = &dsc->dohFrontend->d_http2Stats;
-  }
-
-  switch (req->res.status) {
-  case 200:
-    ++stats->d_nb200Responses;
-    break;
-  case 400:
-    ++stats->d_nb400Responses;
-    break;
-  case 403:
-    ++stats->d_nb403Responses;
-    break;
-  case 500:
-    ++stats->d_nb500Responses;
-    break;
-  case 502:
-    ++stats->d_nb502Responses;
-    break;
-  default:
-    ++stats->d_nbOtherResponses;
-    break;
-  }
-
-  h2o_setup_next_ostream(req, slot);
-}
-
-/* this is called by h2o when our request dies.
-   We use this to signal to the 'du' that this req is no longer alive */
-static void on_generator_dispose(void *_self)
-{
-  auto* dohUnit = static_cast<DOHUnit**>(_self);
-  if (*dohUnit != nullptr) { // if nullptr, on_dnsdist cleaned up dohUnit already
-    (*dohUnit)->self = nullptr;
-    (*dohUnit)->req = nullptr;
-  }
-}
-
-/* This executes in the main DoH thread.
-   We allocate a DOHUnit and send it to dnsdistclient() function in the doh client thread
-   via a pipe */
-static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, PacketBuffer&& query, const ComboAddress& local, const ComboAddress& remote, std::string&& path)
-{
-  auto* conn = getConnectionFromQuery(req);
-
-  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);
-
-    /* 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 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) {
-      dohUnit->scheme = std::string(req->scheme->name.base, req->scheme->name.len);
-    }
-    dohUnit->query_at = req->query_at;
-
-    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) {
-        // 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);
-      }
-    }
-
-    if (conn != nullptr) {
-      ++conn->d_concurrentStreams;
-    }
-#ifdef HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME
-    h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn);
-    const char * sni = h2o_socket_get_ssl_server_name(sock);
-    if (sni != nullptr) {
-      dohUnit->sni = sni;
-    }
-#endif /* HAVE_H2O_SOCKET_GET_SSL_SERVER_NAME */
-    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(std::move(dohUnit), true);
-#else /* USE_SINGLE_ACCEPTOR_THREAD */
-    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");
-        if (conn != nullptr) {
-          --conn->d_concurrentStreams;
-        }
-        h2o_send_error_500(req, "Internal Server Error", "Internal Server Error", 0);
-      }
-    }
-    catch (...) {
-      vinfolog("Unable to pass a DoH query to the DoH worker thread because we couldn't write to the pipe: %s", stringerror());
-      if (conn != nullptr) {
-        --conn->d_concurrentStreams;
-      }
-      h2o_send_error_500(req, "Internal Server Error", "Internal Server Error", 0);
-    }
-#endif /* USE_SINGLE_ACCEPTOR_THREAD */
-  }
-  catch (const std::exception& e) {
-    vinfolog("Had error parsing DoH DNS packet from %s: %s", remote.toStringWithPort(), e.what());
-    if (conn != nullptr) {
-      --conn->d_concurrentStreams;
-    }
-    h2o_send_error_400(req, "Bad Request", "The DNS query could not be parsed", 0);
-  }
-}
-
-/* can only be called from the main DoH thread */
-static bool getHTTPHeaderValue(const h2o_req_t* req, const std::string& headerName, std::string_view& value)
-{
-  bool found = false;
-  /* early versions of boost::string_ref didn't have the ability to compare to string */
-  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;
-    }
-  }
-
-  return found;
-}
-
-/* can only be called from the main DoH thread */
-static std::optional<ComboAddress> processForwardedForHeader(const h2o_req_t* req, const ComboAddress& remote)
-{
-  static const std::string headerName = "x-forwarded-for";
-  std::string_view value;
-
-  if (getHTTPHeaderValue(req, headerName, value)) {
-    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);
-        }
-      }
-      return ComboAddress(std::string(value));
-    }
-    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);
-    }
-  }
-
-  return std::nullopt;
-}
-
-/*
-  A query has been parsed by h2o, this executes in the main DoH thread.
-  For GET, the base64url-encoded payload is in the 'dns' parameter, which might be the first parameter, or not.
-  For POST, the payload is the payload.
- */
-static int doh_handler(h2o_handler_t *self, h2o_req_t *req)
-{
-  dnsdist::configuration::refreshLocalRuntimeConfiguration();
-
-  try {
-    if (req->conn->ctx->storage.size == 0) {
-      return 0; // although we might was well crash on this
-    }
-    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic): h2o API
-    auto* dsc = static_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
-    auto* connPtr = getConnectionFromQuery(req);
-    if (connPtr == nullptr) {
-      return 0;
-    }
-    auto& conn = *connPtr;
-    if (conn.d_concurrentStreams >= dnsdist::doh::MAX_INCOMING_CONCURRENT_STREAMS) {
-      vinfolog("Too many concurrent streams on connection from %d", conn.d_remote.toStringWithPort());
-      return 0;
-    }
-
-    ++conn.d_nbQueries;
-
-    h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn);
-    if (conn.d_nbQueries == 1) {
-      if (h2o_socket_get_ssl_session_reused(sock) == 0) {
-        ++dsc->clientState->tlsNewSessions;
-      }
-      else {
-        ++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->dohFrontend->d_trustForwardedForHeader) {
-      auto newRemote = processForwardedForHeader(req, remote);
-      if (newRemote) {
-        remote = *newRemote;
-      }
-    }
-
-    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
-      ++dnsdist::metrics::g_stats.aclDrops;
-      vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort());
-      h2o_send_error_403(req, "Forbidden", "DoH query not allowed because of ACL", 0);
-      return 0;
-    }
-
-    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->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);
-        return 0;
-      }
-    }
-
-    // would be nice to be able to use a std::string_view there,
-    // but regex (called by matches() internally) requires a null-terminated string
-    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->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();
-          ++conn.d_concurrentStreams;
-          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")) != 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 */
-      query.reserve(req->entity.len + maxAdditionalSizeForEDNS);
-      query.resize(req->entity.len);
-      memcpy(query.data(), req->entity.base, req->entity.len);
-      doh_dispatch_query(dsc, self, req, std::move(query), conn.d_local, remote, std::move(path));
-    }
-    else if(req->query_at != SIZE_MAX && (req->path.len - req->query_at > 5)) {
-      auto pos = path.find("?dns=");
-      if (pos == string::npos) {
-        pos = path.find("&dns=");
-      }
-      if (pos != string::npos) {
-        // need to base64url decode this
-        string sdns(path.substr(pos+5));
-        std::replace(sdns.begin(), sdns.end(), '-', '+');
-        std::replace(sdns.begin(), sdns.end(), '_', '/');
-        // re-add padding that may have been missing
-        switch (sdns.size() % 4) {
-        case 2:
-          sdns.append(2, '=');
-          break;
-        case 3:
-          sdns.append(1, '=');
-          break;
-        }
-
-        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 + maxAdditionalSizeForEDNS);
-        if(B64Decode(sdns, decoded) < 0) {
-          h2o_send_error_400(req, "Bad Request", "Unable to decode BASE64-URL", 0);
-          ++dsc->dohFrontend->d_badrequests;
-          return 0;
-        }
-
-        ++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->dohFrontend->d_badrequests;
-        return 0;
-      }
-    }
-    else {
-      h2o_send_error_400(req, "Bad Request", "Unable to parse the request", 0);
-      ++dsc->dohFrontend->d_badrequests;
-    }
-    return 0;
-  }
-  catch (const std::exception& e) {
-    vinfolog("DOH Handler function failed with error: '%s'", e.what());
-    return 0;
-  }
-}
-
-const std::unordered_map<std::string, std::string>& DOHUnit::getHTTPHeaders() const
-{
-  if (!headers) {
-    static const HeadersMap empty{};
-    return empty;
-  }
-  return *headers;
-}
-
-std::string DOHUnit::getHTTPPath() const
-{
-  if (query_at == SIZE_MAX) {
-    return path;
-  }
-  return {path, 0, query_at};
-}
-
-const std::string& DOHUnit::getHTTPHost() const
-{
-  return host;
-}
-
-const std::string& DOHUnit::getHTTPScheme() const
-{
-  return scheme;
-}
-
-std::string DOHUnit::getHTTPQueryString() const
-{
-  if (query_at == SIZE_MAX) {
-    return {};
-  }
-  return path.substr(query_at);
-}
-
-void DOHUnit::setHTTPResponse(uint16_t statusCode, PacketBuffer&& body_, const std::string& contentType_)
-{
-  status_code = statusCode;
-  response = std::move(body_);
-  if (!response.empty() && statusCode >= 400) {
-    // we need to make sure it's null-terminated */
-    if (response.at(response.size() - 1) != 0) {
-      response.push_back(0);
-    }
-  }
-
-  contentType = contentType_;
-}
-
-#ifndef USE_SINGLE_ACCEPTOR_THREAD
-/* 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(pdns::channel::Receiver<DOHUnit>&& receiver)
-{
-  setThreadName("dnsdist/doh-cli");
-
-  for(;;) {
-    try {
-      auto tmp = receiver.receive();
-      if (!tmp) {
-        continue;
-      }
-      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 dohUnit->req until we are back into the
-         main DoH thread */
-      if (dohUnit->req == nullptr) {
-        // it got killed in flight already
-        dohUnit->self = nullptr;
-        continue;
-      }
-
-      processDOHQuery(std::move(dohUnit), false);
-    }
-    catch (const std::exception& e) {
-      vinfolog("Error while processing query received over DoH: %s", e.what());
-    }
-    catch (...) {
-      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 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)
-   - processDOHQuery (self-answered queries)
-   */
-static void on_dnsdist(h2o_socket_t *listener, const char *err)
-{
-  (void)err;
-  /* we want to read as many responses from the pipe as possible before
-     giving up. Even if we are overloaded and fighting with the DoH connections
-     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) {
-    DOHUnitUniquePtr dohUnit{nullptr};
-    try {
-      auto tmp = dsc->d_responseReceiver.receive();
-      if (!tmp) {
-        return;
-      }
-      dohUnit = std::move(*tmp);
-    }
-    catch (const std::exception& e) {
-      warnlog("Error reading a DOH internal response: %s", e.what());
-      return;
-    }
-
-    if (dohUnit->req == nullptr) { // it got killed in flight
-      dohUnit->self = nullptr;
-      continue;
-    }
-
-    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 */
-      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(dohUnit), false);
-
-      if (g_tcpclientthreads && g_tcpclientthreads->passCrossProtocolQueryToThread(std::move(cpq))) {
-        continue;
-      }
-      vinfolog("Unable to pass DoH query to a TCP worker thread after getting a TC response over UDP");
-      continue;
-    }
-
-    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 dohUnit->req anymore
-      *dohUnit->self = nullptr; // so we don't clean up again in on_generator_dispose
-      dohUnit->self = nullptr;
-    }
-
-    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)
-{
-  auto* dsc = static_cast<DOHServerConfig*>(listener->data);
-
-  if (err != nullptr) {
-    return;
-  }
-
-  h2o_socket_t* sock = h2o_evloop_socket_accept(listener);
-  if (sock == nullptr) {
-    return;
-  }
-
-  const int descriptor = h2o_socket_get_fd(sock);
-  if (descriptor == -1) {
-    h2o_socket_close(sock);
-    return;
-  }
-
-  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 && !dnsdist::configuration::getCurrentRuntimeConfiguration().d_ACL.match(remote)) {
-    ++dnsdist::metrics::g_stats.aclDrops;
-    vinfolog("Dropping DoH connection from %s because of ACL", remote.toStringWithPort());
-    h2o_socket_close(sock);
-    return;
-  }
-
-  auto connectionResult = dnsdist::IncomingConcurrentTCPConnectionsManager::accountNewTCPConnection(remote, false);
-  if (connectionResult == dnsdist::IncomingConcurrentTCPConnectionsManager::NewConnectionResult::Denied) {
-    h2o_socket_close(sock);
-    return;
-  }
-
-  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->clientState->tcpMaxConcurrentConnections.load()) {
-    dsc->clientState->tcpMaxConcurrentConnections.store(concurrentConnections);
-  }
-
-  auto& conn = t_conns[descriptor];
-
-  gettimeofday(&conn.d_connectionStartTime, nullptr);
-  conn.d_nbQueries = 0;
-  conn.d_acceptCtx = std::atomic_load_explicit(&dsc->accept_ctx, std::memory_order_acquire);
-  conn.d_desc = descriptor;
-  conn.d_remote = remote;
-
-  sock->on_close.cb = on_socketclose;
-  sock->on_close.data = &conn;
-  sock->data = dsc;
-
-  ++dsc->dohFrontend->d_httpconnects;
-
-  h2o_accept(conn.d_acceptCtx->get(), sock);
-}
-
-static int create_listener(std::shared_ptr<DOHServerConfig>& dsc, int descriptor)
-{
-  dsc->h2o_socket = std::unique_ptr<h2o_socket_t, decltype(&h2o_socket_close)>{h2o_evloop_socket_create(dsc->h2o_ctx.loop, descriptor, H2O_SOCKET_FLAG_DONT_READ), &h2o_socket_close};
-  dsc->h2o_socket->data = dsc.get();
-  h2o_socket_read_start(dsc->h2o_socket.get(), on_accept);
-
-  return 0;
-}
-
-#ifndef DISABLE_OCSP_STAPLING
-static int ocsp_stapling_callback(SSL* ssl, void* arg)
-{
-  if (ssl == nullptr || arg == nullptr) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-  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
-// 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
-// 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
-{
-  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(sslContext, *ctx->d_ticketKeys, keyName, ivector, ectx, hctx, enc);
-  if (enc == 0) {
-    if (ret == 0) {
-      ++ctx->d_cs->tlsUnknownTicketKey;
-    }
-    else if (ret == 2) {
-      ++ctx->d_cs->tlsInactiveTicketKey;
-    }
-  }
-
-  return ret;
-}
-
-static void setupTLSContext(DOHAcceptContext& acceptCtx,
-                            TLSConfig& tlsConfig,
-                            TLSErrorCounters& counters)
-{
-  if (tlsConfig.d_ciphers.empty()) {
-    tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS.data();
-  }
-
-  auto [ctx, warnings] = libssl_init_server_context_no_sni(tlsConfig, acceptCtx.d_ocspResponses);
-  for (const auto& warning : warnings) {
-    warnlog("%s", warning);
-  }
-
-  if (tlsConfig.d_enableTickets && tlsConfig.d_numberOfTicketsKeys > 0) {
-    acceptCtx.d_ticketKeys = std::make_unique<OpenSSLTLSTicketKeysRing>(tlsConfig.d_numberOfTicketsKeys);
-#if OPENSSL_VERSION_MAJOR >= 3
-    SSL_CTX_set_tlsext_ticket_key_evp_cb(ctx.get(), &ticket_key_callback);
-#else
-    SSL_CTX_set_tlsext_ticket_key_cb(ctx.get(), &ticket_key_callback);
-#endif
-    libssl_set_ticket_key_callback_data(ctx.get(), &acceptCtx);
-  }
-
-#ifndef DISABLE_OCSP_STAPLING
-  if (!acceptCtx.d_ocspResponses.empty()) {
-    SSL_CTX_set_tlsext_status_cb(ctx.get(), &ocsp_stapling_callback);
-    SSL_CTX_set_tlsext_status_arg(ctx.get(), &acceptCtx.d_ocspResponses);
-  }
-#endif /* DISABLE_OCSP_STAPLING */
-
-  libssl_set_error_counters_callback(*ctx.get(), &counters);
-
-  if (!tlsConfig.d_keyLogFile.empty()) {
-    acceptCtx.d_keyLogFile = libssl_set_key_log_file(ctx.get(), tlsConfig.d_keyLogFile);
-  }
-
-  h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols);
-
-  acceptCtx.d_ticketsKeyRotationDelay = tlsConfig.d_ticketsKeyRotationDelay;
-  if (tlsConfig.d_ticketKeyFile.empty()) {
-    acceptCtx.handleTicketsKeyRotation();
-  }
-  else {
-    acceptCtx.loadTicketsKeys(tlsConfig.d_ticketKeyFile);
-  }
-
-  auto* nativeCtx = acceptCtx.get();
-  nativeCtx->ssl_ctx = ctx.release();
-}
-
-static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool setupTLS)
-{
-  auto* nativeCtx = ctx.get();
-  nativeCtx->ctx = &dsc.h2o_ctx;
-  nativeCtx->hosts = dsc.h2o_config.hosts;
-  auto dohFrontend = std::atomic_load_explicit(&dsc.dohFrontend, std::memory_order_acquire);
-  ctx.d_ticketsKeyRotationDelay = dohFrontend->d_tlsContext->d_tlsConfig.d_ticketsKeyRotationDelay;
-
-  if (setupTLS && dohFrontend->isHTTPS()) {
-    try {
-      setupTLSContext(ctx,
-                      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 '" + 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 *))
-{
-  h2o_pathconf_t *pathconf = h2o_config_register_path(hostconf, path, 0);
-  if (pathconf == nullptr) {
-    return pathconf;
-  }
-  h2o_filter_t *filter = h2o_create_filter(pathconf, sizeof(*filter));
-  if (filter != nullptr) {
-    filter->on_setup_ostream = on_response_ready_cb;
-  }
-
-  h2o_handler_t *handler = h2o_create_handler(pathconf, sizeof(*handler));
-  if (handler != nullptr) {
-    handler->on_req = on_req;
-  }
-
-  return pathconf;
-}
-
-// this is the entrypoint from dnsdist.cc
-void dohThread(ClientState* clientState)
-{
-  try {
-    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, 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(dohFrontend->d_tlsContext->d_addr.toString().c_str(), dohFrontend->d_tlsContext->d_addr.toString().size()), 65535);
-
-    dsc->paths = dohFrontend->d_urls;
-    for (const auto& url : dsc->paths) {
-      register_handler(hostconf, url.c_str(), doh_handler);
-    }
-
-    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 = std::unique_ptr<h2o_socket_t, decltype(&h2o_socket_close)>{h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->d_responseReceiver.getDescriptor(), H2O_SOCKET_FLAG_DONT_READ), &h2o_socket_close};
-    sock->data = dsc.get();
-
-    // this listens to responses from dnsdist to turn into http responses
-    h2o_socket_read_start(sock.get(), on_dnsdist);
-
-    setupAcceptContext(*dsc->accept_ctx, *dsc, false);
-
-    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, 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));
-      }
-    }
-
-    bool stop = false;
-    do {
-      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", stringerror(errno));
-          stop = true;
-        }
-      }
-    }
-    while (!stop);
-
-    h2o_evloop_destroy(dsc->h2o_ctx.loop);
-  }
-  catch (const std::exception& e) {
-    throw runtime_error("DOH thread failed to launch: " + std::string(e.what()));
-  }
-  catch (...) {
-    throw runtime_error("DOH thread failed to launch");
-  }
-}
-
-void DOHUnit::handleUDPResponse(PacketBuffer&& udpResponse, InternalQueryState&& state, [[maybe_unused]] const std::shared_ptr<DownstreamState>& downstream_)
-{
-  auto dohUnit = std::unique_ptr<DOHUnit>(this);
-  dohUnit->ids = std::move(state);
-
-  {
-    dnsheader_aligned dnsHeader(udpResponse.data());
-    if (dnsHeader.get()->tc) {
-      dohUnit->truncated = true;
-    }
-  }
-  if (!dohUnit->truncated) {
-    DNSResponse dnsResponse(dohUnit->ids, udpResponse, dohUnit->downstream);
-    dnsheader cleartextDH{};
-    memcpy(&cleartextDH, dnsResponse.getHeader().get(), sizeof(cleartextDH));
-
-    dnsResponse.ids.du = std::move(dohUnit);
-    if (!processResponse(udpResponse, dnsResponse, false)) {
-      if (dnsResponse.ids.du) {
-        dohUnit = getDUFromIDS(dnsResponse.ids);
-        dohUnit->status_code = 503;
-        sendDoHUnitToTheMainThread(std::move(dohUnit), "Response dropped by rules");
-      }
-      return;
-    }
-
-    if (dnsResponse.isAsynchronous()) {
-      return;
-    }
-
-    dohUnit = getDUFromIDS(dnsResponse.ids);
-    dohUnit->response = std::move(udpResponse);
-    auto udiff = dohUnit->ids.queryRealTime.udiff();
-    vinfolog("Got answer from %s, relayed to %s (https), took %d us", dohUnit->downstream->d_config.remote.toStringWithPort(), dohUnit->ids.origRemote.toStringWithPort(), udiff);
-
-    handleResponseSent(dohUnit->ids, udiff, dnsResponse.ids.origRemote, dohUnit->downstream->d_config.remote, dohUnit->response.size(), cleartextDH, dohUnit->downstream->getProtocol(), true);
-
-    ++dnsdist::metrics::g_stats.responses;
-    if (dohUnit->ids.cs != nullptr) {
-      ++dohUnit->ids.cs->responses;
-    }
-  }
-
-  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);
-  }
-}
-
-void H2ODOHFrontend::loadTicketsKeys(const std::string& keyFile)
-{
-  if (d_dsc && d_dsc->accept_ctx) {
-    d_dsc->accept_ctx->loadTicketsKeys(keyFile);
-  }
-}
-
-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 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/pdns/dnsdistdist/doh.hh b/pdns/dnsdistdist/doh.hh
deleted file mode 100644 (file)
index 04fe358..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-
-#include "config.h"
-
-#ifdef HAVE_DNS_OVER_HTTPS
-#ifdef HAVE_LIBH2OEVLOOP
-
-#include <ctime>
-#include <memory>
-#include <string>
-
-struct CrossProtocolQuery;
-struct DNSQuestion;
-
-std::unique_ptr<CrossProtocolQuery> getDoHCrossProtocolQueryFromDQ(DNSQuestion& dq, bool isResponse);
-
-#include "dnsdist-doh-common.hh"
-
-struct H2ODOHFrontend : public DOHFrontend
-{
-public:
-  void setup() override;
-  void reloadCertificates() override;
-
-  void rotateTicketsKey(time_t now) override;
-  void loadTicketsKeys(const std::string& keyFile) override;
-  void handleTicketsKeyRotation() override;
-  std::string getNextTicketsKeyRotation() const override;
-  size_t getTicketsKeysCount() override;
-};
-
-void dohThread(ClientState* clientState);
-
-#endif /* HAVE_LIBH2OEVLOOP */
-#endif /* HAVE_DNS_OVER_HTTPS  */
index baf9118e67296fc499f925d989e7a6f6f455de58..064154595cec98cf661332b336a8a439056a339c 100644 (file)
@@ -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 or nghttp2) @<:@default=no@:>@]),
+    AS_HELP_STRING([--enable-dns-over-https], [enable incoming DNS over HTTPS (DoH) support (requires nghttp2) @<:@default=no@:>@]),
     [enable_dns_over_https=$enableval],
     [enable_dns_over_https=no]
   )
diff --git a/pdns/dnsdistdist/m4/pdns_check_libh2o_evloop.m4 b/pdns/dnsdistdist/m4/pdns_check_libh2o_evloop.m4
deleted file mode 100644 (file)
index 43c1122..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-AC_DEFUN([PDNS_WITH_LIBH2OEVLOOP], [
-  AC_MSG_CHECKING([whether we will be linking in libh2o-evloop])
-  HAVE_LIBH2OEVLOOP=0
-  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
-    ], [ : ])
-  ])
-  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])
-    ])
-  ])
-])
index faa30ffe3c158c9b50b8d3c8b7f31be34ffe31e2..84c08c7750eaa03fef8d49b05204835d4abd15fa 100644 (file)
@@ -74,7 +74,6 @@ subdir('meson' / 'ipcipher')                # IPCipher (requires libcrypto)
 subdir('meson' / 'cdb')                     # CDB
 subdir('meson' / 'ebpf')                    # eBPF
 subdir('meson' / 'gnutls')                  # GNUTLS
-subdir('meson' / 'h2o')                     # H2O
 subdir('meson' / 'lmdb')                    # LMDB
 subdir('meson' / 'nghttp2')                 # NGHTTP2
 subdir('meson' / 'quiche')                  # Quiche
@@ -225,12 +224,6 @@ conditional_sources = {
     ],
     'condition': dep_cdb.found(),
   },
-  'doh': {
-    'sources': [
-      src_dir / 'doh.cc',
-    ],
-    'condition': dep_libh2o_evloop.found(),
-   },
   'doq': {
     'sources': [
       src_dir / 'doq.cc',
@@ -391,7 +384,6 @@ deps = [
   dep_libcrypto,
   dep_gnutls,
   dep_libedit,
-  dep_libh2o_evloop,
   dep_json11,
   dep_libnghttp2,
   dep_libquiche,
index 8c8aec50f1d880b08faae2160509641f53232248..54b1433d7e67a441b7add7bcdd8d60fa8916e67e 100644 (file)
@@ -4,10 +4,10 @@ if opt_doh2.enabled()
   if not dep_libssl.found() and not dep_gnutls.found()
     error('DNS over HTTP/2 support was requested but neither OpenSSL libssl nor GnuTLS support is enabled')
   endif
-  if not dep_libnghttp2.found() and not dep_libh2o_evloop.found()
-    error('DNS over HTTP/2 support was requested but neither nghttp2 not libh2o-evloop support is enabled')
+  if not dep_libnghttp2.found()
+    error('DNS over HTTP/2 support was requested but nghttp2 support is enabled')
   endif
 endif
 
-conf.set('HAVE_DNS_OVER_HTTPS', opt_doh2.allowed() and (dep_libssl.found() or dep_gnutls.found()) and (dep_libnghttp2.found() or dep_libh2o_evloop.found()), description: 'DNS over HTTP/2 (DoH)')
-summary('DNS over HTTP/2', opt_doh2.allowed() and (dep_libssl.found() or dep_gnutls.found()) and (dep_libnghttp2.found() or dep_libh2o_evloop.found()), bool_yn: true, section: 'Configuration')
+conf.set('HAVE_DNS_OVER_HTTPS', opt_doh2.allowed() and (dep_libssl.found() or dep_gnutls.found()) and (dep_libnghttp2.found()), description: 'DNS over HTTP/2 (DoH)')
+summary('DNS over HTTP/2', opt_doh2.allowed() and (dep_libssl.found() or dep_gnutls.found()) and (dep_libnghttp2.found()), bool_yn: true, section: 'Configuration')
diff --git a/pdns/dnsdistdist/meson/h2o/meson.build b/pdns/dnsdistdist/meson/h2o/meson.build
deleted file mode 100644 (file)
index 4c758f0..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-opt_h2o = get_option('h2o')
-dep_libh2o_evloop = dependency('libh2o-evloop', required: opt_h2o)
-
-if dep_libh2o_evloop.found()
-  funcs = [
-    'h2o_socket_get_ssl_server_name',
-  ]
-
-  foreach func: funcs
-    has = cxx.has_function(func, dependencies: dep_libh2o_evloop)
-    conf.set('HAVE_' + func.to_upper(), has, description: 'Have h2o ' + func)
-  endforeach
-endif
-
-conf.set('HAVE_LIBH2OEVLOOP', dep_libh2o_evloop.found(), description: 'H2O library with event loop support for DNS over HTTP/2')
-summary('H2O library with event loop support for DNS over HTTP/2', dep_libh2o_evloop.found(), bool_yn: true, section: 'DNS over HTTP/2')
index e66d1d4091f1ed2cbf09e0f7db4d6fe0bc79e707..2dab4f385fcb2bff28e54ae6a3fad23c322d3226 100644 (file)
@@ -28,7 +28,6 @@ option('systemd-service-group', type: 'string', value: 'dnsdist', description: '
 option('auto-var-init', type: 'combo', value: 'disabled', choices: ['zero', 'pattern', 'disabled'], description: 'Enable initialization of automatic variables')
 option('snmp', type: 'feature', value: 'disabled', description: 'Enable SNMP')
 option('dnstap', type: 'feature', value: 'auto', description: 'Enable DNSTAP support through libfstrm')
-option('h2o', type: 'feature', value: 'disabled', description: 'Enable H2O library with event loop support for DNS over HTTP/2')
 option('nghttp2', type: 'feature', value: 'auto', description: 'Enable nghttp2 library support for DNS over HTTP/2')
 option('cdb', type: 'feature', value: 'auto', description: 'CDB key-value store support')
 option('lmdb', type: 'feature', value: 'auto', description: 'LMDB key-value store support')
index 9cf6662f50a1f36263e1a8645627cf38dafe8020..a00368c5f5628d82f3c1a6e7f0b8deb70f50e5d9 100644 (file)
@@ -1148,9 +1148,6 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     def sendDOHWithNGHTTP2QueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
         return self.sendDOHQuery(self._dohWithNGHTTP2ServerPort, self._serverName if not serverName else serverName, self._dohWithNGHTTP2BaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, timeout=timeout)
 
-    def sendDOHWithH2OQueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
-        return self.sendDOHQuery(self._dohWithH2OServerPort, self._serverName if not serverName else serverName, self._dohWithH2OBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, timeout=timeout)
-
     def sendDOTQueryWrapper(self, query, response, useQueue=True, timeout=2, serverName=None):
         return self.sendDOTQuery(self._tlsServerPort, self._serverName if not serverName else serverName, query, response, self._caCert, useQueue=useQueue, timeout=timeout)
 
index 6bea2cb7d4e1f7c59fc70dc38134063acb3e3c19..96292f249cd5e435a93cf2a99dd057bdf076adfd 100644 (file)
@@ -101,9 +101,7 @@ class AsyncTests(object):
     _caCert = "ca.pem"
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithH2OServerPort = pickAvailablePort()
     _dohWithNGHTTP2BaseURL = "https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort)
-    _dohWithH2OBaseURL = "https://%s:%d/" % (_serverName, _dohWithH2OServerPort)
     _doqServerPort = pickAvailablePort()
 
     def testPass(self):
@@ -127,7 +125,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -157,15 +154,10 @@ class AsyncTests(object):
             "sendTCPQuery",
             "sendDOTQueryWrapper",
             "sendDOHWithNGHTTP2QueryWrapper",
-            "sendDOHWithH2OQueryWrapper",
             "sendDOQQueryWrapper",
         ):
             sender = getattr(self, method)
-            if (
-                method != "sendDOTQueryWrapper"
-                and method != "sendDOHWithH2OQueryWrapper"
-                and method != "sendDOQQueryWrapper"
-            ):
+            if method != "sendDOTQueryWrapper" and method != "sendDOQQueryWrapper":
                 # first time to fill the cache
                 # disabled for DoT since it was already filled via TCP
                 (receivedQuery, receivedResponse) = sender(query, response)
@@ -202,7 +194,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -235,7 +226,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -272,7 +262,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -311,7 +300,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -344,7 +332,6 @@ class AsyncTests(object):
                 "sendTCPQuery",
                 "sendDOTQueryWrapper",
                 "sendDOHWithNGHTTP2QueryWrapper",
-                "sendDOHWithH2OQueryWrapper",
                 "sendDOQQueryWrapper",
             ):
                 sender = getattr(self, method)
@@ -377,7 +364,6 @@ class AsyncTests(object):
             "sendTCPQuery",
             "sendDOTQueryWrapper",
             "sendDOHWithNGHTTP2QueryWrapper",
-            "sendDOHWithH2OQueryWrapper",
             "sendDOQQueryWrapper",
         ):
             sender = getattr(self, method)
@@ -400,7 +386,6 @@ class AsyncTests(object):
             "sendTCPQuery",
             "sendDOTQueryWrapper",
             "sendDOHWithNGHTTP2QueryWrapper",
-            "sendDOHWithH2OQueryWrapper",
             "sendDOQQueryWrapper",
         ):
             sender = getattr(self, method)
@@ -426,7 +411,6 @@ class AsyncTests(object):
             "sendTCPQuery",
             "sendDOTQueryWrapper",
             "sendDOHWithNGHTTP2QueryWrapper",
-            "sendDOHWithH2OQueryWrapper",
             "sendDOQQueryWrapper",
         ):
             sender = getattr(self, method)
@@ -444,7 +428,7 @@ class AsyncTests(object):
         # the query is first forwarded over UDP, leading to a TC=1 answer from the
         # backend, then over TCP
 
-        for method in ("sendDOHWithNGHTTP2QueryWrapper", "sendDOHWithH2OQueryWrapper"):
+        for method in ["sendDOHWithNGHTTP2QueryWrapper"]:
             sender = getattr(self, method)
             name = "timeout-then-accept." + method + ".tc.async.tests.powerdns.com."
             query = dns.message.make_query(name, "A", "IN")
@@ -490,7 +474,6 @@ class TestAsyncFFI(DNSDistTest, AsyncTests):
     newServer{address="127.0.0.1:%d", pool="tcp-only", tcpOnly=true }
 
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library="h2o"})
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library="nghttp2"})
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
 
@@ -620,9 +603,6 @@ class TestAsyncFFI(DNSDistTest, AsyncTests):
         "_tlsServerPort",
         "_serverCert",
         "_serverKey",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
         "_dohWithNGHTTP2ServerPort",
         "_serverCert",
         "_serverKey",
@@ -642,7 +622,6 @@ class TestAsyncLua(DNSDistTest, AsyncTests):
     newServer{address="127.0.0.1:%d", pool="tcp-only", tcpOnly=true }
 
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library="h2o"})
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library="nghttp2"})
     addDOQLocal("127.0.0.1:%d", "%s", "%s")
 
@@ -753,9 +732,6 @@ class TestAsyncLua(DNSDistTest, AsyncTests):
         "_tlsServerPort",
         "_serverCert",
         "_serverKey",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
         "_dohWithNGHTTP2ServerPort",
         "_serverCert",
         "_serverKey",
index da02f0360504d6a21d2753671640a9a7100cdacf..be16466bfaf6978827675856002ccaa1e67df27e 100644 (file)
@@ -263,8 +263,6 @@ class DOHTests(object):
         """
         DOH: qdcount == 0
         """
-        if self._dohLibrary == 'h2o':
-            raise unittest.SkipTest('h2o tries to parse the qname early, so this check will fail')
         query = dns.message.Message()
         query.id = 0
         query.flags &= ~dns.flags.RD
@@ -349,8 +347,6 @@ class DOHTests(object):
         """
         DOH: Invalid method
         """
-        if self._dohLibrary == 'h2o':
-            raise unittest.SkipTest('h2o does not check the HTTP method')
         name = 'invalid-method.doh.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
         wire = query.to_wire()
@@ -397,8 +393,6 @@ class DOHTests(object):
         """
         DOH: HTTP/1.1
         """
-        if self._dohLibrary == 'h2o':
-            raise unittest.SkipTest('h2o supports HTTP/1.1, this test is only relevant for nghttp2')
         httpConnections = self.getHTTPCounter('connects')
         http1 = self.getHTTPCounter('http/1.1')
         http2 = self.getHTTPCounter('http/2')
@@ -440,8 +434,6 @@ class DOHTests(object):
         """
         DOH: Check that HTTP/1.1 is not selected over H2 when offered in the wrong order by the client
         """
-        if self._dohLibrary == 'h2o':
-            raise unittest.SkipTest('h2o supports HTTP/1.1, this test is only relevant for nghttp2')
         alpn = ['http/1.1', 'h2']
         conn = self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn)
         if not hasattr(conn, 'selected_alpn_protocol'):
@@ -510,8 +502,6 @@ class DOHTests(object):
         """
         DOH: No backend
         """
-        if self._dohLibrary == 'h2o':
-            raise unittest.SkipTest('h2o does not check the HTTP method')
         name = 'no-backend.doh.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
         wire = query.to_wire()
@@ -789,9 +779,6 @@ class DOHTests(object):
 class TestDoHNGHTTP2(DOHTests, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDoHH2O(DOHTests, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class TestDoHNGHTTP2Yaml(DOHTests, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
     _yaml_config_template = """---
@@ -995,9 +982,6 @@ class DOHSubPathsTests(object):
 class TestDoHSubPathsNGHTTP2(DOHSubPathsTests, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDoHSubPathsH2O(DOHSubPathsTests, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHAddingECSTests(object):
 
     _serverKey = 'server.key'
@@ -1097,9 +1081,6 @@ class DOHAddingECSTests(object):
 class TestDoHAddingECSNGHTTP2(DOHAddingECSTests, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDoHAddingECSH2O(DOHAddingECSTests, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHOverHTTP(object):
     _dohServerPort = pickAvailablePort()
     _serverName = 'tls.tests.dnsdist.org'
@@ -1167,12 +1148,6 @@ class TestDOHOverHTTPNGHTTP2(DOHOverHTTP, DNSDistDOHTest):
 Configuration 'configs/dnsdist_TestDOHOverHTTPNGHTTP2.conf' OK!
 """ % (DOHOverHTTP._dohServerPort)
 
-class TestDOHOverHTTPH2O(DOHOverHTTP, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-    _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:%d, running in DNS over HTTP mode instead of DNS over HTTPS
-Configuration 'configs/dnsdist_TestDOHOverHTTPH2O.conf' OK!
-""" % (DOHOverHTTP._dohServerPort)
-
 class DOHWithCache(object):
 
     _serverKey = 'server.key'
@@ -1386,9 +1361,6 @@ class TestDOHWithCacheNGHTTP2(DOHWithCache, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
     _verboseMode = True
 
-class TestDOHWithCacheH2O(DOHWithCache, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHWithoutCacheControl(object):
 
     _serverKey = 'server.key'
@@ -1433,9 +1405,6 @@ class DOHWithoutCacheControl(object):
 class TestDOHWithoutCacheControlNGHTTP2(DOHWithoutCacheControl, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHWithoutCacheControlH2O(DOHWithoutCacheControl, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHFFI(object):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
@@ -1500,9 +1469,6 @@ class DOHFFI(object):
 class TestDOHFFINGHTTP2(DOHFFI, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHFFIH2O(DOHFFI, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHForwardedFor(object):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
@@ -1571,9 +1537,6 @@ class DOHForwardedFor(object):
 class TestDOHForwardedForNGHTTP2(DOHForwardedFor, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHForwardedForH2O(DOHForwardedFor, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHForwardedForNoTrusted(object):
 
     _serverKey = 'server.key'
@@ -1620,9 +1583,6 @@ class DOHForwardedForNoTrusted(object):
 class TestDOHForwardedForNoTrustedNGHTTP2(DOHForwardedForNoTrusted, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHForwardedForNoTrustedH2O(DOHForwardedForNoTrusted, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHFrontendLimits(object):
 
     # this test suite uses a different responder port
@@ -1655,9 +1615,7 @@ class DOHFrontendLimits(object):
 
         for idx in range(self._maxTCPConnsPerDOHFrontend + 1):
             try:
-                alpn = []
-                if self._dohLibrary != 'h2o':
-                    alpn.append('h2')
+                alpn = ['h2']
                 conns.append(self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn))
             except Exception:
                 conns.append(None)
@@ -1694,9 +1652,6 @@ class DOHFrontendLimits(object):
 class TestDOHFrontendLimitsNGHTTP2(DOHFrontendLimits, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHFrontendLimitsH2O(DOHFrontendLimits, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class Protocols(object):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
@@ -1741,9 +1696,6 @@ class Protocols(object):
 class TestProtocolsNGHTTP2(Protocols, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestProtocolsH2O(Protocols, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHWithPKCS12Cert(object):
     _serverCert = 'server.p12'
     _pkcs12Password = 'passw0rd'
@@ -1784,9 +1736,6 @@ class DOHWithPKCS12Cert(object):
 class TestDOHWithPKCS12CertNGHTTP2(DOHWithPKCS12Cert, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHWithPKCS12CertH2O(DOHWithPKCS12Cert, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHForwardedToTCPOnly(object):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
@@ -1825,9 +1774,6 @@ class DOHForwardedToTCPOnly(object):
 class TestDOHForwardedToTCPOnlyNGHTTP2(DOHForwardedToTCPOnly, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHForwardedToTCPOnlyH2O(DOHForwardedToTCPOnly, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHLimits(object):
     _serverName = 'tls.tests.dnsdist.org'
     _caCert = 'ca.pem'
@@ -1885,9 +1831,6 @@ class DOHLimits(object):
 class TestDOHLimitsNGHTTP2(DOHLimits, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHLimitsH2O(DOHLimits, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
-
 class DOHXFR(object):
     _serverName = 'tls.tests.dnsdist.org'
     _caCert = 'ca.pem'
@@ -1920,5 +1863,3 @@ class DOHXFR(object):
 class TestDOHXFRNGHTTP2(DOHXFR, DNSDistDOHTest):
     _dohLibrary = 'nghttp2'
 
-class TestDOHXFRH2O(DOHXFR, DNSDistDOHTest):
-    _dohLibrary = 'h2o'
index 99a9d6b0f91bd6810c8ed5d39682258f8ec90d2d..39474ed29401dd5772f89af11feb3173829466c4 100644 (file)
@@ -73,7 +73,6 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
     _caCert = "ca.pem"
     _caKey = "ca.key"
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithH2OServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     setKey("%s")
@@ -82,7 +81,6 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
     -- generate an OCSP response file for our certificate, valid one day
     generateOCSPResponse('%s', '%s', '%s', '%s', 1, 0)
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { ocspResponses={"%s"}, library='nghttp2'})
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { ocspResponses={"%s"}, library='h2o'})
     """
     _config_params = [
         "_testServerPort",
@@ -96,10 +94,6 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
         "_serverCert",
         "_serverKey",
         "_ocspFile",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
-        "_ocspFile",
     ]
 
     @classmethod
@@ -120,7 +114,7 @@ class TestOCSPStaplingDOH(DNSDistOCSPStaplingTest):
         """
         OCSP Stapling: DOH
         """
-        for port in [self._dohWithNGHTTP2ServerPort, self._dohWithH2OServerPort]:
+        for port in [self._dohWithNGHTTP2ServerPort]:
             output = self.checkOCSPStaplingStatus(
                 "127.0.0.1", port, self._serverName, self._caCert
             )
@@ -156,14 +150,12 @@ class TestBrokenOCSPStaplingDoH(DNSDistOCSPStaplingTest):
     # invalid OCSP file!
     _ocspFile = "/dev/null"
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithH2OServerPort = pickAvailablePort()
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     setKey("%s")
     controlSocket("127.0.0.1:%d")
 
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { ocspResponses={"%s"}, library='nghttp2'})
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { ocspResponses={"%s"}, library='h2o'})
 
     """
     _config_params = [
@@ -174,17 +166,13 @@ class TestBrokenOCSPStaplingDoH(DNSDistOCSPStaplingTest):
         "_serverCert",
         "_serverKey",
         "_ocspFile",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
-        "_ocspFile",
     ]
 
     def testBrokenOCSPStapling(self):
         """
         OCSP Stapling: Broken (DoH)
         """
-        for port in [self._dohWithNGHTTP2ServerPort, self._dohWithH2OServerPort]:
+        for port in [self._dohWithNGHTTP2ServerPort]:
             output = self.checkOCSPStaplingStatus(
                 "127.0.0.1", port, self._serverName, self._caCert
             )
index e158cc7a7a1b593ce47813e23407de46e6c5e1cb..06d0e8634413b9b7d46f248879527bc6b5e22ed4 100644 (file)
@@ -692,21 +692,18 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
     _tlsServerPort = pickAvailablePort()
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
     _dohWithNGHTTP2BaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort))
-    _dohWithH2OServerPort = pickAvailablePort()
-    _dohWithH2OBaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithH2OServerPort))
     _config_template = """
     newServer{address="127.0.0.1:%d"}
     rl = newRemoteLogger('127.0.0.1:%d')
 
     addTLSLocal("127.0.0.1:%d", "%s", "%s", { provider="openssl" })
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { '/dns-query' }, { keepIncomingHeaders=true, library='nghttp2' })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { '/dns-query' }, { keepIncomingHeaders=true, library='h2o' })
 
     local mytags = {path='doh-path', host='doh-host', ['query-string']='doh-query-string', scheme='doh-scheme', agent='doh-header:user-agent'}
     addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1'}, mytags))
     addResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, false, {serverID='dnsdist-server-1'}, mytags))
     """
-    _config_params = ['_testServerPort', '_protobufServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_dohWithH2OServerPort', '_serverCert', '_serverKey']
+    _config_params = ['_testServerPort', '_protobufServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey']
 
     def testProtobufMetaDoH(self):
         """
@@ -722,7 +719,7 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                                     '127.0.0.1')
         response.answer.append(rrset)
 
-        for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper", "sendDOHWithH2OQueryWrapper"):
+        for method in ("sendUDPQuery", "sendTCPQuery", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"):
             sender = getattr(self, method)
             (receivedQuery, receivedResponse) = sender(query, response)
 
@@ -745,7 +742,7 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                 pbMessageType = dnsmessage_pb2.PBDNSMessage.TCP
             elif method == "sendDOTQueryWrapper":
                 pbMessageType = dnsmessage_pb2.PBDNSMessage.DOT
-            elif method == "sendDOHWithNGHTTP2QueryWrapper" or method == "sendDOHWithH2OQueryWrapper":
+            elif method == "sendDOHWithNGHTTP2QueryWrapper":
                 pbMessageType = dnsmessage_pb2.PBDNSMessage.DOH
 
             self.checkProtobufQuery(msg, pbMessageType, query, dns.rdataclass.IN, dns.rdatatype.A, name)
@@ -756,13 +753,11 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                 tags[entry.key] = entry.value.stringVal[0]
 
             self.assertIn('agent', tags)
-            if method == "sendDOHWithNGHTTP2QueryWrapper" or method == "sendDOHWithH2OQueryWrapper":
+            if method == "sendDOHWithNGHTTP2QueryWrapper":
                 self.assertIn('PycURL', tags['agent'])
                 self.assertIn('host', tags)
                 if method == "sendDOHWithNGHTTP2QueryWrapper":
                     self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithNGHTTP2ServerPort))
-                elif method == "sendDOHWithH2OQueryWrapper":
-                    self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithH2OServerPort))
                 self.assertIn('path', tags)
                 self.assertEqual(tags['path'], '/dns-query')
                 self.assertIn('query-string', tags)
@@ -781,13 +776,11 @@ class TestProtobufMetaDOH(DNSDistProtobufTest):
                 tags[entry.key] = entry.value.stringVal[0]
 
             self.assertIn('agent', tags)
-            if method == "sendDOHWithNGHTTP2QueryWrapper" or method == "sendDOHWithH2OQueryWrapper":
+            if method == "sendDOHWithNGHTTP2QueryWrapper":
                 self.assertIn('PycURL', tags['agent'])
                 self.assertIn('host', tags)
                 if method == "sendDOHWithNGHTTP2QueryWrapper":
                     self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithNGHTTP2ServerPort))
-                elif method == "sendDOHWithH2OQueryWrapper":
-                    self.assertEqual(tags['host'], self._serverName + ':' + str(self._dohWithH2OServerPort))
                 self.assertIn('path', tags)
                 self.assertEqual(tags['path'], '/dns-query')
                 self.assertIn('query-string', tags)
index 578e1dccdbe168cb8beff14d45803ae367d9cdee..2dd9cf3580255113f14b5e53b497e1e85e193a72 100644 (file)
@@ -1220,16 +1220,13 @@ class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
     _caCert = 'ca.pem'
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
     _dohWithNGHTTP2BaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithNGHTTP2ServerPort))
-    _dohWithH2OServerPort = pickAvailablePort()
-    _dohWithH2OBaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohWithH2OServerPort))
     _proxyResponderPort = proxyResponderPort
     _config_template = """
     newServer{address="127.0.0.1:%d", useProxyProtocol=true}
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { '/dns-query' }, { trustForwardedForHeader=true, library='nghttp2' })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { '/dns-query' }, { trustForwardedForHeader=true, library='h2o' })
     setACL( { "::1/128", "127.0.0.0/8" } )
     """
-    _config_params = ['_proxyResponderPort', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_dohWithH2OServerPort', '_serverCert', '_serverKey']
+    _config_params = ['_proxyResponderPort', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey']
 
     def testTruncation(self):
         """
@@ -1250,7 +1247,7 @@ class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
                                     '127.0.0.1')
         response.answer.append(rrset)
 
-        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL), (self._dohWithH2OServerPort, self._dohWithH2OBaseURL)]:
+        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
           # first response is a TC=1
           tcResponse = dns.message.make_response(query)
           tcResponse.flags |= dns.flags.TC
@@ -1302,7 +1299,7 @@ class TestDOHWithOutgoingProxyProtocol(DNSDistDOHTest):
                                     '127.0.0.1')
         response.answer.append(rrset)
 
-        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL), (self._dohWithH2OServerPort, self._dohWithH2OBaseURL)]:
+        for (port,url) in [(self._dohWithNGHTTP2ServerPort, self._dohWithNGHTTP2BaseURL)]:
           # the query should be dropped
           (receivedQuery, receivedResponse) = self.sendDOHQuery(port, self._serverName, url, query, caFile=self._caCert, customHeaders=['x-forwarded-for: [::1]:8080'], useQueue=False)
           self.assertFalse(receivedQuery)
index db8ceecdc4b387ebd2b1caa31b76f04309f37d52..4c25018b94291fe18228ea3a110660fe57a6557e 100644 (file)
@@ -105,13 +105,11 @@ class TestNoTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
     _serverName = "tls.tests.dnsdist.org"
     _caCert = "ca.pem"
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithH2OServerPort = pickAvailablePort()
     _numberOfKeys = 0
     _config_template = """
     newServer{address="127.0.0.1:%d"}
 
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d, numberOfStoredSessions=0, sessionTickets=false, library='nghttp2' })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d, numberOfStoredSessions=0, sessionTickets=false, library='h2o' })
     """
     _config_params = [
         "_testServerPort",
@@ -119,17 +117,13 @@ class TestNoTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
         "_serverCert",
         "_serverKey",
         "_numberOfKeys",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
-        "_numberOfKeys",
     ]
 
     def testNoSessionResumption(self):
         """
         Session Resumption: DoH (disabled)
         """
-        for port in [self._dohWithNGHTTP2ServerPort, self._dohWithH2OServerPort]:
+        for port in [self._dohWithNGHTTP2ServerPort]:
             self.assertFalse(
                 self.checkSessionResumed(
                     "127.0.0.1",
@@ -162,7 +156,6 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
     _serverName = "tls.tests.dnsdist.org"
     _caCert = "ca.pem"
     _dohWithNGHTTP2ServerPort = pickAvailablePort()
-    _dohWithH2OServerPort = pickAvailablePort()
     _numberOfKeys = 5
     _config_template = """
     setKey("%s")
@@ -170,7 +163,6 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
     newServer{address="127.0.0.1:%d"}
 
     addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d, library='nghttp2' })
-    addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d, library='h2o' })
     """
     _config_params = [
         "_consoleKeyB64",
@@ -180,10 +172,6 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
         "_serverCert",
         "_serverKey",
         "_numberOfKeys",
-        "_dohWithH2OServerPort",
-        "_serverCert",
-        "_serverKey",
-        "_numberOfKeys",
     ]
 
     def testSessionResumption(self):
@@ -192,7 +180,6 @@ class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest):
         """
         for port, bindIdx in [
             (self._dohWithNGHTTP2ServerPort, 0),
-            (self._dohWithH2OServerPort, 1),
         ]:
             self.assertFalse(
                 self.checkSessionResumed(
index 8564b5e2f9e65694ecdcf3f67fff90dacbceb101..a267dda594b60e6e99e2b8d22ff251e361336c91 100644 (file)
--- a/tasks.py
+++ b/tasks.py
@@ -340,7 +340,6 @@ def install_dnsdist_test_deps(c, skipXDP=False): # FIXME: rename this, we do way
                libxdp1'
 
     c.sudo(f'apt-get install -y {deps}')
-    ci_install_libh2o(c)
     c.run('sed "s/agentxperms 0700 0755 dnsdist/agentxperms 0777 0755/g" regression-tests.dnsdist/snmpd.conf | sudo tee /etc/snmp/snmpd.conf')
     c.sudo('/etc/init.d/snmpd restart')
     time.sleep(5)
@@ -353,7 +352,6 @@ def install_rec_build_deps(c):
 @task(optional=['skipXDP'])
 def install_dnsdist_build_deps(c, skipXDP=False):
     c.sudo('apt-get install -y --no-install-recommends ' +  ' '.join(all_build_deps + git_build_deps + dnsdist_build_deps + (dnsdist_xdp_build_deps if not skipXDP else [])))
-    ci_install_libh2o(c)
 
 @task
 def ci_autoconf(c, meson=False):
@@ -762,7 +760,6 @@ def ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_fla
                       --enable-yaml \
                       --prefix=/opt/dnsdist \
                       --with-gnutls \
-                      --with-h2o \
                       --with-libsodium \
                       --with-lua=luajit \
                       --with-libcap \
@@ -777,7 +774,6 @@ def ci_dnsdist_configure_autotools(features, additional_flags, additional_ld_fla
                       --without-cdb \
                       --without-ebpf \
                       --without-gnutls \
-                      --without-h2o \
                       --without-libedit \
                       --without-libsodium \
                       --without-lmdb \
@@ -804,7 +800,6 @@ def ci_dnsdist_configure_meson(c, features, additional_flags, additional_ld_flag
                       -D dnscrypt=enabled \
                       -D dnstap=enabled \
                       -D ebpf=enabled \
-                      -D h2o=enabled \
                       -D ipcipher=enabled \
                       -D ipcrypt2=enabled \
                       -D libedit=enabled \
@@ -826,7 +821,6 @@ def ci_dnsdist_configure_meson(c, features, additional_flags, additional_ld_flag
                       -D dnscrypt=disabled \
                       -D dnstap=disabled \
                       -D ebpf=disabled \
-                      -D h2o=disabled \
                       -D ipcipher=disabled \
                       -D ipcrypt2=disabled \
                       -D libedit=disabled \
@@ -1276,23 +1270,6 @@ def coverity_upload(c, email, project, tarball):
             --form description="master build" \
             https://scan.coverity.com/builds?project={project}', hide=True)
 
-def build_and_install_libh2o(c):
-    with c.cd(f'{repo_home}/builder-support/helpers/'):
-        c.run('sudo sh install_h2o.sh')
-
-    c.run("sudo mkdir -p /usr/lib/pkgconfig")
-    c.run("sudo cp /opt/lib/pkgconfig/libh2o-evloop.pc /usr/lib/pkgconfig/libh2o-evloop.pc")
-
-@task
-def ci_install_libh2o(c):
-    libh2o_package_name = "libh2o-evloop-dev" # also installs libh2o-evloop0.13 on Debian 11 & 12
-    res = c.run(f'apt-cache policy {libh2o_package_name} | grep -qq Candidate && echo "True" || echo ""')
-
-    if bool(res.stdout.strip()):
-        c.run(f'sudo apt-get install -y {libh2o_package_name}')
-    else:
-        build_and_install_libh2o(c)
-
 @task
 def ci_build_and_install_quiche(c, repo):
     with c.cd(f'{repo}/builder-support/helpers/'):