]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Proper detection of nghttp2 support
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 25 Aug 2021 08:49:13 +0000 (10:49 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 13 Sep 2021 13:28:27 +0000 (15:28 +0200)
pdns/dnsdist-lua.cc
pdns/dnsdist.cc
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/dnsdist-nghttp2.cc
pdns/dnsdistdist/m4/dnsdist_enable_doh.m4
pdns/dnsdistdist/m4/pdns_with_nghttp2.m4 [new file with mode: 0644]

index c63486621d47fe135d37c3bbc25f7270e9c5eed4..5ea08281c68c6b994e66155bd31aa4b54613930a 100644 (file)
@@ -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<string>(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);
index 00fa3f22865fd64351f42dd48f3cca58dcaf81bb..57d5322b04c9282e5f81cf1baf5cfd13884e8f18 100644 (file)
@@ -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
index 03ae3e1110204af63f75933be85f9c1fd7d3ac32..3e62c1ff184105c7e84793fb266aa0007021c356 100644 (file)
@@ -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
index 02ac66043dd6c1c34d103e7604f5a516d795a3dc..774ace1c45ec4874b41942ff26fab4caa2b2b2dd 100644 (file)
@@ -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])]
index 0aea4d7170d892b0d012a47f4e26978b5b61f7d6..bf6449a2766986c0c3a371c38a7dea9f95927767 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "config.h"
+
+#ifdef HAVE_NGHTTP2
 #include <nghttp2/nghttp2.h>
+#endif /* HAVE_NGHTTP2 */
 
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-tcp.hh"
@@ -37,6 +41,7 @@
 std::atomic<uint64_t> g_dohStatesDumpRequested{0};
 std::unique_ptr<DoHClientCollection> g_dohClientThreads{nullptr};
 
+#ifdef HAVE_NGHTTP2
 class DoHConnectionToBackend: public TCPConnectionToBackend
 {
 public:
@@ -657,69 +662,6 @@ DoHConnectionToBackend::DoHConnectionToBackend(std::shared_ptr<DownstreamState>
   }
 }
 
-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<CrossProtocolQuery>&& 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<boost::uuids::uuid, std::deque<std::shared_ptr<DoHConnectionToBackend>>> 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<CrossProtocolQuery>&& 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<DoHClientCollection>(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<TLSCtx>& ctx)
@@ -1011,19 +1026,27 @@ bool setupDoHClientProtocolNegotiation(std::shared_ptr<TLSCtx>& 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<std::vector<uint8_t>> 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<DownstreamState>& ds, std::unique_ptr<FDMultiplexer>& mplexer, std::shared_ptr<TCPQuerySender>& sender, InternalQuery&& query)
 {
+#ifdef HAVE_NGHTTP2
   struct timeval now;
   gettimeofday(&now, nullptr);
 
   auto newConnection = std::make_shared<DoHConnectionToBackend>(ds, mplexer, now);
   newConnection->queueQuery(sender, std::move(query));
   return true;
+#else /* HAVE_NGHTTP2 */
+  return false;
+#endif /* HAVE_NGHTTP2 */
 }
index 4053d7a09447ff67a92ff9395a437a1542f080e7..876a21890f2ba3da91f5fc7784d1ee66c98883bf 100644 (file)
@@ -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 (file)
index 0000000..aa6a5c2
--- /dev/null
@@ -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])
+    ])
+  ])
+])