]> granicus.if.org Git - pdns/commitdiff
dnsdist: Move the DoH ticket keys logic into the DOHAcceptContext
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 15 Oct 2019 14:43:43 +0000 (16:43 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 23 Oct 2019 10:22:00 +0000 (12:22 +0200)
pdns/dnsdist-lua.cc
pdns/dnsdistdist/doh.cc
pdns/doh.hh

index 6c492322efbd426003723ae0da9a9b00546e9ae7..6fcdfa5b6522cd3fdf3463c8ea9eabbad4234b1c 100644 (file)
@@ -1828,7 +1828,7 @@ void setupLuaConfig(bool client)
           ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "GET" % "POST" % "Bad" % "Errors" % "Redirects" % "Valid" % "# ticket keys" % "Rotation delay" % "Next rotation") << endl;
           size_t counter = 0;
           for (const auto& ctx : g_dohlocals) {
-            ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http1Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->d_tlsConfig.d_ticketsKeyRotationDelay % ctx->getNextTicketsKeyRotation()) << endl;
+            ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http1Stats.d_nbQueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_redirectresponses % ctx->d_validresponses % ctx->getTicketsKeysCount() % ctx->getTicketsKeyRotationDelay() % ctx->getNextTicketsKeyRotation()) << endl;
             counter++;
           }
           g_outputBuffer = ret.str();
index 194f441e5dbdba89317aff3a732b6d45f1105a81..09edacbcbfa54d4c82cfa3b6df01c8c8e6dece7c 100644 (file)
@@ -62,6 +62,7 @@ public:
   DOHAcceptContext()
   {
     memset(&d_h2o_accept_ctx, 0, sizeof(d_h2o_accept_ctx));
+    d_rotatingTicketsKey.clear();
   }
   DOHAcceptContext(const DOHAcceptContext&) = delete;
   DOHAcceptContext& operator=(const DOHAcceptContext&) = delete;
@@ -89,12 +90,83 @@ public:
     }
   }
 
+  time_t getNextTicketsKeyRotation() const
+  {
+    return d_ticketsKeyNextRotation;
+  }
+
+  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};
   ClientState* d_cs{nullptr};
+  time_t d_ticketsKeyRotationDelay{0};
 
 private:
   h2o_accept_ctx_t d_h2o_accept_ctx;
   std::atomic<uint64_t> d_refcnt{1};
+  time_t d_ticketsKeyNextRotation{0};
+  std::atomic_flag d_rotatingTicketsKey;
 };
 
 // we create one of these per thread, and pass around a pointer to it
@@ -940,63 +1012,61 @@ static int ocsp_stapling_callback(SSL* ssl, void* arg)
 
 static int ticket_key_callback(SSL *s, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
 {
-  DOHFrontend* df = reinterpret_cast<DOHFrontend*>(libssl_get_ticket_key_callback_data(s));
-  if (df == nullptr || !df->d_ticketKeys) {
+  DOHAcceptContext* ctx = reinterpret_cast<DOHAcceptContext*>(libssl_get_ticket_key_callback_data(s));
+  if (ctx == nullptr || !ctx->d_ticketKeys) {
     return -1;
   }
 
-  df->handleTicketsKeyRotation();
+  ctx->handleTicketsKeyRotation();
 
-  auto ret = libssl_ticket_key_callback(s, *df->d_ticketKeys, keyName, iv, ectx, hctx, enc);
+  auto ret = libssl_ticket_key_callback(s, *ctx->d_ticketKeys, keyName, iv, ectx, hctx, enc);
   if (enc == 0) {
     if (ret == 0) {
-      ++df->d_dsc->cs->tlsUnknownTicketKey;
+      ++ctx->d_cs->tlsUnknownTicketKey;
     }
     else if (ret == 2) {
-      ++df->d_dsc->cs->tlsInactiveTicketKey;
+      ++ctx->d_cs->tlsInactiveTicketKey;
     }
   }
 
   return ret;
 }
 
-static std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> getTLSContext(DOHFrontend& df,
-                                                                 std::map<int, std::string>& ocspResponses)
+static void setupTLSContext(DOHAcceptContext& acceptCtx,
+                            TLSConfig& tlsConfig,
+                            TLSErrorCounters& counters)
 {
-  try {
-    if (df.d_tlsConfig.d_ciphers.empty()) {
-      df.d_tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS;
-    }
-
-    auto ctx = libssl_init_server_context(df.d_tlsConfig, ocspResponses);
+  if (tlsConfig.d_ciphers.empty()) {
+    tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS;
+  }
 
-    if (df.d_tlsConfig.d_enableTickets && df.d_tlsConfig.d_numberOfTicketsKeys > 0) {
-      df.d_ticketKeys = std::unique_ptr<OpenSSLTLSTicketKeysRing>(new OpenSSLTLSTicketKeysRing(df.d_tlsConfig.d_numberOfTicketsKeys));
-      SSL_CTX_set_tlsext_ticket_key_cb(ctx.get(), &ticket_key_callback);
-      libssl_set_ticket_key_callback_data(ctx.get(), &df);
-    }
+  auto ctx = libssl_init_server_context(tlsConfig, acceptCtx.d_ocspResponses);
 
-    if (!ocspResponses.empty()) {
-      SSL_CTX_set_tlsext_status_cb(ctx.get(), &ocsp_stapling_callback);
-      SSL_CTX_set_tlsext_status_arg(ctx.get(), &ocspResponses);
-    }
+  if (tlsConfig.d_enableTickets && tlsConfig.d_numberOfTicketsKeys > 0) {
+    acceptCtx.d_ticketKeys = std::unique_ptr<OpenSSLTLSTicketKeysRing>(new OpenSSLTLSTicketKeysRing(tlsConfig.d_numberOfTicketsKeys));
+    SSL_CTX_set_tlsext_ticket_key_cb(ctx.get(), &ticket_key_callback);
+    libssl_set_ticket_key_callback_data(ctx.get(), &acceptCtx);
+  }
 
-    libssl_set_error_counters_callback(ctx, &df.d_tlsCounters);
+  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);
+  }
 
-    h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols);
+  libssl_set_error_counters_callback(ctx, &counters);
 
-    if (df.d_tlsConfig.d_ticketKeyFile.empty()) {
-      df.handleTicketsKeyRotation();
-    }
-    else {
-      df.loadTicketsKeys(df.d_tlsConfig.d_ticketKeyFile);
-    }
+  h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols);
 
