From: Remi Gacogne Date: Wed, 25 Aug 2021 08:49:13 +0000 (+0200) Subject: dnsdist: Proper detection of nghttp2 support X-Git-Tag: dnsdist-1.7.0-alpha1~23^2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e069889b15693c28164bd5bbe3873a1ebd1b816;p=thirdparty%2Fpdns.git dnsdist: Proper detection of nghttp2 support --- diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index c63486621d..5ea08281c6 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -531,10 +531,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) ret->d_tlsCtx = getTLSContext(tlsParams); if (vars.count("dohPath")) { +#ifdef HAVE_NGHTTP2 ret->d_dohPath = boost::get(vars.at("dohPath")); if (ret->d_tlsCtx) { setupDoHClientProtocolNegotiation(ret->d_tlsCtx); } +#else /* HAVE_NGHTTP2 */ + throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but nghttp2 support is not available"); +#endif /* HAVE_NGHTTP2 */ } else { setupDoTProtocolNegotiation(ret->d_tlsCtx); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 00fa3f2286..57d5322b04 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -2320,6 +2320,9 @@ int main(int argc, char** argv) #endif #ifdef HAVE_LMDB cout<<"lmdb "; +#endif +#ifdef HAVE_NGHTTP2 + cout<<"outgoing-dns-over-https(nghttp2) "; #endif cout<<"protobuf "; #ifdef HAVE_RE2 diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index 03ae3e1110..3e62c1ff18 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS += $(SYSTEMD_CFLAGS) \ $(FSTRM_CFLAGS) \ $(YAHTTP_CFLAGS) \ $(NET_SNMP_CFLAGS) \ + $(NGHTTP2_CFLAGS) \ $(LIBCAP_CFLAGS) \ -I$(top_srcdir)/ext/protozero/include \ -DSYSCONFDIR=\"${sysconfdir}\" \ @@ -303,7 +304,6 @@ testrunner_SOURCES = \ dnsdist_LDFLAGS = \ $(AM_LDFLAGS) \ $(PROGRAM_LDFLAGS) \ - -lnghttp2 \ -pthread dnsdist_LDADD = \ @@ -322,7 +322,6 @@ testrunner_LDFLAGS = \ $(AM_LDFLAGS) \ $(PROGRAM_LDFLAGS) \ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) \ - -lnghttp2 \ -pthread testrunner_LDADD = \ @@ -374,6 +373,11 @@ endif endif +if HAVE_NGHTTP2 +dnsdist_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS) +testrunner_LDADD += $(NGHTTP2_LDFLAGS) $(NGHTTP2_LIBS) +endif + if !HAVE_LUA_HPP BUILT_SOURCES += lua.hpp nodist_dnsdist_SOURCES = lua.hpp diff --git a/pdns/dnsdistdist/configure.ac b/pdns/dnsdistdist/configure.ac index 02ac66043d..774ace1c45 100644 --- a/pdns/dnsdistdist/configure.ac +++ b/pdns/dnsdistdist/configure.ac @@ -96,6 +96,8 @@ AS_IF([test "x$enable_dns_over_https" != "xno"], [ ]) ]) +PDNS_WITH_NGHTTP2 + PDNS_CHECK_CDB PDNS_CHECK_LMDB @@ -224,6 +226,10 @@ AS_IF([test "x$enable_dns_over_tls" != "xno" -o "x$enable_dns_over_https" != "xn [AC_MSG_NOTICE([OpenSSL: no])] )] ) +AS_IF([test "x$NGHTTP2_LIBS" != "x"], + [AC_MSG_NOTICE([nghttp2: yes])], + [AC_MSG_NOTICE([nghttp2: no])] +) AS_IF([test "x$CDB_LIBS" != "x"], [AC_MSG_NOTICE([cdb: yes])], [AC_MSG_NOTICE([cdb: no])] diff --git a/pdns/dnsdistdist/dnsdist-nghttp2.cc b/pdns/dnsdistdist/dnsdist-nghttp2.cc index 0aea4d7170..bf6449a276 100644 --- a/pdns/dnsdistdist/dnsdist-nghttp2.cc +++ b/pdns/dnsdistdist/dnsdist-nghttp2.cc @@ -20,7 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" + +#ifdef HAVE_NGHTTP2 #include +#endif /* HAVE_NGHTTP2 */ #include "dnsdist-nghttp2.hh" #include "dnsdist-tcp.hh" @@ -37,6 +41,7 @@ std::atomic g_dohStatesDumpRequested{0}; std::unique_ptr g_dohClientThreads{nullptr}; +#ifdef HAVE_NGHTTP2 class DoHConnectionToBackend: public TCPConnectionToBackend { public: @@ -657,69 +662,6 @@ DoHConnectionToBackend::DoHConnectionToBackend(std::shared_ptr } } -struct DoHClientCollection::DoHWorkerThread -{ - DoHWorkerThread() - { - } - - DoHWorkerThread(int crossProtocolPipe): d_crossProtocolQueryPipe(crossProtocolPipe) - { - } - - DoHWorkerThread(DoHWorkerThread&& rhs): d_crossProtocolQueryPipe(rhs.d_crossProtocolQueryPipe) - { - rhs.d_crossProtocolQueryPipe = -1; - } - - DoHWorkerThread& operator=(DoHWorkerThread&& rhs) - { - if (d_crossProtocolQueryPipe != -1) { - close(d_crossProtocolQueryPipe); - } - - d_crossProtocolQueryPipe = rhs.d_crossProtocolQueryPipe; - rhs.d_crossProtocolQueryPipe = -1; - - return *this; - } - - DoHWorkerThread(const DoHWorkerThread& rhs) = delete; - DoHWorkerThread& operator=(const DoHWorkerThread&) = delete; - - ~DoHWorkerThread() - { - if (d_crossProtocolQueryPipe != -1) { - close(d_crossProtocolQueryPipe); - } - } - - int d_crossProtocolQueryPipe{-1}; -}; - -DoHClientCollection::DoHClientCollection(size_t maxThreads): d_clientThreads(maxThreads), d_maxThreads(maxThreads) -{ -} - -bool DoHClientCollection::passCrossProtocolQueryToThread(std::unique_ptr&& cpq) -{ - if (d_numberOfThreads == 0) { - throw std::runtime_error("No DoH worker thread yet"); - } - - uint64_t pos = d_pos++; - auto pipe = d_clientThreads.at(pos % d_numberOfThreads).d_crossProtocolQueryPipe; - auto tmp = cpq.release(); - - if (write(pipe, &tmp, sizeof(tmp)) != sizeof(tmp)) { - delete tmp; - tmp = nullptr; - return false; - } - - return true; -} - thread_local map>> DownstreamDoHConnectionsManager::t_downstreamConnections; size_t DownstreamDoHConnectionsManager::s_maxCachedConnectionsPerDownstream{10}; time_t DownstreamDoHConnectionsManager::s_nextCleanup{0}; @@ -923,8 +865,82 @@ static void dohClientThread(int crossProtocolPipeFD) } } +static bool select_next_proto_callback(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen) { + if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) { + vinfolog("The remote DoH backend did not advertise " NGHTTP2_PROTO_VERSION_ID); + return false; + } + return true; +} + +#endif /* HAVE_NGHTTP2 */ + +struct DoHClientCollection::DoHWorkerThread +{ + DoHWorkerThread() + { + } + + DoHWorkerThread(int crossProtocolPipe): d_crossProtocolQueryPipe(crossProtocolPipe) + { + } + + DoHWorkerThread(DoHWorkerThread&& rhs): d_crossProtocolQueryPipe(rhs.d_crossProtocolQueryPipe) + { + rhs.d_crossProtocolQueryPipe = -1; + } + + DoHWorkerThread& operator=(DoHWorkerThread&& rhs) + { + if (d_crossProtocolQueryPipe != -1) { + close(d_crossProtocolQueryPipe); + } + + d_crossProtocolQueryPipe = rhs.d_crossProtocolQueryPipe; + rhs.d_crossProtocolQueryPipe = -1; + + return *this; + } + + DoHWorkerThread(const DoHWorkerThread& rhs) = delete; + DoHWorkerThread& operator=(const DoHWorkerThread&) = delete; + + ~DoHWorkerThread() + { + if (d_crossProtocolQueryPipe != -1) { + close(d_crossProtocolQueryPipe); + } + } + + int d_crossProtocolQueryPipe{-1}; +}; + +DoHClientCollection::DoHClientCollection(size_t maxThreads): d_clientThreads(maxThreads), d_maxThreads(maxThreads) +{ +} + +bool DoHClientCollection::passCrossProtocolQueryToThread(std::unique_ptr&& cpq) +{ + if (d_numberOfThreads == 0) { + throw std::runtime_error("No DoH worker thread yet"); + } + + uint64_t pos = d_pos++; + auto pipe = d_clientThreads.at(pos % d_numberOfThreads).d_crossProtocolQueryPipe; + auto tmp = cpq.release(); + + if (write(pipe, &tmp, sizeof(tmp)) != sizeof(tmp)) { + delete tmp; + tmp = nullptr; + return false; + } + + return true; +} + void DoHClientCollection::addThread() { +#ifdef HAVE_NGHTTP2 auto preparePipe = [](int fds[2], const std::string& type) -> bool { if (pipe(fds) < 0) { errlog("Error creating the DoH thread %s pipe: %s", type, stringerror()); @@ -988,22 +1004,21 @@ void DoHClientCollection::addThread() d_clientThreads.at(d_numberOfThreads) = std::move(worker); ++d_numberOfThreads; } +#else /* HAVE_NGHTTP2 */ + throw std::runtime_error("DoHClientCollection::addThread() called but nghttp2 support is not available"); +#endif /* HAVE_NGHTTP2 */ } bool initDoHWorkers() { +#ifdef HAVE_NGHTTP2 #warning FIXME: number of DoH threads g_dohClientThreads = std::make_unique(4); g_dohClientThreads->addThread(); return true; -} - -static bool select_next_proto_callback(unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen) { - if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) { - vinfolog("The remote DoH backend did not advertise " NGHTTP2_PROTO_VERSION_ID); - return false; - } - return true; +#else + return false; +#endif /* HAVE_NGHTTP2 */ } bool setupDoHClientProtocolNegotiation(std::shared_ptr& ctx) @@ -1011,19 +1026,27 @@ bool setupDoHClientProtocolNegotiation(std::shared_ptr& ctx) if (ctx == nullptr) { return false; } +#ifdef HAVE_NGHTTP2 /* we want to set the ALPN to h2, if only to mitigate the ALPACA attack */ const std::vector> h2Alpns = {{'h', '2'}}; ctx->setALPNProtos(h2Alpns); ctx->setNextProtocolSelectCallback(select_next_proto_callback); return true; +#else /* HAVE_NGHTTP2 */ + return false; +#endif /* HAVE_NGHTTP2 */ } bool sendH2Query(const std::shared_ptr& ds, std::unique_ptr& mplexer, std::shared_ptr& sender, InternalQuery&& query) { +#ifdef HAVE_NGHTTP2 struct timeval now; gettimeofday(&now, nullptr); auto newConnection = std::make_shared(ds, mplexer, now); newConnection->queueQuery(sender, std::move(query)); return true; +#else /* HAVE_NGHTTP2 */ + return false; +#endif /* HAVE_NGHTTP2 */ } diff --git a/pdns/dnsdistdist/m4/dnsdist_enable_doh.m4 b/pdns/dnsdistdist/m4/dnsdist_enable_doh.m4 index 4053d7a094..876a21890f 100644 --- a/pdns/dnsdistdist/m4/dnsdist_enable_doh.m4 +++ b/pdns/dnsdistdist/m4/dnsdist_enable_doh.m4 @@ -1,7 +1,7 @@ AC_DEFUN([DNSDIST_ENABLE_DNS_OVER_HTTPS], [ - AC_MSG_CHECKING([whether to enable DNS over HTTPS (DoH) support]) + 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 DNS over HTTPS (DoH) support (requires libh2o) @<:@default=no@:>@]), + AS_HELP_STRING([--enable-dns-over-https], [enable incoming DNS over HTTPS (DoH) support (requires libh2o) @<:@default=no@:>@]), [enable_dns_over_https=$enableval], [enable_dns_over_https=no] ) diff --git a/pdns/dnsdistdist/m4/pdns_with_nghttp2.m4 b/pdns/dnsdistdist/m4/pdns_with_nghttp2.m4 new file mode 100644 index 0000000000..aa6a5c2fb1 --- /dev/null +++ b/pdns/dnsdistdist/m4/pdns_with_nghttp2.m4 @@ -0,0 +1,32 @@ +AC_DEFUN([PDNS_WITH_NGHTTP2], [ + AC_MSG_CHECKING([whether we will be linking in nghttp2]) + HAVE_NGHTTP2=0 + AC_ARG_WITH([nghttp2], + AS_HELP_STRING([--with-nghttp2],[use nghttp2 @<:@default=auto@:>@]), + [with_nghttp2=$withval], + [with_nghttp2=auto], + ) + AC_MSG_RESULT([$with_nghttp2]) + + AS_IF([test "x$with_nghttp2" != "xno"], [ + AS_IF([test "x$with_nghttp2" = "xyes" -o "x$with_nghttp2" = "xauto"], [ + PKG_CHECK_MODULES([NGHTTP2], [libnghttp2], [ + [HAVE_NGHTTP2=1] + AC_DEFINE([HAVE_NGHTTP2], [1], [Define to 1 if you have nghttp2]) + save_CFLAGS=$CFLAGS + save_LIBS=$LIBS + CFLAGS="$NGHTTP2_CFLAGS $CFLAGS" + LIBS="$NGHTTP2_LIBS $LIBS" + CFLAGS=$save_CFLAGS + LIBS=$save_LIBS + + ], [ : ]) + ]) + ]) + AM_CONDITIONAL([HAVE_NGHTTP2], [test "x$NGHTTP2_LIBS" != "x"]) + AS_IF([test "x$with_nghttp2" = "xyes"], [ + AS_IF([test x"$NGHTTP2_LIBS" = "x"], [ + AC_MSG_ERROR([nghttp2 requested but libraries were not found]) + ]) + ]) +])