-    return ctx;
+  if (tlsConfig.d_ticketKeyFile.empty()) {
+    acceptCtx.handleTicketsKeyRotation();
   }
-  catch (const std::runtime_error& e) {
-    throw std::runtime_error("Error setting up TLS context for DoH listener on '" + df.d_local.toStringWithPort() + "': " + e.what());
+  else {
+    acceptCtx.loadTicketsKeys(tlsConfig.d_ticketKeyFile);
   }
+
+  auto nativeCtx = acceptCtx.get();
+  nativeCtx->ssl_ctx = ctx.release();
+  acceptCtx.release();
 }
 
 static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool setupTLS)
@@ -1004,11 +1074,17 @@ static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool
   auto nativeCtx = ctx.get();
   nativeCtx->ctx = &dsc.h2o_ctx;
   nativeCtx->hosts = dsc.h2o_config.hosts;
-  if (setupTLS && !dsc.df->d_tlsConfig.d_certKeyPairs.empty()) {
-    auto tlsCtx = getTLSContext(*dsc.df,
-                                ctx.d_ocspResponses);
+  ctx.d_ticketsKeyRotationDelay = dsc.df->d_tlsConfig.d_ticketsKeyRotationDelay;
 
-    nativeCtx->ssl_ctx = tlsCtx.release();
+  if (setupTLS && !dsc.df->d_tlsConfig.d_certKeyPairs.empty()) {
+    try {
+      setupTLSContext(ctx,
+                      dsc.df->d_tlsConfig,
+                      dsc.df->d_tlsCounters);
+    }
+    catch (const std::runtime_error& e) {
+      throw std::runtime_error("Error setting up TLS context for DoH listener on '" + dsc.df->d_local.toStringWithPort() + "': " + e.what());
+    }
   }
   ctx.d_cs = dsc.cs;
   ctx.release();
@@ -1016,55 +1092,40 @@ static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool
 
 void DOHFrontend::rotateTicketsKey(time_t now)
 {
-  if (!d_ticketKeys) {
-    return;
-  }
-
-  d_ticketKeys->rotateTicketsKey(now);
-
-  if (d_tlsConfig.d_ticketsKeyRotationDelay > 0) {
-    d_ticketsKeyNextRotation = now + d_tlsConfig.d_ticketsKeyRotationDelay;
+  if (d_dsc && d_dsc->accept_ctx) {
+    d_dsc->accept_ctx->rotateTicketsKey(now);
   }
 }
 
 void DOHFrontend::loadTicketsKeys(const std::string& keyFile)
 {
-  if (!d_ticketKeys) {
-    return;
-  }
-  d_ticketKeys->loadTicketsKeys(keyFile);
-
-  if (d_tlsConfig.d_ticketsKeyRotationDelay > 0) {
-    d_ticketsKeyNextRotation = time(nullptr) + d_tlsConfig.d_ticketsKeyRotationDelay;
+  if (d_dsc && d_dsc->accept_ctx) {
+    d_dsc->accept_ctx->loadTicketsKeys(keyFile);
   }
 }
 
 void DOHFrontend::handleTicketsKeyRotation()
 {
-  if (d_tlsConfig.d_ticketsKeyRotationDelay == 0) {
-    return;
+  if (d_dsc && d_dsc->accept_ctx) {
+    d_dsc->accept_ctx->handleTicketsKeyRotation();
   }
+}
 
-  time_t now = time(nullptr);
-  if (now > d_ticketsKeyNextRotation) {
-    if (d_rotatingTicketsKey.test_and_set()) {
-      /* someone is already rotating */
-      return;
-    }
-    try {
-      rotateTicketsKey(now);
+time_t DOHFrontend::getNextTicketsKeyRotation() const
+{
+  if (d_dsc && d_dsc->accept_ctx) {
+    return d_dsc->accept_ctx->getNextTicketsKeyRotation();
+  }
+  return 0;
+}
 
-      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;
-    }
+size_t DOHFrontend::getTicketsKeysCount() const
+{
+  size_t res = 0;
+  if (d_dsc && d_dsc->accept_ctx) {
+    res = d_dsc->accept_ctx->getTicketsKeysCount();
   }
+  return res;
 }
 
 void DOHFrontend::reloadCertificates()
@@ -1083,12 +1144,14 @@ void DOHFrontend::setup()
   d_dsc = std::make_shared<DOHServerConfig>(d_idleTimeout);
 
   if  (!d_tlsConfig.d_certKeyPairs.empty()) {
-    auto tlsCtx = getTLSContext(*this,
-                                d_dsc->accept_ctx->d_ocspResponses);
-
-    auto accept_ctx = d_dsc->accept_ctx->get();
-    accept_ctx->ssl_ctx = tlsCtx.release();
-    d_dsc->accept_ctx->release();
+    try {
+      setupTLSContext(*d_dsc->accept_ctx,
+                      d_tlsConfig,
+                      d_tlsCounters);
+    }
+    catch (const std::runtime_error& e) {
+      throw std::runtime_error("Error setting up TLS context for DoH listener on '" + d_local.toStringWithPort() + "': " + e.what());
+    }
   }
 }
 
index 80481ec4dbdacc09ce2d262026174b41ae44f90f..53cfbcd206630491bd74c43212e4c55cce68781d 100644 (file)
@@ -42,7 +42,6 @@ struct DOHFrontend
 {
   DOHFrontend()
   {
-    d_rotatingTicketsKey.clear();
   }
 
   std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
@@ -50,9 +49,6 @@ struct DOHFrontend
   TLSConfig d_tlsConfig;
   TLSErrorCounters d_tlsCounters;
   std::string d_serverTokens{"h2o/dnsdist"};
-#ifdef HAVE_DNS_OVER_HTTPS
-  std::unique_ptr<OpenSSLTLSTicketKeysRing> d_ticketKeys{nullptr};
-#endif
   std::vector<std::pair<std::string, std::string>> d_customResponseHeaders;
   ComboAddress d_local;
 
@@ -81,6 +77,10 @@ struct DOHFrontend
   HTTPVersionStats d_http1Stats;
   HTTPVersionStats d_http2Stats;
 
+  time_t getTicketsKeyRotationDelay() const
+  {
+    return d_tlsConfig.d_ticketsKeyRotationDelay;
+  }
 
 #ifndef HAVE_DNS_OVER_HTTPS
   void setup()
@@ -103,35 +103,27 @@ struct DOHFrontend
   {
   }
 
-#else
-  void setup();
-  void reloadCertificates();
-
-  void rotateTicketsKey(time_t now);
-  void loadTicketsKeys(const std::string& keyFile);
-  void handleTicketsKeyRotation();
-
-#endif /* HAVE_DNS_OVER_HTTPS */
-
   time_t getNextTicketsKeyRotation() const
   {
-    return d_ticketsKeyNextRotation;
+    return 0;
   }
 
   size_t getTicketsKeysCount() const
   {
     size_t res = 0;
-#ifdef HAVE_DNS_OVER_HTTPS
-    if (d_ticketKeys) {
-      res = d_ticketKeys->getKeysCount();
-    }
-#endif /* HAVE_DNS_OVER_HTTPS */
     return res;
   }
 
-private:
-  time_t d_ticketsKeyNextRotation{0};
-  std::atomic_flag d_rotatingTicketsKey;
+#else
+  void setup();
+  void reloadCertificates();
+
+  void rotateTicketsKey(time_t now);
+  void loadTicketsKeys(const std::string& keyFile);
+  void handleTicketsKeyRotation();
+  time_t getNextTicketsKeyRotation() const;
+  size_t getTicketsKeysCount() const;
+#endif /* HAVE_DNS_OVER_HTTPS */
 };
 
 #ifndef HAVE_DNS_OVER_HTTPS